From 6f1c2f098767c734d01c1e142643e27a62c67c15 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Wed, 7 May 2025 17:04:55 +0530 Subject: [PATCH 001/130] feat: fees contracts --- .../FeesManager.sol | 51 +++--------- contracts/evmx/fees/WatcherFeesManager.sol | 65 +++++++++++++++ contracts/evmx/interfaces/IFeesManager.sol | 83 ++++++++----------- .../evmx/interfaces/IWatcherFeesManager.sol | 24 ++++++ .../interfaces/IWatcherPrecompileConfig.sol | 1 - .../interfaces/IWatcherPrecompileLimits.sol | 24 ------ .../WatcherPrecompileLimits.sol | 81 ------------------ 7 files changed, 135 insertions(+), 194 deletions(-) rename contracts/evmx/{payload-delivery => fees}/FeesManager.sol (94%) create mode 100644 contracts/evmx/fees/WatcherFeesManager.sol create mode 100644 contracts/evmx/interfaces/IWatcherFeesManager.sol delete mode 100644 contracts/evmx/interfaces/IWatcherPrecompileLimits.sol delete mode 100644 contracts/evmx/watcherPrecompile/WatcherPrecompileLimits.sol diff --git a/contracts/evmx/payload-delivery/FeesManager.sol b/contracts/evmx/fees/FeesManager.sol similarity index 94% rename from contracts/evmx/payload-delivery/FeesManager.sol rename to contracts/evmx/fees/FeesManager.sol index 7f5e5e61..6cebd5c1 100644 --- a/contracts/evmx/payload-delivery/FeesManager.sol +++ b/contracts/evmx/fees/FeesManager.sol @@ -4,7 +4,6 @@ pragma solidity ^0.8.21; import {Ownable} from "solady/auth/Ownable.sol"; import "solady/utils/Initializable.sol"; import "solady/utils/ECDSA.sol"; -import {IFeesPlug} from "../interfaces/IFeesPlug.sol"; import "../interfaces/IFeesManager.sol"; import {AddressResolverUtil} from "../AddressResolverUtil.sol"; import {NotAuctionManager, InvalidWatcherSignature, NonceUsed} from "../../utils/common/Errors.sol"; @@ -14,41 +13,29 @@ abstract contract FeesManagerStorage is IFeesManager { // slots [0-49] reserved for gap uint256[50] _gap_before; - // slot 50 - uint256 public feesCounter; - - // slot 51 - uint32 public evmxSlug; - - // slot 52 - bytes32 public sbType; - - // user credits - mapping(address => UserCredits) public userCredits; - - // user nonce - mapping(address => uint256) public userNonce; + //===== user ===== + // user credits => stores fees for user, app gateway, transmitters and watcher precompile + mapping(address => UserCredits) public userFees; + // user approved app gateways + // userAddress => appGateway => isWhitelisted + mapping(address => mapping(address => bool)) public isAppGatewayWhitelisted; // token pool balances // chainSlug => token address => amount mapping(uint32 => mapping(address => uint256)) public tokenPoolBalances; - // user approved app gateways - // userAddress => appGateway => isWhitelisted - mapping(address => mapping(address => bool)) public isAppGatewayWhitelisted; - // slot 54 /// @notice Mapping to track request credits details for each request count /// @dev requestCount => RequestFee mapping(uint40 => uint256) public requestCountCredits; - // @dev amount - uint256 public watcherPrecompileCredits; - // slot 56 /// @notice Mapping to track nonce to whether it has been used - /// @dev signatureNonce => isNonceUsed - mapping(uint256 => bool) public isNonceUsed; + /// @dev address => signatureNonce => isNonceUsed + /// @dev used by watchers or other users in signatures + mapping(address => mapping(uint256 => bool)) public isNonceUsed; + + uint256 public withdrawCounter; // slots [57-106] reserved for gap uint256[50] _gap_after; @@ -115,22 +102,6 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol /// @notice Emitted when credits are unwrapped event CreditsUnwrapped(address indexed consumeFrom, uint256 amount); - /// @notice Error thrown when insufficient fees are available - error InsufficientCreditsAvailable(); - /// @notice Error thrown when no fees are available for a transmitter - error NoFeesForTransmitter(); - /// @notice Error thrown when no fees was blocked - error NoCreditsBlocked(); - /// @notice Error thrown when caller is invalid - error InvalidCaller(); - /// @notice Error thrown when user signature is invalid - error InvalidUserSignature(); - /// @notice Error thrown when app gateway is not whitelisted - error AppGatewayNotWhitelisted(); - - error InvalidAmount(); - error InsufficientBalance(); - constructor() { _disableInitializers(); // disable for implementation } diff --git a/contracts/evmx/fees/WatcherFeesManager.sol b/contracts/evmx/fees/WatcherFeesManager.sol new file mode 100644 index 00000000..2479bf48 --- /dev/null +++ b/contracts/evmx/fees/WatcherFeesManager.sol @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import "solady/utils/Initializable.sol"; +import {Ownable} from "solady/auth/Ownable.sol"; +import {AddressResolverUtil} from "../AddressResolverUtil.sol"; +import "../interfaces/IWatcherFeesManager.sol"; +import {SCHEDULE, QUERY, FINALIZE, CALLBACK} from "../../utils/common/Constants.sol"; + +/// @title WatcherFeesManager +/// @notice Contract for managing watcher fees +contract WatcherFeesManager is IWatcherFeesManager, Initializable, Ownable, AddressResolverUtil { + // slots 0-49 (50) reserved for gauge + // slots 50-100 (51) reserved for addr resolver util + + // slots [101-150]: gap for future storage variables + uint256[50] _gap_before; + + // slot 157: fees + mapping(bytes32 => uint256) public watcherFees; + + /// @notice Emitted when the query fees are set + event WatcherFeesSet(bytes32 feeType, uint256 fees); + + error WatcherFeesNotSet(bytes32 feeType); + + /// @notice Initial initialization (version 1) + function initialize(address owner_, address addressResolver_, uint256) public reinitializer(1) { + _setAddressResolver(addressResolver_); + _initializeOwner(owner_); + } + + function setWatcherFees(bytes32 feeType, uint256 fees) external onlyOwner { + watcherFees[feeType] = fees; + emit WatcherFeesSet(feeType, fees); + } + + function getWatcherFees(bytes32 feeType) external view returns (uint256) { + return watcherFees[feeType]; + } + + function getTotalWatcherFeesRequired( + bytes32[] memory feeTypes_, + uint256[] memory counts_ + ) external view returns (uint256) { + uint256 totalFees = 0; + for (uint256 i = 0; i < feeTypes_.length; i++) { + totalFees += watcherFees[feeTypes_[i]] * counts_[i]; + } + return totalFees; + } + + function payWatcherFees( + bytes32[] memory feeTypes_, + uint256[] memory counts_, + address consumeFrom_ + ) external { + uint256 totalFees = 0; + for (uint256 i = 0; i < feeTypes_.length; i++) { + totalFees += watcherFees[feeTypes_[i]] * counts_[i]; + } + + // call to fees manager to pay fees + } +} diff --git a/contracts/evmx/interfaces/IFeesManager.sol b/contracts/evmx/interfaces/IFeesManager.sol index d7afdbaf..f5fb68d3 100644 --- a/contracts/evmx/interfaces/IFeesManager.sol +++ b/contracts/evmx/interfaces/IFeesManager.sol @@ -1,66 +1,53 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import {Bid, QueuePayloadParams, PayloadSubmitParams, AppGatewayWhitelistParams} from "../../utils/common/Structs.sol"; - interface IFeesManager { - function blockCredits( - address consumeFrom_, - uint256 transmitterCredits_, - uint40 requestCount_ - ) external; + // native to credit + function wrap() external payable; - function unblockCredits(uint40 requestCount_) external; + function unwrap(uint256 amount) external; - function isUserCreditsEnough( - address consumeFrom_, - address appGateway_, - uint256 amount_ - ) external view returns (bool); + // credits from vault + function depositCredits( + address token, + address from, + uint32 chainSlug, + bytes calldata watcherSignature + ) external payable; - function unblockAndAssignCredits(uint40 requestCount_, address transmitter_) external; + function getAvailableCredits(address user) external view returns (uint256); - function assignWatcherPrecompileCreditsFromRequestCount( - uint256 fees_, - uint40 requestCount_ + // withdraw credits onchain + // finalize and release sign, no AM needed, can be used by watcher and transmitter + function withdrawCreditsTo( + uint32 chainSlug, + address to, + uint256 amount, + bool needAuction ) external; - function assignWatcherPrecompileCreditsFromAddress( - uint256 fees_, - address consumeFrom_ + function withdrawNativeTo( + uint32 chainSlug, + address to, + uint256 amount, + bool needAuction ) external; - function whitelistAppGatewayWithSignature( - bytes memory feeApprovalData_ - ) external returns (address consumeFrom, address appGateway, bool isApproved); + // Fee settlement + // if addr(0) then settle to original user, onlyWatcherPrecompile can call + function settleFees(uint40 requestId, address transmitter) external; - function whitelistAppGateways(AppGatewayWhitelistParams[] calldata params_) external; + // onlyWatcherPrecompile, request's AM can call + function blockCredits(uint40 requestId, address user, uint256 amount) external; - function getWithdrawTransmitterCreditsPayloadParams( - address transmitter_, - uint32 chainSlug_, - address token_, - address receiver_, - uint256 amount_ - ) external returns (PayloadSubmitParams[] memory); + // onlyWatcherPrecompile, request's AM can call + function unblockCredits(uint40 requestId, address user, uint256 amount) external; - function getMaxCreditsAvailableForWithdraw( - address transmitter_ - ) external view returns (uint256); + // msg sender should be user whitelisted app gateway + function deductCredits(address user, uint256 amount) external; - function withdrawCredits( - address originAppGatewayOrUser_, - uint32 chainSlug_, - address token_, - uint256 amount_, - address receiver_ - ) external; + // whitelist + function whitelistAppGatewayWithSignature(bytes calldata signature) external; - function depositCredits( - address depositTo_, - uint32 chainSlug_, - address token_, - uint256 signatureNonce_, - bytes memory signature_ - ) external payable; + function whitelistAppGateways(address[] calldata appGateways) external; } diff --git a/contracts/evmx/interfaces/IWatcherFeesManager.sol b/contracts/evmx/interfaces/IWatcherFeesManager.sol new file mode 100644 index 00000000..a3d61e34 --- /dev/null +++ b/contracts/evmx/interfaces/IWatcherFeesManager.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +/// @title IWatcherFeesManager +/// @notice Interface for the Watcher Precompile system that handles payload verification and execution +/// @dev Defines core functionality for payload processing and promise resolution +interface IWatcherFeesManager { + // Watcher precompile fees + function getWatcherFees(bytes32 feeType) external view returns (uint256); + + function setWatcherFees(bytes32 feeType, uint256 fees) external; + + // Watcher fees + function getTotalWatcherFeesRequired( + bytes32[] memory feeTypes_, + uint256[] memory counts_ + ) external view returns (uint256); + + function payWatcherFees( + bytes32[] memory feeTypes_, + uint256[] memory counts_, + address consumeFrom_ + ) external; +} diff --git a/contracts/evmx/interfaces/IWatcherPrecompileConfig.sol b/contracts/evmx/interfaces/IWatcherPrecompileConfig.sol index fcfc4026..491b5c91 100644 --- a/contracts/evmx/interfaces/IWatcherPrecompileConfig.sol +++ b/contracts/evmx/interfaces/IWatcherPrecompileConfig.sol @@ -59,5 +59,4 @@ interface IWatcherPrecompileConfig { uint256 signatureNonce_, bytes calldata signature_ ) external; - } diff --git a/contracts/evmx/interfaces/IWatcherPrecompileLimits.sol b/contracts/evmx/interfaces/IWatcherPrecompileLimits.sol deleted file mode 100644 index d71447b0..00000000 --- a/contracts/evmx/interfaces/IWatcherPrecompileLimits.sol +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -pragma solidity ^0.8.21; - -import {LimitParams, UpdateLimitParams} from "../../utils/common/Structs.sol"; - -/// @title IWatcherPrecompileLimits -/// @notice Interface for the Watcher Precompile system that handles payload verification and execution -/// @dev Defines core functionality for payload processing and promise resolution -interface IWatcherPrecompileLimits { - function getTotalFeesRequired( - uint256 queryCount_, - uint256 finalizeCount_, - uint256 scheduleCount_, - uint256 callbackCount_ - ) external view returns (uint256); - - function queryFees() external view returns (uint256); - - function finalizeFees() external view returns (uint256); - - function timeoutFees() external view returns (uint256); - - function callBackFees() external view returns (uint256); -} diff --git a/contracts/evmx/watcherPrecompile/WatcherPrecompileLimits.sol b/contracts/evmx/watcherPrecompile/WatcherPrecompileLimits.sol deleted file mode 100644 index 850feb16..00000000 --- a/contracts/evmx/watcherPrecompile/WatcherPrecompileLimits.sol +++ /dev/null @@ -1,81 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -pragma solidity ^0.8.21; - -import "solady/utils/Initializable.sol"; -import {Ownable} from "solady/auth/Ownable.sol"; -import {AddressResolverUtil} from "../AddressResolverUtil.sol"; -import "../interfaces/IWatcherPrecompileLimits.sol"; -import {SCHEDULE, QUERY, FINALIZE, CALLBACK} from "../../utils/common/Constants.sol"; - -/// @title WatcherPrecompileLimits -/// @notice Contract for managing watcher precompile limits -contract WatcherPrecompileLimits is - IWatcherPrecompileLimits, - Initializable, - Ownable, - AddressResolverUtil -{ - // slots 0-49 (50) reserved for gauge - // slots 50-100 (51) reserved for addr resolver util - - // slots [101-150]: gap for future storage variables - uint256[50] _gap_before; - - // slot 157: fees - uint256 public queryFees; - uint256 public finalizeFees; - uint256 public timeoutFees; - uint256 public callBackFees; - - /// @notice Emitted when the query fees are set - event QueryFeesSet(uint256 queryFees); - /// @notice Emitted when the finalize fees are set - event FinalizeFeesSet(uint256 finalizeFees); - /// @notice Emitted when the timeout fees are set - event TimeoutFeesSet(uint256 timeoutFees); - /// @notice Emitted when the call back fees are set - event CallBackFeesSet(uint256 callBackFees); - - error WatcherFeesNotSet(bytes32 limitType); - - /// @notice Initial initialization (version 1) - function initialize(address owner_, address addressResolver_, uint256) public reinitializer(1) { - _setAddressResolver(addressResolver_); - _initializeOwner(owner_); - } - - function setQueryFees(uint256 queryFees_) external onlyOwner { - queryFees = queryFees_; - emit QueryFeesSet(queryFees_); - } - - function setFinalizeFees(uint256 finalizeFees_) external onlyOwner { - finalizeFees = finalizeFees_; - emit FinalizeFeesSet(finalizeFees_); - } - - function setTimeoutFees(uint256 timeoutFees_) external onlyOwner { - timeoutFees = timeoutFees_; - emit TimeoutFeesSet(timeoutFees_); - } - - function setCallBackFees(uint256 callBackFees_) external onlyOwner { - callBackFees = callBackFees_; - emit CallBackFeesSet(callBackFees_); - } - - function getTotalFeesRequired( - uint256 queryCount_, - uint256 finalizeCount_, - uint256 scheduleCount_, - uint256 callbackCount_ - ) external view returns (uint256) { - uint256 totalFees = 0; - totalFees += callbackCount_ * callBackFees; - totalFees += queryCount_ * queryFees; - totalFees += finalizeCount_ * finalizeFees; - totalFees += scheduleCount_ * timeoutFees; - - return totalFees; - } -} From 1d47c70ecfd62455631ef9ec696f8cfe25f7f04c Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Wed, 7 May 2025 20:07:19 +0530 Subject: [PATCH 002/130] feat: helpers --- contracts/evmx/AddressResolverUtil.sol | 104 ------------------ contracts/evmx/helpers/AddressResolver.sol | 66 +++++++++++ .../evmx/helpers/AddressResolverUtil.sol | 53 +++++++++ .../AsyncDeployer.sol} | 82 +------------- .../evmx/interfaces/IAddressResolver.sol | 54 ++------- contracts/evmx/interfaces/IAsyncDeployer.sol | 28 +++++ .../evmx/{helpers => mocks}/ProxyFactory.sol | 0 .../evmx/{helpers => mocks}/TestUSDC.sol | 0 8 files changed, 163 insertions(+), 224 deletions(-) delete mode 100644 contracts/evmx/AddressResolverUtil.sol create mode 100644 contracts/evmx/helpers/AddressResolver.sol create mode 100644 contracts/evmx/helpers/AddressResolverUtil.sol rename contracts/evmx/{AddressResolver.sol => helpers/AsyncDeployer.sol} (70%) create mode 100644 contracts/evmx/interfaces/IAsyncDeployer.sol rename contracts/evmx/{helpers => mocks}/ProxyFactory.sol (100%) rename contracts/evmx/{helpers => mocks}/TestUSDC.sol (100%) diff --git a/contracts/evmx/AddressResolverUtil.sol b/contracts/evmx/AddressResolverUtil.sol deleted file mode 100644 index 7e08fcc0..00000000 --- a/contracts/evmx/AddressResolverUtil.sol +++ /dev/null @@ -1,104 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -pragma solidity ^0.8.21; - -import "./interfaces/IAddressResolver.sol"; -import "./interfaces/IMiddleware.sol"; -import "./interfaces/IWatcherPrecompile.sol"; -import "./interfaces/IWatcherPrecompileConfig.sol"; -import "./interfaces/IWatcherPrecompileLimits.sol"; -import "./interfaces/IFeesManager.sol"; - -/// @title AddressResolverUtil -/// @notice Utility contract for resolving system contract addresses -/// @dev Provides access control and address resolution functionality for the system -abstract contract AddressResolverUtil { - /// @notice The address resolver contract reference - /// @dev Used to look up system contract addresses - // slot 0 - IAddressResolver public addressResolver__; - - // slots 1-50 reserved for future use - uint256[50] __gap_resolver_util; - - /// @notice Error thrown when an invalid address attempts to call the Payload Delivery only function - error OnlyPayloadDelivery(); - /// @notice Error thrown when an invalid address attempts to call the Watcher only function - error OnlyWatcherPrecompile(); - /// @notice Error thrown when an invalid address attempts to call the Watcher precompile or delivery helper - error OnlyWatcherPrecompileOrDeliveryHelper(); - - /// @notice Restricts function access to the delivery helper contract - /// @dev Validates that msg.sender matches the registered delivery helper address - modifier onlyDeliveryHelper() { - if (msg.sender != addressResolver__.deliveryHelper()) { - revert OnlyPayloadDelivery(); - } - - _; - } - - /// @notice Restricts function access to the watcher precompile contract - /// @dev Validates that msg.sender matches the registered watcher precompile address - modifier onlyWatcherPrecompile() { - if (msg.sender != address(addressResolver__.watcherPrecompile__())) { - revert OnlyWatcherPrecompile(); - } - - _; - } - - /// @notice Restricts function access to the watcher precompile contract - /// @dev Validates that msg.sender matches the registered watcher precompile address - modifier onlyWatcherPrecompileOrDeliveryHelper() { - if ( - msg.sender != address(addressResolver__.watcherPrecompile__()) && - msg.sender != addressResolver__.deliveryHelper() - ) { - revert OnlyWatcherPrecompileOrDeliveryHelper(); - } - - _; - } - - /// @notice Gets the delivery helper contract interface - /// @return IMiddleware interface of the registered delivery helper - /// @dev Resolves and returns the delivery helper contract for interaction - function deliveryHelper__() public view returns (IMiddleware) { - return IMiddleware(addressResolver__.deliveryHelper()); - } - - /// @notice Gets the watcher precompile contract interface - /// @return IWatcherPrecompile interface of the registered watcher precompile - /// @dev Resolves and returns the watcher precompile contract for interaction - function watcherPrecompile__() public view returns (IWatcherPrecompile) { - return addressResolver__.watcherPrecompile__(); - } - - /// @notice Gets the watcher precompile config contract interface - /// @return IWatcherPrecompileConfig interface of the registered watcher precompile config - /// @dev Resolves and returns the watcher precompile config contract for interaction - function watcherPrecompileConfig() public view returns (IWatcherPrecompileConfig) { - return addressResolver__.watcherPrecompile__().watcherPrecompileConfig__(); - } - - /// @notice Gets the watcher precompile limits contract interface - /// @return IWatcherPrecompileLimits interface of the registered watcher precompile limits - /// @dev Resolves and returns the watcher precompile limits contract for interaction - function watcherPrecompileLimits() public view returns (IWatcherPrecompileLimits) { - return addressResolver__.watcherPrecompile__().watcherPrecompileLimits__(); - } - - /// @notice Internal function to set the address resolver - /// @param _addressResolver The address of the resolver contract - /// @dev Should be called in the initialization of inheriting contracts - function _setAddressResolver(address _addressResolver) internal { - addressResolver__ = IAddressResolver(_addressResolver); - } - - function _getCoreAppGateway( - address originAppGateway_ - ) internal view returns (address appGateway) { - appGateway = addressResolver__.contractsToGateways(originAppGateway_); - if (appGateway == address(0)) appGateway = originAppGateway_; - } -} diff --git a/contracts/evmx/helpers/AddressResolver.sol b/contracts/evmx/helpers/AddressResolver.sol new file mode 100644 index 00000000..d92e1dc9 --- /dev/null +++ b/contracts/evmx/helpers/AddressResolver.sol @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import {Ownable} from "solady/auth/Ownable.sol"; +import {Initializable} from "solady/utils/Initializable.sol"; +import "./interfaces/IAddressResolver.sol"; + +abstract contract AddressResolverStorage is IAddressResolver { + // slots [0-49] reserved for gap + uint256[50] _gap_before; + + IWatcherPrecompile public override watcherPrecompile__; + address public override feesManager; + address public override asyncDeployer; + address public override defaultAuctionManager; + + // slots [61-110] reserved for gap + uint256[50] _gap_after; +} + +/// @title AddressResolver Contract +/// @notice This contract is responsible for fetching latest core addresses and deploying Forwarder and AsyncPromise contracts. +/// @dev Inherits the Ownable contract and implements the IAddressResolver interface. +contract AddressResolver is AddressResolverStorage, Initializable, Ownable { + /// @notice Error thrown if AppGateway contract was already set by a different address + error InvalidAppGateway(address contractAddress_); + + /// @notice Event emitted when the fees manager is updated + event FeesManagerUpdated(address feesManager_); + /// @notice Event emitted when the watcher precompile is updated + event WatcherPrecompileUpdated(address watcherPrecompile_); + + constructor() { + _disableInitializers(); // disable for implementation + } + + /// @notice Initializer to replace constructor for upgradeable contracts + /// @dev it deploys the forwarder and async promise implementations and beacons for them + /// @dev this contract is owner of the beacons for upgrading later + /// @param owner_ The address of the contract owner + function initialize(address owner_) public reinitializer(1) { + version = 1; + _initializeOwner(owner_); + } + + /// @notice Updates the address of the fees manager + /// @param feesManager_ The address of the fees manager + function setFeesManager(address feesManager_) external onlyOwner { + feesManager = feesManager_; + emit FeesManagerUpdated(feesManager_); + } + + /// @notice Updates the address of the default auction manager + /// @param defaultAuctionManager_ The address of the default auction manager + function setDefaultAuctionManager(address defaultAuctionManager_) external onlyOwner { + defaultAuctionManager = defaultAuctionManager_; + emit DefaultAuctionManagerUpdated(defaultAuctionManager_); + } + + /// @notice Updates the address of the watcher precompile contract + /// @param watcherPrecompile_ The address of the watcher precompile contract + function setWatcherPrecompile(address watcherPrecompile_) external onlyOwner { + watcherPrecompile__ = IWatcherPrecompile(watcherPrecompile_); + emit WatcherPrecompileUpdated(watcherPrecompile_); + } +} diff --git a/contracts/evmx/helpers/AddressResolverUtil.sol b/contracts/evmx/helpers/AddressResolverUtil.sol new file mode 100644 index 00000000..be45b206 --- /dev/null +++ b/contracts/evmx/helpers/AddressResolverUtil.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import "./interfaces/IAddressResolver.sol"; +import "./interfaces/IWatcherPrecompile.sol"; +import "./interfaces/IFeesManager.sol"; + +/// @title AddressResolverUtil +/// @notice Utility contract for resolving system contract addresses +/// @dev Provides access control and address resolution functionality for the system +abstract contract AddressResolverUtil { + /// @notice The address resolver contract reference + /// @dev Used to look up system contract addresses + // slot 0 + IAddressResolver public addressResolver__; + + // slots 1-50 reserved for future use + uint256[50] __gap_resolver_util; + + /// @notice Error thrown when an invalid address attempts to call the Watcher only function + error OnlyWatcherPrecompile(); + + /// @notice Restricts function access to the watcher precompile contract + /// @dev Validates that msg.sender matches the registered watcher precompile address + modifier onlyWatcherPrecompile() { + if (msg.sender != address(addressResolver__.watcherPrecompile__())) { + revert OnlyWatcherPrecompile(); + } + + _; + } + + /// @notice Gets the watcher precompile contract interface + /// @return IWatcherPrecompile interface of the registered watcher precompile + /// @dev Resolves and returns the watcher precompile contract for interaction + function watcherPrecompile__() public view returns (IWatcherPrecompile) { + return addressResolver__.watcherPrecompile__(); + } + + /// @notice Internal function to set the address resolver + /// @param _addressResolver The address of the resolver contract + /// @dev Should be called in the initialization of inheriting contracts + function _setAddressResolver(address _addressResolver) internal { + addressResolver__ = IAddressResolver(_addressResolver); + } + + function _getCoreAppGateway( + address originAppGateway_ + ) internal view returns (address appGateway) { + appGateway = addressResolver__.contractsToGateways(originAppGateway_); + if (appGateway == address(0)) appGateway = originAppGateway_; + } +} diff --git a/contracts/evmx/AddressResolver.sol b/contracts/evmx/helpers/AsyncDeployer.sol similarity index 70% rename from contracts/evmx/AddressResolver.sol rename to contracts/evmx/helpers/AsyncDeployer.sol index 35e9dca9..4be148df 100644 --- a/contracts/evmx/AddressResolver.sol +++ b/contracts/evmx/helpers/AsyncDeployer.sol @@ -9,66 +9,33 @@ import "./interfaces/IAddressResolver.sol"; import {Forwarder} from "./Forwarder.sol"; import {AsyncPromise} from "./AsyncPromise.sol"; -abstract contract AddressResolverStorage is IAddressResolver { +abstract contract AsyncDeployerStorage is IAddressResolver { // slots [0-49] reserved for gap uint256[50] _gap_before; // slot 50 - IWatcherPrecompile public override watcherPrecompile__; - - // slot 51 UpgradeableBeacon public forwarderBeacon; // slot 52 UpgradeableBeacon public asyncPromiseBeacon; - // slot 53 - address public override deliveryHelper; - - // slot 54 - address public override feesManager; - // slot 55 address public forwarderImplementation; // slot 56 address public asyncPromiseImplementation; - // slot 57 - address[] internal _promises; - // slot 58 uint256 public asyncPromiseCounter; - // slot 59 - uint64 public version; - address public override defaultAuctionManager; - - // slot 60 - mapping(address => address) public override contractsToGateways; - // slots [61-110] reserved for gap uint256[50] _gap_after; } -/// @title AddressResolver Contract -/// @notice This contract is responsible for fetching latest core addresses and deploying Forwarder and AsyncPromise contracts. +/// @title AsyncDeployer Contract +/// @notice This contract is responsible for deploying Forwarder and AsyncPromise contracts. /// @dev Inherits the Ownable contract and implements the IAddressResolver interface. -contract AddressResolver is AddressResolverStorage, Initializable, Ownable { - /// @notice Error thrown if AppGateway contract was already set by a different address - error InvalidAppGateway(address contractAddress_); - - /// @notice Event emitted when the delivery helper is updated - event DeliveryHelperUpdated(address deliveryHelper_); - /// @notice Event emitted when the fees manager is updated - event FeesManagerUpdated(address feesManager_); - /// @notice Event emitted when the default auction manager is updated - event DefaultAuctionManagerUpdated(address defaultAuctionManager_); - /// @notice Event emitted when the watcher precompile is updated - event WatcherPrecompileUpdated(address watcherPrecompile_); - /// @notice Event emitted when the contracts to gateways mapping is updated - event ContractsToGatewaysUpdated(address contractAddress_, address appGateway_); - +contract AsyncDeployer is AsyncDeployerStorage, Initializable, Ownable { constructor() { _disableInitializers(); // disable for implementation } @@ -201,19 +168,6 @@ contract AddressResolver is AddressResolverStorage, Initializable, Ownable { return _promises; } - /// @notice Sets the contract to gateway mapping - /// @param contractAddress_ The address of the contract - function setContractsToGateways(address contractAddress_) external { - if ( - contractsToGateways[contractAddress_] != address(0) && - contractsToGateways[contractAddress_] != msg.sender - ) { - revert InvalidAppGateway(contractAddress_); - } - contractsToGateways[contractAddress_] = msg.sender; - emit ContractsToGatewaysUpdated(contractAddress_, msg.sender); - } - /// @notice Gets the predicted address of a Forwarder proxy contract /// @param chainContractAddress_ The address of the chain contract /// @param chainSlug_ The chain slug @@ -261,32 +215,4 @@ contract AddressResolver is AddressResolverStorage, Initializable, Ownable { asyncPromiseBeacon.upgradeTo(implementation_); emit ImplementationUpdated("AsyncPromise", implementation_); } - - /// @notice Updates the address of the delivery helper - /// @param deliveryHelper_ The address of the delivery helper - function setDeliveryHelper(address deliveryHelper_) external onlyOwner { - deliveryHelper = deliveryHelper_; - emit DeliveryHelperUpdated(deliveryHelper_); - } - - /// @notice Updates the address of the fees manager - /// @param feesManager_ The address of the fees manager - function setFeesManager(address feesManager_) external onlyOwner { - feesManager = feesManager_; - emit FeesManagerUpdated(feesManager_); - } - - /// @notice Updates the address of the default auction manager - /// @param defaultAuctionManager_ The address of the default auction manager - function setDefaultAuctionManager(address defaultAuctionManager_) external onlyOwner { - defaultAuctionManager = defaultAuctionManager_; - emit DefaultAuctionManagerUpdated(defaultAuctionManager_); - } - - /// @notice Updates the address of the watcher precompile contract - /// @param watcherPrecompile_ The address of the watcher precompile contract - function setWatcherPrecompile(address watcherPrecompile_) external onlyOwner { - watcherPrecompile__ = IWatcherPrecompile(watcherPrecompile_); - emit WatcherPrecompileUpdated(watcherPrecompile_); - } } diff --git a/contracts/evmx/interfaces/IAddressResolver.sol b/contracts/evmx/interfaces/IAddressResolver.sol index 1e8684bc..ff123e69 100644 --- a/contracts/evmx/interfaces/IAddressResolver.sol +++ b/contracts/evmx/interfaces/IAddressResolver.sol @@ -33,55 +33,25 @@ interface IAddressResolver { /// @param newImplementation The new implementation address event ImplementationUpdated(string contractName, address newImplementation); - /// @notice Gets the address of the delivery helper contract - /// @return The delivery helper contract address - /// @dev Returns zero address if not configured - function deliveryHelper() external view returns (address); + // any other address resolution + function getAddress(bytes32 name) external view returns (address); - /// @notice Gets the address of the fees manager contract - /// @return The fees manager contract address - /// @dev Returns zero address if not configured - function feesManager() external view returns (address); + function setAddress(bytes32 name, address addr) external; - /// @notice Gets the address of the default auction manager contract - /// @return The auction manager contract address - /// @dev Returns zero address if not configured - function defaultAuctionManager() external view returns (address); + // System component addresses + function getWatcherPrecompile() external view returns (address); - /// @notice Gets the watcher precompile contract instance - /// @return The watcher precompile contract instance - /// @dev Returns instance with zero address if not configured - function watcherPrecompile__() external view returns (IWatcherPrecompile); + function getFeesManager() external view returns (address); - /// @notice Maps contract addresses to their corresponding gateway addresses - /// @param contractAddress_ The address of the contract to lookup - /// @return The gateway address associated with the contract - function contractsToGateways(address contractAddress_) external view returns (address); + function getDefaultAuctionManager() external view returns (address); - /// @notice Gets the list of all deployed async promise contracts - /// @return Array of async promise contract addresses - function getPromises() external view returns (address[] memory); + function getAsyncDeployer() external view returns (address); - /// @notice Maps a contract address to its gateway - /// @param contractAddress_ The contract address to map - /// @dev Creates bidirectional mapping between contract and gateway - function setContractsToGateways(address contractAddress_) external; + function setFeesManager(address feesManager_) external; - /// @notice Clears the list of deployed async promise contracts array - function clearPromises() external; + function setDefaultAuctionManager(address defaultAuctionManager_) external; - /// @notice Deploys or returns the address of a new forwarder contract if not already deployed - /// @param chainContractAddress_ The contract address on the `chainSlug_` - /// @param chainSlug_ The identifier of the chain - /// @return The address of the newly deployed forwarder contract - function getOrDeployForwarderContract( - address appGateway_, - address chainContractAddress_, - uint32 chainSlug_ - ) external returns (address); + function setWatcherPrecompile(address watcherPrecompile_) external; - /// @notice Deploys a new async promise contract - /// @param invoker_ The address that can invoke/execute the promise - /// @return The address of the newly deployed async promise contract - function deployAsyncPromiseContract(address invoker_) external returns (address); + function setAsyncDeployer(address asyncDeployer_) external; } diff --git a/contracts/evmx/interfaces/IAsyncDeployer.sol b/contracts/evmx/interfaces/IAsyncDeployer.sol new file mode 100644 index 00000000..f2699a36 --- /dev/null +++ b/contracts/evmx/interfaces/IAsyncDeployer.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +/// @title IAsyncDeployer +/// @notice Interface for deploying Forwarder and AsyncPromise contracts +/// @dev Provides address lookup functionality for core system components +interface IAsyncDeployer { + // Forwarder Management + function getOrDeployForwarderContract( + address appGateway_, + address chainContractAddress_, + uint32 chainSlug_ + ) external returns (address); + + function getForwarderAddress( + address chainContractAddress_, + uint32 chainSlug_ + ) external view returns (address); + + function setForwarderImplementation(address implementation_) external; + + // Async Promise Management + function deployAsyncPromiseContract(address invoker_) external returns (address); + + function getAsyncPromiseAddress(address invoker_) external view returns (address); + + function setAsyncPromiseImplementation(address implementation_) external; +} diff --git a/contracts/evmx/helpers/ProxyFactory.sol b/contracts/evmx/mocks/ProxyFactory.sol similarity index 100% rename from contracts/evmx/helpers/ProxyFactory.sol rename to contracts/evmx/mocks/ProxyFactory.sol diff --git a/contracts/evmx/helpers/TestUSDC.sol b/contracts/evmx/mocks/TestUSDC.sol similarity index 100% rename from contracts/evmx/helpers/TestUSDC.sol rename to contracts/evmx/mocks/TestUSDC.sol From 2cecd9de303e95c2b9353975d18d912394c0a86a Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Wed, 7 May 2025 20:37:36 +0530 Subject: [PATCH 003/130] feat: config --- ...ecompileConfig.sol => IConfigurations.sol} | 29 ++++++++-------- .../evmx/interfaces/IWatcherPrecompile.sol | 2 -- .../Configurations.sol} | 33 +++++++------------ contracts/utils/common/Structs.sol | 3 +- 4 files changed, 29 insertions(+), 38 deletions(-) rename contracts/evmx/interfaces/{IWatcherPrecompileConfig.sol => IConfigurations.sol} (74%) rename contracts/evmx/{watcherPrecompile/WatcherPrecompileConfig.sol => watcher/Configurations.sol} (91%) diff --git a/contracts/evmx/interfaces/IWatcherPrecompileConfig.sol b/contracts/evmx/interfaces/IConfigurations.sol similarity index 74% rename from contracts/evmx/interfaces/IWatcherPrecompileConfig.sol rename to contracts/evmx/interfaces/IConfigurations.sol index 491b5c91..91c70a48 100644 --- a/contracts/evmx/interfaces/IWatcherPrecompileConfig.sol +++ b/contracts/evmx/interfaces/IConfigurations.sol @@ -3,28 +3,28 @@ pragma solidity ^0.8.21; import {AppGatewayConfig, PlugConfig} from "../../utils/common/Structs.sol"; -/// @title IWatcherPrecompileConfig +/// @title IConfigurations /// @notice Interface for the Watcher Precompile system that handles payload verification and execution /// @dev Defines core functionality for payload processing and promise resolution -interface IWatcherPrecompileConfig { +interface IConfigurations { + struct SocketConfig { + address socket; + address contractFactoryPlug; + address feesPlug; + } + /// @notice The chain slug of the watcher precompile function evmxSlug() external view returns (uint32); - /// @notice Maps chain slug to their associated switchboard - function switchboards(uint32 chainSlug, bytes32 sbType) external view returns (address); - /// @notice Maps chain slug to their associated socket - function sockets(uint32 chainSlug) external view returns (address); - - /// @notice Maps chain slug to their associated contract factory plug - function contractFactoryPlug(uint32 chainSlug) external view returns (address); - - /// @notice Maps chain slug to their associated fees plug - function feesPlug(uint32 chainSlug) external view returns (address); + function socketConfigs(uint32 chainSlug) external view returns (SocketConfig memory); /// @notice Maps nonce to whether it has been used function isNonceUsed(uint256 nonce) external view returns (bool); + /// @notice Maps contract address to their associated app gateway + function coreAppGateways(address contractAddress) external view returns (address); + /// @notice Maps app gateway, chain slug and plug to validity function isValidPlug( address appGateway, @@ -54,9 +54,12 @@ interface IWatcherPrecompileConfig { address middleware_ ) external view; - function setAppGateways( + function setPlugConfigs( AppGatewayConfig[] calldata configs_, uint256 signatureNonce_, bytes calldata signature_ ) external; + + // core app gateway is msg sender + function setCoreAppGateway(address appGateway_) external; } diff --git a/contracts/evmx/interfaces/IWatcherPrecompile.sol b/contracts/evmx/interfaces/IWatcherPrecompile.sol index 1dd0dabb..0785e7d3 100644 --- a/contracts/evmx/interfaces/IWatcherPrecompile.sol +++ b/contracts/evmx/interfaces/IWatcherPrecompile.sol @@ -2,8 +2,6 @@ pragma solidity ^0.8.21; import {DigestParams, ResolvedPromises, PayloadParams, TriggerParams, PayloadSubmitParams, RequestParams} from "../../utils/common/Structs.sol"; -import {IWatcherPrecompileLimits} from "./IWatcherPrecompileLimits.sol"; -import {IWatcherPrecompileConfig} from "./IWatcherPrecompileConfig.sol"; /// @title IWatcherPrecompile /// @notice Interface for the Watcher Precompile system that handles payload verification and execution diff --git a/contracts/evmx/watcherPrecompile/WatcherPrecompileConfig.sol b/contracts/evmx/watcher/Configurations.sol similarity index 91% rename from contracts/evmx/watcherPrecompile/WatcherPrecompileConfig.sol rename to contracts/evmx/watcher/Configurations.sol index b0a3984f..4929d076 100644 --- a/contracts/evmx/watcherPrecompile/WatcherPrecompileConfig.sol +++ b/contracts/evmx/watcher/Configurations.sol @@ -4,20 +4,15 @@ pragma solidity ^0.8.21; import "solady/utils/Initializable.sol"; import {ECDSA} from "solady/utils/ECDSA.sol"; import {Ownable} from "solady/auth/Ownable.sol"; -import "../interfaces/IWatcherPrecompileConfig.sol"; +import "../interfaces/IConfigurations.sol"; import {AddressResolverUtil} from "../AddressResolverUtil.sol"; import {InvalidWatcherSignature, NonceUsed} from "../../utils/common/Errors.sol"; import "./core/WatcherIdUtils.sol"; -/// @title WatcherPrecompileConfig +/// @title Configurations /// @notice Configuration contract for the Watcher Precompile system /// @dev Handles the mapping between networks, plugs, and app gateways for payload execution -contract WatcherPrecompileConfig is - IWatcherPrecompileConfig, - Initializable, - Ownable, - AddressResolverUtil -{ +contract Configurations is IConfigurations, Initializable, Ownable, AddressResolverUtil { // slots 0-50 (51) reserved for addr resolver util // slots [51-100]: gap for future storage variables @@ -40,25 +35,21 @@ contract WatcherPrecompileConfig is // slot 104: sockets /// @notice Maps chain slug to their associated socket /// @dev chainSlug => socket address - mapping(uint32 => address) public sockets; + mapping(uint32 => SocketConfig) public socketConfigs; - // slot 105: contractFactoryPlug - /// @notice Maps chain slug to their associated contract factory plug - /// @dev chainSlug => contract factory plug address - mapping(uint32 => address) public contractFactoryPlug; + // slot 107: contractsToGateways + /// @notice Maps contract address to their associated app gateway + /// @dev contractAddress => appGateway + mapping(address => address) public coreAppGateways; - // slot 106: feesPlug - /// @notice Maps chain slug to their associated fees plug - /// @dev chainSlug => fees plug address - mapping(uint32 => address) public feesPlug; - - // slot 107: isNonceUsed + // slot 108: isNonceUsed /// @notice Maps nonce to whether it has been used /// @dev signatureNonce => isValid mapping(uint256 => bool) public isNonceUsed; - // slot 108: isValidPlug - // appGateway => chainSlug => plug => isValid + // slot 109: isValidPlug + /// @notice Maps app gateway, chain slug, and plug to whether it is valid + /// @dev appGateway => chainSlug => plug => isValid mapping(address => mapping(uint32 => mapping(address => bool))) public isValidPlug; /// @notice Emitted when a new plug is configured for an app gateway diff --git a/contracts/utils/common/Structs.sol b/contracts/utils/common/Structs.sol index 2f93bf17..0ed7c361 100644 --- a/contracts/utils/common/Structs.sol +++ b/contracts/utils/common/Structs.sol @@ -82,9 +82,8 @@ struct UpdateLimitParams { } struct AppGatewayConfig { + PlugConfig plugConfig; address plug; - bytes32 appGatewayId; - address switchboard; uint32 chainSlug; } // Plug config: From f23b3782f886f192b6cf6db36f4f9fb0692c473b Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Wed, 7 May 2025 20:54:30 +0530 Subject: [PATCH 004/130] feat: deployer gateway --- .../evmx/app-gateways/DeployerGateway.sol | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 contracts/evmx/app-gateways/DeployerGateway.sol diff --git a/contracts/evmx/app-gateways/DeployerGateway.sol b/contracts/evmx/app-gateways/DeployerGateway.sol new file mode 100644 index 00000000..caca044f --- /dev/null +++ b/contracts/evmx/app-gateways/DeployerGateway.sol @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import {AppGatewayBase} from "../base/AppGatewayBase.sol"; +import {PayloadSubmitParams, QueuePayloadParams} from "../../utils/common/Structs.sol"; + +/// @title DeployerGateway +/// @notice App gateway contract responsible for handling deployment requests +/// @dev Extends AppGatewayBase to provide deployment queueing functionality +contract DeployerGateway is AppGatewayBase { + /// @notice Emitted when a new deployment request is queued + /// @param bytecode The contract bytecode to deploy + /// @param salt The deployment salt + event DeploymentQueued(bytes bytecode, bytes32 salt); + + /// @notice Deploys a contract + /// @param contractId_ The contract ID + /// @param chainSlug_ The chain slug + function deploy( + bytes32 deploymentType_, + bytes32 contractId_, + uint32 chainSlug_, + IsPlug isPlug_, + bytes memory initCallData_ + ) external { + if (!isAsyncModifierSet) revert AsyncModifierNotUsed(); + + address asyncPromise = addressResolver__.deployAsyncPromiseContract(address(this)); + IPromise(asyncPromise).then(this.setAddress.selector, abi.encode(chainSlug_, contractId_)); + + isValidPromise[asyncPromise] = true; + onCompleteData = abi.encode(chainSlug_, true); + + QueuePayloadParams memory queuePayloadParams = QueuePayloadParams({ + chainSlug: chainSlug_, + callType: CallType.DEPLOY, + isParallel: overrideParams.isParallelCall, + isPlug: isPlug_, + writeFinality: overrideParams.writeFinality, + asyncPromise: asyncPromise, + switchboard: watcherPrecompileConfig().switchboards(chainSlug_, sbType), + target: address(0), + appGateway: address(this), + gasLimit: overrideParams.gasLimit, + value: overrideParams.value, + readAt: overrideParams.readAt, + payload: creationCodeWithArgs[contractId_], + initCallData: initCallData_ + }); + + if (queuePayloadParams.payload.length > PAYLOAD_SIZE_LIMIT) revert PayloadTooLarge(); + IMiddleware(deliveryHelper__()).queue(queuePayloadParams); + } + + /// @notice Sets the address for a deployed contract + /// @param data_ The data + /// @param returnData_ The return data + function setAddress(bytes memory data_, bytes memory returnData_) external onlyPromises { + (uint32 chainSlug, bytes32 contractId) = abi.decode(data_, (uint32, bytes32)); + address forwarderContractAddress = addressResolver__.getOrDeployForwarderContract( + address(this), + abi.decode(returnData_, (address)), + chainSlug + ); + + forwarderAddresses[contractId][chainSlug] = forwarderContractAddress; + } + + function _createDeployPayloadDetails( + QueuePayloadParams memory queuePayloadParams_ + ) internal returns (bytes memory payload, address target) { + bytes32 salt = keccak256( + abi.encode(queuePayloadParams_.appGateway, queuePayloadParams_.chainSlug, saltCounter++) + ); + + // app gateway is set in the plug deployed on chain + payload = abi.encodeWithSelector( + IContractFactoryPlug.deployContract.selector, + queuePayloadParams_.isPlug, + salt, + bytes32(uint256(uint160(queuePayloadParams_.appGateway))), + queuePayloadParams_.switchboard, + queuePayloadParams_.payload, + queuePayloadParams_.initCallData + ); + + // getting app gateway for deployer as the plug is connected to the app gateway + target = getDeliveryHelperPlugAddress(queuePayloadParams_.chainSlug); + } +} From 3f14af803ac8d07d56e2b3e7562467edf5b8d116 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Wed, 7 May 2025 20:56:16 +0530 Subject: [PATCH 005/130] feat: auction manager gateway --- .../AuctionManager.sol | 7 +-- contracts/evmx/base/AppGatewayBase.sol | 50 ------------------- contracts/evmx/{ => helpers}/AsyncPromise.sol | 0 contracts/evmx/{ => helpers}/Forwarder.sol | 0 .../ContractFactoryPlug.sol | 0 .../{payload-delivery => plugs}/FeesPlug.sol | 0 6 files changed, 2 insertions(+), 55 deletions(-) rename contracts/evmx/{payload-delivery => app-gateways}/AuctionManager.sol (97%) rename contracts/evmx/{ => helpers}/AsyncPromise.sol (100%) rename contracts/evmx/{ => helpers}/Forwarder.sol (100%) rename contracts/evmx/{payload-delivery => plugs}/ContractFactoryPlug.sol (100%) rename contracts/evmx/{payload-delivery => plugs}/FeesPlug.sol (100%) diff --git a/contracts/evmx/payload-delivery/AuctionManager.sol b/contracts/evmx/app-gateways/AuctionManager.sol similarity index 97% rename from contracts/evmx/payload-delivery/AuctionManager.sol rename to contracts/evmx/app-gateways/AuctionManager.sol index bf625c8b..9efbfc92 100644 --- a/contracts/evmx/payload-delivery/AuctionManager.sol +++ b/contracts/evmx/app-gateways/AuctionManager.sol @@ -4,13 +4,10 @@ pragma solidity ^0.8.21; import {ECDSA} from "solady/utils/ECDSA.sol"; import "solady/utils/Initializable.sol"; import "../interfaces/IAuctionManager.sol"; -import {IMiddleware} from "../interfaces/IMiddleware.sol"; -import {IFeesManager} from "../interfaces/IFeesManager.sol"; import "../../utils/AccessControl.sol"; -import {AddressResolverUtil} from "../AddressResolverUtil.sol"; import {AuctionClosed, AuctionAlreadyStarted, BidExceedsMaxFees, LowerBidAlreadyExists, InvalidTransmitter} from "../../utils/common/Errors.sol"; import {TRANSMITTER_ROLE} from "../../utils/common/AccessRoles.sol"; - +import {AppGatewayBase} from "../base/AppGatewayBase.sol"; /// @title AuctionManagerStorage /// @notice Storage for the AuctionManager contract abstract contract AuctionManagerStorage is IAuctionManager { @@ -52,7 +49,7 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, - AddressResolverUtil + AppGatewayBase { event AuctionRestarted(uint40 requestCount); event AuctionStarted(uint40 requestCount); diff --git a/contracts/evmx/base/AppGatewayBase.sol b/contracts/evmx/base/AppGatewayBase.sol index 1c8af3a6..a178d65f 100644 --- a/contracts/evmx/base/AppGatewayBase.sol +++ b/contracts/evmx/base/AppGatewayBase.sol @@ -137,56 +137,6 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { _deploy(contractId_, chainSlug_, isPlug_, new bytes(0)); } - /// @notice Deploys a contract - /// @param contractId_ The contract ID - /// @param chainSlug_ The chain slug - function _deploy( - bytes32 contractId_, - uint32 chainSlug_, - IsPlug isPlug_, - bytes memory initCallData_ - ) internal { - if (!isAsyncModifierSet) revert AsyncModifierNotUsed(); - - address asyncPromise = addressResolver__.deployAsyncPromiseContract(address(this)); - IPromise(asyncPromise).then(this.setAddress.selector, abi.encode(chainSlug_, contractId_)); - - isValidPromise[asyncPromise] = true; - onCompleteData = abi.encode(chainSlug_, true); - - QueuePayloadParams memory queuePayloadParams = QueuePayloadParams({ - chainSlug: chainSlug_, - callType: CallType.DEPLOY, - isParallel: overrideParams.isParallelCall, - isPlug: isPlug_, - writeFinality: overrideParams.writeFinality, - asyncPromise: asyncPromise, - switchboard: watcherPrecompileConfig().switchboards(chainSlug_, sbType), - target: address(0), - appGateway: address(this), - gasLimit: overrideParams.gasLimit, - value: overrideParams.value, - readAt: overrideParams.readAt, - payload: creationCodeWithArgs[contractId_], - initCallData: initCallData_ - }); - IMiddleware(deliveryHelper__()).queue(queuePayloadParams); - } - - /// @notice Sets the address for a deployed contract - /// @param data_ The data - /// @param returnData_ The return data - function setAddress(bytes memory data_, bytes memory returnData_) external onlyPromises { - (uint32 chainSlug, bytes32 contractId) = abi.decode(data_, (uint32, bytes32)); - address forwarderContractAddress = addressResolver__.getOrDeployForwarderContract( - address(this), - abi.decode(returnData_, (address)), - chainSlug - ); - - forwarderAddresses[contractId][chainSlug] = forwarderContractAddress; - } - /// @notice Gets the socket address /// @param chainSlug_ The chain slug /// @return socketAddress_ The socket address diff --git a/contracts/evmx/AsyncPromise.sol b/contracts/evmx/helpers/AsyncPromise.sol similarity index 100% rename from contracts/evmx/AsyncPromise.sol rename to contracts/evmx/helpers/AsyncPromise.sol diff --git a/contracts/evmx/Forwarder.sol b/contracts/evmx/helpers/Forwarder.sol similarity index 100% rename from contracts/evmx/Forwarder.sol rename to contracts/evmx/helpers/Forwarder.sol diff --git a/contracts/evmx/payload-delivery/ContractFactoryPlug.sol b/contracts/evmx/plugs/ContractFactoryPlug.sol similarity index 100% rename from contracts/evmx/payload-delivery/ContractFactoryPlug.sol rename to contracts/evmx/plugs/ContractFactoryPlug.sol diff --git a/contracts/evmx/payload-delivery/FeesPlug.sol b/contracts/evmx/plugs/FeesPlug.sol similarity index 100% rename from contracts/evmx/payload-delivery/FeesPlug.sol rename to contracts/evmx/plugs/FeesPlug.sol From 9a33df5f184b630381da5703f2248ecd6c78ef04 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Thu, 8 May 2025 14:11:25 +0530 Subject: [PATCH 006/130] feat: watcher storage --- .../evmx/app-gateways/AuctionManager.sol | 12 +- .../evmx/app-gateways/DeployerGateway.sol | 5 + .../WatcherPrecompileStorageAdapter.sol | 75 ++++++++ contracts/utils/common/Structs.sol | 164 +++++++----------- 4 files changed, 153 insertions(+), 103 deletions(-) create mode 100644 contracts/evmx/watcher/WatcherPrecompileStorageAdapter.sol diff --git a/contracts/evmx/app-gateways/AuctionManager.sol b/contracts/evmx/app-gateways/AuctionManager.sol index 9efbfc92..84cc5188 100644 --- a/contracts/evmx/app-gateways/AuctionManager.sol +++ b/contracts/evmx/app-gateways/AuctionManager.sol @@ -8,6 +8,7 @@ import "../../utils/AccessControl.sol"; import {AuctionClosed, AuctionAlreadyStarted, BidExceedsMaxFees, LowerBidAlreadyExists, InvalidTransmitter} from "../../utils/common/Errors.sol"; import {TRANSMITTER_ROLE} from "../../utils/common/AccessRoles.sol"; import {AppGatewayBase} from "../base/AppGatewayBase.sol"; + /// @title AuctionManagerStorage /// @notice Storage for the AuctionManager contract abstract contract AuctionManagerStorage is IAuctionManager { @@ -17,6 +18,10 @@ abstract contract AuctionManagerStorage is IAuctionManager { // slot 50 uint32 public evmxSlug; + // slot 50 + /// @notice The timeout after which a bid expires + uint128 public bidTimeout; + // slot 51 uint256 public maxReAuctionCount; @@ -45,12 +50,7 @@ abstract contract AuctionManagerStorage is IAuctionManager { /// @title AuctionManager /// @notice Contract for managing auctions and placing bids -contract AuctionManager is - AuctionManagerStorage, - Initializable, - AccessControl, - AppGatewayBase -{ +contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, AppGatewayBase { event AuctionRestarted(uint40 requestCount); event AuctionStarted(uint40 requestCount); event AuctionEnded(uint40 requestCount, Bid winningBid); diff --git a/contracts/evmx/app-gateways/DeployerGateway.sol b/contracts/evmx/app-gateways/DeployerGateway.sol index caca044f..003d5a77 100644 --- a/contracts/evmx/app-gateways/DeployerGateway.sol +++ b/contracts/evmx/app-gateways/DeployerGateway.sol @@ -8,6 +8,11 @@ import {PayloadSubmitParams, QueuePayloadParams} from "../../utils/common/Struct /// @notice App gateway contract responsible for handling deployment requests /// @dev Extends AppGatewayBase to provide deployment queueing functionality contract DeployerGateway is AppGatewayBase { + + // slot 51 + /// @notice The counter for the salt used to generate/deploy the contract address + uint256 public saltCounter; + /// @notice Emitted when a new deployment request is queued /// @param bytecode The contract bytecode to deploy /// @param salt The deployment salt diff --git a/contracts/evmx/watcher/WatcherPrecompileStorageAdapter.sol b/contracts/evmx/watcher/WatcherPrecompileStorageAdapter.sol new file mode 100644 index 00000000..ba764866 --- /dev/null +++ b/contracts/evmx/watcher/WatcherPrecompileStorageAdapter.sol @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import "../PayloadHeaderDecoder.sol"; +import "../../interfaces/IWatcherPrecompile.sol"; +import {IAppGateway} from "../../interfaces/IAppGateway.sol"; +import {IPromise} from "../../interfaces/IPromise.sol"; +import {IMiddleware} from "../../interfaces/IMiddleware.sol"; +import {InvalidCallerTriggered, TimeoutDelayTooLarge, TimeoutAlreadyResolved, InvalidInboxCaller, ResolvingTimeoutTooEarly, CallFailed, AppGatewayAlreadyCalled, InvalidWatcherSignature, NonceUsed, RequestAlreadyExecuted} from "../../../utils/common/Errors.sol"; +import {ResolvedPromises, AppGatewayConfig, LimitParams, WriteFinality, UpdateLimitParams, PlugConfig, DigestParams, TimeoutRequest, QueuePayloadParams, PayloadParams, RequestParams, RequestMetadata} from "../../../utils/common/Structs.sol"; + +/// @title WatcherPrecompileStorage +/// @notice Storage contract for the WatcherPrecompile system +/// @dev This contract contains all the storage variables used by the WatcherPrecompile system +/// @dev It is inherited by WatcherPrecompileCore and WatcherPrecompile +abstract contract WatcherPrecompileStorage is IWatcherPrecompile { + // slot 50 + /// @notice The chain slug of the watcher precompile + uint32 public evmxSlug; + + // IDs + /// @notice Counter for tracking payload requests + uint40 public payloadCounter; + + /// @notice Counter for tracking request counts + uint40 public override nextRequestCount; + + /// @notice Counter for tracking batch counts + uint40 public nextBatchCount; + + // Payload Params + /// @notice The time from finalize for the payload to be executed + /// @dev Expiry time in seconds for payload execution + uint256 public expiryTime; + + // slot 52 + /// @notice The maximum delay for a timeout + /// @dev Maximum timeout delay in seconds + uint256 public maxTimeoutDelayInSeconds; + + + // slot 54 + /// @notice The maximum message value limit for a chain + mapping(uint32 => uint256) public chainMaxMsgValueLimit; + + // slot 55 + /// @notice Maps nonce to whether it has been used + /// @dev Used to prevent replay attacks with signature nonces + /// @dev signatureNonce => isValid + mapping(uint256 => bool) public isNonceUsed; + + // slot 56 + /// @notice Mapping to store watcher proofs + /// @dev Maps payload ID to proof bytes + /// @dev payloadId => proof bytes + mapping(bytes32 => bytes) public watcherProofs; + + // slot 59 + /// @notice Mapping to store the list of payload IDs for each batch + mapping(uint40 => bytes32[]) public batchPayloadIds; + + // slot 60 + /// @notice Mapping to store the batch IDs for each request + mapping(uint40 => uint40[]) public requestBatchIds; + + // slot 61 + // queue => update to payloadParams, assign id, store in payloadParams map + /// @notice Mapping to store the payload parameters for each payload ID + mapping(bytes32 => PayloadParams) public payloads; + + // slot 53 + /// @notice The metadata for a request + mapping(uint40 => RequestParams) public requests; + +} diff --git a/contracts/utils/common/Structs.sol b/contracts/utils/common/Structs.sol index 0ed7c361..f1c2c13f 100644 --- a/contracts/utils/common/Structs.sol +++ b/contracts/utils/common/Structs.sol @@ -50,6 +50,8 @@ enum ExecutionStatus { Reverted } + +// not needed /// @notice Creates a struct to hold batch parameters struct BatchParams { address appGateway; @@ -100,21 +102,10 @@ struct TriggerParams { bytes overrides; bytes payload; } -// timeout: -struct TimeoutRequest { - address target; - uint256 delayInSeconds; - uint256 executeAt; - uint256 executedAt; - bool isResolved; - bytes payload; -} - struct ResolvedPromises { bytes32 payloadId; bytes returnData; } - // AM struct Bid { uint256 fee; @@ -122,22 +113,33 @@ struct Bid { bytes extraData; } +struct ExecuteParams { + CallType callType; + uint40 requestCount; + uint40 batchCount; + uint40 payloadCount; + uint256 deadline; + uint256 gasLimit; + uint256 value; + bytes32 prevDigestsHash; + address target; + bytes payload; + bytes extraData; +} + +struct TransmissionParams { + uint256 socketFees; + address refundAddress; + bytes extraData; + bytes transmitterSignature; +} + struct OnChainFees { uint32 chainSlug; address token; uint256 amount; } -// App gateway base: -struct OverrideParams { - Read isReadCall; - Parallel isParallelCall; - WriteFinality writeFinality; - uint256 gasLimit; - uint256 value; - uint256 readAt; -} - struct UserCredits { uint256 totalCredits; uint256 blockedCredits; @@ -157,117 +159,85 @@ struct DigestParams { bytes32 appGatewayId; bytes32 prevDigestsHash; } - -struct QueuePayloadParams { - uint32 chainSlug; - CallType callType; - Parallel isParallel; - IsPlug isPlug; +// App gateway base: +struct OverrideParams { + Read isReadCall; + Parallel isParallelCall; WriteFinality writeFinality; - address asyncPromise; - address switchboard; - address target; - address appGateway; uint256 gasLimit; uint256 value; uint256 readAt; +} + +// payload +struct Transaction { + uint32 chainSlug; + address target; bytes payload; +} + +struct DeployParam { + IsPlug isPlug; bytes initCallData; } -struct PayloadSubmitParams { - uint256 levelNumber; - uint32 chainSlug; - CallType callType; - Parallel isParallel; - WriteFinality writeFinality; +struct QueuePayloadParams { + OverrideParams overrideParams; + DeployParam deployParam; + Transaction transaction; address asyncPromise; address switchboard; address target; address appGateway; - uint256 gasLimit; - uint256 value; - uint256 readAt; - bytes payload; } struct PayloadParams { - // uint40 requestCount + uint40 batchCount + uint40 payloadCount + uint32 chainSlug - // CallType callType + Parallel isParallel + WriteFinality writeFinality - bytes32 payloadHeader; - // uint40 requestCount; - // uint40 batchCount; - // uint40 payloadCount; - // uint32 chainSlug; - // CallType callType; - // Parallel isParallel; - // WriteFinality writeFinality; + Transaction transaction; + OverrideParams overrideParams; + TimeoutRequest timeoutRequest; + uint40 requestCount; + uint40 batchCount; + uint40 payloadCount; address asyncPromise; address switchboard; - address target; address appGateway; bytes32 payloadId; bytes32 prevDigestsHash; - uint256 gasLimit; - uint256 value; - uint256 readAt; uint256 deadline; - bytes payload; address finalizedTransmitter; } +// timeout: +struct TimeoutRequest { + uint256 delayInSeconds; + uint256 executeAt; + uint256 executedAt; + bool isResolved; +} -struct RequestParams { +// request +struct RequestTrackingParams { bool isRequestCancelled; uint40 currentBatch; - // updated while processing request uint256 currentBatchPayloadsLeft; uint256 payloadsRemaining; - uint256 queryCount; - uint256 finalizeCount; - uint256 scheduleCount; - address middleware; - // updated after auction - address transmitter; - PayloadParams[] payloadParamsArray; } -struct RequestMetadata { - bool onlyReadRequests; - address consumeFrom; - address appGateway; - address auctionManager; +struct RequestFeesDetails { uint256 maxFees; uint256 queryCount; uint256 finalizeCount; + uint256 scheduleCount; + address consumeFrom; Bid winningBid; - bytes onCompleteData; -} - -struct ExecuteParams { - CallType callType; - uint40 requestCount; - uint40 batchCount; - uint40 payloadCount; - uint256 deadline; - uint256 gasLimit; - uint256 value; - bytes32 prevDigestsHash; - address target; - bytes payload; - bytes extraData; } -struct TransmissionParams { - uint256 socketFees; - address refundAddress; - bytes extraData; - bytes transmitterSignature; +struct RequestParams { + RequestTrackingParams requestTrackingParams; + RequestFeesDetails requestFeesDetails; + PayloadParams[] payloadParamsArray; + address appGateway; + address auctionManager; + bool onlyReadRequests; + bytes onCompleteData; } -struct PayloadIdParams { - uint40 requestCount; - uint40 batchCount; - uint40 payloadCount; - uint32 chainSlug; - address switchboard; -} From 3fc9c0d3d11011be31441251c1fda38bc0d1dca8 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Thu, 8 May 2025 15:01:35 +0530 Subject: [PATCH 007/130] fix: interface --- contracts/evmx/interfaces/IMiddleware.sol | 77 ------------------- .../evmx/interfaces/IWatcherPrecompile.sol | 61 +++------------ 2 files changed, 10 insertions(+), 128 deletions(-) delete mode 100644 contracts/evmx/interfaces/IMiddleware.sol diff --git a/contracts/evmx/interfaces/IMiddleware.sol b/contracts/evmx/interfaces/IMiddleware.sol deleted file mode 100644 index 3fc7d2e2..00000000 --- a/contracts/evmx/interfaces/IMiddleware.sol +++ /dev/null @@ -1,77 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -pragma solidity ^0.8.21; -import {PayloadSubmitParams, QueuePayloadParams, Bid, WriteFinality, BatchParams, CallType, Parallel, IsPlug, RequestMetadata} from "../../utils/common/Structs.sol"; - -/// @title IMiddleware -/// @notice Interface for the Middleware contract -interface IMiddleware { - /// @notice Returns the timeout after which a bid expires - function bidTimeout() external view returns (uint128); - - /// @notice Returns the metadata for a request - /// @param requestCount_ The request id - /// @return requestMetadata The metadata for the request - function getRequestMetadata( - uint40 requestCount_ - ) external view returns (RequestMetadata memory); - - /// @notice Clears the temporary queue used to store payloads for a request - function clearQueue() external; - - /// @notice Queues a payload for a request - /// @param queuePayloadParams_ The parameters for the payload - function queue(QueuePayloadParams memory queuePayloadParams_) external; - - /// @notice Batches a request - /// @param fees_ The fees for the request - /// @param auctionManager_ The address of the auction manager - /// @param onCompleteData_ The data to be passed to the onComplete callback - /// @return requestCount The request id - function batch( - uint256 fees_, - address auctionManager_, - address consumeFrom_, - bytes memory onCompleteData_ - ) external returns (uint40 requestCount); - - /// @notice Withdraws funds to a receiver - /// @param chainSlug_ The chain slug - /// @param token_ The token address - /// @param amount_ The amount to withdraw - /// @param receiver_ The receiver address - /// @param auctionManager_ The address of the auction manager - /// @param fees_ The fees for the request - function withdrawTo( - uint32 chainSlug_, - address token_, - uint256 amount_, - address receiver_, - address auctionManager_, - uint256 fees_ - ) external returns (uint40); - - /// @notice Cancels a request - /// @param requestCount_ The request id - function cancelRequest(uint40 requestCount_) external; - - /// @notice Increases the fees for a request - /// @param requestCount_ The request id - /// @param fees_ The new fees - function increaseFees(uint40 requestCount_, uint256 fees_) external; - - /// @notice Starts the request processing - /// @param requestCount_ The request id - /// @param winningBid_ The winning bid - function startRequestProcessing(uint40 requestCount_, Bid memory winningBid_) external; - - /// @notice Returns the fees for a request - function getFees(uint40 requestCount_) external view returns (uint256); - - /// @notice Finishes a request by assigning fees and calling the onComplete callback - /// @param requestCount_ The request id - function finishRequest(uint40 requestCount_) external; - - /// @notice Handles request reverts by unblocking the fees and calling the onRevert callback - /// @param requestCount_ The request id - function handleRequestReverts(uint40 requestCount_) external; -} diff --git a/contracts/evmx/interfaces/IWatcherPrecompile.sol b/contracts/evmx/interfaces/IWatcherPrecompile.sol index 0785e7d3..702347ae 100644 --- a/contracts/evmx/interfaces/IWatcherPrecompile.sol +++ b/contracts/evmx/interfaces/IWatcherPrecompile.sol @@ -99,38 +99,17 @@ interface IWatcherPrecompile { error InvalidLevelNumber(); error DeadlineNotPassedForOnChainRevert(); - /// @notice Calculates the digest hash of payload parameters - /// @param params_ The payload parameters - /// @return digest The calculated digest - function getDigest(DigestParams memory params_) external pure returns (bytes32 digest); - - /// @notice Gets the batch IDs for a request - /// @param requestCount_ The request count - /// @return Array of batch IDs - function getBatches(uint40 requestCount_) external view returns (uint40[] memory); - - /// @notice Gets the payload IDs for a batch - /// @param batchCount_ The batch count - /// @return Array of payload IDs - function getBatchPayloadIds(uint40 batchCount_) external view returns (bytes32[] memory); - - /// @notice Gets the payload parameters for a payload ID - /// @param payloadId_ The payload ID - /// @return The payload parameters - function getPayloadParams(bytes32 payloadId_) external view returns (PayloadParams memory); - - function setTimeout( - uint256 delayInSeconds_, - bytes calldata payload_ - ) external returns (bytes32); - - function resolveTimeout( - bytes32 timeoutId_, - uint256 signatureNonce_, - bytes calldata signature_ - ) external; + function queue(QueuePayloadParams[] calldata queuePayloadParams_) external; + + /// @notice Clears the temporary queue used to store payloads for a request + function clearQueue() external; - function query(PayloadParams memory params_) external; + function request() external returns (uint40 requestCount); + + /// @notice Increases the fees for a request + /// @param requestCount_ The request id + /// @param fees_ The new fees + function increaseFees(uint40 requestCount_, uint256 fees_) external; function finalized( bytes32 payloadId_, @@ -156,29 +135,9 @@ interface IWatcherPrecompile { bytes calldata signature_ ) external; - function setMaxTimeoutDelayInSeconds(uint256 maxTimeoutDelayInSeconds_) external; - - function callAppGateways( - TriggerParams[] calldata params_, - uint256 signatureNonce_, - bytes calldata signature_ - ) external; - function setExpiryTime(uint256 expiryTime_) external; - function submitRequest( - PayloadSubmitParams[] calldata payloadSubmitParams - ) external returns (uint40 requestCount); - - function startProcessingRequest(uint40 requestCount, address transmitter) external; - function getCurrentRequestCount() external view returns (uint40); - function watcherPrecompileConfig__() external view returns (IWatcherPrecompileConfig); - - function watcherPrecompileLimits__() external view returns (IWatcherPrecompileLimits); - - function getRequestParams(uint40 requestCount) external view returns (RequestParams memory); - function nextRequestCount() external view returns (uint40); } From bcb1b7f3358bed95c79e7cbaf0eb8cf45f8eea3f Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Thu, 8 May 2025 19:43:39 +0530 Subject: [PATCH 008/130] feat: specs --- .../app-gateway/DeliveryHelper.sol | 0 .../app-gateway/DeliveryUtils.sol | 0 .../app-gateway/FeesHelpers.sol | 0 .../app-gateway/RequestQueue.sol | 2 - contracts/app-gateway/RequestQueueLib.sol | 187 ++++++++ .../core/RequestHandler.sol | 1 - .../core/WatcherIdUtils.sol | 0 .../core/WatcherPrecompile.sol | 55 --- .../core/WatcherPrecompileCore.sol | 0 .../core/WatcherPrecompileStorage.sol | 14 + .../evmx/app-gateways/AuctionManager.sol | 47 +- .../evmx/app-gateways/DeployerGateway.sol | 11 +- contracts/evmx/base/AppGatewayBase.sol | 4 +- .../evmx/interfaces/IWatcherPrecompile.sol | 85 +++- .../PayloadHeaderDecoder.sol | 0 .../app-gateway/DeliveryHelperStorage.sol | 44 -- contracts/evmx/watcher/PromiseResolver.sol | 211 +++++++++ contracts/evmx/watcher/Trigger.sol | 85 ++++ .../WatcherPrecompileStorageAdapter.sol | 10 +- .../evmx/watcher/precompiles/Finalize.sol | 108 +++++ contracts/evmx/watcher/precompiles/Query.sol | 71 +++ .../evmx/watcher/precompiles/Timeout.sol | 102 +++++ .../WatcherPrecompileStorageAdapter.sol | 433 ++++++++++++++++++ contracts/utils/common/Structs.sol | 39 +- 24 files changed, 1338 insertions(+), 171 deletions(-) rename contracts/{evmx/payload-delivery => }/app-gateway/DeliveryHelper.sol (100%) rename contracts/{evmx/payload-delivery => }/app-gateway/DeliveryUtils.sol (100%) rename contracts/{evmx/payload-delivery => }/app-gateway/FeesHelpers.sol (100%) rename contracts/{evmx/payload-delivery => }/app-gateway/RequestQueue.sol (99%) create mode 100644 contracts/app-gateway/RequestQueueLib.sol rename contracts/{evmx/watcherPrecompile => }/core/RequestHandler.sol (99%) rename contracts/{evmx/watcherPrecompile => }/core/WatcherIdUtils.sol (100%) rename contracts/{evmx/watcherPrecompile => }/core/WatcherPrecompile.sol (87%) rename contracts/{evmx/watcherPrecompile => }/core/WatcherPrecompileCore.sol (100%) rename contracts/{evmx/watcherPrecompile => }/core/WatcherPrecompileStorage.sol (91%) rename contracts/evmx/{watcherPrecompile => libs}/PayloadHeaderDecoder.sol (100%) delete mode 100644 contracts/evmx/payload-delivery/app-gateway/DeliveryHelperStorage.sol create mode 100644 contracts/evmx/watcher/PromiseResolver.sol create mode 100644 contracts/evmx/watcher/Trigger.sol create mode 100644 contracts/evmx/watcher/precompiles/Finalize.sol create mode 100644 contracts/evmx/watcher/precompiles/Query.sol create mode 100644 contracts/evmx/watcher/precompiles/Timeout.sol create mode 100644 contracts/evmx/watcher/precompiles/WatcherPrecompileStorageAdapter.sol diff --git a/contracts/evmx/payload-delivery/app-gateway/DeliveryHelper.sol b/contracts/app-gateway/DeliveryHelper.sol similarity index 100% rename from contracts/evmx/payload-delivery/app-gateway/DeliveryHelper.sol rename to contracts/app-gateway/DeliveryHelper.sol diff --git a/contracts/evmx/payload-delivery/app-gateway/DeliveryUtils.sol b/contracts/app-gateway/DeliveryUtils.sol similarity index 100% rename from contracts/evmx/payload-delivery/app-gateway/DeliveryUtils.sol rename to contracts/app-gateway/DeliveryUtils.sol diff --git a/contracts/evmx/payload-delivery/app-gateway/FeesHelpers.sol b/contracts/app-gateway/FeesHelpers.sol similarity index 100% rename from contracts/evmx/payload-delivery/app-gateway/FeesHelpers.sol rename to contracts/app-gateway/FeesHelpers.sol diff --git a/contracts/evmx/payload-delivery/app-gateway/RequestQueue.sol b/contracts/app-gateway/RequestQueue.sol similarity index 99% rename from contracts/evmx/payload-delivery/app-gateway/RequestQueue.sol rename to contracts/app-gateway/RequestQueue.sol index 73a7b809..51f9bd82 100644 --- a/contracts/evmx/payload-delivery/app-gateway/RequestQueue.sol +++ b/contracts/app-gateway/RequestQueue.sol @@ -69,7 +69,6 @@ abstract contract RequestQueue is DeliveryUtils { params.finalizeCount = finalizeCount; _checkBatch(consumeFrom_, params.appGateway, params.maxFees); - return _submitBatchRequest(payloadSubmitParamsArray, consumeFrom_, params); } @@ -209,7 +208,6 @@ abstract contract RequestQueue is DeliveryUtils { (payload, target) = _createDeployPayloadDetails(queuePayloadParams_); } - if (payload.length > PAYLOAD_SIZE_LIMIT) revert PayloadTooLarge(); if (queuePayloadParams_.value > chainMaxMsgValueLimit[queuePayloadParams_.chainSlug]) revert MaxMsgValueLimitExceeded(); diff --git a/contracts/app-gateway/RequestQueueLib.sol b/contracts/app-gateway/RequestQueueLib.sol new file mode 100644 index 00000000..c7abca27 --- /dev/null +++ b/contracts/app-gateway/RequestQueueLib.sol @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import "../common/Structs.sol"; +import "../common/Errors.sol"; + +/// @title RequestQueueLib +/// @notice Pure function library for processing and validating payload request batches +/// @dev Extracted from RequestQueue contract, with storage operations removed +library RequestQueueLib { + /// @notice Validates a batch of payloads + /// @param payloadCount The number of payloads in the batch + /// @param maxPayloadCount The maximum number of payloads allowed + /// @return isValid Whether the batch is valid + function validateBatch( + uint256 payloadCount, + uint256 maxPayloadCount + ) public pure returns (bool isValid) { + return payloadCount <= maxPayloadCount; + } + + /// @notice Analyzes an array of queue payload params and creates payload submit params + /// @param queuePayloadParams An array of queue payload params + /// @return payloadSubmitParams The resulting array of payload submit params + /// @return onlyReadRequests Whether the batch contains only read requests + /// @return queryCount The number of query (read) operations + /// @return finalizeCount The number of finalize (write) operations + function createPayloadSubmitParams( + QueuePayloadParams[] memory queuePayloadParams + ) + public + pure + returns ( + PayloadSubmitParams[] memory payloadSubmitParams, + bool onlyReadRequests, + uint256 queryCount, + uint256 finalizeCount + ) + { + if (queuePayloadParams.length == 0) { + return (new PayloadSubmitParams[](0), true, 0, 0); + } + + payloadSubmitParams = new PayloadSubmitParams[](queuePayloadParams.length); + onlyReadRequests = queuePayloadParams[0].callType == CallType.READ; + + uint256 currentLevel = 0; + for (uint256 i = 0; i < queuePayloadParams.length; i++) { + if (queuePayloadParams[i].callType == CallType.READ) { + queryCount++; + } else { + onlyReadRequests = false; + finalizeCount++; + } + + // Update level for calls + if (i > 0 && queuePayloadParams[i].isParallel != Parallel.ON) { + currentLevel = currentLevel + 1; + } + + payloadSubmitParams[i] = createPayloadDetails(currentLevel, queuePayloadParams[i]); + } + } + + /// @notice Creates the payload details for a given level and queue params + /// @param level The level number for parallel execution + /// @param queueParams The queue payload parameters + /// @return payloadDetails The payload submit parameters + function createPayloadDetails( + uint256 level, + QueuePayloadParams memory queueParams + ) public pure returns (PayloadSubmitParams memory payloadDetails) { + // Skip deploy case - we're ignoring deploy-related functions + + return + PayloadSubmitParams({ + levelNumber: level, + chainSlug: queueParams.chainSlug, + callType: queueParams.callType, + isParallel: queueParams.isParallel, + writeFinality: queueParams.writeFinality, + asyncPromise: queueParams.asyncPromise, + switchboard: queueParams.switchboard, + target: queueParams.target, + appGateway: queueParams.appGateway, + gasLimit: queueParams.gasLimit == 0 ? 10_000_000 : queueParams.gasLimit, + value: queueParams.value, + readAt: queueParams.readAt, + payload: queueParams.payload + }); + } + + /// @notice Calculates fees needed for a batch + /// @param queryCount Number of read operations + /// @param finalizeCount Number of write operations + /// @param baseQueryFee Base fee for query operations + /// @param baseFinalizeFee Base fee for finalize operations + /// @return totalFees The total fees required + function calculateRequiredFees( + uint256 queryCount, + uint256 finalizeCount, + uint256 baseQueryFee, + uint256 baseFinalizeFee + ) public pure returns (uint256 totalFees) { + return (queryCount * baseQueryFee) + (finalizeCount * baseFinalizeFee); + } + + /// @notice Determines if the batch should be processed immediately + /// @param onlyReadRequests Whether the batch contains only read requests + /// @return shouldProcessImmediately Whether the batch should be processed immediately + function shouldProcessImmediately( + bool onlyReadRequests + ) public pure returns (bool shouldProcessImmediately) { + return onlyReadRequests; + } + + /// @notice Validates payload values against chain limits + /// @param payloadParams Array of payload parameters + /// @param chainValueLimits Mapping of chain slug to max value limit + /// @return isValid Whether all values are valid + function validatePayloadValues( + PayloadSubmitParams[] memory payloadParams, + mapping(uint32 => uint256) storage chainValueLimits + ) public view returns (bool isValid) { + for (uint256 i = 0; i < payloadParams.length; i++) { + uint32 chainSlug = payloadParams[i].chainSlug; + uint256 value = payloadParams[i].value; + + if (value > chainValueLimits[chainSlug]) { + return false; + } + } + return true; + } + + /// @notice Creates batch parameters from payload analysis + /// @param appGateway The application gateway address + /// @param auctionManager The auction manager address + /// @param maxFees The maximum fees allowed + /// @param onCompleteData Data to be used on batch completion + /// @param queryCount Number of read operations + /// @param finalizeCount Number of write operations + /// @param onlyReadRequests Whether the batch contains only read requests + /// @return batchParams The batch parameters + function createBatchParams( + address appGateway, + address auctionManager, + uint256 maxFees, + bytes memory onCompleteData, + uint256 queryCount, + uint256 finalizeCount, + bool onlyReadRequests + ) public pure returns (BatchParams memory batchParams) { + return + BatchParams({ + appGateway: appGateway, + auctionManager: auctionManager, + maxFees: maxFees, + onCompleteData: onCompleteData, + onlyReadRequests: onlyReadRequests, + queryCount: queryCount, + finalizeCount: finalizeCount + }); + } + + /// @notice Creates request metadata + /// @param params The batch parameters + /// @param consumeFrom Address to consume fees from + /// @return metadata The request metadata + function createRequestMetadata( + BatchParams memory params, + address consumeFrom + ) public pure returns (RequestMetadata memory metadata) { + return + RequestMetadata({ + appGateway: params.appGateway, + auctionManager: params.auctionManager, + maxFees: params.maxFees, + winningBid: Bid({fee: 0, transmitter: address(0), extraData: new bytes(0)}), + onCompleteData: params.onCompleteData, + onlyReadRequests: params.onlyReadRequests, + consumeFrom: consumeFrom, + queryCount: params.queryCount, + finalizeCount: params.finalizeCount + }); + } +} diff --git a/contracts/evmx/watcherPrecompile/core/RequestHandler.sol b/contracts/core/RequestHandler.sol similarity index 99% rename from contracts/evmx/watcherPrecompile/core/RequestHandler.sol rename to contracts/core/RequestHandler.sol index d6f620eb..661034cb 100644 --- a/contracts/evmx/watcherPrecompile/core/RequestHandler.sol +++ b/contracts/core/RequestHandler.sol @@ -135,7 +135,6 @@ abstract contract RequestHandler is WatcherPrecompileCore { /// @dev It verifies that the caller is the middleware and that the request hasn't been started yet function startProcessingRequest(uint40 requestCount, address transmitter_) public { RequestParams storage r = requestParams[requestCount]; - if (r.middleware != msg.sender) revert InvalidCaller(); if (r.transmitter != address(0)) revert AlreadyStarted(); if (r.currentBatchPayloadsLeft > 0) revert AlreadyStarted(); diff --git a/contracts/evmx/watcherPrecompile/core/WatcherIdUtils.sol b/contracts/core/WatcherIdUtils.sol similarity index 100% rename from contracts/evmx/watcherPrecompile/core/WatcherIdUtils.sol rename to contracts/core/WatcherIdUtils.sol diff --git a/contracts/evmx/watcherPrecompile/core/WatcherPrecompile.sol b/contracts/core/WatcherPrecompile.sol similarity index 87% rename from contracts/evmx/watcherPrecompile/core/WatcherPrecompile.sol rename to contracts/core/WatcherPrecompile.sol index 878ef213..f58e304f 100644 --- a/contracts/evmx/watcherPrecompile/core/WatcherPrecompile.sol +++ b/contracts/core/WatcherPrecompile.sol @@ -232,61 +232,6 @@ contract WatcherPrecompile is RequestHandler { emit MarkedRevert(payloadId_, isRevertingOnchain_); } - // ================== On-Chain Inbox ================== - - /// @notice Calls app gateways with the specified parameters - /// @param params_ Array of call from chain parameters - /// @param signatureNonce_ The nonce of the signature - /// @param signature_ The signature of the watcher - /// @dev This function calls app gateways with the specified parameters - /// @dev It verifies that the signature is valid and that the app gateway hasn't been called yet - function callAppGateways( - TriggerParams[] memory params_, - uint256 signatureNonce_, - bytes memory signature_ - ) external { - _isWatcherSignatureValid( - abi.encode(this.callAppGateways.selector, params_), - signatureNonce_, - signature_ - ); - - for (uint256 i = 0; i < params_.length; i++) { - if (appGatewayCalled[params_[i].triggerId]) revert AppGatewayAlreadyCalled(); - - address appGateway = WatcherIdUtils.decodeAppGatewayId(params_[i].appGatewayId); - if ( - !watcherPrecompileConfig__.isValidPlug( - appGateway, - params_[i].chainSlug, - params_[i].plug - ) - ) revert InvalidCallerTriggered(); - - IFeesManager(addressResolver__.feesManager()).assignWatcherPrecompileCreditsFromAddress( - watcherPrecompileLimits__.callBackFees(), - appGateway - ); - - appGatewayCaller = appGateway; - appGatewayCalled[params_[i].triggerId] = true; - - (bool success, , ) = appGateway.tryCall( - 0, - gasleft(), - 0, // setting max_copy_bytes to 0 as not using returnData right now - params_[i].payload - ); - if (!success) { - emit AppGatewayCallFailed(params_[i].triggerId); - } else { - emit CalledAppGateway(params_[i].triggerId); - } - } - - appGatewayCaller = address(0); - } - // ================== Helper functions ================== /// @notice Sets the maximum timeout delay in seconds diff --git a/contracts/evmx/watcherPrecompile/core/WatcherPrecompileCore.sol b/contracts/core/WatcherPrecompileCore.sol similarity index 100% rename from contracts/evmx/watcherPrecompile/core/WatcherPrecompileCore.sol rename to contracts/core/WatcherPrecompileCore.sol diff --git a/contracts/evmx/watcherPrecompile/core/WatcherPrecompileStorage.sol b/contracts/core/WatcherPrecompileStorage.sol similarity index 91% rename from contracts/evmx/watcherPrecompile/core/WatcherPrecompileStorage.sol rename to contracts/core/WatcherPrecompileStorage.sol index 2ef880e3..bbd65c60 100644 --- a/contracts/evmx/watcherPrecompile/core/WatcherPrecompileStorage.sol +++ b/contracts/core/WatcherPrecompileStorage.sol @@ -45,10 +45,24 @@ abstract contract WatcherPrecompileStorage is IWatcherPrecompile { /// @notice stores temporary address of the app gateway caller from a chain address public appGatewayCaller; + + // slot 52 + /// @notice The parameters array used to store payloads for a request + QueuePayloadParams[] public queuePayloadParams; + + // slot 53 + /// @notice The metadata for a request + mapping(uint40 => RequestMetadata) public requests; + // slot 54 /// @notice The prefix for timeout IDs uint256 public timeoutIdPrefix; + // slot 54 + /// @notice The maximum message value limit for a chain + mapping(uint32 => uint256) public chainMaxMsgValueLimit; + + // slot 55 /// @notice Maps nonce to whether it has been used /// @dev Used to prevent replay attacks with signature nonces diff --git a/contracts/evmx/app-gateways/AuctionManager.sol b/contracts/evmx/app-gateways/AuctionManager.sol index 84cc5188..96a66227 100644 --- a/contracts/evmx/app-gateways/AuctionManager.sol +++ b/contracts/evmx/app-gateways/AuctionManager.sol @@ -129,6 +129,7 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, // end the auction if the no auction end delay if (auctionEndDelaySeconds > 0) { _startAuction(requestCount_); + // queue and create request watcherPrecompile__().setTimeout( auctionEndDelaySeconds, abi.encodeWithSelector(this.endAuction.selector, requestCount_) @@ -147,11 +148,8 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, if (requestMetadata.auctionManager != address(this)) revert InvalidBid(); // get the total fees required for the watcher precompile ops - uint256 watcherFees = watcherPrecompileLimits().getTotalFeesRequired( - requestMetadata.queryCount, - requestMetadata.finalizeCount, - 0, - 0 + uint256 watcherFees = watcherPrecompile().getMaxFees( + requestCount_ ); return requestMetadata.maxFees - watcherFees; } @@ -170,25 +168,35 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, auctionClosed[requestCount_] = true; RequestMetadata memory requestMetadata = _getRequestMetadata(requestCount_); + // block the fees - IFeesManager(addressResolver__.feesManager()).blockCredits( - requestMetadata.consumeFrom, - winningBid.fee, - requestCount_ - ); + // in startRequestProcessing, block the fees from bid + // IFeesManager(addressResolver__.feesManager()).blockCredits( + // requestMetadata.consumeFrom, + // winningBid.fee, + // requestCount_ + // ); // set the timeout for the bid expiration // useful in case a transmitter did bid but did not execute payloads - watcherPrecompile__().setTimeout( - IMiddleware(addressResolver__.deliveryHelper()).bidTimeout(), - abi.encodeWithSelector(this.expireBid.selector, requestCount_) - ); + // todo: queue and submit timeouts + // watcherPrecompile__().timeout( + // address(this), + // abi.encodeWithSelector(this.expireBid.selector, requestCount_) + // ); // start the request processing, it will finalize the request - IMiddleware(addressResolver__.deliveryHelper()).startRequestProcessing( - requestCount_, - winningBid - ); + if(requestMetadata.transmitter != address(0)) { + IWatcherPrecompile(addressResolver__.watcherPrecompile()).updateTransmitter( + requestCount_, + winningBid + ); + } else + IWatcherPrecompile(addressResolver__.watcherPrecompile()).startRequestProcessing( + requestCount_, + winningBid + ); + } emit AuctionEnded(requestCount_, winningBid); } @@ -207,7 +215,8 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, auctionClosed[requestCount_] = false; reAuctionCount[requestCount_]++; - IFeesManager(addressResolver__.feesManager()).unblockCredits(requestCount_); + // todo: unblock credits by calling watcher for updating transmitter to addr(0) + // IFeesManager(addressResolver__.feesManager()).unblockCredits(requestCount_); emit AuctionRestarted(requestCount_); } diff --git a/contracts/evmx/app-gateways/DeployerGateway.sol b/contracts/evmx/app-gateways/DeployerGateway.sol index 003d5a77..64ea36b3 100644 --- a/contracts/evmx/app-gateways/DeployerGateway.sol +++ b/contracts/evmx/app-gateways/DeployerGateway.sol @@ -12,7 +12,7 @@ contract DeployerGateway is AppGatewayBase { // slot 51 /// @notice The counter for the salt used to generate/deploy the contract address uint256 public saltCounter; - + /// @notice Emitted when a new deployment request is queued /// @param bytecode The contract bytecode to deploy /// @param salt The deployment salt @@ -26,7 +26,8 @@ contract DeployerGateway is AppGatewayBase { bytes32 contractId_, uint32 chainSlug_, IsPlug isPlug_, - bytes memory initCallData_ + bytes memory initCallData_, + bytes memory payload_ ) external { if (!isAsyncModifierSet) revert AsyncModifierNotUsed(); @@ -49,12 +50,12 @@ contract DeployerGateway is AppGatewayBase { gasLimit: overrideParams.gasLimit, value: overrideParams.value, readAt: overrideParams.readAt, - payload: creationCodeWithArgs[contractId_], + payload: payload_, initCallData: initCallData_ }); if (queuePayloadParams.payload.length > PAYLOAD_SIZE_LIMIT) revert PayloadTooLarge(); - IMiddleware(deliveryHelper__()).queue(queuePayloadParams); + IWatcher(deliveryHelper__()).queue(queuePayloadParams); } /// @notice Sets the address for a deployed contract @@ -68,7 +69,7 @@ contract DeployerGateway is AppGatewayBase { chainSlug ); - forwarderAddresses[contractId][chainSlug] = forwarderContractAddress; + forwarderAddresses[appGateway][contractId][chainSlug] = forwarderContractAddress; } function _createDeployPayloadDetails( diff --git a/contracts/evmx/base/AppGatewayBase.sol b/contracts/evmx/base/AppGatewayBase.sol index a178d65f..2ce7ec7e 100644 --- a/contracts/evmx/base/AppGatewayBase.sol +++ b/contracts/evmx/base/AppGatewayBase.sol @@ -46,7 +46,7 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { function _postAsync() internal { isAsyncModifierSet = false; - deliveryHelper__().batch(maxFees, auctionManager, consumeFrom, onCompleteData); + watcher__().submitRequest(maxFees, auctionManager, consumeFrom, onCompleteData); _markValidPromises(); onCompleteData = bytes(""); } @@ -54,7 +54,7 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { function _preAsync(bytes memory feesApprovalData_) internal { isAsyncModifierSet = true; _clearOverrides(); - deliveryHelper__().clearQueue(); + watcher__().clearQueue(); addressResolver__.clearPromises(); _handleFeesApproval(feesApprovalData_); diff --git a/contracts/evmx/interfaces/IWatcherPrecompile.sol b/contracts/evmx/interfaces/IWatcherPrecompile.sol index 702347ae..88795fee 100644 --- a/contracts/evmx/interfaces/IWatcherPrecompile.sol +++ b/contracts/evmx/interfaces/IWatcherPrecompile.sol @@ -99,12 +99,73 @@ interface IWatcherPrecompile { error InvalidLevelNumber(); error DeadlineNotPassedForOnChainRevert(); - function queue(QueuePayloadParams[] calldata queuePayloadParams_) external; + QueueParams[] queuePayloadParams; + function queueSubmitStart(QueueParams calldata queuePayloadParams_) external; + + // queue: + function queue(QueueParams calldata queuePayloadParams_) external; + // push in queue + + // validateAndGetPrecompileData: + // finalize: verifyConnection, max msg gas limit is under limit, + // timeout: max delay + // query: + // return encoded data and fees + /// @notice Clears the temporary queue used to store payloads for a request - function clearQueue() external; + function clearQueueAndPrecompileFees() external; + + function submitRequest(address auctionManager, bytes onCompleteData) external returns (uint40 requestCount); + // { + // (params.precompileData, fees) = IPrecompile.getPrecompileData(queuePayloadParams_); + // } + // precompileFees += fees + // if coreAppGateway is not set, set it else check if it is the same + // decide level + // create id and assign counts + // store payload struct + + // set default AM if addr(0) + // total fees check from maxFees + // verify if msg sender have same core app gateway + // create and store req param + // if writeCount == 0, startProcessing else wait + + function assignTransmitter(uint40 requestCount, Bid memory bid_) external; + // validate AM from req param + // update transmitter + // assignTransmitter + // - block for new transmitter + // refinalize payloads for new transmitter + // 0 => non zero + // non zero => non zero + // - unblock credits from prev transmitter + // non zero => 0 + // - just unblock credits and return + // if(_validateProcessBatch() == true) processBatch() + + // _processBatch(); + // if a batch is already processed or in process, reprocess it for new transmitter + // deduct fee with precompile call (IPrecompile.handlePayload(payloadParams) returns fees) + // prev digest hash create + + // handlePayload: + // create digest, deadline + // emit relevant events + + function _validateProcessBatch() external; + // if request is cancelled, return + // check if all payloads from last batch are executed, else return; + // check if all payloads are executed, if yes call _settleRequest + + function _settleRequest(uint40 requestCount) external; + // if yes, call settleFees on FM and call onCompleteData in App gateway, if not success emit DataNotExecuted() + + function markPayloadResolved(uint40 requestCount, RequestParams memory requestParams) external; + // update RequestTrackingParams + // if(_validateProcessBatch() == true) processBatch() - function request() external returns (uint40 requestCount); /// @notice Increases the fees for a request /// @param requestCount_ The request id @@ -118,24 +179,10 @@ interface IWatcherPrecompile { bytes calldata signature_ ) external; - function updateTransmitter(uint40 requestCount, address transmitter) external; - function cancelRequest(uint40 requestCount) external; + // settleFees on FM - function resolvePromises( - ResolvedPromises[] calldata resolvedPromises_, - uint256 signatureNonce_, - bytes calldata signature_ - ) external; - - function markRevert( - bool isRevertingOnchain_, - bytes32 payloadId_, - uint256 signatureNonce_, - bytes calldata signature_ - ) external; - - function setExpiryTime(uint256 expiryTime_) external; + function getMaxFees(uint40 requestCount) external view returns (uint256); function getCurrentRequestCount() external view returns (uint40); diff --git a/contracts/evmx/watcherPrecompile/PayloadHeaderDecoder.sol b/contracts/evmx/libs/PayloadHeaderDecoder.sol similarity index 100% rename from contracts/evmx/watcherPrecompile/PayloadHeaderDecoder.sol rename to contracts/evmx/libs/PayloadHeaderDecoder.sol diff --git a/contracts/evmx/payload-delivery/app-gateway/DeliveryHelperStorage.sol b/contracts/evmx/payload-delivery/app-gateway/DeliveryHelperStorage.sol deleted file mode 100644 index f6fbcc15..00000000 --- a/contracts/evmx/payload-delivery/app-gateway/DeliveryHelperStorage.sol +++ /dev/null @@ -1,44 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -pragma solidity ^0.8.21; - -import "../../interfaces/IMiddleware.sol"; -import {IAddressResolver} from "../../interfaces/IAddressResolver.sol"; -import {IContractFactoryPlug} from "../../interfaces/IContractFactoryPlug.sol"; -import {IAppGateway} from "../../interfaces/IAppGateway.sol"; -import {IAuctionManager} from "../../interfaces/IAuctionManager.sol"; -import {IFeesManager} from "../../interfaces/IFeesManager.sol"; - -import {NotAuctionManager, InvalidTransmitter, InvalidIndex} from "../../../utils/common/Errors.sol"; -import {DEPLOY, PAYLOAD_SIZE_LIMIT, REQUEST_PAYLOAD_COUNT_LIMIT} from "../../../utils/common/Constants.sol"; - -/// @title DeliveryHelperStorage -/// @notice Storage contract for DeliveryHelper -abstract contract DeliveryHelperStorage is IMiddleware { - // slots [0-49] reserved for gap - uint256[50] _gap_before; - - // slot 50 - /// @notice The timeout after which a bid expires - uint128 public bidTimeout; - - // slot 51 - /// @notice The counter for the salt used to generate/deploy the contract address - uint256 public saltCounter; - - // slot 52 - /// @notice The parameters array used to store payloads for a request - QueuePayloadParams[] public queuePayloadParams; - - // slot 53 - /// @notice The metadata for a request - mapping(uint40 => RequestMetadata) public requests; - - // slot 54 - /// @notice The maximum message value limit for a chain - mapping(uint32 => uint256) public chainMaxMsgValueLimit; - - // slots [55-104] reserved for gap - uint256[50] _gap_after; - - // slots 105-155 (51) reserved for addr resolver utils -} diff --git a/contracts/evmx/watcher/PromiseResolver.sol b/contracts/evmx/watcher/PromiseResolver.sol new file mode 100644 index 00000000..83aacc90 --- /dev/null +++ b/contracts/evmx/watcher/PromiseResolver.sol @@ -0,0 +1,211 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import "../../interfaces/IWatcherPrecompile.sol"; +import "../../interfaces/IPromise.sol"; +import "../../libs/PayloadHeaderDecoder.sol"; +import "../../common/Structs.sol"; +import "../../common/Errors.sol"; +import "../../core/WatcherIdUtils.sol"; + +interface IPromiseResolver { + function resolvePromises( + ResolvedPromises[] calldata resolvedPromises_, + uint256 signatureNonce_, + bytes calldata signature_ + ) external; + + function markRevert( + bool isRevertingOnchain_, + bytes32 payloadId_, + uint256 signatureNonce_, + bytes calldata signature_ + ) external; +} + +/// @title PromiseResolver +/// @notice Contract that handles promise resolution and revert marking logic +/// @dev This contract interacts with the WatcherPrecompileStorage for storage access +contract PromiseResolver { + using PayloadHeaderDecoder for bytes32; + + // The address of the WatcherPrecompileStorage contract + address public watcherStorage; + + // Only WatcherPrecompileStorage can call functions + modifier onlyWatcherStorage() { + require(msg.sender == watcherStorage, "Only WatcherStorage can call"); + _; + } + + /// @notice Sets the WatcherPrecompileStorage address + /// @param watcherStorage_ The address of the WatcherPrecompileStorage contract + constructor(address watcherStorage_) { + watcherStorage = watcherStorage_; + } + + /// @notice Updates the WatcherPrecompileStorage address + /// @param watcherStorage_ The new address of the WatcherPrecompileStorage contract + function setWatcherStorage(address watcherStorage_) external onlyWatcherStorage { + watcherStorage = watcherStorage_; + } + + /// @notice Resolves a promise with return data + /// @param resolvedPromise The resolved promise data + /// @param requestCount The request count associated with the promise + /// @return success Whether the promise was successfully resolved + function resolvePromise( + ResolvedPromises memory resolvedPromise, + uint40 requestCount + ) external onlyWatcherStorage returns (bool success) { + // Get payload params and request params from WatcherPrecompileStorage + IWatcherPrecompile watcher = IWatcherPrecompile(watcherStorage); + PayloadParams memory payloadParams = watcher.getPayloadParams(resolvedPromise.payloadId); + + address asyncPromise = payloadParams.asyncPromise; + + // If there's no promise contract, nothing to resolve + if (asyncPromise == address(0)) { + return false; + } + + // Attempt to resolve the promise through the promise contract + bool resolutionSuccess = IPromise(asyncPromise).markResolved( + requestCount, + resolvedPromise.payloadId, + resolvedPromise.returnData + ); + + if (!resolutionSuccess) { + // Emit event through WatcherPrecompileStorage + emit IWatcherPrecompile.PromiseNotResolved(resolvedPromise.payloadId, asyncPromise); + return false; + } + + // Update storage in WatcherPrecompileStorage + watcher.updateResolvedAt(resolvedPromise.payloadId, block.timestamp); + watcher.decrementBatchCounters(requestCount); + // payloadsRemaining-- + + // Emit event through WatcherPrecompileStorage + emit IWatcherPrecompile.PromiseResolved(resolvedPromise.payloadId, asyncPromise); + + // Check if we need to process next batch + processBatch(requestCount); + + return true; + } + + /// @notice Marks a request as reverting + /// @param isRevertingOnchain Whether the request is reverting onchain + /// @param payloadId The unique identifier of the payload + /// @param currentTimestamp The current block timestamp + /// @return success Whether the request was successfully marked as reverting + function markRevert( + bool isRevertingOnchain, + bytes32 payloadId, + uint256 currentTimestamp + ) external onlyWatcherStorage returns (bool success) { + // Get payload params from WatcherPrecompileStorage + IWatcherPrecompile watcher = IWatcherPrecompile(watcherStorage); + PayloadParams memory payloadParams = watcher.getPayloadParams(payloadId); + + // Validate deadline + if (payloadParams.deadline > currentTimestamp) { + return false; + } + + uint40 requestCount = payloadParams.payloadHeader.getRequestCount(); + + // Mark request as cancelled directly in the watcher + watcher.cancelRequest(requestCount); + + // Handle onchain revert if necessary + if (isRevertingOnchain && payloadParams.asyncPromise != address(0)) { + IPromise(payloadParams.asyncPromise).markOnchainRevert(requestCount, payloadId); + } + + // Emit event through WatcherPrecompileStorage + emit IWatcherPrecompile.MarkedRevert(payloadId, isRevertingOnchain); + + return true; + } + + /// @notice Check if we need to process next batch + /// @param requestCount The request count + function _checkAndProcessBatch(uint40 requestCount) private { + IWatcherPrecompile watcher = IWatcherPrecompile(watcherStorage); + + // Check if current batch is complete and there are more payloads to process + if (shouldProcessNextBatch(requestCount)) { + // Process next batch + watcher.processNextBatch(requestCount); + } + + // Check if request is complete + if (isRequestComplete(requestCount)) { + // Finish request + watcher.finishRequest(requestCount); + } + } + + /// @notice Determines if a request is complete + /// @param payloadsRemaining Total payloads remaining for the request + /// @return isComplete Whether the request is complete + function isRequestComplete(uint256 payloadsRemaining) public pure returns (bool isComplete) { + return payloadsRemaining == 0; + } + + /// @notice Validates that a promise can be resolved + /// @param payloadId The unique identifier of the payload + /// @param requestCount The request count + /// @return isValid Whether the promise can be resolved + function validatePromiseResolution( + bytes32 payloadId, + uint40 requestCount + ) external view returns (bool isValid) { + if (payloadId == bytes32(0) || requestCount == 0) return false; + + IWatcherPrecompile watcher = IWatcherPrecompile(watcherStorage); + // Check if the request has been cancelled + if (watcher.isRequestCancelled(requestCount)) return false; + + // Check if the promise has already been executed + if (watcher.isPromiseExecuted(payloadId)) return false; + + return true; + } + + /// @notice Validates that a request can be marked as reverting + /// @param payloadId The unique identifier of the payload + /// @param deadline The deadline for the payload execution + /// @param currentTimestamp The current block timestamp + /// @return isValid Whether the request can be marked as reverting + function validateRevertMarking( + bytes32 payloadId, + uint256 deadline, + uint256 currentTimestamp + ) external view returns (bool isValid) { + if (payloadId == bytes32(0)) return false; + if (deadline > currentTimestamp) return false; + + IWatcherPrecompile watcher = IWatcherPrecompile(watcherStorage); + uint40 requestCount = watcher.getRequestCountFromPayloadId(payloadId); + + // Check if the request has already been cancelled + if (watcher.isRequestCancelled(requestCount)) return false; + + return true; + } + + /// @notice Determines if a batch should be processed next + /// @param currentBatchPayloadsLeft Number of payloads left in current batch + /// @param payloadsRemaining Total payloads remaining + /// @return shouldProcess Whether next batch should be processed + function shouldProcessNextBatch( + uint256 currentBatchPayloadsLeft, + uint256 payloadsRemaining + ) public pure returns (bool shouldProcess) { + return currentBatchPayloadsLeft == 0 && payloadsRemaining > 0; + } +} diff --git a/contracts/evmx/watcher/Trigger.sol b/contracts/evmx/watcher/Trigger.sol new file mode 100644 index 00000000..4579e18d --- /dev/null +++ b/contracts/evmx/watcher/Trigger.sol @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +/// @title Trigger +/// @notice Contract that handles trigger validation and execution logic +/// @dev This contract interacts with the WatcherPrecompileStorage for storage access +contract Trigger { + // The address of the WatcherPrecompileStorage contract + address public watcherStorage; + + /// @notice stores temporary address of the app gateway caller from a chain + address public appGatewayCaller; + + // slot 57 + /// @notice Mapping to store if appGateway has been called with trigger from on-chain Inbox + /// @dev Maps call ID to boolean indicating if the appGateway has been called + /// @dev callId => bool + mapping(bytes32 => bool) public appGatewayCalled; + + + // Only WatcherPrecompileStorage can call functions + modifier onlyWatcherStorage() { + require(msg.sender == watcherStorage, "Only WatcherStorage can call"); + _; + } + + /// @notice Sets the WatcherPrecompileStorage address + /// @param watcherStorage_ The address of the WatcherPrecompileStorage contract + constructor(address watcherStorage_) { + watcherStorage = watcherStorage_; + } + + /// @notice Updates the WatcherPrecompileStorage address + /// @param watcherStorage_ The new address of the WatcherPrecompileStorage contract + function setWatcherStorage(address watcherStorage_) external onlyWatcherStorage { + watcherStorage = watcherStorage_; + } + + /// @notice Calls app gateways with the specified parameters + /// @param params_ Array of call from chain parameters + /// @param signatureNonce_ The nonce of the signature + /// @param signature_ The signature of the watcher + /// @dev This function calls app gateways with the specified parameters + /// @dev It verifies that the signature is valid and that the app gateway hasn't been called yet + function callAppGateways( + TriggerParams[] memory params_, + uint256 signatureNonce_, + bytes memory signature_ + ) external onlyWatcherStorage { + for (uint256 i = 0; i < params_.length; i++) { + if (appGatewayCalled[params_[i].triggerId]) revert AppGatewayAlreadyCalled(); + + address appGateway = WatcherIdUtils.decodeAppGatewayId(params_[i].appGatewayId); + if ( + !watcherPrecompileConfig__.isValidPlug( + appGateway, + params_[i].chainSlug, + params_[i].plug + ) + ) revert InvalidCallerTriggered(); + + IFeesManager(addressResolver__.feesManager()).assignWatcherPrecompileCreditsFromAddress( + watcherPrecompileLimits__.callBackFees(), + appGateway + ); + + appGatewayCaller = appGateway; + appGatewayCalled[params_[i].triggerId] = true; + + (bool success, , ) = appGateway.tryCall( + 0, + gasleft(), + 0, // setting max_copy_bytes to 0 as not using returnData right now + params_[i].payload + ); + if (!success) { + emit AppGatewayCallFailed(params_[i].triggerId); + } else { + emit CalledAppGateway(params_[i].triggerId); + } + } + + appGatewayCaller = address(0); + } +} diff --git a/contracts/evmx/watcher/WatcherPrecompileStorageAdapter.sol b/contracts/evmx/watcher/WatcherPrecompileStorageAdapter.sol index ba764866..e5de87f4 100644 --- a/contracts/evmx/watcher/WatcherPrecompileStorageAdapter.sol +++ b/contracts/evmx/watcher/WatcherPrecompileStorageAdapter.sol @@ -38,7 +38,6 @@ abstract contract WatcherPrecompileStorage is IWatcherPrecompile { /// @dev Maximum timeout delay in seconds uint256 public maxTimeoutDelayInSeconds; - // slot 54 /// @notice The maximum message value limit for a chain mapping(uint32 => uint256) public chainMaxMsgValueLimit; @@ -62,7 +61,7 @@ abstract contract WatcherPrecompileStorage is IWatcherPrecompile { // slot 60 /// @notice Mapping to store the batch IDs for each request mapping(uint40 => uint40[]) public requestBatchIds; - + // slot 61 // queue => update to payloadParams, assign id, store in payloadParams map /// @notice Mapping to store the payload parameters for each payload ID @@ -71,5 +70,12 @@ abstract contract WatcherPrecompileStorage is IWatcherPrecompile { // slot 53 /// @notice The metadata for a request mapping(uint40 => RequestParams) public requests; +} + +contract WatcherPrecompileStorageAdapter is WatcherPrecompileStorage { + + // all function from watcher requiring signature + function watcherUpdater(address[] callData contracts, bytes[] callData data_, uint256[] calldata nonces_, bytes[] callData signatures_) { + } } diff --git a/contracts/evmx/watcher/precompiles/Finalize.sol b/contracts/evmx/watcher/precompiles/Finalize.sol new file mode 100644 index 00000000..61ddc26e --- /dev/null +++ b/contracts/evmx/watcher/precompiles/Finalize.sol @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import "../../interfaces/IWatcherPrecompile.sol"; +import "../../interfaces/IFeesManager.sol"; +import "../../interfaces/IMiddleware.sol"; +import "../../libs/PayloadHeaderDecoder.sol"; +import "../../core/WatcherIdUtils.sol"; +import "../../../utils/common/Structs.sol"; +import "../../../utils/common/Errors.sol"; + +/// @title Finalize +/// @notice Library that handles finalization logic for the WatcherPrecompile system +/// @dev This library contains pure functions for finalization operations +library Finalize { + using PayloadHeaderDecoder for bytes32; + + /// @notice Calculates the digest hash of payload parameters + /// @param params_ The payload parameters to calculate the digest for + /// @return digest The calculated digest hash + /// @dev This function creates a keccak256 hash of the payload parameters + function getDigest(DigestParams memory params_) public pure returns (bytes32 digest) { + digest = keccak256( + abi.encode( + params_.socket, + params_.transmitter, + params_.payloadId, + params_.deadline, + params_.callType, + params_.gasLimit, + params_.value, + params_.payload, + params_.target, + params_.appGatewayId, + params_.prevDigestsHash, + bytes("") + ) + ); + } + + /// @notice Prepares the parameters needed for finalization + /// @param params_ The payload parameters to be finalized + /// @param transmitter_ The address of the transmitter + /// @param chainSlug The chain slug where the finalization is happening + /// @param evmxSlug The EVMx chain slug + /// @param deadline The deadline for the finalization + /// @param socketsAddress The address of the sockets contract + /// @param middleware The address of the middleware contract + /// @param prevDigestsHash The hash of previous batch digests + /// @return digestParams The digest parameters for the finalization + function prepareDigestParams( + PayloadParams memory params_, + address transmitter_, + uint32 chainSlug, + uint32 evmxSlug, + uint256 deadline, + address socketsAddress, + address middleware, + bytes32 prevDigestsHash + ) public pure returns (DigestParams memory digestParams) { + // Verify that the app gateway is properly configured for this chain and target + // This verification would happen in the storage contract + + // Construct parameters for digest calculation + digestParams = DigestParams( + socketsAddress, + transmitter_, + params_.payloadId, + deadline, + params_.payloadHeader.getCallType(), + params_.gasLimit, + params_.value, + params_.payload, + params_.target, + WatcherIdUtils.encodeAppGatewayId(params_.appGateway), + prevDigestsHash + ); + } + + /// @notice Processes the finalization of a proof + /// @param payloadId_ The unique identifier of the request + /// @param proof_ The watcher's proof + /// @param signatureData Encoded signature data for verification + /// @return The verification result indicating whether the finalization was successful + function processFinalization( + bytes32 payloadId_, + bytes memory proof_, + bytes memory signatureData + ) public pure returns (bool) { + // This is just the logic for processing finalization + // Actual storage updates would happen in the storage contract + + // The return value indicates whether the verification was successful + // In the actual implementation, this would be used to determine whether to update storage + return signatureData.length > 0 && proof_.length > 0 && payloadId_ != bytes32(0); + } + + /// @notice Creates the event data for finalization + /// @param payloadId_ The unique identifier of the request + /// @param proof_ The watcher's proof + /// @return The encoded event data for finalization + function createFinalizedEventData( + bytes32 payloadId_, + bytes memory proof_ + ) public pure returns (bytes memory) { + return abi.encode(payloadId_, proof_); + } +} diff --git a/contracts/evmx/watcher/precompiles/Query.sol b/contracts/evmx/watcher/precompiles/Query.sol new file mode 100644 index 00000000..869139f1 --- /dev/null +++ b/contracts/evmx/watcher/precompiles/Query.sol @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import "../../interfaces/IWatcherPrecompile.sol"; +import "../../libs/PayloadHeaderDecoder.sol"; +import "../../../utils/common/Structs.sol"; +import "../../../utils/common/Errors.sol"; + +/// @title Query +/// @notice Library that handles query logic for the WatcherPrecompile system +/// @dev This library contains pure functions for query operations +library Query { + using PayloadHeaderDecoder for bytes32; + + /// @notice Validates query parameters + /// @param params_ The payload parameters for the query + /// @return isValid Whether the query parameters are valid + function validateQueryParams(PayloadParams memory params_) public pure returns (bool isValid) { + // Query is valid if it has a valid payload ID and target + return params_.payloadId != bytes32(0) && params_.target != address(0); + } + + /// @notice Prepares the batch of payload parameters for a given batch count + /// @param payloadParams Array of payload parameters to process + /// @return An array of validated PayloadParams for the batch + function prepareBatch( + PayloadParams[] memory payloadParams + ) public pure returns (PayloadParams[] memory) { + // Batch logic would normally involve storage interactions + // This function provides the pure logic for preparation + return payloadParams; + } + + /// @notice Creates the event data for a query request + /// @param params_ The payload parameters for the query + /// @return The encoded event data for query request + function createQueryRequestEventData( + PayloadParams memory params_ + ) public pure returns (bytes memory) { + return abi.encode(params_); + } + + /// @notice Validates batch parameters for query processing + /// @param batchCount The batch count to validate + /// @param requestCount The request count to validate + /// @return isValid Whether the batch parameters are valid + function validateBatchParams( + uint40 batchCount, + uint40 requestCount + ) public pure returns (bool isValid) { + return batchCount > 0 && requestCount > 0; + } + + /// @notice Prepares parameters for batch processing + /// @param payloadParamsArray Array of payload parameters + /// @param batchSize The size of the batch + /// @return totalPayloads The number of payloads to process + function prepareBatchProcessing( + PayloadParams[] memory payloadParamsArray, + uint256 batchSize + ) public pure returns (uint256 totalPayloads) { + // Validate and count payloads that should be processed + uint256 total = 0; + for (uint256 i = 0; i < payloadParamsArray.length && i < batchSize; i++) { + if (validateQueryParams(payloadParamsArray[i])) { + total++; + } + } + return total; + } +} diff --git a/contracts/evmx/watcher/precompiles/Timeout.sol b/contracts/evmx/watcher/precompiles/Timeout.sol new file mode 100644 index 00000000..67fcf6c5 --- /dev/null +++ b/contracts/evmx/watcher/precompiles/Timeout.sol @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import "../../interfaces/IWatcherPrecompile.sol"; +import "../../../utils/common/Structs.sol"; +import "../../../utils/common/Errors.sol"; + +/// @title Timeout +/// @notice Library that handles timeout logic for the WatcherPrecompile system +/// @dev This library contains pure functions for timeout operations +library Timeout { + /// @notice Validates timeout parameters + /// @param delayInSeconds_ The delay in seconds before the timeout executes + /// @param maxTimeoutDelayInSeconds The maximum allowed timeout delay + /// @return isValid Whether the timeout parameters are valid + function validateTimeoutParams( + uint256 delayInSeconds_, + uint256 maxTimeoutDelayInSeconds + ) public pure returns (bool isValid) { + return delayInSeconds_ <= maxTimeoutDelayInSeconds; + } + + /// @notice Encodes a unique timeout ID + /// @param timeoutIdPrefix The prefix for timeout IDs + /// @param counter The counter value to include in the ID + /// @return timeoutId The encoded timeout ID + function encodeTimeoutId( + uint256 timeoutIdPrefix, + uint256 counter + ) public pure returns (bytes32 timeoutId) { + // Encode timeout ID by bit-shifting and combining: + // EVMx chainSlug (32 bits) | watcher precompile address (160 bits) | counter (64 bits) + return bytes32(timeoutIdPrefix | counter); + } + + /// @notice Prepares a timeout request + /// @param target The target address for the timeout callback + /// @param delayInSeconds_ The delay in seconds before the timeout executes + /// @param executeAt The timestamp when the timeout should be executed + /// @param payload_ The payload data to be executed after the timeout + /// @return request The prepared timeout request + function prepareTimeoutRequest( + address target, + uint256 delayInSeconds_, + uint256 executeAt, + bytes memory payload_ + ) public pure returns (TimeoutRequest memory request) { + request.target = target; + request.delayInSeconds = delayInSeconds_; + request.executeAt = executeAt; + request.payload = payload_; + request.isResolved = false; + request.executedAt = 0; + return request; + } + + /// @notice Validates timeout resolution conditions + /// @param request The timeout request to validate + /// @param currentTimestamp The current block timestamp + /// @return isValid Whether the timeout can be resolved + function validateTimeoutResolution( + TimeoutRequest memory request, + uint256 currentTimestamp + ) public pure returns (bool isValid) { + if (request.target == address(0)) return false; + if (request.isResolved) return false; + if (currentTimestamp < request.executeAt) return false; + return true; + } + + /// @notice Creates the event data for timeout request + /// @param timeoutId The unique identifier for the timeout + /// @param target The target address for the timeout callback + /// @param payload The payload data to be executed + /// @param executeAt The timestamp when the timeout should be executed + /// @return The encoded event data for timeout request + function createTimeoutRequestEventData( + bytes32 timeoutId, + address target, + bytes memory payload, + uint256 executeAt + ) public pure returns (bytes memory) { + return abi.encode(timeoutId, target, payload, executeAt); + } + + /// @notice Creates the event data for timeout resolution + /// @param timeoutId The unique identifier for the timeout + /// @param target The target address for the timeout callback + /// @param payload The payload data that was executed + /// @param executedAt The timestamp when the timeout was executed + /// @param returnData The return data from the timeout execution + /// @return The encoded event data for timeout resolution + function createTimeoutResolvedEventData( + bytes32 timeoutId, + address target, + bytes memory payload, + uint256 executedAt, + bytes memory returnData + ) public pure returns (bytes memory) { + return abi.encode(timeoutId, target, payload, executedAt, returnData); + } +} diff --git a/contracts/evmx/watcher/precompiles/WatcherPrecompileStorageAdapter.sol b/contracts/evmx/watcher/precompiles/WatcherPrecompileStorageAdapter.sol new file mode 100644 index 00000000..db5d9dbd --- /dev/null +++ b/contracts/evmx/watcher/precompiles/WatcherPrecompileStorageAdapter.sol @@ -0,0 +1,433 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import "solady/utils/ECDSA.sol"; +import "solady/auth/Ownable.sol"; +import "solady/utils/LibCall.sol"; +import "solady/utils/Initializable.sol"; + +import "../../../interfaces/IWatcherPrecompile.sol"; +import "../../../interfaces/IFeesManager.sol"; +import "../../../interfaces/IMiddleware.sol"; +import "../../../interfaces/IPromise.sol"; +import "../../PayloadHeaderDecoder.sol"; +import "../../core/WatcherIdUtils.sol"; +import "../../../utils/common/Structs.sol"; +import "../../../utils/common/Errors.sol"; +import "../../../AddressResolverUtil.sol"; +import "./Finalize.sol"; +import "./Timeout.sol"; +import "./Query.sol"; + +/// @title WatcherPrecompileStorageAdapter +/// @notice Contract that manages storage and interacts with pure function libraries +/// @dev This contract serves as an adapter between the storage and the pure function libraries +contract WatcherPrecompileStorageAdapter is + IWatcherPrecompile, + Initializable, + Ownable, + AddressResolverUtil +{ + using LibCall for address; + using PayloadHeaderDecoder for bytes32; + using Finalize for bytes; + + // Storage variables similar to WatcherPrecompileStorage + uint32 public evmxSlug; + uint40 public payloadCounter; + uint40 public override nextRequestCount; + uint40 public nextBatchCount; + uint256 public expiryTime; + uint256 public maxTimeoutDelayInSeconds; + address public appGatewayCaller; + uint256 public timeoutIdPrefix; + + mapping(uint256 => bool) public isNonceUsed; + mapping(bytes32 => TimeoutRequest) public timeoutRequests; + mapping(bytes32 => bytes) public watcherProofs; + mapping(bytes32 => bool) public appGatewayCalled; + mapping(uint40 => RequestParams) public requestParams; + mapping(uint40 => bytes32[]) public batchPayloadIds; + mapping(uint40 => uint40[]) public requestBatchIds; + mapping(bytes32 => PayloadParams) public payloads; + mapping(bytes32 => bool) public isPromiseExecuted; + IWatcherPrecompileLimits public watcherPrecompileLimits__; + IWatcherPrecompileConfig public watcherPrecompileConfig__; + mapping(uint40 => RequestMetadata) public requestMetadata; + + /// @notice Constructor that disables initializers for the implementation + constructor() { + _disableInitializers(); + } + + /// @notice Initializes the contract with the required parameters + /// @param owner_ The address of the owner + /// @param addressResolver_ The address of the address resolver + /// @param expiryTime_ The expiry time for payload execution + /// @param evmxSlug_ The EVM chain slug + /// @param watcherPrecompileLimits_ The address of the watcher precompile limits contract + /// @param watcherPrecompileConfig_ The address of the watcher precompile config contract + function initialize( + address owner_, + address addressResolver_, + uint256 expiryTime_, + uint32 evmxSlug_, + address watcherPrecompileLimits_, + address watcherPrecompileConfig_ + ) public reinitializer(1) { + _setAddressResolver(addressResolver_); + _initializeOwner(owner_); + + watcherPrecompileLimits__ = IWatcherPrecompileLimits(watcherPrecompileLimits_); + watcherPrecompileConfig__ = IWatcherPrecompileConfig(watcherPrecompileConfig_); + maxTimeoutDelayInSeconds = 24 * 60 * 60; // 24 hours + expiryTime = expiryTime_; + evmxSlug = evmxSlug_; + + timeoutIdPrefix = (uint256(evmxSlug_) << 224) | (uint256(uint160(address(this))) << 64); + } + + // ================== Timeout functions ================== + + /// @notice Sets a timeout for a payload execution on app gateway + /// @param delayInSeconds_ The delay in seconds before the timeout executes + /// @param payload_ The payload data to be executed after the timeout + /// @return The unique identifier for the timeout request + function setTimeout(uint256 delayInSeconds_, bytes memory payload_) external returns (bytes32) { + if (!Timeout.validateTimeoutParams(delayInSeconds_, maxTimeoutDelayInSeconds)) + revert TimeoutDelayTooLarge(); + + _consumeCallbackFeesFromAddress(watcherPrecompileLimits__.timeoutFees(), msg.sender); + + uint256 executeAt = block.timestamp + delayInSeconds_; + bytes32 timeoutId = Timeout.encodeTimeoutId(timeoutIdPrefix, payloadCounter++); + + timeoutRequests[timeoutId] = Timeout.prepareTimeoutRequest( + msg.sender, + delayInSeconds_, + executeAt, + payload_ + ); + + // Emit event for watcher to track timeout and resolve when timeout is reached + emit TimeoutRequested(timeoutId, msg.sender, payload_, executeAt); + return timeoutId; + } + + /// @notice Resolves a timeout + /// @param timeoutId_ The unique identifier for the timeout + /// @param signatureNonce_ The nonce used in the watcher's signature + /// @param signature_ The watcher's signature + function resolveTimeout( + bytes32 timeoutId_, + uint256 signatureNonce_, + bytes memory signature_ + ) external { + _isWatcherSignatureValid( + abi.encode(this.resolveTimeout.selector, timeoutId_), + signatureNonce_, + signature_ + ); + + TimeoutRequest storage timeoutRequest_ = timeoutRequests[timeoutId_]; + if (!Timeout.validateTimeoutResolution(timeoutRequest_, block.timestamp)) { + if (timeoutRequest_.target == address(0)) revert InvalidTimeoutRequest(); + if (timeoutRequest_.isResolved) revert TimeoutAlreadyResolved(); + revert ResolvingTimeoutTooEarly(); + } + + (bool success, , bytes memory returnData) = timeoutRequest_.target.tryCall( + 0, + gasleft(), + 0, // setting max_copy_bytes to 0 as not using returnData right now + timeoutRequest_.payload + ); + if (!success) revert CallFailed(); + + timeoutRequest_.isResolved = true; + timeoutRequest_.executedAt = block.timestamp; + + emit TimeoutResolved( + timeoutId_, + timeoutRequest_.target, + timeoutRequest_.payload, + block.timestamp, + returnData + ); + } + + // ================== Query functions ================== + + /// @notice Creates a new query request + /// @param params_ The payload parameters + function query(PayloadParams memory params_) external { + if (!Query.validateQueryParams(params_)) revert InvalidQueryParams(); + + _consumeCallbackFeesFromRequestCount( + watcherPrecompileLimits__.queryFees(), + params_.payloadHeader.getRequestCount() + ); + + payloads[params_.payloadId].prevDigestsHash = _getPreviousDigestsHash( + params_.payloadHeader.getBatchCount() + ); + + emit QueryRequested(params_); + } + + /// @notice Marks a request as finalized with a proof on digest + /// @param payloadId_ The unique identifier of the request + /// @param proof_ The watcher's proof + /// @param signatureNonce_ The nonce of the signature + /// @param signature_ The signature of the watcher + function finalized( + bytes32 payloadId_, + bytes memory proof_, + uint256 signatureNonce_, + bytes memory signature_ + ) external { + _isWatcherSignatureValid( + abi.encode(this.finalized.selector, payloadId_, proof_), + signatureNonce_, + signature_ + ); + + // Process finalization using the Finalize library + if (Finalize.processFinalization(payloadId_, proof_, signature_)) { + watcherProofs[payloadId_] = proof_; + emit Finalized(payloadId_, proof_); + } + } + + /// @notice Resolves multiple promises with their return data + /// @param resolvedPromises_ Array of resolved promises and their return data + /// @param signatureNonce_ The nonce of the signature + /// @param signature_ The signature of the watcher + function resolvePromises( + ResolvedPromises[] memory resolvedPromises_, + uint256 signatureNonce_, + bytes memory signature_ + ) external { + _isWatcherSignatureValid( + abi.encode(this.resolvePromises.selector, resolvedPromises_), + signatureNonce_, + signature_ + ); + + for (uint256 i = 0; i < resolvedPromises_.length; i++) { + uint40 requestCount = payloads[resolvedPromises_[i].payloadId] + .payloadHeader + .getRequestCount(); + RequestParams storage requestParams_ = requestParams[requestCount]; + + if (Query.validatePromiseResolution(resolvedPromises_[i], requestCount)) { + _processPromiseResolution(resolvedPromises_[i], requestParams_); + _checkAndProcessBatch(requestParams_, requestCount); + } + } + } + + // ================== Helper functions ================== + + /// @notice Sets the maximum timeout delay in seconds + /// @param maxTimeoutDelayInSeconds_ The maximum timeout delay in seconds + function setMaxTimeoutDelayInSeconds(uint256 maxTimeoutDelayInSeconds_) external onlyOwner { + maxTimeoutDelayInSeconds = maxTimeoutDelayInSeconds_; + emit MaxTimeoutDelayInSecondsSet(maxTimeoutDelayInSeconds_); + } + + /// @notice Sets the expiry time for payload execution + /// @param expiryTime_ The expiry time in seconds + function setExpiryTime(uint256 expiryTime_) external onlyOwner { + expiryTime = expiryTime_; + emit ExpiryTimeSet(expiryTime_); + } + + /// @notice Verifies that a watcher signature is valid + /// @param inputData_ The input data to verify + /// @param signatureNonce_ The nonce of the signature + /// @param signature_ The signature to verify + function _isWatcherSignatureValid( + bytes memory inputData_, + uint256 signatureNonce_, + bytes memory signature_ + ) internal { + if (isNonceUsed[signatureNonce_]) revert NonceUsed(); + isNonceUsed[signatureNonce_] = true; + + bytes32 digest = keccak256( + abi.encode(address(this), evmxSlug, signatureNonce_, inputData_) + ); + digest = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", digest)); + + address signer = ECDSA.recover(digest, signature_); + if (signer != owner()) revert InvalidWatcherSignature(); + } + + /// @notice Process promise resolution + function _processPromiseResolution( + ResolvedPromises memory resolvedPromise_, + RequestParams storage requestParams_ + ) internal { + PayloadParams memory payloadParams = payloads[resolvedPromise_.payloadId]; + address asyncPromise = payloadParams.asyncPromise; + uint40 requestCount = payloadParams.payloadHeader.getRequestCount(); + + if (asyncPromise != address(0)) { + bool success = IPromise(asyncPromise).markResolved( + requestCount, + resolvedPromise_.payloadId, + resolvedPromise_.returnData + ); + + if (!success) { + emit PromiseNotResolved(resolvedPromise_.payloadId, asyncPromise); + return; + } + } + + isPromiseExecuted[resolvedPromise_.payloadId] = true; + requestParams_.currentBatchPayloadsLeft--; + requestParams_.payloadsRemaining--; + + emit PromiseResolved(resolvedPromise_.payloadId, asyncPromise); + } + + /// @notice Check and process batch + function _checkAndProcessBatch( + RequestParams storage requestParams_, + uint40 requestCount + ) internal { + if (requestParams_.currentBatchPayloadsLeft == 0 && requestParams_.payloadsRemaining > 0) { + _processBatch(requestCount, ++requestParams_.currentBatch); + } + + if (requestParams_.payloadsRemaining == 0) { + IMiddleware(requestParams_.middleware).finishRequest(requestCount); + } + } + + /// @notice Process batch + function _processBatch(uint40 requestCount_, uint40 batchCount_) internal { + RequestParams storage r = requestParams[requestCount_]; + PayloadParams[] memory payloadParamsArray = _getBatch(batchCount_); + if (r.isRequestCancelled) revert RequestCancelled(); + + uint256 totalPayloads = 0; + for (uint40 i = 0; i < payloadParamsArray.length; i++) { + if (isPromiseExecuted[payloadParamsArray[i].payloadId]) continue; + totalPayloads++; + + if (payloadParamsArray[i].payloadHeader.getCallType() != CallType.READ) { + _finalize(payloadParamsArray[i], r.transmitter); + } else { + query(payloadParamsArray[i]); + } + } + + r.currentBatchPayloadsLeft = totalPayloads; + } + + /// @notice Finalizes a payload request + function _finalize( + PayloadParams memory params_, + address transmitter_ + ) internal returns (bytes32) { + uint32 chainSlug = params_.payloadHeader.getChainSlug(); + + // Verify that the app gateway is properly configured for this chain and target + watcherPrecompileConfig__.verifyConnections( + chainSlug, + params_.target, + params_.appGateway, + params_.switchboard, + requestParams[params_.payloadHeader.getRequestCount()].middleware + ); + + _consumeCallbackFeesFromRequestCount( + watcherPrecompileLimits__.finalizeFees(), + params_.payloadHeader.getRequestCount() + ); + + uint256 deadline = block.timestamp + expiryTime; + payloads[params_.payloadId].deadline = deadline; + payloads[params_.payloadId].finalizedTransmitter = transmitter_; + + bytes32 prevDigestsHash = _getPreviousDigestsHash(params_.payloadHeader.getBatchCount()); + payloads[params_.payloadId].prevDigestsHash = prevDigestsHash; + + // Use the Finalize library to prepare digest parameters + DigestParams memory digestParams = Finalize.prepareDigestParams( + params_, + transmitter_, + chainSlug, + evmxSlug, + deadline, + watcherPrecompileConfig__.sockets(chainSlug), + requestParams[params_.payloadHeader.getRequestCount()].middleware, + prevDigestsHash + ); + + // Calculate digest from payload parameters + bytes32 digest = Finalize.getDigest(digestParams); + emit FinalizeRequested(digest, payloads[params_.payloadId]); + + return digest; + } + + /// @notice Gets the hash of previous batch digests + function _getPreviousDigestsHash(uint40 batchCount_) internal view returns (bytes32) { + bytes32[] memory payloadIds = batchPayloadIds[batchCount_]; + bytes32 prevDigestsHash = bytes32(0); + + for (uint40 i = 0; i < payloadIds.length; i++) { + PayloadParams memory p = payloads[payloadIds[i]]; + DigestParams memory digestParams = DigestParams( + watcherPrecompileConfig__.sockets(p.payloadHeader.getChainSlug()), + p.finalizedTransmitter, + p.payloadId, + p.deadline, + p.payloadHeader.getCallType(), + p.gasLimit, + p.value, + p.payload, + p.target, + WatcherIdUtils.encodeAppGatewayId(p.appGateway), + p.prevDigestsHash + ); + prevDigestsHash = keccak256( + abi.encodePacked(prevDigestsHash, Finalize.getDigest(digestParams)) + ); + } + return prevDigestsHash; + } + + /// @notice Gets the batch of payload parameters for a given batch count + function _getBatch(uint40 batchCount) internal view returns (PayloadParams[] memory) { + bytes32[] memory payloadIds = batchPayloadIds[batchCount]; + PayloadParams[] memory payloadParamsArray = new PayloadParams[](payloadIds.length); + + for (uint40 i = 0; i < payloadIds.length; i++) { + payloadParamsArray[i] = payloads[payloadIds[i]]; + } + return payloadParamsArray; + } + + /// @notice Consume callback fees from request count + function _consumeCallbackFeesFromRequestCount(uint256 fees_, uint40 requestCount_) internal { + // for callbacks in all precompiles + uint256 feesToConsume = fees_ + watcherPrecompileLimits__.callBackFees(); + IFeesManager(addressResolver__.feesManager()) + .assignWatcherPrecompileCreditsFromRequestCount(feesToConsume, requestCount_); + } + + /// @notice Consume callback fees from address + function _consumeCallbackFeesFromAddress(uint256 fees_, address consumeFrom_) internal { + // for callbacks in all precompiles + uint256 feesToConsume = fees_ + watcherPrecompileLimits__.callBackFees(); + IFeesManager(addressResolver__.feesManager()).assignWatcherPrecompileCreditsFromAddress( + feesToConsume, + consumeFrom_ + ); + } +} diff --git a/contracts/utils/common/Structs.sol b/contracts/utils/common/Structs.sol index f1c2c13f..6fdeb289 100644 --- a/contracts/utils/common/Structs.sol +++ b/contracts/utils/common/Structs.sol @@ -5,7 +5,7 @@ pragma solidity ^0.8.21; enum CallType { READ, WRITE, - DEPLOY + SCHEDULE } enum IsPlug { @@ -50,8 +50,7 @@ enum ExecutionStatus { Reverted } - -// not needed +// not needed /// @notice Creates a struct to hold batch parameters struct BatchParams { address appGateway; @@ -161,7 +160,7 @@ struct DigestParams { } // App gateway base: struct OverrideParams { - Read isReadCall; + CallType callType; Parallel isParallelCall; WriteFinality writeFinality; uint256 gasLimit; @@ -181,40 +180,39 @@ struct DeployParam { bytes initCallData; } -struct QueuePayloadParams { +struct QueueParams { OverrideParams overrideParams; - DeployParam deployParam; Transaction transaction; address asyncPromise; address switchboard; - address target; - address appGateway; } struct PayloadParams { - Transaction transaction; - OverrideParams overrideParams; - TimeoutRequest timeoutRequest; uint40 requestCount; uint40 batchCount; uint40 payloadCount; address asyncPromise; - address switchboard; address appGateway; bytes32 payloadId; bytes32 prevDigestsHash; - uint256 deadline; - address finalizedTransmitter; + uint256 resolvedAt; + bytes precompileData; + + // uint256 deadline; + // address finalizedTransmitter; + // Transaction transaction; + // OverrideParams overrideParams; + // TimeoutRequest timeoutRequest; + // address switchboard; } // timeout: struct TimeoutRequest { uint256 delayInSeconds; uint256 executeAt; - uint256 executedAt; bool isResolved; } -// request +// request struct RequestTrackingParams { bool isRequestCancelled; uint40 currentBatch; @@ -224,9 +222,7 @@ struct RequestTrackingParams { struct RequestFeesDetails { uint256 maxFees; - uint256 queryCount; - uint256 finalizeCount; - uint256 scheduleCount; + uint256 watcherFees; address consumeFrom; Bid winningBid; } @@ -234,10 +230,9 @@ struct RequestFeesDetails { struct RequestParams { RequestTrackingParams requestTrackingParams; RequestFeesDetails requestFeesDetails; - PayloadParams[] payloadParamsArray; address appGateway; address auctionManager; - bool onlyReadRequests; + uint256 finalizeCount; + bool isRequestExecuted; bytes onCompleteData; } - From 8efdaec6c6d82a70cbaded05b4036e93194f2f39 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Fri, 9 May 2025 15:30:38 +0530 Subject: [PATCH 009/130] feat: forwarder --- contracts/evmx/base/AppGatewayBase.sol | 19 ++-------- .../evmx/helpers/AddressResolverUtil.sol | 14 ++------ contracts/evmx/helpers/Forwarder.sol | 35 ++++++------------- contracts/evmx/interfaces/IAppGateway.sol | 14 ++------ 4 files changed, 20 insertions(+), 62 deletions(-) diff --git a/contracts/evmx/base/AppGatewayBase.sol b/contracts/evmx/base/AppGatewayBase.sol index 2ce7ec7e..2b2fa9b7 100644 --- a/contracts/evmx/base/AppGatewayBase.sol +++ b/contracts/evmx/base/AppGatewayBase.sol @@ -156,8 +156,7 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { return address(0); } - onChainAddress = IForwarder(forwarderAddresses[contractId_][chainSlug_]) - .getOnChainAddress(); + onChainAddress = IForwarder(forwarderAddresses[contractId_][chainSlug_]).getOnChainAddress(); } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -258,20 +257,8 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { maxFees = fees_; } - function getOverrideParams() - public - view - returns (Read, Parallel, WriteFinality, uint256, uint256, uint256, bytes32) - { - return ( - overrideParams.isReadCall, - overrideParams.isParallelCall, - overrideParams.writeFinality, - overrideParams.readAt, - overrideParams.gasLimit, - overrideParams.value, - sbType - ); + function getOverrideParams() public view returns (OverrideParams, bytes32) { + return (overrideParams, sbType); } //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/contracts/evmx/helpers/AddressResolverUtil.sol b/contracts/evmx/helpers/AddressResolverUtil.sol index be45b206..0a917b00 100644 --- a/contracts/evmx/helpers/AddressResolverUtil.sol +++ b/contracts/evmx/helpers/AddressResolverUtil.sol @@ -1,9 +1,8 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import "./interfaces/IAddressResolver.sol"; -import "./interfaces/IWatcherPrecompile.sol"; -import "./interfaces/IFeesManager.sol"; +import "../interfaces/IAddressResolver.sol"; +import "../interfaces/IWatcherPrecompile.sol"; /// @title AddressResolverUtil /// @notice Utility contract for resolving system contract addresses @@ -19,7 +18,7 @@ abstract contract AddressResolverUtil { /// @notice Error thrown when an invalid address attempts to call the Watcher only function error OnlyWatcherPrecompile(); - + /// @notice Restricts function access to the watcher precompile contract /// @dev Validates that msg.sender matches the registered watcher precompile address modifier onlyWatcherPrecompile() { @@ -43,11 +42,4 @@ abstract contract AddressResolverUtil { function _setAddressResolver(address _addressResolver) internal { addressResolver__ = IAddressResolver(_addressResolver); } - - function _getCoreAppGateway( - address originAppGateway_ - ) internal view returns (address appGateway) { - appGateway = addressResolver__.contractsToGateways(originAppGateway_); - if (appGateway == address(0)) appGateway = originAppGateway_; - } } diff --git a/contracts/evmx/helpers/Forwarder.sol b/contracts/evmx/helpers/Forwarder.sol index f6d214c2..34b91131 100644 --- a/contracts/evmx/helpers/Forwarder.sol +++ b/contracts/evmx/helpers/Forwarder.sol @@ -92,7 +92,7 @@ contract Forwarder is ForwarderStorage, Initializable, AddressResolverUtil { /// @notice Fallback function to process the contract calls to onChainAddress /// @dev It queues the calls in the middleware and deploys the promise contract fallback() external { - if (address(deliveryHelper__()) == address(0)) { + if (address(watcherPrecompile__()) == address(0)) { revert DeliveryHelperNotSet(); } @@ -108,36 +108,23 @@ contract Forwarder is ForwarderStorage, Initializable, AddressResolverUtil { latestRequestCount = watcherPrecompile__().nextRequestCount(); // fetch the override params from app gateway - ( - Read isReadCall, - Parallel isParallelCall, - WriteFinality writeFinality, - uint256 readAt, - uint256 gasLimit, - uint256 value, - bytes32 sbType - ) = IAppGateway(msg.sender).getOverrideParams(); + (OverrideParams overrideParams, bytes32 sbType) = IAppGateway(msg.sender) + .getOverrideParams(); // get the switchboard address from the watcher precompile config address switchboard = watcherPrecompileConfig().switchboards(chainSlug, sbType); // Queue the call in the middleware. - deliveryHelper__().queue( + watcherPrecompile__().queue( QueuePayloadParams({ - chainSlug: chainSlug, - callType: isReadCall == Read.ON ? CallType.READ : CallType.WRITE, - isParallel: isParallelCall, - isPlug: IsPlug.NO, - writeFinality: writeFinality, + overrideParams: overrideParams, + transaction: Transaction({ + chainSlug: chainSlug, + target: onChainAddress, + payload: msg.data + }), asyncPromise: latestAsyncPromise, - switchboard: switchboard, - target: onChainAddress, - appGateway: msg.sender, - gasLimit: gasLimit, - value: value, - readAt: readAt, - payload: msg.data, - initCallData: bytes("") + switchboard: switchboard }) ); } diff --git a/contracts/evmx/interfaces/IAppGateway.sol b/contracts/evmx/interfaces/IAppGateway.sol index 7036cd43..f6d3a2a1 100644 --- a/contracts/evmx/interfaces/IAppGateway.sol +++ b/contracts/evmx/interfaces/IAppGateway.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import {Read, Parallel, QueuePayloadParams, OverrideParams, WriteFinality, PayloadParams} from "../../utils/common/Structs.sol"; +import {OverrideParams} from "../../utils/common/Structs.sol"; /// @title IAppGateway /// @notice Interface for the app gateway @@ -11,17 +11,9 @@ interface IAppGateway { function isAsyncModifierSet() external view returns (bool); /// @notice Gets the override parameters - /// @return read_ The read parameters - /// @return parallel_ The parallel parameters - /// @return writeFinality_ The write finality parameters - /// @return readTimeout_ The read timeout - /// @return writeTimeout_ The write timeout - /// @return writeFinalityTimeout_ The write finality timeout + /// @return overrideParams_ The override parameters /// @return sbType_ The switchboard type - function getOverrideParams() - external - view - returns (Read, Parallel, WriteFinality, uint256, uint256, uint256, bytes32); + function getOverrideParams() external view returns (OverrideParams memory, bytes32); /// @notice Handles the request complete event /// @param requestCount_ The request count From 1039f46d9c9f3d7c3181d9c0208571a333957b00 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Fri, 9 May 2025 15:30:50 +0530 Subject: [PATCH 010/130] feat: configurations --- contracts/evmx/interfaces/IConfigurations.sol | 14 +--- contracts/evmx/watcher/Configurations.sol | 65 +++++-------------- 2 files changed, 21 insertions(+), 58 deletions(-) diff --git a/contracts/evmx/interfaces/IConfigurations.sol b/contracts/evmx/interfaces/IConfigurations.sol index 91c70a48..d2374574 100644 --- a/contracts/evmx/interfaces/IConfigurations.sol +++ b/contracts/evmx/interfaces/IConfigurations.sol @@ -19,9 +19,6 @@ interface IConfigurations { /// @notice Maps chain slug to their associated socket function socketConfigs(uint32 chainSlug) external view returns (SocketConfig memory); - /// @notice Maps nonce to whether it has been used - function isNonceUsed(uint256 nonce) external view returns (bool); - /// @notice Maps contract address to their associated app gateway function coreAppGateways(address contractAddress) external view returns (address); @@ -50,16 +47,11 @@ interface IConfigurations { uint32 chainSlug_, address target_, address appGateway_, - address switchboard_, - address middleware_ + address switchboard_ ) external view; - function setPlugConfigs( - AppGatewayConfig[] calldata configs_, - uint256 signatureNonce_, - bytes calldata signature_ - ) external; + function setPlugConfigs(AppGatewayConfig[] calldata configs_) external; - // core app gateway is msg sender + /// @notice Sets the core app gateway for the watcher precompile function setCoreAppGateway(address appGateway_) external; } diff --git a/contracts/evmx/watcher/Configurations.sol b/contracts/evmx/watcher/Configurations.sol index 4929d076..a119b927 100644 --- a/contracts/evmx/watcher/Configurations.sol +++ b/contracts/evmx/watcher/Configurations.sol @@ -102,17 +102,7 @@ contract Configurations is IConfigurations, Initializable, Ownable, AddressResol /// @dev Only callable by the watcher /// @dev This helps in verifying that plugs are called by respective app gateways /// @param configs_ Array of configurations containing app gateway, network, plug, and switchboard details - function setAppGateways( - AppGatewayConfig[] calldata configs_, - uint256 signatureNonce_, - bytes calldata signature_ - ) external { - _isWatcherSignatureValid( - abi.encode(this.setAppGateways.selector, configs_), - signatureNonce_, - signature_ - ); - + function setPlugConfigs(AppGatewayConfig[] calldata configs_) external onlyWatcherPrecompile { for (uint256 i = 0; i < configs_.length; i++) { // Store the plug configuration for this network and plug _plugConfigs[configs_[i].chainSlug][configs_[i].plug] = PlugConfig({ @@ -128,15 +118,15 @@ contract Configurations is IConfigurations, Initializable, Ownable, AddressResol /// @param chainSlug_ The identifier of the network function setOnChainContracts( uint32 chainSlug_, - address socket_, - address contractFactoryPlug_, - address feesPlug_ - ) external onlyOwner { - sockets[chainSlug_] = socket_; - contractFactoryPlug[chainSlug_] = contractFactoryPlug_; - feesPlug[chainSlug_] = feesPlug_; - - emit OnChainContractSet(chainSlug_, socket_, contractFactoryPlug_, feesPlug_); + SocketConfig memory socketConfig_ + ) external onlyWatcherPrecompile { + socketConfigs[chainSlug_] = socketConfig_; + emit OnChainContractSet( + chainSlug_, + socketConfig_.socket, + socketConfig_.contractFactoryPlug, + socketConfig_.feesPlug + ); } /// @notice Sets the switchboard for a network @@ -147,7 +137,7 @@ contract Configurations is IConfigurations, Initializable, Ownable, AddressResol uint32 chainSlug_, bytes32 sbType_, address switchboard_ - ) external onlyOwner { + ) external onlyWatcherPrecompile { switchboards[chainSlug_][sbType_] = switchboard_; emit SwitchboardSet(chainSlug_, sbType_, switchboard_); } @@ -163,6 +153,11 @@ contract Configurations is IConfigurations, Initializable, Ownable, AddressResol emit IsValidPlugSet(msg.sender, chainSlug_, plug_, isValid_); } + function setCoreAppGateway(address appGateway_) external { + coreAppGateways[appGateway_] = msg.sender; + emit CoreAppGatewaySet(appGateway_, msg.sender); + } + /// @notice Retrieves the configuration for a specific plug on a network /// @dev Returns zero addresses if configuration doesn't exist /// @param chainSlug_ The identifier of the network @@ -189,35 +184,11 @@ contract Configurations is IConfigurations, Initializable, Ownable, AddressResol uint32 chainSlug_, address target_, address appGateway_, - address switchboard_, - address middleware_ + address switchboard_ ) external view { - // if target is contractFactoryPlug, return - // as connection is with middleware delivery helper and not app gateway - if ( - middleware_ == address(deliveryHelper__()) && target_ == contractFactoryPlug[chainSlug_] - ) return; - (bytes32 appGatewayId, address switchboard) = getPlugConfigs(chainSlug_, target_); + if (appGatewayId != WatcherIdUtils.encodeAppGatewayId(appGateway_)) revert InvalidGateway(); if (switchboard != switchboard_) revert InvalidSwitchboard(); } - - function _isWatcherSignatureValid( - bytes memory inputData_, - uint256 signatureNonce_, - bytes memory signature_ - ) internal { - if (isNonceUsed[signatureNonce_]) revert NonceUsed(); - isNonceUsed[signatureNonce_] = true; - - bytes32 digest = keccak256( - abi.encode(address(this), evmxSlug, signatureNonce_, inputData_) - ); - digest = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", digest)); - - // recovered signer is checked for the valid roles later - address signer = ECDSA.recover(digest, signature_); - if (signer != owner()) revert InvalidWatcherSignature(); - } } From 0aba364c86e781f100d2f52fea46b9a680cd2183 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Fri, 9 May 2025 17:53:47 +0530 Subject: [PATCH 011/130] rm: old code --- contracts/app-gateway/DeliveryHelper.sol | 25 - contracts/app-gateway/DeliveryUtils.sol | 92 ---- contracts/app-gateway/FeesHelpers.sol | 99 ---- contracts/app-gateway/RequestQueue.sol | 12 +- contracts/app-gateway/RequestQueueLib.sol | 187 -------- contracts/core/RequestHandler.sol | 7 +- contracts/core/WatcherPrecompile.sol | 320 ------------- contracts/core/WatcherPrecompileCore.sol | 53 +-- contracts/core/WatcherPrecompileStorage.sol | 125 ----- contracts/evmx/fees/FeesManager.sol | 63 +++ contracts/evmx/interfaces/IPrecompile.sol | 20 + .../evmx/interfaces/IWatcherPrecompile.sol | 3 - .../{core => evmx/libs}/WatcherIdUtils.sol | 0 contracts/evmx/watcher/PromiseResolver.sol | 203 +++----- contracts/evmx/watcher/RequestHandler.sol | 121 +++++ .../WatcherPrecompileStorageAdapter.sol | 106 ++++- .../evmx/watcher/precompiles/Finalize.sol | 125 ++--- contracts/evmx/watcher/precompiles/Query.sol | 81 ++-- .../evmx/watcher/precompiles/Timeout.sol | 14 + .../WatcherPrecompileStorageAdapter.sol | 433 ------------------ contracts/utils/common/Structs.sol | 2 +- 21 files changed, 451 insertions(+), 1640 deletions(-) delete mode 100644 contracts/app-gateway/DeliveryUtils.sol delete mode 100644 contracts/app-gateway/FeesHelpers.sol delete mode 100644 contracts/app-gateway/RequestQueueLib.sol delete mode 100644 contracts/core/WatcherPrecompile.sol delete mode 100644 contracts/core/WatcherPrecompileStorage.sol create mode 100644 contracts/evmx/interfaces/IPrecompile.sol rename contracts/{core => evmx/libs}/WatcherIdUtils.sol (100%) create mode 100644 contracts/evmx/watcher/RequestHandler.sol delete mode 100644 contracts/evmx/watcher/precompiles/WatcherPrecompileStorageAdapter.sol diff --git a/contracts/app-gateway/DeliveryHelper.sol b/contracts/app-gateway/DeliveryHelper.sol index 24a78e3b..9536bedf 100644 --- a/contracts/app-gateway/DeliveryHelper.sol +++ b/contracts/app-gateway/DeliveryHelper.sol @@ -6,23 +6,6 @@ import "./FeesHelpers.sol"; /// @title DeliveryHelper /// @notice Contract for managing payload delivery contract DeliveryHelper is FeesHelpers { - constructor() { - _disableInitializers(); // disable for implementation - } - - /// @notice Initializer function to replace constructor - /// @param addressResolver_ The address resolver contract - /// @param owner_ The owner address - function initialize( - address addressResolver_, - address owner_, - uint128 bidTimeout_ - ) public reinitializer(1) { - _setAddressResolver(addressResolver_); - _initializeOwner(owner_); - - bidTimeout = bidTimeout_; - } /// @notice Calls the watcher precompile to start processing a request /// @dev If a transmitter was already assigned, it updates the transmitter in watcher precompile too @@ -104,12 +87,4 @@ contract DeliveryHelper is FeesHelpers { } } - /// @notice Returns the request metadata - /// @param requestCount_ The ID of the request - /// @return requestMetadata The request metadata - function getRequestMetadata( - uint40 requestCount_ - ) external view returns (RequestMetadata memory) { - return requests[requestCount_]; - } } diff --git a/contracts/app-gateway/DeliveryUtils.sol b/contracts/app-gateway/DeliveryUtils.sol deleted file mode 100644 index 14dc88bb..00000000 --- a/contracts/app-gateway/DeliveryUtils.sol +++ /dev/null @@ -1,92 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -pragma solidity ^0.8.21; - -import "solady/utils/Initializable.sol"; -import {Ownable} from "solady/auth/Ownable.sol"; -import {AddressResolverUtil} from "../../AddressResolverUtil.sol"; -import "./DeliveryHelperStorage.sol"; - -/// @notice Abstract contract for managing asynchronous payloads -abstract contract DeliveryUtils is - DeliveryHelperStorage, - Initializable, - Ownable, - AddressResolverUtil -{ - // slots [156-206] reserved for gap - uint256[50] _gap_delivery_utils; - - /// @notice Error thrown if payload is too large - error PayloadTooLarge(); - /// @notice Error thrown if trying to cancel a batch without being the application gateway - error OnlyAppGateway(); - /// @notice Error thrown when a winning bid exists - error WinningBidExists(); - /// @notice Error thrown when a bid is insufficient - error InsufficientFees(); - /// @notice Error thrown when a request contains only reads - error ReadOnlyRequests(); - - /// @notice Error thrown when a request contains more than 10 payloads - error RequestPayloadCountLimitExceeded(); - /// @notice Error thrown when a maximum message value limit is exceeded - error MaxMsgValueLimitExceeded(); - - event BidTimeoutUpdated(uint256 newBidTimeout); - - /// @notice Emitted when a payload is submitted - event PayloadSubmitted( - uint40 indexed requestCount, - address indexed appGateway, - PayloadSubmitParams[] payloadSubmitParams, - uint256 fees, - address auctionManager, - bool onlyReadRequests - ); - - /// @notice Emitted when fees are increased - event FeesIncreased( - address indexed appGateway, - uint40 indexed requestCount, - uint256 newMaxFees - ); - /// @notice Emitted when chain max message value limits are updated - event ChainMaxMsgValueLimitsUpdated(uint32[] chainSlugs, uint256[] maxMsgValueLimits); - /// @notice Emitted when a request is cancelled - event RequestCancelled(uint40 indexed requestCount); - - modifier onlyAuctionManager(uint40 requestCount_) { - if (msg.sender != requests[requestCount_].auctionManager) revert NotAuctionManager(); - _; - } - - /// @notice Gets the payload delivery plug address - /// @param chainSlug_ The chain identifier - /// @return address The address of the payload delivery plug - function getDeliveryHelperPlugAddress(uint32 chainSlug_) public view returns (address) { - return watcherPrecompileConfig().contractFactoryPlug(chainSlug_); - } - - /// @notice Updates the bid timeout - /// @param newBidTimeout_ The new bid timeout value - function updateBidTimeout(uint128 newBidTimeout_) external onlyOwner { - bidTimeout = newBidTimeout_; - emit BidTimeoutUpdated(newBidTimeout_); - } - - /// @notice Updates the maximum message value limit for multiple chains - /// @param chainSlugs_ Array of chain identifiers - /// @param maxMsgValueLimits_ Array of corresponding maximum message value limits - function updateChainMaxMsgValueLimits( - uint32[] calldata chainSlugs_, - uint256[] calldata maxMsgValueLimits_ - ) external onlyOwner { - if (chainSlugs_.length != maxMsgValueLimits_.length) revert InvalidIndex(); - - for (uint256 i = 0; i < chainSlugs_.length; i++) { - chainMaxMsgValueLimit[chainSlugs_[i]] = maxMsgValueLimits_[i]; - } - - emit ChainMaxMsgValueLimitsUpdated(chainSlugs_, maxMsgValueLimits_); - } -} diff --git a/contracts/app-gateway/FeesHelpers.sol b/contracts/app-gateway/FeesHelpers.sol deleted file mode 100644 index f1845865..00000000 --- a/contracts/app-gateway/FeesHelpers.sol +++ /dev/null @@ -1,99 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -pragma solidity ^0.8.21; - -import "./RequestQueue.sol"; - -/// @title RequestAsync -/// @notice Abstract contract for managing asynchronous payload batches -abstract contract FeesHelpers is RequestQueue { - // slots [258-308] reserved for gap - uint256[50] _gap_batch_async; - - error NewMaxFeesLowerThanCurrent(uint256 current, uint256 new_); - - /// @notice Increases the fees for a request if no bid is placed - /// @param requestCount_ The ID of the request - /// @param newMaxFees_ The new maximum fees - function increaseFees(uint40 requestCount_, uint256 newMaxFees_) external override { - address appGateway = _getCoreAppGateway(msg.sender); - // todo: should we allow core app gateway too? - if (appGateway != requests[requestCount_].appGateway) { - revert OnlyAppGateway(); - } - if (requests[requestCount_].winningBid.transmitter != address(0)) revert WinningBidExists(); - if (requests[requestCount_].maxFees >= newMaxFees_) - revert NewMaxFeesLowerThanCurrent(requests[requestCount_].maxFees, newMaxFees_); - requests[requestCount_].maxFees = newMaxFees_; - emit FeesIncreased(appGateway, requestCount_, newMaxFees_); - } - - /// @notice Withdraws funds to a specified receiver - /// @param chainSlug_ The chain identifier - /// @param token_ The address of the token - /// @param amount_ The amount of tokens to withdraw - /// @param receiver_ The address of the receiver - /// @param fees_ The fees data - function withdrawTo( - uint32 chainSlug_, - address token_, - uint256 amount_, - address receiver_, - address auctionManager_, - uint256 fees_ - ) external returns (uint40) { - IFeesManager(addressResolver__.feesManager()).withdrawCredits( - msg.sender, - chainSlug_, - token_, - amount_, - receiver_ - ); - return _batch(msg.sender, auctionManager_, msg.sender, fees_, bytes("")); - } - - /// @notice Withdraws fees to a specified receiver - /// @param chainSlug_ The chain identifier - /// @param token_ The token address - /// @param receiver_ The address of the receiver - function withdrawTransmitterFees( - uint32 chainSlug_, - address token_, - address receiver_, - uint256 amount_ - ) external returns (uint40 requestCount) { - address transmitter = msg.sender; - - PayloadSubmitParams[] memory payloadSubmitParamsArray = IFeesManager( - addressResolver__.feesManager() - ).getWithdrawTransmitterCreditsPayloadParams( - transmitter, - chainSlug_, - token_, - receiver_, - amount_ - ); - - RequestMetadata memory requestMetadata = RequestMetadata({ - appGateway: addressResolver__.feesManager(), - auctionManager: address(0), - maxFees: 0, - winningBid: Bid({transmitter: transmitter, fee: 0, extraData: new bytes(0)}), - onCompleteData: bytes(""), - onlyReadRequests: false, - consumeFrom: transmitter, - queryCount: 0, - finalizeCount: 1 - }); // finalize for plug contract - requestCount = watcherPrecompile__().submitRequest(payloadSubmitParamsArray); - requests[requestCount] = requestMetadata; - // same transmitter can execute requests without auction - watcherPrecompile__().startProcessingRequest(requestCount, transmitter); - } - - /// @notice Returns the fees for a request - /// @param requestCount_ The ID of the request - /// @return fees The fees data - function getFees(uint40 requestCount_) external view returns (uint256) { - return requests[requestCount_].maxFees; - } -} diff --git a/contracts/app-gateway/RequestQueue.sol b/contracts/app-gateway/RequestQueue.sol index 51f9bd82..c4adcc5e 100644 --- a/contracts/app-gateway/RequestQueue.sol +++ b/contracts/app-gateway/RequestQueue.sol @@ -8,17 +8,7 @@ abstract contract RequestQueue is DeliveryUtils { // slots [207-257] reserved for gap uint256[50] _gap_queue_async; - /// @notice Clears the call parameters array - function clearQueue() public { - delete queuePayloadParams; - } - - /// @notice Queues a new payload - /// @param queuePayloadParams_ The call parameters - function queue(QueuePayloadParams memory queuePayloadParams_) external { - queuePayloadParams.push(queuePayloadParams_); - } - + /// @notice Initiates a batch of payloads /// @param maxFees_ The fees data /// @param auctionManager_ The auction manager address diff --git a/contracts/app-gateway/RequestQueueLib.sol b/contracts/app-gateway/RequestQueueLib.sol deleted file mode 100644 index c7abca27..00000000 --- a/contracts/app-gateway/RequestQueueLib.sol +++ /dev/null @@ -1,187 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -pragma solidity ^0.8.21; - -import "../common/Structs.sol"; -import "../common/Errors.sol"; - -/// @title RequestQueueLib -/// @notice Pure function library for processing and validating payload request batches -/// @dev Extracted from RequestQueue contract, with storage operations removed -library RequestQueueLib { - /// @notice Validates a batch of payloads - /// @param payloadCount The number of payloads in the batch - /// @param maxPayloadCount The maximum number of payloads allowed - /// @return isValid Whether the batch is valid - function validateBatch( - uint256 payloadCount, - uint256 maxPayloadCount - ) public pure returns (bool isValid) { - return payloadCount <= maxPayloadCount; - } - - /// @notice Analyzes an array of queue payload params and creates payload submit params - /// @param queuePayloadParams An array of queue payload params - /// @return payloadSubmitParams The resulting array of payload submit params - /// @return onlyReadRequests Whether the batch contains only read requests - /// @return queryCount The number of query (read) operations - /// @return finalizeCount The number of finalize (write) operations - function createPayloadSubmitParams( - QueuePayloadParams[] memory queuePayloadParams - ) - public - pure - returns ( - PayloadSubmitParams[] memory payloadSubmitParams, - bool onlyReadRequests, - uint256 queryCount, - uint256 finalizeCount - ) - { - if (queuePayloadParams.length == 0) { - return (new PayloadSubmitParams[](0), true, 0, 0); - } - - payloadSubmitParams = new PayloadSubmitParams[](queuePayloadParams.length); - onlyReadRequests = queuePayloadParams[0].callType == CallType.READ; - - uint256 currentLevel = 0; - for (uint256 i = 0; i < queuePayloadParams.length; i++) { - if (queuePayloadParams[i].callType == CallType.READ) { - queryCount++; - } else { - onlyReadRequests = false; - finalizeCount++; - } - - // Update level for calls - if (i > 0 && queuePayloadParams[i].isParallel != Parallel.ON) { - currentLevel = currentLevel + 1; - } - - payloadSubmitParams[i] = createPayloadDetails(currentLevel, queuePayloadParams[i]); - } - } - - /// @notice Creates the payload details for a given level and queue params - /// @param level The level number for parallel execution - /// @param queueParams The queue payload parameters - /// @return payloadDetails The payload submit parameters - function createPayloadDetails( - uint256 level, - QueuePayloadParams memory queueParams - ) public pure returns (PayloadSubmitParams memory payloadDetails) { - // Skip deploy case - we're ignoring deploy-related functions - - return - PayloadSubmitParams({ - levelNumber: level, - chainSlug: queueParams.chainSlug, - callType: queueParams.callType, - isParallel: queueParams.isParallel, - writeFinality: queueParams.writeFinality, - asyncPromise: queueParams.asyncPromise, - switchboard: queueParams.switchboard, - target: queueParams.target, - appGateway: queueParams.appGateway, - gasLimit: queueParams.gasLimit == 0 ? 10_000_000 : queueParams.gasLimit, - value: queueParams.value, - readAt: queueParams.readAt, - payload: queueParams.payload - }); - } - - /// @notice Calculates fees needed for a batch - /// @param queryCount Number of read operations - /// @param finalizeCount Number of write operations - /// @param baseQueryFee Base fee for query operations - /// @param baseFinalizeFee Base fee for finalize operations - /// @return totalFees The total fees required - function calculateRequiredFees( - uint256 queryCount, - uint256 finalizeCount, - uint256 baseQueryFee, - uint256 baseFinalizeFee - ) public pure returns (uint256 totalFees) { - return (queryCount * baseQueryFee) + (finalizeCount * baseFinalizeFee); - } - - /// @notice Determines if the batch should be processed immediately - /// @param onlyReadRequests Whether the batch contains only read requests - /// @return shouldProcessImmediately Whether the batch should be processed immediately - function shouldProcessImmediately( - bool onlyReadRequests - ) public pure returns (bool shouldProcessImmediately) { - return onlyReadRequests; - } - - /// @notice Validates payload values against chain limits - /// @param payloadParams Array of payload parameters - /// @param chainValueLimits Mapping of chain slug to max value limit - /// @return isValid Whether all values are valid - function validatePayloadValues( - PayloadSubmitParams[] memory payloadParams, - mapping(uint32 => uint256) storage chainValueLimits - ) public view returns (bool isValid) { - for (uint256 i = 0; i < payloadParams.length; i++) { - uint32 chainSlug = payloadParams[i].chainSlug; - uint256 value = payloadParams[i].value; - - if (value > chainValueLimits[chainSlug]) { - return false; - } - } - return true; - } - - /// @notice Creates batch parameters from payload analysis - /// @param appGateway The application gateway address - /// @param auctionManager The auction manager address - /// @param maxFees The maximum fees allowed - /// @param onCompleteData Data to be used on batch completion - /// @param queryCount Number of read operations - /// @param finalizeCount Number of write operations - /// @param onlyReadRequests Whether the batch contains only read requests - /// @return batchParams The batch parameters - function createBatchParams( - address appGateway, - address auctionManager, - uint256 maxFees, - bytes memory onCompleteData, - uint256 queryCount, - uint256 finalizeCount, - bool onlyReadRequests - ) public pure returns (BatchParams memory batchParams) { - return - BatchParams({ - appGateway: appGateway, - auctionManager: auctionManager, - maxFees: maxFees, - onCompleteData: onCompleteData, - onlyReadRequests: onlyReadRequests, - queryCount: queryCount, - finalizeCount: finalizeCount - }); - } - - /// @notice Creates request metadata - /// @param params The batch parameters - /// @param consumeFrom Address to consume fees from - /// @return metadata The request metadata - function createRequestMetadata( - BatchParams memory params, - address consumeFrom - ) public pure returns (RequestMetadata memory metadata) { - return - RequestMetadata({ - appGateway: params.appGateway, - auctionManager: params.auctionManager, - maxFees: params.maxFees, - winningBid: Bid({fee: 0, transmitter: address(0), extraData: new bytes(0)}), - onCompleteData: params.onCompleteData, - onlyReadRequests: params.onlyReadRequests, - consumeFrom: consumeFrom, - queryCount: params.queryCount, - finalizeCount: params.finalizeCount - }); - } -} diff --git a/contracts/core/RequestHandler.sol b/contracts/core/RequestHandler.sol index 661034cb..5e1fb639 100644 --- a/contracts/core/RequestHandler.sol +++ b/contracts/core/RequestHandler.sol @@ -170,10 +170,5 @@ abstract contract RequestHandler is WatcherPrecompileCore { r.currentBatchPayloadsLeft = totalPayloads; } - /// @notice Gets the current request count - /// @return The current request count - /// @dev This function returns the next request count, which is the current request count - function getCurrentRequestCount() external view returns (uint40) { - return nextRequestCount; - } + } diff --git a/contracts/core/WatcherPrecompile.sol b/contracts/core/WatcherPrecompile.sol deleted file mode 100644 index f58e304f..00000000 --- a/contracts/core/WatcherPrecompile.sol +++ /dev/null @@ -1,320 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -pragma solidity ^0.8.21; - -import "./RequestHandler.sol"; -import {LibCall} from "solady/utils/LibCall.sol"; - -/// @title WatcherPrecompile -/// @notice Contract that handles request submission, iteration and execution -/// @dev This contract extends RequestHandler to provide the main functionality for the WatcherPrecompile system -/// @dev It handles timeout requests, finalization, queries, and promise resolution -contract WatcherPrecompile is RequestHandler { - using PayloadHeaderDecoder for bytes32; - using LibCall for address; - - /// @notice Constructor that disables initializers for the implementation - constructor() { - _disableInitializers(); - } - - /// @notice Initializes the contract with the required parameters - /// @param owner_ The address of the owner - /// @param addressResolver_ The address of the address resolver - /// @param expiryTime_ The expiry time for payload execution - /// @param evmxSlug_ The EVM chain slug - /// @param watcherPrecompileLimits_ The address of the watcher precompile limits contract - /// @param watcherPrecompileConfig_ The address of the watcher precompile config contract - /// @dev This function initializes the contract with the required parameters and sets up the initial state - function initialize( - address owner_, - address addressResolver_, - uint256 expiryTime_, - uint32 evmxSlug_, - address watcherPrecompileLimits_, - address watcherPrecompileConfig_ - ) public reinitializer(1) { - _setAddressResolver(addressResolver_); - _initializeOwner(owner_); - - watcherPrecompileLimits__ = IWatcherPrecompileLimits(watcherPrecompileLimits_); - watcherPrecompileConfig__ = IWatcherPrecompileConfig(watcherPrecompileConfig_); - maxTimeoutDelayInSeconds = 24 * 60 * 60; // 24 hours - expiryTime = expiryTime_; - evmxSlug = evmxSlug_; - - timeoutIdPrefix = (uint256(evmxSlug_) << 224) | (uint256(uint160(address(this))) << 64); - } - - // ================== Timeout functions ================== - - /// @notice Sets a timeout for a payload execution on app gateway - /// @dev This function creates a timeout request that will be executed after the specified `delayInSeconds_` - /// @dev request is executed on msg.sender - /// @dev msg sender needs SCHEDULE precompile limit - /// @param delayInSeconds_ The delay in seconds before the timeout executes - /// @param payload_ The payload data to be executed after the timeout - /// @return The unique identifier for the timeout request - function setTimeout(uint256 delayInSeconds_, bytes memory payload_) external returns (bytes32) { - return _setTimeout(delayInSeconds_, payload_); - } - - /// @notice Ends the timeouts and calls the target address with the callback payload - /// @param timeoutId_ The unique identifier for the timeout - /// @param signatureNonce_ The nonce used in the watcher's signature - /// @param signature_ The watcher's signature - /// @dev It verifies if the signature is valid and the timeout hasn't been resolved yet - function resolveTimeout( - bytes32 timeoutId_, - uint256 signatureNonce_, - bytes memory signature_ - ) external { - _isWatcherSignatureValid( - abi.encode(this.resolveTimeout.selector, timeoutId_), - signatureNonce_, - signature_ - ); - - TimeoutRequest storage timeoutRequest_ = timeoutRequests[timeoutId_]; - if (timeoutRequest_.target == address(0)) revert InvalidTimeoutRequest(); - if (timeoutRequest_.isResolved) revert TimeoutAlreadyResolved(); - if (block.timestamp < timeoutRequest_.executeAt) revert ResolvingTimeoutTooEarly(); - - (bool success, , bytes memory returnData) = timeoutRequest_.target.tryCall( - 0, - gasleft(), - 0, // setting max_copy_bytes to 0 as not using returnData right now - timeoutRequest_.payload - ); - if (!success) revert CallFailed(); - - timeoutRequest_.isResolved = true; - timeoutRequest_.executedAt = block.timestamp; - - emit TimeoutResolved( - timeoutId_, - timeoutRequest_.target, - timeoutRequest_.payload, - block.timestamp, - returnData - ); - } - - // ================== Query functions ================== - - /// @notice Creates a new query request - /// @param params_ The payload parameters - /// @dev This function creates a new query request - function query(PayloadParams memory params_) external { - _query(params_); - } - - /// @notice Marks a request as finalized with a proof on digest - /// @param payloadId_ The unique identifier of the request - /// @param proof_ The watcher's proof - /// @param signatureNonce_ The nonce of the signature - /// @param signature_ The signature of the watcher - /// @dev This function marks a request as finalized with a proof - /// @dev It verifies that the signature is valid - /// @dev Watcher signs on following digest for validation on switchboard: - /// @dev keccak256(abi.encode(switchboard, digest)) - function finalized( - bytes32 payloadId_, - bytes memory proof_, - uint256 signatureNonce_, - bytes memory signature_ - ) external { - _isWatcherSignatureValid( - abi.encode(this.finalized.selector, payloadId_, proof_), - signatureNonce_, - signature_ - ); - - watcherProofs[payloadId_] = proof_; - emit Finalized(payloadId_, proof_); - } - - /// @notice Updates the transmitter for a request - /// @param requestCount The request count to update - /// @param transmitter The new transmitter address - /// @dev This function updates the transmitter for a request - /// @dev It verifies that the caller is the middleware and that the request hasn't been started yet - function updateTransmitter(uint40 requestCount, address transmitter) public { - RequestParams storage r = requestParams[requestCount]; - if (r.isRequestCancelled) revert RequestCancelled(); - if (r.payloadsRemaining == 0) revert RequestAlreadyExecuted(); - if (r.middleware != msg.sender) revert InvalidCaller(); - if (r.transmitter != address(0)) revert RequestNotProcessing(); - r.transmitter = transmitter; - - _processBatch(requestCount, r.currentBatch); - } - - /// @notice Cancels a request - /// @param requestCount The request count to cancel - /// @dev This function cancels a request - /// @dev It verifies that the caller is the middleware and that the request hasn't been cancelled yet - function cancelRequest(uint40 requestCount) external { - RequestParams storage r = requestParams[requestCount]; - if (r.isRequestCancelled) revert RequestAlreadyCancelled(); - if (r.middleware != msg.sender) revert InvalidCaller(); - - r.isRequestCancelled = true; - emit RequestCancelledFromGateway(requestCount); - } - - /// @notice Resolves multiple promises with their return data - /// @param resolvedPromises_ Array of resolved promises and their return data - /// @param signatureNonce_ The nonce of the signature - /// @param signature_ The signature of the watcher - /// @dev This function resolves multiple promises with their return data - /// @dev It verifies that the signature is valid - /// @dev It also processes the next batch if the current batch is complete - function resolvePromises( - ResolvedPromises[] memory resolvedPromises_, - uint256 signatureNonce_, - bytes memory signature_ - ) external { - _isWatcherSignatureValid( - abi.encode(this.resolvePromises.selector, resolvedPromises_), - signatureNonce_, - signature_ - ); - - for (uint256 i = 0; i < resolvedPromises_.length; i++) { - uint40 requestCount = payloads[resolvedPromises_[i].payloadId] - .payloadHeader - .getRequestCount(); - RequestParams storage requestParams_ = requestParams[requestCount]; - - _processPromiseResolution(resolvedPromises_[i], requestParams_); - _checkAndProcessBatch(requestParams_, requestCount); - } - } - - /// @notice Marks a request as reverting - /// @param isRevertingOnchain_ Whether the request is reverting onchain - /// @param payloadId_ The unique identifier of the payload - /// @param signatureNonce_ The nonce of the signature - /// @param signature_ The signature of the watcher - /// @dev Only valid watcher can mark a request as reverting - /// @dev This function marks a request as reverting if callback or payload is reverting on chain - /// @dev Request is marked cancelled for both cases. - function markRevert( - bool isRevertingOnchain_, - bytes32 payloadId_, - uint256 signatureNonce_, - bytes memory signature_ - ) external { - _isWatcherSignatureValid( - abi.encode(this.markRevert.selector, isRevertingOnchain_, payloadId_), - signatureNonce_, - signature_ - ); - - PayloadParams memory payloadParams = payloads[payloadId_]; - if (payloadParams.deadline > block.timestamp) revert DeadlineNotPassedForOnChainRevert(); - - RequestParams storage currentRequestParams = requestParams[ - payloadParams.payloadHeader.getRequestCount() - ]; - currentRequestParams.isRequestCancelled = true; - - IMiddleware(currentRequestParams.middleware).handleRequestReverts( - payloadParams.payloadHeader.getRequestCount() - ); - - if (isRevertingOnchain_ && payloadParams.asyncPromise != address(0)) - IPromise(payloadParams.asyncPromise).markOnchainRevert( - payloadParams.payloadHeader.getRequestCount(), - payloadId_ - ); - - emit MarkedRevert(payloadId_, isRevertingOnchain_); - } - - // ================== Helper functions ================== - - /// @notice Sets the maximum timeout delay in seconds - /// @param maxTimeoutDelayInSeconds_ The maximum timeout delay in seconds - /// @dev This function sets the maximum timeout delay in seconds - /// @dev Only callable by the contract owner - function setMaxTimeoutDelayInSeconds(uint256 maxTimeoutDelayInSeconds_) external onlyOwner { - maxTimeoutDelayInSeconds = maxTimeoutDelayInSeconds_; - emit MaxTimeoutDelayInSecondsSet(maxTimeoutDelayInSeconds_); - } - - /// @notice Sets the expiry time for payload execution - /// @param expiryTime_ The expiry time in seconds - /// @dev This function sets the expiry time for payload execution - /// @dev Only callable by the contract owner - function setExpiryTime(uint256 expiryTime_) external onlyOwner { - expiryTime = expiryTime_; - emit ExpiryTimeSet(expiryTime_); - } - - /// @notice Sets the watcher precompile limits contract - /// @param watcherPrecompileLimits_ The address of the watcher precompile limits contract - /// @dev This function sets the watcher precompile limits contract - /// @dev Only callable by the contract owner - function setWatcherPrecompileLimits(address watcherPrecompileLimits_) external onlyOwner { - watcherPrecompileLimits__ = IWatcherPrecompileLimits(watcherPrecompileLimits_); - emit WatcherPrecompileLimitsSet(watcherPrecompileLimits_); - } - - /// @notice Sets the watcher precompile config contract - /// @param watcherPrecompileConfig_ The address of the watcher precompile config contract - /// @dev This function sets the watcher precompile config contract - /// @dev Only callable by the contract owner - function setWatcherPrecompileConfig(address watcherPrecompileConfig_) external onlyOwner { - watcherPrecompileConfig__ = IWatcherPrecompileConfig(watcherPrecompileConfig_); - emit WatcherPrecompileConfigSet(watcherPrecompileConfig_); - } - - /// @notice Gets the request parameters for a request - /// @param requestCount The request count to get the parameters for - /// @return The request parameters for the given request count - function getRequestParams(uint40 requestCount) external view returns (RequestParams memory) { - return requestParams[requestCount]; - } - - function _processPromiseResolution( - ResolvedPromises memory resolvedPromise_, - RequestParams storage requestParams_ - ) internal { - PayloadParams memory payloadParams = payloads[resolvedPromise_.payloadId]; - address asyncPromise = payloadParams.asyncPromise; - uint40 requestCount = payloadParams.payloadHeader.getRequestCount(); - - if (asyncPromise != address(0)) { - bool success = IPromise(asyncPromise).markResolved( - requestCount, - resolvedPromise_.payloadId, - resolvedPromise_.returnData - ); - - if (!success) { - emit PromiseNotResolved(resolvedPromise_.payloadId, asyncPromise); - return; - } - } - - isPromiseExecuted[resolvedPromise_.payloadId] = true; - requestParams_.currentBatchPayloadsLeft--; - requestParams_.payloadsRemaining--; - - emit PromiseResolved(resolvedPromise_.payloadId, asyncPromise); - } - - function _checkAndProcessBatch( - RequestParams storage requestParams_, - uint40 requestCount - ) internal { - if (requestParams_.currentBatchPayloadsLeft == 0 && requestParams_.payloadsRemaining > 0) { - _processBatch(requestCount, ++requestParams_.currentBatch); - } - - if (requestParams_.payloadsRemaining == 0) { - IMiddleware(requestParams_.middleware).finishRequest(requestCount); - } - } -} diff --git a/contracts/core/WatcherPrecompileCore.sol b/contracts/core/WatcherPrecompileCore.sol index 9da6d736..cc5f0059 100644 --- a/contracts/core/WatcherPrecompileCore.sol +++ b/contracts/core/WatcherPrecompileCore.sol @@ -115,7 +115,6 @@ abstract contract WatcherPrecompileCore is payloads[params_.payloadId].prevDigestsHash = _getPreviousDigestsHash( params_.payloadHeader.getBatchCount() ); - emit QueryRequested(params_); } // ================== Helper functions ================== @@ -185,37 +184,7 @@ abstract contract WatcherPrecompileCore is return payloadParamsArray; } - /// @notice Encodes an ID for a timeout or payload - /// @return The encoded ID - /// @dev This function creates a unique ID by combining the chain slug, address, and a counter - function _encodeTimeoutId() internal returns (bytes32) { - // Encode timeout ID by bit-shifting and combining: - // EVMx chainSlug (32 bits) | watcher precompile address (160 bits) | counter (64 bits) - return bytes32(timeoutIdPrefix | payloadCounter++); - } - - /// @notice Verifies that a watcher signature is valid - /// @param inputData_ The input data to verify - /// @param signatureNonce_ The nonce of the signature - /// @param signature_ The signature to verify - /// @dev This function verifies that the signature was created by the watcher and that the nonce has not been used before - function _isWatcherSignatureValid( - bytes memory inputData_, - uint256 signatureNonce_, - bytes memory signature_ - ) internal { - if (isNonceUsed[signatureNonce_]) revert NonceUsed(); - isNonceUsed[signatureNonce_] = true; - - bytes32 digest = keccak256( - abi.encode(address(this), evmxSlug, signatureNonce_, inputData_) - ); - digest = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", digest)); - - // recovered signer is checked for the valid roles later - address signer = ECDSA.recover(digest, signature_); - if (signer != owner()) revert InvalidWatcherSignature(); - } + function _consumeCallbackFeesFromRequestCount(uint256 fees_, uint40 requestCount_) internal { // for callbacks in all precompiles @@ -233,24 +202,4 @@ abstract contract WatcherPrecompileCore is ); } - /// @notice Gets the batch IDs for a request - /// @param requestCount_ The request count to get the batch IDs for - /// @return An array of batch IDs for the given request - function getBatches(uint40 requestCount_) external view returns (uint40[] memory) { - return requestBatchIds[requestCount_]; - } - - /// @notice Gets the payload IDs for a batch - /// @param batchCount_ The batch count to get the payload IDs for - /// @return An array of payload IDs for the given batch - function getBatchPayloadIds(uint40 batchCount_) external view returns (bytes32[] memory) { - return batchPayloadIds[batchCount_]; - } - - /// @notice Gets the payload parameters for a payload ID - /// @param payloadId_ The payload ID to get the parameters for - /// @return The payload parameters for the given payload ID - function getPayloadParams(bytes32 payloadId_) external view returns (PayloadParams memory) { - return payloads[payloadId_]; - } } diff --git a/contracts/core/WatcherPrecompileStorage.sol b/contracts/core/WatcherPrecompileStorage.sol deleted file mode 100644 index bbd65c60..00000000 --- a/contracts/core/WatcherPrecompileStorage.sol +++ /dev/null @@ -1,125 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -pragma solidity ^0.8.21; - -import "../PayloadHeaderDecoder.sol"; -import "../../interfaces/IWatcherPrecompile.sol"; -import {IAppGateway} from "../../interfaces/IAppGateway.sol"; -import {IPromise} from "../../interfaces/IPromise.sol"; -import {IMiddleware} from "../../interfaces/IMiddleware.sol"; -import {QUERY, FINALIZE, SCHEDULE, MAX_COPY_BYTES} from "../../../utils/common/Constants.sol"; -import {InvalidCallerTriggered, TimeoutDelayTooLarge, TimeoutAlreadyResolved, InvalidInboxCaller, ResolvingTimeoutTooEarly, CallFailed, AppGatewayAlreadyCalled, InvalidWatcherSignature, NonceUsed, RequestAlreadyExecuted} from "../../../utils/common/Errors.sol"; -import {ResolvedPromises, AppGatewayConfig, LimitParams, WriteFinality, UpdateLimitParams, PlugConfig, DigestParams, TimeoutRequest, QueuePayloadParams, PayloadParams, RequestParams, RequestMetadata} from "../../../utils/common/Structs.sol"; - -/// @title WatcherPrecompileStorage -/// @notice Storage contract for the WatcherPrecompile system -/// @dev This contract contains all the storage variables used by the WatcherPrecompile system -/// @dev It is inherited by WatcherPrecompileCore and WatcherPrecompile -abstract contract WatcherPrecompileStorage is IWatcherPrecompile { - // slots [0-49]: gap for future storage variables - uint256[50] _gap_before; - - // slot 50 - /// @notice The chain slug of the watcher precompile - uint32 public evmxSlug; - - /// @notice Counter for tracking payload requests - uint40 public payloadCounter; - - /// @notice Counter for tracking request counts - uint40 public override nextRequestCount; - - /// @notice Counter for tracking batch counts - uint40 public nextBatchCount; - - // slot 51 - /// @notice The time from finalize for the payload to be executed - /// @dev Expiry time in seconds for payload execution - uint256 public expiryTime; - - // slot 52 - /// @notice The maximum delay for a timeout - /// @dev Maximum timeout delay in seconds - uint256 public maxTimeoutDelayInSeconds; - - // slot 53 - /// @notice stores temporary address of the app gateway caller from a chain - address public appGatewayCaller; - - - // slot 52 - /// @notice The parameters array used to store payloads for a request - QueuePayloadParams[] public queuePayloadParams; - - // slot 53 - /// @notice The metadata for a request - mapping(uint40 => RequestMetadata) public requests; - - // slot 54 - /// @notice The prefix for timeout IDs - uint256 public timeoutIdPrefix; - - // slot 54 - /// @notice The maximum message value limit for a chain - mapping(uint32 => uint256) public chainMaxMsgValueLimit; - - - // slot 55 - /// @notice Maps nonce to whether it has been used - /// @dev Used to prevent replay attacks with signature nonces - /// @dev signatureNonce => isValid - mapping(uint256 => bool) public isNonceUsed; - - // slot 55 - /// @notice Mapping to store timeout requests - /// @dev Maps timeout ID to TimeoutRequest struct - /// @dev timeoutId => TimeoutRequest struct - mapping(bytes32 => TimeoutRequest) public timeoutRequests; - - // slot 56 - /// @notice Mapping to store watcher proofs - /// @dev Maps payload ID to proof bytes - /// @dev payloadId => proof bytes - mapping(bytes32 => bytes) public watcherProofs; - - // slot 57 - /// @notice Mapping to store if appGateway has been called with trigger from on-chain Inbox - /// @dev Maps call ID to boolean indicating if the appGateway has been called - /// @dev callId => bool - mapping(bytes32 => bool) public appGatewayCalled; - - // slot 58 - /// @notice Mapping to store the request parameters for each request count - mapping(uint40 => RequestParams) public requestParams; - - // slot 59 - /// @notice Mapping to store the list of payload IDs for each batch - mapping(uint40 => bytes32[]) public batchPayloadIds; - - // slot 60 - /// @notice Mapping to store the batch IDs for each request - mapping(uint40 => uint40[]) public requestBatchIds; - - // slot 61 - /// @notice Mapping to store the payload parameters for each payload ID - mapping(bytes32 => PayloadParams) public payloads; - - // slot 62 - /// @notice Mapping to store if a promise has been executed - mapping(bytes32 => bool) public isPromiseExecuted; - - // slot 63 - IWatcherPrecompileLimits public watcherPrecompileLimits__; - - // slot 64 - IWatcherPrecompileConfig public watcherPrecompileConfig__; - - // slot 65 - /// @notice Mapping to store the request metadata for each request count - mapping(uint40 => RequestMetadata) public requestMetadata; - - // slots [67-114]: gap for future storage variables - uint256[48] _gap_after; - - // slots 115-165 (51) reserved for access control - // slots 166-216 (51) reserved for addr resolver util -} diff --git a/contracts/evmx/fees/FeesManager.sol b/contracts/evmx/fees/FeesManager.sol index 6cebd5c1..538961e2 100644 --- a/contracts/evmx/fees/FeesManager.sol +++ b/contracts/evmx/fees/FeesManager.sol @@ -467,3 +467,66 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol signer = ECDSA.recover(digest, signature_); } } + +// /// @notice Withdraws funds to a specified receiver +// /// @param chainSlug_ The chain identifier +// /// @param token_ The address of the token +// /// @param amount_ The amount of tokens to withdraw +// /// @param receiver_ The address of the receiver +// /// @param fees_ The fees data +// function withdrawTo( +// uint32 chainSlug_, +// address token_, +// uint256 amount_, +// address receiver_, +// address auctionManager_, +// uint256 fees_ +// ) external returns (uint40) { +// IFeesManager(addressResolver__.feesManager()).withdrawCredits( +// msg.sender, +// chainSlug_, +// token_, +// amount_, +// receiver_ +// ); +// return _batch(msg.sender, auctionManager_, msg.sender, fees_, bytes("")); +// } + +// /// @notice Withdraws fees to a specified receiver +// /// @param chainSlug_ The chain identifier +// /// @param token_ The token address +// /// @param receiver_ The address of the receiver +// function withdrawTransmitterFees( +// uint32 chainSlug_, +// address token_, +// address receiver_, +// uint256 amount_ +// ) external returns (uint40 requestCount) { +// address transmitter = msg.sender; + +// PayloadSubmitParams[] memory payloadSubmitParamsArray = IFeesManager( +// addressResolver__.feesManager() +// ).getWithdrawTransmitterCreditsPayloadParams( +// transmitter, +// chainSlug_, +// token_, +// receiver_, +// amount_ +// ); + +// RequestMetadata memory requestMetadata = RequestMetadata({ +// appGateway: addressResolver__.feesManager(), +// auctionManager: address(0), +// maxFees: 0, +// winningBid: Bid({transmitter: transmitter, fee: 0, extraData: new bytes(0)}), +// onCompleteData: bytes(""), +// onlyReadRequests: false, +// consumeFrom: transmitter, +// queryCount: 0, +// finalizeCount: 1 +// }); // finalize for plug contract +// requestCount = watcherPrecompile__().submitRequest(payloadSubmitParamsArray); +// requests[requestCount] = requestMetadata; +// // same transmitter can execute requests without auction +// watcherPrecompile__().startProcessingRequest(requestCount, transmitter); +// } \ No newline at end of file diff --git a/contracts/evmx/interfaces/IPrecompile.sol b/contracts/evmx/interfaces/IPrecompile.sol new file mode 100644 index 00000000..2a15d93c --- /dev/null +++ b/contracts/evmx/interfaces/IPrecompile.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import "../../utils/common/Structs.sol"; + +/// @title IPrecompile +/// @notice Interface for precompile functionality +interface IPrecompile { + /// @notice Gets precompile data and fees for queue parameters + /// @param queuePayloadParams_ The queue parameters to process + /// @return precompileData The encoded precompile data + /// @return fees Estimated fees required for processing + function getPrecompileData(QueueParams calldata queuePayloadParams_) external returns (bytes memory precompileData, uint256 fees); + + /// @notice Handles payload processing and returns fees + /// @param payloadParams The payload parameters to handle + /// @return fees The fees required for processing + function handlePayload(PayloadParams calldata payloadParams) external returns (uint256 fees); +} + diff --git a/contracts/evmx/interfaces/IWatcherPrecompile.sol b/contracts/evmx/interfaces/IWatcherPrecompile.sol index 88795fee..b98d7770 100644 --- a/contracts/evmx/interfaces/IWatcherPrecompile.sol +++ b/contracts/evmx/interfaces/IWatcherPrecompile.sol @@ -15,9 +15,6 @@ interface IWatcherPrecompile { /// @param triggerId The unique identifier for the trigger event AppGatewayCallFailed(bytes32 triggerId); - /// @notice Emitted when a new query is requested - event QueryRequested(PayloadParams params); - /// @notice Emitted when a finalize request is made event FinalizeRequested(bytes32 digest, PayloadParams params); diff --git a/contracts/core/WatcherIdUtils.sol b/contracts/evmx/libs/WatcherIdUtils.sol similarity index 100% rename from contracts/core/WatcherIdUtils.sol rename to contracts/evmx/libs/WatcherIdUtils.sol diff --git a/contracts/evmx/watcher/PromiseResolver.sol b/contracts/evmx/watcher/PromiseResolver.sol index 83aacc90..fbe44414 100644 --- a/contracts/evmx/watcher/PromiseResolver.sol +++ b/contracts/evmx/watcher/PromiseResolver.sol @@ -9,7 +9,7 @@ import "../../common/Errors.sol"; import "../../core/WatcherIdUtils.sol"; interface IPromiseResolver { - function resolvePromises( + function resolvePromises( ResolvedPromises[] calldata resolvedPromises_, uint256 signatureNonce_, bytes calldata signature_ @@ -50,50 +50,68 @@ contract PromiseResolver { watcherStorage = watcherStorage_; } - /// @notice Resolves a promise with return data - /// @param resolvedPromise The resolved promise data - /// @param requestCount The request count associated with the promise - /// @return success Whether the promise was successfully resolved - function resolvePromise( - ResolvedPromises memory resolvedPromise, - uint40 requestCount - ) external onlyWatcherStorage returns (bool success) { - // Get payload params and request params from WatcherPrecompileStorage - IWatcherPrecompile watcher = IWatcherPrecompile(watcherStorage); - PayloadParams memory payloadParams = watcher.getPayloadParams(resolvedPromise.payloadId); - - address asyncPromise = payloadParams.asyncPromise; - - // If there's no promise contract, nothing to resolve - if (asyncPromise == address(0)) { - return false; + /// @notice Resolves multiple promises with their return data + /// @param resolvedPromises_ Array of resolved promises and their return data + /// @param signatureNonce_ The nonce of the signature + /// @param signature_ The signature of the watcher + /// @dev This function resolves multiple promises with their return data + /// @dev It verifies that the signature is valid + /// @dev It also processes the next batch if the current batch is complete + function resolvePromises( + ResolvedPromises[] memory resolvedPromises_, + uint256 signatureNonce_, + bytes memory signature_ + ) external { + for (uint256 i = 0; i < resolvedPromises_.length; i++) { + uint40 requestCount = payloads[resolvedPromises_[i].payloadId] + .payloadHeader + .getRequestCount(); + RequestParams storage requestParams_ = requestParams[requestCount]; + + _processPromiseResolution(resolvedPromises_[i], requestParams_); + _checkAndProcessBatch(requestParams_, requestCount); } + } - // Attempt to resolve the promise through the promise contract - bool resolutionSuccess = IPromise(asyncPromise).markResolved( - requestCount, - resolvedPromise.payloadId, - resolvedPromise.returnData - ); + function _processPromiseResolution( + ResolvedPromises memory resolvedPromise_, + RequestParams storage requestParams_ + ) internal { + PayloadParams memory payloadParams = payloads[resolvedPromise_.payloadId]; + address asyncPromise = payloadParams.asyncPromise; + uint40 requestCount = payloadParams.payloadHeader.getRequestCount(); - if (!resolutionSuccess) { - // Emit event through WatcherPrecompileStorage - emit IWatcherPrecompile.PromiseNotResolved(resolvedPromise.payloadId, asyncPromise); - return false; + if (asyncPromise != address(0)) { + bool success = IPromise(asyncPromise).markResolved( + requestCount, + resolvedPromise_.payloadId, + resolvedPromise_.returnData + ); + + if (!success) { + emit PromiseNotResolved(resolvedPromise_.payloadId, asyncPromise); + return; + } } - // Update storage in WatcherPrecompileStorage - watcher.updateResolvedAt(resolvedPromise.payloadId, block.timestamp); - watcher.decrementBatchCounters(requestCount); - // payloadsRemaining-- + isPromiseExecuted[resolvedPromise_.payloadId] = true; + requestParams_.currentBatchPayloadsLeft--; + requestParams_.payloadsRemaining--; - // Emit event through WatcherPrecompileStorage - emit IWatcherPrecompile.PromiseResolved(resolvedPromise.payloadId, asyncPromise); + emit PromiseResolved(resolvedPromise_.payloadId, asyncPromise); + } - // Check if we need to process next batch - processBatch(requestCount); + function _checkAndProcessBatch( + RequestParams storage requestParams_, + uint40 requestCount + ) internal { + if (requestParams_.currentBatchPayloadsLeft == 0 && requestParams_.payloadsRemaining > 0) { + _processBatch(requestCount, ++requestParams_.currentBatch); + } - return true; + if (requestParams_.payloadsRemaining == 0) { + IMiddleware(requestParams_.middleware).finishRequest(requestCount); + } } /// @notice Marks a request as reverting @@ -107,105 +125,24 @@ contract PromiseResolver { uint256 currentTimestamp ) external onlyWatcherStorage returns (bool success) { // Get payload params from WatcherPrecompileStorage - IWatcherPrecompile watcher = IWatcherPrecompile(watcherStorage); - PayloadParams memory payloadParams = watcher.getPayloadParams(payloadId); - - // Validate deadline - if (payloadParams.deadline > currentTimestamp) { - return false; - } - - uint40 requestCount = payloadParams.payloadHeader.getRequestCount(); - - // Mark request as cancelled directly in the watcher - watcher.cancelRequest(requestCount); - - // Handle onchain revert if necessary - if (isRevertingOnchain && payloadParams.asyncPromise != address(0)) { - IPromise(payloadParams.asyncPromise).markOnchainRevert(requestCount, payloadId); - } - - // Emit event through WatcherPrecompileStorage - emit IWatcherPrecompile.MarkedRevert(payloadId, isRevertingOnchain); - - return true; - } + PayloadParams memory payloadParams = payloads[payloadId_]; + if (payloadParams.deadline > block.timestamp) revert DeadlineNotPassedForOnChainRevert(); - /// @notice Check if we need to process next batch - /// @param requestCount The request count - function _checkAndProcessBatch(uint40 requestCount) private { - IWatcherPrecompile watcher = IWatcherPrecompile(watcherStorage); + RequestParams storage currentRequestParams = requestParams[ + payloadParams.payloadHeader.getRequestCount() + ]; + currentRequestParams.isRequestCancelled = true; - // Check if current batch is complete and there are more payloads to process - if (shouldProcessNextBatch(requestCount)) { - // Process next batch - watcher.processNextBatch(requestCount); - } - - // Check if request is complete - if (isRequestComplete(requestCount)) { - // Finish request - watcher.finishRequest(requestCount); - } - } - - /// @notice Determines if a request is complete - /// @param payloadsRemaining Total payloads remaining for the request - /// @return isComplete Whether the request is complete - function isRequestComplete(uint256 payloadsRemaining) public pure returns (bool isComplete) { - return payloadsRemaining == 0; - } - - /// @notice Validates that a promise can be resolved - /// @param payloadId The unique identifier of the payload - /// @param requestCount The request count - /// @return isValid Whether the promise can be resolved - function validatePromiseResolution( - bytes32 payloadId, - uint40 requestCount - ) external view returns (bool isValid) { - if (payloadId == bytes32(0) || requestCount == 0) return false; - - IWatcherPrecompile watcher = IWatcherPrecompile(watcherStorage); - // Check if the request has been cancelled - if (watcher.isRequestCancelled(requestCount)) return false; - - // Check if the promise has already been executed - if (watcher.isPromiseExecuted(payloadId)) return false; - - return true; - } - - /// @notice Validates that a request can be marked as reverting - /// @param payloadId The unique identifier of the payload - /// @param deadline The deadline for the payload execution - /// @param currentTimestamp The current block timestamp - /// @return isValid Whether the request can be marked as reverting - function validateRevertMarking( - bytes32 payloadId, - uint256 deadline, - uint256 currentTimestamp - ) external view returns (bool isValid) { - if (payloadId == bytes32(0)) return false; - if (deadline > currentTimestamp) return false; - - IWatcherPrecompile watcher = IWatcherPrecompile(watcherStorage); - uint40 requestCount = watcher.getRequestCountFromPayloadId(payloadId); - - // Check if the request has already been cancelled - if (watcher.isRequestCancelled(requestCount)) return false; + IMiddleware(currentRequestParams.middleware).handleRequestReverts( + payloadParams.payloadHeader.getRequestCount() + ); - return true; - } + if (isRevertingOnchain_ && payloadParams.asyncPromise != address(0)) + IPromise(payloadParams.asyncPromise).markOnchainRevert( + payloadParams.payloadHeader.getRequestCount(), + payloadId_ + ); - /// @notice Determines if a batch should be processed next - /// @param currentBatchPayloadsLeft Number of payloads left in current batch - /// @param payloadsRemaining Total payloads remaining - /// @return shouldProcess Whether next batch should be processed - function shouldProcessNextBatch( - uint256 currentBatchPayloadsLeft, - uint256 payloadsRemaining - ) public pure returns (bool shouldProcess) { - return currentBatchPayloadsLeft == 0 && payloadsRemaining > 0; + emit MarkedRevert(payloadId_, isRevertingOnchain_); } } diff --git a/contracts/evmx/watcher/RequestHandler.sol b/contracts/evmx/watcher/RequestHandler.sol new file mode 100644 index 00000000..34283ef6 --- /dev/null +++ b/contracts/evmx/watcher/RequestHandler.sol @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import "../../interfaces/IWatcherPrecompile.sol"; +import "../../libs/PayloadHeaderDecoder.sol"; +import "../../utils/common/Structs.sol"; +import "../../utils/common/Errors.sol"; + +/// @title RequestHandler +/// @notice Contract that handles request processing and management +/// @dev This contract interacts with the WatcherPrecompileStorage for storage access +contract RequestHandler { + using PayloadHeaderDecoder for bytes32; + + // The address of the WatcherPrecompileStorage contract + address public watcherStorage; + + // Only WatcherPrecompileStorage can call functions + modifier onlyWatcherStorage() { + require(msg.sender == watcherStorage, "Only WatcherStorage can call"); + _; + } + + /// @notice Sets the WatcherPrecompileStorage address + /// @param watcherStorage_ The address of the WatcherPrecompileStorage contract + constructor(address watcherStorage_) { + watcherStorage = watcherStorage_; + } + + /// @notice Updates the WatcherPrecompileStorage address + /// @param watcherStorage_ The new address of the WatcherPrecompileStorage contract + function setWatcherStorage(address watcherStorage_) external onlyWatcherStorage { + watcherStorage = watcherStorage_; + } + + /// @notice Increases the fees for a request if no bid is placed + /// @param requestCount_ The ID of the request + /// @param newMaxFees_ The new maximum fees + function increaseFees(uint40 requestCount_, uint256 newMaxFees_) external override { + address appGateway = _getCoreAppGateway(msg.sender); + // todo: should we allow core app gateway too? + if (appGateway != requests[requestCount_].appGateway) { + revert OnlyAppGateway(); + } + if (requests[requestCount_].winningBid.transmitter != address(0)) revert WinningBidExists(); + if (requests[requestCount_].maxFees >= newMaxFees_) + revert NewMaxFeesLowerThanCurrent(requests[requestCount_].maxFees, newMaxFees_); + requests[requestCount_].maxFees = newMaxFees_; + emit FeesIncreased(appGateway, requestCount_, newMaxFees_); + } + + /// @notice Updates the transmitter for a request + /// @param requestCount The request count to update + /// @param transmitter The new transmitter address + /// @dev This function updates the transmitter for a request + /// @dev It verifies that the caller is the middleware and that the request hasn't been started yet + function updateTransmitter(uint40 requestCount, address transmitter) public { + RequestParams storage r = requestParams[requestCount]; + if (r.isRequestCancelled) revert RequestCancelled(); + if (r.payloadsRemaining == 0) revert RequestAlreadyExecuted(); + if (r.middleware != msg.sender) revert InvalidCaller(); + if (r.transmitter != address(0)) revert RequestNotProcessing(); + r.transmitter = transmitter; + + _processBatch(requestCount, r.currentBatch); + } + + /// @notice Cancels a request + /// @param requestCount The request count to cancel + /// @dev This function cancels a request + /// @dev It verifies that the caller is the middleware and that the request hasn't been cancelled yet + function cancelRequest(uint40 requestCount) external { + RequestParams storage r = requestParams[requestCount]; + if (r.isRequestCancelled) revert RequestAlreadyCancelled(); + if (r.middleware != msg.sender) revert InvalidCaller(); + + r.isRequestCancelled = true; + emit RequestCancelledFromGateway(requestCount); + } + + /// @notice Ends the timeouts and calls the target address with the callback payload + /// @param timeoutId_ The unique identifier for the timeout + /// @param signatureNonce_ The nonce used in the watcher's signature + /// @param signature_ The watcher's signature + /// @dev It verifies if the signature is valid and the timeout hasn't been resolved yet + function resolveTimeout( + bytes32 timeoutId_, + uint256 signatureNonce_, + bytes memory signature_ + ) external { + _isWatcherSignatureValid( + abi.encode(this.resolveTimeout.selector, timeoutId_), + signatureNonce_, + signature_ + ); + + TimeoutRequest storage timeoutRequest_ = timeoutRequests[timeoutId_]; + if (timeoutRequest_.target == address(0)) revert InvalidTimeoutRequest(); + if (timeoutRequest_.isResolved) revert TimeoutAlreadyResolved(); + if (block.timestamp < timeoutRequest_.executeAt) revert ResolvingTimeoutTooEarly(); + + (bool success, , bytes memory returnData) = timeoutRequest_.target.tryCall( + 0, + gasleft(), + 0, // setting max_copy_bytes to 0 as not using returnData right now + timeoutRequest_.payload + ); + if (!success) revert CallFailed(); + + timeoutRequest_.isResolved = true; + timeoutRequest_.executedAt = block.timestamp; + + emit TimeoutResolved( + timeoutId_, + timeoutRequest_.target, + timeoutRequest_.payload, + block.timestamp, + returnData + ); + } +} diff --git a/contracts/evmx/watcher/WatcherPrecompileStorageAdapter.sol b/contracts/evmx/watcher/WatcherPrecompileStorageAdapter.sol index e5de87f4..49e56817 100644 --- a/contracts/evmx/watcher/WatcherPrecompileStorageAdapter.sol +++ b/contracts/evmx/watcher/WatcherPrecompileStorageAdapter.sol @@ -4,8 +4,6 @@ pragma solidity ^0.8.21; import "../PayloadHeaderDecoder.sol"; import "../../interfaces/IWatcherPrecompile.sol"; import {IAppGateway} from "../../interfaces/IAppGateway.sol"; -import {IPromise} from "../../interfaces/IPromise.sol"; -import {IMiddleware} from "../../interfaces/IMiddleware.sol"; import {InvalidCallerTriggered, TimeoutDelayTooLarge, TimeoutAlreadyResolved, InvalidInboxCaller, ResolvingTimeoutTooEarly, CallFailed, AppGatewayAlreadyCalled, InvalidWatcherSignature, NonceUsed, RequestAlreadyExecuted} from "../../../utils/common/Errors.sol"; import {ResolvedPromises, AppGatewayConfig, LimitParams, WriteFinality, UpdateLimitParams, PlugConfig, DigestParams, TimeoutRequest, QueuePayloadParams, PayloadParams, RequestParams, RequestMetadata} from "../../../utils/common/Structs.sol"; @@ -14,6 +12,9 @@ import {ResolvedPromises, AppGatewayConfig, LimitParams, WriteFinality, UpdateLi /// @dev This contract contains all the storage variables used by the WatcherPrecompile system /// @dev It is inherited by WatcherPrecompileCore and WatcherPrecompile abstract contract WatcherPrecompileStorage is IWatcherPrecompile { + // slots [0-49]: gap for future storage variables + uint256[50] _gap_before; + // slot 50 /// @notice The chain slug of the watcher precompile uint32 public evmxSlug; @@ -33,15 +34,6 @@ abstract contract WatcherPrecompileStorage is IWatcherPrecompile { /// @dev Expiry time in seconds for payload execution uint256 public expiryTime; - // slot 52 - /// @notice The maximum delay for a timeout - /// @dev Maximum timeout delay in seconds - uint256 public maxTimeoutDelayInSeconds; - - // slot 54 - /// @notice The maximum message value limit for a chain - mapping(uint32 => uint256) public chainMaxMsgValueLimit; - // slot 55 /// @notice Maps nonce to whether it has been used /// @dev Used to prevent replay attacks with signature nonces @@ -70,12 +62,102 @@ abstract contract WatcherPrecompileStorage is IWatcherPrecompile { // slot 53 /// @notice The metadata for a request mapping(uint40 => RequestParams) public requests; + + // slot 62 + /// @notice The queue of payloads + QueueParams[] public queue; + + // slots [67-114]: gap for future storage variables + uint256[48] _gap_after; + + // slots 115-165 (51) reserved for access control + // slots 166-216 (51) reserved for addr resolver util } contract WatcherPrecompileStorageAdapter is WatcherPrecompileStorage { + /// @notice Clears the call parameters array + function clearQueue() public { + delete queuePayloadParams; + } + + /// @notice Queues a new payload + /// @param queuePayloadParams_ The call parameters + function queue(QueuePayloadParams memory queuePayloadParams_) external { + queuePayloadParams.push(queuePayloadParams_); + } + + + /// @notice Marks a request as finalized with a proof on digest + /// @param payloadId_ The unique identifier of the request + /// @param proof_ The watcher's proof + /// @dev This function marks a request as finalized with a proof + function finalized(bytes32 payloadId_, bytes memory proof_) public onlyOwner { + watcherProofs[payloadId_] = proof_; + emit Finalized(payloadId_, proof_); + } + + /// @notice Sets the expiry time for payload execution + /// @param expiryTime_ The expiry time in seconds + /// @dev This function sets the expiry time for payload execution + /// @dev Only callable by the contract owner + function setExpiryTime(uint256 expiryTime_) external onlyOwner { + expiryTime = expiryTime_; + emit ExpiryTimeSet(expiryTime_); + } + + + /// @notice Gets the current request count + /// @return The current request count + /// @dev This function returns the next request count, which is the current request count + function getCurrentRequestCount() external view returns (uint40) { + return nextRequestCount; + } + + /// @notice Gets the request parameters for a request + /// @param requestCount The request count to get the parameters for + /// @return The request parameters for the given request count + function getRequestParams(uint40 requestCount) external view returns (RequestParams memory) { + return requestParams[requestCount]; + } + // all function from watcher requiring signature - function watcherUpdater(address[] callData contracts, bytes[] callData data_, uint256[] calldata nonces_, bytes[] callData signatures_) { + function watcherMultiCall(address[] callData contracts, bytes[] callData data_, uint256[] calldata nonces_, bytes[] callData signatures_) { + for (uint40 i = 0; i < contracts.length; i++) { + if (contracts[i] == address(0)) revert InvalidContract(); + if (data_[i].length == 0) revert InvalidData(); + if (nonces_[i] == 0) revert InvalidNonce(); + if (signatures_[i].length == 0) revert InvalidSignature(); + + // check if signature is valid + if (!_isWatcherSignatureValid(nonces_[i], data_[i], signatures_[i])) revert InvalidSignature(); + + // call the contract + (bool success, bytes memory result) = contracts[i].call(data_[i]); + if (!success) revert CallFailed(); + } + } + /// @notice Verifies that a watcher signature is valid + /// @param signatureNonce_ The nonce of the signature + /// @param inputData_ The input data to verify + /// @param signature_ The signature to verify + /// @dev This function verifies that the signature was created by the watcher and that the nonce has not been used before + function _isWatcherSignatureValid( + uint256 signatureNonce_, + bytes memory inputData_, + bytes memory signature_ + ) internal { + if (isNonceUsed[signatureNonce_]) revert NonceUsed(); + isNonceUsed[signatureNonce_] = true; + + bytes32 digest = keccak256( + abi.encode(address(this), evmxSlug, signatureNonce_, inputData_) + ); + digest = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", digest)); + + // recovered signer is checked for the valid roles later + address signer = ECDSA.recover(digest, signature_); + if (signer != owner()) revert InvalidWatcherSignature(); } } diff --git a/contracts/evmx/watcher/precompiles/Finalize.sol b/contracts/evmx/watcher/precompiles/Finalize.sol index 61ddc26e..8d9494e5 100644 --- a/contracts/evmx/watcher/precompiles/Finalize.sol +++ b/contracts/evmx/watcher/precompiles/Finalize.sol @@ -2,107 +2,56 @@ pragma solidity ^0.8.21; import "../../interfaces/IWatcherPrecompile.sol"; -import "../../interfaces/IFeesManager.sol"; -import "../../interfaces/IMiddleware.sol"; import "../../libs/PayloadHeaderDecoder.sol"; -import "../../core/WatcherIdUtils.sol"; import "../../../utils/common/Structs.sol"; import "../../../utils/common/Errors.sol"; /// @title Finalize -/// @notice Library that handles finalization logic for the WatcherPrecompile system -/// @dev This library contains pure functions for finalization operations -library Finalize { +/// @notice Handles finalization precompile logic +contract Finalize is IPrecompile { using PayloadHeaderDecoder for bytes32; - /// @notice Calculates the digest hash of payload parameters - /// @param params_ The payload parameters to calculate the digest for - /// @return digest The calculated digest hash - /// @dev This function creates a keccak256 hash of the payload parameters - function getDigest(DigestParams memory params_) public pure returns (bytes32 digest) { - digest = keccak256( - abi.encode( - params_.socket, - params_.transmitter, - params_.payloadId, - params_.deadline, - params_.callType, - params_.gasLimit, - params_.value, - params_.payload, - params_.target, - params_.appGatewayId, - params_.prevDigestsHash, - bytes("") - ) + /// @notice The watcher precompile fees manager + IWatcherFeesManager public immutable watcherFeesManager; + + /// @notice Gets precompile data and fees for queue parameters + /// @param queuePayloadParams_ The queue parameters to process + /// @return precompileData The encoded precompile data + /// @return fees Estimated fees required for processing + function getPrecompileData( + QueueParams calldata queuePayloadParams_ + ) external pure returns (bytes memory precompileData, uint256 fees) { + // For finalize precompile, encode the payload parameters + precompileData = abi.encode( + queuePayloadParams_.transaction, + queuePayloadParams_.overrideParams ); + fees = watcherFeesManager.finalizeFees(); } - /// @notice Prepares the parameters needed for finalization - /// @param params_ The payload parameters to be finalized - /// @param transmitter_ The address of the transmitter - /// @param chainSlug The chain slug where the finalization is happening - /// @param evmxSlug The EVMx chain slug - /// @param deadline The deadline for the finalization - /// @param socketsAddress The address of the sockets contract - /// @param middleware The address of the middleware contract - /// @param prevDigestsHash The hash of previous batch digests - /// @return digestParams The digest parameters for the finalization - function prepareDigestParams( - PayloadParams memory params_, - address transmitter_, - uint32 chainSlug, - uint32 evmxSlug, - uint256 deadline, - address socketsAddress, - address middleware, - bytes32 prevDigestsHash - ) public pure returns (DigestParams memory digestParams) { - // Verify that the app gateway is properly configured for this chain and target - // This verification would happen in the storage contract - - // Construct parameters for digest calculation - digestParams = DigestParams( - socketsAddress, - transmitter_, - params_.payloadId, - deadline, - params_.payloadHeader.getCallType(), - params_.gasLimit, - params_.value, - params_.payload, - params_.target, - WatcherIdUtils.encodeAppGatewayId(params_.appGateway), - prevDigestsHash - ); + /// @notice Handles payload processing and returns fees + /// @param payloadParams The payload parameters to handle + /// @return fees The fees required for processing + function handlePayload( + PayloadParams calldata payloadParams + ) external pure returns (uint256 fees) { + fees = watcherFeesManager.finalizeFees(); + emit FinalizeRequested(bytes32(0), payloadParams); // digest will be calculated in core } - /// @notice Processes the finalization of a proof - /// @param payloadId_ The unique identifier of the request - /// @param proof_ The watcher's proof - /// @param signatureData Encoded signature data for verification - /// @return The verification result indicating whether the finalization was successful - function processFinalization( - bytes32 payloadId_, - bytes memory proof_, - bytes memory signatureData - ) public pure returns (bool) { - // This is just the logic for processing finalization - // Actual storage updates would happen in the storage contract + /// @notice Updates the maximum message value limit for multiple chains + /// @param chainSlugs_ Array of chain identifiers + /// @param maxMsgValueLimits_ Array of corresponding maximum message value limits + function updateChainMaxMsgValueLimits( + uint32[] calldata chainSlugs_, + uint256[] calldata maxMsgValueLimits_ + ) external onlyOwner { + if (chainSlugs_.length != maxMsgValueLimits_.length) revert InvalidIndex(); - // The return value indicates whether the verification was successful - // In the actual implementation, this would be used to determine whether to update storage - return signatureData.length > 0 && proof_.length > 0 && payloadId_ != bytes32(0); - } + for (uint256 i = 0; i < chainSlugs_.length; i++) { + chainMaxMsgValueLimit[chainSlugs_[i]] = maxMsgValueLimits_[i]; + } - /// @notice Creates the event data for finalization - /// @param payloadId_ The unique identifier of the request - /// @param proof_ The watcher's proof - /// @return The encoded event data for finalization - function createFinalizedEventData( - bytes32 payloadId_, - bytes memory proof_ - ) public pure returns (bytes memory) { - return abi.encode(payloadId_, proof_); + emit ChainMaxMsgValueLimitsUpdated(chainSlugs_, maxMsgValueLimits_); } } diff --git a/contracts/evmx/watcher/precompiles/Query.sol b/contracts/evmx/watcher/precompiles/Query.sol index 869139f1..6c1058eb 100644 --- a/contracts/evmx/watcher/precompiles/Query.sol +++ b/contracts/evmx/watcher/precompiles/Query.sol @@ -7,65 +7,40 @@ import "../../../utils/common/Structs.sol"; import "../../../utils/common/Errors.sol"; /// @title Query -/// @notice Library that handles query logic for the WatcherPrecompile system -/// @dev This library contains pure functions for query operations -library Query { +/// @notice Handles query precompile logic +contract Query is IPrecompile { using PayloadHeaderDecoder for bytes32; - /// @notice Validates query parameters - /// @param params_ The payload parameters for the query - /// @return isValid Whether the query parameters are valid - function validateQueryParams(PayloadParams memory params_) public pure returns (bool isValid) { - // Query is valid if it has a valid payload ID and target - return params_.payloadId != bytes32(0) && params_.target != address(0); - } + /// @notice Emitted when a new query is requested + event QueryRequested(PayloadParams params); - /// @notice Prepares the batch of payload parameters for a given batch count - /// @param payloadParams Array of payload parameters to process - /// @return An array of validated PayloadParams for the batch - function prepareBatch( - PayloadParams[] memory payloadParams - ) public pure returns (PayloadParams[] memory) { - // Batch logic would normally involve storage interactions - // This function provides the pure logic for preparation - return payloadParams; - } + /// @notice The watcher precompile fees manager + IWatcherFeesManager public immutable watcherFeesManager; - /// @notice Creates the event data for a query request - /// @param params_ The payload parameters for the query - /// @return The encoded event data for query request - function createQueryRequestEventData( - PayloadParams memory params_ - ) public pure returns (bytes memory) { - return abi.encode(params_); - } + /// @notice Gets precompile data and fees for queue parameters + /// @param queuePayloadParams_ The queue parameters to process + /// @return precompileData The encoded precompile data + /// @return fees Estimated fees required for processing + function getPrecompileData( + QueueParams calldata queuePayloadParams_ + ) external pure returns (bytes memory precompileData, uint256 fees) { + if (queuePayloadParams_.target != address(0)) revert InvalidTarget(); - /// @notice Validates batch parameters for query processing - /// @param batchCount The batch count to validate - /// @param requestCount The request count to validate - /// @return isValid Whether the batch parameters are valid - function validateBatchParams( - uint40 batchCount, - uint40 requestCount - ) public pure returns (bool isValid) { - return batchCount > 0 && requestCount > 0; + // For query precompile, encode the payload parameters + precompileData = abi.encode( + queuePayloadParams_.transaction, + queuePayloadParams_.overrideParams.readAt + ); + fees = watcherFeesManager.queryFees(); } - /// @notice Prepares parameters for batch processing - /// @param payloadParamsArray Array of payload parameters - /// @param batchSize The size of the batch - /// @return totalPayloads The number of payloads to process - function prepareBatchProcessing( - PayloadParams[] memory payloadParamsArray, - uint256 batchSize - ) public pure returns (uint256 totalPayloads) { - // Validate and count payloads that should be processed - uint256 total = 0; - for (uint256 i = 0; i < payloadParamsArray.length && i < batchSize; i++) { - if (validateQueryParams(payloadParamsArray[i])) { - total++; - } - } - return total; + /// @notice Handles payload processing and returns fees + /// @param payloadParams The payload parameters to handle + /// @return fees The fees required for processing + function handlePayload( + PayloadParams calldata payloadParams + ) external pure returns (uint256 fees) { + fees = watcherFeesManager.queryFees(); + emit QueryRequested(payloadParams); } } diff --git a/contracts/evmx/watcher/precompiles/Timeout.sol b/contracts/evmx/watcher/precompiles/Timeout.sol index 67fcf6c5..90700066 100644 --- a/contracts/evmx/watcher/precompiles/Timeout.sol +++ b/contracts/evmx/watcher/precompiles/Timeout.sol @@ -9,6 +9,20 @@ import "../../../utils/common/Errors.sol"; /// @notice Library that handles timeout logic for the WatcherPrecompile system /// @dev This library contains pure functions for timeout operations library Timeout { + // slot 52 + /// @notice The maximum delay for a timeout + /// @dev Maximum timeout delay in seconds + uint256 public maxTimeoutDelayInSeconds; + + /// @notice Sets the maximum timeout delay in seconds + /// @param maxTimeoutDelayInSeconds_ The maximum timeout delay in seconds + /// @dev This function sets the maximum timeout delay in seconds + /// @dev Only callable by the contract owner + function setMaxTimeoutDelayInSeconds(uint256 maxTimeoutDelayInSeconds_) external onlyOwner { + maxTimeoutDelayInSeconds = maxTimeoutDelayInSeconds_; + emit MaxTimeoutDelayInSecondsSet(maxTimeoutDelayInSeconds_); + } + /// @notice Validates timeout parameters /// @param delayInSeconds_ The delay in seconds before the timeout executes /// @param maxTimeoutDelayInSeconds The maximum allowed timeout delay diff --git a/contracts/evmx/watcher/precompiles/WatcherPrecompileStorageAdapter.sol b/contracts/evmx/watcher/precompiles/WatcherPrecompileStorageAdapter.sol deleted file mode 100644 index db5d9dbd..00000000 --- a/contracts/evmx/watcher/precompiles/WatcherPrecompileStorageAdapter.sol +++ /dev/null @@ -1,433 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -pragma solidity ^0.8.21; - -import "solady/utils/ECDSA.sol"; -import "solady/auth/Ownable.sol"; -import "solady/utils/LibCall.sol"; -import "solady/utils/Initializable.sol"; - -import "../../../interfaces/IWatcherPrecompile.sol"; -import "../../../interfaces/IFeesManager.sol"; -import "../../../interfaces/IMiddleware.sol"; -import "../../../interfaces/IPromise.sol"; -import "../../PayloadHeaderDecoder.sol"; -import "../../core/WatcherIdUtils.sol"; -import "../../../utils/common/Structs.sol"; -import "../../../utils/common/Errors.sol"; -import "../../../AddressResolverUtil.sol"; -import "./Finalize.sol"; -import "./Timeout.sol"; -import "./Query.sol"; - -/// @title WatcherPrecompileStorageAdapter -/// @notice Contract that manages storage and interacts with pure function libraries -/// @dev This contract serves as an adapter between the storage and the pure function libraries -contract WatcherPrecompileStorageAdapter is - IWatcherPrecompile, - Initializable, - Ownable, - AddressResolverUtil -{ - using LibCall for address; - using PayloadHeaderDecoder for bytes32; - using Finalize for bytes; - - // Storage variables similar to WatcherPrecompileStorage - uint32 public evmxSlug; - uint40 public payloadCounter; - uint40 public override nextRequestCount; - uint40 public nextBatchCount; - uint256 public expiryTime; - uint256 public maxTimeoutDelayInSeconds; - address public appGatewayCaller; - uint256 public timeoutIdPrefix; - - mapping(uint256 => bool) public isNonceUsed; - mapping(bytes32 => TimeoutRequest) public timeoutRequests; - mapping(bytes32 => bytes) public watcherProofs; - mapping(bytes32 => bool) public appGatewayCalled; - mapping(uint40 => RequestParams) public requestParams; - mapping(uint40 => bytes32[]) public batchPayloadIds; - mapping(uint40 => uint40[]) public requestBatchIds; - mapping(bytes32 => PayloadParams) public payloads; - mapping(bytes32 => bool) public isPromiseExecuted; - IWatcherPrecompileLimits public watcherPrecompileLimits__; - IWatcherPrecompileConfig public watcherPrecompileConfig__; - mapping(uint40 => RequestMetadata) public requestMetadata; - - /// @notice Constructor that disables initializers for the implementation - constructor() { - _disableInitializers(); - } - - /// @notice Initializes the contract with the required parameters - /// @param owner_ The address of the owner - /// @param addressResolver_ The address of the address resolver - /// @param expiryTime_ The expiry time for payload execution - /// @param evmxSlug_ The EVM chain slug - /// @param watcherPrecompileLimits_ The address of the watcher precompile limits contract - /// @param watcherPrecompileConfig_ The address of the watcher precompile config contract - function initialize( - address owner_, - address addressResolver_, - uint256 expiryTime_, - uint32 evmxSlug_, - address watcherPrecompileLimits_, - address watcherPrecompileConfig_ - ) public reinitializer(1) { - _setAddressResolver(addressResolver_); - _initializeOwner(owner_); - - watcherPrecompileLimits__ = IWatcherPrecompileLimits(watcherPrecompileLimits_); - watcherPrecompileConfig__ = IWatcherPrecompileConfig(watcherPrecompileConfig_); - maxTimeoutDelayInSeconds = 24 * 60 * 60; // 24 hours - expiryTime = expiryTime_; - evmxSlug = evmxSlug_; - - timeoutIdPrefix = (uint256(evmxSlug_) << 224) | (uint256(uint160(address(this))) << 64); - } - - // ================== Timeout functions ================== - - /// @notice Sets a timeout for a payload execution on app gateway - /// @param delayInSeconds_ The delay in seconds before the timeout executes - /// @param payload_ The payload data to be executed after the timeout - /// @return The unique identifier for the timeout request - function setTimeout(uint256 delayInSeconds_, bytes memory payload_) external returns (bytes32) { - if (!Timeout.validateTimeoutParams(delayInSeconds_, maxTimeoutDelayInSeconds)) - revert TimeoutDelayTooLarge(); - - _consumeCallbackFeesFromAddress(watcherPrecompileLimits__.timeoutFees(), msg.sender); - - uint256 executeAt = block.timestamp + delayInSeconds_; - bytes32 timeoutId = Timeout.encodeTimeoutId(timeoutIdPrefix, payloadCounter++); - - timeoutRequests[timeoutId] = Timeout.prepareTimeoutRequest( - msg.sender, - delayInSeconds_, - executeAt, - payload_ - ); - - // Emit event for watcher to track timeout and resolve when timeout is reached - emit TimeoutRequested(timeoutId, msg.sender, payload_, executeAt); - return timeoutId; - } - - /// @notice Resolves a timeout - /// @param timeoutId_ The unique identifier for the timeout - /// @param signatureNonce_ The nonce used in the watcher's signature - /// @param signature_ The watcher's signature - function resolveTimeout( - bytes32 timeoutId_, - uint256 signatureNonce_, - bytes memory signature_ - ) external { - _isWatcherSignatureValid( - abi.encode(this.resolveTimeout.selector, timeoutId_), - signatureNonce_, - signature_ - ); - - TimeoutRequest storage timeoutRequest_ = timeoutRequests[timeoutId_]; - if (!Timeout.validateTimeoutResolution(timeoutRequest_, block.timestamp)) { - if (timeoutRequest_.target == address(0)) revert InvalidTimeoutRequest(); - if (timeoutRequest_.isResolved) revert TimeoutAlreadyResolved(); - revert ResolvingTimeoutTooEarly(); - } - - (bool success, , bytes memory returnData) = timeoutRequest_.target.tryCall( - 0, - gasleft(), - 0, // setting max_copy_bytes to 0 as not using returnData right now - timeoutRequest_.payload - ); - if (!success) revert CallFailed(); - - timeoutRequest_.isResolved = true; - timeoutRequest_.executedAt = block.timestamp; - - emit TimeoutResolved( - timeoutId_, - timeoutRequest_.target, - timeoutRequest_.payload, - block.timestamp, - returnData - ); - } - - // ================== Query functions ================== - - /// @notice Creates a new query request - /// @param params_ The payload parameters - function query(PayloadParams memory params_) external { - if (!Query.validateQueryParams(params_)) revert InvalidQueryParams(); - - _consumeCallbackFeesFromRequestCount( - watcherPrecompileLimits__.queryFees(), - params_.payloadHeader.getRequestCount() - ); - - payloads[params_.payloadId].prevDigestsHash = _getPreviousDigestsHash( - params_.payloadHeader.getBatchCount() - ); - - emit QueryRequested(params_); - } - - /// @notice Marks a request as finalized with a proof on digest - /// @param payloadId_ The unique identifier of the request - /// @param proof_ The watcher's proof - /// @param signatureNonce_ The nonce of the signature - /// @param signature_ The signature of the watcher - function finalized( - bytes32 payloadId_, - bytes memory proof_, - uint256 signatureNonce_, - bytes memory signature_ - ) external { - _isWatcherSignatureValid( - abi.encode(this.finalized.selector, payloadId_, proof_), - signatureNonce_, - signature_ - ); - - // Process finalization using the Finalize library - if (Finalize.processFinalization(payloadId_, proof_, signature_)) { - watcherProofs[payloadId_] = proof_; - emit Finalized(payloadId_, proof_); - } - } - - /// @notice Resolves multiple promises with their return data - /// @param resolvedPromises_ Array of resolved promises and their return data - /// @param signatureNonce_ The nonce of the signature - /// @param signature_ The signature of the watcher - function resolvePromises( - ResolvedPromises[] memory resolvedPromises_, - uint256 signatureNonce_, - bytes memory signature_ - ) external { - _isWatcherSignatureValid( - abi.encode(this.resolvePromises.selector, resolvedPromises_), - signatureNonce_, - signature_ - ); - - for (uint256 i = 0; i < resolvedPromises_.length; i++) { - uint40 requestCount = payloads[resolvedPromises_[i].payloadId] - .payloadHeader - .getRequestCount(); - RequestParams storage requestParams_ = requestParams[requestCount]; - - if (Query.validatePromiseResolution(resolvedPromises_[i], requestCount)) { - _processPromiseResolution(resolvedPromises_[i], requestParams_); - _checkAndProcessBatch(requestParams_, requestCount); - } - } - } - - // ================== Helper functions ================== - - /// @notice Sets the maximum timeout delay in seconds - /// @param maxTimeoutDelayInSeconds_ The maximum timeout delay in seconds - function setMaxTimeoutDelayInSeconds(uint256 maxTimeoutDelayInSeconds_) external onlyOwner { - maxTimeoutDelayInSeconds = maxTimeoutDelayInSeconds_; - emit MaxTimeoutDelayInSecondsSet(maxTimeoutDelayInSeconds_); - } - - /// @notice Sets the expiry time for payload execution - /// @param expiryTime_ The expiry time in seconds - function setExpiryTime(uint256 expiryTime_) external onlyOwner { - expiryTime = expiryTime_; - emit ExpiryTimeSet(expiryTime_); - } - - /// @notice Verifies that a watcher signature is valid - /// @param inputData_ The input data to verify - /// @param signatureNonce_ The nonce of the signature - /// @param signature_ The signature to verify - function _isWatcherSignatureValid( - bytes memory inputData_, - uint256 signatureNonce_, - bytes memory signature_ - ) internal { - if (isNonceUsed[signatureNonce_]) revert NonceUsed(); - isNonceUsed[signatureNonce_] = true; - - bytes32 digest = keccak256( - abi.encode(address(this), evmxSlug, signatureNonce_, inputData_) - ); - digest = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", digest)); - - address signer = ECDSA.recover(digest, signature_); - if (signer != owner()) revert InvalidWatcherSignature(); - } - - /// @notice Process promise resolution - function _processPromiseResolution( - ResolvedPromises memory resolvedPromise_, - RequestParams storage requestParams_ - ) internal { - PayloadParams memory payloadParams = payloads[resolvedPromise_.payloadId]; - address asyncPromise = payloadParams.asyncPromise; - uint40 requestCount = payloadParams.payloadHeader.getRequestCount(); - - if (asyncPromise != address(0)) { - bool success = IPromise(asyncPromise).markResolved( - requestCount, - resolvedPromise_.payloadId, - resolvedPromise_.returnData - ); - - if (!success) { - emit PromiseNotResolved(resolvedPromise_.payloadId, asyncPromise); - return; - } - } - - isPromiseExecuted[resolvedPromise_.payloadId] = true; - requestParams_.currentBatchPayloadsLeft--; - requestParams_.payloadsRemaining--; - - emit PromiseResolved(resolvedPromise_.payloadId, asyncPromise); - } - - /// @notice Check and process batch - function _checkAndProcessBatch( - RequestParams storage requestParams_, - uint40 requestCount - ) internal { - if (requestParams_.currentBatchPayloadsLeft == 0 && requestParams_.payloadsRemaining > 0) { - _processBatch(requestCount, ++requestParams_.currentBatch); - } - - if (requestParams_.payloadsRemaining == 0) { - IMiddleware(requestParams_.middleware).finishRequest(requestCount); - } - } - - /// @notice Process batch - function _processBatch(uint40 requestCount_, uint40 batchCount_) internal { - RequestParams storage r = requestParams[requestCount_]; - PayloadParams[] memory payloadParamsArray = _getBatch(batchCount_); - if (r.isRequestCancelled) revert RequestCancelled(); - - uint256 totalPayloads = 0; - for (uint40 i = 0; i < payloadParamsArray.length; i++) { - if (isPromiseExecuted[payloadParamsArray[i].payloadId]) continue; - totalPayloads++; - - if (payloadParamsArray[i].payloadHeader.getCallType() != CallType.READ) { - _finalize(payloadParamsArray[i], r.transmitter); - } else { - query(payloadParamsArray[i]); - } - } - - r.currentBatchPayloadsLeft = totalPayloads; - } - - /// @notice Finalizes a payload request - function _finalize( - PayloadParams memory params_, - address transmitter_ - ) internal returns (bytes32) { - uint32 chainSlug = params_.payloadHeader.getChainSlug(); - - // Verify that the app gateway is properly configured for this chain and target - watcherPrecompileConfig__.verifyConnections( - chainSlug, - params_.target, - params_.appGateway, - params_.switchboard, - requestParams[params_.payloadHeader.getRequestCount()].middleware - ); - - _consumeCallbackFeesFromRequestCount( - watcherPrecompileLimits__.finalizeFees(), - params_.payloadHeader.getRequestCount() - ); - - uint256 deadline = block.timestamp + expiryTime; - payloads[params_.payloadId].deadline = deadline; - payloads[params_.payloadId].finalizedTransmitter = transmitter_; - - bytes32 prevDigestsHash = _getPreviousDigestsHash(params_.payloadHeader.getBatchCount()); - payloads[params_.payloadId].prevDigestsHash = prevDigestsHash; - - // Use the Finalize library to prepare digest parameters - DigestParams memory digestParams = Finalize.prepareDigestParams( - params_, - transmitter_, - chainSlug, - evmxSlug, - deadline, - watcherPrecompileConfig__.sockets(chainSlug), - requestParams[params_.payloadHeader.getRequestCount()].middleware, - prevDigestsHash - ); - - // Calculate digest from payload parameters - bytes32 digest = Finalize.getDigest(digestParams); - emit FinalizeRequested(digest, payloads[params_.payloadId]); - - return digest; - } - - /// @notice Gets the hash of previous batch digests - function _getPreviousDigestsHash(uint40 batchCount_) internal view returns (bytes32) { - bytes32[] memory payloadIds = batchPayloadIds[batchCount_]; - bytes32 prevDigestsHash = bytes32(0); - - for (uint40 i = 0; i < payloadIds.length; i++) { - PayloadParams memory p = payloads[payloadIds[i]]; - DigestParams memory digestParams = DigestParams( - watcherPrecompileConfig__.sockets(p.payloadHeader.getChainSlug()), - p.finalizedTransmitter, - p.payloadId, - p.deadline, - p.payloadHeader.getCallType(), - p.gasLimit, - p.value, - p.payload, - p.target, - WatcherIdUtils.encodeAppGatewayId(p.appGateway), - p.prevDigestsHash - ); - prevDigestsHash = keccak256( - abi.encodePacked(prevDigestsHash, Finalize.getDigest(digestParams)) - ); - } - return prevDigestsHash; - } - - /// @notice Gets the batch of payload parameters for a given batch count - function _getBatch(uint40 batchCount) internal view returns (PayloadParams[] memory) { - bytes32[] memory payloadIds = batchPayloadIds[batchCount]; - PayloadParams[] memory payloadParamsArray = new PayloadParams[](payloadIds.length); - - for (uint40 i = 0; i < payloadIds.length; i++) { - payloadParamsArray[i] = payloads[payloadIds[i]]; - } - return payloadParamsArray; - } - - /// @notice Consume callback fees from request count - function _consumeCallbackFeesFromRequestCount(uint256 fees_, uint40 requestCount_) internal { - // for callbacks in all precompiles - uint256 feesToConsume = fees_ + watcherPrecompileLimits__.callBackFees(); - IFeesManager(addressResolver__.feesManager()) - .assignWatcherPrecompileCreditsFromRequestCount(feesToConsume, requestCount_); - } - - /// @notice Consume callback fees from address - function _consumeCallbackFeesFromAddress(uint256 fees_, address consumeFrom_) internal { - // for callbacks in all precompiles - uint256 feesToConsume = fees_ + watcherPrecompileLimits__.callBackFees(); - IFeesManager(addressResolver__.feesManager()).assignWatcherPrecompileCreditsFromAddress( - feesToConsume, - consumeFrom_ - ); - } -} diff --git a/contracts/utils/common/Structs.sol b/contracts/utils/common/Structs.sol index 6fdeb289..31295861 100644 --- a/contracts/utils/common/Structs.sol +++ b/contracts/utils/common/Structs.sol @@ -195,7 +195,7 @@ struct PayloadParams { address appGateway; bytes32 payloadId; bytes32 prevDigestsHash; - uint256 resolvedAt; + uint256 resolvedAt; // replaced isPromiseExecuted bytes precompileData; // uint256 deadline; From 9334aef870e47cb54c1056e41b6a54439bac60d1 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Wed, 14 May 2025 17:38:05 +0530 Subject: [PATCH 012/130] fix: watcher basic structure --- contracts/evmx/fees/WatcherFeesManager.sol | 65 ---- contracts/evmx/interfaces/IPrecompile.sol | 5 +- .../{IWatcherPrecompile.sol => IWatcher.sol} | 35 +- contracts/evmx/libs/PayloadHeaderDecoder.sol | 166 -------- contracts/evmx/watcher/Configurations.sol | 6 +- contracts/evmx/watcher/PromiseResolver.sol | 4 +- contracts/evmx/watcher/RequestHandler.sol | 355 +++++++++++++----- contracts/evmx/watcher/Trigger.sol | 11 +- ...ecompileStorageAdapter.sol => Watcher.sol} | 163 ++++---- contracts/evmx/watcher/WatcherBase.sol | 28 ++ .../evmx/watcher/precompiles/Finalize.sol | 57 --- contracts/evmx/watcher/precompiles/Query.sol | 46 --- contracts/evmx/watcher/precompiles/Read.sol | 45 +++ .../evmx/watcher/precompiles/Schedule.sol | 169 +++++++++ .../evmx/watcher/precompiles/Timeout.sol | 116 ------ contracts/evmx/watcher/precompiles/Write.sol | 99 +++++ contracts/utils/common/Structs.sol | 31 +- 17 files changed, 738 insertions(+), 663 deletions(-) delete mode 100644 contracts/evmx/fees/WatcherFeesManager.sol rename contracts/evmx/interfaces/{IWatcherPrecompile.sol => IWatcher.sol} (94%) delete mode 100644 contracts/evmx/libs/PayloadHeaderDecoder.sol rename contracts/evmx/watcher/{WatcherPrecompileStorageAdapter.sol => Watcher.sol} (52%) create mode 100644 contracts/evmx/watcher/WatcherBase.sol delete mode 100644 contracts/evmx/watcher/precompiles/Finalize.sol delete mode 100644 contracts/evmx/watcher/precompiles/Query.sol create mode 100644 contracts/evmx/watcher/precompiles/Read.sol create mode 100644 contracts/evmx/watcher/precompiles/Schedule.sol delete mode 100644 contracts/evmx/watcher/precompiles/Timeout.sol create mode 100644 contracts/evmx/watcher/precompiles/Write.sol diff --git a/contracts/evmx/fees/WatcherFeesManager.sol b/contracts/evmx/fees/WatcherFeesManager.sol deleted file mode 100644 index 2479bf48..00000000 --- a/contracts/evmx/fees/WatcherFeesManager.sol +++ /dev/null @@ -1,65 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -pragma solidity ^0.8.21; - -import "solady/utils/Initializable.sol"; -import {Ownable} from "solady/auth/Ownable.sol"; -import {AddressResolverUtil} from "../AddressResolverUtil.sol"; -import "../interfaces/IWatcherFeesManager.sol"; -import {SCHEDULE, QUERY, FINALIZE, CALLBACK} from "../../utils/common/Constants.sol"; - -/// @title WatcherFeesManager -/// @notice Contract for managing watcher fees -contract WatcherFeesManager is IWatcherFeesManager, Initializable, Ownable, AddressResolverUtil { - // slots 0-49 (50) reserved for gauge - // slots 50-100 (51) reserved for addr resolver util - - // slots [101-150]: gap for future storage variables - uint256[50] _gap_before; - - // slot 157: fees - mapping(bytes32 => uint256) public watcherFees; - - /// @notice Emitted when the query fees are set - event WatcherFeesSet(bytes32 feeType, uint256 fees); - - error WatcherFeesNotSet(bytes32 feeType); - - /// @notice Initial initialization (version 1) - function initialize(address owner_, address addressResolver_, uint256) public reinitializer(1) { - _setAddressResolver(addressResolver_); - _initializeOwner(owner_); - } - - function setWatcherFees(bytes32 feeType, uint256 fees) external onlyOwner { - watcherFees[feeType] = fees; - emit WatcherFeesSet(feeType, fees); - } - - function getWatcherFees(bytes32 feeType) external view returns (uint256) { - return watcherFees[feeType]; - } - - function getTotalWatcherFeesRequired( - bytes32[] memory feeTypes_, - uint256[] memory counts_ - ) external view returns (uint256) { - uint256 totalFees = 0; - for (uint256 i = 0; i < feeTypes_.length; i++) { - totalFees += watcherFees[feeTypes_[i]] * counts_[i]; - } - return totalFees; - } - - function payWatcherFees( - bytes32[] memory feeTypes_, - uint256[] memory counts_, - address consumeFrom_ - ) external { - uint256 totalFees = 0; - for (uint256 i = 0; i < feeTypes_.length; i++) { - totalFees += watcherFees[feeTypes_[i]] * counts_[i]; - } - - // call to fees manager to pay fees - } -} diff --git a/contracts/evmx/interfaces/IPrecompile.sol b/contracts/evmx/interfaces/IPrecompile.sol index 2a15d93c..7155492a 100644 --- a/contracts/evmx/interfaces/IPrecompile.sol +++ b/contracts/evmx/interfaces/IPrecompile.sol @@ -10,11 +10,12 @@ interface IPrecompile { /// @param queuePayloadParams_ The queue parameters to process /// @return precompileData The encoded precompile data /// @return fees Estimated fees required for processing - function getPrecompileData(QueueParams calldata queuePayloadParams_) external returns (bytes memory precompileData, uint256 fees); + function getPrecompileData( + QueueParams calldata queuePayloadParams_ + ) external returns (bytes memory precompileData, uint256 fees); /// @notice Handles payload processing and returns fees /// @param payloadParams The payload parameters to handle /// @return fees The fees required for processing function handlePayload(PayloadParams calldata payloadParams) external returns (uint256 fees); } - diff --git a/contracts/evmx/interfaces/IWatcherPrecompile.sol b/contracts/evmx/interfaces/IWatcher.sol similarity index 94% rename from contracts/evmx/interfaces/IWatcherPrecompile.sol rename to contracts/evmx/interfaces/IWatcher.sol index b98d7770..0813c91e 100644 --- a/contracts/evmx/interfaces/IWatcherPrecompile.sol +++ b/contracts/evmx/interfaces/IWatcher.sol @@ -3,10 +3,10 @@ pragma solidity ^0.8.21; import {DigestParams, ResolvedPromises, PayloadParams, TriggerParams, PayloadSubmitParams, RequestParams} from "../../utils/common/Structs.sol"; -/// @title IWatcherPrecompile +/// @title IWatcher /// @notice Interface for the Watcher Precompile system that handles payload verification and execution /// @dev Defines core functionality for payload processing and promise resolution -interface IWatcherPrecompile { +interface IWatcher { /// @notice Emitted when a new call is made to an app gateway /// @param triggerId The unique identifier for the trigger event CalledAppGateway(bytes32 triggerId); @@ -96,24 +96,28 @@ interface IWatcherPrecompile { error InvalidLevelNumber(); error DeadlineNotPassedForOnChainRevert(); - QueueParams[] queuePayloadParams; - function queueSubmitStart(QueueParams calldata queuePayloadParams_) external; // queue: function queue(QueueParams calldata queuePayloadParams_) external; - // push in queue + // push in queue // validateAndGetPrecompileData: - // finalize: verifyConnection, max msg gas limit is under limit, - // timeout: max delay - // query: + // write: verifyConnection, max msg gas limit is under limit, + // schedule: max delay + // read: // return encoded data and fees - + /// @notice Clears the temporary queue used to store payloads for a request - function clearQueueAndPrecompileFees() external; + function clearQueue() external; + + function submitRequest( + uint256 maxFees, + address auctionManager, + address consumeFrom, + bytes onCompleteData + ) external returns (uint40 requestCount); - function submitRequest(address auctionManager, bytes onCompleteData) external returns (uint40 requestCount); // { // (params.precompileData, fees) = IPrecompile.getPrecompileData(queuePayloadParams_); // } @@ -127,15 +131,17 @@ interface IWatcherPrecompile { // total fees check from maxFees // verify if msg sender have same core app gateway // create and store req param + // clear queue // if writeCount == 0, startProcessing else wait function assignTransmitter(uint40 requestCount, Bid memory bid_) external; + // validate AM from req param // update transmitter // assignTransmitter // - block for new transmitter // refinalize payloads for new transmitter - // 0 => non zero + // 0 => non zero // non zero => non zero // - unblock credits from prev transmitter // non zero => 0 @@ -152,18 +158,20 @@ interface IWatcherPrecompile { // emit relevant events function _validateProcessBatch() external; + // if request is cancelled, return // check if all payloads from last batch are executed, else return; // check if all payloads are executed, if yes call _settleRequest function _settleRequest(uint40 requestCount) external; + // if yes, call settleFees on FM and call onCompleteData in App gateway, if not success emit DataNotExecuted() function markPayloadResolved(uint40 requestCount, RequestParams memory requestParams) external; + // update RequestTrackingParams // if(_validateProcessBatch() == true) processBatch() - /// @notice Increases the fees for a request /// @param requestCount_ The request id /// @param fees_ The new fees @@ -177,6 +185,7 @@ interface IWatcherPrecompile { ) external; function cancelRequest(uint40 requestCount) external; + // settleFees on FM function getMaxFees(uint40 requestCount) external view returns (uint256); diff --git a/contracts/evmx/libs/PayloadHeaderDecoder.sol b/contracts/evmx/libs/PayloadHeaderDecoder.sol deleted file mode 100644 index 22879a1c..00000000 --- a/contracts/evmx/libs/PayloadHeaderDecoder.sol +++ /dev/null @@ -1,166 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -pragma solidity ^0.8.21; - -import {CallType, Parallel, WriteFinality} from "../../utils/common/Structs.sol"; - -library PayloadHeaderDecoder { - // Corrected mapping (most significant bits on the left): - // [256.....................................................................80][79.............................................0] - // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - // requestCount(40) | batchCount(40) | payloadCount(40) | chainSlug(32) | callType(8) | isParallel(8) | writeFinality(8) - // - // Bits: - // requestCount: [216..255] (shift >> 216) - // batchCount: [176..215] (shift >> 176, mask 0xFFFFFFFFFF) - // payloadCount: [136..175] - // chainSlug: [104..135] - // callType: [96..103] - // isParallel: [88..95] - // writeFinality: [80..87] - - // ------------------------------------------------------------------------- - // GETTERS - // ------------------------------------------------------------------------- - function getRequestCount(bytes32 payloadHeader_) internal pure returns (uint40) { - // Top 40 bits => shift right by 216 - return uint40(uint256(payloadHeader_) >> 216); - } - - function getBatchCount(bytes32 payloadHeader_) internal pure returns (uint40) { - return uint40((uint256(payloadHeader_) >> 176) & 0xFFFFFFFFFF); - } - - function getPayloadCount(bytes32 payloadHeader_) internal pure returns (uint40) { - return uint40((uint256(payloadHeader_) >> 136) & 0xFFFFFFFFFF); - } - - function getChainSlug(bytes32 payloadHeader_) internal pure returns (uint32) { - return uint32((uint256(payloadHeader_) >> 104) & 0xFFFFFFFF); - } - - function getCallType(bytes32 payloadHeader_) internal pure returns (CallType) { - return CallType(uint8((uint256(payloadHeader_) >> 96) & 0xFF)); - } - - function getIsParallel(bytes32 payloadHeader_) internal pure returns (Parallel) { - return Parallel(uint8((uint256(payloadHeader_) >> 88) & 0xFF)); - } - - function getWriteFinality(bytes32 payloadHeader_) internal pure returns (WriteFinality) { - return WriteFinality(uint8((uint256(payloadHeader_) >> 80) & 0xFF)); - } - - // ------------------------------------------------------------------------- - // SETTERS - // ------------------------------------------------------------------------- - - /// @notice Sets the request count in a payloadHeader (top 40 bits) - function setRequestCount( - bytes32 payloadHeader_, - uint40 requestCount_ - ) internal pure returns (bytes32) { - // Clear bits [216..255], then OR in the new requestCount << 216 - return - bytes32( - (uint256(payloadHeader_) & ~((uint256(0xFFFFFFFFFF)) << 216)) | - (uint256(requestCount_) << 216) - ); - } - - /// @notice Sets the batch count in a payloadHeader [176..215] - function setBatchCount( - bytes32 payloadHeader_, - uint40 batchCount_ - ) internal pure returns (bytes32) { - return - bytes32( - (uint256(payloadHeader_) & ~((uint256(0xFFFFFFFFFF)) << 176)) | - ((uint256(batchCount_) & 0xFFFFFFFFFF) << 176) - ); - } - - /// @notice Sets the payload count [136..175] - function setPayloadCount( - bytes32 payloadHeader_, - uint40 payloadCount_ - ) internal pure returns (bytes32) { - return - bytes32( - (uint256(payloadHeader_) & ~((uint256(0xFFFFFFFFFF)) << 136)) | - ((uint256(payloadCount_) & 0xFFFFFFFFFF) << 136) - ); - } - - /// @notice Sets the chain slug [104..135] - function setChainSlug( - bytes32 payloadHeader_, - uint32 chainSlug_ - ) internal pure returns (bytes32) { - return - bytes32( - (uint256(payloadHeader_) & ~((uint256(0xFFFFFFFF)) << 104)) | - ((uint256(chainSlug_) & 0xFFFFFFFF) << 104) - ); - } - - /// @notice Sets the call type [96..103] - function setCallType( - bytes32 payloadHeader_, - CallType callType_ - ) internal pure returns (bytes32) { - return - bytes32( - (uint256(payloadHeader_) & ~((uint256(0xFF)) << 96)) | - ((uint256(uint8(callType_)) & 0xFF) << 96) - ); - } - - /// @notice Sets the parallel flag [88..95] - function setIsParallel( - bytes32 payloadHeader_, - Parallel isParallel_ - ) internal pure returns (bytes32) { - return - bytes32( - (uint256(payloadHeader_) & ~((uint256(0xFF)) << 88)) | - ((uint256(uint8(isParallel_)) & 0xFF) << 88) - ); - } - - /// @notice Sets the write finality [80..87] - function setWriteFinality( - bytes32 payloadHeader_, - WriteFinality writeFinality_ - ) internal pure returns (bytes32) { - return - bytes32( - (uint256(payloadHeader_) & ~((uint256(0xFF)) << 80)) | - ((uint256(uint8(writeFinality_)) & 0xFF) << 80) - ); - } - - // ------------------------------------------------------------------------- - // CREATE - // ------------------------------------------------------------------------- - /// @notice Creates a new payloadHeader with all fields set - function createPayloadHeader( - uint40 requestCount_, - uint40 batchCount_, - uint40 payloadCount_, - uint32 chainSlug_, - CallType callType_, - Parallel isParallel_, - WriteFinality writeFinality_ - ) internal pure returns (bytes32) { - return - bytes32( - (uint256(requestCount_) << 216) | - ((uint256(batchCount_) & 0xFFFFFFFFFF) << 176) | - ((uint256(payloadCount_) & 0xFFFFFFFFFF) << 136) | - ((uint256(chainSlug_) & 0xFFFFFFFF) << 104) | - ((uint256(uint8(callType_)) & 0xFF) << 96) | - ((uint256(uint8(isParallel_)) & 0xFF) << 88) | - ((uint256(uint8(writeFinality_)) & 0xFF) << 80) - ); - } -} diff --git a/contracts/evmx/watcher/Configurations.sol b/contracts/evmx/watcher/Configurations.sol index a119b927..447df5b7 100644 --- a/contracts/evmx/watcher/Configurations.sol +++ b/contracts/evmx/watcher/Configurations.sol @@ -179,16 +179,16 @@ contract Configurations is IConfigurations, Initializable, Ownable, AddressResol /// @param chainSlug_ The identifier of the network /// @param target_ The address of the target /// @param appGateway_ The address of the app gateway - /// @param switchboard_ The address of the switchboard + /// @param switchboardType_ The type of switchboard function verifyConnections( uint32 chainSlug_, address target_, address appGateway_, - address switchboard_ + bytes32 switchboardType_ ) external view { (bytes32 appGatewayId, address switchboard) = getPlugConfigs(chainSlug_, target_); if (appGatewayId != WatcherIdUtils.encodeAppGatewayId(appGateway_)) revert InvalidGateway(); - if (switchboard != switchboard_) revert InvalidSwitchboard(); + if (switchboard != switchboards[chainSlug_][switchboardType_]) revert InvalidSwitchboard(); } } diff --git a/contracts/evmx/watcher/PromiseResolver.sol b/contracts/evmx/watcher/PromiseResolver.sol index fbe44414..54c64b47 100644 --- a/contracts/evmx/watcher/PromiseResolver.sol +++ b/contracts/evmx/watcher/PromiseResolver.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import "../../interfaces/IWatcherPrecompile.sol"; +import "../../interfaces/IWatcher.sol"; import "../../interfaces/IPromise.sol"; import "../../libs/PayloadHeaderDecoder.sol"; import "../../common/Structs.sol"; @@ -125,7 +125,7 @@ contract PromiseResolver { uint256 currentTimestamp ) external onlyWatcherStorage returns (bool success) { // Get payload params from WatcherPrecompileStorage - PayloadParams memory payloadParams = payloads[payloadId_]; + PayloadParams memory payloadParams = payloads[payloadId_]; if (payloadParams.deadline > block.timestamp) revert DeadlineNotPassedForOnChainRevert(); RequestParams storage currentRequestParams = requestParams[ diff --git a/contracts/evmx/watcher/RequestHandler.sol b/contracts/evmx/watcher/RequestHandler.sol index 34283ef6..3d7fb870 100644 --- a/contracts/evmx/watcher/RequestHandler.sol +++ b/contracts/evmx/watcher/RequestHandler.sol @@ -1,121 +1,290 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import "../../interfaces/IWatcherPrecompile.sol"; -import "../../libs/PayloadHeaderDecoder.sol"; +import "./WatcherBase.sol"; import "../../utils/common/Structs.sol"; import "../../utils/common/Errors.sol"; +import "../../utils/common/Constants.sol"; + +import "../interfaces/IPrecompile.sol"; /// @title RequestHandler /// @notice Contract that handles request processing and management /// @dev This contract interacts with the WatcherPrecompileStorage for storage access -contract RequestHandler { - using PayloadHeaderDecoder for bytes32; +contract RequestHandler is WatcherBase { + error InvalidPrecompileData(); + error InvalidCallType(); - // The address of the WatcherPrecompileStorage contract - address public watcherStorage; + /// @notice Counter for tracking payload requests + uint40 public payloadCounter; - // Only WatcherPrecompileStorage can call functions - modifier onlyWatcherStorage() { - require(msg.sender == watcherStorage, "Only WatcherStorage can call"); - _; - } + /// @notice Counter for tracking request counts + uint40 public nextRequestCount = 1; + + /// @notice Counter for tracking batch counts + uint40 public nextBatchCount; + + /// @notice Mapping to store the list of payload IDs for each batch + mapping(uint40 => bytes32[]) public batchPayloadIds; + + /// @notice Mapping to store the batch IDs for each request + mapping(uint40 => uint40[]) public requestBatchIds; - /// @notice Sets the WatcherPrecompileStorage address - /// @param watcherStorage_ The address of the WatcherPrecompileStorage contract - constructor(address watcherStorage_) { - watcherStorage = watcherStorage_; + /// @notice Mapping to store the precompiles for each call type + mapping(bytes4 => IPrecompile) public precompiles; + + constructor(address watcherStorage_) WatcherBase(watcherStorage_) {} + + function setPrecompile(bytes4 callType_, IPrecompile precompile_) external onlyWatcherStorage { + precompiles[callType_] = precompile_; } - /// @notice Updates the WatcherPrecompileStorage address - /// @param watcherStorage_ The new address of the WatcherPrecompileStorage contract - function setWatcherStorage(address watcherStorage_) external onlyWatcherStorage { - watcherStorage = watcherStorage_; + function submitRequest( + uint256 maxFees_, + address auctionManager_, + address consumeFrom_, + address appGateway_, + QueueParams[] calldata queuePayloadParams_, + bytes memory onCompleteData_ + ) external onlyWatcherPrecompile returns (uint40 requestCount, address[] memory promiseList) { + if (queuePayloadParams_.length == 0) return uint40(0); + if (queuePayloadParams.length > REQUEST_PAYLOAD_COUNT_LIMIT) + revert RequestPayloadCountLimitExceeded(); + + address appGateway = _getCoreAppGateway(appGateway_); + if (!IFeesManager(feesManager__()).isUserCreditsEnough(consumeFrom_, appGateway, maxFees_)) + revert InsufficientFees(); + + requestCount = nextRequestCount++; + RequestParams memory r = RequestParams({ + requestTrackingParams: RequestTrackingParams({ + currentBatch: nextBatchCount, + currentBatchPayloadsLeft: 0, + payloadsRemaining: queuePayloadParams_.length + }), + requestFeesDetails: RequestFeesDetails({ + watcherFees: 0, + consumeFrom: consumeFrom_, + maxFees: maxFees_ + }), + writeCount: 0, + auctionManager: _getAuctionManager(auctionManager_), + appGateway: appGateway, + onCompleteData: onCompleteData_ + }); + + (r.requestFeesDetails.watcherFees, r.writeCount, promiseList) = _createRequest( + queuePayloadParams_, + appGateway, + requestCount + ); + + if (r.requestFeesDetails.watcherFees > maxFees_) revert InsufficientFees(); + watcherPrecompile__().setRequestParams(requestCount, r); + + if (r.writeCount == 0) startProcessingRequest(); + emit RequestSubmitted(); } - /// @notice Increases the fees for a request if no bid is placed - /// @param requestCount_ The ID of the request - /// @param newMaxFees_ The new maximum fees - function increaseFees(uint40 requestCount_, uint256 newMaxFees_) external override { - address appGateway = _getCoreAppGateway(msg.sender); - // todo: should we allow core app gateway too? - if (appGateway != requests[requestCount_].appGateway) { - revert OnlyAppGateway(); + function _createRequest( + QueueParams[] calldata queuePayloadParams_, + address appGateway_, + uint40 requestCount_ + ) + internal + returns (uint256 totalWatcherFees, uint256 writeCount, address[] memory promiseList) + { + // push first batch count + requestBatchIds[requestCount_].push(nextBatchCount); + + for (uint256 i = 0; i < queuePayloadParams.length; i++) { + QueueParams calldata queuePayloadParam = queuePayloadParams_[i]; + bytes4 callType = queuePayloadParam.overrideParams.callType; + + // checks + if (getCoreAppGateway(queuePayloadParam.appGateway) != appGateway_) + revert InvalidAppGateway(); + + if (callType == WRITE) writeCount++; + + // decide batch count + if (i > 0 && queuePayloadParams[i].isParallel != Parallel.ON) { + nextBatchCount++; + requestBatchCounts[requestCount_].push(nextBatchCount); + } + + // get the switchboard address from the watcher precompile config + address switchboard = watcherPrecompileConfig().switchboards( + queuePayloadParam.chainSlug, + queuePayloadParam.switchboardType + ); + + // process payload data and store + (uint256 fees, bytes memory precompileData) = _validateAndGetPrecompileData( + queuePayloadParam, + appGateway_, + callType + ); + totalWatcherFees += fees; + + // create payload id + uint40 payloadCount = payloadCounter++; + bytes32 payloadId = WatcherIdUtils.createPayloadId( + requestCount_, + batchCount, + payloadCount, + switchboard, + queuePayloadParam.chainSlug + ); + batchPayloadIds[batchCount].push(payloadId); + + // create prev digest hash + PayloadSubmitParams memory p = PayloadSubmitParams({ + requestCount: requestCount_, + batchCount: batchCount, + payloadCount: payloadCount, + payloadId: payloadId, + prevDigestsHash: prevDigestsHash, + precompileData: precompileData, + asyncPromise: queuePayloadParams_.asyncPromise, + appGateway: queuePayloadParams_.appGateway + }); + promiseList.push(queuePayloadParams_.asyncPromise); + watcherPrecompile__().setPayloadParams(payloadId, p); } - if (requests[requestCount_].winningBid.transmitter != address(0)) revert WinningBidExists(); - if (requests[requestCount_].maxFees >= newMaxFees_) - revert NewMaxFeesLowerThanCurrent(requests[requestCount_].maxFees, newMaxFees_); - requests[requestCount_].maxFees = newMaxFees_; - emit FeesIncreased(appGateway, requestCount_, newMaxFees_); + + nextBatchCount++; } - /// @notice Updates the transmitter for a request - /// @param requestCount The request count to update - /// @param transmitter The new transmitter address - /// @dev This function updates the transmitter for a request - /// @dev It verifies that the caller is the middleware and that the request hasn't been started yet - function updateTransmitter(uint40 requestCount, address transmitter) public { - RequestParams storage r = requestParams[requestCount]; - if (r.isRequestCancelled) revert RequestCancelled(); - if (r.payloadsRemaining == 0) revert RequestAlreadyExecuted(); - if (r.middleware != msg.sender) revert InvalidCaller(); - if (r.transmitter != address(0)) revert RequestNotProcessing(); - r.transmitter = transmitter; - - _processBatch(requestCount, r.currentBatch); + function _validateAndGetPrecompileData( + QueueParams calldata payloadParams_, + address appGateway_, + bytes4 callType_ + ) internal returns (uint256, bytes memory) { + if (address(precompiles[callType_]) == address(0)) revert InvalidCallType(); + + return + IPrecompile(precompiles[callType_]).validateAndGetPrecompileData( + payloadParams_, + appGateway_ + ); } - /// @notice Cancels a request - /// @param requestCount The request count to cancel - /// @dev This function cancels a request - /// @dev It verifies that the caller is the middleware and that the request hasn't been cancelled yet - function cancelRequest(uint40 requestCount) external { - RequestParams storage r = requestParams[requestCount]; - if (r.isRequestCancelled) revert RequestAlreadyCancelled(); - if (r.middleware != msg.sender) revert InvalidCaller(); - - r.isRequestCancelled = true; - emit RequestCancelledFromGateway(requestCount); + function _getAuctionManager(address auctionManager_) internal view returns (address) { + return + auctionManager_ == address(0) + ? addressResolver__().defaultAuctionManager() + : auctionManager_; } - /// @notice Ends the timeouts and calls the target address with the callback payload - /// @param timeoutId_ The unique identifier for the timeout - /// @param signatureNonce_ The nonce used in the watcher's signature - /// @param signature_ The watcher's signature - /// @dev It verifies if the signature is valid and the timeout hasn't been resolved yet - function resolveTimeout( - bytes32 timeoutId_, - uint256 signatureNonce_, - bytes memory signature_ - ) external { - _isWatcherSignatureValid( - abi.encode(this.resolveTimeout.selector, timeoutId_), - signatureNonce_, - signature_ - ); + //todo + function _getPreviousDigestsHash(uint40 batchCount_) internal view returns (bytes32) { + bytes32[] memory payloadIds = batchPayloadIds[batchCount_]; + bytes32 prevDigestsHash = bytes32(0); - TimeoutRequest storage timeoutRequest_ = timeoutRequests[timeoutId_]; - if (timeoutRequest_.target == address(0)) revert InvalidTimeoutRequest(); - if (timeoutRequest_.isResolved) revert TimeoutAlreadyResolved(); - if (block.timestamp < timeoutRequest_.executeAt) revert ResolvingTimeoutTooEarly(); + for (uint40 i = 0; i < payloadIds.length; i++) { + PayloadParams memory p = payloads[payloadIds[i]]; + DigestParams memory digestParams = DigestParams( + watcherPrecompileConfig__.sockets(p.payloadHeader.getChainSlug()), + p.finalizedTransmitter, + p.payloadId, + p.deadline, + p.payloadHeader.getCallType(), + p.gasLimit, + p.value, + p.payload, + p.target, + WatcherIdUtils.encodeAppGatewayId(p.appGateway), + p.prevDigestsHash + ); + prevDigestsHash = keccak256(abi.encodePacked(prevDigestsHash, getDigest(digestParams))); + } + return prevDigestsHash; + } - (bool success, , bytes memory returnData) = timeoutRequest_.target.tryCall( - 0, - gasleft(), - 0, // setting max_copy_bytes to 0 as not using returnData right now - timeoutRequest_.payload - ); - if (!success) revert CallFailed(); + // /// @notice Increases the fees for a request if no bid is placed + // /// @param requestCount_ The ID of the request + // /// @param newMaxFees_ The new maximum fees + // function increaseFees(uint40 requestCount_, uint256 newMaxFees_) external override { + // address appGateway = _getCoreAppGateway(msg.sender); + // // todo: should we allow core app gateway too? + // if (appGateway != requests[requestCount_].appGateway) { + // revert OnlyAppGateway(); + // } + // if (requests[requestCount_].winningBid.transmitter != address(0)) revert WinningBidExists(); + // if (requests[requestCount_].maxFees >= newMaxFees_) + // revert NewMaxFeesLowerThanCurrent(requests[requestCount_].maxFees, newMaxFees_); + // requests[requestCount_].maxFees = newMaxFees_; + // emit FeesIncreased(appGateway, requestCount_, newMaxFees_); + // } - timeoutRequest_.isResolved = true; - timeoutRequest_.executedAt = block.timestamp; + // /// @notice Updates the transmitter for a request + // /// @param requestCount The request count to update + // /// @param transmitter The new transmitter address + // /// @dev This function updates the transmitter for a request + // /// @dev It verifies that the caller is the middleware and that the request hasn't been started yet + // function updateTransmitter(uint40 requestCount, address transmitter) public { + // RequestParams storage r = requestParams[requestCount]; + // if (r.isRequestCancelled) revert RequestCancelled(); + // if (r.payloadsRemaining == 0) revert RequestAlreadyExecuted(); + // if (r.middleware != msg.sender) revert InvalidCaller(); + // if (r.transmitter != address(0)) revert RequestNotProcessing(); + // r.transmitter = transmitter; - emit TimeoutResolved( - timeoutId_, - timeoutRequest_.target, - timeoutRequest_.payload, - block.timestamp, - returnData - ); - } + // _processBatch(requestCount, r.currentBatch); + // } + + // /// @notice Cancels a request + // /// @param requestCount The request count to cancel + // /// @dev This function cancels a request + // /// @dev It verifies that the caller is the middleware and that the request hasn't been cancelled yet + // function cancelRequest(uint40 requestCount) external { + // RequestParams storage r = requestParams[requestCount]; + // if (r.isRequestCancelled) revert RequestAlreadyCancelled(); + // if (r.middleware != msg.sender) revert InvalidCaller(); + + // r.isRequestCancelled = true; + // emit RequestCancelledFromGateway(requestCount); + // } + + // /// @notice Ends the timeouts and calls the target address with the callback payload + // /// @param timeoutId_ The unique identifier for the timeout + // /// @param signatureNonce_ The nonce used in the watcher's signature + // /// @param signature_ The watcher's signature + // /// @dev It verifies if the signature is valid and the timeout hasn't been resolved yet + // function resolveTimeout( + // bytes32 timeoutId_, + // uint256 signatureNonce_, + // bytes memory signature_ + // ) external { + // _isWatcherSignatureValid( + // abi.encode(this.resolveTimeout.selector, timeoutId_), + // signatureNonce_, + // signature_ + // ); + + // TimeoutRequest storage timeoutRequest_ = timeoutRequests[timeoutId_]; + // if (timeoutRequest_.target == address(0)) revert InvalidTimeoutRequest(); + // if (timeoutRequest_.isResolved) revert TimeoutAlreadyResolved(); + // if (block.timestamp < timeoutRequest_.executeAt) revert ResolvingTimeoutTooEarly(); + + // (bool success, , bytes memory returnData) = timeoutRequest_.target.tryCall( + // 0, + // gasleft(), + // 0, // setting max_copy_bytes to 0 as not using returnData right now + // timeoutRequest_.payload + // ); + // if (!success) revert CallFailed(); + + // timeoutRequest_.isResolved = true; + // timeoutRequest_.executedAt = block.timestamp; + + // emit TimeoutResolved( + // timeoutId_, + // timeoutRequest_.target, + // timeoutRequest_.payload, + // block.timestamp, + // returnData + // ); + // } } diff --git a/contracts/evmx/watcher/Trigger.sol b/contracts/evmx/watcher/Trigger.sol index 4579e18d..9371d7c7 100644 --- a/contracts/evmx/watcher/Trigger.sol +++ b/contracts/evmx/watcher/Trigger.sol @@ -1,6 +1,8 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; +import {TriggerParams} from "../../utils/common/Structs.sol"; + /// @title Trigger /// @notice Contract that handles trigger validation and execution logic /// @dev This contract interacts with the WatcherPrecompileStorage for storage access @@ -17,7 +19,6 @@ contract Trigger { /// @dev callId => bool mapping(bytes32 => bool) public appGatewayCalled; - // Only WatcherPrecompileStorage can call functions modifier onlyWatcherStorage() { require(msg.sender == watcherStorage, "Only WatcherStorage can call"); @@ -59,10 +60,10 @@ contract Trigger { ) ) revert InvalidCallerTriggered(); - IFeesManager(addressResolver__.feesManager()).assignWatcherPrecompileCreditsFromAddress( - watcherPrecompileLimits__.callBackFees(), - appGateway - ); + feesManager__().assignWatcherPrecompileCreditsFromAddress( + watcherPrecompileLimits__.callBackFees(), + appGateway + ); appGatewayCaller = appGateway; appGatewayCalled[params_[i].triggerId] = true; diff --git a/contracts/evmx/watcher/WatcherPrecompileStorageAdapter.sol b/contracts/evmx/watcher/Watcher.sol similarity index 52% rename from contracts/evmx/watcher/WatcherPrecompileStorageAdapter.sol rename to contracts/evmx/watcher/Watcher.sol index 49e56817..e913fe9e 100644 --- a/contracts/evmx/watcher/WatcherPrecompileStorageAdapter.sol +++ b/contracts/evmx/watcher/Watcher.sol @@ -1,17 +1,17 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import "../PayloadHeaderDecoder.sol"; -import "../../interfaces/IWatcherPrecompile.sol"; -import {IAppGateway} from "../../interfaces/IAppGateway.sol"; -import {InvalidCallerTriggered, TimeoutDelayTooLarge, TimeoutAlreadyResolved, InvalidInboxCaller, ResolvingTimeoutTooEarly, CallFailed, AppGatewayAlreadyCalled, InvalidWatcherSignature, NonceUsed, RequestAlreadyExecuted} from "../../../utils/common/Errors.sol"; -import {ResolvedPromises, AppGatewayConfig, LimitParams, WriteFinality, UpdateLimitParams, PlugConfig, DigestParams, TimeoutRequest, QueuePayloadParams, PayloadParams, RequestParams, RequestMetadata} from "../../../utils/common/Structs.sol"; +import "../interfaces/IWatcher.sol"; -/// @title WatcherPrecompileStorage +import {InvalidCallerTriggered, TimeoutDelayTooLarge, TimeoutAlreadyResolved, InvalidInboxCaller, ResolvingTimeoutTooEarly, CallFailed, AppGatewayAlreadyCalled, InvalidWatcherSignature, NonceUsed, RequestAlreadyExecuted} from "../../utils/common/Errors.sol"; +import {ResolvedPromises, AppGatewayConfig, LimitParams, WriteFinality, UpdateLimitParams, PlugConfig, DigestParams, TimeoutRequest, QueuePayloadParams, PayloadParams, RequestParams, RequestMetadata} from "../../utils/common/Structs.sol"; + +/// @title WatcherStorage /// @notice Storage contract for the WatcherPrecompile system /// @dev This contract contains all the storage variables used by the WatcherPrecompile system /// @dev It is inherited by WatcherPrecompileCore and WatcherPrecompile -abstract contract WatcherPrecompileStorage is IWatcherPrecompile { +abstract contract WatcherStorage is IWatcher { + // todo: can we remove proxies? // slots [0-49]: gap for future storage variables uint256[50] _gap_before; @@ -19,81 +19,112 @@ abstract contract WatcherPrecompileStorage is IWatcherPrecompile { /// @notice The chain slug of the watcher precompile uint32 public evmxSlug; - // IDs - /// @notice Counter for tracking payload requests - uint40 public payloadCounter; - - /// @notice Counter for tracking request counts - uint40 public override nextRequestCount; - - /// @notice Counter for tracking batch counts - uint40 public nextBatchCount; - // Payload Params - /// @notice The time from finalize for the payload to be executed + /// @notice The time from queue for the payload to be executed /// @dev Expiry time in seconds for payload execution uint256 public expiryTime; - // slot 55 /// @notice Maps nonce to whether it has been used /// @dev Used to prevent replay attacks with signature nonces /// @dev signatureNonce => isValid mapping(uint256 => bool) public isNonceUsed; - // slot 56 - /// @notice Mapping to store watcher proofs - /// @dev Maps payload ID to proof bytes - /// @dev payloadId => proof bytes - mapping(bytes32 => bytes) public watcherProofs; - - // slot 59 - /// @notice Mapping to store the list of payload IDs for each batch - mapping(uint40 => bytes32[]) public batchPayloadIds; - - // slot 60 - /// @notice Mapping to store the batch IDs for each request - mapping(uint40 => uint40[]) public requestBatchIds; - - // slot 61 // queue => update to payloadParams, assign id, store in payloadParams map /// @notice Mapping to store the payload parameters for each payload ID mapping(bytes32 => PayloadParams) public payloads; - // slot 53 /// @notice The metadata for a request mapping(uint40 => RequestParams) public requests; - // slot 62 /// @notice The queue of payloads QueueParams[] public queue; - // slots [67-114]: gap for future storage variables - uint256[48] _gap_after; + address public latestAsyncPromise; + address public latestPromiseCaller; + + // slots [51-100]: gap for future storage variables + uint256[50] _gap_after; // slots 115-165 (51) reserved for access control // slots 166-216 (51) reserved for addr resolver util } -contract WatcherPrecompileStorageAdapter is WatcherPrecompileStorage { - /// @notice Clears the call parameters array +contract Watcher is WatcherStorage { + constructor( + address requestHandler_, + address configManager_, + address trigger_, + address precompileFeesManager_, + address promiseResolver_, + address addressResolver_ + ) { + requestHandler = requestHandler_; + configManager = configManager_; + trigger = trigger_; + precompileFeesManager = precompileFeesManager_; + promiseResolver = promiseResolver_; + addressResolver = addressResolver_; + } + + /// @notice Clears the call parameters array function clearQueue() public { - delete queuePayloadParams; + delete queue; } + // todo: delegate call? + // todo: check app gateway input auth /// @notice Queues a new payload - /// @param queuePayloadParams_ The call parameters - function queue(QueuePayloadParams memory queuePayloadParams_) external { - queuePayloadParams.push(queuePayloadParams_); + /// @param queue_ The call parameters + function queue( + QueueParams memory queue_, + address appGateway_ + ) external returns (address, uint40) { + // Deploy a new async promise contract. + latestAsyncPromise = asyncDeployer__().deployAsyncPromiseContract(appGateway_); + queue_.asyncPromise = latestAsyncPromise; + + // Add the promise to the queue. + queue.push(queue_); + // return the promise and request count + return (latestAsyncPromise, requestHandler.nextRequestCount()); } - - /// @notice Marks a request as finalized with a proof on digest - /// @param payloadId_ The unique identifier of the request - /// @param proof_ The watcher's proof - /// @dev This function marks a request as finalized with a proof - function finalized(bytes32 payloadId_, bytes memory proof_) public onlyOwner { - watcherProofs[payloadId_] = proof_; - emit Finalized(payloadId_, proof_); + function then(bytes4 selector_, bytes memory data_) external { + if (latestAsyncPromise == address(0)) revert NoAsyncPromiseFound(); + if (latestRequestCount != requestHandler.nextRequestCount()) revert RequestCountMismatch(); + + address latestAsyncPromise_ = latestAsyncPromise; + latestAsyncPromise = address(0); + + // as same req count is checked, assuming app gateway will be same else it will revert on batch + promise_ = IPromise(latestAsyncPromise_).then(selector_, data_); + } + + function submitRequest( + uint256 maxFees, + address auctionManager, + address consumeFrom, + bytes onCompleteData + ) external returns (uint40 requestCount, address[] memory promiseList) { + (requestCount, promiseList) = requestHandler.submitRequest( + maxFees, + auctionManager, + consumeFrom, + msg.sender, + queue, + onCompleteData + ); + clearQueue(); + } + + function setPayloadParams(bytes32 payloadId_, PayloadParams memory payloadParams_) external { + if (msg.sender != address(requestHandler)) revert InvalidCaller(); + payloads[payloadId_] = payloadParams_; + } + + function setRequestParams(uint40 requestCount_, RequestParams memory requestParams_) external { + if (msg.sender != address(requestHandler)) revert InvalidCaller(); + requests[requestCount_] = requestParams_; } /// @notice Sets the expiry time for payload execution @@ -105,24 +136,13 @@ contract WatcherPrecompileStorageAdapter is WatcherPrecompileStorage { emit ExpiryTimeSet(expiryTime_); } - - /// @notice Gets the current request count - /// @return The current request count - /// @dev This function returns the next request count, which is the current request count - function getCurrentRequestCount() external view returns (uint40) { - return nextRequestCount; - } - - /// @notice Gets the request parameters for a request - /// @param requestCount The request count to get the parameters for - /// @return The request parameters for the given request count - function getRequestParams(uint40 requestCount) external view returns (RequestParams memory) { - return requestParams[requestCount]; - } - - // all function from watcher requiring signature - function watcherMultiCall(address[] callData contracts, bytes[] callData data_, uint256[] calldata nonces_, bytes[] callData signatures_) { + function watcherMultiCall( + address[] memory contracts, + bytes[] memory data_, + uint256[] memory nonces_, + bytes[] memory signatures_ + ) external { for (uint40 i = 0; i < contracts.length; i++) { if (contracts[i] == address(0)) revert InvalidContract(); if (data_[i].length == 0) revert InvalidData(); @@ -130,7 +150,8 @@ contract WatcherPrecompileStorageAdapter is WatcherPrecompileStorage { if (signatures_[i].length == 0) revert InvalidSignature(); // check if signature is valid - if (!_isWatcherSignatureValid(nonces_[i], data_[i], signatures_[i])) revert InvalidSignature(); + if (!_isWatcherSignatureValid(nonces_[i], data_[i], signatures_[i])) + revert InvalidSignature(); // call the contract (bool success, bytes memory result) = contracts[i].call(data_[i]); @@ -138,7 +159,7 @@ contract WatcherPrecompileStorageAdapter is WatcherPrecompileStorage { } } - /// @notice Verifies that a watcher signature is valid + /// @notice Verifies that a watcher signature is valid /// @param signatureNonce_ The nonce of the signature /// @param inputData_ The input data to verify /// @param signature_ The signature to verify diff --git a/contracts/evmx/watcher/WatcherBase.sol b/contracts/evmx/watcher/WatcherBase.sol new file mode 100644 index 00000000..cb499eae --- /dev/null +++ b/contracts/evmx/watcher/WatcherBase.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import "../interfaces/IWatcher.sol"; + +/// @title WatcherBase +contract WatcherBase { + // The address of the WatcherPrecompileStorage contract + address public watcher; + + // Only WatcherPrecompileStorage can call functions + modifier onlyWatcher() { + require(msg.sender == watcher, "Only Watcher can call"); + _; + } + + /// @notice Sets the WatcherPrecompileStorage address + /// @param watcher_ The address of the WatcherPrecompileStorage contract + constructor(address watcher_) { + watcher = watcher_; + } + + /// @notice Updates the WatcherPrecompileStorage address + /// @param watcher_ The new address of the WatcherPrecompileStorage contract + function setWatcher(address watcher_) external onlyWatcher { + watcher = watcher_; + } +} diff --git a/contracts/evmx/watcher/precompiles/Finalize.sol b/contracts/evmx/watcher/precompiles/Finalize.sol deleted file mode 100644 index 8d9494e5..00000000 --- a/contracts/evmx/watcher/precompiles/Finalize.sol +++ /dev/null @@ -1,57 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -pragma solidity ^0.8.21; - -import "../../interfaces/IWatcherPrecompile.sol"; -import "../../libs/PayloadHeaderDecoder.sol"; -import "../../../utils/common/Structs.sol"; -import "../../../utils/common/Errors.sol"; - -/// @title Finalize -/// @notice Handles finalization precompile logic -contract Finalize is IPrecompile { - using PayloadHeaderDecoder for bytes32; - - /// @notice The watcher precompile fees manager - IWatcherFeesManager public immutable watcherFeesManager; - - /// @notice Gets precompile data and fees for queue parameters - /// @param queuePayloadParams_ The queue parameters to process - /// @return precompileData The encoded precompile data - /// @return fees Estimated fees required for processing - function getPrecompileData( - QueueParams calldata queuePayloadParams_ - ) external pure returns (bytes memory precompileData, uint256 fees) { - // For finalize precompile, encode the payload parameters - precompileData = abi.encode( - queuePayloadParams_.transaction, - queuePayloadParams_.overrideParams - ); - fees = watcherFeesManager.finalizeFees(); - } - - /// @notice Handles payload processing and returns fees - /// @param payloadParams The payload parameters to handle - /// @return fees The fees required for processing - function handlePayload( - PayloadParams calldata payloadParams - ) external pure returns (uint256 fees) { - fees = watcherFeesManager.finalizeFees(); - emit FinalizeRequested(bytes32(0), payloadParams); // digest will be calculated in core - } - - /// @notice Updates the maximum message value limit for multiple chains - /// @param chainSlugs_ Array of chain identifiers - /// @param maxMsgValueLimits_ Array of corresponding maximum message value limits - function updateChainMaxMsgValueLimits( - uint32[] calldata chainSlugs_, - uint256[] calldata maxMsgValueLimits_ - ) external onlyOwner { - if (chainSlugs_.length != maxMsgValueLimits_.length) revert InvalidIndex(); - - for (uint256 i = 0; i < chainSlugs_.length; i++) { - chainMaxMsgValueLimit[chainSlugs_[i]] = maxMsgValueLimits_[i]; - } - - emit ChainMaxMsgValueLimitsUpdated(chainSlugs_, maxMsgValueLimits_); - } -} diff --git a/contracts/evmx/watcher/precompiles/Query.sol b/contracts/evmx/watcher/precompiles/Query.sol deleted file mode 100644 index 6c1058eb..00000000 --- a/contracts/evmx/watcher/precompiles/Query.sol +++ /dev/null @@ -1,46 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -pragma solidity ^0.8.21; - -import "../../interfaces/IWatcherPrecompile.sol"; -import "../../libs/PayloadHeaderDecoder.sol"; -import "../../../utils/common/Structs.sol"; -import "../../../utils/common/Errors.sol"; - -/// @title Query -/// @notice Handles query precompile logic -contract Query is IPrecompile { - using PayloadHeaderDecoder for bytes32; - - /// @notice Emitted when a new query is requested - event QueryRequested(PayloadParams params); - - /// @notice The watcher precompile fees manager - IWatcherFeesManager public immutable watcherFeesManager; - - /// @notice Gets precompile data and fees for queue parameters - /// @param queuePayloadParams_ The queue parameters to process - /// @return precompileData The encoded precompile data - /// @return fees Estimated fees required for processing - function getPrecompileData( - QueueParams calldata queuePayloadParams_ - ) external pure returns (bytes memory precompileData, uint256 fees) { - if (queuePayloadParams_.target != address(0)) revert InvalidTarget(); - - // For query precompile, encode the payload parameters - precompileData = abi.encode( - queuePayloadParams_.transaction, - queuePayloadParams_.overrideParams.readAt - ); - fees = watcherFeesManager.queryFees(); - } - - /// @notice Handles payload processing and returns fees - /// @param payloadParams The payload parameters to handle - /// @return fees The fees required for processing - function handlePayload( - PayloadParams calldata payloadParams - ) external pure returns (uint256 fees) { - fees = watcherFeesManager.queryFees(); - emit QueryRequested(payloadParams); - } -} diff --git a/contracts/evmx/watcher/precompiles/Read.sol b/contracts/evmx/watcher/precompiles/Read.sol new file mode 100644 index 00000000..3129bd22 --- /dev/null +++ b/contracts/evmx/watcher/precompiles/Read.sol @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import "../../interfaces/IWatcher.sol"; +import "../../../utils/common/Structs.sol"; +import "../../../utils/common/Errors.sol"; + +/// @title Read +/// @notice Handles read precompile logic +contract Read is IPrecompile { + /// @notice Emitted when a new read is requested + event ReadRequested(PayloadParams params); + + uint256 public readFees; + uint256 public callbackFees; + + /// @notice Gets precompile data and fees for queue parameters + /// @param queuePayloadParams_ The queue parameters to process + /// @return precompileData The encoded precompile data + /// @return fees Estimated fees required for processing + function validateAndGetPrecompileData( + QueueParams calldata queuePayloadParams_, + address + ) external view returns (bytes memory precompileData, uint256 fees) { + if (queuePayloadParams_.transaction.target != address(0)) revert InvalidTarget(); + if (queuePayloadParams_.transaction.payload.length > 0) revert InvalidPayloadSize(); + + // For read precompile, encode the payload parameters + precompileData = abi.encode( + queuePayloadParams_.transaction, + queuePayloadParams_.overrideParams.readAtBlockNumber + ); + fees = readFees + callbackFees; + } + + /// @notice Handles payload processing and returns fees + /// @param payloadParams The payload parameters to handle + /// @return fees The fees required for processing + function handlePayload( + PayloadParams calldata payloadParams + ) external pure returns (uint256 fees) { + fees = readFees + callbackFees; + emit ReadRequested(payloadParams); + } +} diff --git a/contracts/evmx/watcher/precompiles/Schedule.sol b/contracts/evmx/watcher/precompiles/Schedule.sol new file mode 100644 index 00000000..06a6efb7 --- /dev/null +++ b/contracts/evmx/watcher/precompiles/Schedule.sol @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import "../../interfaces/IPrecompile.sol"; +import "../../../utils/common/Structs.sol"; +import "../../../utils/common/Errors.sol"; + +/// @title Schedule +/// @notice Library that handles schedule logic for the WatcherPrecompile system +/// @dev This library contains pure functions for schedule operations +contract Schedule is IPrecompile { + // slot 52 + /// @notice The maximum delay for a schedule + /// @dev Maximum schedule delay in seconds + uint256 public maxScheduleDelayInSeconds; + + /// @notice The fees per second for a schedule + uint256 public scheduleFeesPerSecond; + /// @notice The callback fees for a schedule + uint256 public scheduleCallbackFees; + + /// @notice Emitted when the maximum schedule delay in seconds is set + event MaxScheduleDelayInSecondsSet(uint256 maxScheduleDelayInSeconds_); + /// @notice Emitted when the fees per second for a schedule is set + event ScheduleFeesPerSecondSet(uint256 scheduleFeesPerSecond_); + /// @notice Emitted when the callback fees for a schedule is set + event ScheduleCallbackFeesSet(uint256 scheduleCallbackFees_); + + /// @notice Sets the maximum schedule delay in seconds + /// @param maxScheduleDelayInSeconds_ The maximum schedule delay in seconds + /// @dev This function sets the maximum schedule delay in seconds + /// @dev Only callable by the contract owner + function setMaxScheduleDelayInSeconds(uint256 maxScheduleDelayInSeconds_) external onlyOwner { + maxScheduleDelayInSeconds = maxScheduleDelayInSeconds_; + emit MaxScheduleDelayInSecondsSet(maxScheduleDelayInSeconds_); + } + + /// @notice Sets the fees per second for a schedule + /// @param scheduleFeesPerSecond_ The fees per second for a schedule + /// @dev This function sets the fees per second for a schedule + /// @dev Only callable by the contract owner + function setScheduleFeesPerSecond(uint256 scheduleFeesPerSecond_) external onlyOwner { + scheduleFeesPerSecond = scheduleFeesPerSecond_; + emit ScheduleFeesPerSecondSet(scheduleFeesPerSecond_); + } + + /// @notice Sets the callback fees for a schedule + /// @param scheduleCallbackFees_ The callback fees for a schedule + /// @dev This function sets the callback fees for a schedule + /// @dev Only callable by the contract owner + function setScheduleCallbackFees(uint256 scheduleCallbackFees_) external onlyOwner { + scheduleCallbackFees = scheduleCallbackFees_; + emit ScheduleCallbackFeesSet(scheduleCallbackFees_); + } + + /// @notice Validates schedule parameters and return data with fees + /// @dev assuming that tx is executed on EVMx chain + function validateAndGetPrecompileData( + QueueParams calldata queuePayloadParams_, + address appGateway_ + ) external view returns (bytes memory precompileData, uint256 fees) { + if ( + queuePayloadParams_.transaction.target != address(0) && + appGateway_ != getCoreAppGateway(queuePayloadParams_.transaction.target) + ) revert InvalidTarget(); + + if ( + queuePayloadParams_.transaction.payload.length > 0 && + queuePayloadParams_.transaction.payload.length < PAYLOAD_SIZE_LIMIT + ) { + revert InvalidPayloadSize(); + } + if (queuePayloadParams_.overrideParams.delayInSeconds > maxScheduleDelayInSeconds) + revert InvalidScheduleDelay(); + + // todo: how do we store tx data in promise and execute? + + // For schedule precompile, encode the payload parameters + precompileData = abi.encode( + queuePayloadParams_.transaction, + queuePayloadParams_.overrideParams.delayInSeconds + ); + + fees = + scheduleFeesPerSecond * + queuePayloadParams_.overrideParams.delayInSeconds + + scheduleCallbackFees; + } + + // /// @notice Encodes a unique schedule ID + // /// @param scheduleIdPrefix The prefix for schedule IDs + // /// @param counter The counter value to include in the ID + // /// @return scheduleId The encoded schedule ID + // function encodeScheduleId( + // uint256 scheduleIdPrefix, + // uint256 counter + // ) public pure returns (bytes32 scheduleId) { + // // Encode schedule ID by bit-shifting and combining: + // // EVMx chainSlug (32 bits) | watcher precompile address (160 bits) | counter (64 bits) + // return bytes32(scheduleIdPrefix | counter); + // } + + /// @notice Prepares a schedule request + /// @param target The target address for the schedule callback + /// @param delayInSeconds_ The delay in seconds before the schedule executes + /// @param executeAt The timestamp when the schedule should be executed + /// @param payload_ The payload data to be executed after the schedule + /// @return request The prepared schedule request + function prepareScheduleRequest( + address target, + uint256 delayInSeconds_, + uint256 executeAt, + bytes memory payload_ + ) public pure returns (ScheduleRequest memory request) { + request.target = target; + request.delayInSeconds = delayInSeconds_; + request.executeAt = executeAt; + request.payload = payload_; + request.isResolved = false; + request.executedAt = 0; + return request; + } + + /// @notice Validates schedule resolution conditions + /// @param request The schedule request to validate + /// @param currentTimestamp The current block timestamp + /// @return isValid Whether the schedule can be resolved + function _validateScheduleResolution( + ScheduleRequest memory request, + uint256 currentTimestamp + ) internal pure returns (bool isValid) { + if (request.target == address(0)) return false; + if (request.isResolved) return false; + if (currentTimestamp < request.executeAt) return false; + return true; + } + + /// @notice Creates the event data for schedule request + /// @param scheduleId The unique identifier for the schedule + /// @param target The target address for the schedule callback + /// @param payload The payload data to be executed + /// @param executeAt The timestamp when the schedule should be executed + /// @return The encoded event data for schedule request + function createScheduleRequestEventData( + bytes32 scheduleId, + address target, + bytes memory payload, + uint256 executeAt + ) public pure returns (bytes memory) { + return abi.encode(scheduleId, target, payload, executeAt); + } + + /// @notice Creates the event data for schedule resolution + /// @param scheduleId The unique identifier for the schedule + /// @param target The target address for the schedule callback + /// @param payload The payload data that was executed + /// @param executedAt The timestamp when the schedule was executed + /// @param returnData The return data from the schedule execution + /// @return The encoded event data for schedule resolution + function createScheduleResolvedEventData( + bytes32 scheduleId, + address target, + bytes memory payload, + uint256 executedAt, + bytes memory returnData + ) public pure returns (bytes memory) { + return abi.encode(scheduleId, target, payload, executedAt, returnData); + } +} diff --git a/contracts/evmx/watcher/precompiles/Timeout.sol b/contracts/evmx/watcher/precompiles/Timeout.sol deleted file mode 100644 index 90700066..00000000 --- a/contracts/evmx/watcher/precompiles/Timeout.sol +++ /dev/null @@ -1,116 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -pragma solidity ^0.8.21; - -import "../../interfaces/IWatcherPrecompile.sol"; -import "../../../utils/common/Structs.sol"; -import "../../../utils/common/Errors.sol"; - -/// @title Timeout -/// @notice Library that handles timeout logic for the WatcherPrecompile system -/// @dev This library contains pure functions for timeout operations -library Timeout { - // slot 52 - /// @notice The maximum delay for a timeout - /// @dev Maximum timeout delay in seconds - uint256 public maxTimeoutDelayInSeconds; - - /// @notice Sets the maximum timeout delay in seconds - /// @param maxTimeoutDelayInSeconds_ The maximum timeout delay in seconds - /// @dev This function sets the maximum timeout delay in seconds - /// @dev Only callable by the contract owner - function setMaxTimeoutDelayInSeconds(uint256 maxTimeoutDelayInSeconds_) external onlyOwner { - maxTimeoutDelayInSeconds = maxTimeoutDelayInSeconds_; - emit MaxTimeoutDelayInSecondsSet(maxTimeoutDelayInSeconds_); - } - - /// @notice Validates timeout parameters - /// @param delayInSeconds_ The delay in seconds before the timeout executes - /// @param maxTimeoutDelayInSeconds The maximum allowed timeout delay - /// @return isValid Whether the timeout parameters are valid - function validateTimeoutParams( - uint256 delayInSeconds_, - uint256 maxTimeoutDelayInSeconds - ) public pure returns (bool isValid) { - return delayInSeconds_ <= maxTimeoutDelayInSeconds; - } - - /// @notice Encodes a unique timeout ID - /// @param timeoutIdPrefix The prefix for timeout IDs - /// @param counter The counter value to include in the ID - /// @return timeoutId The encoded timeout ID - function encodeTimeoutId( - uint256 timeoutIdPrefix, - uint256 counter - ) public pure returns (bytes32 timeoutId) { - // Encode timeout ID by bit-shifting and combining: - // EVMx chainSlug (32 bits) | watcher precompile address (160 bits) | counter (64 bits) - return bytes32(timeoutIdPrefix | counter); - } - - /// @notice Prepares a timeout request - /// @param target The target address for the timeout callback - /// @param delayInSeconds_ The delay in seconds before the timeout executes - /// @param executeAt The timestamp when the timeout should be executed - /// @param payload_ The payload data to be executed after the timeout - /// @return request The prepared timeout request - function prepareTimeoutRequest( - address target, - uint256 delayInSeconds_, - uint256 executeAt, - bytes memory payload_ - ) public pure returns (TimeoutRequest memory request) { - request.target = target; - request.delayInSeconds = delayInSeconds_; - request.executeAt = executeAt; - request.payload = payload_; - request.isResolved = false; - request.executedAt = 0; - return request; - } - - /// @notice Validates timeout resolution conditions - /// @param request The timeout request to validate - /// @param currentTimestamp The current block timestamp - /// @return isValid Whether the timeout can be resolved - function validateTimeoutResolution( - TimeoutRequest memory request, - uint256 currentTimestamp - ) public pure returns (bool isValid) { - if (request.target == address(0)) return false; - if (request.isResolved) return false; - if (currentTimestamp < request.executeAt) return false; - return true; - } - - /// @notice Creates the event data for timeout request - /// @param timeoutId The unique identifier for the timeout - /// @param target The target address for the timeout callback - /// @param payload The payload data to be executed - /// @param executeAt The timestamp when the timeout should be executed - /// @return The encoded event data for timeout request - function createTimeoutRequestEventData( - bytes32 timeoutId, - address target, - bytes memory payload, - uint256 executeAt - ) public pure returns (bytes memory) { - return abi.encode(timeoutId, target, payload, executeAt); - } - - /// @notice Creates the event data for timeout resolution - /// @param timeoutId The unique identifier for the timeout - /// @param target The target address for the timeout callback - /// @param payload The payload data that was executed - /// @param executedAt The timestamp when the timeout was executed - /// @param returnData The return data from the timeout execution - /// @return The encoded event data for timeout resolution - function createTimeoutResolvedEventData( - bytes32 timeoutId, - address target, - bytes memory payload, - uint256 executedAt, - bytes memory returnData - ) public pure returns (bytes memory) { - return abi.encode(timeoutId, target, payload, executedAt, returnData); - } -} diff --git a/contracts/evmx/watcher/precompiles/Write.sol b/contracts/evmx/watcher/precompiles/Write.sol new file mode 100644 index 00000000..0b544697 --- /dev/null +++ b/contracts/evmx/watcher/precompiles/Write.sol @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import "../../interfaces/IWatcher.sol"; +import "../../../utils/common/Structs.sol"; +import "../../../utils/common/Errors.sol"; + +/// @title Write +/// @notice Handles write precompile logic +contract Write is IPrecompile { + /// @notice Mapping to store watcher proofs + /// @dev Maps payload ID to proof bytes + /// @dev payloadId => proof bytes + mapping(bytes32 => bytes) public watcherProofs; + + uint256 public writeFees; + uint256 public callbackFees; + + /// @notice Gets precompile data and fees for queue parameters + /// @param queuePayloadParams_ The queue parameters to process + /// @return precompileData The encoded precompile data + /// @return fees Estimated fees required for processing + function validateAndGetPrecompileData( + QueueParams calldata queuePayloadParams_, + address appGateway_ + ) external view returns (bytes memory precompileData, uint256 fees) { + if (queuePayloadParams_.value > chainMaxMsgValueLimit[queuePayloadParams_.chainSlug]) + revert MaxMsgValueLimitExceeded(); + + if (queuePayloadParams_.transaction.target != address(0)) { + revert InvalidTarget(); + } + + if ( + queuePayloadParams_.transaction.payload.length > 0 && + queuePayloadParams_.transaction.payload.length < PAYLOAD_SIZE_LIMIT + ) { + revert InvalidPayloadSize(); + } + + configurations__().verifyConnections( + queuePayloadParams_.chainSlug, + queuePayloadParams_.transaction.target, + appGateway_, + queuePayloadParams_.switchboardType + ); + + // For write precompile, encode the payload parameters + precompileData = abi.encode( + queuePayloadParams_.transaction, + queuePayloadParams_.overrideParams.writeFinality, + queuePayloadParams_.overrideParams.gasLimit, + queuePayloadParams_.overrideParams.value + ); + + //todo: no callback fees if callback data not set in promise + fees = writeFees + callbackFees; + } + + /// @notice Handles payload processing and returns fees + /// @param payloadParams The payload parameters to handle + /// @return fees The fees required for processing + function handlePayload( + PayloadParams calldata payloadParams + ) external pure returns (uint256 fees) { + fees = writeFees + callbackFees; + emit WriteRequested(payloadParams); + } + + /// @notice Marks a write request as finalized with a proof on digest + /// @param payloadId_ The unique identifier of the request + /// @param proof_ The watcher's proof + function finalize(bytes32 payloadId_, bytes memory proof_) public onlyOwner { + watcherProofs[payloadId_] = proof_; + emit Finalized(payloadId_, proof_); + } + + /// @notice Updates the maximum message value limit for multiple chains + /// @param chainSlugs_ Array of chain identifiers + /// @param maxMsgValueLimits_ Array of corresponding maximum message value limits + function updateChainMaxMsgValueLimits( + uint32[] calldata chainSlugs_, + uint256[] calldata maxMsgValueLimits_ + ) external onlyOwner { + if (chainSlugs_.length != maxMsgValueLimits_.length) revert InvalidIndex(); + + for (uint256 i = 0; i < chainSlugs_.length; i++) { + chainMaxMsgValueLimit[chainSlugs_[i]] = maxMsgValueLimits_[i]; + } + + emit ChainMaxMsgValueLimitsUpdated(chainSlugs_, maxMsgValueLimits_); + } + + function setFees(uint256 writeFees_, uint256 callbackFees_) external onlyOwner { + writeFees = writeFees_; + callbackFees = callbackFees_; + emit FeesSet(writeFees_, callbackFees_); + } +} diff --git a/contracts/utils/common/Structs.sol b/contracts/utils/common/Structs.sol index 31295861..e4742e40 100644 --- a/contracts/utils/common/Structs.sol +++ b/contracts/utils/common/Structs.sol @@ -2,12 +2,6 @@ pragma solidity ^0.8.21; //// ENUMS //// -enum CallType { - READ, - WRITE, - SCHEDULE -} - enum IsPlug { YES, NO @@ -50,18 +44,6 @@ enum ExecutionStatus { Reverted } -// not needed -/// @notice Creates a struct to hold batch parameters -struct BatchParams { - address appGateway; - address auctionManager; - uint256 maxFees; - bytes onCompleteData; - bool onlyReadRequests; - uint256 queryCount; - uint256 finalizeCount; -} - struct AppGatewayWhitelistParams { address appGateway; bool isApproved; @@ -113,7 +95,7 @@ struct Bid { } struct ExecuteParams { - CallType callType; + bytes4 callType; uint40 requestCount; uint40 batchCount; uint40 payloadCount; @@ -150,7 +132,7 @@ struct DigestParams { address transmitter; bytes32 payloadId; uint256 deadline; - CallType callType; + bytes4 callType; uint256 gasLimit; uint256 value; bytes payload; @@ -160,12 +142,13 @@ struct DigestParams { } // App gateway base: struct OverrideParams { - CallType callType; + bytes4 callType; Parallel isParallelCall; WriteFinality writeFinality; uint256 gasLimit; uint256 value; - uint256 readAt; + uint256 readAtBlockNumber; + uint256 delayInSeconds; } // payload @@ -184,7 +167,7 @@ struct QueueParams { OverrideParams overrideParams; Transaction transaction; address asyncPromise; - address switchboard; + bytes32 switchboardType; } struct PayloadParams { @@ -232,7 +215,7 @@ struct RequestParams { RequestFeesDetails requestFeesDetails; address appGateway; address auctionManager; - uint256 finalizeCount; + uint256 writeCount; bool isRequestExecuted; bytes onCompleteData; } From 98324cc61d13ab5e945febdac6e31876d3b6e396 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Wed, 14 May 2025 17:38:32 +0530 Subject: [PATCH 013/130] fix: helpers and utils --- contracts/evmx/base/AppGatewayBase.sol | 139 +++++++++++------- contracts/evmx/helpers/AddressResolver.sol | 25 +++- .../evmx/helpers/AddressResolverUtil.sol | 25 +++- contracts/evmx/helpers/AsyncDeployer.sol | 25 +--- contracts/evmx/helpers/AsyncPromise.sol | 29 +--- contracts/evmx/helpers/Forwarder.sol | 38 ++--- contracts/utils/common/Constants.sol | 9 +- 7 files changed, 150 insertions(+), 140 deletions(-) diff --git a/contracts/evmx/base/AppGatewayBase.sol b/contracts/evmx/base/AppGatewayBase.sol index 2b2fa9b7..526138f6 100644 --- a/contracts/evmx/base/AppGatewayBase.sol +++ b/contracts/evmx/base/AppGatewayBase.sol @@ -1,14 +1,12 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import "../AddressResolverUtil.sol"; +import "../helpers/AddressResolverUtil.sol"; import "../interfaces/IAppGateway.sol"; import "../interfaces/IForwarder.sol"; -import "../interfaces/IMiddleware.sol"; -import "../interfaces/IPromise.sol"; import {InvalidPromise, FeesNotSet, AsyncModifierNotUsed} from "../../utils/common/Errors.sol"; -import {FAST} from "../../utils/common/Constants.sol"; +import {FAST, READ, WRITE, SCHEDULE} from "../../utils/common/Constants.sol"; /// @title AppGatewayBase /// @notice Abstract contract for the app gateway @@ -28,59 +26,54 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { address public consumeFrom; /// @notice Modifier to treat functions async - modifier async(bytes memory feesApprovalData_) { - _preAsync(feesApprovalData_); + modifier async() { + _preAsync(); _; _postAsync(); } - // todo: can't overload modifier with same name, can rename later - /// @notice Modifier to treat functions async with consume from address - modifier asyncWithConsume(address consumeFrom_) { - _preAsync(new bytes(0)); - consumeFrom = consumeFrom_; + /// @notice Modifier to ensure only valid promises can call the function + /// @dev only valid promises can call the function + modifier onlyPromises() { + if (!isValidPromise[msg.sender]) revert InvalidPromise(); + // remove promise once resolved + isValidPromise[msg.sender] = false; _; - _postAsync(); + } + + /// @notice Constructor for AppGatewayBase + /// @param addressResolver_ The address resolver address + constructor(address addressResolver_) { + _setAddressResolver(addressResolver_); + sbType = FAST; } function _postAsync() internal { isAsyncModifierSet = false; - watcher__().submitRequest(maxFees, auctionManager, consumeFrom, onCompleteData); - _markValidPromises(); - onCompleteData = bytes(""); + (uint40 requestCount, address[] memory promises) = watcherPrecompile__().submitRequest( + maxFees, + auctionManager, + consumeFrom, + onCompleteData + ); + _markValidPromises(promises); } - function _preAsync(bytes memory feesApprovalData_) internal { + function _preAsync() internal { isAsyncModifierSet = true; _clearOverrides(); - watcher__().clearQueue(); - addressResolver__.clearPromises(); + watcherPrecompile__().clearQueue(); + } + function _approveFeesWithSignature(bytes memory feesApprovalData_) internal { _handleFeesApproval(feesApprovalData_); } function _handleFeesApproval(bytes memory feesApprovalData_) internal { if (feesApprovalData_.length > 0) { - (consumeFrom, , ) = IFeesManager(addressResolver__.feesManager()) - .whitelistAppGatewayWithSignature(feesApprovalData_); - } else consumeFrom = address(this); - } - - /// @notice Modifier to ensure only valid promises can call the function - /// @dev only valid promises can call the function - modifier onlyPromises() { - if (!isValidPromise[msg.sender]) revert InvalidPromise(); - // remove promise once resolved - isValidPromise[msg.sender] = false; - _; - } - - /// @notice Constructor for AppGatewayBase - /// @param addressResolver_ The address resolver address - constructor(address addressResolver_) { - _setAddressResolver(addressResolver_); - sbType = FAST; + (consumeFrom, , ) = feesManager__().whitelistAppGatewayWithSignature(feesApprovalData_); + } } /// @notice Sets the switchboard type @@ -109,10 +102,9 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { } /// @notice Marks the promises as valid - function _markValidPromises() internal { - address[] memory promises = addressResolver__.getPromises(); - for (uint256 i = 0; i < promises.length; i++) { - isValidPromise[promises[i]] = true; + function _markValidPromises(address[] memory promises_) internal { + for (uint256 i = 0; i < promises_.length; i++) { + isValidPromise[promises_[i]] = true; } } @@ -137,11 +129,33 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { _deploy(contractId_, chainSlug_, isPlug_, new bytes(0)); } + function _schedule(uint256 delayInSeconds_, bytes memory payload_) internal { + if (!isAsyncModifierSet) revert AsyncModifierNotUsed(); + overrideParams.callType = SCHEDULE; + overrideParams.delayInSeconds = delayInSeconds_; + + (address promise_, ) = watcherPrecompile__().queue( + QueuePayloadParams({ + overrideParams: overrideParams, + transaction: Transaction({ + chainSlug: uint32(0), + target: address(this), + payload: payload_ + }), + asyncPromise: address(0), + switchboardType: sbType + }), + address(this) + ); + + watcher__().then(promise_); + } + /// @notice Gets the socket address /// @param chainSlug_ The chain slug /// @return socketAddress_ The socket address function getSocketAddress(uint32 chainSlug_) public view returns (address) { - return watcherPrecompileConfig().sockets(chainSlug_); + return watcherPrecompile__().sockets(chainSlug_); } /// @notice Gets the on-chain address @@ -156,7 +170,12 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { return address(0); } - onChainAddress = IForwarder(forwarderAddresses[contractId_][chainSlug_]).getOnChainAddress(); + onChainAddress = IForwarder(forwarderAddresses[contractId_][chainSlug_]) + .getOnChainAddress(); + } + + function _setCallType(Read isReadCall_) internal { + overrideParams.callType = isReadCall_ ? READ : WRITE; } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -174,19 +193,27 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { uint256 gasLimit_, uint256 fees_ ) internal { - overrideParams.isReadCall = isReadCall_; + _setCallType(isReadCall_); overrideParams.isParallelCall = isParallelCall_; overrideParams.gasLimit = gasLimit_; maxFees = fees_; } function _clearOverrides() internal { - overrideParams.isReadCall = Read.OFF; + overrideParams.callType = WRITE; overrideParams.isParallelCall = Parallel.OFF; overrideParams.gasLimit = 0; overrideParams.value = 0; - overrideParams.readAt = 0; + overrideParams.readAtBlockNumber = 0; overrideParams.writeFinality = WriteFinality.LOW; + overrideParams.delayInSeconds = 0; + consumeFrom = address(this); + onCompleteData = bytes(""); + } + + /// @notice Modifier to treat functions async with consume from address + function _setOverrides(address consumeFrom_) internal { + consumeFrom = consumeFrom_; } /// @notice Sets isReadCall, maxFees and gasLimit overrides @@ -194,7 +221,7 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { /// @param isParallelCall_ The sequential call flag /// @param gasLimit_ The gas limit function _setOverrides(Read isReadCall_, Parallel isParallelCall_, uint256 gasLimit_) internal { - overrideParams.isReadCall = isReadCall_; + _setCallType(isReadCall_); overrideParams.isParallelCall = isParallelCall_; overrideParams.gasLimit = gasLimit_; } @@ -203,7 +230,7 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { /// @param isReadCall_ The read call flag /// @param isParallelCall_ The sequential call flag function _setOverrides(Read isReadCall_, Parallel isParallelCall_) internal { - overrideParams.isReadCall = isReadCall_; + _setCallType(isReadCall_); overrideParams.isParallelCall = isParallelCall_; } @@ -221,24 +248,24 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { /// @notice Sets isParallelCall overrides /// @param isParallelCall_ The sequential call flag - /// @param readAt_ The read anchor value. Currently block number. - function _setOverrides(Parallel isParallelCall_, uint256 readAt_) internal { + /// @param readAtBlockNumber_ The read anchor value. Currently block number. + function _setOverrides(Parallel isParallelCall_, uint256 readAtBlockNumber_) internal { overrideParams.isParallelCall = isParallelCall_; - overrideParams.readAt = readAt_; + overrideParams.readAtBlockNumber = readAtBlockNumber_; } /// @notice Sets isReadCall overrides /// @param isReadCall_ The read call flag function _setOverrides(Read isReadCall_) internal { - overrideParams.isReadCall = isReadCall_; + _setCallType(isReadCall_); } /// @notice Sets isReadCall overrides /// @param isReadCall_ The read call flag - /// @param readAt_ The read anchor value. Currently block number. - function _setOverrides(Read isReadCall_, uint256 readAt_) internal { - overrideParams.isReadCall = isReadCall_; - overrideParams.readAt = readAt_; + /// @param readAtBlockNumber_ The read anchor value. Currently block number. + function _setOverrides(Read isReadCall_, uint256 readAtBlockNumber_) internal { + _setCallType(isReadCall_); + overrideParams.readAtBlockNumber = readAtBlockNumber_; } /// @notice Sets gasLimit overrides diff --git a/contracts/evmx/helpers/AddressResolver.sol b/contracts/evmx/helpers/AddressResolver.sol index d92e1dc9..3956d71c 100644 --- a/contracts/evmx/helpers/AddressResolver.sol +++ b/contracts/evmx/helpers/AddressResolver.sol @@ -4,15 +4,19 @@ pragma solidity ^0.8.21; import {Ownable} from "solady/auth/Ownable.sol"; import {Initializable} from "solady/utils/Initializable.sol"; import "./interfaces/IAddressResolver.sol"; +import "./interfaces/IWatcher.sol"; +import "./interfaces/IFeesManager.sol"; +import "./interfaces/IDefaultAuctionManager.sol"; +import "./interfaces/IAsyncDeployer.sol"; abstract contract AddressResolverStorage is IAddressResolver { // slots [0-49] reserved for gap uint256[50] _gap_before; - IWatcherPrecompile public override watcherPrecompile__; - address public override feesManager; - address public override asyncDeployer; - address public override defaultAuctionManager; + IWatcher public override watcherPrecompile__; + IFeesManager public override feesManager; + IAsyncDeployer public override asyncDeployer; + IDefaultAuctionManager public override defaultAuctionManager; // slots [61-110] reserved for gap uint256[50] _gap_after; @@ -46,21 +50,28 @@ contract AddressResolver is AddressResolverStorage, Initializable, Ownable { /// @notice Updates the address of the fees manager /// @param feesManager_ The address of the fees manager function setFeesManager(address feesManager_) external onlyOwner { - feesManager = feesManager_; + feesManager = IFeesManager(feesManager_); emit FeesManagerUpdated(feesManager_); } /// @notice Updates the address of the default auction manager /// @param defaultAuctionManager_ The address of the default auction manager function setDefaultAuctionManager(address defaultAuctionManager_) external onlyOwner { - defaultAuctionManager = defaultAuctionManager_; + defaultAuctionManager = IDefaultAuctionManager(defaultAuctionManager_); emit DefaultAuctionManagerUpdated(defaultAuctionManager_); } /// @notice Updates the address of the watcher precompile contract /// @param watcherPrecompile_ The address of the watcher precompile contract function setWatcherPrecompile(address watcherPrecompile_) external onlyOwner { - watcherPrecompile__ = IWatcherPrecompile(watcherPrecompile_); + watcherPrecompile__ = IWatcher(watcherPrecompile_); emit WatcherPrecompileUpdated(watcherPrecompile_); } + + /// @notice Returns the address of the async deployer + /// @return The address of the async deployer + function setAsyncDeployer(address asyncDeployer_) external onlyOwner { + asyncDeployer = IAsyncDeployer(asyncDeployer_); + emit AsyncDeployerUpdated(asyncDeployer_); + } } diff --git a/contracts/evmx/helpers/AddressResolverUtil.sol b/contracts/evmx/helpers/AddressResolverUtil.sol index 0a917b00..736d5eb4 100644 --- a/contracts/evmx/helpers/AddressResolverUtil.sol +++ b/contracts/evmx/helpers/AddressResolverUtil.sol @@ -2,12 +2,13 @@ pragma solidity ^0.8.21; import "../interfaces/IAddressResolver.sol"; -import "../interfaces/IWatcherPrecompile.sol"; +import "../interfaces/IWatcher.sol"; +import "../interfaces/IFeesManager.sol"; /// @title AddressResolverUtil /// @notice Utility contract for resolving system contract addresses /// @dev Provides access control and address resolution functionality for the system -abstract contract AddressResolverUtil { +abstract contract AddressResolverBase { /// @notice The address resolver contract reference /// @dev Used to look up system contract addresses // slot 0 @@ -21,7 +22,7 @@ abstract contract AddressResolverUtil { /// @notice Restricts function access to the watcher precompile contract /// @dev Validates that msg.sender matches the registered watcher precompile address - modifier onlyWatcherPrecompile() { + modifier onlyWatcher() { if (msg.sender != address(addressResolver__.watcherPrecompile__())) { revert OnlyWatcherPrecompile(); } @@ -30,12 +31,26 @@ abstract contract AddressResolverUtil { } /// @notice Gets the watcher precompile contract interface - /// @return IWatcherPrecompile interface of the registered watcher precompile + /// @return IWatcher interface of the registered watcher precompile /// @dev Resolves and returns the watcher precompile contract for interaction - function watcherPrecompile__() public view returns (IWatcherPrecompile) { + function watcherPrecompile__() public view returns (IWatcher) { return addressResolver__.watcherPrecompile__(); } + /// @notice Gets the watcher precompile contract interface + /// @return IWatcher interface of the registered watcher precompile + /// @dev Resolves and returns the watcher precompile contract for interaction + function feesManager__() public view returns (IFeesManager) { + return addressResolver__.feesManager__(); + } + + /// @notice Gets the async deployer contract interface + /// @return IAsyncDeployer interface of the registered async deployer + /// @dev Resolves and returns the async deployer contract for interaction + function asyncDeployer__() public view returns (IAsyncDeployer) { + return addressResolver__.asyncDeployer__(); + } + /// @notice Internal function to set the address resolver /// @param _addressResolver The address of the resolver contract /// @dev Should be called in the initialization of inheriting contracts diff --git a/contracts/evmx/helpers/AsyncDeployer.sol b/contracts/evmx/helpers/AsyncDeployer.sol index 4be148df..42e47f7f 100644 --- a/contracts/evmx/helpers/AsyncDeployer.sol +++ b/contracts/evmx/helpers/AsyncDeployer.sol @@ -28,6 +28,9 @@ abstract contract AsyncDeployerStorage is IAddressResolver { // slot 58 uint256 public asyncPromiseCounter; + // slot 59 + address public addressResolver; + // slots [61-110] reserved for gap uint256[50] _gap_after; } @@ -36,8 +39,9 @@ abstract contract AsyncDeployerStorage is IAddressResolver { /// @notice This contract is responsible for deploying Forwarder and AsyncPromise contracts. /// @dev Inherits the Ownable contract and implements the IAddressResolver interface. contract AsyncDeployer is AsyncDeployerStorage, Initializable, Ownable { - constructor() { + constructor(address addressResolver_) { _disableInitializers(); // disable for implementation + addressResolver = addressResolver_; } /// @notice Initializer to replace constructor for upgradeable contracts @@ -110,14 +114,13 @@ contract AsyncDeployer is AsyncDeployerStorage, Initializable, Ownable { function _createAsyncPromiseParams( address invoker_ ) internal view returns (bytes32 salt, bytes memory initData) { - bytes memory constructorArgs = abi.encode(invoker_, msg.sender, address(this)); + bytes memory constructorArgs = abi.encode(invoker_, addressResolver); // creates init data initData = abi.encodeWithSelector( AsyncPromise.initialize.selector, invoker_, - msg.sender, - address(this) + addressResolver ); // creates salt with a counter @@ -136,8 +139,6 @@ contract AsyncDeployer is AsyncDeployerStorage, Initializable, Ownable { // deploys the proxy newAsyncPromise = _deployProxy(salt, address(asyncPromiseBeacon), initData); - _promises.push(newAsyncPromise); - emit AsyncPromiseDeployed(newAsyncPromise, salt); } @@ -156,18 +157,6 @@ contract AsyncDeployer is AsyncDeployerStorage, Initializable, Ownable { return proxy; } - /// @notice Clears the list of promises - /// @dev this function helps in queueing the promises and whitelisting on gateway at the end. - function clearPromises() external { - delete _promises; - } - - /// @notice Gets the list of promises - /// @return array of promises deployed while queueing async calls - function getPromises() external view returns (address[] memory) { - return _promises; - } - /// @notice Gets the predicted address of a Forwarder proxy contract /// @param chainContractAddress_ The address of the chain contract /// @param chainSlug_ The chain slug diff --git a/contracts/evmx/helpers/AsyncPromise.sol b/contracts/evmx/helpers/AsyncPromise.sol index 0f8f48ae..3271366d 100644 --- a/contracts/evmx/helpers/AsyncPromise.sol +++ b/contracts/evmx/helpers/AsyncPromise.sol @@ -13,7 +13,6 @@ abstract contract AsyncPromiseStorage is IPromise { // slots [0-49] reserved for gap uint256[50] _gap_before; - // slot 50 // bytes1 /// @notice The callback selector to be called on the invoker. bytes4 public callbackSelector; @@ -28,10 +27,6 @@ abstract contract AsyncPromiseStorage is IPromise { /// @dev The callback will be executed on this address address public localInvoker; - // slot 51 - /// @notice The forwarder address which can set the callback selector and data - address public forwarder; - // slot 52 /// @notice The callback data to be used when the promise is resolved. bytes public callbackData; @@ -49,8 +44,8 @@ contract AsyncPromise is AsyncPromiseStorage, Initializable, AddressResolverUtil using LibCall for address; /// @notice Error thrown when attempting to resolve an already resolved promise. error PromiseAlreadyResolved(); - /// @notice Only the forwarder or local invoker can set then's promise callback - error OnlyForwarderOrLocalInvoker(); + /// @notice Only the local invoker can set then's promise callback + error OnlyInvoker(); /// @notice Error thrown when attempting to set an already existing promise error PromiseAlreadySetUp(); /// @notice Error thrown when the promise reverts @@ -62,16 +57,9 @@ contract AsyncPromise is AsyncPromiseStorage, Initializable, AddressResolverUtil /// @notice Initialize promise states /// @param invoker_ The address of the local invoker - /// @param forwarder_ The address of the forwarder /// @param addressResolver_ The address resolver contract address - function initialize( - address invoker_, - address forwarder_, - address addressResolver_ - ) public initializer { + function initialize(address invoker_, address addressResolver_) public initializer { localInvoker = invoker_; - forwarder = forwarder_; - _setAddressResolver(addressResolver_); } @@ -82,7 +70,7 @@ contract AsyncPromise is AsyncPromiseStorage, Initializable, AddressResolverUtil uint40 requestCount_, bytes32 payloadId_, bytes memory returnData_ - ) external override onlyWatcherPrecompile returns (bool success) { + ) external override onlyWatcher returns (bool success) { if (resolved) revert PromiseAlreadyResolved(); resolved = true; @@ -108,7 +96,7 @@ contract AsyncPromise is AsyncPromiseStorage, Initializable, AddressResolverUtil function markOnchainRevert( uint40 requestCount_, bytes32 payloadId_ - ) external override onlyWatcherPrecompile { + ) external override onlyWatcher { _handleRevert(requestCount_, payloadId_, AsyncPromiseState.ONCHAIN_REVERTING); } @@ -134,12 +122,7 @@ contract AsyncPromise is AsyncPromiseStorage, Initializable, AddressResolverUtil function then( bytes4 selector_, bytes memory data_ - ) external override returns (address promise_) { - // allows forwarder or local invoker to set the callback selector and data - if (msg.sender != forwarder && msg.sender != localInvoker) { - revert OnlyForwarderOrLocalInvoker(); - } - + ) external override onlyWatcher returns (address promise_) { // if the promise is already set up, revert if (state == AsyncPromiseState.WAITING_FOR_CALLBACK_EXECUTION) { revert PromiseAlreadySetUp(); diff --git a/contracts/evmx/helpers/Forwarder.sol b/contracts/evmx/helpers/Forwarder.sol index 34b91131..f22fd364 100644 --- a/contracts/evmx/helpers/Forwarder.sol +++ b/contracts/evmx/helpers/Forwarder.sol @@ -7,7 +7,7 @@ import "./interfaces/IAppGateway.sol"; import "./interfaces/IPromise.sol"; import "./interfaces/IForwarder.sol"; import {AddressResolverUtil} from "./AddressResolverUtil.sol"; -import {AsyncModifierNotUsed, NoAsyncPromiseFound, PromiseCallerMismatch, RequestCountMismatch, DeliveryHelperNotSet} from "../utils/common/Errors.sol"; +import {AsyncModifierNotUsed, NoAsyncPromiseFound, PromiseCallerMismatch, RequestCountMismatch, WatcherNotSt} from "../utils/common/Errors.sol"; import "solady/utils/Initializable.sol"; /// @title Forwarder Storage @@ -22,10 +22,6 @@ abstract contract ForwarderStorage is IForwarder { /// @notice on-chain address associated with this forwarder address public onChainAddress; - // slot 51 - /// @notice caches the latest async promise address for the last call - address public latestAsyncPromise; - // slot 52 /// @notice the address of the contract that called the latest async promise address public latestPromiseCaller; @@ -66,15 +62,8 @@ contract Forwarder is ForwarderStorage, Initializable, AddressResolverUtil { /// @param data_ The data to be passed to callback /// @return promise_ The address of the new promise function then(bytes4 selector_, bytes memory data_) external returns (address promise_) { - if (latestAsyncPromise == address(0)) revert NoAsyncPromiseFound(); - if (latestPromiseCaller != msg.sender) revert PromiseCallerMismatch(); - if (latestRequestCount != watcherPrecompile__().nextRequestCount()) - revert RequestCountMismatch(); - - address latestAsyncPromise_ = latestAsyncPromise; - latestAsyncPromise = address(0); - - promise_ = IPromise(latestAsyncPromise_).then(selector_, data_); + if (lastForwarderCaller != msg.sender) revert CallerMismatch(); + promise_ = watcherPrecompile__().then(selector_, data_, msg.sender); } /// @notice Returns the on-chain address associated with this forwarder. @@ -93,28 +82,20 @@ contract Forwarder is ForwarderStorage, Initializable, AddressResolverUtil { /// @dev It queues the calls in the middleware and deploys the promise contract fallback() external { if (address(watcherPrecompile__()) == address(0)) { - revert DeliveryHelperNotSet(); + revert WatcherNotSet(); } // validates if the async modifier is set bool isAsyncModifierSet = IAppGateway(msg.sender).isAsyncModifierSet(); if (!isAsyncModifierSet) revert AsyncModifierNotUsed(); - // Deploy a new async promise contract. - latestAsyncPromise = addressResolver__.deployAsyncPromiseContract(msg.sender); - - // set the latest promise caller and request count for validating if the future .then call is valid - latestPromiseCaller = msg.sender; - latestRequestCount = watcherPrecompile__().nextRequestCount(); - // fetch the override params from app gateway (OverrideParams overrideParams, bytes32 sbType) = IAppGateway(msg.sender) .getOverrideParams(); - // get the switchboard address from the watcher precompile config - address switchboard = watcherPrecompileConfig().switchboards(chainSlug, sbType); - // Queue the call in the middleware. + // and sets the latest promise caller and request count for validating if the future .then call is valid + latestPromiseCaller = msg.sender; watcherPrecompile__().queue( QueuePayloadParams({ overrideParams: overrideParams, @@ -123,9 +104,10 @@ contract Forwarder is ForwarderStorage, Initializable, AddressResolverUtil { target: onChainAddress, payload: msg.data }), - asyncPromise: latestAsyncPromise, - switchboard: switchboard - }) + asyncPromise: address(0), + switchboardType: sbType + }), + latestPromiseCaller ); } } diff --git a/contracts/utils/common/Constants.sol b/contracts/utils/common/Constants.sol index 7b17f483..921173b9 100644 --- a/contracts/utils/common/Constants.sol +++ b/contracts/utils/common/Constants.sol @@ -6,11 +6,14 @@ address constant ETH_ADDRESS = address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEe bytes32 constant FORWARD_CALL = keccak256("FORWARD_CALL"); bytes32 constant DISTRIBUTE_FEE = keccak256("DISTRIBUTE_FEE"); bytes32 constant DEPLOY = keccak256("DEPLOY"); -bytes32 constant QUERY = keccak256("QUERY"); -bytes32 constant FINALIZE = keccak256("FINALIZE"); -bytes32 constant SCHEDULE = keccak256("SCHEDULE"); + +bytes4 constant READ = bytes4(keccak256("READ")); +bytes4 constant WRITE = bytes4(keccak256("WRITE")); +bytes4 constant SCHEDULE = bytes4(keccak256("SCHEDULE")); + bytes32 constant CALLBACK = keccak256("CALLBACK"); bytes32 constant FAST = keccak256("FAST"); + uint256 constant REQUEST_PAYLOAD_COUNT_LIMIT = 10; uint256 constant PAYLOAD_SIZE_LIMIT = 24_500; uint16 constant MAX_COPY_BYTES = 2048; // 2KB From 3c3230a5a59d4d7419b3229ee8c74975d4218db1 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Wed, 14 May 2025 17:38:41 +0530 Subject: [PATCH 014/130] fix: rm extra code --- contracts/app-gateway/DeliveryHelper.sol | 8 +- contracts/app-gateway/RequestQueue.sol | 181 +----------------- contracts/core/RequestHandler.sol | 32 +--- contracts/core/WatcherPrecompileCore.sol | 37 +--- .../evmx/app-gateways/AuctionManager.sol | 28 +-- .../evmx/app-gateways/DeployerGateway.sol | 37 ++-- contracts/evmx/fees/FeesManager.sol | 22 +-- .../evmx/interfaces/IAddressResolver.sol | 2 +- contracts/protocol/Socket.sol | 4 +- contracts/protocol/SocketConfig.sol | 2 +- test/mock/MockWatcherPrecompile.sol | 2 +- 11 files changed, 56 insertions(+), 299 deletions(-) diff --git a/contracts/app-gateway/DeliveryHelper.sol b/contracts/app-gateway/DeliveryHelper.sol index 9536bedf..c1c5a667 100644 --- a/contracts/app-gateway/DeliveryHelper.sol +++ b/contracts/app-gateway/DeliveryHelper.sol @@ -6,7 +6,6 @@ import "./FeesHelpers.sol"; /// @title DeliveryHelper /// @notice Contract for managing payload delivery contract DeliveryHelper is FeesHelpers { - /// @notice Calls the watcher precompile to start processing a request /// @dev If a transmitter was already assigned, it updates the transmitter in watcher precompile too /// @param requestCount_ The ID of the request @@ -37,7 +36,7 @@ contract DeliveryHelper is FeesHelpers { // todo: move it to watcher precompile if (requestMetadata_.winningBid.transmitter != address(0)) - IFeesManager(addressResolver__.feesManager()).unblockAndAssignCredits( + feesManager__().unblockAndAssignCredits( requestCount_, requestMetadata_.winningBid.transmitter ); @@ -77,14 +76,13 @@ contract DeliveryHelper is FeesHelpers { function _settleFees(uint40 requestCount_) internal { // If the request has a winning bid, ie. transmitter already assigned, unblock and assign fees if (requests[requestCount_].winningBid.transmitter != address(0)) { - IFeesManager(addressResolver__.feesManager()).unblockAndAssignCredits( + feesManager__().unblockAndAssignCredits( requestCount_, requests[requestCount_].winningBid.transmitter ); } else { // If the request has no winning bid, ie. transmitter not assigned, unblock fees - IFeesManager(addressResolver__.feesManager()).unblockCredits(requestCount_); + feesManager__().unblockCredits(requestCount_); } } - } diff --git a/contracts/app-gateway/RequestQueue.sol b/contracts/app-gateway/RequestQueue.sol index c4adcc5e..e704bb07 100644 --- a/contracts/app-gateway/RequestQueue.sol +++ b/contracts/app-gateway/RequestQueue.sol @@ -5,164 +5,21 @@ import "./DeliveryUtils.sol"; /// @notice Abstract contract for managing asynchronous payloads abstract contract RequestQueue is DeliveryUtils { - // slots [207-257] reserved for gap - uint256[50] _gap_queue_async; - - - /// @notice Initiates a batch of payloads - /// @param maxFees_ The fees data - /// @param auctionManager_ The auction manager address - /// @return requestCount The ID of the batch - function batch( - uint256 maxFees_, - address auctionManager_, - address consumeFrom_, - bytes memory onCompleteData_ - ) external returns (uint40 requestCount) { - address appGateway = _getCoreAppGateway(msg.sender); - return _batch(appGateway, auctionManager_, consumeFrom_, maxFees_, onCompleteData_); - } - - /// @notice Initiates a batch of payloads - /// @dev it checks fees, payload limits and creates the payload submit params array after assigning proper levels - /// @dev It also modifies the deploy payloads as needed by contract factory plug - /// @dev Stores request metadata and submits the request to watcher precompile - function _batch( - address appGateway_, - address auctionManager_, - address consumeFrom_, - uint256 maxFees_, - bytes memory onCompleteData_ - ) internal returns (uint40 requestCount) { - if (queuePayloadParams.length == 0) return 0; - - BatchParams memory params = BatchParams({ - appGateway: appGateway_, - auctionManager: _getAuctionManager(auctionManager_), - maxFees: maxFees_, - onCompleteData: onCompleteData_, - onlyReadRequests: false, - queryCount: 0, - finalizeCount: 0 - }); - - // Split the function into smaller parts - ( - PayloadSubmitParams[] memory payloadSubmitParamsArray, - bool onlyReadRequests, - uint256 queryCount, - uint256 finalizeCount - ) = _createPayloadSubmitParamsArray(); - - params.onlyReadRequests = onlyReadRequests; - params.queryCount = queryCount; - params.finalizeCount = finalizeCount; - - _checkBatch(consumeFrom_, params.appGateway, params.maxFees); - return _submitBatchRequest(payloadSubmitParamsArray, consumeFrom_, params); - } - function _submitBatchRequest( PayloadSubmitParams[] memory payloadSubmitParamsArray, address consumeFrom_, BatchParams memory params ) internal returns (uint40 requestCount) { - RequestMetadata memory requestMetadata = RequestMetadata({ - appGateway: params.appGateway, - auctionManager: params.auctionManager, - maxFees: params.maxFees, - winningBid: Bid({fee: 0, transmitter: address(0), extraData: new bytes(0)}), - onCompleteData: params.onCompleteData, - onlyReadRequests: params.onlyReadRequests, - consumeFrom: consumeFrom_, - queryCount: params.queryCount, - finalizeCount: params.finalizeCount - }); - - requestCount = watcherPrecompile__().submitRequest(payloadSubmitParamsArray); - requests[requestCount] = requestMetadata; - - if (params.onlyReadRequests) { - watcherPrecompile__().startProcessingRequest(requestCount, address(0)); - } - - uint256 watcherFees = watcherPrecompileLimits().getTotalFeesRequired( - params.queryCount, - params.finalizeCount, - 0, - 0 - ); - if (watcherFees > params.maxFees) revert InsufficientFees(); - uint256 maxTransmitterFees = params.maxFees - watcherFees; - emit PayloadSubmitted( requestCount, params.appGateway, payloadSubmitParamsArray, - maxTransmitterFees, + params.maxFees - watcherFees, params.auctionManager, params.onlyReadRequests ); } - function _getAuctionManager(address auctionManager_) internal view returns (address) { - return - auctionManager_ == address(0) - ? IAddressResolver(addressResolver__).defaultAuctionManager() - : auctionManager_; - } - - function _checkBatch( - address consumeFrom_, - address appGateway_, - uint256 maxFees_ - ) internal view { - if (queuePayloadParams.length > REQUEST_PAYLOAD_COUNT_LIMIT) - revert RequestPayloadCountLimitExceeded(); - - if ( - !IFeesManager(addressResolver__.feesManager()).isUserCreditsEnough( - consumeFrom_, - appGateway_, - maxFees_ - ) - ) revert InsufficientFees(); - } - - /// @notice Creates an array of payload details - /// @return payloadDetailsArray An array of payload details - function _createPayloadSubmitParamsArray() - internal - returns ( - PayloadSubmitParams[] memory payloadDetailsArray, - bool onlyReadRequests, - uint256 queryCount, - uint256 finalizeCount - ) - { - payloadDetailsArray = new PayloadSubmitParams[](queuePayloadParams.length); - onlyReadRequests = queuePayloadParams[0].callType == CallType.READ; - - uint256 currentLevel = 0; - for (uint256 i = 0; i < queuePayloadParams.length; i++) { - if (queuePayloadParams[i].callType == CallType.READ) { - queryCount++; - } else { - onlyReadRequests = false; - finalizeCount++; - } - - // Update level for calls - if (i > 0 && queuePayloadParams[i].isParallel != Parallel.ON) { - currentLevel = currentLevel + 1; - } - - payloadDetailsArray[i] = _createPayloadDetails(currentLevel, queuePayloadParams[i]); - } - - clearQueue(); - } - function _createDeployPayloadDetails( QueuePayloadParams memory queuePayloadParams_ ) internal returns (bytes memory payload, address target) { @@ -184,40 +41,4 @@ abstract contract RequestQueue is DeliveryUtils { // getting app gateway for deployer as the plug is connected to the app gateway target = getDeliveryHelperPlugAddress(queuePayloadParams_.chainSlug); } - - /// @notice Creates the payload details for a given call parameters - /// @param queuePayloadParams_ The call parameters - /// @return payloadDetails The payload details - function _createPayloadDetails( - uint256 level_, - QueuePayloadParams memory queuePayloadParams_ - ) internal returns (PayloadSubmitParams memory) { - bytes memory payload = queuePayloadParams_.payload; - address target = queuePayloadParams_.target; - if (queuePayloadParams_.callType == CallType.DEPLOY) { - (payload, target) = _createDeployPayloadDetails(queuePayloadParams_); - } - - if (queuePayloadParams_.value > chainMaxMsgValueLimit[queuePayloadParams_.chainSlug]) - revert MaxMsgValueLimitExceeded(); - - return - PayloadSubmitParams({ - levelNumber: level_, - chainSlug: queuePayloadParams_.chainSlug, - callType: queuePayloadParams_.callType, - isParallel: queuePayloadParams_.isParallel, - writeFinality: queuePayloadParams_.writeFinality, - asyncPromise: queuePayloadParams_.asyncPromise, - switchboard: queuePayloadParams_.switchboard, - target: target, - appGateway: queuePayloadParams_.appGateway, - gasLimit: queuePayloadParams_.gasLimit == 0 - ? 10_000_000 - : queuePayloadParams_.gasLimit, - value: queuePayloadParams_.value, - readAt: queuePayloadParams_.readAt, - payload: payload - }); - } } diff --git a/contracts/core/RequestHandler.sol b/contracts/core/RequestHandler.sol index 5e1fb639..11638231 100644 --- a/contracts/core/RequestHandler.sol +++ b/contracts/core/RequestHandler.sol @@ -21,8 +21,6 @@ abstract contract RequestHandler is WatcherPrecompileCore { function submitRequest( PayloadSubmitParams[] memory payloadSubmitParams_ ) public returns (uint40 requestCount) { - address appGateway = _checkAppGateways(payloadSubmitParams_); - requestCount = nextRequestCount++; uint40 batchCount = nextBatchCount; uint40 currentBatch = batchCount; @@ -35,7 +33,7 @@ abstract contract RequestHandler is WatcherPrecompileCore { PayloadSubmitParams memory p = payloadSubmitParams_[i]; // Count reads and writes for checking limits - if (p.callType == CallType.READ) { + if (p.callType == READ) { readCount++; } else writeCount++; @@ -49,14 +47,6 @@ abstract contract RequestHandler is WatcherPrecompileCore { } } - uint40 localPayloadCount = payloadCounter++; - bytes32 payloadId = WatcherIdUtils.createPayloadId( - requestCount, - batchCount, - localPayloadCount, - p.switchboard, - p.chainSlug - ); batchPayloadIds[batchCount].push(payloadId); bytes32 payloadHeader = PayloadHeaderDecoder.createPayloadHeader( @@ -73,13 +63,11 @@ abstract contract RequestHandler is WatcherPrecompileCore { payloads[payloadId].asyncPromise = p.asyncPromise; payloads[payloadId].switchboard = p.switchboard; payloads[payloadId].target = p.target; - payloads[payloadId].appGateway = p.callType == CallType.DEPLOY - ? addressResolver__.deliveryHelper() - : p.appGateway; + payloads[payloadId].appGateway = p.appGateway; payloads[payloadId].payloadId = payloadId; payloads[payloadId].gasLimit = p.gasLimit; payloads[payloadId].value = p.value; - payloads[payloadId].readAt = p.readAt; + payloads[payloadId].readAtBlockNumber = p.readAtBlockNumber; payloads[payloadId].payload = p.payload; requestParams[requestCount].payloadParamsArray.push(payloads[payloadId]); @@ -89,13 +77,7 @@ abstract contract RequestHandler is WatcherPrecompileCore { // Push the final batch ID to the request's batch list and increment the counter // This is needed because the last batch in the loop above doesn't get added since there's no next level to trigger it requestBatchIds[requestCount].push(nextBatchCount++); - - requestParams[requestCount].queryCount = readCount; - requestParams[requestCount].finalizeCount = writeCount; - requestParams[requestCount].currentBatch = currentBatch; - requestParams[requestCount].payloadsRemaining = payloadSubmitParams_.length; - requestParams[requestCount].middleware = msg.sender; emit RequestSubmitted( msg.sender, @@ -111,12 +93,8 @@ abstract contract RequestHandler is WatcherPrecompileCore { function _checkAppGateways( PayloadSubmitParams[] memory payloadSubmitParams ) internal view returns (address appGateway) { - bool isDeliveryHelper = msg.sender == addressResolver__.deliveryHelper(); - // Get first app gateway and use it as reference - address coreAppGateway = isDeliveryHelper - ? _getCoreAppGateway(payloadSubmitParams[0].appGateway) - : _getCoreAppGateway(msg.sender); + address coreAppGateway = _getCoreAppGateway(msg.sender); // Skip first element since we already checked it for (uint256 i = 1; i < payloadSubmitParams.length; i++) { @@ -169,6 +147,4 @@ abstract contract RequestHandler is WatcherPrecompileCore { r.currentBatchPayloadsLeft = totalPayloads; } - - } diff --git a/contracts/core/WatcherPrecompileCore.sol b/contracts/core/WatcherPrecompileCore.sol index cc5f0059..74b5b4d3 100644 --- a/contracts/core/WatcherPrecompileCore.sol +++ b/contracts/core/WatcherPrecompileCore.sol @@ -15,7 +15,7 @@ import "./WatcherPrecompileStorage.sol"; /// @dev This contract implements the core functionality for payload verification, execution, and app configurations /// @dev It is inherited by WatcherPrecompile and provides the base implementation for request handling abstract contract WatcherPrecompileCore is - IWatcherPrecompile, + IWatcher, WatcherPrecompileStorage, Initializable, Ownable, @@ -58,22 +58,6 @@ abstract contract WatcherPrecompileCore is PayloadParams memory params_, address transmitter_ ) internal returns (bytes32 digest) { - uint32 chainSlug = params_.payloadHeader.getChainSlug(); - - // Verify that the app gateway is properly configured for this chain and target - watcherPrecompileConfig__.verifyConnections( - chainSlug, - params_.target, - params_.appGateway, - params_.switchboard, - requestParams[params_.payloadHeader.getRequestCount()].middleware - ); - - _consumeCallbackFeesFromRequestCount( - watcherPrecompileLimits__.finalizeFees(), - params_.payloadHeader.getRequestCount() - ); - uint256 deadline = block.timestamp + expiryTime; payloads[params_.payloadId].deadline = deadline; payloads[params_.payloadId].finalizedTransmitter = transmitter_; @@ -107,11 +91,6 @@ abstract contract WatcherPrecompileCore is /// @param params_ The payload parameters for the query /// @dev This function sets up a query request and emits a QueryRequested event function _query(PayloadParams memory params_) internal { - _consumeCallbackFeesFromRequestCount( - watcherPrecompileLimits__.queryFees(), - params_.payloadHeader.getRequestCount() - ); - payloads[params_.payloadId].prevDigestsHash = _getPreviousDigestsHash( params_.payloadHeader.getBatchCount() ); @@ -184,22 +163,18 @@ abstract contract WatcherPrecompileCore is return payloadParamsArray; } - - function _consumeCallbackFeesFromRequestCount(uint256 fees_, uint40 requestCount_) internal { // for callbacks in all precompiles uint256 feesToConsume = fees_ + watcherPrecompileLimits__.callBackFees(); - IFeesManager(addressResolver__.feesManager()) - .assignWatcherPrecompileCreditsFromRequestCount(feesToConsume, requestCount_); + feesManager__().assignWatcherPrecompileCreditsFromRequestCount( + feesToConsume, + requestCount_ + ); } function _consumeCallbackFeesFromAddress(uint256 fees_, address consumeFrom_) internal { // for callbacks in all precompiles uint256 feesToConsume = fees_ + watcherPrecompileLimits__.callBackFees(); - IFeesManager(addressResolver__.feesManager()).assignWatcherPrecompileCreditsFromAddress( - feesToConsume, - consumeFrom_ - ); + feesManager__().assignWatcherPrecompileCreditsFromAddress(feesToConsume, consumeFrom_); } - } diff --git a/contracts/evmx/app-gateways/AuctionManager.sol b/contracts/evmx/app-gateways/AuctionManager.sol index 96a66227..adf78cf5 100644 --- a/contracts/evmx/app-gateways/AuctionManager.sol +++ b/contracts/evmx/app-gateways/AuctionManager.sol @@ -148,9 +148,7 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, if (requestMetadata.auctionManager != address(this)) revert InvalidBid(); // get the total fees required for the watcher precompile ops - uint256 watcherFees = watcherPrecompile().getMaxFees( - requestCount_ - ); + uint256 watcherFees = watcherPrecompile().getMaxFees(requestCount_); return requestMetadata.maxFees - watcherFees; } @@ -168,10 +166,10 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, auctionClosed[requestCount_] = true; RequestMetadata memory requestMetadata = _getRequestMetadata(requestCount_); - + // block the fees // in startRequestProcessing, block the fees from bid - // IFeesManager(addressResolver__.feesManager()).blockCredits( + // feesManager__().blockCredits( // requestMetadata.consumeFrom, // winningBid.fee, // requestCount_ @@ -185,17 +183,11 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, // abi.encodeWithSelector(this.expireBid.selector, requestCount_) // ); - // start the request processing, it will finalize the request - if(requestMetadata.transmitter != address(0)) { - IWatcherPrecompile(addressResolver__.watcherPrecompile()).updateTransmitter( - requestCount_, - winningBid - ); - } else - IWatcherPrecompile(addressResolver__.watcherPrecompile()).startRequestProcessing( - requestCount_, - winningBid - ); + // start the request processing, it will queue the request + if (requestMetadata.transmitter != address(0)) { + IWatcher(watcherPrecompile__()).updateTransmitter(requestCount_, winningBid); + } else { + IWatcher(watcherPrecompile__()).startRequestProcessing(requestCount_, winningBid); } emit AuctionEnded(requestCount_, winningBid); @@ -216,7 +208,7 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, reAuctionCount[requestCount_]++; // todo: unblock credits by calling watcher for updating transmitter to addr(0) - // IFeesManager(addressResolver__.feesManager()).unblockCredits(requestCount_); + // feesManager__().unblockCredits(requestCount_); emit AuctionRestarted(requestCount_); } @@ -240,6 +232,6 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, function _getRequestMetadata( uint40 requestCount_ ) internal view returns (RequestMetadata memory) { - return IMiddleware(addressResolver__.deliveryHelper()).getRequestMetadata(requestCount_); + return watcherPrecompile__().getRequestMetadata(requestCount_); } } diff --git a/contracts/evmx/app-gateways/DeployerGateway.sol b/contracts/evmx/app-gateways/DeployerGateway.sol index 64ea36b3..e69feb92 100644 --- a/contracts/evmx/app-gateways/DeployerGateway.sol +++ b/contracts/evmx/app-gateways/DeployerGateway.sol @@ -8,7 +8,6 @@ import {PayloadSubmitParams, QueuePayloadParams} from "../../utils/common/Struct /// @notice App gateway contract responsible for handling deployment requests /// @dev Extends AppGatewayBase to provide deployment queueing functionality contract DeployerGateway is AppGatewayBase { - // slot 51 /// @notice The counter for the salt used to generate/deploy the contract address uint256 public saltCounter; @@ -25,35 +24,31 @@ contract DeployerGateway is AppGatewayBase { bytes32 deploymentType_, bytes32 contractId_, uint32 chainSlug_, - IsPlug isPlug_, + OverrideParams memory overrideParams_, bytes memory initCallData_, bytes memory payload_ ) external { if (!isAsyncModifierSet) revert AsyncModifierNotUsed(); - - address asyncPromise = addressResolver__.deployAsyncPromiseContract(address(this)); - IPromise(asyncPromise).then(this.setAddress.selector, abi.encode(chainSlug_, contractId_)); - - isValidPromise[asyncPromise] = true; onCompleteData = abi.encode(chainSlug_, true); QueuePayloadParams memory queuePayloadParams = QueuePayloadParams({ - chainSlug: chainSlug_, - callType: CallType.DEPLOY, - isParallel: overrideParams.isParallelCall, - isPlug: isPlug_, - writeFinality: overrideParams.writeFinality, - asyncPromise: asyncPromise, - switchboard: watcherPrecompileConfig().switchboards(chainSlug_, sbType), - target: address(0), - appGateway: address(this), - gasLimit: overrideParams.gasLimit, - value: overrideParams.value, - readAt: overrideParams.readAt, - payload: payload_, - initCallData: initCallData_ + overrideParams: overrideParams, + transaction: Transaction({ + chainSlug: chainSlug_, + target: contractFactoryPlug[chainSlug_], + payload: payload_ + }), + asyncPromise: address(0), + switchboardType: sbType }); + // isPlug: isPlug_, + // payload: payload_, + // initCallData: initCallData_ + + IPromise(asyncPromise).then(this.setAddress.selector, abi.encode(chainSlug_, contractId_)); + isValidPromise[asyncPromise] = true; + if (queuePayloadParams.payload.length > PAYLOAD_SIZE_LIMIT) revert PayloadTooLarge(); IWatcher(deliveryHelper__()).queue(queuePayloadParams); } diff --git a/contracts/evmx/fees/FeesManager.sol b/contracts/evmx/fees/FeesManager.sol index 538961e2..b624e41b 100644 --- a/contracts/evmx/fees/FeesManager.sol +++ b/contracts/evmx/fees/FeesManager.sol @@ -7,7 +7,7 @@ import "solady/utils/ECDSA.sol"; import "../interfaces/IFeesManager.sol"; import {AddressResolverUtil} from "../AddressResolverUtil.sol"; import {NotAuctionManager, InvalidWatcherSignature, NonceUsed} from "../../utils/common/Errors.sol"; -import {Bid, CallType, Parallel, WriteFinality, QueuePayloadParams, IsPlug, PayloadSubmitParams, RequestMetadata, UserCredits} from "../../utils/common/Structs.sol"; +import {Bid, Parallel, WriteFinality, QueuePayloadParams, IsPlug, PayloadSubmitParams, RequestMetadata, UserCredits} from "../../utils/common/Structs.sol"; abstract contract FeesManagerStorage is IFeesManager { // slots [0-49] reserved for gap @@ -127,8 +127,6 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol /// @return The available fee amount function getAvailableCredits(address consumeFrom_) public view returns (uint256) { UserCredits memory userCredit = userCredits[consumeFrom_]; - if (userCredit.totalCredits == 0 || userCredit.totalCredits <= userCredit.blockedCredits) - return 0; return userCredit.totalCredits - userCredit.blockedCredits; } @@ -194,6 +192,7 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol ) internal returns (address, address, bool) { (address consumeFrom, address appGateway, bool isApproved, bytes memory signature_) = abi .decode(feeApprovalData_, (address, address, bool, bytes)); + if (signature_.length == 0) { // If no signature, consumeFrom is appGateway return (appGateway, appGateway, isApproved); @@ -395,7 +394,7 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol payloadSubmitParamsArray[0] = PayloadSubmitParams({ levelNumber: 0, chainSlug: chainSlug_, - callType: CallType.WRITE, + callType: WRITE, isParallel: Parallel.OFF, writeFinality: WriteFinality.LOW, asyncPromise: address(0), @@ -404,7 +403,7 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol appGateway: address(this), gasLimit: 10000000, value: 0, - readAt: 0, + readAtBlockNumber: 0, payload: payload }); return payloadSubmitParamsArray; @@ -437,7 +436,7 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol appGateway: address(this), gasLimit: 10000000, value: 0, - readAt: 0, + readAtBlockNumber: 0, payload: payload_, initCallData: bytes("") }); @@ -482,7 +481,7 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol // address auctionManager_, // uint256 fees_ // ) external returns (uint40) { -// IFeesManager(addressResolver__.feesManager()).withdrawCredits( +// feesManager__().withdrawCredits( // msg.sender, // chainSlug_, // token_, @@ -504,9 +503,8 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol // ) external returns (uint40 requestCount) { // address transmitter = msg.sender; -// PayloadSubmitParams[] memory payloadSubmitParamsArray = IFeesManager( -// addressResolver__.feesManager() -// ).getWithdrawTransmitterCreditsPayloadParams( +// PayloadSubmitParams[] memory payloadSubmitParamsArray = feesManager__() +// .getWithdrawTransmitterCreditsPayloadParams( // transmitter, // chainSlug_, // token_, @@ -515,7 +513,7 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol // ); // RequestMetadata memory requestMetadata = RequestMetadata({ -// appGateway: addressResolver__.feesManager(), +// appGateway: feesManager__(), // auctionManager: address(0), // maxFees: 0, // winningBid: Bid({transmitter: transmitter, fee: 0, extraData: new bytes(0)}), @@ -529,4 +527,4 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol // requests[requestCount] = requestMetadata; // // same transmitter can execute requests without auction // watcherPrecompile__().startProcessingRequest(requestCount, transmitter); -// } \ No newline at end of file +// } diff --git a/contracts/evmx/interfaces/IAddressResolver.sol b/contracts/evmx/interfaces/IAddressResolver.sol index ff123e69..3871ed52 100644 --- a/contracts/evmx/interfaces/IAddressResolver.sol +++ b/contracts/evmx/interfaces/IAddressResolver.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import "./IWatcherPrecompile.sol"; +import "./IWatcher.sol"; /// @title IAddressResolver /// @notice Interface for resolving system contract addresses diff --git a/contracts/protocol/Socket.sol b/contracts/protocol/Socket.sol index 2b39f518..222b83c3 100644 --- a/contracts/protocol/Socket.sol +++ b/contracts/protocol/Socket.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.21; import {LibCall} from "solady/utils/LibCall.sol"; import "./SocketUtils.sol"; +import {WRITE} from "../../utils/common/Constants.sol"; /** * @title Socket @@ -74,8 +75,9 @@ contract Socket is SocketUtils { ) external payable returns (bool, bytes memory) { // check if the deadline has passed if (executeParams_.deadline < block.timestamp) revert DeadlinePassed(); + // check if the call type is valid - if (executeParams_.callType == CallType.READ) revert ReadOnlyCall(); + if (executeParams_.callType != WRITE) revert InvalidCallType(); PlugConfig memory plugConfig = _plugConfigs[executeParams_.target]; // check if the plug is disconnected diff --git a/contracts/protocol/SocketConfig.sol b/contracts/protocol/SocketConfig.sol index e3fb0194..79e72105 100644 --- a/contracts/protocol/SocketConfig.sol +++ b/contracts/protocol/SocketConfig.sol @@ -7,7 +7,7 @@ import {IPlug} from "./interfaces/IPlug.sol"; import "./interfaces/ISocketFeeManager.sol"; import "../utils/AccessControl.sol"; import {GOVERNANCE_ROLE, RESCUE_ROLE, SWITCHBOARD_DISABLER_ROLE} from "../utils/common/AccessRoles.sol"; -import {CallType, PlugConfig, SwitchboardStatus, ExecutionStatus} from "../utils/common/Structs.sol"; +import {PlugConfig, SwitchboardStatus, ExecutionStatus} from "../utils/common/Structs.sol"; import {PlugNotFound, InvalidAppGateway, InvalidTransmitter} from "../utils/common/Errors.sol"; import {MAX_COPY_BYTES} from "../utils/common/Constants.sol"; diff --git a/test/mock/MockWatcherPrecompile.sol b/test/mock/MockWatcherPrecompile.sol index ee89876b..af96fceb 100644 --- a/test/mock/MockWatcherPrecompile.sol +++ b/test/mock/MockWatcherPrecompile.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.21; import "../../contracts/evmx/interfaces/IAppGateway.sol"; -import "../../contracts/evmx/interfaces/IWatcherPrecompile.sol"; +import "../../contracts/evmx/interfaces/IWatcher.sol"; import "../../contracts/evmx/interfaces/IPromise.sol"; import {TimeoutRequest, TriggerParams, PlugConfig, ResolvedPromises, AppGatewayConfig} from "../../contracts/utils/common/Structs.sol"; From 76a7efa5b8846da78d9daa7c712e2b7d761b9f41 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Wed, 14 May 2025 23:33:50 +0530 Subject: [PATCH 015/130] fix: app gateway check in queue --- contracts/evmx/watcher/Watcher.sol | 12 ++++++++++-- contracts/evmx/watcher/precompiles/Write.sol | 1 - 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/contracts/evmx/watcher/Watcher.sol b/contracts/evmx/watcher/Watcher.sol index e913fe9e..435d3575 100644 --- a/contracts/evmx/watcher/Watcher.sol +++ b/contracts/evmx/watcher/Watcher.sol @@ -40,7 +40,7 @@ abstract contract WatcherStorage is IWatcher { QueueParams[] public queue; address public latestAsyncPromise; - address public latestPromiseCaller; + address public appGatewayTemp; // slots [51-100]: gap for future storage variables uint256[50] _gap_after; @@ -79,8 +79,14 @@ contract Watcher is WatcherStorage { QueueParams memory queue_, address appGateway_ ) external returns (address, uint40) { + address coreAppGateway = getCoreAppGateway(appGateway_); // Deploy a new async promise contract. - latestAsyncPromise = asyncDeployer__().deployAsyncPromiseContract(appGateway_); + if (appGatewayTemp != address(0)) + if (appGatewayTemp != coreAppGateway || coreAppGateway == address(0)) + revert InvalidAppGateway(); + + latestAsyncPromise = asyncDeployer__().deployAsyncPromiseContract(coreAppGateway); + appGatewayTemp = coreAppGateway; queue_.asyncPromise = latestAsyncPromise; // Add the promise to the queue. @@ -106,6 +112,8 @@ contract Watcher is WatcherStorage { address consumeFrom, bytes onCompleteData ) external returns (uint40 requestCount, address[] memory promiseList) { + if (getCoreAppGateway(msg.sender) != appGatewayTemp) revert InvalidAppGateways(); + (requestCount, promiseList) = requestHandler.submitRequest( maxFees, auctionManager, diff --git a/contracts/evmx/watcher/precompiles/Write.sol b/contracts/evmx/watcher/precompiles/Write.sol index 0b544697..dfdec214 100644 --- a/contracts/evmx/watcher/precompiles/Write.sol +++ b/contracts/evmx/watcher/precompiles/Write.sol @@ -53,7 +53,6 @@ contract Write is IPrecompile { queuePayloadParams_.overrideParams.value ); - //todo: no callback fees if callback data not set in promise fees = writeFees + callbackFees; } From fc87a876a44cceb9d8ae35400b70b612a5ef6838 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Wed, 14 May 2025 23:38:35 +0530 Subject: [PATCH 016/130] fix: configurations --- contracts/evmx/interfaces/IConfigurations.sol | 39 +++++++++---------- contracts/evmx/watcher/Configurations.sol | 32 +++++---------- 2 files changed, 28 insertions(+), 43 deletions(-) diff --git a/contracts/evmx/interfaces/IConfigurations.sol b/contracts/evmx/interfaces/IConfigurations.sol index d2374574..91d2aacd 100644 --- a/contracts/evmx/interfaces/IConfigurations.sol +++ b/contracts/evmx/interfaces/IConfigurations.sol @@ -13,14 +13,16 @@ interface IConfigurations { address feesPlug; } - /// @notice The chain slug of the watcher precompile - function evmxSlug() external view returns (uint32); - - /// @notice Maps chain slug to their associated socket - function socketConfigs(uint32 chainSlug) external view returns (SocketConfig memory); + /// @notice Verifies connections between components + function verifyConnections( + uint32 chainSlug_, + address target_, + address appGateway_, + address switchboard_ + ) external view; /// @notice Maps contract address to their associated app gateway - function coreAppGateways(address contractAddress) external view returns (address); + function getCoreAppGateway(address contractAddress) external view returns (address); /// @notice Maps app gateway, chain slug and plug to validity function isValidPlug( @@ -29,29 +31,26 @@ interface IConfigurations { address plug ) external view returns (bool); - /// @notice Sets the switchboard for a network - function setSwitchboard(uint32 chainSlug_, bytes32 sbType_, address switchboard_) external; - - /// @notice Sets valid plugs for each chain slug - /// @dev This function is used to verify if a plug deployed on a chain slug is valid connection to the app gateway - function setIsValidPlug(uint32 chainSlug_, address plug_, bool isValid_) external; - /// @notice Retrieves the configuration for a specific plug on a network function getPlugConfigs( uint32 chainSlug_, address plug_ ) external view returns (bytes32, address); - /// @notice Verifies connections between components - function verifyConnections( - uint32 chainSlug_, - address target_, - address appGateway_, - address switchboard_ - ) external view; + /// @notice Maps chain slug to their associated socket + function socketConfigs(uint32 chainSlug) external view returns (SocketConfig memory); + + /// @notice Sets the switchboard for a network + function setSwitchboard(uint32 chainSlug_, bytes32 sbType_, address switchboard_) external; + + /// @notice Sets valid plugs for each chain slug + /// @dev This function is used to verify if a plug deployed on a chain slug is valid connection to the app gateway + function setIsValidPlug(bool isValid_, uint32 chainSlug_, address plug_) external; function setPlugConfigs(AppGatewayConfig[] calldata configs_) external; + function setOnChainContracts(uint32 chainSlug_, SocketConfig memory socketConfig_) external; + /// @notice Sets the core app gateway for the watcher precompile function setCoreAppGateway(address appGateway_) external; } diff --git a/contracts/evmx/watcher/Configurations.sol b/contracts/evmx/watcher/Configurations.sol index 447df5b7..21ebb8f2 100644 --- a/contracts/evmx/watcher/Configurations.sol +++ b/contracts/evmx/watcher/Configurations.sol @@ -2,27 +2,20 @@ pragma solidity ^0.8.21; import "solady/utils/Initializable.sol"; -import {ECDSA} from "solady/utils/ECDSA.sol"; -import {Ownable} from "solady/auth/Ownable.sol"; import "../interfaces/IConfigurations.sol"; import {AddressResolverUtil} from "../AddressResolverUtil.sol"; -import {InvalidWatcherSignature, NonceUsed} from "../../utils/common/Errors.sol"; import "./core/WatcherIdUtils.sol"; /// @title Configurations /// @notice Configuration contract for the Watcher Precompile system /// @dev Handles the mapping between networks, plugs, and app gateways for payload execution -contract Configurations is IConfigurations, Initializable, Ownable, AddressResolverUtil { +contract Configurations is IConfigurations, Initializable, AddressResolverUtil { // slots 0-50 (51) reserved for addr resolver util // slots [51-100]: gap for future storage variables uint256[50] _gap_before; - // slot 101: evmxSlug - /// @notice The chain slug of the watcher precompile - uint32 public evmxSlug; - - // slot 102: _plugConfigs + // slot 101: _plugConfigs /// @notice Maps network and plug to their configuration /// @dev chainSlug => plug => PlugConfig mapping(uint32 => mapping(address => PlugConfig)) internal _plugConfigs; @@ -42,11 +35,6 @@ contract Configurations is IConfigurations, Initializable, Ownable, AddressResol /// @dev contractAddress => appGateway mapping(address => address) public coreAppGateways; - // slot 108: isNonceUsed - /// @notice Maps nonce to whether it has been used - /// @dev signatureNonce => isValid - mapping(uint256 => bool) public isNonceUsed; - // slot 109: isValidPlug /// @notice Maps app gateway, chain slug, and plug to whether it is valid /// @dev appGateway => chainSlug => plug => isValid @@ -87,15 +75,8 @@ contract Configurations is IConfigurations, Initializable, Ownable, AddressResol error InvalidSwitchboard(); /// @notice Initial initialization (version 1) - function initialize( - address owner_, - address addressResolver_, - uint32 evmxSlug_ - ) public reinitializer(1) { + function initialize(address addressResolver_) public reinitializer(1) { _setAddressResolver(addressResolver_); - _initializeOwner(owner_); - - evmxSlug = evmxSlug_; } /// @notice Configures app gateways with their respective plugs and switchboards @@ -148,7 +129,7 @@ contract Configurations is IConfigurations, Initializable, Ownable, AddressResol /// @param chainSlug_ The identifier of the network /// @param plug_ The address of the plug /// @param isValid_ Whether the plug is valid - function setIsValidPlug(uint32 chainSlug_, address plug_, bool isValid_) external { + function setIsValidPlug(bool isValid_, uint32 chainSlug_, address plug_) external { isValidPlug[msg.sender][chainSlug_][plug_] = isValid_; emit IsValidPlugSet(msg.sender, chainSlug_, plug_, isValid_); } @@ -158,6 +139,11 @@ contract Configurations is IConfigurations, Initializable, Ownable, AddressResol emit CoreAppGatewaySet(appGateway_, msg.sender); } + function getCoreAppGateway(address appGateway_) external view returns (address coreAppGateway) { + coreAppGateway = coreAppGateways[appGateway_]; + if (coreAppGateway == address(0)) coreAppGateway = appGateway_; + } + /// @notice Retrieves the configuration for a specific plug on a network /// @dev Returns zero addresses if configuration doesn't exist /// @param chainSlug_ The identifier of the network From 0b7f59a13927eb9f59766d05e90eb7ad3f782ef5 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Wed, 14 May 2025 23:50:19 +0530 Subject: [PATCH 017/130] fix: watcher events and sender auth --- contracts/evmx/interfaces/IWatcher.sol | 3 ++- contracts/evmx/watcher/RequestHandler.sol | 15 +++++++++++---- contracts/evmx/watcher/precompiles/Read.sol | 9 ++++++++- contracts/evmx/watcher/precompiles/Schedule.sol | 9 +++++---- contracts/evmx/watcher/precompiles/Write.sol | 10 ++++++---- 5 files changed, 32 insertions(+), 14 deletions(-) diff --git a/contracts/evmx/interfaces/IWatcher.sol b/contracts/evmx/interfaces/IWatcher.sol index 0813c91e..57d20cb9 100644 --- a/contracts/evmx/interfaces/IWatcher.sol +++ b/contracts/evmx/interfaces/IWatcher.sol @@ -58,8 +58,9 @@ interface IWatcher { ); event RequestSubmitted( - address middleware, + bool hasWrite, uint40 requestCount, + RequestParams requestParams, PayloadParams[] payloadParamsArray ); diff --git a/contracts/evmx/watcher/RequestHandler.sol b/contracts/evmx/watcher/RequestHandler.sol index 3d7fb870..18e37e88 100644 --- a/contracts/evmx/watcher/RequestHandler.sol +++ b/contracts/evmx/watcher/RequestHandler.sol @@ -73,7 +73,8 @@ contract RequestHandler is WatcherBase { onCompleteData: onCompleteData_ }); - (r.requestFeesDetails.watcherFees, r.writeCount, promiseList) = _createRequest( + PayloadParams[] memory payloads; + (r.requestFeesDetails.watcherFees, r.writeCount, promiseList, payloads) = _createRequest( queuePayloadParams_, appGateway, requestCount @@ -83,7 +84,7 @@ contract RequestHandler is WatcherBase { watcherPrecompile__().setRequestParams(requestCount, r); if (r.writeCount == 0) startProcessingRequest(); - emit RequestSubmitted(); + emit RequestSubmitted(r.writeCount > 0, requestCount, r, payloads); } function _createRequest( @@ -92,7 +93,12 @@ contract RequestHandler is WatcherBase { uint40 requestCount_ ) internal - returns (uint256 totalWatcherFees, uint256 writeCount, address[] memory promiseList) + returns ( + uint256 totalWatcherFees, + uint256 writeCount, + address[] memory promiseList, + PayloadParams[] memory payloads + ) { // push first batch count requestBatchIds[requestCount_].push(nextBatchCount); @@ -139,7 +145,7 @@ contract RequestHandler is WatcherBase { batchPayloadIds[batchCount].push(payloadId); // create prev digest hash - PayloadSubmitParams memory p = PayloadSubmitParams({ + PayloadParams memory p = PayloadParams({ requestCount: requestCount_, batchCount: batchCount, payloadCount: payloadCount, @@ -150,6 +156,7 @@ contract RequestHandler is WatcherBase { appGateway: queuePayloadParams_.appGateway }); promiseList.push(queuePayloadParams_.asyncPromise); + payloads.push(p); watcherPrecompile__().setPayloadParams(payloadId, p); } diff --git a/contracts/evmx/watcher/precompiles/Read.sol b/contracts/evmx/watcher/precompiles/Read.sol index 3129bd22..0469919b 100644 --- a/contracts/evmx/watcher/precompiles/Read.sol +++ b/contracts/evmx/watcher/precompiles/Read.sol @@ -4,10 +4,11 @@ pragma solidity ^0.8.21; import "../../interfaces/IWatcher.sol"; import "../../../utils/common/Structs.sol"; import "../../../utils/common/Errors.sol"; +import "../WatcherBase.sol"; /// @title Read /// @notice Handles read precompile logic -contract Read is IPrecompile { +contract Read is IPrecompile, WatcherBase { /// @notice Emitted when a new read is requested event ReadRequested(PayloadParams params); @@ -42,4 +43,10 @@ contract Read is IPrecompile { fees = readFees + callbackFees; emit ReadRequested(payloadParams); } + + function setFees(uint256 readFees_, uint256 callbackFees_) external onlyWatcher { + readFees = readFees_; + callbackFees = callbackFees_; + emit FeesSet(readFees_, callbackFees_); + } } diff --git a/contracts/evmx/watcher/precompiles/Schedule.sol b/contracts/evmx/watcher/precompiles/Schedule.sol index 06a6efb7..57bc43b7 100644 --- a/contracts/evmx/watcher/precompiles/Schedule.sol +++ b/contracts/evmx/watcher/precompiles/Schedule.sol @@ -4,11 +4,12 @@ pragma solidity ^0.8.21; import "../../interfaces/IPrecompile.sol"; import "../../../utils/common/Structs.sol"; import "../../../utils/common/Errors.sol"; +import "../WatcherBase.sol"; /// @title Schedule /// @notice Library that handles schedule logic for the WatcherPrecompile system /// @dev This library contains pure functions for schedule operations -contract Schedule is IPrecompile { +contract Schedule is IPrecompile, WatcherBase { // slot 52 /// @notice The maximum delay for a schedule /// @dev Maximum schedule delay in seconds @@ -30,7 +31,7 @@ contract Schedule is IPrecompile { /// @param maxScheduleDelayInSeconds_ The maximum schedule delay in seconds /// @dev This function sets the maximum schedule delay in seconds /// @dev Only callable by the contract owner - function setMaxScheduleDelayInSeconds(uint256 maxScheduleDelayInSeconds_) external onlyOwner { + function setMaxScheduleDelayInSeconds(uint256 maxScheduleDelayInSeconds_) external onlyWatcher { maxScheduleDelayInSeconds = maxScheduleDelayInSeconds_; emit MaxScheduleDelayInSecondsSet(maxScheduleDelayInSeconds_); } @@ -39,7 +40,7 @@ contract Schedule is IPrecompile { /// @param scheduleFeesPerSecond_ The fees per second for a schedule /// @dev This function sets the fees per second for a schedule /// @dev Only callable by the contract owner - function setScheduleFeesPerSecond(uint256 scheduleFeesPerSecond_) external onlyOwner { + function setScheduleFeesPerSecond(uint256 scheduleFeesPerSecond_) external onlyWatcher { scheduleFeesPerSecond = scheduleFeesPerSecond_; emit ScheduleFeesPerSecondSet(scheduleFeesPerSecond_); } @@ -48,7 +49,7 @@ contract Schedule is IPrecompile { /// @param scheduleCallbackFees_ The callback fees for a schedule /// @dev This function sets the callback fees for a schedule /// @dev Only callable by the contract owner - function setScheduleCallbackFees(uint256 scheduleCallbackFees_) external onlyOwner { + function setScheduleCallbackFees(uint256 scheduleCallbackFees_) external onlyWatcher { scheduleCallbackFees = scheduleCallbackFees_; emit ScheduleCallbackFeesSet(scheduleCallbackFees_); } diff --git a/contracts/evmx/watcher/precompiles/Write.sol b/contracts/evmx/watcher/precompiles/Write.sol index dfdec214..48fe72e9 100644 --- a/contracts/evmx/watcher/precompiles/Write.sol +++ b/contracts/evmx/watcher/precompiles/Write.sol @@ -5,9 +5,11 @@ import "../../interfaces/IWatcher.sol"; import "../../../utils/common/Structs.sol"; import "../../../utils/common/Errors.sol"; +import "../WatcherBase.sol"; + /// @title Write /// @notice Handles write precompile logic -contract Write is IPrecompile { +contract Write is IPrecompile, WatcherBase { /// @notice Mapping to store watcher proofs /// @dev Maps payload ID to proof bytes /// @dev payloadId => proof bytes @@ -69,7 +71,7 @@ contract Write is IPrecompile { /// @notice Marks a write request as finalized with a proof on digest /// @param payloadId_ The unique identifier of the request /// @param proof_ The watcher's proof - function finalize(bytes32 payloadId_, bytes memory proof_) public onlyOwner { + function finalize(bytes32 payloadId_, bytes memory proof_) public onlyWatcher { watcherProofs[payloadId_] = proof_; emit Finalized(payloadId_, proof_); } @@ -80,7 +82,7 @@ contract Write is IPrecompile { function updateChainMaxMsgValueLimits( uint32[] calldata chainSlugs_, uint256[] calldata maxMsgValueLimits_ - ) external onlyOwner { + ) external onlyWatcher { if (chainSlugs_.length != maxMsgValueLimits_.length) revert InvalidIndex(); for (uint256 i = 0; i < chainSlugs_.length; i++) { @@ -90,7 +92,7 @@ contract Write is IPrecompile { emit ChainMaxMsgValueLimitsUpdated(chainSlugs_, maxMsgValueLimits_); } - function setFees(uint256 writeFees_, uint256 callbackFees_) external onlyOwner { + function setFees(uint256 writeFees_, uint256 callbackFees_) external onlyWatcher { writeFees = writeFees_; callbackFees = callbackFees_; emit FeesSet(writeFees_, callbackFees_); From cba1ff39dcaadc641d6389105db8b0d62c57f6ce Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Thu, 15 May 2025 17:12:20 +0530 Subject: [PATCH 018/130] fix: auction manager --- contracts/app-gateway/RequestQueue.sol | 44 ------ contracts/core/RequestHandler.sol | 98 ------------ .../evmx/app-gateways/AuctionManager.sol | 139 ++++++++++-------- contracts/evmx/interfaces/IAuctionManager.sol | 4 +- 4 files changed, 83 insertions(+), 202 deletions(-) delete mode 100644 contracts/app-gateway/RequestQueue.sol diff --git a/contracts/app-gateway/RequestQueue.sol b/contracts/app-gateway/RequestQueue.sol deleted file mode 100644 index e704bb07..00000000 --- a/contracts/app-gateway/RequestQueue.sol +++ /dev/null @@ -1,44 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -pragma solidity ^0.8.21; - -import "./DeliveryUtils.sol"; - -/// @notice Abstract contract for managing asynchronous payloads -abstract contract RequestQueue is DeliveryUtils { - function _submitBatchRequest( - PayloadSubmitParams[] memory payloadSubmitParamsArray, - address consumeFrom_, - BatchParams memory params - ) internal returns (uint40 requestCount) { - emit PayloadSubmitted( - requestCount, - params.appGateway, - payloadSubmitParamsArray, - params.maxFees - watcherFees, - params.auctionManager, - params.onlyReadRequests - ); - } - - function _createDeployPayloadDetails( - QueuePayloadParams memory queuePayloadParams_ - ) internal returns (bytes memory payload, address target) { - bytes32 salt = keccak256( - abi.encode(queuePayloadParams_.appGateway, queuePayloadParams_.chainSlug, saltCounter++) - ); - - // app gateway is set in the plug deployed on chain - payload = abi.encodeWithSelector( - IContractFactoryPlug.deployContract.selector, - queuePayloadParams_.isPlug, - salt, - bytes32(uint256(uint160(queuePayloadParams_.appGateway))), - queuePayloadParams_.switchboard, - queuePayloadParams_.payload, - queuePayloadParams_.initCallData - ); - - // getting app gateway for deployer as the plug is connected to the app gateway - target = getDeliveryHelperPlugAddress(queuePayloadParams_.chainSlug); - } -} diff --git a/contracts/core/RequestHandler.sol b/contracts/core/RequestHandler.sol index 11638231..86b93c76 100644 --- a/contracts/core/RequestHandler.sol +++ b/contracts/core/RequestHandler.sol @@ -8,104 +8,6 @@ import "./WatcherPrecompileCore.sol"; /// @dev This contract extends WatcherPrecompileCore to provide request handling functionality /// @dev It manages the submission of payload requests and their processing abstract contract RequestHandler is WatcherPrecompileCore { - using PayloadHeaderDecoder for bytes32; - - // slots [266-315] reserved for gap - uint256[50] _request_handler_gap; - - /// @notice Submits a batch of payload requests from middleware - /// @param payloadSubmitParams_ Array of payload submit parameters - /// @return requestCount The unique identifier for the submitted request - /// @dev This function processes a batch of payload requests and assigns them to batches - /// @dev It also consumes limits for the app gateway based on the number of reads and writes - function submitRequest( - PayloadSubmitParams[] memory payloadSubmitParams_ - ) public returns (uint40 requestCount) { - requestCount = nextRequestCount++; - uint40 batchCount = nextBatchCount; - uint40 currentBatch = batchCount; - - uint256 readCount; - uint256 writeCount; - PayloadSubmitParams memory lastP; - - for (uint256 i = 0; i < payloadSubmitParams_.length; i++) { - PayloadSubmitParams memory p = payloadSubmitParams_[i]; - - // Count reads and writes for checking limits - if (p.callType == READ) { - readCount++; - } else writeCount++; - - // checking level number for batching - if (i > 0) { - if (p.levelNumber != lastP.levelNumber && p.levelNumber != lastP.levelNumber + 1) - revert InvalidLevelNumber(); - if (p.levelNumber == lastP.levelNumber + 1) { - requestBatchIds[requestCount].push(batchCount); - batchCount = ++nextBatchCount; - } - } - - batchPayloadIds[batchCount].push(payloadId); - - bytes32 payloadHeader = PayloadHeaderDecoder.createPayloadHeader( - requestCount, - batchCount, - localPayloadCount, - p.chainSlug, - p.callType, - p.isParallel, - p.writeFinality - ); - - payloads[payloadId].payloadHeader = payloadHeader; - payloads[payloadId].asyncPromise = p.asyncPromise; - payloads[payloadId].switchboard = p.switchboard; - payloads[payloadId].target = p.target; - payloads[payloadId].appGateway = p.appGateway; - payloads[payloadId].payloadId = payloadId; - payloads[payloadId].gasLimit = p.gasLimit; - payloads[payloadId].value = p.value; - payloads[payloadId].readAtBlockNumber = p.readAtBlockNumber; - payloads[payloadId].payload = p.payload; - - requestParams[requestCount].payloadParamsArray.push(payloads[payloadId]); - lastP = p; - } - - // Push the final batch ID to the request's batch list and increment the counter - // This is needed because the last batch in the loop above doesn't get added since there's no next level to trigger it - requestBatchIds[requestCount].push(nextBatchCount++); - requestParams[requestCount].currentBatch = currentBatch; - - emit RequestSubmitted( - msg.sender, - requestCount, - requestParams[requestCount].payloadParamsArray - ); - } - - /// @notice Checks if all app gateways in the payload submit parameters are valid and same - /// @dev It also handles special cases for the delivery helper - /// @param payloadSubmitParams Array of payload submit parameters - /// @return appGateway The core app gateway address - function _checkAppGateways( - PayloadSubmitParams[] memory payloadSubmitParams - ) internal view returns (address appGateway) { - // Get first app gateway and use it as reference - address coreAppGateway = _getCoreAppGateway(msg.sender); - - // Skip first element since we already checked it - for (uint256 i = 1; i < payloadSubmitParams.length; i++) { - appGateway = isDeliveryHelper - ? _getCoreAppGateway(payloadSubmitParams[i].appGateway) - : coreAppGateway; - - if (appGateway != coreAppGateway) revert InvalidGateway(); - } - } - /// @notice Starts processing a request with a specified transmitter /// @param requestCount The request count to start processing /// @param transmitter_ The winning bid, contains fees, transmitter and extra data diff --git a/contracts/evmx/app-gateways/AuctionManager.sol b/contracts/evmx/app-gateways/AuctionManager.sol index adf78cf5..a872043d 100644 --- a/contracts/evmx/app-gateways/AuctionManager.sol +++ b/contracts/evmx/app-gateways/AuctionManager.sol @@ -12,9 +12,6 @@ import {AppGatewayBase} from "../base/AppGatewayBase.sol"; /// @title AuctionManagerStorage /// @notice Storage for the AuctionManager contract abstract contract AuctionManagerStorage is IAuctionManager { - // slots [0-49] reserved for gap - uint256[50] _gap_before; - // slot 50 uint32 public evmxSlug; @@ -40,12 +37,6 @@ abstract contract AuctionManagerStorage is IAuctionManager { // slot 56 mapping(uint40 => uint256) public reAuctionCount; - - // slots [57-106] reserved for gap - uint256[50] _gap_after; - - // slots 107-157 (51) reserved for access control - // slots 158-208 (51) reserved for addr resolver util } /// @title AuctionManager @@ -65,7 +56,6 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, } /// @notice Initializer function to replace constructor - /// @param evmxSlug_ The chain slug for the VM /// @param auctionEndDelaySeconds_ The delay in seconds before an auction can end /// @param addressResolver_ The address of the address resolver /// @param owner_ The address of the contract owner @@ -73,15 +63,17 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, function initialize( uint32 evmxSlug_, uint256 auctionEndDelaySeconds_, + uint256 bidTimeout_, + uint256 maxReAuctionCount_, address addressResolver_, - address owner_, - uint256 maxReAuctionCount_ + address owner_ ) public reinitializer(1) { _setAddressResolver(addressResolver_); _initializeOwner(owner_); evmxSlug = evmxSlug_; auctionEndDelaySeconds = auctionEndDelaySeconds_; + bidTimeout = bidTimeout_; maxReAuctionCount = maxReAuctionCount_; } @@ -90,6 +82,11 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, emit AuctionEndDelaySecondsSet(auctionEndDelaySeconds_); } + function setMaxReAuctionCount(uint256 maxReAuctionCount_) external onlyOwner { + maxReAuctionCount = maxReAuctionCount_; + emit MaxReAuctionCountSet(maxReAuctionCount_); + } + /// @notice Places a bid for an auction /// @param requestCount_ The ID of the auction /// @param bidFees The bid amount @@ -97,6 +94,7 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, function bid( uint40 requestCount_, uint256 bidFees, + address scheduleFees_, bytes memory transmitterSignature, bytes memory extraData ) external { @@ -109,66 +107,54 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, ); if (!_hasRole(TRANSMITTER_ROLE, transmitter)) revert InvalidTransmitter(); - uint256 transmitterCredits = getTransmitterMaxFeesAvailable(requestCount_); - - // check if the bid exceeds the max fees quoted by app gateway subtracting the watcher fees - if (bidFees > transmitterCredits) revert BidExceedsMaxFees(); - // check if the bid is lower than the existing bid if ( winningBids[requestCount_].transmitter != address(0) && bidFees >= winningBids[requestCount_].fee ) revert LowerBidAlreadyExists(); + uint256 transmitterCredits = quotedTransmitterFees(requestCount_); + if (bidFees > transmitterCredits) revert BidExceedsMaxFees(); + // create a new bid Bid memory newBid = Bid({fee: bidFees, transmitter: transmitter, extraData: extraData}); - - // update the winning bid winningBids[requestCount_] = newBid; // end the auction if the no auction end delay if (auctionEndDelaySeconds > 0) { _startAuction(requestCount_); - // queue and create request - watcherPrecompile__().setTimeout( - auctionEndDelaySeconds, - abi.encodeWithSelector(this.endAuction.selector, requestCount_) - ); + _createRequest(auctionEndDelaySeconds, scheduleFees_, transmitter, abi.encodeWithSelector(this.endAuction.selector, requestCount_, scheduleFees_)); } else { - _endAuction(requestCount_); + _endAuction(requestCount_, scheduleFees_); } emit BidPlaced(requestCount_, newBid); } - function getTransmitterMaxFeesAvailable(uint40 requestCount_) public view returns (uint256) { - RequestMetadata memory requestMetadata = _getRequestMetadata(requestCount_); - - // check if the bid is for this auction manager - if (requestMetadata.auctionManager != address(this)) revert InvalidBid(); + function _startAuction(uint40 requestCount_) internal { + if (auctionClosed[requestCount_]) revert AuctionClosed(); + if (auctionStarted[requestCount_]) revert AuctionAlreadyStarted(); - // get the total fees required for the watcher precompile ops - uint256 watcherFees = watcherPrecompile().getMaxFees(requestCount_); - return requestMetadata.maxFees - watcherFees; + auctionStarted[requestCount_] = true; + emit AuctionStarted(requestCount_); } /// @notice Ends an auction /// @param requestCount_ The ID of the auction - function endAuction(uint40 requestCount_) external onlyWatcherPrecompile { + function endAuction(uint40 requestCount_, uint256 scheduleFees_) external onlyWatcherPrecompile { if (auctionClosed[requestCount_]) return; - _endAuction(requestCount_); + _endAuction(requestCount_, scheduleFees_); } - function _endAuction(uint40 requestCount_) internal { + function _endAuction(uint40 requestCount_, uint256 scheduleFees_) internal { // get the winning bid, if no transmitter is set, revert Bid memory winningBid = winningBids[requestCount_]; if (winningBid.transmitter == address(0)) revert InvalidTransmitter(); auctionClosed[requestCount_] = true; - RequestMetadata memory requestMetadata = _getRequestMetadata(requestCount_); + RequestParams memory requestParams = _getRequestParams(requestCount_); - // block the fees - // in startRequestProcessing, block the fees from bid + // todo: block fees in watcher in startRequestProcessing // feesManager__().blockCredits( // requestMetadata.consumeFrom, // winningBid.fee, @@ -177,14 +163,11 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, // set the timeout for the bid expiration // useful in case a transmitter did bid but did not execute payloads - // todo: queue and submit timeouts - // watcherPrecompile__().timeout( - // address(this), - // abi.encodeWithSelector(this.expireBid.selector, requestCount_) - // ); + _createRequest(bidTimeout, scheduleFees_, winningBid.transmitter, abi.encodeWithSelector(this.expireBid.selector, requestCount_)); + // todo: merge them and create a single function call // start the request processing, it will queue the request - if (requestMetadata.transmitter != address(0)) { + if (requestParams.requestFeesDetails.bid.transmitter != address(0)) { IWatcher(watcherPrecompile__()).updateTransmitter(requestCount_, winningBid); } else { IWatcher(watcherPrecompile__()).startRequestProcessing(requestCount_, winningBid); @@ -199,27 +182,71 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, /// @param requestCount_ The request id function expireBid(uint40 requestCount_) external onlyWatcherPrecompile { if (reAuctionCount[requestCount_] >= maxReAuctionCount) revert MaxReAuctionCountReached(); - RequestParams memory requestParams = watcherPrecompile__().getRequestParams(requestCount_); + RequestParams memory requestParams = _getRequestParams(requestCount_); // if executed, bid is not expired - if (requestParams.payloadsRemaining == 0 || requestParams.isRequestCancelled) return; - winningBids[requestCount_] = Bid({fee: 0, transmitter: address(0), extraData: ""}); + if (requestParams.requestTrackingParams.payloadsRemaining == 0 || requestParams.requestTrackingParams.isRequestCancelled) return; + + delete winningBids[requestCount_]; auctionClosed[requestCount_] = false; reAuctionCount[requestCount_]++; // todo: unblock credits by calling watcher for updating transmitter to addr(0) // feesManager__().unblockCredits(requestCount_); + emit AuctionRestarted(requestCount_); } - function _startAuction(uint40 requestCount_) internal { - if (auctionClosed[requestCount_]) revert AuctionClosed(); - if (auctionStarted[requestCount_]) revert AuctionAlreadyStarted(); + function _createRequest(uint256 delayInSeconds_, uint256 maxFees_, address consumeFrom_, bytes memory payload_) internal { + QueueParams memory queueParams = QueueParams({ + overrideParams: OverrideParams({ + overrideParams.isParallelCall = Parallel.OFF; + gasLimit: 0, + value: 0, + readAtBlockNumber: 0, + writeFinality: WriteFinality.LOW, + delayInSeconds: delayInSeconds_ + }), + transaction: Transaction({ + chainSlug: evmxSlug, + target: address(this), + payload: payload_ + }), + asyncPromise: address(0), + switchboardType: sbType + }); - auctionStarted[requestCount_] = true; - emit AuctionStarted(requestCount_); + // queue and create request + watcherPrecompile__().queueAndRequest( + queueParams, + maxFees_, + address(this), + consumeFrom_, + bytes("") + ); } + /// @notice Returns the quoted transmitter fees for a request + /// @dev returns the max fees quoted by app gateway subtracting the watcher fees + /// @param requestCount_ The request id + /// @return The quoted transmitter fees + function quotedTransmitterFees(uint40 requestCount_) public view returns (uint256) { + RequestParams memory requestParams = _getRequestParams(requestCount_); + // check if the bid is for this auction manager + if (requestParams.auctionManager != address(this)) revert InvalidBid(); + // get the total fees required for the watcher precompile ops + return + requestParams.requestFeesDetails.maxFees - requestParams.requestFeesDetails.watcherFees; + } + + function _getRequestParams(uint40 requestCount_) internal view returns (RequestParams memory) { + return watcherPrecompile__().getRequestParams(requestCount_); + } + + /// @notice Recovers the signer of a message + /// @param digest_ The digest of the message + /// @param signature_ The signature of the message + /// @return The signer of the message function _recoverSigner( bytes32 digest_, bytes memory signature_ @@ -228,10 +255,4 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, // recovered signer is checked for the valid roles later signer = ECDSA.recover(digest, signature_); } - - function _getRequestMetadata( - uint40 requestCount_ - ) internal view returns (RequestMetadata memory) { - return watcherPrecompile__().getRequestMetadata(requestCount_); - } } diff --git a/contracts/evmx/interfaces/IAuctionManager.sol b/contracts/evmx/interfaces/IAuctionManager.sol index c741c8e9..c0ee59f7 100644 --- a/contracts/evmx/interfaces/IAuctionManager.sol +++ b/contracts/evmx/interfaces/IAuctionManager.sol @@ -12,13 +12,15 @@ interface IAuctionManager { function bid( uint40 requestCount_, uint256 fee_, + address scheduleFees_, bytes memory transmitterSignature_, bytes memory extraData_ ) external; /// @notice Ends an auction /// @param requestCount_ The request count - function endAuction(uint40 requestCount_) external; + /// @param scheduleFees_ The schedule fees + function endAuction(uint40 requestCount_, uint256 scheduleFees_) external; /// @notice Checks if an auction is closed /// @param requestCount_ The request count From 981ec48c2cb2f8855d9e385a440ed812b10472c3 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Fri, 16 May 2025 15:24:08 +0530 Subject: [PATCH 019/130] feat: refactor fee manager --- contracts/evmx/fees/CreditUtils.sol | 204 ++++++++++ contracts/evmx/fees/FeesManager.sol | 576 ++++------------------------ contracts/evmx/fees/FeesStorage.sol | 36 ++ contracts/evmx/fees/UserUtils.sol | 239 ++++++++++++ 4 files changed, 552 insertions(+), 503 deletions(-) create mode 100644 contracts/evmx/fees/CreditUtils.sol create mode 100644 contracts/evmx/fees/FeesStorage.sol create mode 100644 contracts/evmx/fees/UserUtils.sol diff --git a/contracts/evmx/fees/CreditUtils.sol b/contracts/evmx/fees/CreditUtils.sol new file mode 100644 index 00000000..c7734c76 --- /dev/null +++ b/contracts/evmx/fees/CreditUtils.sol @@ -0,0 +1,204 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import "./UserUtils.sol"; + +/// @title FeesManager +/// @notice Contract for managing fees +abstract contract CreditUtils is UserUtils { + /// @notice Emitted when fees are blocked for a batch + /// @param requestCount The batch identifier + /// @param consumeFrom The consume from address + /// @param amount The blocked amount + event CreditsBlocked(uint40 indexed requestCount, address indexed consumeFrom, uint256 amount); + + /// @notice Emitted when transmitter fees are updated + /// @param requestCount The batch identifier + /// @param transmitter The transmitter address + /// @param amount The new amount deposited + event TransmitterCreditsUpdated( + uint40 indexed requestCount, + address indexed transmitter, + uint256 amount + ); + event WatcherPrecompileCreditsAssigned(uint256 amount, address consumeFrom); + + /// @notice Emitted when fees are unblocked and assigned to a transmitter + /// @param requestCount The batch identifier + /// @param transmitter The transmitter address + /// @param amount The unblocked amount + event CreditsUnblockedAndAssigned( + uint40 indexed requestCount, + address indexed transmitter, + uint256 amount + ); + + /// @notice Emitted when fees are unblocked + /// @param requestCount The batch identifier + /// @param appGateway The app gateway address + event CreditsUnblocked(uint40 indexed requestCount, address indexed appGateway); + + /// @notice Emitted when insufficient watcher precompile fees are available + event InsufficientWatcherPrecompileCreditsAvailable( + uint32 chainSlug, + address token, + address consumeFrom + ); + + /// @notice Blocks fees for a request count + /// @param consumeFrom_ The fees payer address + /// @param transmitterCredits_ The total fees to block + /// @param requestCount_ The batch identifier + /// @dev Only callable by delivery helper + function blockCredits( + uint40 requestCount_, + uint256 credits_, + address consumeFrom_ + ) external onlyWatcher { + // todo: check in watcher if AM is correct while starting process or updating transmitter + // Block fees + if (getAvailableCredits(consumeFrom_) < credits_) revert InsufficientCreditsAvailable(); + + UserCredits storage userCredit = userCredits[consumeFrom_]; + userCredit.blockedCredits += credits_; + + requestCountCredits[requestCount_] = credits_; + emit CreditsBlocked(requestCount_, consumeFrom_, credits_); + } + + /// @notice Unblocks fees after successful execution and assigns them to the transmitter + /// @param requestCount_ The async ID of the executed batch + /// @param consumeFor_ The address of the receiver + function unblockAndAssignCredits( + uint40 requestCount_, + address consumeFor_ + ) external override onlyWatcher { + uint256 blockedCredits = requestCountCredits[requestCount_]; + if (blockedCredits == 0) return; + + RequestParams memory requestParams = _getRequestParams(requestCount_); + uint256 fees = requestParams.requestFeesDetails.maxFees; + + // Unblock fees from deposit + _useBlockedUserCredits(requestParams.consumeFrom, blockedCredits, fees); + + // Assign fees to transmitter + userCredits[consumeFor_].totalCredits += fees; + + // Clean up storage + delete requestCountCredits[requestCount_]; + emit CreditsUnblockedAndAssigned(requestCount_, consumeFor_, fees); + } + + function _useBlockedUserCredits( + address consumeFrom_, + uint256 toConsumeFromBlocked_, + uint256 toConsumeFromTotal_ + ) internal { + UserCredits storage userCredit = userCredits[consumeFrom_]; + userCredit.blockedCredits -= toConsumeFromBlocked_; + userCredit.totalCredits -= toConsumeFromTotal_; + } + + function _useAvailableUserCredits(address consumeFrom_, uint256 toConsume_) internal { + UserCredits storage userCredit = userCredits[consumeFrom_]; + if (userCredit.totalCredits < toConsume_) revert InsufficientCreditsAvailable(); + userCredit.totalCredits -= toConsume_; + } + + function assignWatcherPrecompileCreditsFromAddress( + uint256 amount_, + address consumeFrom_ + ) external onlyWatcher { + // deduct the fees from the user + _useAvailableUserCredits(consumeFrom_, amount_); + // add the fees to the watcher precompile + watcherPrecompileCredits += amount_; + emit WatcherPrecompileCreditsAssigned(amount_, consumeFrom_); + } + + function unblockCredits(uint40 requestCount_) external onlyWatcher { + RequestParams memory requestParams = _getRequestParams(requestCount_); + + // todo: check in watcher + // if (msg.sender != requestParams.auctionManager) revert InvalidCaller(); + + uint256 blockedCredits = requestCountCredits[requestCount_]; + if (blockedCredits == 0) return; + + // Unblock fees from deposit + _useBlockedUserCredits( + requestParams.requestFeesDetails.consumeFrom, + blockedCredits, + requestParams.requestFeesDetails.maxFees + ); + delete requestCountCredits[requestCount_]; + emit CreditsUnblocked(requestCount_, requestParams.requestFeesDetails.consumeFrom); + } + + function _getRequestParams(uint40 requestCount_) internal view returns (RequestParams memory) { + return watcherPrecompile__().getRequestParams(requestCount_); + } +} + +// /// @notice Withdraws funds to a specified receiver +// /// @param chainSlug_ The chain identifier +// /// @param token_ The address of the token +// /// @param amount_ The amount of tokens to withdraw +// /// @param receiver_ The address of the receiver +// /// @param fees_ The fees data +// function withdrawTo( +// uint32 chainSlug_, +// address token_, +// uint256 amount_, +// address receiver_, +// address auctionManager_, +// uint256 fees_ +// ) external returns (uint40) { +// feesManager__().withdrawCredits( +// msg.sender, +// chainSlug_, +// token_, +// amount_, +// receiver_ +// ); +// return _batch(msg.sender, auctionManager_, msg.sender, fees_, bytes("")); +// } + +// /// @notice Withdraws fees to a specified receiver +// /// @param chainSlug_ The chain identifier +// /// @param token_ The token address +// /// @param receiver_ The address of the receiver +// function withdrawTransmitterFees( +// uint32 chainSlug_, +// address token_, +// address receiver_, +// uint256 amount_ +// ) external returns (uint40 requestCount) { +// address transmitter = msg.sender; + +// PayloadSubmitParams[] memory payloadSubmitParamsArray = feesManager__() +// .getWithdrawTransmitterCreditsPayloadParams( +// transmitter, +// chainSlug_, +// token_, +// receiver_, +// amount_ +// ); + +// RequestMetadata memory requestMetadata = RequestMetadata({ +// appGateway: feesManager__(), +// auctionManager: address(0), +// maxFees: 0, +// winningBid: Bid({transmitter: transmitter, fee: 0, extraData: new bytes(0)}), +// onCompleteData: bytes(""), +// onlyReadRequests: false, +// consumeFrom: transmitter, +// queryCount: 0, +// finalizeCount: 1 +// }); // finalize for plug contract +// requestCount = watcherPrecompile__().submitRequest(payloadSubmitParamsArray); +// requests[requestCount] = requestMetadata; +// // same transmitter can execute requests without auction +// watcherPrecompile__().startProcessingRequest(requestCount, transmitter); +// } diff --git a/contracts/evmx/fees/FeesManager.sol b/contracts/evmx/fees/FeesManager.sol index b624e41b..b6888e29 100644 --- a/contracts/evmx/fees/FeesManager.sol +++ b/contracts/evmx/fees/FeesManager.sol @@ -1,107 +1,11 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import {Ownable} from "solady/auth/Ownable.sol"; -import "solady/utils/Initializable.sol"; -import "solady/utils/ECDSA.sol"; -import "../interfaces/IFeesManager.sol"; -import {AddressResolverUtil} from "../AddressResolverUtil.sol"; -import {NotAuctionManager, InvalidWatcherSignature, NonceUsed} from "../../utils/common/Errors.sol"; -import {Bid, Parallel, WriteFinality, QueuePayloadParams, IsPlug, PayloadSubmitParams, RequestMetadata, UserCredits} from "../../utils/common/Structs.sol"; - -abstract contract FeesManagerStorage is IFeesManager { - // slots [0-49] reserved for gap - uint256[50] _gap_before; - - //===== user ===== - // user credits => stores fees for user, app gateway, transmitters and watcher precompile - mapping(address => UserCredits) public userFees; - // user approved app gateways - // userAddress => appGateway => isWhitelisted - mapping(address => mapping(address => bool)) public isAppGatewayWhitelisted; - - // token pool balances - // chainSlug => token address => amount - mapping(uint32 => mapping(address => uint256)) public tokenPoolBalances; - - // slot 54 - /// @notice Mapping to track request credits details for each request count - /// @dev requestCount => RequestFee - mapping(uint40 => uint256) public requestCountCredits; - - // slot 56 - /// @notice Mapping to track nonce to whether it has been used - /// @dev address => signatureNonce => isNonceUsed - /// @dev used by watchers or other users in signatures - mapping(address => mapping(uint256 => bool)) public isNonceUsed; - - uint256 public withdrawCounter; - - // slots [57-106] reserved for gap - uint256[50] _gap_after; - - // slots 107-157 (51) reserved for addr resolver util -} +import "./CreditUtils.sol"; /// @title FeesManager /// @notice Contract for managing fees -contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResolverUtil { - /// @notice Emitted when fees are blocked for a batch - /// @param requestCount The batch identifier - /// @param consumeFrom The consume from address - /// @param amount The blocked amount - event CreditsBlocked(uint40 indexed requestCount, address indexed consumeFrom, uint256 amount); - - /// @notice Emitted when transmitter fees are updated - /// @param requestCount The batch identifier - /// @param transmitter The transmitter address - /// @param amount The new amount deposited - event TransmitterCreditsUpdated( - uint40 indexed requestCount, - address indexed transmitter, - uint256 amount - ); - event WatcherPrecompileCreditsAssigned(uint256 amount, address consumeFrom); - /// @notice Emitted when fees deposited are updated - /// @param chainSlug The chain identifier - /// @param appGateway The app gateway address - /// @param token The token address - /// @param amount The new amount deposited - event CreditsDeposited( - uint32 indexed chainSlug, - address indexed appGateway, - address indexed token, - uint256 amount - ); - - /// @notice Emitted when fees are unblocked and assigned to a transmitter - /// @param requestCount The batch identifier - /// @param transmitter The transmitter address - /// @param amount The unblocked amount - event CreditsUnblockedAndAssigned( - uint40 indexed requestCount, - address indexed transmitter, - uint256 amount - ); - - /// @notice Emitted when fees are unblocked - /// @param requestCount The batch identifier - /// @param appGateway The app gateway address - event CreditsUnblocked(uint40 indexed requestCount, address indexed appGateway); - - /// @notice Emitted when insufficient watcher precompile fees are available - event InsufficientWatcherPrecompileCreditsAvailable( - uint32 chainSlug, - address token, - address consumeFrom - ); - - /// @notice Emitted when credits are wrapped - event CreditsWrapped(address indexed consumeFrom, uint256 amount); - - /// @notice Emitted when credits are unwrapped - event CreditsUnwrapped(address indexed consumeFrom, uint256 amount); - +contract FeesManager is CreditUtils, Initializable, Ownable, AddressResolverUtil { constructor() { _disableInitializers(); // disable for implementation } @@ -122,409 +26,75 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol _initializeOwner(owner_); } - /// @notice Returns available (unblocked) fees for a gateway - /// @param consumeFrom_ The app gateway address - /// @return The available fee amount - function getAvailableCredits(address consumeFrom_) public view returns (uint256) { - UserCredits memory userCredit = userCredits[consumeFrom_]; - return userCredit.totalCredits - userCredit.blockedCredits; - } - - /// @notice Adds the fees deposited for an app gateway on a chain - /// @param depositTo_ The app gateway address - // @dev only callable by watcher precompile - // @dev will need tokenAmount_ and creditAmount_ when introduce tokens except stables - function depositCredits( - address depositTo_, - uint32 chainSlug_, - address token_, - uint256 signatureNonce_, - bytes memory signature_ - ) external payable { - if (isNonceUsed[signatureNonce_]) revert NonceUsed(); - isNonceUsed[signatureNonce_] = true; - - uint256 amount = msg.value; - - // check signature - bytes32 digest = keccak256( - abi.encode(depositTo_, chainSlug_, token_, amount, address(this), evmxSlug) - ); - - if (_recoverSigner(digest, signature_) != owner()) revert InvalidWatcherSignature(); - - UserCredits storage userCredit = userCredits[depositTo_]; - userCredit.totalCredits += amount; - tokenPoolBalances[chainSlug_][token_] += amount; - emit CreditsDeposited(chainSlug_, depositTo_, token_, amount); - } - - function wrap() external payable { - UserCredits storage userCredit = userCredits[msg.sender]; - userCredit.totalCredits += msg.value; - emit CreditsWrapped(msg.sender, msg.value); - } - - function unwrap(uint256 amount_) external { - UserCredits storage userCredit = userCredits[msg.sender]; - if (userCredit.totalCredits < amount_) revert InsufficientCreditsAvailable(); - userCredit.totalCredits -= amount_; - - // todo: if contract balance not enough, take from our pool? - if (address(this).balance < amount_) revert InsufficientBalance(); - payable(msg.sender).transfer(amount_); - emit CreditsUnwrapped(msg.sender, amount_); - } - - function isUserCreditsEnough( - address consumeFrom_, - address appGateway_, - uint256 amount_ - ) external view returns (bool) { - // If consumeFrom is not appGateway, check if it is whitelisted - if (consumeFrom_ != appGateway_ && !isAppGatewayWhitelisted[consumeFrom_][appGateway_]) - revert AppGatewayNotWhitelisted(); - return getAvailableCredits(consumeFrom_) >= amount_; - } - - function _processFeeApprovalData( - bytes memory feeApprovalData_ - ) internal returns (address, address, bool) { - (address consumeFrom, address appGateway, bool isApproved, bytes memory signature_) = abi - .decode(feeApprovalData_, (address, address, bool, bytes)); - - if (signature_.length == 0) { - // If no signature, consumeFrom is appGateway - return (appGateway, appGateway, isApproved); - } - bytes32 digest = keccak256( - abi.encode( - address(this), - evmxSlug, - consumeFrom, - appGateway, - userNonce[consumeFrom], - isApproved - ) - ); - if (_recoverSigner(digest, signature_) != consumeFrom) revert InvalidUserSignature(); - isAppGatewayWhitelisted[consumeFrom][appGateway] = isApproved; - userNonce[consumeFrom]++; - - return (consumeFrom, appGateway, isApproved); - } - - function whitelistAppGatewayWithSignature( - bytes memory feeApprovalData_ - ) external returns (address consumeFrom, address appGateway, bool isApproved) { - return _processFeeApprovalData(feeApprovalData_); - } - - /// @notice Whitelists multiple app gateways for the caller - /// @param params_ Array of app gateway addresses to whitelist - function whitelistAppGateways(AppGatewayWhitelistParams[] calldata params_) external { - for (uint256 i = 0; i < params_.length; i++) { - isAppGatewayWhitelisted[msg.sender][params_[i].appGateway] = params_[i].isApproved; - } - } - - modifier onlyAuctionManager(uint40 requestCount_) { - if (msg.sender != deliveryHelper__().getRequestMetadata(requestCount_).auctionManager) - revert NotAuctionManager(); - _; - } - - /// @notice Blocks fees for a request count - /// @param consumeFrom_ The fees payer address - /// @param transmitterCredits_ The total fees to block - /// @param requestCount_ The batch identifier - /// @dev Only callable by delivery helper - function blockCredits( - address consumeFrom_, - uint256 transmitterCredits_, - uint40 requestCount_ - ) external onlyAuctionManager(requestCount_) { - // Block fees - if (getAvailableCredits(consumeFrom_) < transmitterCredits_) - revert InsufficientCreditsAvailable(); - - UserCredits storage userCredit = userCredits[consumeFrom_]; - userCredit.blockedCredits += transmitterCredits_; - - requestCountCredits[requestCount_] = transmitterCredits_; - - emit CreditsBlocked(requestCount_, consumeFrom_, transmitterCredits_); - } - - /// @notice Unblocks fees after successful execution and assigns them to the transmitter - /// @param requestCount_ The async ID of the executed batch - /// @param transmitter_ The address of the transmitter who executed the batch - function unblockAndAssignCredits( - uint40 requestCount_, - address transmitter_ - ) external override onlyDeliveryHelper { - uint256 blockedCredits = requestCountCredits[requestCount_]; - if (blockedCredits == 0) return; - RequestMetadata memory requestMetadata = deliveryHelper__().getRequestMetadata( - requestCount_ - ); - uint256 fees = requestMetadata.winningBid.fee; - - // Unblock fees from deposit - _useBlockedUserCredits(requestMetadata.consumeFrom, blockedCredits, fees); - - // Assign fees to transmitter - userCredits[transmitter_].totalCredits += fees; - - // Clean up storage - delete requestCountCredits[requestCount_]; - emit CreditsUnblockedAndAssigned(requestCount_, transmitter_, fees); - } - - function _useBlockedUserCredits( - address consumeFrom_, - uint256 toConsumeFromBlocked_, - uint256 toConsumeFromTotal_ - ) internal { - UserCredits storage userCredit = userCredits[consumeFrom_]; - userCredit.blockedCredits -= toConsumeFromBlocked_; - userCredit.totalCredits -= toConsumeFromTotal_; - } - - function _useAvailableUserCredits(address consumeFrom_, uint256 toConsume_) internal { - UserCredits storage userCredit = userCredits[consumeFrom_]; - if (userCredit.totalCredits < toConsume_) revert InsufficientCreditsAvailable(); - userCredit.totalCredits -= toConsume_; - } - - function assignWatcherPrecompileCreditsFromRequestCount( - uint256 amount_, - uint40 requestCount_ - ) external onlyWatcherPrecompile { - RequestMetadata memory requestMetadata = deliveryHelper__().getRequestMetadata( - requestCount_ - ); - _assignWatcherPrecompileCredits(amount_, requestMetadata.consumeFrom); - } - - function assignWatcherPrecompileCreditsFromAddress( - uint256 amount_, - address consumeFrom_ - ) external onlyWatcherPrecompile { - _assignWatcherPrecompileCredits(amount_, consumeFrom_); - } - - function _assignWatcherPrecompileCredits(uint256 amount_, address consumeFrom_) internal { - // deduct the fees from the user - _useAvailableUserCredits(consumeFrom_, amount_); - // add the fees to the watcher precompile - watcherPrecompileCredits += amount_; - emit WatcherPrecompileCreditsAssigned(amount_, consumeFrom_); - } - - function unblockCredits(uint40 requestCount_) external { - RequestMetadata memory requestMetadata = deliveryHelper__().getRequestMetadata( - requestCount_ - ); - - if ( - msg.sender != requestMetadata.auctionManager && - msg.sender != address(deliveryHelper__()) - ) revert InvalidCaller(); - - uint256 blockedCredits = requestCountCredits[requestCount_]; - if (blockedCredits == 0) return; - - // Unblock fees from deposit - UserCredits storage userCredit = userCredits[requestMetadata.consumeFrom]; - userCredit.blockedCredits -= blockedCredits; - - delete requestCountCredits[requestCount_]; - emit CreditsUnblocked(requestCount_, requestMetadata.consumeFrom); - } - - /// @notice Withdraws funds to a specified receiver - /// @dev This function is used to withdraw fees from the fees plug - /// @param originAppGatewayOrUser_ The address of the app gateway - /// @param chainSlug_ The chain identifier - /// @param token_ The address of the token - /// @param amount_ The amount of tokens to withdraw - /// @param receiver_ The address of the receiver - function withdrawCredits( - address originAppGatewayOrUser_, - uint32 chainSlug_, - address token_, - uint256 amount_, - address receiver_ - ) public { - if (msg.sender != address(deliveryHelper__())) originAppGatewayOrUser_ = msg.sender; - address source = _getCoreAppGateway(originAppGatewayOrUser_); - - // Check if amount is available in fees plug - uint256 availableAmount = getAvailableCredits(source); - if (availableAmount < amount_) revert InsufficientCreditsAvailable(); - - _useAvailableUserCredits(source, amount_); - tokenPoolBalances[chainSlug_][token_] -= amount_; - - // Add it to the queue and submit request - _queue(chainSlug_, abi.encodeCall(IFeesPlug.withdrawFees, (token_, receiver_, amount_))); - } - - /// @notice Withdraws fees to a specified receiver - /// @param chainSlug_ The chain identifier - /// @param token_ The token address - /// @param receiver_ The address of the receiver - function getWithdrawTransmitterCreditsPayloadParams( - address transmitter_, - uint32 chainSlug_, - address token_, - address receiver_, - uint256 amount_ - ) external onlyDeliveryHelper returns (PayloadSubmitParams[] memory) { - uint256 maxCreditsAvailableForWithdraw = getMaxCreditsAvailableForWithdraw(transmitter_); - if (amount_ > maxCreditsAvailableForWithdraw) revert InsufficientCreditsAvailable(); - - // Clean up storage - _useAvailableUserCredits(transmitter_, amount_); - tokenPoolBalances[chainSlug_][token_] -= amount_; - - bytes memory payload = abi.encodeCall(IFeesPlug.withdrawFees, (token_, receiver_, amount_)); - PayloadSubmitParams[] memory payloadSubmitParamsArray = new PayloadSubmitParams[](1); - payloadSubmitParamsArray[0] = PayloadSubmitParams({ - levelNumber: 0, - chainSlug: chainSlug_, - callType: WRITE, - isParallel: Parallel.OFF, - writeFinality: WriteFinality.LOW, - asyncPromise: address(0), - switchboard: _getSwitchboard(chainSlug_), - target: _getFeesPlugAddress(chainSlug_), - appGateway: address(this), - gasLimit: 10000000, - value: 0, - readAtBlockNumber: 0, - payload: payload - }); - return payloadSubmitParamsArray; - } - - function getMaxCreditsAvailableForWithdraw(address transmitter_) public view returns (uint256) { - uint256 watcherFees = watcherPrecompileLimits().getTotalFeesRequired(0, 1, 0, 1); - uint256 transmitterCredits = userCredits[transmitter_].totalCredits; - return transmitterCredits > watcherFees ? transmitterCredits - watcherFees : 0; - } - - function _getSwitchboard(uint32 chainSlug_) internal view returns (address) { - return watcherPrecompile__().watcherPrecompileConfig__().switchboards(chainSlug_, sbType); - } - - function _createQueuePayloadParams( - uint32 chainSlug_, - bytes memory payload_ - ) internal view returns (QueuePayloadParams memory) { - return - QueuePayloadParams({ - chainSlug: chainSlug_, - callType: CallType.WRITE, - isParallel: Parallel.OFF, - isPlug: IsPlug.NO, - writeFinality: WriteFinality.LOW, - asyncPromise: address(0), - switchboard: _getSwitchboard(chainSlug_), - target: _getFeesPlugAddress(chainSlug_), - appGateway: address(this), - gasLimit: 10000000, - value: 0, - readAtBlockNumber: 0, - payload: payload_, - initCallData: bytes("") - }); - } - - /// @notice hook called by watcher precompile when request is finished - function onRequestComplete(uint40 requestCount_, bytes memory) external {} - - function _queue(uint32 chainSlug_, bytes memory payload_) internal { - QueuePayloadParams memory queuePayloadParams = _createQueuePayloadParams( - chainSlug_, - payload_ - ); - deliveryHelper__().queue(queuePayloadParams); - } - - function _getFeesPlugAddress(uint32 chainSlug_) internal view returns (address) { - return watcherPrecompileConfig().feesPlug(chainSlug_); - } - - function _recoverSigner( - bytes32 digest_, - bytes memory signature_ - ) internal view returns (address signer) { - bytes32 digest = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", digest_)); - // recovered signer is checked for the valid roles later - signer = ECDSA.recover(digest, signature_); - } + // /// @notice Withdraws funds to a specified receiver + // /// @dev This function is used to withdraw fees from the fees plug + // /// @param originAppGatewayOrUser_ The address of the app gateway + // /// @param chainSlug_ The chain identifier + // /// @param token_ The address of the token + // /// @param amount_ The amount of tokens to withdraw + // /// @param receiver_ The address of the receiver + // function withdrawCredits( + // address originAppGatewayOrUser_, + // uint32 chainSlug_, + // address token_, + // uint256 amount_, + // address receiver_ + // ) public { + // if (msg.sender != address(deliveryHelper__())) originAppGatewayOrUser_ = msg.sender; + // address source = _getCoreAppGateway(originAppGatewayOrUser_); + + // // Check if amount is available in fees plug + // uint256 availableAmount = getAvailableCredits(source); + // if (availableAmount < amount_) revert InsufficientCreditsAvailable(); + + // _useAvailableUserCredits(source, amount_); + // tokenPoolBalances[chainSlug_][token_] -= amount_; + + // // Add it to the queue and submit request + // _queue(chainSlug_, abi.encodeCall(IFeesPlug.withdrawFees, (token_, receiver_, amount_))); + // } + + // /// @notice Withdraws fees to a specified receiver + // /// @param chainSlug_ The chain identifier + // /// @param token_ The token address + // /// @param receiver_ The address of the receiver + // function getWithdrawTransmitterCreditsPayloadParams( + // address transmitter_, + // uint32 chainSlug_, + // address token_, + // address receiver_, + // uint256 amount_ + // ) external onlyWatcher returns (PayloadSubmitParams[] memory) { + // uint256 maxCreditsAvailableForWithdraw = getMaxCreditsAvailableForWithdraw(transmitter_); + // if (amount_ > maxCreditsAvailableForWithdraw) revert InsufficientCreditsAvailable(); + + // // Clean up storage + // _useAvailableUserCredits(transmitter_, amount_); + // tokenPoolBalances[chainSlug_][token_] -= amount_; + + // bytes memory payload = abi.encodeCall(IFeesPlug.withdrawFees, (token_, receiver_, amount_)); + // PayloadSubmitParams[] memory payloadSubmitParamsArray = new PayloadSubmitParams[](1); + // payloadSubmitParamsArray[0] = PayloadSubmitParams({ + // levelNumber: 0, + // chainSlug: chainSlug_, + // callType: WRITE, + // isParallel: Parallel.OFF, + // writeFinality: WriteFinality.LOW, + // asyncPromise: address(0), + // switchboard: _getSwitchboard(chainSlug_), + // target: _getFeesPlugAddress(chainSlug_), + // appGateway: address(this), + // gasLimit: 10000000, + // value: 0, + // readAtBlockNumber: 0, + // payload: payload + // }); + // return payloadSubmitParamsArray; + // } + + // function getMaxCreditsAvailableForWithdraw(address transmitter_) public view returns (uint256) { + // uint256 watcherFees = watcherPrecompileLimits().getTotalFeesRequired(0, 1, 0, 1); + // uint256 transmitterCredits = userCredits[transmitter_].totalCredits; + // return transmitterCredits > watcherFees ? transmitterCredits - watcherFees : 0; + // } } - -// /// @notice Withdraws funds to a specified receiver -// /// @param chainSlug_ The chain identifier -// /// @param token_ The address of the token -// /// @param amount_ The amount of tokens to withdraw -// /// @param receiver_ The address of the receiver -// /// @param fees_ The fees data -// function withdrawTo( -// uint32 chainSlug_, -// address token_, -// uint256 amount_, -// address receiver_, -// address auctionManager_, -// uint256 fees_ -// ) external returns (uint40) { -// feesManager__().withdrawCredits( -// msg.sender, -// chainSlug_, -// token_, -// amount_, -// receiver_ -// ); -// return _batch(msg.sender, auctionManager_, msg.sender, fees_, bytes("")); -// } - -// /// @notice Withdraws fees to a specified receiver -// /// @param chainSlug_ The chain identifier -// /// @param token_ The token address -// /// @param receiver_ The address of the receiver -// function withdrawTransmitterFees( -// uint32 chainSlug_, -// address token_, -// address receiver_, -// uint256 amount_ -// ) external returns (uint40 requestCount) { -// address transmitter = msg.sender; - -// PayloadSubmitParams[] memory payloadSubmitParamsArray = feesManager__() -// .getWithdrawTransmitterCreditsPayloadParams( -// transmitter, -// chainSlug_, -// token_, -// receiver_, -// amount_ -// ); - -// RequestMetadata memory requestMetadata = RequestMetadata({ -// appGateway: feesManager__(), -// auctionManager: address(0), -// maxFees: 0, -// winningBid: Bid({transmitter: transmitter, fee: 0, extraData: new bytes(0)}), -// onCompleteData: bytes(""), -// onlyReadRequests: false, -// consumeFrom: transmitter, -// queryCount: 0, -// finalizeCount: 1 -// }); // finalize for plug contract -// requestCount = watcherPrecompile__().submitRequest(payloadSubmitParamsArray); -// requests[requestCount] = requestMetadata; -// // same transmitter can execute requests without auction -// watcherPrecompile__().startProcessingRequest(requestCount, transmitter); -// } diff --git a/contracts/evmx/fees/FeesStorage.sol b/contracts/evmx/fees/FeesStorage.sol new file mode 100644 index 00000000..ce7b13dc --- /dev/null +++ b/contracts/evmx/fees/FeesStorage.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import {Ownable} from "solady/auth/Ownable.sol"; +import "solady/utils/Initializable.sol"; +import "solady/utils/ECDSA.sol"; +import "../interfaces/IFeesManager.sol"; +import {AddressResolverUtil} from "../AddressResolverUtil.sol"; +import {NotAuctionManager, InvalidWatcherSignature, NonceUsed} from "../../utils/common/Errors.sol"; +import {Bid, Parallel, WriteFinality, QueuePayloadParams, IsPlug, PayloadSubmitParams, RequestMetadata, UserCredits} from "../../utils/common/Structs.sol"; +import "../watcher/WatcherBase.sol"; + +abstract contract FeesManagerStorage is IFeesManager, WatcherBase { + // user credits => stores fees for user, app gateway, transmitters and watcher precompile + mapping(address => UserCredits) public userCredits; + // user approved app gateways + // userAddress => appGateway => isWhitelisted + mapping(address => mapping(address => bool)) public isAppGatewayWhitelisted; + + // token pool balances + // chainSlug => token address => amount + mapping(uint32 => mapping(address => uint256)) public tokenPoolBalances; + + // slot 54 + /// @notice Mapping to track request credits details for each request count + /// @dev requestCount => RequestFee + mapping(uint40 => uint256) public requestCountCredits; + + // slot 56 + /// @notice Mapping to track nonce to whether it has been used + /// @dev address => signatureNonce => isNonceUsed + /// @dev used by watchers or other users in signatures + mapping(address => mapping(uint256 => bool)) public isNonceUsed; + + uint256 public withdrawCounter; +} diff --git a/contracts/evmx/fees/UserUtils.sol b/contracts/evmx/fees/UserUtils.sol new file mode 100644 index 00000000..af6519d8 --- /dev/null +++ b/contracts/evmx/fees/UserUtils.sol @@ -0,0 +1,239 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import "./FeesStorage.sol"; + +/// @title UserUtils +/// @notice Contract for managing user utils +abstract contract UserUtils is FeesStorage, Initializable, Ownable, AddressResolverUtil { + /// @notice Emitted when fees deposited are updated + /// @param chainSlug The chain identifier + /// @param appGateway The app gateway address + /// @param token The token address + /// @param amount The new amount deposited + event CreditsDeposited( + uint32 indexed chainSlug, + address indexed appGateway, + address indexed token, + uint256 amount + ); + + /// @notice Emitted when credits are wrapped + event CreditsWrapped(address indexed consumeFrom, uint256 amount); + + /// @notice Emitted when credits are unwrapped + event CreditsUnwrapped(address indexed consumeFrom, uint256 amount); + + /// @notice Deposits credits and native tokens to a user + /// @param depositTo_ The address to deposit the credits to + /// @param chainSlug_ The chain slug + /// @param token_ The token address + /// @param nativeAmount_ The native amount + /// @param creditAmount_ The credit amount + function deposit( + address depositTo_, + uint32 chainSlug_, + address token_, + uint256 nativeAmount_, + uint256 creditAmount_ + ) external payable onlyWatcher { + if (creditAmount_ + nativeAmount_ != msg.value) revert InvalidAmount(); + + UserCredits storage userCredit = userCredits[depositTo_]; + userCredit.totalCredits += creditAmount_; + tokenPoolBalances[chainSlug_][token_] += creditAmount_; + payable(depositTo_).transfer(nativeAmount_); + + emit CreditsDeposited(chainSlug_, depositTo_, token_, creditAmount_); + } + + /// @notice Adds the fees deposited for an app gateway on a chain + /// @param depositTo_ The app gateway address + // @dev only callable by watcher precompile + // @dev will need tokenAmount_ and creditAmount_ when introduce tokens except stables + function depositCredits( + address depositTo_, + uint32 chainSlug_, + address token_, + uint256 nativeAmount_, + uint256 creditAmount_ + ) external payable onlyWatcher { + if (creditAmount_ + nativeAmount_ != msg.value) revert InvalidAmount(); + + UserCredits storage userCredit = userCredits[depositTo_]; + userCredit.totalCredits += creditAmount_; + tokenPoolBalances[chainSlug_][token_] += creditAmount_; + payable(depositTo_).transfer(nativeAmount_); + + emit CreditsDeposited(chainSlug_, depositTo_, token_, creditAmount_); + } + + function wrap() external payable { + UserCredits storage userCredit = userCredits[msg.sender]; + userCredit.totalCredits += msg.value; + emit CreditsWrapped(msg.sender, msg.value); + } + + function unwrap(uint256 amount_) external { + UserCredits storage userCredit = userCredits[msg.sender]; + if (userCredit.totalCredits < amount_) revert InsufficientCreditsAvailable(); + userCredit.totalCredits -= amount_; + + // todo: if contract balance not enough, take from our pool? + if (address(this).balance < amount_) revert InsufficientBalance(); + payable(msg.sender).transfer(amount_); + + emit CreditsUnwrapped(msg.sender, amount_); + } + + /// @notice Returns available (unblocked) credits for a gateway + /// @param consumeFrom_ The app gateway address + /// @return The available credit amount + function getAvailableCredits(address consumeFrom_) public view returns (uint256) { + UserCredits memory userCredit = userCredits[consumeFrom_]; + return userCredit.totalCredits - userCredit.blockedCredits; + } + + /// @notice Checks if the user has enough credits + /// @param consumeFrom_ The app gateway address + /// @param appGateway_ The app gateway address + /// @param amount_ The amount + /// @return True if the user has enough credits, false otherwise + function isUserCreditsEnough( + address consumeFrom_, + address appGateway_, + uint256 amount_ + ) external view returns (bool) { + // If consumeFrom is not appGateway, check if it is whitelisted + if (consumeFrom_ != appGateway_ && !isAppGatewayWhitelisted[consumeFrom_][appGateway_]) + revert AppGatewayNotWhitelisted(); + return getAvailableCredits(consumeFrom_) >= amount_; + } + + function whitelistAppGatewayWithSignature( + bytes memory feeApprovalData_ + ) external returns (address consumeFrom, address appGateway, bool isApproved) { + return _processFeeApprovalData(feeApprovalData_); + } + + /// @notice Whitelists multiple app gateways for the caller + /// @param params_ Array of app gateway addresses to whitelist + function whitelistAppGateways(AppGatewayWhitelistParams[] calldata params_) external { + for (uint256 i = 0; i < params_.length; i++) { + isAppGatewayWhitelisted[msg.sender][params_[i].appGateway] = params_[i].isApproved; + } + } + + function _processFeeApprovalData( + bytes memory feeApprovalData_ + ) internal returns (address, address, bool) { + (address consumeFrom, address appGateway, bool isApproved, bytes memory signature_) = abi + .decode(feeApprovalData_, (address, address, bool, bytes)); + + if (signature_.length == 0) { + // If no signature, consumeFrom is appGateway + return (appGateway, appGateway, isApproved); + } + bytes32 digest = keccak256( + abi.encode( + address(this), + evmxSlug, + consumeFrom, + appGateway, + userNonce[consumeFrom], + isApproved + ) + ); + if (_recoverSigner(digest, signature_) != consumeFrom) revert InvalidUserSignature(); + isAppGatewayWhitelisted[consumeFrom][appGateway] = isApproved; + userNonce[consumeFrom]++; + + return (consumeFrom, appGateway, isApproved); + } + + /// @notice Withdraws funds to a specified receiver + /// @dev This function is used to withdraw fees from the fees plug + /// @param originAppGatewayOrUser_ The address of the app gateway + /// @param chainSlug_ The chain identifier + /// @param token_ The address of the token + /// @param amount_ The amount of tokens to withdraw + /// @param receiver_ The address of the receiver + function withdrawCredits( + address originAppGatewayOrUser_, + uint32 chainSlug_, + address token_, + uint256 amount_, + uint256 maxFees_, + address receiver_ + ) public { + if (msg.sender != address(deliveryHelper__())) originAppGatewayOrUser_ = msg.sender; + address source = _getCoreAppGateway(originAppGatewayOrUser_); + + // Check if amount is available in fees plug + uint256 availableAmount = getAvailableCredits(source); + if (availableAmount < amount_) revert InsufficientCreditsAvailable(); + + _useAvailableUserCredits(source, amount_); + tokenPoolBalances[chainSlug_][token_] -= amount_; + + // Add it to the queue and submit request + _createRequest( + chainSlug_, + msg.sender, + maxFees_, + abi.encodeCall(IFeesPlug.withdrawFees, (token_, receiver_, amount_)) + ); + } + + function _createRequest( + uint32 chainSlug_, + address consumeFrom_, + uint256 maxFees_, + bytes memory payload_ + ) internal { + QueueParams memory queueParams = QueueParams({ + overrideParams: OverrideParams({ + isPlug: IsPlug.NO, + callType: WRITE, + isParallelCall: Parallel.OFF, + gasLimit: 10000000, + value: 0, + readAtBlockNumber: 0, + writeFinality: WriteFinality.LOW, + delayInSeconds: 0 + }), + transaction: Transaction({ + chainSlug: chainSlug_, + target: _getFeesPlugAddress(chainSlug_), + payload: payload_ + }), + asyncPromise: address(0), + switchboardType: sbType + }); + + // queue and create request + watcherPrecompile__().queueAndRequest( + queueParams, + maxFees_, + address(0), + consumeFrom_, + bytes("") + ); + } + + /// @notice hook called by watcher precompile when request is finished + function onRequestComplete(uint40 requestCount_, bytes memory) external {} + + function _getFeesPlugAddress(uint32 chainSlug_) internal view returns (address) { + return watcherPrecompileConfig().feesPlug(chainSlug_); + } + + function _recoverSigner( + bytes32 digest_, + bytes memory signature_ + ) internal view returns (address signer) { + bytes32 digest = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", digest_)); + // recovered signer is checked for the valid roles later + signer = ECDSA.recover(digest, signature_); + } +} From eb2e9674aebb3b4c0f58fba2628796d0961e72b8 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Fri, 16 May 2025 15:24:17 +0530 Subject: [PATCH 020/130] fix: lint --- .../evmx/app-gateways/AuctionManager.sol | 87 +++++++++++------- contracts/evmx/interfaces/IWatcher.sol | 7 +- contracts/evmx/watcher/Trigger.sol | 92 ++++++++----------- contracts/evmx/watcher/Watcher.sol | 72 +++++++++++---- 4 files changed, 146 insertions(+), 112 deletions(-) diff --git a/contracts/evmx/app-gateways/AuctionManager.sol b/contracts/evmx/app-gateways/AuctionManager.sol index a872043d..734a0e66 100644 --- a/contracts/evmx/app-gateways/AuctionManager.sol +++ b/contracts/evmx/app-gateways/AuctionManager.sol @@ -123,7 +123,12 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, // end the auction if the no auction end delay if (auctionEndDelaySeconds > 0) { _startAuction(requestCount_); - _createRequest(auctionEndDelaySeconds, scheduleFees_, transmitter, abi.encodeWithSelector(this.endAuction.selector, requestCount_, scheduleFees_)); + _createRequest( + auctionEndDelaySeconds, + scheduleFees_, + transmitter, + abi.encodeWithSelector(this.endAuction.selector, requestCount_, scheduleFees_) + ); } else { _endAuction(requestCount_, scheduleFees_); } @@ -141,7 +146,10 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, /// @notice Ends an auction /// @param requestCount_ The ID of the auction - function endAuction(uint40 requestCount_, uint256 scheduleFees_) external onlyWatcherPrecompile { + function endAuction( + uint40 requestCount_, + uint256 scheduleFees_ + ) external onlyWatcherPrecompile { if (auctionClosed[requestCount_]) return; _endAuction(requestCount_, scheduleFees_); } @@ -163,7 +171,12 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, // set the timeout for the bid expiration // useful in case a transmitter did bid but did not execute payloads - _createRequest(bidTimeout, scheduleFees_, winningBid.transmitter, abi.encodeWithSelector(this.expireBid.selector, requestCount_)); + _createRequest( + bidTimeout, + scheduleFees_, + winningBid.transmitter, + abi.encodeWithSelector(this.expireBid.selector, requestCount_) + ); // todo: merge them and create a single function call // start the request processing, it will queue the request @@ -185,45 +198,55 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, RequestParams memory requestParams = _getRequestParams(requestCount_); // if executed, bid is not expired - if (requestParams.requestTrackingParams.payloadsRemaining == 0 || requestParams.requestTrackingParams.isRequestCancelled) return; - + if ( + requestParams.requestTrackingParams.payloadsRemaining == 0 || + requestParams.requestTrackingParams.isRequestCancelled + ) return; + delete winningBids[requestCount_]; auctionClosed[requestCount_] = false; reAuctionCount[requestCount_]++; // todo: unblock credits by calling watcher for updating transmitter to addr(0) // feesManager__().unblockCredits(requestCount_); - + emit AuctionRestarted(requestCount_); } - function _createRequest(uint256 delayInSeconds_, uint256 maxFees_, address consumeFrom_, bytes memory payload_) internal { + function _createRequest( + uint256 delayInSeconds_, + uint256 maxFees_, + address consumeFrom_, + bytes memory payload_ + ) internal { QueueParams memory queueParams = QueueParams({ - overrideParams: OverrideParams({ - overrideParams.isParallelCall = Parallel.OFF; - gasLimit: 0, - value: 0, - readAtBlockNumber: 0, - writeFinality: WriteFinality.LOW, - delayInSeconds: delayInSeconds_ - }), - transaction: Transaction({ - chainSlug: evmxSlug, - target: address(this), - payload: payload_ - }), - asyncPromise: address(0), - switchboardType: sbType - }); - - // queue and create request - watcherPrecompile__().queueAndRequest( - queueParams, - maxFees_, - address(this), - consumeFrom_, - bytes("") - ); + overrideParams: OverrideParams({ + isPlug: IsPlug.NO, + callType: CallType.WRITE, + isParallelCall: Parallel.OFF, + gasLimit: 0, + value: 0, + readAtBlockNumber: 0, + writeFinality: WriteFinality.LOW, + delayInSeconds: delayInSeconds_ + }), + transaction: Transaction({ + chainSlug: evmxSlug, + target: address(this), + payload: payload_ + }), + asyncPromise: address(0), + switchboardType: sbType + }); + + // queue and create request + watcherPrecompile__().queueAndRequest( + queueParams, + maxFees_, + address(this), + consumeFrom_, + bytes("") + ); } /// @notice Returns the quoted transmitter fees for a request diff --git a/contracts/evmx/interfaces/IWatcher.sol b/contracts/evmx/interfaces/IWatcher.sol index 57d20cb9..22fa5d64 100644 --- a/contracts/evmx/interfaces/IWatcher.sol +++ b/contracts/evmx/interfaces/IWatcher.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import {DigestParams, ResolvedPromises, PayloadParams, TriggerParams, PayloadSubmitParams, RequestParams} from "../../utils/common/Structs.sol"; +import {PayloadParams, RequestParams, QueueParams, Bid} from "../../utils/common/Structs.sol"; /// @title IWatcher /// @notice Interface for the Watcher Precompile system that handles payload verification and execution @@ -116,7 +116,7 @@ interface IWatcher { uint256 maxFees, address auctionManager, address consumeFrom, - bytes onCompleteData + bytes calldata onCompleteData ) external returns (uint40 requestCount); // { @@ -188,10 +188,9 @@ interface IWatcher { function cancelRequest(uint40 requestCount) external; // settleFees on FM - function getMaxFees(uint40 requestCount) external view returns (uint256); function getCurrentRequestCount() external view returns (uint40); - function nextRequestCount() external view returns (uint40); + function getRequestParams(uint40 requestCount) external view returns (RequestParams memory); } diff --git a/contracts/evmx/watcher/Trigger.sol b/contracts/evmx/watcher/Trigger.sol index 9371d7c7..d9898d93 100644 --- a/contracts/evmx/watcher/Trigger.sol +++ b/contracts/evmx/watcher/Trigger.sol @@ -2,85 +2,65 @@ pragma solidity ^0.8.21; import {TriggerParams} from "../../utils/common/Structs.sol"; +import {InvalidCallerTriggered, AppGatewayAlreadyCalled} from "../../utils/common/Errors.sol"; + +import "./WatcherBase.sol"; +import "../helpers/AddressResolverUtil.sol"; /// @title Trigger /// @notice Contract that handles trigger validation and execution logic /// @dev This contract interacts with the WatcherPrecompileStorage for storage access -contract Trigger { - // The address of the WatcherPrecompileStorage contract - address public watcherStorage; - +contract Trigger is WatcherBase, AddressResolverUtil { /// @notice stores temporary address of the app gateway caller from a chain address public appGatewayCaller; - // slot 57 + /// @notice Stores the trigger fees + uint256 public triggerFees; + /// @notice Mapping to store if appGateway has been called with trigger from on-chain Inbox /// @dev Maps call ID to boolean indicating if the appGateway has been called /// @dev callId => bool mapping(bytes32 => bool) public appGatewayCalled; - // Only WatcherPrecompileStorage can call functions - modifier onlyWatcherStorage() { - require(msg.sender == watcherStorage, "Only WatcherStorage can call"); - _; - } - - /// @notice Sets the WatcherPrecompileStorage address - /// @param watcherStorage_ The address of the WatcherPrecompileStorage contract - constructor(address watcherStorage_) { - watcherStorage = watcherStorage_; - } + /// @notice Sets the Watcher address + /// @param watcher_ The address of the WatcherPrecompileStorage contract + constructor(address watcher_) WatcherBase(watcher_) {} - /// @notice Updates the WatcherPrecompileStorage address - /// @param watcherStorage_ The new address of the WatcherPrecompileStorage contract - function setWatcherStorage(address watcherStorage_) external onlyWatcherStorage { - watcherStorage = watcherStorage_; + /// @notice Sets the trigger fees + /// @param triggerFees_ The amount of fees to set + function setTriggerFees(uint256 triggerFees_) external onlyWatcher { + triggerFees = triggerFees_; } /// @notice Calls app gateways with the specified parameters /// @param params_ Array of call from chain parameters - /// @param signatureNonce_ The nonce of the signature - /// @param signature_ The signature of the watcher /// @dev This function calls app gateways with the specified parameters - /// @dev It verifies that the signature is valid and that the app gateway hasn't been called yet - function callAppGateways( - TriggerParams[] memory params_, - uint256 signatureNonce_, - bytes memory signature_ - ) external onlyWatcherStorage { - for (uint256 i = 0; i < params_.length; i++) { - if (appGatewayCalled[params_[i].triggerId]) revert AppGatewayAlreadyCalled(); + function callAppGateways(TriggerParams memory params_) external onlyWatcher { + if (appGatewayCalled[params_.triggerId]) revert AppGatewayAlreadyCalled(); - address appGateway = WatcherIdUtils.decodeAppGatewayId(params_[i].appGatewayId); - if ( - !watcherPrecompileConfig__.isValidPlug( - appGateway, - params_[i].chainSlug, - params_[i].plug - ) - ) revert InvalidCallerTriggered(); + address appGateway = WatcherIdUtils.decodeAppGatewayId(params_.appGatewayId); + if (!watcherPrecompileConfig__.isValidPlug(appGateway, params_.chainSlug, params_.plug)) + revert InvalidCallerTriggered(); - feesManager__().assignWatcherPrecompileCreditsFromAddress( - watcherPrecompileLimits__.callBackFees(), - appGateway - ); + feesManager__().assignWatcherPrecompileCreditsFromAddress(triggerFees, appGateway); - appGatewayCaller = appGateway; - appGatewayCalled[params_[i].triggerId] = true; + // todo: store and update in watcher contract + // appGatewayCaller = appGateway; - (bool success, , ) = appGateway.tryCall( - 0, - gasleft(), - 0, // setting max_copy_bytes to 0 as not using returnData right now - params_[i].payload - ); - if (!success) { - emit AppGatewayCallFailed(params_[i].triggerId); - } else { - emit CalledAppGateway(params_[i].triggerId); - } + appGatewayCalled[params_.triggerId] = true; + (bool success, , ) = appGateway.tryCall( + 0, + gasleft(), + 0, // setting max_copy_bytes to 0 as not using returnData right now + params_.payload + ); + if (!success) { + emit AppGatewayCallFailed(params_.triggerId); + } else { + emit CalledAppGateway(params_.triggerId); } - appGatewayCaller = address(0); + // todo: store and update in watcher contract + // appGatewayCaller = address(0); } } diff --git a/contracts/evmx/watcher/Watcher.sol b/contracts/evmx/watcher/Watcher.sol index 435d3575..5c9dd149 100644 --- a/contracts/evmx/watcher/Watcher.sol +++ b/contracts/evmx/watcher/Watcher.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.21; import "../interfaces/IWatcher.sol"; import {InvalidCallerTriggered, TimeoutDelayTooLarge, TimeoutAlreadyResolved, InvalidInboxCaller, ResolvingTimeoutTooEarly, CallFailed, AppGatewayAlreadyCalled, InvalidWatcherSignature, NonceUsed, RequestAlreadyExecuted} from "../../utils/common/Errors.sol"; -import {ResolvedPromises, AppGatewayConfig, LimitParams, WriteFinality, UpdateLimitParams, PlugConfig, DigestParams, TimeoutRequest, QueuePayloadParams, PayloadParams, RequestParams, RequestMetadata} from "../../utils/common/Structs.sol"; +import {ResolvedPromises, AppGatewayConfig, LimitParams, WriteFinality, UpdateLimitParams, PlugConfig, DigestParams, TimeoutRequest, QueueParams, PayloadParams, RequestParams} from "../../utils/common/Structs.sol"; /// @title WatcherStorage /// @notice Storage contract for the WatcherPrecompile system @@ -37,8 +37,7 @@ abstract contract WatcherStorage is IWatcher { mapping(uint40 => RequestParams) public requests; /// @notice The queue of payloads - QueueParams[] public queue; - + QueueParams[] public payloadQueue; address public latestAsyncPromise; address public appGatewayTemp; @@ -50,20 +49,21 @@ abstract contract WatcherStorage is IWatcher { } contract Watcher is WatcherStorage { + IRequestHandler public requestHandler__; + IConfigManager public configManager__; + IPromiseResolver public promiseResolver__; + IAddressResolver public addressResolver__; + constructor( address requestHandler_, address configManager_, - address trigger_, - address precompileFeesManager_, address promiseResolver_, address addressResolver_ ) { - requestHandler = requestHandler_; - configManager = configManager_; - trigger = trigger_; - precompileFeesManager = precompileFeesManager_; - promiseResolver = promiseResolver_; - addressResolver = addressResolver_; + requestHandler__ = requestHandler_; + configManager__ = configManager_; + promiseResolver__ = promiseResolver_; + addressResolver__ = addressResolver_; } /// @notice Clears the call parameters array @@ -71,6 +71,17 @@ contract Watcher is WatcherStorage { delete queue; } + function queueAndRequest( + QueueParams memory queue_, + uint256 maxFees, + address auctionManager, + address consumeFrom, + bytes onCompleteData + ) internal returns (uint40, address[] memory) { + _queue(queue_, msg.sender); + return _submitRequest(maxFees, auctionManager, consumeFrom, onCompleteData); + } + // todo: delegate call? // todo: check app gateway input auth /// @notice Queues a new payload @@ -79,6 +90,13 @@ contract Watcher is WatcherStorage { QueueParams memory queue_, address appGateway_ ) external returns (address, uint40) { + return _queue(queue_, appGateway_); + } + + function _queue( + QueueParams memory queue_, + address appGateway_ + ) internal returns (address, uint40) { address coreAppGateway = getCoreAppGateway(appGateway_); // Deploy a new async promise contract. if (appGatewayTemp != address(0)) @@ -90,14 +108,15 @@ contract Watcher is WatcherStorage { queue_.asyncPromise = latestAsyncPromise; // Add the promise to the queue. - queue.push(queue_); + payloadQueue.push(queue_); // return the promise and request count - return (latestAsyncPromise, requestHandler.nextRequestCount()); + return (latestAsyncPromise, requestHandler__.nextRequestCount()); } function then(bytes4 selector_, bytes memory data_) external { if (latestAsyncPromise == address(0)) revert NoAsyncPromiseFound(); - if (latestRequestCount != requestHandler.nextRequestCount()) revert RequestCountMismatch(); + if (latestRequestCount != requestHandler__.nextRequestCount()) + revert RequestCountMismatch(); address latestAsyncPromise_ = latestAsyncPromise; latestAsyncPromise = address(0); @@ -111,15 +130,24 @@ contract Watcher is WatcherStorage { address auctionManager, address consumeFrom, bytes onCompleteData - ) external returns (uint40 requestCount, address[] memory promiseList) { + ) external returns (uint40, address[] memory) { + return _submitRequest(maxFees, auctionManager, consumeFrom, onCompleteData); + } + + function _submitRequest( + uint256 maxFees, + address auctionManager, + address consumeFrom, + bytes onCompleteData + ) internal returns (uint40 requestCount, address[] memory promiseList) { if (getCoreAppGateway(msg.sender) != appGatewayTemp) revert InvalidAppGateways(); - (requestCount, promiseList) = requestHandler.submitRequest( + (requestCount, promiseList) = requestHandler__.submitRequest( maxFees, auctionManager, consumeFrom, msg.sender, - queue, + payloadQueue, onCompleteData ); clearQueue(); @@ -139,18 +167,22 @@ contract Watcher is WatcherStorage { /// @param expiryTime_ The expiry time in seconds /// @dev This function sets the expiry time for payload execution /// @dev Only callable by the contract owner - function setExpiryTime(uint256 expiryTime_) external onlyOwner { + function setExpiryTime(uint256 expiryTime_) external { expiryTime = expiryTime_; emit ExpiryTimeSet(expiryTime_); } + function getRequestParams(uint40 requestCount_) external view returns (RequestParams memory) { + return requests[requestCount_]; + } + // all function from watcher requiring signature function watcherMultiCall( address[] memory contracts, bytes[] memory data_, uint256[] memory nonces_, bytes[] memory signatures_ - ) external { + ) external payable { for (uint40 i = 0; i < contracts.length; i++) { if (contracts[i] == address(0)) revert InvalidContract(); if (data_[i].length == 0) revert InvalidData(); @@ -162,7 +194,7 @@ contract Watcher is WatcherStorage { revert InvalidSignature(); // call the contract - (bool success, bytes memory result) = contracts[i].call(data_[i]); + (bool success, bytes memory result) = contracts[i].call{value: msg.value}(data_[i]); if (!success) revert CallFailed(); } } From fa4ae54daa30300ba673c157e0e2c64ce605b737 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Mon, 19 May 2025 23:24:42 +0530 Subject: [PATCH 021/130] rm: old contracts --- contracts/app-gateway/DeliveryHelper.sol | 88 ----------- contracts/core/RequestHandler.sol | 52 ------- contracts/core/WatcherPrecompileCore.sol | 180 ----------------------- 3 files changed, 320 deletions(-) delete mode 100644 contracts/app-gateway/DeliveryHelper.sol delete mode 100644 contracts/core/RequestHandler.sol delete mode 100644 contracts/core/WatcherPrecompileCore.sol diff --git a/contracts/app-gateway/DeliveryHelper.sol b/contracts/app-gateway/DeliveryHelper.sol deleted file mode 100644 index c1c5a667..00000000 --- a/contracts/app-gateway/DeliveryHelper.sol +++ /dev/null @@ -1,88 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -pragma solidity ^0.8.21; - -import "./FeesHelpers.sol"; - -/// @title DeliveryHelper -/// @notice Contract for managing payload delivery -contract DeliveryHelper is FeesHelpers { - /// @notice Calls the watcher precompile to start processing a request - /// @dev If a transmitter was already assigned, it updates the transmitter in watcher precompile too - /// @param requestCount_ The ID of the request - /// @param winningBid_ The winning bid - function startRequestProcessing( - uint40 requestCount_, - Bid memory winningBid_ - ) external onlyAuctionManager(requestCount_) { - if (requests[requestCount_].onlyReadRequests) revert ReadOnlyRequests(); - if (winningBid_.transmitter == address(0)) revert InvalidTransmitter(); - - RequestMetadata storage requestMetadata_ = requests[requestCount_]; - // if a transmitter was already assigned, it means the request was restarted - bool isRestarted = requestMetadata_.winningBid.transmitter != address(0); - requestMetadata_.winningBid = winningBid_; - - if (!isRestarted) { - watcherPrecompile__().startProcessingRequest(requestCount_, winningBid_.transmitter); - } else { - watcherPrecompile__().updateTransmitter(requestCount_, winningBid_.transmitter); - } - } - - /// @notice Finishes the request processing by assigning fees and calling the on complete hook on app gateway - /// @param requestCount_ The ID of the request - function finishRequest(uint40 requestCount_) external onlyWatcherPrecompile { - RequestMetadata storage requestMetadata_ = requests[requestCount_]; - - // todo: move it to watcher precompile - if (requestMetadata_.winningBid.transmitter != address(0)) - feesManager__().unblockAndAssignCredits( - requestCount_, - requestMetadata_.winningBid.transmitter - ); - - if (requestMetadata_.appGateway.code.length > 0) { - IAppGateway(requestMetadata_.appGateway).onRequestComplete( - requestCount_, - requestMetadata_.onCompleteData - ); - } - } - - /// @notice Cancels a request and settles the fees - /// @dev if no transmitter was assigned, fees is unblocked to app gateway - /// @dev Only app gateway can call this function - /// @param requestCount_ The ID of the request - function cancelRequest(uint40 requestCount_) external { - if (msg.sender != requests[requestCount_].appGateway) { - revert OnlyAppGateway(); - } - - _settleFees(requestCount_); - watcherPrecompile__().cancelRequest(requestCount_); - emit RequestCancelled(requestCount_); - } - - /// @notice For request reverts, settles the fees - /// @param requestCount_ The ID of the request - function handleRequestReverts(uint40 requestCount_) external onlyWatcherPrecompile { - _settleFees(requestCount_); - } - - /// @notice Settles the fees for a request - /// @dev If a transmitter was already assigned, it unblocks and assigns fees to the transmitter - /// @dev If no transmitter was assigned, it unblocks fees to the app gateway - /// @param requestCount_ The ID of the request - function _settleFees(uint40 requestCount_) internal { - // If the request has a winning bid, ie. transmitter already assigned, unblock and assign fees - if (requests[requestCount_].winningBid.transmitter != address(0)) { - feesManager__().unblockAndAssignCredits( - requestCount_, - requests[requestCount_].winningBid.transmitter - ); - } else { - // If the request has no winning bid, ie. transmitter not assigned, unblock fees - feesManager__().unblockCredits(requestCount_); - } - } -} diff --git a/contracts/core/RequestHandler.sol b/contracts/core/RequestHandler.sol deleted file mode 100644 index 86b93c76..00000000 --- a/contracts/core/RequestHandler.sol +++ /dev/null @@ -1,52 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -pragma solidity ^0.8.21; - -import "./WatcherPrecompileCore.sol"; - -/// @title RequestHandler -/// @notice Contract that handles request submission and processing -/// @dev This contract extends WatcherPrecompileCore to provide request handling functionality -/// @dev It manages the submission of payload requests and their processing -abstract contract RequestHandler is WatcherPrecompileCore { - /// @notice Starts processing a request with a specified transmitter - /// @param requestCount The request count to start processing - /// @param transmitter_ The winning bid, contains fees, transmitter and extra data - /// @dev This function initiates the processing of a request by a transmitter - /// @dev It verifies that the caller is the middleware and that the request hasn't been started yet - function startProcessingRequest(uint40 requestCount, address transmitter_) public { - RequestParams storage r = requestParams[requestCount]; - if (r.transmitter != address(0)) revert AlreadyStarted(); - if (r.currentBatchPayloadsLeft > 0) revert AlreadyStarted(); - - uint40 batchCount = r.payloadParamsArray[0].payloadHeader.getBatchCount(); - r.transmitter = transmitter_; - r.currentBatch = batchCount; - - _processBatch(requestCount, batchCount); - } - - /// @notice Processes a batch of payloads for a request - /// @param requestCount_ The request count to process - /// @param batchCount_ The batch count to process - /// @dev This function processes all payloads in a batch, either finalizing them or querying them - /// @dev It skips payloads that have already been executed - function _processBatch(uint40 requestCount_, uint40 batchCount_) internal { - RequestParams storage r = requestParams[requestCount_]; - PayloadParams[] memory payloadParamsArray = _getBatch(batchCount_); - if (r.isRequestCancelled) revert RequestCancelled(); - - uint256 totalPayloads = 0; - for (uint40 i = 0; i < payloadParamsArray.length; i++) { - if (isPromiseExecuted[payloadParamsArray[i].payloadId]) continue; - totalPayloads++; - - if (payloadParamsArray[i].payloadHeader.getCallType() != CallType.READ) { - _finalize(payloadParamsArray[i], r.transmitter); - } else { - _query(payloadParamsArray[i]); - } - } - - r.currentBatchPayloadsLeft = totalPayloads; - } -} diff --git a/contracts/core/WatcherPrecompileCore.sol b/contracts/core/WatcherPrecompileCore.sol deleted file mode 100644 index 74b5b4d3..00000000 --- a/contracts/core/WatcherPrecompileCore.sol +++ /dev/null @@ -1,180 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -pragma solidity ^0.8.21; - -import {ECDSA} from "solady/utils/ECDSA.sol"; -import {Ownable} from "solady/auth/Ownable.sol"; - -import "solady/utils/Initializable.sol"; -import {AddressResolverUtil} from "../../AddressResolverUtil.sol"; -import {IFeesManager} from "../../interfaces/IFeesManager.sol"; -import "./WatcherIdUtils.sol"; -import "./WatcherPrecompileStorage.sol"; - -/// @title WatcherPrecompileCore -/// @notice Core functionality for the WatcherPrecompile system -/// @dev This contract implements the core functionality for payload verification, execution, and app configurations -/// @dev It is inherited by WatcherPrecompile and provides the base implementation for request handling -abstract contract WatcherPrecompileCore is - IWatcher, - WatcherPrecompileStorage, - Initializable, - Ownable, - AddressResolverUtil -{ - using PayloadHeaderDecoder for bytes32; - - // slots [216-265] reserved for gap - uint256[50] _core_gap; - - // ================== Timeout functions ================== - - /// @notice Sets a timeout for a payload execution on app gateway - /// @return timeoutId The unique identifier for the timeout request - function _setTimeout( - uint256 delayInSeconds_, - bytes memory payload_ - ) internal returns (bytes32 timeoutId) { - if (delayInSeconds_ > maxTimeoutDelayInSeconds) revert TimeoutDelayTooLarge(); - _consumeCallbackFeesFromAddress(watcherPrecompileLimits__.timeoutFees(), msg.sender); - - uint256 executeAt = block.timestamp + delayInSeconds_; - timeoutId = _encodeTimeoutId(); - - timeoutRequests[timeoutId].target = msg.sender; - timeoutRequests[timeoutId].delayInSeconds = delayInSeconds_; - timeoutRequests[timeoutId].executeAt = executeAt; - timeoutRequests[timeoutId].payload = payload_; - - // emits event for watcher to track timeout and resolve when timeout is reached - emit TimeoutRequested(timeoutId, msg.sender, payload_, executeAt); - } - - /// @notice Finalizes a payload request and requests the watcher to release the proofs - /// @param params_ The payload parameters to be finalized - /// @param transmitter_ The address of the transmitter - /// @return digest The digest hash of the finalized payload - /// @dev This function verifies the app gateway configuration and creates a digest for the payload - function _finalize( - PayloadParams memory params_, - address transmitter_ - ) internal returns (bytes32 digest) { - uint256 deadline = block.timestamp + expiryTime; - payloads[params_.payloadId].deadline = deadline; - payloads[params_.payloadId].finalizedTransmitter = transmitter_; - - bytes32 prevDigestsHash = _getPreviousDigestsHash(params_.payloadHeader.getBatchCount()); - payloads[params_.payloadId].prevDigestsHash = prevDigestsHash; - - // Construct parameters for digest calculation - DigestParams memory digestParams_ = DigestParams( - watcherPrecompileConfig__.sockets(chainSlug), - transmitter_, - params_.payloadId, - deadline, - params_.payloadHeader.getCallType(), - params_.gasLimit, - params_.value, - params_.payload, - params_.target, - WatcherIdUtils.encodeAppGatewayId(params_.appGateway), - prevDigestsHash - ); - - // Calculate digest from payload parameters - digest = getDigest(digestParams_); - emit FinalizeRequested(digest, payloads[params_.payloadId]); - } - - // ================== Query functions ================== - - /// @notice Creates a new query request - /// @param params_ The payload parameters for the query - /// @dev This function sets up a query request and emits a QueryRequested event - function _query(PayloadParams memory params_) internal { - payloads[params_.payloadId].prevDigestsHash = _getPreviousDigestsHash( - params_.payloadHeader.getBatchCount() - ); - } - - // ================== Helper functions ================== - - /// @notice Calculates the digest hash of payload parameters - /// @dev extraData is empty for now, not needed for this EVMx - /// @param params_ The payload parameters to calculate the digest for - /// @return digest The calculated digest hash - /// @dev This function creates a keccak256 hash of the payload parameters - function getDigest(DigestParams memory params_) public pure returns (bytes32 digest) { - digest = keccak256( - abi.encode( - params_.socket, - params_.transmitter, - params_.payloadId, - params_.deadline, - params_.callType, - params_.gasLimit, - params_.value, - params_.payload, - params_.target, - params_.appGatewayId, - params_.prevDigestsHash, - bytes("") - ) - ); - } - - /// @notice Gets the hash of previous batch digests - /// @param batchCount_ The batch count to get the previous digests hash - /// @return The hash of all digests in the previous batch - function _getPreviousDigestsHash(uint40 batchCount_) internal view returns (bytes32) { - bytes32[] memory payloadIds = batchPayloadIds[batchCount_]; - bytes32 prevDigestsHash = bytes32(0); - - for (uint40 i = 0; i < payloadIds.length; i++) { - PayloadParams memory p = payloads[payloadIds[i]]; - DigestParams memory digestParams = DigestParams( - watcherPrecompileConfig__.sockets(p.payloadHeader.getChainSlug()), - p.finalizedTransmitter, - p.payloadId, - p.deadline, - p.payloadHeader.getCallType(), - p.gasLimit, - p.value, - p.payload, - p.target, - WatcherIdUtils.encodeAppGatewayId(p.appGateway), - p.prevDigestsHash - ); - prevDigestsHash = keccak256(abi.encodePacked(prevDigestsHash, getDigest(digestParams))); - } - return prevDigestsHash; - } - - /// @notice Gets the batch of payload parameters for a given batch count - /// @param batchCount The batch count to get the payload parameters for - /// @return An array of PayloadParams for the given batch - /// @dev This function retrieves all payload parameters for a specific batch - function _getBatch(uint40 batchCount) internal view returns (PayloadParams[] memory) { - bytes32[] memory payloadIds = batchPayloadIds[batchCount]; - PayloadParams[] memory payloadParamsArray = new PayloadParams[](payloadIds.length); - - for (uint40 i = 0; i < payloadIds.length; i++) { - payloadParamsArray[i] = payloads[payloadIds[i]]; - } - return payloadParamsArray; - } - - function _consumeCallbackFeesFromRequestCount(uint256 fees_, uint40 requestCount_) internal { - // for callbacks in all precompiles - uint256 feesToConsume = fees_ + watcherPrecompileLimits__.callBackFees(); - feesManager__().assignWatcherPrecompileCreditsFromRequestCount( - feesToConsume, - requestCount_ - ); - } - - function _consumeCallbackFeesFromAddress(uint256 fees_, address consumeFrom_) internal { - // for callbacks in all precompiles - uint256 feesToConsume = fees_ + watcherPrecompileLimits__.callBackFees(); - feesManager__().assignWatcherPrecompileCreditsFromAddress(feesToConsume, consumeFrom_); - } -} From b87602f59770a7e33736ec14de933ca945ea2b58 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Mon, 19 May 2025 23:25:15 +0530 Subject: [PATCH 022/130] fix: fee manager changes --- contracts/evmx/fees/CreditUtils.sol | 40 ++++++---------------- contracts/evmx/fees/UserUtils.sol | 21 ++++++++++++ contracts/evmx/interfaces/IFeesManager.sol | 6 ++-- contracts/evmx/plugs/FeesPlug.sol | 2 +- 4 files changed, 35 insertions(+), 34 deletions(-) diff --git a/contracts/evmx/fees/CreditUtils.sol b/contracts/evmx/fees/CreditUtils.sol index c7734c76..f0f59406 100644 --- a/contracts/evmx/fees/CreditUtils.sol +++ b/contracts/evmx/fees/CreditUtils.sol @@ -52,11 +52,9 @@ abstract contract CreditUtils is UserUtils { /// @dev Only callable by delivery helper function blockCredits( uint40 requestCount_, - uint256 credits_, - address consumeFrom_ + address consumeFrom_, + uint256 credits_ ) external onlyWatcher { - // todo: check in watcher if AM is correct while starting process or updating transmitter - // Block fees if (getAvailableCredits(consumeFrom_) < credits_) revert InsufficientCreditsAvailable(); UserCredits storage userCredit = userCredits[consumeFrom_]; @@ -68,10 +66,10 @@ abstract contract CreditUtils is UserUtils { /// @notice Unblocks fees after successful execution and assigns them to the transmitter /// @param requestCount_ The async ID of the executed batch - /// @param consumeFor_ The address of the receiver + /// @param assignTo_ The address of the transmitter function unblockAndAssignCredits( uint40 requestCount_, - address consumeFor_ + address assignTo_ ) external override onlyWatcher { uint256 blockedCredits = requestCountCredits[requestCount_]; if (blockedCredits == 0) return; @@ -80,24 +78,14 @@ abstract contract CreditUtils is UserUtils { uint256 fees = requestParams.requestFeesDetails.maxFees; // Unblock fees from deposit - _useBlockedUserCredits(requestParams.consumeFrom, blockedCredits, fees); + _updateUserCredits(requestParams.consumeFrom, blockedCredits, fees); // Assign fees to transmitter - userCredits[consumeFor_].totalCredits += fees; + userCredits[assignTo_].totalCredits += fees; // Clean up storage delete requestCountCredits[requestCount_]; - emit CreditsUnblockedAndAssigned(requestCount_, consumeFor_, fees); - } - - function _useBlockedUserCredits( - address consumeFrom_, - uint256 toConsumeFromBlocked_, - uint256 toConsumeFromTotal_ - ) internal { - UserCredits storage userCredit = userCredits[consumeFrom_]; - userCredit.blockedCredits -= toConsumeFromBlocked_; - userCredit.totalCredits -= toConsumeFromTotal_; + emit CreditsUnblockedAndAssigned(requestCount_, assignTo_, fees); } function _useAvailableUserCredits(address consumeFrom_, uint256 toConsume_) internal { @@ -118,22 +106,14 @@ abstract contract CreditUtils is UserUtils { } function unblockCredits(uint40 requestCount_) external onlyWatcher { - RequestParams memory requestParams = _getRequestParams(requestCount_); - - // todo: check in watcher - // if (msg.sender != requestParams.auctionManager) revert InvalidCaller(); - + RequestParams memory r = _getRequestParams(requestCount_); uint256 blockedCredits = requestCountCredits[requestCount_]; if (blockedCredits == 0) return; // Unblock fees from deposit - _useBlockedUserCredits( - requestParams.requestFeesDetails.consumeFrom, - blockedCredits, - requestParams.requestFeesDetails.maxFees - ); + _updateUserCredits(r.requestFeesDetails.consumeFrom, blockedCredits, 0); delete requestCountCredits[requestCount_]; - emit CreditsUnblocked(requestCount_, requestParams.requestFeesDetails.consumeFrom); + emit CreditsUnblocked(requestCount_, r.requestFeesDetails.consumeFrom); } function _getRequestParams(uint40 requestCount_) internal view returns (RequestParams memory) { diff --git a/contracts/evmx/fees/UserUtils.sol b/contracts/evmx/fees/UserUtils.sol index af6519d8..c6694d1e 100644 --- a/contracts/evmx/fees/UserUtils.sol +++ b/contracts/evmx/fees/UserUtils.sol @@ -110,6 +110,27 @@ abstract contract UserUtils is FeesStorage, Initializable, Ownable, AddressResol return getAvailableCredits(consumeFrom_) >= amount_; } + function _updateUserCredits( + address consumeFrom_, + uint256 toConsumeFromBlocked_, + uint256 toConsumeFromTotal_ + ) internal { + UserCredits storage userCredit = userCredits[consumeFrom_]; + userCredit.blockedCredits -= toConsumeFromBlocked_; + userCredit.totalCredits -= toConsumeFromTotal_; + } + + // todo: if watcher, don't check whitelist + function transferCredits(address from_, address to_, uint256 amount_) external { + if (!isAppGatewayWhitelisted[from_][to_]) revert AppGatewayNotWhitelisted(); + + if (!isUserCreditsEnough(from_, to_, amount_)) revert InsufficientCreditsAvailable(); + userCredits[from_].totalCredits -= amount_; + userCredits[to_].totalCredits += amount_; + + emit CreditsTransferred(from_, to_, amount_); + } + function whitelistAppGatewayWithSignature( bytes memory feeApprovalData_ ) external returns (address consumeFrom, address appGateway, bool isApproved) { diff --git a/contracts/evmx/interfaces/IFeesManager.sol b/contracts/evmx/interfaces/IFeesManager.sol index f5fb68d3..af2e71a7 100644 --- a/contracts/evmx/interfaces/IFeesManager.sol +++ b/contracts/evmx/interfaces/IFeesManager.sol @@ -34,13 +34,13 @@ interface IFeesManager { ) external; // Fee settlement - // if addr(0) then settle to original user, onlyWatcherPrecompile can call + // if addr(0) then settle to original user, onlyWatcher can call function settleFees(uint40 requestId, address transmitter) external; - // onlyWatcherPrecompile, request's AM can call + // onlyWatcher, request's AM can call function blockCredits(uint40 requestId, address user, uint256 amount) external; - // onlyWatcherPrecompile, request's AM can call + // onlyWatcher, request's AM can call function unblockCredits(uint40 requestId, address user, uint256 amount) external; // msg sender should be user whitelisted app gateway diff --git a/contracts/evmx/plugs/FeesPlug.sol b/contracts/evmx/plugs/FeesPlug.sol index 8d7fa8a8..a10b5616 100644 --- a/contracts/evmx/plugs/FeesPlug.sol +++ b/contracts/evmx/plugs/FeesPlug.sol @@ -11,7 +11,7 @@ import "../../utils/RescueFundsLib.sol"; import {ETH_ADDRESS} from "../../utils/common/Constants.sol"; import {InvalidTokenAddress, FeesAlreadyPaid} from "../../utils/common/Errors.sol"; -/// @title FeesManager +/// @title FeesPlug /// @notice Contract for managing fees on a network /// @dev The amount deposited here is locked and updated in the EVMx for an app gateway /// @dev The fees are redeemed by the transmitters executing request or can be withdrawn by the owner From 46e3d2557f2d686ab4746e2e2c9afcf4111f1237 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Mon, 19 May 2025 23:25:30 +0530 Subject: [PATCH 023/130] fix: auction manager review --- .../evmx/app-gateways/AuctionManager.sol | 115 +++++++++--------- 1 file changed, 59 insertions(+), 56 deletions(-) diff --git a/contracts/evmx/app-gateways/AuctionManager.sol b/contracts/evmx/app-gateways/AuctionManager.sol index 734a0e66..90e48f24 100644 --- a/contracts/evmx/app-gateways/AuctionManager.sol +++ b/contracts/evmx/app-gateways/AuctionManager.sol @@ -12,6 +12,14 @@ import {AppGatewayBase} from "../base/AppGatewayBase.sol"; /// @title AuctionManagerStorage /// @notice Storage for the AuctionManager contract abstract contract AuctionManagerStorage is IAuctionManager { + enum AuctionStatus { + NOT_STARTED, + OPEN, + CLOSED, + RESTARTED, + EXPIRED + } + // slot 50 uint32 public evmxSlug; @@ -26,14 +34,12 @@ abstract contract AuctionManagerStorage is IAuctionManager { uint256 public auctionEndDelaySeconds; // slot 53 + /// @notice The winning bid for a request (requestCount => Bid) mapping(uint40 => Bid) public winningBids; // slot 54 - // requestCount => auction status - mapping(uint40 => bool) public override auctionClosed; - - // slot 55 - mapping(uint40 => bool) public override auctionStarted; + /// @notice The auction status for a request (requestCount => AuctionStatus) + mapping(uint40 => AuctionStatus) public override auctionStatus; // slot 56 mapping(uint40 => uint256) public reAuctionCount; @@ -52,6 +58,7 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, error MaxReAuctionCountReached(); constructor() { + // todo: evmx slug can be immutable and set here _disableInitializers(); // disable for implementation } @@ -94,11 +101,13 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, function bid( uint40 requestCount_, uint256 bidFees, - address scheduleFees_, bytes memory transmitterSignature, bytes memory extraData ) external { - if (auctionClosed[requestCount_]) revert AuctionClosed(); + if ( + auctionStatus[requestCount_] != AuctionStatus.OPEN && + auctionStatus[requestCount_] != AuctionStatus.RESTARTED + ) revert AuctionNotOpen(); // check if the transmitter is valid address transmitter = _recoverSigner( @@ -108,84 +117,73 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, if (!_hasRole(TRANSMITTER_ROLE, transmitter)) revert InvalidTransmitter(); // check if the bid is lower than the existing bid - if ( - winningBids[requestCount_].transmitter != address(0) && - bidFees >= winningBids[requestCount_].fee - ) revert LowerBidAlreadyExists(); + if (bidFees >= winningBids[requestCount_].fee && bidFees != 0) + revert LowerBidAlreadyExists(); - uint256 transmitterCredits = quotedTransmitterFees(requestCount_); + uint256 transmitterCredits = get(requestCount_); if (bidFees > transmitterCredits) revert BidExceedsMaxFees(); + deductScheduleFees( + transmitter, + winningBids[requestCount_].transmitter == address(0) + ? address(this) + : winningBids[requestCount_].transmitter + ); + // create a new bid Bid memory newBid = Bid({fee: bidFees, transmitter: transmitter, extraData: extraData}); winningBids[requestCount_] = newBid; // end the auction if the no auction end delay - if (auctionEndDelaySeconds > 0) { + if (auctionEndDelaySeconds > 0 && auctionStatus[requestCount_] != AuctionStatus.OPEN) { _startAuction(requestCount_); _createRequest( auctionEndDelaySeconds, - scheduleFees_, - transmitter, - abi.encodeWithSelector(this.endAuction.selector, requestCount_, scheduleFees_) + address(this), + abi.encodeWithSelector(this.endAuction.selector, requestCount_) ); } else { - _endAuction(requestCount_, scheduleFees_); + _endAuction(requestCount_); } emit BidPlaced(requestCount_, newBid); } function _startAuction(uint40 requestCount_) internal { - if (auctionClosed[requestCount_]) revert AuctionClosed(); - if (auctionStarted[requestCount_]) revert AuctionAlreadyStarted(); - - auctionStarted[requestCount_] = true; + if (auctionStatus[requestCount_] != AuctionStatus.OPEN) revert AuctionNotOpen(); + auctionStatus[requestCount_] = AuctionStatus.OPEN; emit AuctionStarted(requestCount_); } /// @notice Ends an auction /// @param requestCount_ The ID of the auction - function endAuction( - uint40 requestCount_, - uint256 scheduleFees_ - ) external onlyWatcherPrecompile { - if (auctionClosed[requestCount_]) return; - _endAuction(requestCount_, scheduleFees_); + function endAuction(uint40 requestCount_) external onlyWatcher { + if ( + auctionStatus[requestCount_] == AuctionStatus.CLOSED || + auctionStatus[requestCount_] == AuctionStatus.NOT_STARTED + ) return; + _endAuction(requestCount_); } - function _endAuction(uint40 requestCount_, uint256 scheduleFees_) internal { + function _endAuction(uint40 requestCount_) internal { // get the winning bid, if no transmitter is set, revert Bid memory winningBid = winningBids[requestCount_]; if (winningBid.transmitter == address(0)) revert InvalidTransmitter(); + auctionStatus[requestCount_] = AuctionStatus.CLOSED; - auctionClosed[requestCount_] = true; - RequestParams memory requestParams = _getRequestParams(requestCount_); - - // todo: block fees in watcher in startRequestProcessing - // feesManager__().blockCredits( - // requestMetadata.consumeFrom, - // winningBid.fee, - // requestCount_ - // ); - + // todo: might block the request processing if transmitter don't have enough balance + // not implementing this for now // set the timeout for the bid expiration // useful in case a transmitter did bid but did not execute payloads _createRequest( bidTimeout, - scheduleFees_, + deductScheduleFees(winningBid.transmitter, address(this)), winningBid.transmitter, abi.encodeWithSelector(this.expireBid.selector, requestCount_) ); - // todo: merge them and create a single function call // start the request processing, it will queue the request - if (requestParams.requestFeesDetails.bid.transmitter != address(0)) { - IWatcher(watcherPrecompile__()).updateTransmitter(requestCount_, winningBid); - } else { - IWatcher(watcherPrecompile__()).startRequestProcessing(requestCount_, winningBid); - } - + IWatcher(watcherPrecompile__()).assignTransmitter(requestCount_, winningBid); emit AuctionEnded(requestCount_, winningBid); } @@ -193,7 +191,7 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, /// @dev Auction can be restarted only for `maxReAuctionCount` times. /// @dev It also unblocks the fees from last transmitter to be assigned to the new winner. /// @param requestCount_ The request id - function expireBid(uint40 requestCount_) external onlyWatcherPrecompile { + function expireBid(uint40 requestCount_) external onlyWatcher { if (reAuctionCount[requestCount_] >= maxReAuctionCount) revert MaxReAuctionCountReached(); RequestParams memory requestParams = _getRequestParams(requestCount_); @@ -204,12 +202,13 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, ) return; delete winningBids[requestCount_]; - auctionClosed[requestCount_] = false; + auctionStatus[requestCount_] = AuctionStatus.RESTARTED; reAuctionCount[requestCount_]++; - // todo: unblock credits by calling watcher for updating transmitter to addr(0) - // feesManager__().unblockCredits(requestCount_); - + IWatcher(watcherPrecompile__()).assignTransmitter( + requestCount_, + Bid({fee: 0, transmitter: address(0), extraData: ""}) + ); emit AuctionRestarted(requestCount_); } @@ -222,7 +221,7 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, QueueParams memory queueParams = QueueParams({ overrideParams: OverrideParams({ isPlug: IsPlug.NO, - callType: CallType.WRITE, + callType: SCHEDULE, isParallelCall: Parallel.OFF, gasLimit: 0, value: 0, @@ -244,7 +243,7 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, queueParams, maxFees_, address(this), - consumeFrom_, + address(this), bytes("") ); } @@ -253,13 +252,17 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, /// @dev returns the max fees quoted by app gateway subtracting the watcher fees /// @param requestCount_ The request id /// @return The quoted transmitter fees - function quotedTransmitterFees(uint40 requestCount_) public view returns (uint256) { + function getMaxFees(uint40 requestCount_) internal view returns (uint256) { RequestParams memory requestParams = _getRequestParams(requestCount_); // check if the bid is for this auction manager if (requestParams.auctionManager != address(this)) revert InvalidBid(); // get the total fees required for the watcher precompile ops - return - requestParams.requestFeesDetails.maxFees - requestParams.requestFeesDetails.watcherFees; + return requestParams.requestFeesDetails.maxFees; + } + + function deductScheduleFees(address from_, address to_) internal returns (uint256 watcherFees) { + watcherFees = watcher__().getPrecompileFees(SCHEDULE); + feesManager__().transferCredits(from_, to_, watcherFees); } function _getRequestParams(uint40 requestCount_) internal view returns (RequestParams memory) { From 593379dbcf42dbc2394d1a5b6b62787d96ad2dfa Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Mon, 19 May 2025 23:26:53 +0530 Subject: [PATCH 024/130] fix: refactor --- .../evmx/helpers/AddressResolverUtil.sol | 4 +- contracts/evmx/helpers/Forwarder.sol | 1 - contracts/evmx/interfaces/IPrecompile.sol | 2 +- contracts/evmx/interfaces/IWatcher.sol | 48 +------------------ contracts/evmx/watcher/Configurations.sol | 6 +-- contracts/evmx/watcher/Watcher.sol | 25 ++-------- .../counter/CounterAppGateway.sol | 4 +- 7 files changed, 15 insertions(+), 75 deletions(-) diff --git a/contracts/evmx/helpers/AddressResolverUtil.sol b/contracts/evmx/helpers/AddressResolverUtil.sol index 736d5eb4..e1990623 100644 --- a/contracts/evmx/helpers/AddressResolverUtil.sol +++ b/contracts/evmx/helpers/AddressResolverUtil.sol @@ -18,13 +18,13 @@ abstract contract AddressResolverBase { uint256[50] __gap_resolver_util; /// @notice Error thrown when an invalid address attempts to call the Watcher only function - error OnlyWatcherPrecompile(); + error onlyWatcherAllowed(); /// @notice Restricts function access to the watcher precompile contract /// @dev Validates that msg.sender matches the registered watcher precompile address modifier onlyWatcher() { if (msg.sender != address(addressResolver__.watcherPrecompile__())) { - revert OnlyWatcherPrecompile(); + revert onlyWatcherAllowed(); } _; diff --git a/contracts/evmx/helpers/Forwarder.sol b/contracts/evmx/helpers/Forwarder.sol index f22fd364..3d1a26b8 100644 --- a/contracts/evmx/helpers/Forwarder.sol +++ b/contracts/evmx/helpers/Forwarder.sol @@ -4,7 +4,6 @@ pragma solidity ^0.8.21; import "./interfaces/IAddressResolver.sol"; import "./interfaces/IMiddleware.sol"; import "./interfaces/IAppGateway.sol"; -import "./interfaces/IPromise.sol"; import "./interfaces/IForwarder.sol"; import {AddressResolverUtil} from "./AddressResolverUtil.sol"; import {AsyncModifierNotUsed, NoAsyncPromiseFound, PromiseCallerMismatch, RequestCountMismatch, WatcherNotSt} from "../utils/common/Errors.sol"; diff --git a/contracts/evmx/interfaces/IPrecompile.sol b/contracts/evmx/interfaces/IPrecompile.sol index 7155492a..20e50ba8 100644 --- a/contracts/evmx/interfaces/IPrecompile.sol +++ b/contracts/evmx/interfaces/IPrecompile.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import "../../utils/common/Structs.sol"; +import {QueueParams, PayloadParams} from "../../utils/common/Structs.sol"; /// @title IPrecompile /// @notice Interface for precompile functionality diff --git a/contracts/evmx/interfaces/IWatcher.sol b/contracts/evmx/interfaces/IWatcher.sol index 22fa5d64..481b26d5 100644 --- a/contracts/evmx/interfaces/IWatcher.sol +++ b/contracts/evmx/interfaces/IWatcher.sol @@ -99,16 +99,8 @@ interface IWatcher { function queueSubmitStart(QueueParams calldata queuePayloadParams_) external; - // queue: function queue(QueueParams calldata queuePayloadParams_) external; - // push in queue - // validateAndGetPrecompileData: - // write: verifyConnection, max msg gas limit is under limit, - // schedule: max delay - // read: - // return encoded data and fees - /// @notice Clears the temporary queue used to store payloads for a request function clearQueue() external; @@ -119,55 +111,19 @@ interface IWatcher { bytes calldata onCompleteData ) external returns (uint40 requestCount); - // { - // (params.precompileData, fees) = IPrecompile.getPrecompileData(queuePayloadParams_); - // } - // precompileFees += fees - // if coreAppGateway is not set, set it else check if it is the same - // decide level - // create id and assign counts - // store payload struct - - // set default AM if addr(0) - // total fees check from maxFees - // verify if msg sender have same core app gateway - // create and store req param - // clear queue - // if writeCount == 0, startProcessing else wait - function assignTransmitter(uint40 requestCount, Bid memory bid_) external; - // validate AM from req param - // update transmitter - // assignTransmitter - // - block for new transmitter - // refinalize payloads for new transmitter - // 0 => non zero - // non zero => non zero - // - unblock credits from prev transmitter - // non zero => 0 - // - just unblock credits and return - // if(_validateProcessBatch() == true) processBatch() - // _processBatch(); - // if a batch is already processed or in process, reprocess it for new transmitter - // deduct fee with precompile call (IPrecompile.handlePayload(payloadParams) returns fees) // prev digest hash create + // create digest, deadline // handlePayload: - // create digest, deadline // emit relevant events function _validateProcessBatch() external; - // if request is cancelled, return - // check if all payloads from last batch are executed, else return; - // check if all payloads are executed, if yes call _settleRequest - function _settleRequest(uint40 requestCount) external; - // if yes, call settleFees on FM and call onCompleteData in App gateway, if not success emit DataNotExecuted() - function markPayloadResolved(uint40 requestCount, RequestParams memory requestParams) external; // update RequestTrackingParams @@ -186,8 +142,8 @@ interface IWatcher { ) external; function cancelRequest(uint40 requestCount) external; - // settleFees on FM + function getMaxFees(uint40 requestCount) external view returns (uint256); function getCurrentRequestCount() external view returns (uint40); diff --git a/contracts/evmx/watcher/Configurations.sol b/contracts/evmx/watcher/Configurations.sol index 21ebb8f2..0ec3697e 100644 --- a/contracts/evmx/watcher/Configurations.sol +++ b/contracts/evmx/watcher/Configurations.sol @@ -83,7 +83,7 @@ contract Configurations is IConfigurations, Initializable, AddressResolverUtil { /// @dev Only callable by the watcher /// @dev This helps in verifying that plugs are called by respective app gateways /// @param configs_ Array of configurations containing app gateway, network, plug, and switchboard details - function setPlugConfigs(AppGatewayConfig[] calldata configs_) external onlyWatcherPrecompile { + function setPlugConfigs(AppGatewayConfig[] calldata configs_) external onlyWatcher { for (uint256 i = 0; i < configs_.length; i++) { // Store the plug configuration for this network and plug _plugConfigs[configs_[i].chainSlug][configs_[i].plug] = PlugConfig({ @@ -100,7 +100,7 @@ contract Configurations is IConfigurations, Initializable, AddressResolverUtil { function setOnChainContracts( uint32 chainSlug_, SocketConfig memory socketConfig_ - ) external onlyWatcherPrecompile { + ) external onlyWatcher { socketConfigs[chainSlug_] = socketConfig_; emit OnChainContractSet( chainSlug_, @@ -118,7 +118,7 @@ contract Configurations is IConfigurations, Initializable, AddressResolverUtil { uint32 chainSlug_, bytes32 sbType_, address switchboard_ - ) external onlyWatcherPrecompile { + ) external onlyWatcher { switchboards[chainSlug_][sbType_] = switchboard_; emit SwitchboardSet(chainSlug_, sbType_, switchboard_); } diff --git a/contracts/evmx/watcher/Watcher.sol b/contracts/evmx/watcher/Watcher.sol index 5c9dd149..f554e700 100644 --- a/contracts/evmx/watcher/Watcher.sol +++ b/contracts/evmx/watcher/Watcher.sol @@ -2,7 +2,6 @@ pragma solidity ^0.8.21; import "../interfaces/IWatcher.sol"; - import {InvalidCallerTriggered, TimeoutDelayTooLarge, TimeoutAlreadyResolved, InvalidInboxCaller, ResolvingTimeoutTooEarly, CallFailed, AppGatewayAlreadyCalled, InvalidWatcherSignature, NonceUsed, RequestAlreadyExecuted} from "../../utils/common/Errors.sol"; import {ResolvedPromises, AppGatewayConfig, LimitParams, WriteFinality, UpdateLimitParams, PlugConfig, DigestParams, TimeoutRequest, QueueParams, PayloadParams, RequestParams} from "../../utils/common/Structs.sol"; @@ -11,7 +10,6 @@ import {ResolvedPromises, AppGatewayConfig, LimitParams, WriteFinality, UpdateLi /// @dev This contract contains all the storage variables used by the WatcherPrecompile system /// @dev It is inherited by WatcherPrecompileCore and WatcherPrecompile abstract contract WatcherStorage is IWatcher { - // todo: can we remove proxies? // slots [0-49]: gap for future storage variables uint256[50] _gap_before; @@ -29,13 +27,6 @@ abstract contract WatcherStorage is IWatcher { /// @dev signatureNonce => isValid mapping(uint256 => bool) public isNonceUsed; - // queue => update to payloadParams, assign id, store in payloadParams map - /// @notice Mapping to store the payload parameters for each payload ID - mapping(bytes32 => PayloadParams) public payloads; - - /// @notice The metadata for a request - mapping(uint40 => RequestParams) public requests; - /// @notice The queue of payloads QueueParams[] public payloadQueue; address public latestAsyncPromise; @@ -153,16 +144,6 @@ contract Watcher is WatcherStorage { clearQueue(); } - function setPayloadParams(bytes32 payloadId_, PayloadParams memory payloadParams_) external { - if (msg.sender != address(requestHandler)) revert InvalidCaller(); - payloads[payloadId_] = payloadParams_; - } - - function setRequestParams(uint40 requestCount_, RequestParams memory requestParams_) external { - if (msg.sender != address(requestHandler)) revert InvalidCaller(); - requests[requestCount_] = requestParams_; - } - /// @notice Sets the expiry time for payload execution /// @param expiryTime_ The expiry time in seconds /// @dev This function sets the expiry time for payload execution @@ -173,7 +154,11 @@ contract Watcher is WatcherStorage { } function getRequestParams(uint40 requestCount_) external view returns (RequestParams memory) { - return requests[requestCount_]; + return requestHandler__().getRequestParams(requestCount_); + } + + function getPayloadParams(bytes32 payloadId_) external view returns (PayloadParams memory) { + return requestHandler__().getPayloadParams(payloadId_); } // all function from watcher requiring signature diff --git a/test/apps/app-gateways/counter/CounterAppGateway.sol b/test/apps/app-gateways/counter/CounterAppGateway.sol index eecc2c79..4b7e0275 100644 --- a/test/apps/app-gateways/counter/CounterAppGateway.sol +++ b/test/apps/app-gateways/counter/CounterAppGateway.sol @@ -102,7 +102,7 @@ contract CounterAppGateway is AppGatewayBase, Ownable { watcherPrecompileConfig().setIsValidPlug(chainSlug_, plug_, true); } - function increase(uint256 value_) external onlyWatcherPrecompile { + function increase(uint256 value_) external onlyWatcher { counterVal += value_; } @@ -115,7 +115,7 @@ contract CounterAppGateway is AppGatewayBase, Ownable { watcherPrecompile__().setTimeout(delayInSeconds_, payload); } - function resolveTimeout(uint256 creationTimestamp_) external onlyWatcherPrecompile { + function resolveTimeout(uint256 creationTimestamp_) external onlyWatcher { emit TimeoutResolved(creationTimestamp_, block.timestamp); } From ae08ea96953df49b6d64af90311fd02a494819bc Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Mon, 19 May 2025 23:27:24 +0530 Subject: [PATCH 025/130] feat: request processing --- contracts/evmx/watcher/RequestHandler.sol | 304 +++++++++++------- contracts/evmx/watcher/WatcherBase.sol | 6 + .../{Read.sol => ReadPrecompile.sol} | 4 +- .../{Schedule.sol => SchedulePrecompile.sol} | 51 ++- contracts/evmx/watcher/precompiles/Write.sol | 100 ------ .../watcher/precompiles/WritePrecompile.sol | 200 ++++++++++++ contracts/utils/common/Structs.sol | 42 +-- 7 files changed, 458 insertions(+), 249 deletions(-) rename contracts/evmx/watcher/precompiles/{Read.sol => ReadPrecompile.sol} (95%) rename contracts/evmx/watcher/precompiles/{Schedule.sol => SchedulePrecompile.sol} (78%) delete mode 100644 contracts/evmx/watcher/precompiles/Write.sol create mode 100644 contracts/evmx/watcher/precompiles/WritePrecompile.sol diff --git a/contracts/evmx/watcher/RequestHandler.sol b/contracts/evmx/watcher/RequestHandler.sol index 18e37e88..ad77191b 100644 --- a/contracts/evmx/watcher/RequestHandler.sol +++ b/contracts/evmx/watcher/RequestHandler.sol @@ -15,12 +15,12 @@ contract RequestHandler is WatcherBase { error InvalidPrecompileData(); error InvalidCallType(); - /// @notice Counter for tracking payload requests - uint40 public payloadCounter; - /// @notice Counter for tracking request counts uint40 public nextRequestCount = 1; + /// @notice Counter for tracking payload requests + uint40 public payloadCounter; + /// @notice Counter for tracking batch counts uint40 public nextBatchCount; @@ -33,9 +33,25 @@ contract RequestHandler is WatcherBase { /// @notice Mapping to store the precompiles for each call type mapping(bytes4 => IPrecompile) public precompiles; + // queue => update to payloadParams, assign id, store in payloadParams map + /// @notice Mapping to store the payload parameters for each payload ID + mapping(bytes32 => PayloadParams) public payloads; + + /// @notice The metadata for a request + mapping(uint40 => RequestParams) public requests; + + /// @notice Mapping to store if a promise is executed for each payload ID + mapping(bytes32 => bool) public isPromiseExecuted; + constructor(address watcherStorage_) WatcherBase(watcherStorage_) {} - function setPrecompile(bytes4 callType_, IPrecompile precompile_) external onlyWatcherStorage { + modifier isRequestCancelled(uint40 requestCount_) { + if (requestParams[requestCount_].requestTrackingParams.isRequestCancelled) + revert RequestCancelled(); + _; + } + + function setPrecompile(bytes4 callType_, IPrecompile precompile_) external onlyWatcher { precompiles[callType_] = precompile_; } @@ -46,7 +62,7 @@ contract RequestHandler is WatcherBase { address appGateway_, QueueParams[] calldata queuePayloadParams_, bytes memory onCompleteData_ - ) external onlyWatcherPrecompile returns (uint40 requestCount, address[] memory promiseList) { + ) external onlyWatcher returns (uint40 requestCount, address[] memory promiseList) { if (queuePayloadParams_.length == 0) return uint40(0); if (queuePayloadParams.length > REQUEST_PAYLOAD_COUNT_LIMIT) revert RequestPayloadCountLimitExceeded(); @@ -56,16 +72,20 @@ contract RequestHandler is WatcherBase { revert InsufficientFees(); requestCount = nextRequestCount++; - RequestParams memory r = RequestParams({ + RequestParams storage r = requestParams[requestCount]; + r = RequestParams({ requestTrackingParams: RequestTrackingParams({ + isRequestCancelled: false, + isRequestExecuted: false, + firstBatchCount: nextBatchCount, currentBatch: nextBatchCount, currentBatchPayloadsLeft: 0, payloadsRemaining: queuePayloadParams_.length }), requestFeesDetails: RequestFeesDetails({ - watcherFees: 0, + maxFees: maxFees_, consumeFrom: consumeFrom_, - maxFees: maxFees_ + winningBid: Bid({transmitter: address(0), fees: 0}) }), writeCount: 0, auctionManager: _getAuctionManager(auctionManager_), @@ -73,18 +93,42 @@ contract RequestHandler is WatcherBase { onCompleteData: onCompleteData_ }); - PayloadParams[] memory payloads; - (r.requestFeesDetails.watcherFees, r.writeCount, promiseList, payloads) = _createRequest( + PayloadParams[] memory payloadParams; + uint256 totalWatcherFees; + (totalWatcherFees, r.writeCount, promiseList, payloadParams) = _createRequest( queuePayloadParams_, appGateway, requestCount ); - if (r.requestFeesDetails.watcherFees > maxFees_) revert InsufficientFees(); - watcherPrecompile__().setRequestParams(requestCount, r); + if (totalWatcherFees > maxFees_) revert InsufficientFees(); - if (r.writeCount == 0) startProcessingRequest(); - emit RequestSubmitted(r.writeCount > 0, requestCount, r, payloads); + if (r.writeCount == 0) _processBatch(requestCount, r.requestTrackingParams.currentBatch, r); + emit RequestSubmitted(r.writeCount > 0, requestCount, totalWatcherFees, r, payloadParams); + } + + // called by auction manager when a auction ends or a new transmitter is assigned (bid expiry) + function assignTransmitter( + uint40 requestCount_, + Bid memory bid_ + ) external isRequestCancelled(requestCount_) { + RequestParams storage r = requestParams[requestCount_]; + if (r.auctionManager != msg.sender) revert InvalidCaller(); + if (r.writeCount == 0) revert NoWriteRequest(); + + if (r.requestFeesDetails.winningBid.transmitter == bid_.transmitter) + revert AlreadyStarted(); + + if (r.requestFeesDetails.winningBid.transmitter != address(0)) { + feesManager__().unblockCredits(requestCount_); + } + r.requestFeesDetails.winningBid = bid_; + + if (bid_.transmitter == address(0)) return; + feesManager__().blockCredits(requestCount_, r.requestFeesDetails.consumeFrom, bid_.fees); + + // re-finalize current batch again or finalize the batch for the first time + _processBatch(requestCount_, r.requestTrackingParams.currentBatch, r); } function _createRequest( @@ -97,7 +141,7 @@ contract RequestHandler is WatcherBase { uint256 totalWatcherFees, uint256 writeCount, address[] memory promiseList, - PayloadParams[] memory payloads + PayloadParams[] memory payloadParams ) { // push first batch count @@ -149,15 +193,17 @@ contract RequestHandler is WatcherBase { requestCount: requestCount_, batchCount: batchCount, payloadCount: payloadCount, - payloadId: payloadId, - prevDigestsHash: prevDigestsHash, - precompileData: precompileData, + callType: callType, asyncPromise: queuePayloadParams_.asyncPromise, - appGateway: queuePayloadParams_.appGateway + appGateway: queuePayloadParams_.appGateway, + payloadId: payloadId, + resolvedAt: 0, + deadline: 0, + precompileData: precompileData }); promiseList.push(queuePayloadParams_.asyncPromise); - payloads.push(p); - watcherPrecompile__().setPayloadParams(payloadId, p); + payloadParams.push(p); + payloads[payloadId] = p; } nextBatchCount++; @@ -169,7 +215,6 @@ contract RequestHandler is WatcherBase { bytes4 callType_ ) internal returns (uint256, bytes memory) { if (address(precompiles[callType_]) == address(0)) revert InvalidCallType(); - return IPrecompile(precompiles[callType_]).validateAndGetPrecompileData( payloadParams_, @@ -184,114 +229,123 @@ contract RequestHandler is WatcherBase { : auctionManager_; } - //todo - function _getPreviousDigestsHash(uint40 batchCount_) internal view returns (bytes32) { + function _processBatch( + uint40 requestCount_, + uint40 batchCount_, + RequestParams storage r + ) internal { + if (r.requestTrackingParams.isRequestExecuted) return; + bytes32[] memory payloadIds = batchPayloadIds[batchCount_]; - bytes32 prevDigestsHash = bytes32(0); + uint256 totalPayloads = 0; + uint256 totalFees = 0; for (uint40 i = 0; i < payloadIds.length; i++) { - PayloadParams memory p = payloads[payloadIds[i]]; - DigestParams memory digestParams = DigestParams( - watcherPrecompileConfig__.sockets(p.payloadHeader.getChainSlug()), - p.finalizedTransmitter, - p.payloadId, - p.deadline, - p.payloadHeader.getCallType(), - p.gasLimit, - p.value, - p.payload, - p.target, - WatcherIdUtils.encodeAppGatewayId(p.appGateway), - p.prevDigestsHash + bytes32 payloadId = payloadIds[i]; + + // check needed for re-finalize, in case a payload is already executed by last transmitter + if (isPromiseExecuted[payloadId]) continue; + totalPayloads++; + + PayloadParams storage payloadParams = payloads[payloadId]; + uint256 deadline = block.timestamp + expiryTime; + payloadParams.deadline = deadline; + + uint256 fees = IPrecompile(precompiles[payloadParams.callType]).handlePayload( + r.requestFeesDetails.winningBid.transmitter, + payloadParams ); - prevDigestsHash = keccak256(abi.encodePacked(prevDigestsHash, getDigest(digestParams))); + totalFees += fees; + } + + r.requestTrackingParams.currentBatchPayloadsLeft = totalPayloads; + + address watcherFeesPayer = r.requestFeesDetails.winningBid.transmitter == address(0) + ? r.requestFeesDetails.consumeFrom + : r.requestFeesDetails.winningBid.transmitter; + feesManager__().transferCredits(watcherFeesPayer, address(this), totalFees); + } + + function markPayloadExecutedAndProcessBatch( + uint40 requestCount_, + bytes32 payloadId_ + ) external onlyPromiseResolver isRequestCancelled(requestCount_) { + RequestParams storage r = requestParams[requestCount_]; + + isPromiseExecuted[payloadId_] = true; + r.requestTrackingParams.currentBatchPayloadsLeft--; + r.requestTrackingParams.payloadsRemaining--; + + if (r.requestTrackingParams.currentBatchPayloadsLeft != 0) return; + if (r.requestTrackingParams.payloadsRemaining == 0) { + _settleRequest(requestCount_, r); + return; } - return prevDigestsHash; + + r.requestTrackingParams.currentBatch++; + _processBatch(requestCount_, r.requestTrackingParams.currentBatch_, r); } - // /// @notice Increases the fees for a request if no bid is placed - // /// @param requestCount_ The ID of the request - // /// @param newMaxFees_ The new maximum fees - // function increaseFees(uint40 requestCount_, uint256 newMaxFees_) external override { - // address appGateway = _getCoreAppGateway(msg.sender); - // // todo: should we allow core app gateway too? - // if (appGateway != requests[requestCount_].appGateway) { - // revert OnlyAppGateway(); - // } - // if (requests[requestCount_].winningBid.transmitter != address(0)) revert WinningBidExists(); - // if (requests[requestCount_].maxFees >= newMaxFees_) - // revert NewMaxFeesLowerThanCurrent(requests[requestCount_].maxFees, newMaxFees_); - // requests[requestCount_].maxFees = newMaxFees_; - // emit FeesIncreased(appGateway, requestCount_, newMaxFees_); - // } - - // /// @notice Updates the transmitter for a request - // /// @param requestCount The request count to update - // /// @param transmitter The new transmitter address - // /// @dev This function updates the transmitter for a request - // /// @dev It verifies that the caller is the middleware and that the request hasn't been started yet - // function updateTransmitter(uint40 requestCount, address transmitter) public { - // RequestParams storage r = requestParams[requestCount]; - // if (r.isRequestCancelled) revert RequestCancelled(); - // if (r.payloadsRemaining == 0) revert RequestAlreadyExecuted(); - // if (r.middleware != msg.sender) revert InvalidCaller(); - // if (r.transmitter != address(0)) revert RequestNotProcessing(); - // r.transmitter = transmitter; - - // _processBatch(requestCount, r.currentBatch); - // } - - // /// @notice Cancels a request - // /// @param requestCount The request count to cancel - // /// @dev This function cancels a request - // /// @dev It verifies that the caller is the middleware and that the request hasn't been cancelled yet - // function cancelRequest(uint40 requestCount) external { - // RequestParams storage r = requestParams[requestCount]; - // if (r.isRequestCancelled) revert RequestAlreadyCancelled(); - // if (r.middleware != msg.sender) revert InvalidCaller(); - - // r.isRequestCancelled = true; - // emit RequestCancelledFromGateway(requestCount); - // } - - // /// @notice Ends the timeouts and calls the target address with the callback payload - // /// @param timeoutId_ The unique identifier for the timeout - // /// @param signatureNonce_ The nonce used in the watcher's signature - // /// @param signature_ The watcher's signature - // /// @dev It verifies if the signature is valid and the timeout hasn't been resolved yet - // function resolveTimeout( - // bytes32 timeoutId_, - // uint256 signatureNonce_, - // bytes memory signature_ - // ) external { - // _isWatcherSignatureValid( - // abi.encode(this.resolveTimeout.selector, timeoutId_), - // signatureNonce_, - // signature_ - // ); - - // TimeoutRequest storage timeoutRequest_ = timeoutRequests[timeoutId_]; - // if (timeoutRequest_.target == address(0)) revert InvalidTimeoutRequest(); - // if (timeoutRequest_.isResolved) revert TimeoutAlreadyResolved(); - // if (block.timestamp < timeoutRequest_.executeAt) revert ResolvingTimeoutTooEarly(); - - // (bool success, , bytes memory returnData) = timeoutRequest_.target.tryCall( - // 0, - // gasleft(), - // 0, // setting max_copy_bytes to 0 as not using returnData right now - // timeoutRequest_.payload - // ); - // if (!success) revert CallFailed(); - - // timeoutRequest_.isResolved = true; - // timeoutRequest_.executedAt = block.timestamp; - - // emit TimeoutResolved( - // timeoutId_, - // timeoutRequest_.target, - // timeoutRequest_.payload, - // block.timestamp, - // returnData - // ); - // } + function _settleRequest(uint40 requestCount_, RequestParams storage r) internal { + if (r.requestTrackingParams.isRequestExecuted) return; + r.requestTrackingParams.isRequestExecuted = true; + + feesManager__().unblockAndAssignCredits( + requestCount_, + r.requestFeesDetails.winningBid.transmitter + ); + + if (r.appGateway.code.length > 0 && r.onCompleteData.length > 0) { + try + IAppGateway(r.appGateway).onRequestComplete(requestCount_, r.onCompleteData) + {} catch { + emit RequestCompletedWithErrors(requestCount_); + } + } + + emit RequestSettled(requestCount_, r.requestFeesDetails.winningBid.transmitter); + } } + +// /// @notice Increases the fees for a request if no bid is placed +// /// @param requestCount_ The ID of the request +// /// @param newMaxFees_ The new maximum fees +// function increaseFees(uint40 requestCount_, uint256 newMaxFees_) external override { +// address appGateway = _getCoreAppGateway(msg.sender); +// // todo: should we allow core app gateway too? +// if (appGateway != requests[requestCount_].appGateway) { +// revert OnlyAppGateway(); +// } +// if (requests[requestCount_].winningBid.transmitter != address(0)) revert WinningBidExists(); +// if (requests[requestCount_].maxFees >= newMaxFees_) +// revert NewMaxFeesLowerThanCurrent(requests[requestCount_].maxFees, newMaxFees_); +// requests[requestCount_].maxFees = newMaxFees_; +// emit FeesIncreased(appGateway, requestCount_, newMaxFees_); +// } + +// /// @notice Cancels a request +// /// @param requestCount The request count to cancel +// /// @dev This function cancels a request +// /// @dev It verifies that the caller is the middleware and that the request hasn't been cancelled yet +// function cancelRequest(uint40 requestCount) external { +// RequestParams storage r = requestParams[requestCount]; +// if (r.isRequestCancelled) revert RequestAlreadyCancelled(); +// if (r.middleware != msg.sender) revert InvalidCaller(); + +// r.isRequestCancelled = true; +// emit RequestCancelledFromGateway(requestCount); +// } + +// /// @notice Cancels a request and settles the fees +// /// @dev if no transmitter was assigned, fees is unblocked to app gateway +// /// @dev Only app gateway can call this function +// /// @param requestCount_ The ID of the request +// function cancelRequest(uint40 requestCount_) external { +// if (msg.sender != requests[requestCount_].appGateway) { +// revert OnlyAppGateway(); +// } + +// _settleFees(requestCount_); +// watcherPrecompile__().cancelRequest(requestCount_); +// emit RequestCancelled(requestCount_); +// } diff --git a/contracts/evmx/watcher/WatcherBase.sol b/contracts/evmx/watcher/WatcherBase.sol index cb499eae..bb6e766a 100644 --- a/contracts/evmx/watcher/WatcherBase.sol +++ b/contracts/evmx/watcher/WatcherBase.sol @@ -25,4 +25,10 @@ contract WatcherBase { function setWatcher(address watcher_) external onlyWatcher { watcher = watcher_; } + + /// @notice Returns the configurations of the WatcherPrecompileStorage contract + /// @return configurations The configurations of the WatcherPrecompileStorage contract + function configurations__() external view returns (IConfigurations) { + return IWatcher(watcher).configurations__(); + } } diff --git a/contracts/evmx/watcher/precompiles/Read.sol b/contracts/evmx/watcher/precompiles/ReadPrecompile.sol similarity index 95% rename from contracts/evmx/watcher/precompiles/Read.sol rename to contracts/evmx/watcher/precompiles/ReadPrecompile.sol index 0469919b..c89aedbf 100644 --- a/contracts/evmx/watcher/precompiles/Read.sol +++ b/contracts/evmx/watcher/precompiles/ReadPrecompile.sol @@ -1,14 +1,14 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import "../../interfaces/IWatcher.sol"; +import "../../interfaces/IPrecompile.sol"; import "../../../utils/common/Structs.sol"; import "../../../utils/common/Errors.sol"; import "../WatcherBase.sol"; /// @title Read /// @notice Handles read precompile logic -contract Read is IPrecompile, WatcherBase { +contract ReadPrecompile is IPrecompile, WatcherBase { /// @notice Emitted when a new read is requested event ReadRequested(PayloadParams params); diff --git a/contracts/evmx/watcher/precompiles/Schedule.sol b/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol similarity index 78% rename from contracts/evmx/watcher/precompiles/Schedule.sol rename to contracts/evmx/watcher/precompiles/SchedulePrecompile.sol index 57bc43b7..4ab3ad90 100644 --- a/contracts/evmx/watcher/precompiles/Schedule.sol +++ b/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol @@ -6,10 +6,10 @@ import "../../../utils/common/Structs.sol"; import "../../../utils/common/Errors.sol"; import "../WatcherBase.sol"; -/// @title Schedule +/// @title SchedulePrecompile /// @notice Library that handles schedule logic for the WatcherPrecompile system /// @dev This library contains pure functions for schedule operations -contract Schedule is IPrecompile, WatcherBase { +contract SchedulePrecompile is IPrecompile, WatcherBase { // slot 52 /// @notice The maximum delay for a schedule /// @dev Maximum schedule delay in seconds @@ -168,3 +168,50 @@ contract Schedule is IPrecompile, WatcherBase { return abi.encode(scheduleId, target, payload, executedAt, returnData); } } + +// /// @notice Ends the timeouts and calls the target address with the callback payload +// /// @param timeoutId_ The unique identifier for the timeout +// function resolveTimeout( +// bytes32 timeoutId_, +// ) external { +// TimeoutRequest storage timeoutRequest_ = timeoutRequests[timeoutId_]; +// if (timeoutRequest_.target == address(0)) revert InvalidTimeoutRequest(); +// if (timeoutRequest_.isResolved) revert TimeoutAlreadyResolved(); +// if (block.timestamp < timeoutRequest_.executeAt) revert ResolvingTimeoutTooEarly(); + +// (bool success, , bytes memory returnData) = timeoutRequest_.target.tryCall( +// 0, +// gasleft(), +// 0, // setting max_copy_bytes to 0 as not using returnData right now +// timeoutRequest_.payload +// ); +// if (!success) revert CallFailed(); +// timeoutRequest_.isResolved = true; +// timeoutRequest_.executedAt = block.timestamp; + +// emit TimeoutResolved( +// timeoutId_, +// timeoutRequest_.target, +// timeoutRequest_.payload, +// block.timestamp, +// returnData +// ); +// } + +// /// @notice Sets a timeout for a payload execution on app gateway +// /// @return timeoutId The unique identifier for the timeout request +// function _setTimeout( +// uint256 delayInSeconds_, +// bytes memory payload_ +// ) internal returns (bytes32 timeoutId) { +// uint256 executeAt = block.timestamp + delayInSeconds_; +// timeoutId = _encodeTimeoutId(); + +// timeoutRequests[timeoutId].target = msg.sender; +// timeoutRequests[timeoutId].delayInSeconds = delayInSeconds_; +// timeoutRequests[timeoutId].executeAt = executeAt; +// timeoutRequests[timeoutId].payload = payload_; + +// // emits event for watcher to track timeout and resolve when timeout is reached +// emit TimeoutRequested(timeoutId, msg.sender, payload_, executeAt); +// } diff --git a/contracts/evmx/watcher/precompiles/Write.sol b/contracts/evmx/watcher/precompiles/Write.sol deleted file mode 100644 index 48fe72e9..00000000 --- a/contracts/evmx/watcher/precompiles/Write.sol +++ /dev/null @@ -1,100 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -pragma solidity ^0.8.21; - -import "../../interfaces/IWatcher.sol"; -import "../../../utils/common/Structs.sol"; -import "../../../utils/common/Errors.sol"; - -import "../WatcherBase.sol"; - -/// @title Write -/// @notice Handles write precompile logic -contract Write is IPrecompile, WatcherBase { - /// @notice Mapping to store watcher proofs - /// @dev Maps payload ID to proof bytes - /// @dev payloadId => proof bytes - mapping(bytes32 => bytes) public watcherProofs; - - uint256 public writeFees; - uint256 public callbackFees; - - /// @notice Gets precompile data and fees for queue parameters - /// @param queuePayloadParams_ The queue parameters to process - /// @return precompileData The encoded precompile data - /// @return fees Estimated fees required for processing - function validateAndGetPrecompileData( - QueueParams calldata queuePayloadParams_, - address appGateway_ - ) external view returns (bytes memory precompileData, uint256 fees) { - if (queuePayloadParams_.value > chainMaxMsgValueLimit[queuePayloadParams_.chainSlug]) - revert MaxMsgValueLimitExceeded(); - - if (queuePayloadParams_.transaction.target != address(0)) { - revert InvalidTarget(); - } - - if ( - queuePayloadParams_.transaction.payload.length > 0 && - queuePayloadParams_.transaction.payload.length < PAYLOAD_SIZE_LIMIT - ) { - revert InvalidPayloadSize(); - } - - configurations__().verifyConnections( - queuePayloadParams_.chainSlug, - queuePayloadParams_.transaction.target, - appGateway_, - queuePayloadParams_.switchboardType - ); - - // For write precompile, encode the payload parameters - precompileData = abi.encode( - queuePayloadParams_.transaction, - queuePayloadParams_.overrideParams.writeFinality, - queuePayloadParams_.overrideParams.gasLimit, - queuePayloadParams_.overrideParams.value - ); - - fees = writeFees + callbackFees; - } - - /// @notice Handles payload processing and returns fees - /// @param payloadParams The payload parameters to handle - /// @return fees The fees required for processing - function handlePayload( - PayloadParams calldata payloadParams - ) external pure returns (uint256 fees) { - fees = writeFees + callbackFees; - emit WriteRequested(payloadParams); - } - - /// @notice Marks a write request as finalized with a proof on digest - /// @param payloadId_ The unique identifier of the request - /// @param proof_ The watcher's proof - function finalize(bytes32 payloadId_, bytes memory proof_) public onlyWatcher { - watcherProofs[payloadId_] = proof_; - emit Finalized(payloadId_, proof_); - } - - /// @notice Updates the maximum message value limit for multiple chains - /// @param chainSlugs_ Array of chain identifiers - /// @param maxMsgValueLimits_ Array of corresponding maximum message value limits - function updateChainMaxMsgValueLimits( - uint32[] calldata chainSlugs_, - uint256[] calldata maxMsgValueLimits_ - ) external onlyWatcher { - if (chainSlugs_.length != maxMsgValueLimits_.length) revert InvalidIndex(); - - for (uint256 i = 0; i < chainSlugs_.length; i++) { - chainMaxMsgValueLimit[chainSlugs_[i]] = maxMsgValueLimits_[i]; - } - - emit ChainMaxMsgValueLimitsUpdated(chainSlugs_, maxMsgValueLimits_); - } - - function setFees(uint256 writeFees_, uint256 callbackFees_) external onlyWatcher { - writeFees = writeFees_; - callbackFees = callbackFees_; - emit FeesSet(writeFees_, callbackFees_); - } -} diff --git a/contracts/evmx/watcher/precompiles/WritePrecompile.sol b/contracts/evmx/watcher/precompiles/WritePrecompile.sol new file mode 100644 index 00000000..76988b18 --- /dev/null +++ b/contracts/evmx/watcher/precompiles/WritePrecompile.sol @@ -0,0 +1,200 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import "../../../utils/common/Errors.sol"; +import "../../../utils/common/Constants.sol"; +import "../../interfaces/IPrecompile.sol"; + +import "../WatcherBase.sol"; + +/// @title WritePrecompile +/// @notice Handles write precompile logic +contract WritePrecompile is IPrecompile, WatcherBase { + /// @notice Mapping to store watcher proofs + /// @dev Maps payload ID to proof bytes + /// @dev payloadId => proof bytes + mapping(bytes32 => bytes) public watcherProofs; + + /// @notice The maximum message value limit for a chain + mapping(uint32 => uint256) public chainMaxMsgValueLimit; + + /// @notice The fees for a write + uint256 public writeFees; + /// @notice The callback fees for a write + uint256 public callbackFees; + + error MaxMsgValueLimitExceeded(); + error InvalidTarget(); + error InvalidPayloadSize(); + + /// @notice Emitted when fees are set + event FeesSet(uint256 writeFees, uint256 callbackFees); + event ChainMaxMsgValueLimitsUpdated(uint32[] chainSlugs, uint256[] maxMsgValueLimits); + event WriteRequested(bytes32 digest, PayloadParams payloadParams); + event Finalized(bytes32 payloadId, bytes proof); + + /// @notice Gets precompile data and fees for queue parameters + /// @param queuePayloadParams_ The queue parameters to process + /// @return precompileData The encoded precompile data + /// @return fees Estimated fees required for processing + function validateAndGetPrecompileData( + QueueParams calldata queuePayloadParams_, + address appGateway_ + ) external view returns (bytes memory precompileData, uint256 fees) { + if (queuePayloadParams_.value > chainMaxMsgValueLimit[queuePayloadParams_.chainSlug]) + revert MaxMsgValueLimitExceeded(); + + if (queuePayloadParams_.transaction.target != address(0)) { + revert InvalidTarget(); + } + + if ( + queuePayloadParams_.transaction.payload.length > 0 && + queuePayloadParams_.transaction.payload.length < PAYLOAD_SIZE_LIMIT + ) { + revert InvalidPayloadSize(); + } + + configurations__().verifyConnections( + queuePayloadParams_.chainSlug, + queuePayloadParams_.transaction.target, + appGateway_, + queuePayloadParams_.switchboardType + ); + + // For write precompile, encode the payload parameters + precompileData = abi.encode( + queuePayloadParams_.transaction, + queuePayloadParams_.overrideParams.writeFinality, + queuePayloadParams_.overrideParams.gasLimit, + queuePayloadParams_.overrideParams.value + ); + + fees = writeFees + callbackFees; + } + + /// @notice Handles payload processing and returns fees + /// @param payloadParams The payload parameters to handle + /// @return fees The fees required for processing + /// @return precompileData The precompile data + function handlePayload( + address transmitter_, + PayloadParams calldata payloadParams + ) external pure returns (uint256 fees) { + fees = writeFees + callbackFees; + + ( + Transaction transaction, + WriteFinality writeFinality, + uint256 gasLimit, + uint256 value + ) = abi.decode(payloadParams.precompileData, (Transaction, bool, uint256, uint256)); + + bytes32 prevDigestsHash = _getPreviousDigestsHash(payloadParams); + + // create digest + DigestParams memory digestParams_ = DigestParams( + configManager__().sockets(transaction.chainSlug), + transmitter_, + payloadParams.payloadId, + payloadParams.deadline, + payloadParams.callType, + gasLimit, + value, + transaction.payload, + transaction.target, + WatcherIdUtils.encodeAppGatewayId(payloadParams.appGateway), + prevDigestsHash, + bytes("") + ); + + // Calculate digest from payload parameters + bytes32 digest = getDigest(digestParams_); + + // store digest and prev digest hash + digestHashes[payloadParams.payloadId] = digest; + emit WriteRequested(digest, transaction, writeFinality, gasLimit, value); + } + + function _getPreviousDigestsHash( + PayloadParams memory payloadParams_ + ) internal view returns (bytes32) { + uint40 batchCount = payloadParams_.batchCount; + + // if first batch, return bytes32(0) + uint40[] memory requestBatchIds = requestHandler__().requestBatchIds(batchCount); + if (requestBatchIds[0] == batchCount) return bytes32(0); + + // get previous digests hash from storage for last batchCount if already calculated + if (prevDigestsHashes[batchCount] != bytes32(0)) return prevDigestsHashes[batchCount]; + + // else calculate the previous digests hash + uint40 lastBatchCount = batchCount - 1; + bytes32[] memory payloadIds = requestHandler__().batchPayloadIds(lastBatchCount); + + bytes32 prevDigestsHash = bytes32(0); + for (uint40 i = 0; i < payloadIds.length; i++) { + prevDigestsHash = keccak256( + abi.encodePacked(prevDigestsHash, digestHashes[payloadIds[i]]) + ); + } + + // store the previous digests hash + prevDigestsHashes[batchCount] = prevDigestsHash; + return prevDigestsHash; + } + + /// @notice Calculates the digest hash of payload parameters + /// @dev extraData is empty for now, not needed for this EVMx + /// @param params_ The payload parameters to calculate the digest for + /// @return digest The calculated digest hash + /// @dev This function creates a keccak256 hash of the payload parameters + function getDigest(DigestParams memory params_) public pure returns (bytes32 digest) { + digest = keccak256( + abi.encode( + params_.socket, + params_.transmitter, + params_.payloadId, + params_.deadline, + params_.callType, + params_.gasLimit, + params_.value, + params_.payload, + params_.target, + params_.appGatewayId, + params_.prevDigestsHash, + params_.extraData + ) + ); + } + + /// @notice Marks a write request as finalized with a proof on digest + /// @param payloadId_ The unique identifier of the request + /// @param proof_ The watcher's proof + function finalize(bytes32 payloadId_, bytes memory proof_) public onlyWatcher { + watcherProofs[payloadId_] = proof_; + emit Finalized(payloadId_, proof_); + } + + /// @notice Updates the maximum message value limit for multiple chains + /// @param chainSlugs_ Array of chain identifiers + /// @param maxMsgValueLimits_ Array of corresponding maximum message value limits + function updateChainMaxMsgValueLimits( + uint32[] calldata chainSlugs_, + uint256[] calldata maxMsgValueLimits_ + ) external onlyWatcher { + if (chainSlugs_.length != maxMsgValueLimits_.length) revert InvalidIndex(); + + for (uint256 i = 0; i < chainSlugs_.length; i++) { + chainMaxMsgValueLimit[chainSlugs_[i]] = maxMsgValueLimits_[i]; + } + + emit ChainMaxMsgValueLimitsUpdated(chainSlugs_, maxMsgValueLimits_); + } + + function setFees(uint256 writeFees_, uint256 callbackFees_) external onlyWatcher { + writeFees = writeFees_; + callbackFees = callbackFees_; + emit FeesSet(writeFees_, callbackFees_); + } +} diff --git a/contracts/utils/common/Structs.sol b/contracts/utils/common/Structs.sol index e4742e40..51fe85e2 100644 --- a/contracts/utils/common/Structs.sol +++ b/contracts/utils/common/Structs.sol @@ -139,6 +139,7 @@ struct DigestParams { address target; bytes32 appGatewayId; bytes32 prevDigestsHash; + bytes extraData; } // App gateway base: struct OverrideParams { @@ -174,14 +175,15 @@ struct PayloadParams { uint40 requestCount; uint40 batchCount; uint40 payloadCount; - address asyncPromise; + bytes4 callType; + address asyncPromise; // todo: multiple promise support? address appGateway; bytes32 payloadId; - bytes32 prevDigestsHash; uint256 resolvedAt; // replaced isPromiseExecuted + uint256 deadline; bytes precompileData; - // uint256 deadline; + // bytes32 prevDigestsHash; // address finalizedTransmitter; // Transaction transaction; // OverrideParams overrideParams; @@ -189,33 +191,33 @@ struct PayloadParams { // address switchboard; } // timeout: -struct TimeoutRequest { - uint256 delayInSeconds; - uint256 executeAt; - bool isResolved; -} +// struct TimeoutRequest { +// uint256 delayInSeconds; +// uint256 executeAt; +// bool isResolved; +// } // request struct RequestTrackingParams { bool isRequestCancelled; - uint40 currentBatch; - uint256 currentBatchPayloadsLeft; - uint256 payloadsRemaining; + bool isRequestExecuted; // + uint40 firstBatchCount; // + uint40 currentBatch; // + uint256 currentBatchPayloadsLeft; // + uint256 payloadsRemaining; // } struct RequestFeesDetails { - uint256 maxFees; - uint256 watcherFees; - address consumeFrom; - Bid winningBid; + uint256 maxFees; // + address consumeFrom; // + Bid winningBid; // } struct RequestParams { RequestTrackingParams requestTrackingParams; RequestFeesDetails requestFeesDetails; - address appGateway; - address auctionManager; - uint256 writeCount; - bool isRequestExecuted; - bytes onCompleteData; + address appGateway; // + address auctionManager; // + uint256 writeCount; // + bytes onCompleteData; // } From cced48101dfc6cee325285e598aa2dcdbd7ff61e Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Mon, 19 May 2025 23:27:57 +0530 Subject: [PATCH 026/130] feat: promise resolver --- contracts/evmx/watcher/PromiseResolver.sol | 136 ++++++--------------- 1 file changed, 38 insertions(+), 98 deletions(-) diff --git a/contracts/evmx/watcher/PromiseResolver.sol b/contracts/evmx/watcher/PromiseResolver.sol index 54c64b47..f6dfc77c 100644 --- a/contracts/evmx/watcher/PromiseResolver.sol +++ b/contracts/evmx/watcher/PromiseResolver.sol @@ -1,88 +1,55 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import "../../interfaces/IWatcher.sol"; -import "../../interfaces/IPromise.sol"; -import "../../libs/PayloadHeaderDecoder.sol"; -import "../../common/Structs.sol"; -import "../../common/Errors.sol"; -import "../../core/WatcherIdUtils.sol"; +import {PayloadParams, ResolvedPromises} from "../../utils/common/Structs.sol"; +import "../interfaces/IPromise.sol"; +import "./WatcherBase.sol"; interface IPromiseResolver { - function resolvePromises( - ResolvedPromises[] calldata resolvedPromises_, - uint256 signatureNonce_, - bytes calldata signature_ - ) external; + function resolvePromises(ResolvedPromises[] calldata resolvedPromises_) external; - function markRevert( - bool isRevertingOnchain_, - bytes32 payloadId_, - uint256 signatureNonce_, - bytes calldata signature_ - ) external; + function markRevert(bool isRevertingOnchain_, bytes32 payloadId_) external; } /// @title PromiseResolver /// @notice Contract that handles promise resolution and revert marking logic -/// @dev This contract interacts with the WatcherPrecompileStorage for storage access -contract PromiseResolver { - using PayloadHeaderDecoder for bytes32; +/// @dev This contract interacts with the Watcher for storage access +contract PromiseResolver is IPromiseResolver { + error DeadlineNotPassedForOnChainRevert(); - // The address of the WatcherPrecompileStorage contract - address public watcherStorage; - - // Only WatcherPrecompileStorage can call functions - modifier onlyWatcherStorage() { - require(msg.sender == watcherStorage, "Only WatcherStorage can call"); - _; - } - - /// @notice Sets the WatcherPrecompileStorage address - /// @param watcherStorage_ The address of the WatcherPrecompileStorage contract - constructor(address watcherStorage_) { - watcherStorage = watcherStorage_; - } - - /// @notice Updates the WatcherPrecompileStorage address - /// @param watcherStorage_ The new address of the WatcherPrecompileStorage contract - function setWatcherStorage(address watcherStorage_) external onlyWatcherStorage { - watcherStorage = watcherStorage_; - } + /// @notice Sets the Watcher address + /// @param watcher_ The address of the Watcher contract + constructor(address watcher_) WatcherBase(watcher_) {} /// @notice Resolves multiple promises with their return data /// @param resolvedPromises_ Array of resolved promises and their return data - /// @param signatureNonce_ The nonce of the signature - /// @param signature_ The signature of the watcher /// @dev This function resolves multiple promises with their return data - /// @dev It verifies that the signature is valid /// @dev It also processes the next batch if the current batch is complete - function resolvePromises( - ResolvedPromises[] memory resolvedPromises_, - uint256 signatureNonce_, - bytes memory signature_ - ) external { + function resolvePromises(ResolvedPromises[] memory resolvedPromises_) external onlyWatcher { for (uint256 i = 0; i < resolvedPromises_.length; i++) { - uint40 requestCount = payloads[resolvedPromises_[i].payloadId] - .payloadHeader - .getRequestCount(); - RequestParams storage requestParams_ = requestParams[requestCount]; - - _processPromiseResolution(resolvedPromises_[i], requestParams_); - _checkAndProcessBatch(requestParams_, requestCount); + (uint40 requestCount, bool success) = _processPromiseResolution(resolvedPromises_[i]); + if (success) { + requestHandler__().markPayloadExecutedAndProcessBatch( + requestCount, + resolvedPromises_[i].payloadId + ); + } } } function _processPromiseResolution( - ResolvedPromises memory resolvedPromise_, - RequestParams storage requestParams_ - ) internal { - PayloadParams memory payloadParams = payloads[resolvedPromise_.payloadId]; + ResolvedPromises memory resolvedPromise_ + ) internal returns (uint40 requestCount, bool success) { + PayloadParams memory payloadParams = requestHandler__().getPayloadParams( + resolvedPromise_.payloadId + ); + address asyncPromise = payloadParams.asyncPromise; - uint40 requestCount = payloadParams.payloadHeader.getRequestCount(); + requestCount = payloadParams.requestCount; + success = true; if (asyncPromise != address(0)) { - bool success = IPromise(asyncPromise).markResolved( + success = IPromise(asyncPromise).markResolved( requestCount, resolvedPromise_.payloadId, resolvedPromise_.returnData @@ -90,56 +57,29 @@ contract PromiseResolver { if (!success) { emit PromiseNotResolved(resolvedPromise_.payloadId, asyncPromise); - return; + return (requestCount, false); } } - isPromiseExecuted[resolvedPromise_.payloadId] = true; - requestParams_.currentBatchPayloadsLeft--; - requestParams_.payloadsRemaining--; - emit PromiseResolved(resolvedPromise_.payloadId, asyncPromise); } - function _checkAndProcessBatch( - RequestParams storage requestParams_, - uint40 requestCount - ) internal { - if (requestParams_.currentBatchPayloadsLeft == 0 && requestParams_.payloadsRemaining > 0) { - _processBatch(requestCount, ++requestParams_.currentBatch); - } - - if (requestParams_.payloadsRemaining == 0) { - IMiddleware(requestParams_.middleware).finishRequest(requestCount); - } - } - /// @notice Marks a request as reverting - /// @param isRevertingOnchain Whether the request is reverting onchain - /// @param payloadId The unique identifier of the payload - /// @param currentTimestamp The current block timestamp + /// @param isRevertingOnchain_ Whether the request is reverting onchain + /// @param payloadId_ The unique identifier of the payload /// @return success Whether the request was successfully marked as reverting - function markRevert( - bool isRevertingOnchain, - bytes32 payloadId, - uint256 currentTimestamp - ) external onlyWatcherStorage returns (bool success) { - // Get payload params from WatcherPrecompileStorage - PayloadParams memory payloadParams = payloads[payloadId_]; + function markRevert(bool isRevertingOnchain_, bytes32 payloadId_) external onlyWatcher { + // Get payload params from Watcher + PayloadParams memory payloadParams = requestHandler__().getPayloadParams(payloadId_); if (payloadParams.deadline > block.timestamp) revert DeadlineNotPassedForOnChainRevert(); - RequestParams storage currentRequestParams = requestParams[ - payloadParams.payloadHeader.getRequestCount() - ]; - currentRequestParams.isRequestCancelled = true; - - IMiddleware(currentRequestParams.middleware).handleRequestReverts( - payloadParams.payloadHeader.getRequestCount() - ); + // marks the request as cancelled and settles the fees + requestHandler__().cancelRequest(payloadParams.requestCount); + // marks the promise as onchain reverting if the request is reverting onchain if (isRevertingOnchain_ && payloadParams.asyncPromise != address(0)) IPromise(payloadParams.asyncPromise).markOnchainRevert( - payloadParams.payloadHeader.getRequestCount(), + payloadParams.requestCount, payloadId_ ); From 2531341849d1db0f36a0b62eb06d2a0fe99ddf33 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 20 May 2025 15:58:18 +0530 Subject: [PATCH 027/130] fix: refactor --- .../evmx/app-gateways/AuctionManager.sol | 28 ++++++----- contracts/evmx/interfaces/IWatcher.sol | 16 +++--- contracts/evmx/watcher/RequestHandler.sol | 50 ++++++++++--------- .../watcher/precompiles/ReadPrecompile.sol | 23 +++++---- .../precompiles/SchedulePrecompile.sol | 4 +- contracts/utils/common/Structs.sol | 7 +-- 6 files changed, 64 insertions(+), 64 deletions(-) diff --git a/contracts/evmx/app-gateways/AuctionManager.sol b/contracts/evmx/app-gateways/AuctionManager.sol index 90e48f24..850677c5 100644 --- a/contracts/evmx/app-gateways/AuctionManager.sol +++ b/contracts/evmx/app-gateways/AuctionManager.sol @@ -168,22 +168,24 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, function _endAuction(uint40 requestCount_) internal { // get the winning bid, if no transmitter is set, revert Bid memory winningBid = winningBids[requestCount_]; - if (winningBid.transmitter == address(0)) revert InvalidTransmitter(); auctionStatus[requestCount_] = AuctionStatus.CLOSED; - // todo: might block the request processing if transmitter don't have enough balance - // not implementing this for now - // set the timeout for the bid expiration - // useful in case a transmitter did bid but did not execute payloads - _createRequest( - bidTimeout, - deductScheduleFees(winningBid.transmitter, address(this)), - winningBid.transmitter, - abi.encodeWithSelector(this.expireBid.selector, requestCount_) - ); + if (winningBid.transmitter != address(0)) { + // todo: might block the request processing if transmitter don't have enough balance + // not implementing this for now + // set the timeout for the bid expiration + // useful in case a transmitter did bid but did not execute payloads + _createRequest( + bidTimeout, + deductScheduleFees(winningBid.transmitter, address(this)), + winningBid.transmitter, + abi.encodeWithSelector(this.expireBid.selector, requestCount_) + ); + + // start the request processing, it will queue the request + IWatcher(watcherPrecompile__()).assignTransmitter(requestCount_, winningBid); + } - // start the request processing, it will queue the request - IWatcher(watcherPrecompile__()).assignTransmitter(requestCount_, winningBid); emit AuctionEnded(requestCount_, winningBid); } diff --git a/contracts/evmx/interfaces/IWatcher.sol b/contracts/evmx/interfaces/IWatcher.sol index 481b26d5..10ed34db 100644 --- a/contracts/evmx/interfaces/IWatcher.sol +++ b/contracts/evmx/interfaces/IWatcher.sol @@ -15,13 +15,13 @@ interface IWatcher { /// @param triggerId The unique identifier for the trigger event AppGatewayCallFailed(bytes32 triggerId); - /// @notice Emitted when a finalize request is made - event FinalizeRequested(bytes32 digest, PayloadParams params); + /// @notice Emitted when a proof upload request is made + event WriteProofRequested(bytes32 digest, PayloadParams params); - /// @notice Emitted when a request is finalized + /// @notice Emitted when a proof is uploaded /// @param payloadId The unique identifier for the request /// @param proof The proof from the watcher - event Finalized(bytes32 indexed payloadId, bytes proof); + event WriteProofUploaded(bytes32 indexed payloadId, bytes proof); /// @notice Emitted when a promise is resolved /// @param payloadId The unique identifier for the resolved promise @@ -134,14 +134,10 @@ interface IWatcher { /// @param fees_ The new fees function increaseFees(uint40 requestCount_, uint256 fees_) external; - function finalized( - bytes32 payloadId_, - bytes calldata proof_, - uint256 signatureNonce_, - bytes calldata signature_ - ) external; + function uploadProof(bytes32 payloadId_, bytes calldata proof_) external; function cancelRequest(uint40 requestCount) external; + // settleFees on FM function getMaxFees(uint40 requestCount) external view returns (uint256); diff --git a/contracts/evmx/watcher/RequestHandler.sol b/contracts/evmx/watcher/RequestHandler.sol index ad77191b..32b17c6a 100644 --- a/contracts/evmx/watcher/RequestHandler.sol +++ b/contracts/evmx/watcher/RequestHandler.sol @@ -77,7 +77,6 @@ contract RequestHandler is WatcherBase { requestTrackingParams: RequestTrackingParams({ isRequestCancelled: false, isRequestExecuted: false, - firstBatchCount: nextBatchCount, currentBatch: nextBatchCount, currentBatchPayloadsLeft: 0, payloadsRemaining: queuePayloadParams_.length @@ -94,17 +93,23 @@ contract RequestHandler is WatcherBase { }); PayloadParams[] memory payloadParams; - uint256 totalWatcherFees; - (totalWatcherFees, r.writeCount, promiseList, payloadParams) = _createRequest( + uint256 totalEstimatedWatcherFees; + (totalEstimatedWatcherFees, r.writeCount, promiseList, payloadParams) = _createRequest( queuePayloadParams_, appGateway, requestCount ); - if (totalWatcherFees > maxFees_) revert InsufficientFees(); + if (totalEstimatedWatcherFees > maxFees_) revert InsufficientFees(); if (r.writeCount == 0) _processBatch(requestCount, r.requestTrackingParams.currentBatch, r); - emit RequestSubmitted(r.writeCount > 0, requestCount, totalWatcherFees, r, payloadParams); + emit RequestSubmitted( + r.writeCount > 0, + requestCount, + totalEstimatedWatcherFees, + r, + payloadParams + ); } // called by auction manager when a auction ends or a new transmitter is assigned (bid expiry) @@ -114,20 +119,21 @@ contract RequestHandler is WatcherBase { ) external isRequestCancelled(requestCount_) { RequestParams storage r = requestParams[requestCount_]; if (r.auctionManager != msg.sender) revert InvalidCaller(); - if (r.writeCount == 0) revert NoWriteRequest(); + if (r.requestTrackingParams.isRequestExecuted) revert RequestAlreadySettled(); + if (r.writeCount == 0) revert NoWriteRequest(); if (r.requestFeesDetails.winningBid.transmitter == bid_.transmitter) - revert AlreadyStarted(); + revert AlreadyAssigned(); if (r.requestFeesDetails.winningBid.transmitter != address(0)) { feesManager__().unblockCredits(requestCount_); } - r.requestFeesDetails.winningBid = bid_; + r.requestFeesDetails.winningBid = bid_; if (bid_.transmitter == address(0)) return; feesManager__().blockCredits(requestCount_, r.requestFeesDetails.consumeFrom, bid_.fees); - // re-finalize current batch again or finalize the batch for the first time + // re-process current batch again or process the batch for the first time _processBatch(requestCount_, r.requestTrackingParams.currentBatch, r); } @@ -138,7 +144,7 @@ contract RequestHandler is WatcherBase { ) internal returns ( - uint256 totalWatcherFees, + uint256 totalEstimatedWatcherFees, uint256 writeCount, address[] memory promiseList, PayloadParams[] memory payloadParams @@ -170,12 +176,12 @@ contract RequestHandler is WatcherBase { ); // process payload data and store - (uint256 fees, bytes memory precompileData) = _validateAndGetPrecompileData( + (uint256 estimatedFees, bytes memory precompileData) = _validateAndGetPrecompileData( queuePayloadParam, appGateway_, callType ); - totalWatcherFees += fees; + totalEstimatedWatcherFees += estimatedFees; // create payload id uint40 payloadCount = payloadCounter++; @@ -234,32 +240,28 @@ contract RequestHandler is WatcherBase { uint40 batchCount_, RequestParams storage r ) internal { - if (r.requestTrackingParams.isRequestExecuted) return; - bytes32[] memory payloadIds = batchPayloadIds[batchCount_]; - uint256 totalPayloads = 0; uint256 totalFees = 0; + uint256 fees; + for (uint40 i = 0; i < payloadIds.length; i++) { bytes32 payloadId = payloadIds[i]; - // check needed for re-finalize, in case a payload is already executed by last transmitter - if (isPromiseExecuted[payloadId]) continue; - totalPayloads++; + // check needed for re-process, in case a payload is already executed by last transmitter + if (!isPromiseExecuted[payloadId]) continue; - PayloadParams storage payloadParams = payloads[payloadId]; - uint256 deadline = block.timestamp + expiryTime; - payloadParams.deadline = deadline; + // todo: move it to write precompile + // payloadParams.deadline = block.timestamp + expiryTime; - uint256 fees = IPrecompile(precompiles[payloadParams.callType]).handlePayload( + PayloadParams storage payloadParams = payloads[payloadId]; + (fees, payloadParams) = IPrecompile(precompiles[payloadParams.callType]).handlePayload( r.requestFeesDetails.winningBid.transmitter, payloadParams ); totalFees += fees; } - r.requestTrackingParams.currentBatchPayloadsLeft = totalPayloads; - address watcherFeesPayer = r.requestFeesDetails.winningBid.transmitter == address(0) ? r.requestFeesDetails.consumeFrom : r.requestFeesDetails.winningBid.transmitter; diff --git a/contracts/evmx/watcher/precompiles/ReadPrecompile.sol b/contracts/evmx/watcher/precompiles/ReadPrecompile.sol index c89aedbf..4b0452d9 100644 --- a/contracts/evmx/watcher/precompiles/ReadPrecompile.sol +++ b/contracts/evmx/watcher/precompiles/ReadPrecompile.sol @@ -12,17 +12,17 @@ contract ReadPrecompile is IPrecompile, WatcherBase { /// @notice Emitted when a new read is requested event ReadRequested(PayloadParams params); + /// @notice The fees for a read and includes callback fees uint256 public readFees; - uint256 public callbackFees; /// @notice Gets precompile data and fees for queue parameters /// @param queuePayloadParams_ The queue parameters to process /// @return precompileData The encoded precompile data - /// @return fees Estimated fees required for processing + /// @return estimatedFees Estimated fees required for processing function validateAndGetPrecompileData( QueueParams calldata queuePayloadParams_, address - ) external view returns (bytes memory precompileData, uint256 fees) { + ) external view returns (bytes memory precompileData, uint256 estimatedFees) { if (queuePayloadParams_.transaction.target != address(0)) revert InvalidTarget(); if (queuePayloadParams_.transaction.payload.length > 0) revert InvalidPayloadSize(); @@ -31,22 +31,27 @@ contract ReadPrecompile is IPrecompile, WatcherBase { queuePayloadParams_.transaction, queuePayloadParams_.overrideParams.readAtBlockNumber ); - fees = readFees + callbackFees; + estimatedFees = readFees; } /// @notice Handles payload processing and returns fees /// @param payloadParams The payload parameters to handle /// @return fees The fees required for processing function handlePayload( + address, PayloadParams calldata payloadParams ) external pure returns (uint256 fees) { - fees = readFees + callbackFees; - emit ReadRequested(payloadParams); + fees = readFees; + + (Transaction memory transaction, uint256 readAtBlockNumber) = abi.decode( + payloadParams.precompileData, + (Transaction, uint256) + ); + emit ReadRequested(transaction, readAtBlockNumber, payloadParams.payloadId); } - function setFees(uint256 readFees_, uint256 callbackFees_) external onlyWatcher { + function setFees(uint256 readFees_) external onlyWatcher { readFees = readFees_; - callbackFees = callbackFees_; - emit FeesSet(readFees_, callbackFees_); + emit FeesSet(readFees_); } } diff --git a/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol b/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol index 4ab3ad90..bc0d525c 100644 --- a/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol @@ -59,7 +59,7 @@ contract SchedulePrecompile is IPrecompile, WatcherBase { function validateAndGetPrecompileData( QueueParams calldata queuePayloadParams_, address appGateway_ - ) external view returns (bytes memory precompileData, uint256 fees) { + ) external view returns (bytes memory precompileData, uint256 estimatedFees) { if ( queuePayloadParams_.transaction.target != address(0) && appGateway_ != getCoreAppGateway(queuePayloadParams_.transaction.target) @@ -82,7 +82,7 @@ contract SchedulePrecompile is IPrecompile, WatcherBase { queuePayloadParams_.overrideParams.delayInSeconds ); - fees = + estimatedFees = scheduleFeesPerSecond * queuePayloadParams_.overrideParams.delayInSeconds + scheduleCallbackFees; diff --git a/contracts/utils/common/Structs.sol b/contracts/utils/common/Structs.sol index 51fe85e2..36d11199 100644 --- a/contracts/utils/common/Structs.sol +++ b/contracts/utils/common/Structs.sol @@ -180,15 +180,11 @@ struct PayloadParams { address appGateway; bytes32 payloadId; uint256 resolvedAt; // replaced isPromiseExecuted - uint256 deadline; bytes precompileData; - // bytes32 prevDigestsHash; - // address finalizedTransmitter; - // Transaction transaction; + // uint256 deadline; // OverrideParams overrideParams; // TimeoutRequest timeoutRequest; - // address switchboard; } // timeout: // struct TimeoutRequest { @@ -201,7 +197,6 @@ struct PayloadParams { struct RequestTrackingParams { bool isRequestCancelled; bool isRequestExecuted; // - uint40 firstBatchCount; // uint40 currentBatch; // uint256 currentBatchPayloadsLeft; // uint256 payloadsRemaining; // From 5d128a547167d4511c3013026f32467b85588b61 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 20 May 2025 15:58:31 +0530 Subject: [PATCH 028/130] fix: prev and current digest hash --- .../watcher/precompiles/WritePrecompile.sol | 64 ++++++++----------- 1 file changed, 28 insertions(+), 36 deletions(-) diff --git a/contracts/evmx/watcher/precompiles/WritePrecompile.sol b/contracts/evmx/watcher/precompiles/WritePrecompile.sol index 76988b18..d3ddc983 100644 --- a/contracts/evmx/watcher/precompiles/WritePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/WritePrecompile.sol @@ -18,10 +18,11 @@ contract WritePrecompile is IPrecompile, WatcherBase { /// @notice The maximum message value limit for a chain mapping(uint32 => uint256) public chainMaxMsgValueLimit; - /// @notice The fees for a write + /// @notice The digest hash for a payload + mapping(bytes32 => bytes32) public digestHashes; + + /// @notice The fees for a write and includes callback fees uint256 public writeFees; - /// @notice The callback fees for a write - uint256 public callbackFees; error MaxMsgValueLimitExceeded(); error InvalidTarget(); @@ -36,13 +37,15 @@ contract WritePrecompile is IPrecompile, WatcherBase { /// @notice Gets precompile data and fees for queue parameters /// @param queuePayloadParams_ The queue parameters to process /// @return precompileData The encoded precompile data - /// @return fees Estimated fees required for processing + /// @return estimatedFees Estimated fees required for processing function validateAndGetPrecompileData( QueueParams calldata queuePayloadParams_, address appGateway_ - ) external view returns (bytes memory precompileData, uint256 fees) { - if (queuePayloadParams_.value > chainMaxMsgValueLimit[queuePayloadParams_.chainSlug]) - revert MaxMsgValueLimitExceeded(); + ) external view returns (bytes memory precompileData, uint256 estimatedFees) { + if ( + queuePayloadParams_.value > + chainMaxMsgValueLimit[queuePayloadParams_.transaction.chainSlug] + ) revert MaxMsgValueLimitExceeded(); if (queuePayloadParams_.transaction.target != address(0)) { revert InvalidTarget(); @@ -56,7 +59,7 @@ contract WritePrecompile is IPrecompile, WatcherBase { } configurations__().verifyConnections( - queuePayloadParams_.chainSlug, + queuePayloadParams_.transaction.chainSlug, queuePayloadParams_.transaction.target, appGateway_, queuePayloadParams_.switchboardType @@ -70,7 +73,7 @@ contract WritePrecompile is IPrecompile, WatcherBase { queuePayloadParams_.overrideParams.value ); - fees = writeFees + callbackFees; + estimatedFees = writeFees; } /// @notice Handles payload processing and returns fees @@ -90,7 +93,7 @@ contract WritePrecompile is IPrecompile, WatcherBase { uint256 value ) = abi.decode(payloadParams.precompileData, (Transaction, bool, uint256, uint256)); - bytes32 prevDigestsHash = _getPreviousDigestsHash(payloadParams); + bytes32 prevBatchDigestHash = _getPrevBatchDigestHash(payloadParams); // create digest DigestParams memory digestParams_ = DigestParams( @@ -104,43 +107,33 @@ contract WritePrecompile is IPrecompile, WatcherBase { transaction.payload, transaction.target, WatcherIdUtils.encodeAppGatewayId(payloadParams.appGateway), - prevDigestsHash, + prevBatchDigestHash, bytes("") ); - // Calculate digest from payload parameters + // Calculate and store digest from payload parameters bytes32 digest = getDigest(digestParams_); - - // store digest and prev digest hash digestHashes[payloadParams.payloadId] = digest; - emit WriteRequested(digest, transaction, writeFinality, gasLimit, value); + + emit WriteProofRequested(digest, transaction, writeFinality, gasLimit, value); } - function _getPreviousDigestsHash( - PayloadParams memory payloadParams_ - ) internal view returns (bytes32) { - uint40 batchCount = payloadParams_.batchCount; + function _getPrevBatchDigestHash(uint40 batchCount_) internal view returns (bytes32) { + if (batchCount_ == 0) return bytes32(0); // if first batch, return bytes32(0) - uint40[] memory requestBatchIds = requestHandler__().requestBatchIds(batchCount); - if (requestBatchIds[0] == batchCount) return bytes32(0); - - // get previous digests hash from storage for last batchCount if already calculated - if (prevDigestsHashes[batchCount] != bytes32(0)) return prevDigestsHashes[batchCount]; + uint40[] memory requestBatchIds = requestHandler__().requestBatchIds(batchCount_); + if (requestBatchIds[0] == batchCount_) return bytes32(0); - // else calculate the previous digests hash - uint40 lastBatchCount = batchCount - 1; - bytes32[] memory payloadIds = requestHandler__().batchPayloadIds(lastBatchCount); + uint40 prevBatchCount = batchCount_ - 1; + bytes32[] memory payloadIds = requestHandler__().batchPayloadIds(prevBatchCount); bytes32 prevDigestsHash = bytes32(0); for (uint40 i = 0; i < payloadIds.length; i++) { prevDigestsHash = keccak256( abi.encodePacked(prevDigestsHash, digestHashes[payloadIds[i]]) ); } - - // store the previous digests hash - prevDigestsHashes[batchCount] = prevDigestsHash; return prevDigestsHash; } @@ -168,12 +161,12 @@ contract WritePrecompile is IPrecompile, WatcherBase { ); } - /// @notice Marks a write request as finalized with a proof on digest + /// @notice Marks a write request with a proof on digest /// @param payloadId_ The unique identifier of the request /// @param proof_ The watcher's proof - function finalize(bytes32 payloadId_, bytes memory proof_) public onlyWatcher { + function uploadProof(bytes32 payloadId_, bytes memory proof_) public onlyWatcher { watcherProofs[payloadId_] = proof_; - emit Finalized(payloadId_, proof_); + emit WriteProofUploaded(payloadId_, proof_); } /// @notice Updates the maximum message value limit for multiple chains @@ -192,9 +185,8 @@ contract WritePrecompile is IPrecompile, WatcherBase { emit ChainMaxMsgValueLimitsUpdated(chainSlugs_, maxMsgValueLimits_); } - function setFees(uint256 writeFees_, uint256 callbackFees_) external onlyWatcher { + function setFees(uint256 writeFees_) external onlyWatcher { writeFees = writeFees_; - callbackFees = callbackFees_; - emit FeesSet(writeFees_, callbackFees_); + emit FeesSet(writeFees_); } } From fca1660207c0247346efd6db1b71056baa463a38 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 20 May 2025 16:50:03 +0530 Subject: [PATCH 029/130] fix: todos --- .../evmx/app-gateways/AuctionManager.sol | 5 ++-- contracts/evmx/fees/UserUtils.sol | 25 ++++++++++--------- contracts/evmx/interfaces/IFeesManager.sol | 2 +- contracts/evmx/plugs/FeesPlug.sol | 4 +-- contracts/evmx/watcher/RequestHandler.sol | 9 +++---- 5 files changed, 21 insertions(+), 24 deletions(-) diff --git a/contracts/evmx/app-gateways/AuctionManager.sol b/contracts/evmx/app-gateways/AuctionManager.sol index 850677c5..6f1aa478 100644 --- a/contracts/evmx/app-gateways/AuctionManager.sol +++ b/contracts/evmx/app-gateways/AuctionManager.sol @@ -58,7 +58,7 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, error MaxReAuctionCountReached(); constructor() { - // todo: evmx slug can be immutable and set here + // todo-later: evmx slug can be immutable and set here _disableInitializers(); // disable for implementation } @@ -171,8 +171,7 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, auctionStatus[requestCount_] = AuctionStatus.CLOSED; if (winningBid.transmitter != address(0)) { - // todo: might block the request processing if transmitter don't have enough balance - // not implementing this for now + // todo-later: might block the request processing if transmitter don't have enough balance // set the timeout for the bid expiration // useful in case a transmitter did bid but did not execute payloads _createRequest( diff --git a/contracts/evmx/fees/UserUtils.sol b/contracts/evmx/fees/UserUtils.sol index c6694d1e..77ab20c6 100644 --- a/contracts/evmx/fees/UserUtils.sol +++ b/contracts/evmx/fees/UserUtils.sol @@ -79,7 +79,7 @@ abstract contract UserUtils is FeesStorage, Initializable, Ownable, AddressResol if (userCredit.totalCredits < amount_) revert InsufficientCreditsAvailable(); userCredit.totalCredits -= amount_; - // todo: if contract balance not enough, take from our pool? + // todo-later: if contract balance not enough, take from our pool? if (address(this).balance < amount_) revert InsufficientBalance(); payable(msg.sender).transfer(amount_); @@ -95,19 +95,23 @@ abstract contract UserUtils is FeesStorage, Initializable, Ownable, AddressResol } /// @notice Checks if the user has enough credits - /// @param consumeFrom_ The app gateway address - /// @param appGateway_ The app gateway address + /// @param from_ The app gateway address + /// @param to_ The app gateway address /// @param amount_ The amount /// @return True if the user has enough credits, false otherwise function isUserCreditsEnough( - address consumeFrom_, - address appGateway_, + address from_, + address to_, uint256 amount_ ) external view returns (bool) { - // If consumeFrom is not appGateway, check if it is whitelisted - if (consumeFrom_ != appGateway_ && !isAppGatewayWhitelisted[consumeFrom_][appGateway_]) - revert AppGatewayNotWhitelisted(); - return getAvailableCredits(consumeFrom_) >= amount_; + // If from_ is not same as to_ or to_ is not watcher, check if it is whitelisted + if ( + to_ != address(watcherPrecompile__()) && + from_ != to_ && + !isAppGatewayWhitelisted[from_][to_] + ) revert AppGatewayNotWhitelisted(); + + return getAvailableCredits(from_) >= amount_; } function _updateUserCredits( @@ -120,10 +124,7 @@ abstract contract UserUtils is FeesStorage, Initializable, Ownable, AddressResol userCredit.totalCredits -= toConsumeFromTotal_; } - // todo: if watcher, don't check whitelist function transferCredits(address from_, address to_, uint256 amount_) external { - if (!isAppGatewayWhitelisted[from_][to_]) revert AppGatewayNotWhitelisted(); - if (!isUserCreditsEnough(from_, to_, amount_)) revert InsufficientCreditsAvailable(); userCredits[from_].totalCredits -= amount_; userCredits[to_].totalCredits += amount_; diff --git a/contracts/evmx/interfaces/IFeesManager.sol b/contracts/evmx/interfaces/IFeesManager.sol index af2e71a7..178101ed 100644 --- a/contracts/evmx/interfaces/IFeesManager.sol +++ b/contracts/evmx/interfaces/IFeesManager.sol @@ -18,7 +18,7 @@ interface IFeesManager { function getAvailableCredits(address user) external view returns (uint256); // withdraw credits onchain - // finalize and release sign, no AM needed, can be used by watcher and transmitter + // process and release sign, no AM needed, can be used by watcher and transmitter function withdrawCreditsTo( uint32 chainSlug, address to, diff --git a/contracts/evmx/plugs/FeesPlug.sol b/contracts/evmx/plugs/FeesPlug.sol index a10b5616..5caa2480 100644 --- a/contracts/evmx/plugs/FeesPlug.sol +++ b/contracts/evmx/plugs/FeesPlug.sol @@ -41,7 +41,7 @@ contract FeesPlug is IFeesPlug, PlugBase, AccessControl { event TokenRemovedFromWhitelist(address token); /// @notice Modifier to check if the balance of a token is enough to withdraw - modifier isUserCreditsEnough(address feeToken_, uint256 fee_) { + modifier isBalanceEnough(address feeToken_, uint256 fee_) { uint balance_ = ERC20(feeToken_).balanceOf(address(this)); if (balance_ < fee_) revert InsufficientTokenBalance(feeToken_, balance_, fee_); _; @@ -63,7 +63,7 @@ contract FeesPlug is IFeesPlug, PlugBase, AccessControl { address token_, address receiver_, uint256 amount_ - ) external override onlySocket isUserCreditsEnough(token_, amount_) { + ) external override onlySocket isBalanceEnough(token_, amount_) { SafeTransferLib.safeTransfer(token_, receiver_, amount_); emit FeesWithdrawn(token_, receiver_, amount_); } diff --git a/contracts/evmx/watcher/RequestHandler.sol b/contracts/evmx/watcher/RequestHandler.sol index 32b17c6a..2c752f59 100644 --- a/contracts/evmx/watcher/RequestHandler.sol +++ b/contracts/evmx/watcher/RequestHandler.sol @@ -243,19 +243,16 @@ contract RequestHandler is WatcherBase { bytes32[] memory payloadIds = batchPayloadIds[batchCount_]; uint256 totalFees = 0; - uint256 fees; - for (uint40 i = 0; i < payloadIds.length; i++) { bytes32 payloadId = payloadIds[i]; // check needed for re-process, in case a payload is already executed by last transmitter if (!isPromiseExecuted[payloadId]) continue; - // todo: move it to write precompile - // payloadParams.deadline = block.timestamp + expiryTime; - PayloadParams storage payloadParams = payloads[payloadId]; - (fees, payloadParams) = IPrecompile(precompiles[payloadParams.callType]).handlePayload( + payloadParams.deadline = block.timestamp + expiryTime; + + uint256 fees = IPrecompile(precompiles[payloadParams.callType]).handlePayload( r.requestFeesDetails.winningBid.transmitter, payloadParams ); From b74c7dce9b5a30a6cfca7f6eaff90dc0251a3211 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 20 May 2025 17:28:46 +0530 Subject: [PATCH 030/130] feat: trigger as part of watcher --- contracts/evmx/interfaces/IWatcher.sol | 4 +-- contracts/evmx/watcher/Trigger.sol | 31 +++++------------ contracts/evmx/watcher/Watcher.sol | 42 ++--------------------- contracts/evmx/watcher/WatcherStorage.sol | 38 ++++++++++++++++++++ 4 files changed, 51 insertions(+), 64 deletions(-) create mode 100644 contracts/evmx/watcher/WatcherStorage.sol diff --git a/contracts/evmx/interfaces/IWatcher.sol b/contracts/evmx/interfaces/IWatcher.sol index 10ed34db..14b8a29f 100644 --- a/contracts/evmx/interfaces/IWatcher.sol +++ b/contracts/evmx/interfaces/IWatcher.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; - -import {PayloadParams, RequestParams, QueueParams, Bid} from "../../utils/common/Structs.sol"; +import {TriggerParams, ResolvedPromises, AppGatewayConfig, LimitParams, WriteFinality, UpdateLimitParams, PlugConfig, DigestParams, QueueParams, PayloadParams, RequestParams} from "../../utils/common/Structs.sol"; +import {InvalidCallerTriggered, TimeoutDelayTooLarge, TimeoutAlreadyResolved, InvalidInboxCaller, ResolvingTimeoutTooEarly, CallFailed, AppGatewayAlreadyCalled, InvalidWatcherSignature, NonceUsed, RequestAlreadyExecuted} from "../../utils/common/Errors.sol"; /// @title IWatcher /// @notice Interface for the Watcher Precompile system that handles payload verification and execution diff --git a/contracts/evmx/watcher/Trigger.sol b/contracts/evmx/watcher/Trigger.sol index d9898d93..0c1af2e5 100644 --- a/contracts/evmx/watcher/Trigger.sol +++ b/contracts/evmx/watcher/Trigger.sol @@ -1,51 +1,37 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import {TriggerParams} from "../../utils/common/Structs.sol"; -import {InvalidCallerTriggered, AppGatewayAlreadyCalled} from "../../utils/common/Errors.sol"; - -import "./WatcherBase.sol"; -import "../helpers/AddressResolverUtil.sol"; - +import "./WatcherStorage.sol"; /// @title Trigger /// @notice Contract that handles trigger validation and execution logic /// @dev This contract interacts with the WatcherPrecompileStorage for storage access -contract Trigger is WatcherBase, AddressResolverUtil { +abstract contract Trigger is WatcherStorage { /// @notice stores temporary address of the app gateway caller from a chain address public appGatewayCaller; - /// @notice Stores the trigger fees uint256 public triggerFees; - /// @notice Mapping to store if appGateway has been called with trigger from on-chain Inbox /// @dev Maps call ID to boolean indicating if the appGateway has been called /// @dev callId => bool mapping(bytes32 => bool) public appGatewayCalled; - /// @notice Sets the Watcher address - /// @param watcher_ The address of the WatcherPrecompileStorage contract - constructor(address watcher_) WatcherBase(watcher_) {} - /// @notice Sets the trigger fees /// @param triggerFees_ The amount of fees to set - function setTriggerFees(uint256 triggerFees_) external onlyWatcher { + function setTriggerFees(uint256 triggerFees_) external onlyOwner { triggerFees = triggerFees_; } /// @notice Calls app gateways with the specified parameters /// @param params_ Array of call from chain parameters /// @dev This function calls app gateways with the specified parameters - function callAppGateways(TriggerParams memory params_) external onlyWatcher { + function _callAppGateways(TriggerParams memory params_) internal onlyOwner { if (appGatewayCalled[params_.triggerId]) revert AppGatewayAlreadyCalled(); - address appGateway = WatcherIdUtils.decodeAppGatewayId(params_.appGatewayId); - if (!watcherPrecompileConfig__.isValidPlug(appGateway, params_.chainSlug, params_.plug)) + if (!configurations__().isValidPlug(params_.appGatewayId, params_.chainSlug, params_.plug)) revert InvalidCallerTriggered(); - feesManager__().assignWatcherPrecompileCreditsFromAddress(triggerFees, appGateway); - - // todo: store and update in watcher contract - // appGatewayCaller = appGateway; + feesManager__().transferFrom(appGateway, address(this), triggerFees); + appGatewayCaller = appGateway; appGatewayCalled[params_.triggerId] = true; (bool success, , ) = appGateway.tryCall( @@ -60,7 +46,6 @@ contract Trigger is WatcherBase, AddressResolverUtil { emit CalledAppGateway(params_.triggerId); } - // todo: store and update in watcher contract - // appGatewayCaller = address(0); + appGatewayCaller = address(0); } } diff --git a/contracts/evmx/watcher/Watcher.sol b/contracts/evmx/watcher/Watcher.sol index f554e700..73aa7813 100644 --- a/contracts/evmx/watcher/Watcher.sol +++ b/contracts/evmx/watcher/Watcher.sol @@ -1,45 +1,9 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import "../interfaces/IWatcher.sol"; -import {InvalidCallerTriggered, TimeoutDelayTooLarge, TimeoutAlreadyResolved, InvalidInboxCaller, ResolvingTimeoutTooEarly, CallFailed, AppGatewayAlreadyCalled, InvalidWatcherSignature, NonceUsed, RequestAlreadyExecuted} from "../../utils/common/Errors.sol"; -import {ResolvedPromises, AppGatewayConfig, LimitParams, WriteFinality, UpdateLimitParams, PlugConfig, DigestParams, TimeoutRequest, QueueParams, PayloadParams, RequestParams} from "../../utils/common/Structs.sol"; - -/// @title WatcherStorage -/// @notice Storage contract for the WatcherPrecompile system -/// @dev This contract contains all the storage variables used by the WatcherPrecompile system -/// @dev It is inherited by WatcherPrecompileCore and WatcherPrecompile -abstract contract WatcherStorage is IWatcher { - // slots [0-49]: gap for future storage variables - uint256[50] _gap_before; - - // slot 50 - /// @notice The chain slug of the watcher precompile - uint32 public evmxSlug; - - // Payload Params - /// @notice The time from queue for the payload to be executed - /// @dev Expiry time in seconds for payload execution - uint256 public expiryTime; - - /// @notice Maps nonce to whether it has been used - /// @dev Used to prevent replay attacks with signature nonces - /// @dev signatureNonce => isValid - mapping(uint256 => bool) public isNonceUsed; - - /// @notice The queue of payloads - QueueParams[] public payloadQueue; - address public latestAsyncPromise; - address public appGatewayTemp; - - // slots [51-100]: gap for future storage variables - uint256[50] _gap_after; - - // slots 115-165 (51) reserved for access control - // slots 166-216 (51) reserved for addr resolver util -} +import "./Trigger.sol"; -contract Watcher is WatcherStorage { +contract Watcher is Trigger { IRequestHandler public requestHandler__; IConfigManager public configManager__; IPromiseResolver public promiseResolver__; @@ -148,7 +112,7 @@ contract Watcher is WatcherStorage { /// @param expiryTime_ The expiry time in seconds /// @dev This function sets the expiry time for payload execution /// @dev Only callable by the contract owner - function setExpiryTime(uint256 expiryTime_) external { + function setExpiryTime(uint256 expiryTime_) external onlyOwner { expiryTime = expiryTime_; emit ExpiryTimeSet(expiryTime_); } diff --git a/contracts/evmx/watcher/WatcherStorage.sol b/contracts/evmx/watcher/WatcherStorage.sol new file mode 100644 index 00000000..91336b93 --- /dev/null +++ b/contracts/evmx/watcher/WatcherStorage.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import "../interfaces/IWatcher.sol"; + +/// @title WatcherStorage +/// @notice Storage contract for the WatcherPrecompile system +/// @dev This contract contains all the storage variables used by the WatcherPrecompile system +/// @dev It is inherited by WatcherPrecompileCore and WatcherPrecompile +abstract contract WatcherStorage is IWatcher { + // slots [0-49]: gap for future storage variables + uint256[50] _gap_before; + + // slot 50 + /// @notice The chain slug of the watcher precompile + uint32 public evmxSlug; + + // Payload Params + /// @notice The time from queue for the payload to be executed + /// @dev Expiry time in seconds for payload execution + uint256 public expiryTime; + + /// @notice Maps nonce to whether it has been used + /// @dev Used to prevent replay attacks with signature nonces + /// @dev signatureNonce => isValid + mapping(uint256 => bool) public isNonceUsed; + + /// @notice The queue of payloads + QueueParams[] public payloadQueue; + address public latestAsyncPromise; + address public appGatewayTemp; + + // slots [51-100]: gap for future storage variables + uint256[50] _gap_after; + + // slots 115-165 (51) reserved for access control + // slots 166-216 (51) reserved for addr resolver util +} From 6e4b2a1f1dfe4a493b4de067d8520d3967175415 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 20 May 2025 17:36:32 +0530 Subject: [PATCH 031/130] feat: cancel req and increase fees --- contracts/evmx/base/AppGatewayBase.sol | 16 ++--- contracts/evmx/watcher/RequestHandler.sol | 74 ++++++++++------------- contracts/evmx/watcher/Watcher.sol | 2 +- 3 files changed, 36 insertions(+), 56 deletions(-) diff --git a/contracts/evmx/base/AppGatewayBase.sol b/contracts/evmx/base/AppGatewayBase.sol index 526138f6..bd9933f0 100644 --- a/contracts/evmx/base/AppGatewayBase.sol +++ b/contracts/evmx/base/AppGatewayBase.sol @@ -170,8 +170,7 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { return address(0); } - onChainAddress = IForwarder(forwarderAddresses[contractId_][chainSlug_]) - .getOnChainAddress(); + onChainAddress = IForwarder(forwarderAddresses[contractId_][chainSlug_]).getOnChainAddress(); } function _setCallType(Read isReadCall_) internal { @@ -295,13 +294,13 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { /// @notice Reverts the transaction /// @param requestCount_ The async ID function _revertTx(uint40 requestCount_) internal { - deliveryHelper__().cancelRequest(requestCount_); + watcher__().cancelRequest(requestCount_); } /// @notice increases the transaction maxFees /// @param requestCount_ The async ID function _increaseFees(uint40 requestCount_, uint256 newMaxFees_) internal { - deliveryHelper__().increaseFees(requestCount_, newMaxFees_); + watcher__().increaseFees(requestCount_, newMaxFees_); } /// @notice Withdraws fee tokens @@ -316,14 +315,7 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { address receiver_ ) internal returns (uint40) { return - deliveryHelper__().withdrawTo( - chainSlug_, - token_, - amount_, - receiver_, - auctionManager, - maxFees - ); + watcher__().withdrawTo(chainSlug_, token_, amount_, receiver_, auctionManager, maxFees); } //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/contracts/evmx/watcher/RequestHandler.sol b/contracts/evmx/watcher/RequestHandler.sol index 2c752f59..a5603ade 100644 --- a/contracts/evmx/watcher/RequestHandler.sol +++ b/contracts/evmx/watcher/RequestHandler.sol @@ -265,6 +265,22 @@ contract RequestHandler is WatcherBase { feesManager__().transferCredits(watcherFeesPayer, address(this), totalFees); } + /// @notice Increases the fees for a request if no bid is placed + /// @param requestCount_ The ID of the request + /// @param newMaxFees_ The new maximum fees + function increaseFees(uint40 requestCount_, uint256 newMaxFees_) external { + RequestParams storage r = requestParams[requestCount_]; + address appGateway = _getCoreAppGateway(msg.sender); + + if (appGateway != r.appGateway) revert OnlyAppGateway(); + if (r.requestFeesDetails.winningBid.transmitter != address(0)) revert WinningBidExists(); + if (r.requestFeesDetails.maxFees >= newMaxFees_) + revert NewMaxFeesLowerThanCurrent(r.requestFeesDetails.maxFees, newMaxFees_); + + r.requestFeesDetails.maxFees = newMaxFees_; + emit FeesIncreased(appGateway, requestCount_, newMaxFees_); + } + function markPayloadExecutedAndProcessBatch( uint40 requestCount_, bytes32 payloadId_ @@ -285,6 +301,21 @@ contract RequestHandler is WatcherBase { _processBatch(requestCount_, r.requestTrackingParams.currentBatch_, r); } + /// @notice Cancels a request + /// @param requestCount The request count to cancel + /// @dev This function cancels a request + /// @dev It verifies that the caller is the middleware and that the request hasn't been cancelled yet + function cancelRequest(uint40 requestCount) external { + RequestParams storage r = requestParams[requestCount]; + if (r.isRequestCancelled) revert RequestAlreadyCancelled(); + if (r.appGateway != getCoreAppGateway(msg.sender)) revert InvalidCaller(); + + r.isRequestCancelled = true; + + _settleRequest(requestCount, r); + emit RequestCancelled(requestCount); + } + function _settleRequest(uint40 requestCount_, RequestParams storage r) internal { if (r.requestTrackingParams.isRequestExecuted) return; r.requestTrackingParams.isRequestExecuted = true; @@ -305,46 +336,3 @@ contract RequestHandler is WatcherBase { emit RequestSettled(requestCount_, r.requestFeesDetails.winningBid.transmitter); } } - -// /// @notice Increases the fees for a request if no bid is placed -// /// @param requestCount_ The ID of the request -// /// @param newMaxFees_ The new maximum fees -// function increaseFees(uint40 requestCount_, uint256 newMaxFees_) external override { -// address appGateway = _getCoreAppGateway(msg.sender); -// // todo: should we allow core app gateway too? -// if (appGateway != requests[requestCount_].appGateway) { -// revert OnlyAppGateway(); -// } -// if (requests[requestCount_].winningBid.transmitter != address(0)) revert WinningBidExists(); -// if (requests[requestCount_].maxFees >= newMaxFees_) -// revert NewMaxFeesLowerThanCurrent(requests[requestCount_].maxFees, newMaxFees_); -// requests[requestCount_].maxFees = newMaxFees_; -// emit FeesIncreased(appGateway, requestCount_, newMaxFees_); -// } - -// /// @notice Cancels a request -// /// @param requestCount The request count to cancel -// /// @dev This function cancels a request -// /// @dev It verifies that the caller is the middleware and that the request hasn't been cancelled yet -// function cancelRequest(uint40 requestCount) external { -// RequestParams storage r = requestParams[requestCount]; -// if (r.isRequestCancelled) revert RequestAlreadyCancelled(); -// if (r.middleware != msg.sender) revert InvalidCaller(); - -// r.isRequestCancelled = true; -// emit RequestCancelledFromGateway(requestCount); -// } - -// /// @notice Cancels a request and settles the fees -// /// @dev if no transmitter was assigned, fees is unblocked to app gateway -// /// @dev Only app gateway can call this function -// /// @param requestCount_ The ID of the request -// function cancelRequest(uint40 requestCount_) external { -// if (msg.sender != requests[requestCount_].appGateway) { -// revert OnlyAppGateway(); -// } - -// _settleFees(requestCount_); -// watcherPrecompile__().cancelRequest(requestCount_); -// emit RequestCancelled(requestCount_); -// } diff --git a/contracts/evmx/watcher/Watcher.sol b/contracts/evmx/watcher/Watcher.sol index f554e700..6324c67b 100644 --- a/contracts/evmx/watcher/Watcher.sol +++ b/contracts/evmx/watcher/Watcher.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.21; import "../interfaces/IWatcher.sol"; import {InvalidCallerTriggered, TimeoutDelayTooLarge, TimeoutAlreadyResolved, InvalidInboxCaller, ResolvingTimeoutTooEarly, CallFailed, AppGatewayAlreadyCalled, InvalidWatcherSignature, NonceUsed, RequestAlreadyExecuted} from "../../utils/common/Errors.sol"; -import {ResolvedPromises, AppGatewayConfig, LimitParams, WriteFinality, UpdateLimitParams, PlugConfig, DigestParams, TimeoutRequest, QueueParams, PayloadParams, RequestParams} from "../../utils/common/Structs.sol"; +import {ResolvedPromises, AppGatewayConfig, LimitParams, WriteFinality, UpdateLimitParams, PlugConfig, DigestParams, QueueParams, PayloadParams, RequestParams} from "../../utils/common/Structs.sol"; /// @title WatcherStorage /// @notice Storage contract for the WatcherPrecompile system From c4bc5b79bd0ed09725bb3f85d794ac050aa1e874 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 20 May 2025 18:33:28 +0530 Subject: [PATCH 032/130] fix: addr resolver and async deployer --- contracts/evmx/helpers/AddressResolver.sol | 24 ++++------- .../evmx/helpers/AddressResolverUtil.sol | 7 ++-- contracts/evmx/helpers/AsyncDeployer.sol | 4 +- .../evmx/interfaces/IAddressResolver.sol | 42 +++++-------------- contracts/evmx/interfaces/IAsyncDeployer.sol | 15 +++++++ 5 files changed, 40 insertions(+), 52 deletions(-) diff --git a/contracts/evmx/helpers/AddressResolver.sol b/contracts/evmx/helpers/AddressResolver.sol index 3956d71c..22f74eb4 100644 --- a/contracts/evmx/helpers/AddressResolver.sol +++ b/contracts/evmx/helpers/AddressResolver.sol @@ -4,19 +4,16 @@ pragma solidity ^0.8.21; import {Ownable} from "solady/auth/Ownable.sol"; import {Initializable} from "solady/utils/Initializable.sol"; import "./interfaces/IAddressResolver.sol"; -import "./interfaces/IWatcher.sol"; -import "./interfaces/IFeesManager.sol"; -import "./interfaces/IDefaultAuctionManager.sol"; -import "./interfaces/IAsyncDeployer.sol"; abstract contract AddressResolverStorage is IAddressResolver { // slots [0-49] reserved for gap uint256[50] _gap_before; - IWatcher public override watcherPrecompile__; + IWatcher public override watcher__; IFeesManager public override feesManager; IAsyncDeployer public override asyncDeployer; - IDefaultAuctionManager public override defaultAuctionManager; + + address public override defaultAuctionManager; // slots [61-110] reserved for gap uint256[50] _gap_after; @@ -29,11 +26,6 @@ contract AddressResolver is AddressResolverStorage, Initializable, Ownable { /// @notice Error thrown if AppGateway contract was already set by a different address error InvalidAppGateway(address contractAddress_); - /// @notice Event emitted when the fees manager is updated - event FeesManagerUpdated(address feesManager_); - /// @notice Event emitted when the watcher precompile is updated - event WatcherPrecompileUpdated(address watcherPrecompile_); - constructor() { _disableInitializers(); // disable for implementation } @@ -57,15 +49,15 @@ contract AddressResolver is AddressResolverStorage, Initializable, Ownable { /// @notice Updates the address of the default auction manager /// @param defaultAuctionManager_ The address of the default auction manager function setDefaultAuctionManager(address defaultAuctionManager_) external onlyOwner { - defaultAuctionManager = IDefaultAuctionManager(defaultAuctionManager_); + defaultAuctionManager = defaultAuctionManager_; emit DefaultAuctionManagerUpdated(defaultAuctionManager_); } /// @notice Updates the address of the watcher precompile contract - /// @param watcherPrecompile_ The address of the watcher precompile contract - function setWatcherPrecompile(address watcherPrecompile_) external onlyOwner { - watcherPrecompile__ = IWatcher(watcherPrecompile_); - emit WatcherPrecompileUpdated(watcherPrecompile_); + /// @param watcher_ The address of the watcher precompile contract + function setWatcher(address watcher_) external onlyOwner { + watcher__ = IWatcher(watcher_); + emit WatcherUpdated(watcher_); } /// @notice Returns the address of the async deployer diff --git a/contracts/evmx/helpers/AddressResolverUtil.sol b/contracts/evmx/helpers/AddressResolverUtil.sol index e1990623..aa095277 100644 --- a/contracts/evmx/helpers/AddressResolverUtil.sol +++ b/contracts/evmx/helpers/AddressResolverUtil.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.21; import "../interfaces/IAddressResolver.sol"; import "../interfaces/IWatcher.sol"; import "../interfaces/IFeesManager.sol"; +import "../interfaces/IAsyncDeployer.sol"; /// @title AddressResolverUtil /// @notice Utility contract for resolving system contract addresses @@ -23,7 +24,7 @@ abstract contract AddressResolverBase { /// @notice Restricts function access to the watcher precompile contract /// @dev Validates that msg.sender matches the registered watcher precompile address modifier onlyWatcher() { - if (msg.sender != address(addressResolver__.watcherPrecompile__())) { + if (msg.sender != address(addressResolver__.watcher__())) { revert onlyWatcherAllowed(); } @@ -33,8 +34,8 @@ abstract contract AddressResolverBase { /// @notice Gets the watcher precompile contract interface /// @return IWatcher interface of the registered watcher precompile /// @dev Resolves and returns the watcher precompile contract for interaction - function watcherPrecompile__() public view returns (IWatcher) { - return addressResolver__.watcherPrecompile__(); + function watcher__() public view returns (IWatcher) { + return addressResolver__.watcher__(); } /// @notice Gets the watcher precompile contract interface diff --git a/contracts/evmx/helpers/AsyncDeployer.sol b/contracts/evmx/helpers/AsyncDeployer.sol index 42e47f7f..c33c12f4 100644 --- a/contracts/evmx/helpers/AsyncDeployer.sol +++ b/contracts/evmx/helpers/AsyncDeployer.sol @@ -5,11 +5,11 @@ import {Ownable} from "solady/auth/Ownable.sol"; import {LibClone} from "solady/utils/LibClone.sol"; import {UpgradeableBeacon} from "solady/utils/UpgradeableBeacon.sol"; import {Initializable} from "solady/utils/Initializable.sol"; -import "./interfaces/IAddressResolver.sol"; +import "./interfaces/IAsyncDeployer.sol"; import {Forwarder} from "./Forwarder.sol"; import {AsyncPromise} from "./AsyncPromise.sol"; -abstract contract AsyncDeployerStorage is IAddressResolver { +abstract contract AsyncDeployerStorage is IAsyncDeployer { // slots [0-49] reserved for gap uint256[50] _gap_before; diff --git a/contracts/evmx/interfaces/IAddressResolver.sol b/contracts/evmx/interfaces/IAddressResolver.sol index 3871ed52..cf2f58f2 100644 --- a/contracts/evmx/interfaces/IAddressResolver.sol +++ b/contracts/evmx/interfaces/IAddressResolver.sol @@ -1,37 +1,17 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; import "./IWatcher.sol"; +import "./IFeesManager.sol"; +import "./IAsyncDeployer.sol"; /// @title IAddressResolver /// @notice Interface for resolving system contract addresses /// @dev Provides address lookup functionality for core system components interface IAddressResolver { - /// @notice Emitted when a new address is set in the resolver - /// @param name The identifier of the contract - /// @param oldAddress The previous address of the contract - /// @param newAddress The new address of the contract - event AddressSet(bytes32 indexed name, address oldAddress, address newAddress); - - /// @notice Emitted when a new plug is added to the resolver - /// @param appGateway The address of the app gateway - /// @param chainSlug The chain slug - /// @param plug The address of the plug - event PlugAdded(address appGateway, uint32 chainSlug, address plug); - - /// @notice Emitted when a new forwarder is deployed - /// @param newForwarder The address of the new forwarder - /// @param salt The salt used to deploy the forwarder - event ForwarderDeployed(address newForwarder, bytes32 salt); - - /// @notice Emitted when a new async promise is deployed - /// @param newAsyncPromise The address of the new async promise - /// @param salt The salt used to deploy the async promise - event AsyncPromiseDeployed(address newAsyncPromise, bytes32 salt); - - /// @notice Emitted when an implementation is updated - /// @param contractName The name of the contract - /// @param newImplementation The new implementation address - event ImplementationUpdated(string contractName, address newImplementation); + /// @notice Event emitted when the fees manager is updated + event FeesManagerUpdated(address feesManager_); + /// @notice Event emitted when the watcher precompile is updated + event WatcherUpdated(address watcher_); // any other address resolution function getAddress(bytes32 name) external view returns (address); @@ -39,19 +19,19 @@ interface IAddressResolver { function setAddress(bytes32 name, address addr) external; // System component addresses - function getWatcherPrecompile() external view returns (address); + function watcher__() external view returns (IWatcher); - function getFeesManager() external view returns (address); + function feesManager__() external view returns (IFeesManager); - function getDefaultAuctionManager() external view returns (address); + function asyncDeployer__() external view returns (IAsyncDeployer); - function getAsyncDeployer() external view returns (address); + function defaultAuctionManager() external view returns (address); function setFeesManager(address feesManager_) external; function setDefaultAuctionManager(address defaultAuctionManager_) external; - function setWatcherPrecompile(address watcherPrecompile_) external; + function setWatcher(address watcher_) external; function setAsyncDeployer(address asyncDeployer_) external; } diff --git a/contracts/evmx/interfaces/IAsyncDeployer.sol b/contracts/evmx/interfaces/IAsyncDeployer.sol index f2699a36..9e9fad28 100644 --- a/contracts/evmx/interfaces/IAsyncDeployer.sol +++ b/contracts/evmx/interfaces/IAsyncDeployer.sol @@ -5,6 +5,21 @@ pragma solidity ^0.8.21; /// @notice Interface for deploying Forwarder and AsyncPromise contracts /// @dev Provides address lookup functionality for core system components interface IAsyncDeployer { + /// @notice Emitted when a new forwarder is deployed + /// @param newForwarder The address of the new forwarder + /// @param salt The salt used to deploy the forwarder + event ForwarderDeployed(address newForwarder, bytes32 salt); + + /// @notice Emitted when a new async promise is deployed + /// @param newAsyncPromise The address of the new async promise + /// @param salt The salt used to deploy the async promise + event AsyncPromiseDeployed(address newAsyncPromise, bytes32 salt); + + /// @notice Emitted when an implementation is updated + /// @param contractName The name of the contract + /// @param newImplementation The new implementation address + event ImplementationUpdated(string contractName, address newImplementation); + // Forwarder Management function getOrDeployForwarderContract( address appGateway_, From 035a08a487f5fca99c73abbf000b948ff1e691f8 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Wed, 21 May 2025 14:20:30 +0530 Subject: [PATCH 033/130] fix: review fixes --- contracts/evmx/helpers/AsyncPromise.sol | 94 ++++++++++--------- contracts/evmx/interfaces/IPromise.sol | 3 - contracts/evmx/watcher/PromiseResolver.sol | 3 +- contracts/evmx/watcher/Trigger.sol | 3 +- contracts/evmx/watcher/Watcher.sol | 4 +- .../precompiles/SchedulePrecompile.sol | 2 +- contracts/protocol/Socket.sol | 2 + contracts/utils/common/Errors.sol | 5 + contracts/utils/common/Structs.sol | 2 +- 9 files changed, 67 insertions(+), 51 deletions(-) diff --git a/contracts/evmx/helpers/AsyncPromise.sol b/contracts/evmx/helpers/AsyncPromise.sol index 3271366d..4caf173e 100644 --- a/contracts/evmx/helpers/AsyncPromise.sol +++ b/contracts/evmx/helpers/AsyncPromise.sol @@ -67,50 +67,63 @@ contract AsyncPromise is AsyncPromiseStorage, Initializable, AddressResolverUtil /// @dev Only callable by the watcher precompile. /// @param returnData_ The data returned from the async payload execution. function markResolved( - uint40 requestCount_, + bool exceededMaxCopy_, bytes32 payloadId_, bytes memory returnData_ ) external override onlyWatcher returns (bool success) { - if (resolved) revert PromiseAlreadyResolved(); - - resolved = true; + if ( + state == AsyncPromiseState.CALLBACK_REVERTING || + state == AsyncPromiseState.ONCHAIN_REVERTING || + state == AsyncPromiseState.RESOLVED + ) revert PromiseAlreadyResolved(); state = AsyncPromiseState.RESOLVED; // Call callback to app gateway - if (callbackSelector == bytes4(0)) return true; - - bytes memory combinedCalldata = abi.encodePacked( - callbackSelector, - abi.encode(callbackData, returnData_) - ); - - // setting max_copy_bytes to 0 as not using returnData right now - (success, , ) = localInvoker.tryCall(0, gasleft(), 0, combinedCalldata); - if (success) return success; - - _handleRevert(requestCount_, payloadId_, AsyncPromiseState.CALLBACK_REVERTING); + if (callbackSelector == bytes4(0)) { + success = true; + } else { + exceededMaxCopy = exceededMaxCopy_; + returnData = returnData_; + + bytes memory combinedCalldata = abi.encodePacked( + callbackSelector, + abi.encode(callbackData, returnData_) + ); + + (success, , ) = localInvoker.tryCall(0, gasleft(), 0, combinedCalldata); + if (!success) { + state = AsyncPromiseState.CALLBACK_REVERTING; + _handleRevert(payloadId_); + } + } } /// @notice Marks the promise as onchain reverting. /// @dev Only callable by the watcher precompile. function markOnchainRevert( - uint40 requestCount_, - bytes32 payloadId_ + bool exceededMaxCopy_, + bytes32 payloadId_, + bytes memory returnData_ ) external override onlyWatcher { - _handleRevert(requestCount_, payloadId_, AsyncPromiseState.ONCHAIN_REVERTING); - } + if ( + state == AsyncPromiseState.CALLBACK_REVERTING || + state == AsyncPromiseState.ONCHAIN_REVERTING || + state == AsyncPromiseState.RESOLVED + ) revert PromiseAlreadyResolved(); - function _handleRevert( - uint40 requestCount_, - bytes32 payloadId_, - AsyncPromiseState state_ - ) internal { // to update the state in case selector is bytes(0) but reverting onchain - resolved = true; - state = state_; - try IAppGateway(localInvoker).handleRevert(requestCount_, payloadId_) { - // Successfully handled revert - } catch { + state = AsyncPromiseState.ONCHAIN_REVERTING; + exceededMaxCopy_ = exceededMaxCopy_; + returnData_ = returnData_; + _handleRevert(payloadId_); + } + + /// @notice Handles the revert of the promise. + /// @dev Only callable by the watcher. + /// @dev handleRevert function can be retried till it succeeds + function _handleRevert(bytes32 payloadId_) internal { + try IAppGateway(localInvoker).handleRevert(payloadId_) {} catch { + // todo-later: in this case, promise will stay unresolved revert PromiseRevertFailed(); } } @@ -119,22 +132,19 @@ contract AsyncPromise is AsyncPromiseStorage, Initializable, AddressResolverUtil /// @param selector_ The function selector for the callback. /// @param data_ The data to be passed to the callback. /// @return promise_ The address of the current promise. - function then( - bytes4 selector_, - bytes memory data_ - ) external override onlyWatcher returns (address promise_) { + function then(bytes4 selector_, bytes memory data_) external override onlyWatcher { // if the promise is already set up, revert - if (state == AsyncPromiseState.WAITING_FOR_CALLBACK_EXECUTION) { + if (state != AsyncPromiseState.WAITING_FOR_CALLBACK_SELECTOR) { revert PromiseAlreadySetUp(); } - // if the promise is waiting for the callback selector, set it and update the state - if (state == AsyncPromiseState.WAITING_FOR_SET_CALLBACK_SELECTOR) { - callbackSelector = selector_; - callbackData = data_; - state = AsyncPromiseState.WAITING_FOR_CALLBACK_EXECUTION; - } + // todo: check if we can directly call .then from app gateway + // move watcher checks here + if (msg.sender != localInvoker) revert OnlyInvoker(); - promise_ = address(this); + // if the promise is waiting for the callback selector, set it and update the state + callbackSelector = selector_; + callbackData = data_; + state = AsyncPromiseState.WAITING_FOR_CALLBACK_EXECUTION; } } diff --git a/contracts/evmx/interfaces/IPromise.sol b/contracts/evmx/interfaces/IPromise.sol index c43d6627..6dd3d05d 100644 --- a/contracts/evmx/interfaces/IPromise.sol +++ b/contracts/evmx/interfaces/IPromise.sol @@ -21,7 +21,4 @@ interface IPromise { /// @notice Marks the promise as onchain reverting. /// @dev Only callable by the watcher precompile. function markOnchainRevert(uint40 requestCount_, bytes32 payloadId_) external; - - /// @notice Indicates whether the promise has been resolved. - function resolved() external view returns (bool); } diff --git a/contracts/evmx/watcher/PromiseResolver.sol b/contracts/evmx/watcher/PromiseResolver.sol index f6dfc77c..4e0d3bbc 100644 --- a/contracts/evmx/watcher/PromiseResolver.sol +++ b/contracts/evmx/watcher/PromiseResolver.sol @@ -46,7 +46,6 @@ contract PromiseResolver is IPromiseResolver { address asyncPromise = payloadParams.asyncPromise; requestCount = payloadParams.requestCount; - success = true; if (asyncPromise != address(0)) { success = IPromise(asyncPromise).markResolved( @@ -59,6 +58,8 @@ contract PromiseResolver is IPromiseResolver { emit PromiseNotResolved(resolvedPromise_.payloadId, asyncPromise); return (requestCount, false); } + } else { + success = true; } emit PromiseResolved(resolvedPromise_.payloadId, asyncPromise); diff --git a/contracts/evmx/watcher/Trigger.sol b/contracts/evmx/watcher/Trigger.sol index 0c1af2e5..41a422ec 100644 --- a/contracts/evmx/watcher/Trigger.sol +++ b/contracts/evmx/watcher/Trigger.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.21; import "./WatcherStorage.sol"; + /// @title Trigger /// @notice Contract that handles trigger validation and execution logic /// @dev This contract interacts with the WatcherPrecompileStorage for storage access @@ -31,8 +32,8 @@ abstract contract Trigger is WatcherStorage { revert InvalidCallerTriggered(); feesManager__().transferFrom(appGateway, address(this), triggerFees); - appGatewayCaller = appGateway; + appGatewayCaller = appGateway; appGatewayCalled[params_.triggerId] = true; (bool success, , ) = appGateway.tryCall( 0, diff --git a/contracts/evmx/watcher/Watcher.sol b/contracts/evmx/watcher/Watcher.sol index 73aa7813..811b53dc 100644 --- a/contracts/evmx/watcher/Watcher.sol +++ b/contracts/evmx/watcher/Watcher.sol @@ -73,11 +73,11 @@ contract Watcher is Trigger { if (latestRequestCount != requestHandler__.nextRequestCount()) revert RequestCountMismatch(); - address latestAsyncPromise_ = latestAsyncPromise; + address promise_ = latestAsyncPromise; latestAsyncPromise = address(0); // as same req count is checked, assuming app gateway will be same else it will revert on batch - promise_ = IPromise(latestAsyncPromise_).then(selector_, data_); + IPromise(promise_).then(selector_, data_); } function submitRequest( diff --git a/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol b/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol index bc0d525c..c13490fa 100644 --- a/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.21; import "../../interfaces/IPrecompile.sol"; import "../../../utils/common/Structs.sol"; -import "../../../utils/common/Errors.sol"; +import {InvalidTarget, InvalidPayloadSize, InvalidScheduleDelay, InvalidTimeoutRequest, TimeoutAlreadyResolved, ResolvingTimeoutTooEarly, CallFailed} from "../../../utils/common/Errors.sol"; import "../WatcherBase.sol"; /// @title SchedulePrecompile diff --git a/contracts/protocol/Socket.sol b/contracts/protocol/Socket.sol index 222b83c3..db5b300d 100644 --- a/contracts/protocol/Socket.sol +++ b/contracts/protocol/Socket.sol @@ -170,6 +170,8 @@ contract Socket is SocketUtils { return (success, returnData); } + /// @notice Validates the execution status of a payload + /// @dev This function can be retried till execution status is executed function _validateExecutionStatus(bytes32 payloadId_) internal { if (payloadExecuted[payloadId_] == ExecutionStatus.Executed) revert PayloadAlreadyExecuted(payloadExecuted[payloadId_]); diff --git a/contracts/utils/common/Errors.sol b/contracts/utils/common/Errors.sol index ebfe9dc6..8104e85c 100644 --- a/contracts/utils/common/Errors.sol +++ b/contracts/utils/common/Errors.sol @@ -41,3 +41,8 @@ error PromiseCallerMismatch(); error RequestCountMismatch(); /// @notice Error thrown when delivery helper is not set error DeliveryHelperNotSet(); + +error InvalidTarget(); +error InvalidPayloadSize(); +error InvalidScheduleDelay(); +error InvalidTimeoutRequest(); diff --git a/contracts/utils/common/Structs.sol b/contracts/utils/common/Structs.sol index 36d11199..ef757d3e 100644 --- a/contracts/utils/common/Structs.sol +++ b/contracts/utils/common/Structs.sol @@ -31,7 +31,7 @@ enum SwitchboardStatus { /// @notice The state of the async promise enum AsyncPromiseState { - WAITING_FOR_SET_CALLBACK_SELECTOR, + WAITING_FOR_CALLBACK_SELECTOR, WAITING_FOR_CALLBACK_EXECUTION, CALLBACK_REVERTING, ONCHAIN_REVERTING, From cb7af8c85cc0b1015710e4b6d0acec1b3af0ec7e Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Wed, 21 May 2025 18:34:43 +0530 Subject: [PATCH 034/130] fix: code refactor --- contracts/evmx/base/AppGatewayBase.sol | 2 +- .../evmx/fees/{UserUtils.sol => Credit.sol} | 0 contracts/evmx/fees/CreditUtils.sol | 184 ------------------ contracts/evmx/fees/FeesManager.sol | 176 ++++++++++++++++- .../evmx/helpers/AddressResolverUtil.sol | 2 +- contracts/evmx/helpers/AsyncDeployer.sol | 2 +- contracts/evmx/helpers/AsyncPromise.sol | 22 ++- contracts/evmx/helpers/Forwarder.sol | 25 +-- contracts/evmx/libs/WatcherIdUtils.sol | 50 +++-- contracts/evmx/watcher/Configurations.sol | 2 +- contracts/evmx/watcher/PromiseResolver.sol | 3 +- contracts/evmx/watcher/RequestHandler.sol | 50 ++--- contracts/evmx/watcher/Watcher.sol | 31 ++- contracts/evmx/watcher/WatcherBase.sol | 4 + .../counter/CounterAppGateway.sol | 2 +- 15 files changed, 263 insertions(+), 292 deletions(-) rename contracts/evmx/fees/{UserUtils.sol => Credit.sol} (100%) delete mode 100644 contracts/evmx/fees/CreditUtils.sol diff --git a/contracts/evmx/base/AppGatewayBase.sol b/contracts/evmx/base/AppGatewayBase.sol index bd9933f0..205e2d7e 100644 --- a/contracts/evmx/base/AppGatewayBase.sol +++ b/contracts/evmx/base/AppGatewayBase.sol @@ -148,7 +148,7 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { address(this) ); - watcher__().then(promise_); + IPromise(watcher__().latestAsyncPromise()).then(this.onRequestComplete, onCompleteData); } /// @notice Gets the socket address diff --git a/contracts/evmx/fees/UserUtils.sol b/contracts/evmx/fees/Credit.sol similarity index 100% rename from contracts/evmx/fees/UserUtils.sol rename to contracts/evmx/fees/Credit.sol diff --git a/contracts/evmx/fees/CreditUtils.sol b/contracts/evmx/fees/CreditUtils.sol deleted file mode 100644 index f0f59406..00000000 --- a/contracts/evmx/fees/CreditUtils.sol +++ /dev/null @@ -1,184 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -pragma solidity ^0.8.21; - -import "./UserUtils.sol"; - -/// @title FeesManager -/// @notice Contract for managing fees -abstract contract CreditUtils is UserUtils { - /// @notice Emitted when fees are blocked for a batch - /// @param requestCount The batch identifier - /// @param consumeFrom The consume from address - /// @param amount The blocked amount - event CreditsBlocked(uint40 indexed requestCount, address indexed consumeFrom, uint256 amount); - - /// @notice Emitted when transmitter fees are updated - /// @param requestCount The batch identifier - /// @param transmitter The transmitter address - /// @param amount The new amount deposited - event TransmitterCreditsUpdated( - uint40 indexed requestCount, - address indexed transmitter, - uint256 amount - ); - event WatcherPrecompileCreditsAssigned(uint256 amount, address consumeFrom); - - /// @notice Emitted when fees are unblocked and assigned to a transmitter - /// @param requestCount The batch identifier - /// @param transmitter The transmitter address - /// @param amount The unblocked amount - event CreditsUnblockedAndAssigned( - uint40 indexed requestCount, - address indexed transmitter, - uint256 amount - ); - - /// @notice Emitted when fees are unblocked - /// @param requestCount The batch identifier - /// @param appGateway The app gateway address - event CreditsUnblocked(uint40 indexed requestCount, address indexed appGateway); - - /// @notice Emitted when insufficient watcher precompile fees are available - event InsufficientWatcherPrecompileCreditsAvailable( - uint32 chainSlug, - address token, - address consumeFrom - ); - - /// @notice Blocks fees for a request count - /// @param consumeFrom_ The fees payer address - /// @param transmitterCredits_ The total fees to block - /// @param requestCount_ The batch identifier - /// @dev Only callable by delivery helper - function blockCredits( - uint40 requestCount_, - address consumeFrom_, - uint256 credits_ - ) external onlyWatcher { - if (getAvailableCredits(consumeFrom_) < credits_) revert InsufficientCreditsAvailable(); - - UserCredits storage userCredit = userCredits[consumeFrom_]; - userCredit.blockedCredits += credits_; - - requestCountCredits[requestCount_] = credits_; - emit CreditsBlocked(requestCount_, consumeFrom_, credits_); - } - - /// @notice Unblocks fees after successful execution and assigns them to the transmitter - /// @param requestCount_ The async ID of the executed batch - /// @param assignTo_ The address of the transmitter - function unblockAndAssignCredits( - uint40 requestCount_, - address assignTo_ - ) external override onlyWatcher { - uint256 blockedCredits = requestCountCredits[requestCount_]; - if (blockedCredits == 0) return; - - RequestParams memory requestParams = _getRequestParams(requestCount_); - uint256 fees = requestParams.requestFeesDetails.maxFees; - - // Unblock fees from deposit - _updateUserCredits(requestParams.consumeFrom, blockedCredits, fees); - - // Assign fees to transmitter - userCredits[assignTo_].totalCredits += fees; - - // Clean up storage - delete requestCountCredits[requestCount_]; - emit CreditsUnblockedAndAssigned(requestCount_, assignTo_, fees); - } - - function _useAvailableUserCredits(address consumeFrom_, uint256 toConsume_) internal { - UserCredits storage userCredit = userCredits[consumeFrom_]; - if (userCredit.totalCredits < toConsume_) revert InsufficientCreditsAvailable(); - userCredit.totalCredits -= toConsume_; - } - - function assignWatcherPrecompileCreditsFromAddress( - uint256 amount_, - address consumeFrom_ - ) external onlyWatcher { - // deduct the fees from the user - _useAvailableUserCredits(consumeFrom_, amount_); - // add the fees to the watcher precompile - watcherPrecompileCredits += amount_; - emit WatcherPrecompileCreditsAssigned(amount_, consumeFrom_); - } - - function unblockCredits(uint40 requestCount_) external onlyWatcher { - RequestParams memory r = _getRequestParams(requestCount_); - uint256 blockedCredits = requestCountCredits[requestCount_]; - if (blockedCredits == 0) return; - - // Unblock fees from deposit - _updateUserCredits(r.requestFeesDetails.consumeFrom, blockedCredits, 0); - delete requestCountCredits[requestCount_]; - emit CreditsUnblocked(requestCount_, r.requestFeesDetails.consumeFrom); - } - - function _getRequestParams(uint40 requestCount_) internal view returns (RequestParams memory) { - return watcherPrecompile__().getRequestParams(requestCount_); - } -} - -// /// @notice Withdraws funds to a specified receiver -// /// @param chainSlug_ The chain identifier -// /// @param token_ The address of the token -// /// @param amount_ The amount of tokens to withdraw -// /// @param receiver_ The address of the receiver -// /// @param fees_ The fees data -// function withdrawTo( -// uint32 chainSlug_, -// address token_, -// uint256 amount_, -// address receiver_, -// address auctionManager_, -// uint256 fees_ -// ) external returns (uint40) { -// feesManager__().withdrawCredits( -// msg.sender, -// chainSlug_, -// token_, -// amount_, -// receiver_ -// ); -// return _batch(msg.sender, auctionManager_, msg.sender, fees_, bytes("")); -// } - -// /// @notice Withdraws fees to a specified receiver -// /// @param chainSlug_ The chain identifier -// /// @param token_ The token address -// /// @param receiver_ The address of the receiver -// function withdrawTransmitterFees( -// uint32 chainSlug_, -// address token_, -// address receiver_, -// uint256 amount_ -// ) external returns (uint40 requestCount) { -// address transmitter = msg.sender; - -// PayloadSubmitParams[] memory payloadSubmitParamsArray = feesManager__() -// .getWithdrawTransmitterCreditsPayloadParams( -// transmitter, -// chainSlug_, -// token_, -// receiver_, -// amount_ -// ); - -// RequestMetadata memory requestMetadata = RequestMetadata({ -// appGateway: feesManager__(), -// auctionManager: address(0), -// maxFees: 0, -// winningBid: Bid({transmitter: transmitter, fee: 0, extraData: new bytes(0)}), -// onCompleteData: bytes(""), -// onlyReadRequests: false, -// consumeFrom: transmitter, -// queryCount: 0, -// finalizeCount: 1 -// }); // finalize for plug contract -// requestCount = watcherPrecompile__().submitRequest(payloadSubmitParamsArray); -// requests[requestCount] = requestMetadata; -// // same transmitter can execute requests without auction -// watcherPrecompile__().startProcessingRequest(requestCount, transmitter); -// } diff --git a/contracts/evmx/fees/FeesManager.sol b/contracts/evmx/fees/FeesManager.sol index b6888e29..6e1aa275 100644 --- a/contracts/evmx/fees/FeesManager.sol +++ b/contracts/evmx/fees/FeesManager.sol @@ -1,11 +1,50 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import "./CreditUtils.sol"; +import "./Credit.sol"; /// @title FeesManager /// @notice Contract for managing fees -contract FeesManager is CreditUtils, Initializable, Ownable, AddressResolverUtil { +abstract contract FeesManager is Credit, Initializable, Ownable, AddressResolverUtil { + /// @notice Emitted when fees are blocked for a batch + /// @param requestCount The batch identifier + /// @param consumeFrom The consume from address + /// @param amount The blocked amount + event CreditsBlocked(uint40 indexed requestCount, address indexed consumeFrom, uint256 amount); + + /// @notice Emitted when transmitter fees are updated + /// @param requestCount The batch identifier + /// @param transmitter The transmitter address + /// @param amount The new amount deposited + event TransmitterCreditsUpdated( + uint40 indexed requestCount, + address indexed transmitter, + uint256 amount + ); + event WatcherPrecompileCreditsAssigned(uint256 amount, address consumeFrom); + + /// @notice Emitted when fees are unblocked and assigned to a transmitter + /// @param requestCount The batch identifier + /// @param transmitter The transmitter address + /// @param amount The unblocked amount + event CreditsUnblockedAndAssigned( + uint40 indexed requestCount, + address indexed transmitter, + uint256 amount + ); + + /// @notice Emitted when fees are unblocked + /// @param requestCount The batch identifier + /// @param appGateway The app gateway address + event CreditsUnblocked(uint40 indexed requestCount, address indexed appGateway); + + /// @notice Emitted when insufficient watcher precompile fees are available + event InsufficientWatcherPrecompileCreditsAvailable( + uint32 chainSlug, + address token, + address consumeFrom + ); + constructor() { _disableInitializers(); // disable for implementation } @@ -26,7 +65,135 @@ contract FeesManager is CreditUtils, Initializable, Ownable, AddressResolverUtil _initializeOwner(owner_); } - // /// @notice Withdraws funds to a specified receiver + /// @notice Blocks fees for a request count + /// @param consumeFrom_ The fees payer address + /// @param transmitterCredits_ The total fees to block + /// @param requestCount_ The batch identifier + /// @dev Only callable by delivery helper + function blockCredits( + uint40 requestCount_, + address consumeFrom_, + uint256 credits_ + ) external onlyWatcher { + if (getAvailableCredits(consumeFrom_) < credits_) revert InsufficientCreditsAvailable(); + + UserCredits storage userCredit = userCredits[consumeFrom_]; + userCredit.blockedCredits += credits_; + + requestCountCredits[requestCount_] = credits_; + emit CreditsBlocked(requestCount_, consumeFrom_, credits_); + } + + /// @notice Unblocks fees after successful execution and assigns them to the transmitter + /// @param requestCount_ The async ID of the executed batch + /// @param assignTo_ The address of the transmitter + function unblockAndAssignCredits( + uint40 requestCount_, + address assignTo_ + ) external override onlyWatcher { + uint256 blockedCredits = requestCountCredits[requestCount_]; + if (blockedCredits == 0) return; + + RequestParams memory requestParams = _getRequestParams(requestCount_); + uint256 fees = requestParams.requestFeesDetails.maxFees; + + // Unblock fees from deposit + _updateUserCredits(requestParams.consumeFrom, blockedCredits, fees); + + // Assign fees to transmitter + userCredits[assignTo_].totalCredits += fees; + + // Clean up storage + delete requestCountCredits[requestCount_]; + emit CreditsUnblockedAndAssigned(requestCount_, assignTo_, fees); + } + + function _useAvailableUserCredits(address consumeFrom_, uint256 toConsume_) internal { + UserCredits storage userCredit = userCredits[consumeFrom_]; + if (userCredit.totalCredits < toConsume_) revert InsufficientCreditsAvailable(); + userCredit.totalCredits -= toConsume_; + } + + function unblockCredits(uint40 requestCount_) external onlyWatcher { + RequestParams memory r = _getRequestParams(requestCount_); + uint256 blockedCredits = requestCountCredits[requestCount_]; + if (blockedCredits == 0) return; + + // Unblock fees from deposit + _updateUserCredits(r.requestFeesDetails.consumeFrom, blockedCredits, 0); + delete requestCountCredits[requestCount_]; + emit CreditsUnblocked(requestCount_, r.requestFeesDetails.consumeFrom); + } + + function _getRequestParams(uint40 requestCount_) internal view returns (RequestParams memory) { + return watcher__().getRequestParams(requestCount_); + } +} + +// /// @notice Withdraws funds to a specified receiver +// /// @param chainSlug_ The chain identifier +// /// @param token_ The address of the token +// /// @param amount_ The amount of tokens to withdraw +// /// @param receiver_ The address of the receiver +// /// @param fees_ The fees data +// function withdrawTo( +// uint32 chainSlug_, +// address token_, +// uint256 amount_, +// address receiver_, +// address auctionManager_, +// uint256 fees_ +// ) external returns (uint40) { +// feesManager__().withdrawCredits( +// msg.sender, +// chainSlug_, +// token_, +// amount_, +// receiver_ +// ); +// return _batch(msg.sender, auctionManager_, msg.sender, fees_, bytes("")); +// } + +// /// @notice Withdraws fees to a specified receiver +// /// @param chainSlug_ The chain identifier +// /// @param token_ The token address +// /// @param receiver_ The address of the receiver +// function withdrawTransmitterFees( +// uint32 chainSlug_, +// address token_, +// address receiver_, +// uint256 amount_ +// ) external returns (uint40 requestCount) { +// address transmitter = msg.sender; + +// PayloadSubmitParams[] memory payloadSubmitParamsArray = feesManager__() +// .getWithdrawTransmitterCreditsPayloadParams( +// transmitter, +// chainSlug_, +// token_, +// receiver_, +// amount_ +// ); + +// RequestMetadata memory requestMetadata = RequestMetadata({ +// appGateway: feesManager__(), +// auctionManager: address(0), +// maxFees: 0, +// winningBid: Bid({transmitter: transmitter, fee: 0, extraData: new bytes(0)}), +// onCompleteData: bytes(""), +// onlyReadRequests: false, +// consumeFrom: transmitter, +// queryCount: 0, +// finalizeCount: 1 +// }); // finalize for plug contract +// requestCount = watcherPrecompile__().submitRequest(payloadSubmitParamsArray); +// requests[requestCount] = requestMetadata; +// // same transmitter can execute requests without auction +// watcherPrecompile__().startProcessingRequest(requestCount, transmitter); +// } + + +// /// @notice Withdraws funds to a specified receiver // /// @dev This function is used to withdraw fees from the fees plug // /// @param originAppGatewayOrUser_ The address of the app gateway // /// @param chainSlug_ The chain identifier @@ -96,5 +263,4 @@ contract FeesManager is CreditUtils, Initializable, Ownable, AddressResolverUtil // uint256 watcherFees = watcherPrecompileLimits().getTotalFeesRequired(0, 1, 0, 1); // uint256 transmitterCredits = userCredits[transmitter_].totalCredits; // return transmitterCredits > watcherFees ? transmitterCredits - watcherFees : 0; - // } -} + // } \ No newline at end of file diff --git a/contracts/evmx/helpers/AddressResolverUtil.sol b/contracts/evmx/helpers/AddressResolverUtil.sol index aa095277..a3450e7d 100644 --- a/contracts/evmx/helpers/AddressResolverUtil.sol +++ b/contracts/evmx/helpers/AddressResolverUtil.sol @@ -9,7 +9,7 @@ import "../interfaces/IAsyncDeployer.sol"; /// @title AddressResolverUtil /// @notice Utility contract for resolving system contract addresses /// @dev Provides access control and address resolution functionality for the system -abstract contract AddressResolverBase { +abstract contract AddressResolverUtil { /// @notice The address resolver contract reference /// @dev Used to look up system contract addresses // slot 0 diff --git a/contracts/evmx/helpers/AsyncDeployer.sol b/contracts/evmx/helpers/AsyncDeployer.sol index c33c12f4..01d9f34a 100644 --- a/contracts/evmx/helpers/AsyncDeployer.sol +++ b/contracts/evmx/helpers/AsyncDeployer.sol @@ -132,7 +132,7 @@ contract AsyncDeployer is AsyncDeployerStorage, Initializable, Ownable { /// @return newAsyncPromise The address of the deployed AsyncPromise proxy contract function deployAsyncPromiseContract( address invoker_ - ) external returns (address newAsyncPromise) { + ) external onlyWatcher returns (address newAsyncPromise) { // creates init data and salt (bytes32 salt, bytes memory initData) = _createAsyncPromiseParams(invoker_); asyncPromiseCounter++; diff --git a/contracts/evmx/helpers/AsyncPromise.sol b/contracts/evmx/helpers/AsyncPromise.sol index 4caf173e..a906a5af 100644 --- a/contracts/evmx/helpers/AsyncPromise.sol +++ b/contracts/evmx/helpers/AsyncPromise.sol @@ -16,9 +16,6 @@ abstract contract AsyncPromiseStorage is IPromise { // bytes1 /// @notice The callback selector to be called on the invoker. bytes4 public callbackSelector; - // bytes4 - /// @notice Indicates whether the promise has been resolved. - bool public override resolved; // bytes8 /// @notice The current state of the async promise. AsyncPromiseState public state; @@ -27,6 +24,9 @@ abstract contract AsyncPromiseStorage is IPromise { /// @dev The callback will be executed on this address address public localInvoker; + /// @notice The request count of the promise + uint256 public requestCount; + // slot 52 /// @notice The callback data to be used when the promise is resolved. bytes public callbackData; @@ -58,8 +58,13 @@ contract AsyncPromise is AsyncPromiseStorage, Initializable, AddressResolverUtil /// @notice Initialize promise states /// @param invoker_ The address of the local invoker /// @param addressResolver_ The address resolver contract address - function initialize(address invoker_, address addressResolver_) public initializer { + function initialize( + address invoker_, + address addressResolver_, + uint256 requestCount_ + ) public initializer { localInvoker = invoker_; + requestCount = requestCount_; _setAddressResolver(addressResolver_); } @@ -132,15 +137,14 @@ contract AsyncPromise is AsyncPromiseStorage, Initializable, AddressResolverUtil /// @param selector_ The function selector for the callback. /// @param data_ The data to be passed to the callback. /// @return promise_ The address of the current promise. - function then(bytes4 selector_, bytes memory data_) external override onlyWatcher { + function then(bytes4 selector_, bytes memory data_) external override { + if (msg.sender != localInvoker) revert NotInvoker(); // if the promise is already set up, revert if (state != AsyncPromiseState.WAITING_FOR_CALLBACK_SELECTOR) { revert PromiseAlreadySetUp(); } - - // todo: check if we can directly call .then from app gateway - // move watcher checks here - if (msg.sender != localInvoker) revert OnlyInvoker(); + if (watcher__().latestAsyncPromise != address(this)) revert PromiseAlreadySetUp(); + if (requestCount != watcher__().latestRequestCount) revert RequestCountMismatch(); // if the promise is waiting for the callback selector, set it and update the state callbackSelector = selector_; diff --git a/contracts/evmx/helpers/Forwarder.sol b/contracts/evmx/helpers/Forwarder.sol index 3d1a26b8..f37d3549 100644 --- a/contracts/evmx/helpers/Forwarder.sol +++ b/contracts/evmx/helpers/Forwarder.sol @@ -6,7 +6,7 @@ import "./interfaces/IMiddleware.sol"; import "./interfaces/IAppGateway.sol"; import "./interfaces/IForwarder.sol"; import {AddressResolverUtil} from "./AddressResolverUtil.sol"; -import {AsyncModifierNotUsed, NoAsyncPromiseFound, PromiseCallerMismatch, RequestCountMismatch, WatcherNotSt} from "../utils/common/Errors.sol"; +import {AsyncModifierNotUsed, WatcherNotSet} from "../utils/common/Errors.sol"; import "solady/utils/Initializable.sol"; /// @title Forwarder Storage @@ -21,12 +21,6 @@ abstract contract ForwarderStorage is IForwarder { /// @notice on-chain address associated with this forwarder address public onChainAddress; - // slot 52 - /// @notice the address of the contract that called the latest async promise - address public latestPromiseCaller; - /// @notice the request count of the latest async promise - uint40 public latestRequestCount; - // slots [53-102] reserved for gap uint256[50] _gap_after; @@ -54,17 +48,6 @@ contract Forwarder is ForwarderStorage, Initializable, AddressResolverUtil { _setAddressResolver(addressResolver_); } - /// @notice Stores the callback address and data to be executed once the promise is resolved. - /// @dev This function should not be called before the fallback function. - /// @dev It resets the latest async promise address - /// @param selector_ The function selector for callback - /// @param data_ The data to be passed to callback - /// @return promise_ The address of the new promise - function then(bytes4 selector_, bytes memory data_) external returns (address promise_) { - if (lastForwarderCaller != msg.sender) revert CallerMismatch(); - promise_ = watcherPrecompile__().then(selector_, data_, msg.sender); - } - /// @notice Returns the on-chain address associated with this forwarder. /// @return The on-chain address. function getOnChainAddress() external view returns (address) { @@ -80,7 +63,7 @@ contract Forwarder is ForwarderStorage, Initializable, AddressResolverUtil { /// @notice Fallback function to process the contract calls to onChainAddress /// @dev It queues the calls in the middleware and deploys the promise contract fallback() external { - if (address(watcherPrecompile__()) == address(0)) { + if (address(watcher__()) == address(0)) { revert WatcherNotSet(); } @@ -93,9 +76,7 @@ contract Forwarder is ForwarderStorage, Initializable, AddressResolverUtil { .getOverrideParams(); // Queue the call in the middleware. - // and sets the latest promise caller and request count for validating if the future .then call is valid - latestPromiseCaller = msg.sender; - watcherPrecompile__().queue( + watcher__().queue( QueuePayloadParams({ overrideParams: overrideParams, transaction: Transaction({ diff --git a/contracts/evmx/libs/WatcherIdUtils.sol b/contracts/evmx/libs/WatcherIdUtils.sol index 1d2ed762..9b4db8eb 100644 --- a/contracts/evmx/libs/WatcherIdUtils.sol +++ b/contracts/evmx/libs/WatcherIdUtils.sol @@ -1,32 +1,30 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.22; -library WatcherIdUtils { - function encodeAppGatewayId(address appGateway_) internal pure returns (bytes32) { - return bytes32(uint256(uint160(appGateway_))); - } +// todo: remove watcher id util lib +function encodeAppGatewayId(address appGateway_) pure returns (bytes32) { + return bytes32(uint256(uint160(appGateway_))); +} - function decodeAppGatewayId(bytes32 appGatewayId_) internal pure returns (address) { - return address(uint160(uint256(appGatewayId_))); - } +function decodeAppGatewayId(bytes32 appGatewayId_) pure returns (address) { + return address(uint160(uint256(appGatewayId_))); +} - /// @notice Creates a payload ID from the given parameters - /// @param requestCount_ The request count - /// @param batchCount_ The batch count - /// @param payloadCount_ The payload count - /// @param switchboard_ The switchboard address - /// @param chainSlug_ The chain slug - /// @return The created payload ID - function createPayloadId( - uint40 requestCount_, - uint40 batchCount_, - uint40 payloadCount_, - address switchboard_, - uint32 chainSlug_ - ) internal pure returns (bytes32) { - return - keccak256( - abi.encode(requestCount_, batchCount_, payloadCount_, chainSlug_, switchboard_) - ); - } +// todo: also use in socket +/// @notice Creates a payload ID from the given parameters +/// @param requestCount_ The request count +/// @param batchCount_ The batch count +/// @param payloadCount_ The payload count +/// @param switchboard_ The switchboard address +/// @param chainSlug_ The chain slug +/// @return The created payload ID +function createPayloadId( + uint40 requestCount_, + uint40 batchCount_, + uint40 payloadCount_, + address switchboard_, + uint32 chainSlug_ +) pure returns (bytes32) { + return + keccak256(abi.encode(requestCount_, batchCount_, payloadCount_, chainSlug_, switchboard_)); } diff --git a/contracts/evmx/watcher/Configurations.sol b/contracts/evmx/watcher/Configurations.sol index 0ec3697e..e217d244 100644 --- a/contracts/evmx/watcher/Configurations.sol +++ b/contracts/evmx/watcher/Configurations.sol @@ -174,7 +174,7 @@ contract Configurations is IConfigurations, Initializable, AddressResolverUtil { ) external view { (bytes32 appGatewayId, address switchboard) = getPlugConfigs(chainSlug_, target_); - if (appGatewayId != WatcherIdUtils.encodeAppGatewayId(appGateway_)) revert InvalidGateway(); + if (appGatewayId != encodeAppGatewayId(appGateway_)) revert InvalidGateway(); if (switchboard != switchboards[chainSlug_][switchboardType_]) revert InvalidSwitchboard(); } } diff --git a/contracts/evmx/watcher/PromiseResolver.sol b/contracts/evmx/watcher/PromiseResolver.sol index 4e0d3bbc..4cc3a28e 100644 --- a/contracts/evmx/watcher/PromiseResolver.sol +++ b/contracts/evmx/watcher/PromiseResolver.sol @@ -29,7 +29,7 @@ contract PromiseResolver is IPromiseResolver { for (uint256 i = 0; i < resolvedPromises_.length; i++) { (uint40 requestCount, bool success) = _processPromiseResolution(resolvedPromises_[i]); if (success) { - requestHandler__().markPayloadExecutedAndProcessBatch( + requestHandler__().updateRequestAndProcessBatch( requestCount, resolvedPromises_[i].payloadId ); @@ -37,6 +37,7 @@ contract PromiseResolver is IPromiseResolver { } } + // todo: add max copy bytes and update function inputs function _processPromiseResolution( ResolvedPromises memory resolvedPromise_ ) internal returns (uint40 requestCount, bool success) { diff --git a/contracts/evmx/watcher/RequestHandler.sol b/contracts/evmx/watcher/RequestHandler.sol index a5603ade..05506e32 100644 --- a/contracts/evmx/watcher/RequestHandler.sol +++ b/contracts/evmx/watcher/RequestHandler.sol @@ -67,8 +67,7 @@ contract RequestHandler is WatcherBase { if (queuePayloadParams.length > REQUEST_PAYLOAD_COUNT_LIMIT) revert RequestPayloadCountLimitExceeded(); - address appGateway = _getCoreAppGateway(appGateway_); - if (!IFeesManager(feesManager__()).isUserCreditsEnough(consumeFrom_, appGateway, maxFees_)) + if (!IFeesManager(feesManager__()).isUserCreditsEnough(consumeFrom_, appGateway_, maxFees_)) revert InsufficientFees(); requestCount = nextRequestCount++; @@ -88,7 +87,7 @@ contract RequestHandler is WatcherBase { }), writeCount: 0, auctionManager: _getAuctionManager(auctionManager_), - appGateway: appGateway, + appGateway: appGateway_, onCompleteData: onCompleteData_ }); @@ -96,7 +95,7 @@ contract RequestHandler is WatcherBase { uint256 totalEstimatedWatcherFees; (totalEstimatedWatcherFees, r.writeCount, promiseList, payloadParams) = _createRequest( queuePayloadParams_, - appGateway, + appGateway_, requestCount ); @@ -156,11 +155,6 @@ contract RequestHandler is WatcherBase { for (uint256 i = 0; i < queuePayloadParams.length; i++) { QueueParams calldata queuePayloadParam = queuePayloadParams_[i]; bytes4 callType = queuePayloadParam.overrideParams.callType; - - // checks - if (getCoreAppGateway(queuePayloadParam.appGateway) != appGateway_) - revert InvalidAppGateway(); - if (callType == WRITE) writeCount++; // decide batch count @@ -270,35 +264,47 @@ contract RequestHandler is WatcherBase { /// @param newMaxFees_ The new maximum fees function increaseFees(uint40 requestCount_, uint256 newMaxFees_) external { RequestParams storage r = requestParams[requestCount_]; - address appGateway = _getCoreAppGateway(msg.sender); + address appGateway = getCoreAppGateway(msg.sender); + + if (r.requestTrackingParams.isRequestCancelled) revert RequestAlreadyCancelled(); + if (r.requestTrackingParams.isRequestExecuted) revert RequestAlreadySettled(); if (appGateway != r.appGateway) revert OnlyAppGateway(); - if (r.requestFeesDetails.winningBid.transmitter != address(0)) revert WinningBidExists(); if (r.requestFeesDetails.maxFees >= newMaxFees_) revert NewMaxFeesLowerThanCurrent(r.requestFeesDetails.maxFees, newMaxFees_); + if ( + !IFeesManager(feesManager__()).isUserCreditsEnough( + r.requestFeesDetails.consumeFrom, + appGateway, + newMaxFees_ + ) + ) revert InsufficientFees(); r.requestFeesDetails.maxFees = newMaxFees_; - emit FeesIncreased(appGateway, requestCount_, newMaxFees_); + + // indexed by transmitter and watcher to start bidding or re-processing the request + emit FeesIncreased(requestCount_, newMaxFees_); } - function markPayloadExecutedAndProcessBatch( + function updateRequestAndProcessBatch( uint40 requestCount_, bytes32 payloadId_ ) external onlyPromiseResolver isRequestCancelled(requestCount_) { RequestParams storage r = requestParams[requestCount_]; + // todo: read the status from promise here isPromiseExecuted[payloadId_] = true; r.requestTrackingParams.currentBatchPayloadsLeft--; r.requestTrackingParams.payloadsRemaining--; if (r.requestTrackingParams.currentBatchPayloadsLeft != 0) return; if (r.requestTrackingParams.payloadsRemaining == 0) { + r.requestTrackingParams.isRequestExecuted = true; _settleRequest(requestCount_, r); - return; + } else { + r.requestTrackingParams.currentBatch++; + _processBatch(requestCount_, r.requestTrackingParams.currentBatch, r); } - - r.requestTrackingParams.currentBatch++; - _processBatch(requestCount_, r.requestTrackingParams.currentBatch_, r); } /// @notice Cancels a request @@ -307,25 +313,23 @@ contract RequestHandler is WatcherBase { /// @dev It verifies that the caller is the middleware and that the request hasn't been cancelled yet function cancelRequest(uint40 requestCount) external { RequestParams storage r = requestParams[requestCount]; - if (r.isRequestCancelled) revert RequestAlreadyCancelled(); + if (r.requestTrackingParams.isRequestCancelled) revert RequestAlreadyCancelled(); + if (r.requestTrackingParams.isRequestExecuted) revert RequestAlreadySettled(); if (r.appGateway != getCoreAppGateway(msg.sender)) revert InvalidCaller(); - r.isRequestCancelled = true; + r.requestTrackingParams.isRequestCancelled = true; _settleRequest(requestCount, r); emit RequestCancelled(requestCount); } function _settleRequest(uint40 requestCount_, RequestParams storage r) internal { - if (r.requestTrackingParams.isRequestExecuted) return; - r.requestTrackingParams.isRequestExecuted = true; - feesManager__().unblockAndAssignCredits( requestCount_, r.requestFeesDetails.winningBid.transmitter ); - if (r.appGateway.code.length > 0 && r.onCompleteData.length > 0) { + if (r.onCompleteData.length > 0) { try IAppGateway(r.appGateway).onRequestComplete(requestCount_, r.onCompleteData) {} catch { diff --git a/contracts/evmx/watcher/Watcher.sol b/contracts/evmx/watcher/Watcher.sol index 811b53dc..4d18ceda 100644 --- a/contracts/evmx/watcher/Watcher.sol +++ b/contracts/evmx/watcher/Watcher.sol @@ -53,31 +53,25 @@ contract Watcher is Trigger { address appGateway_ ) internal returns (address, uint40) { address coreAppGateway = getCoreAppGateway(appGateway_); - // Deploy a new async promise contract. + + // checks if app gateway passed by forwarder is coming from same core app gateway group if (appGatewayTemp != address(0)) if (appGatewayTemp != coreAppGateway || coreAppGateway == address(0)) revert InvalidAppGateway(); - latestAsyncPromise = asyncDeployer__().deployAsyncPromiseContract(coreAppGateway); + uint40 requestCount = requestHandler__.nextRequestCount(); + // Deploy a new async promise contract. + latestAsyncPromise = asyncDeployer__().deployAsyncPromiseContract( + coreAppGateway, + requestCount + ); appGatewayTemp = coreAppGateway; queue_.asyncPromise = latestAsyncPromise; // Add the promise to the queue. payloadQueue.push(queue_); // return the promise and request count - return (latestAsyncPromise, requestHandler__.nextRequestCount()); - } - - function then(bytes4 selector_, bytes memory data_) external { - if (latestAsyncPromise == address(0)) revert NoAsyncPromiseFound(); - if (latestRequestCount != requestHandler__.nextRequestCount()) - revert RequestCountMismatch(); - - address promise_ = latestAsyncPromise; - latestAsyncPromise = address(0); - - // as same req count is checked, assuming app gateway will be same else it will revert on batch - IPromise(promise_).then(selector_, data_); + return (latestAsyncPromise, requestCount); } function submitRequest( @@ -95,13 +89,16 @@ contract Watcher is Trigger { address consumeFrom, bytes onCompleteData ) internal returns (uint40 requestCount, address[] memory promiseList) { - if (getCoreAppGateway(msg.sender) != appGatewayTemp) revert InvalidAppGateways(); + // this check is to verify that msg.sender (app gateway base) belongs to correct app gateway + address coreAppGateway = getCoreAppGateway(msg.sender); + if (coreAppGateway != appGatewayTemp) revert InvalidAppGateways(); + latestAsyncPromise = address(0); (requestCount, promiseList) = requestHandler__.submitRequest( maxFees, auctionManager, consumeFrom, - msg.sender, + coreAppGateway, payloadQueue, onCompleteData ); diff --git a/contracts/evmx/watcher/WatcherBase.sol b/contracts/evmx/watcher/WatcherBase.sol index bb6e766a..b79e7ed5 100644 --- a/contracts/evmx/watcher/WatcherBase.sol +++ b/contracts/evmx/watcher/WatcherBase.sol @@ -31,4 +31,8 @@ contract WatcherBase { function configurations__() external view returns (IConfigurations) { return IWatcher(watcher).configurations__(); } + + function getCoreAppGateway(address appGateway_) external view returns (address) { + return IWatcher(watcher).configurations__().getCoreAppGateway(appGateway_); + } } diff --git a/test/apps/app-gateways/counter/CounterAppGateway.sol b/test/apps/app-gateways/counter/CounterAppGateway.sol index 4b7e0275..8fe65074 100644 --- a/test/apps/app-gateways/counter/CounterAppGateway.sol +++ b/test/apps/app-gateways/counter/CounterAppGateway.sol @@ -75,7 +75,7 @@ contract CounterAppGateway is AppGatewayBase, Ownable { for (uint256 i = 0; i < instances_.length; i++) { uint32 chainSlug = IForwarder(instances_[i]).getChainSlug(); ICounter(instances_[i]).getCounter(); - IPromise(instances_[i]).then(this.setCounterValues.selector, abi.encode(chainSlug)); + then(this.setCounterValues.selector, abi.encode(chainSlug)); } _setOverrides(Read.OFF, Parallel.OFF); } From 641847c6eac8879b0fd743bba6f1a6e81291a1be Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Wed, 21 May 2025 21:30:47 +0530 Subject: [PATCH 035/130] feat: timeout precompile --- contracts/evmx/base/AppGatewayBase.sol | 23 +-- contracts/evmx/watcher/PromiseResolver.sol | 2 +- contracts/evmx/watcher/RequestHandler.sol | 25 ++- contracts/evmx/watcher/Trigger.sol | 31 ++-- contracts/evmx/watcher/Watcher.sol | 44 ++++- .../watcher/precompiles/ReadPrecompile.sol | 5 +- .../precompiles/SchedulePrecompile.sol | 157 ++---------------- .../watcher/precompiles/WritePrecompile.sol | 7 +- .../counter/CounterAppGateway.sol | 11 +- 9 files changed, 108 insertions(+), 197 deletions(-) diff --git a/contracts/evmx/base/AppGatewayBase.sol b/contracts/evmx/base/AppGatewayBase.sol index 205e2d7e..2e839fcf 100644 --- a/contracts/evmx/base/AppGatewayBase.sol +++ b/contracts/evmx/base/AppGatewayBase.sol @@ -129,26 +129,17 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { _deploy(contractId_, chainSlug_, isPlug_, new bytes(0)); } - function _schedule(uint256 delayInSeconds_, bytes memory payload_) internal { + /// @notice Schedules a function to be called after a delay + /// @param delayInSeconds_ The delay in seconds + /// @dev callback function and data is set in .then call + function _setTimeout(uint256 delayInSeconds_) internal { if (!isAsyncModifierSet) revert AsyncModifierNotUsed(); overrideParams.callType = SCHEDULE; overrideParams.delayInSeconds = delayInSeconds_; - (address promise_, ) = watcherPrecompile__().queue( - QueuePayloadParams({ - overrideParams: overrideParams, - transaction: Transaction({ - chainSlug: uint32(0), - target: address(this), - payload: payload_ - }), - asyncPromise: address(0), - switchboardType: sbType - }), - address(this) - ); - - IPromise(watcher__().latestAsyncPromise()).then(this.onRequestComplete, onCompleteData); + QueueParams memory queueParams = new QueueParams(); + queueParams.overrideParams = overrideParams; + (address promise_, ) = watcherPrecompile__().queue(queueParams, address(this)); } /// @notice Gets the socket address diff --git a/contracts/evmx/watcher/PromiseResolver.sol b/contracts/evmx/watcher/PromiseResolver.sol index 4cc3a28e..74b03f52 100644 --- a/contracts/evmx/watcher/PromiseResolver.sol +++ b/contracts/evmx/watcher/PromiseResolver.sol @@ -76,7 +76,7 @@ contract PromiseResolver is IPromiseResolver { if (payloadParams.deadline > block.timestamp) revert DeadlineNotPassedForOnChainRevert(); // marks the request as cancelled and settles the fees - requestHandler__().cancelRequest(payloadParams.requestCount); + requestHandler__().cancelRequestFromPromise(payloadParams.requestCount); // marks the promise as onchain reverting if the request is reverting onchain if (isRevertingOnchain_ && payloadParams.asyncPromise != address(0)) diff --git a/contracts/evmx/watcher/RequestHandler.sol b/contracts/evmx/watcher/RequestHandler.sol index 05506e32..9f8eb258 100644 --- a/contracts/evmx/watcher/RequestHandler.sol +++ b/contracts/evmx/watcher/RequestHandler.sol @@ -244,13 +244,11 @@ contract RequestHandler is WatcherBase { if (!isPromiseExecuted[payloadId]) continue; PayloadParams storage payloadParams = payloads[payloadId]; - payloadParams.deadline = block.timestamp + expiryTime; - uint256 fees = IPrecompile(precompiles[payloadParams.callType]).handlePayload( - r.requestFeesDetails.winningBid.transmitter, - payloadParams - ); + (uint256 fees, uint256 deadline) = IPrecompile(precompiles[payloadParams.callType]) + .handlePayload(r.requestFeesDetails.winningBid.transmitter, payloadParams); totalFees += fees; + payloadParams.deadline = deadline; } address watcherFeesPayer = r.requestFeesDetails.winningBid.transmitter == address(0) @@ -292,10 +290,12 @@ contract RequestHandler is WatcherBase { ) external onlyPromiseResolver isRequestCancelled(requestCount_) { RequestParams storage r = requestParams[requestCount_]; + PayloadParams storage payloadParams = payloads[payloadId_]; + IPrecompile(precompiles[payloadParams.callType]).resolvePayload(payloadParams); + // todo: read the status from promise here isPromiseExecuted[payloadId_] = true; - r.requestTrackingParams.currentBatchPayloadsLeft--; - r.requestTrackingParams.payloadsRemaining--; + payloadParams.resolvedAt = block.timestamp; if (r.requestTrackingParams.currentBatchPayloadsLeft != 0) return; if (r.requestTrackingParams.payloadsRemaining == 0) { @@ -313,12 +313,19 @@ contract RequestHandler is WatcherBase { /// @dev It verifies that the caller is the middleware and that the request hasn't been cancelled yet function cancelRequest(uint40 requestCount) external { RequestParams storage r = requestParams[requestCount]; + if (r.appGateway != getCoreAppGateway(msg.sender)) revert InvalidCaller(); + _cancelRequest(requestCount, r); + } + + function handleRevert(uint40 requestCount) external onlyPromiseResolver { + _cancelRequest(requestCount, requestParams[requestCount]); + } + + function _cancelRequest(uint40 requestCount_, RequestParams storage r) internal { if (r.requestTrackingParams.isRequestCancelled) revert RequestAlreadyCancelled(); if (r.requestTrackingParams.isRequestExecuted) revert RequestAlreadySettled(); - if (r.appGateway != getCoreAppGateway(msg.sender)) revert InvalidCaller(); r.requestTrackingParams.isRequestCancelled = true; - _settleRequest(requestCount, r); emit RequestCancelled(requestCount); } diff --git a/contracts/evmx/watcher/Trigger.sol b/contracts/evmx/watcher/Trigger.sol index 41a422ec..78bdcae3 100644 --- a/contracts/evmx/watcher/Trigger.sol +++ b/contracts/evmx/watcher/Trigger.sol @@ -7,46 +7,55 @@ import "./WatcherStorage.sol"; /// @notice Contract that handles trigger validation and execution logic /// @dev This contract interacts with the WatcherPrecompileStorage for storage access abstract contract Trigger is WatcherStorage { - /// @notice stores temporary address of the app gateway caller from a chain - address public appGatewayCaller; + /// @notice stores temporary chainSlug of the trigger from a chain + uint32 public triggerFromChainSlug; + /// @notice stores temporary plug of the trigger from a chain + address public triggerFromPlug; + /// @notice Stores the trigger fees uint256 public triggerFees; + /// @notice Mapping to store if appGateway has been called with trigger from on-chain Inbox /// @dev Maps call ID to boolean indicating if the appGateway has been called /// @dev callId => bool - mapping(bytes32 => bool) public appGatewayCalled; + mapping(bytes32 => bool) public isAppGatewayCalled; /// @notice Sets the trigger fees /// @param triggerFees_ The amount of fees to set - function setTriggerFees(uint256 triggerFees_) external onlyOwner { + function _setTriggerFees(uint256 triggerFees_) internal { triggerFees = triggerFees_; } /// @notice Calls app gateways with the specified parameters /// @param params_ Array of call from chain parameters /// @dev This function calls app gateways with the specified parameters - function _callAppGateways(TriggerParams memory params_) internal onlyOwner { - if (appGatewayCalled[params_.triggerId]) revert AppGatewayAlreadyCalled(); + /// @dev This function cannot be retried even if it fails + /// @dev Call can fail due to gas limit but watcher is a trusted entity + function _callAppGateways(TriggerParams memory params_) internal { + if (isAppGatewayCalled[params_.triggerId]) revert AppGatewayAlreadyCalled(); if (!configurations__().isValidPlug(params_.appGatewayId, params_.chainSlug, params_.plug)) revert InvalidCallerTriggered(); feesManager__().transferFrom(appGateway, address(this), triggerFees); - appGatewayCaller = appGateway; - appGatewayCalled[params_.triggerId] = true; + triggerFromChainSlug = params_.chainSlug; + triggerFromPlug = params_.plug; + isAppGatewayCalled[params_.triggerId] = true; (bool success, , ) = appGateway.tryCall( 0, gasleft(), 0, // setting max_copy_bytes to 0 as not using returnData right now params_.payload ); + if (!success) { - emit AppGatewayCallFailed(params_.triggerId); + emit TriggerFailed(params_.triggerId); } else { - emit CalledAppGateway(params_.triggerId); + emit TriggerSucceeded(params_.triggerId); } - appGatewayCaller = address(0); + triggerFromChainSlug = 0; + triggerFromPlug = address(0); } } diff --git a/contracts/evmx/watcher/Watcher.sol b/contracts/evmx/watcher/Watcher.sol index 4d18ceda..0f572a36 100644 --- a/contracts/evmx/watcher/Watcher.sol +++ b/contracts/evmx/watcher/Watcher.sol @@ -62,7 +62,7 @@ contract Watcher is Trigger { uint40 requestCount = requestHandler__.nextRequestCount(); // Deploy a new async promise contract. latestAsyncPromise = asyncDeployer__().deployAsyncPromiseContract( - coreAppGateway, + appGateway_, requestCount ); appGatewayTemp = coreAppGateway; @@ -122,6 +122,26 @@ contract Watcher is Trigger { return requestHandler__().getPayloadParams(payloadId_); } + function callAppGateways( + TriggerParams[] memory params_, + uint256 nonce_, + bytes memory signature_ + ) external { + _validateSignature(abi.encode(params_), nonce_, signature_); + for (uint40 i = 0; i < params_.length; i++) { + _callAppGateways(params_[i]); + } + } + + function setTriggerFees( + uint256 triggerFees_, + uint256 nonce_, + bytes memory signature_ + ) external { + _validateSignature(abi.encode(triggerFees_), nonce_, signature_); + _setTriggerFees(triggerFees_); + } + // all function from watcher requiring signature function watcherMultiCall( address[] memory contracts, @@ -131,20 +151,26 @@ contract Watcher is Trigger { ) external payable { for (uint40 i = 0; i < contracts.length; i++) { if (contracts[i] == address(0)) revert InvalidContract(); - if (data_[i].length == 0) revert InvalidData(); - if (nonces_[i] == 0) revert InvalidNonce(); - if (signatures_[i].length == 0) revert InvalidSignature(); - - // check if signature is valid - if (!_isWatcherSignatureValid(nonces_[i], data_[i], signatures_[i])) - revert InvalidSignature(); - + _validateSignature(data_[i], nonces_[i], signatures_[i]); // call the contract (bool success, bytes memory result) = contracts[i].call{value: msg.value}(data_[i]); if (!success) revert CallFailed(); } } + function _validateSignature( + bytes memory data_, + uint256 nonce_, + bytes memory signature_ + ) internal { + if (data_.length == 0) revert InvalidData(); + if (nonce_ == 0) revert InvalidNonce(); + if (signature_.length == 0) revert InvalidSignature(); + + // check if signature is valid + if (!_isWatcherSignatureValid(nonce_, data_, signature_)) revert InvalidSignature(); + } + /// @notice Verifies that a watcher signature is valid /// @param signatureNonce_ The nonce of the signature /// @param inputData_ The input data to verify diff --git a/contracts/evmx/watcher/precompiles/ReadPrecompile.sol b/contracts/evmx/watcher/precompiles/ReadPrecompile.sol index 4b0452d9..1a2d63a5 100644 --- a/contracts/evmx/watcher/precompiles/ReadPrecompile.sol +++ b/contracts/evmx/watcher/precompiles/ReadPrecompile.sol @@ -40,8 +40,9 @@ contract ReadPrecompile is IPrecompile, WatcherBase { function handlePayload( address, PayloadParams calldata payloadParams - ) external pure returns (uint256 fees) { + ) external pure returns (uint256 fees, uint256 deadline) { fees = readFees; + deadline = block.timestamp + expiryTime; (Transaction memory transaction, uint256 readAtBlockNumber) = abi.decode( payloadParams.precompileData, @@ -50,6 +51,8 @@ contract ReadPrecompile is IPrecompile, WatcherBase { emit ReadRequested(transaction, readAtBlockNumber, payloadParams.payloadId); } + function resolvePayload(PayloadParams calldata payloadParams_) external {} + function setFees(uint256 readFees_) external onlyWatcher { readFees = readFees_; emit FeesSet(readFees_); diff --git a/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol b/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol index c13490fa..3aad1678 100644 --- a/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol @@ -60,158 +60,35 @@ contract SchedulePrecompile is IPrecompile, WatcherBase { QueueParams calldata queuePayloadParams_, address appGateway_ ) external view returns (bytes memory precompileData, uint256 estimatedFees) { - if ( - queuePayloadParams_.transaction.target != address(0) && - appGateway_ != getCoreAppGateway(queuePayloadParams_.transaction.target) - ) revert InvalidTarget(); - - if ( - queuePayloadParams_.transaction.payload.length > 0 && - queuePayloadParams_.transaction.payload.length < PAYLOAD_SIZE_LIMIT - ) { - revert InvalidPayloadSize(); - } if (queuePayloadParams_.overrideParams.delayInSeconds > maxScheduleDelayInSeconds) revert InvalidScheduleDelay(); - // todo: how do we store tx data in promise and execute? - // For schedule precompile, encode the payload parameters - precompileData = abi.encode( - queuePayloadParams_.transaction, - queuePayloadParams_.overrideParams.delayInSeconds - ); - + precompileData = abi.encode(queuePayloadParams_.overrideParams.delayInSeconds); estimatedFees = scheduleFeesPerSecond * queuePayloadParams_.overrideParams.delayInSeconds + scheduleCallbackFees; } - // /// @notice Encodes a unique schedule ID - // /// @param scheduleIdPrefix The prefix for schedule IDs - // /// @param counter The counter value to include in the ID - // /// @return scheduleId The encoded schedule ID - // function encodeScheduleId( - // uint256 scheduleIdPrefix, - // uint256 counter - // ) public pure returns (bytes32 scheduleId) { - // // Encode schedule ID by bit-shifting and combining: - // // EVMx chainSlug (32 bits) | watcher precompile address (160 bits) | counter (64 bits) - // return bytes32(scheduleIdPrefix | counter); - // } - - /// @notice Prepares a schedule request - /// @param target The target address for the schedule callback - /// @param delayInSeconds_ The delay in seconds before the schedule executes - /// @param executeAt The timestamp when the schedule should be executed - /// @param payload_ The payload data to be executed after the schedule - /// @return request The prepared schedule request - function prepareScheduleRequest( - address target, - uint256 delayInSeconds_, - uint256 executeAt, - bytes memory payload_ - ) public pure returns (ScheduleRequest memory request) { - request.target = target; - request.delayInSeconds = delayInSeconds_; - request.executeAt = executeAt; - request.payload = payload_; - request.isResolved = false; - request.executedAt = 0; - return request; + /// @notice Handles payload processing and returns fees + /// @param payloadParams The payload parameters to handle + /// @return fees The fees required for processing + function handlePayload( + address, + PayloadParams calldata payloadParams + ) external pure returns (uint256 fees, uint256 deadline) { + uint256 delayInSeconds = abi.decode(payloadParams.precompileData, (uint256)); + // expiryTime is very low, to account for infra delay + deadline = block.timestamp + delayInSeconds + expiryTime; + + // emits event for watcher to track timeout and resolve when timeout is reached + emit ScheduleRequested(payloadParams.payloadId, deadline); } - /// @notice Validates schedule resolution conditions - /// @param request The schedule request to validate - /// @param currentTimestamp The current block timestamp - /// @return isValid Whether the schedule can be resolved - function _validateScheduleResolution( - ScheduleRequest memory request, - uint256 currentTimestamp - ) internal pure returns (bool isValid) { - if (request.target == address(0)) return false; - if (request.isResolved) return false; - if (currentTimestamp < request.executeAt) return false; - return true; - } - - /// @notice Creates the event data for schedule request - /// @param scheduleId The unique identifier for the schedule - /// @param target The target address for the schedule callback - /// @param payload The payload data to be executed - /// @param executeAt The timestamp when the schedule should be executed - /// @return The encoded event data for schedule request - function createScheduleRequestEventData( - bytes32 scheduleId, - address target, - bytes memory payload, - uint256 executeAt - ) public pure returns (bytes memory) { - return abi.encode(scheduleId, target, payload, executeAt); - } + function resolvePayload(PayloadParams calldata payloadParams_) external { + if (block.timestamp < payloadParams_.deadline) revert ResolvingTimeoutTooEarly(); - /// @notice Creates the event data for schedule resolution - /// @param scheduleId The unique identifier for the schedule - /// @param target The target address for the schedule callback - /// @param payload The payload data that was executed - /// @param executedAt The timestamp when the schedule was executed - /// @param returnData The return data from the schedule execution - /// @return The encoded event data for schedule resolution - function createScheduleResolvedEventData( - bytes32 scheduleId, - address target, - bytes memory payload, - uint256 executedAt, - bytes memory returnData - ) public pure returns (bytes memory) { - return abi.encode(scheduleId, target, payload, executedAt, returnData); + emit ScheduleResolved(payloadParams_.payloadId); } } - -// /// @notice Ends the timeouts and calls the target address with the callback payload -// /// @param timeoutId_ The unique identifier for the timeout -// function resolveTimeout( -// bytes32 timeoutId_, -// ) external { -// TimeoutRequest storage timeoutRequest_ = timeoutRequests[timeoutId_]; -// if (timeoutRequest_.target == address(0)) revert InvalidTimeoutRequest(); -// if (timeoutRequest_.isResolved) revert TimeoutAlreadyResolved(); -// if (block.timestamp < timeoutRequest_.executeAt) revert ResolvingTimeoutTooEarly(); - -// (bool success, , bytes memory returnData) = timeoutRequest_.target.tryCall( -// 0, -// gasleft(), -// 0, // setting max_copy_bytes to 0 as not using returnData right now -// timeoutRequest_.payload -// ); -// if (!success) revert CallFailed(); -// timeoutRequest_.isResolved = true; -// timeoutRequest_.executedAt = block.timestamp; - -// emit TimeoutResolved( -// timeoutId_, -// timeoutRequest_.target, -// timeoutRequest_.payload, -// block.timestamp, -// returnData -// ); -// } - -// /// @notice Sets a timeout for a payload execution on app gateway -// /// @return timeoutId The unique identifier for the timeout request -// function _setTimeout( -// uint256 delayInSeconds_, -// bytes memory payload_ -// ) internal returns (bytes32 timeoutId) { -// uint256 executeAt = block.timestamp + delayInSeconds_; -// timeoutId = _encodeTimeoutId(); - -// timeoutRequests[timeoutId].target = msg.sender; -// timeoutRequests[timeoutId].delayInSeconds = delayInSeconds_; -// timeoutRequests[timeoutId].executeAt = executeAt; -// timeoutRequests[timeoutId].payload = payload_; - -// // emits event for watcher to track timeout and resolve when timeout is reached -// emit TimeoutRequested(timeoutId, msg.sender, payload_, executeAt); -// } diff --git a/contracts/evmx/watcher/precompiles/WritePrecompile.sol b/contracts/evmx/watcher/precompiles/WritePrecompile.sol index d3ddc983..12802c59 100644 --- a/contracts/evmx/watcher/precompiles/WritePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/WritePrecompile.sol @@ -25,8 +25,6 @@ contract WritePrecompile is IPrecompile, WatcherBase { uint256 public writeFees; error MaxMsgValueLimitExceeded(); - error InvalidTarget(); - error InvalidPayloadSize(); /// @notice Emitted when fees are set event FeesSet(uint256 writeFees, uint256 callbackFees); @@ -83,8 +81,9 @@ contract WritePrecompile is IPrecompile, WatcherBase { function handlePayload( address transmitter_, PayloadParams calldata payloadParams - ) external pure returns (uint256 fees) { + ) external pure returns (uint256 fees, uint256 deadline) { fees = writeFees + callbackFees; + deadline = block.timestamp + expiryTime; ( Transaction transaction, @@ -189,4 +188,6 @@ contract WritePrecompile is IPrecompile, WatcherBase { writeFees = writeFees_; emit FeesSet(writeFees_); } + + function resolvePayload(PayloadParams calldata payloadParams_) external {} } diff --git a/test/apps/app-gateways/counter/CounterAppGateway.sol b/test/apps/app-gateways/counter/CounterAppGateway.sol index 8fe65074..fc87483d 100644 --- a/test/apps/app-gateways/counter/CounterAppGateway.sol +++ b/test/apps/app-gateways/counter/CounterAppGateway.sol @@ -107,15 +107,12 @@ contract CounterAppGateway is AppGatewayBase, Ownable { } // TIMEOUT - function setTimeout(uint256 delayInSeconds_) public { - bytes memory payload = abi.encodeWithSelector( - this.resolveTimeout.selector, - block.timestamp - ); - watcherPrecompile__().setTimeout(delayInSeconds_, payload); + function setTimeout(uint256 delayInSeconds_) public async(bytes("")) { + _setTimeout(delayInSeconds_); + then(this.resolveTimeout.selector, abi.encode(block.timestamp)); } - function resolveTimeout(uint256 creationTimestamp_) external onlyWatcher { + function resolveTimeout(uint256 creationTimestamp_) external onlyPromises { emit TimeoutResolved(creationTimestamp_, block.timestamp); } From d451f10e1040951a6698fabbb60b71e456f417e9 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Thu, 22 May 2025 13:47:23 +0530 Subject: [PATCH 036/130] feat: fix fee plug --- contracts/evmx/plugs/FeesPlug.sol | 57 ++++++++++++++++++------------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/contracts/evmx/plugs/FeesPlug.sol b/contracts/evmx/plugs/FeesPlug.sol index 5caa2480..f0a55978 100644 --- a/contracts/evmx/plugs/FeesPlug.sol +++ b/contracts/evmx/plugs/FeesPlug.sol @@ -2,20 +2,24 @@ pragma solidity ^0.8.21; import "solady/utils/SafeTransferLib.sol"; -import "solady/tokens/ERC20.sol"; import "../../protocol/base/PlugBase.sol"; import "../../utils/AccessControl.sol"; import {RESCUE_ROLE} from "../../utils/common/AccessRoles.sol"; import {IFeesPlug} from "../interfaces/IFeesPlug.sol"; import "../../utils/RescueFundsLib.sol"; -import {ETH_ADDRESS} from "../../utils/common/Constants.sol"; -import {InvalidTokenAddress, FeesAlreadyPaid} from "../../utils/common/Errors.sol"; +import {InvalidTokenAddress} from "../../utils/common/Errors.sol"; + +interface IERC20 { + function balanceOf(address account) external view returns (uint256); +} /// @title FeesPlug /// @notice Contract for managing fees on a network /// @dev The amount deposited here is locked and updated in the EVMx for an app gateway /// @dev The fees are redeemed by the transmitters executing request or can be withdrawn by the owner contract FeesPlug is IFeesPlug, PlugBase, AccessControl { + using SafeTransferLib for address; + /// @notice Mapping to store if a token is whitelisted mapping(address => bool) public whitelistedTokens; @@ -41,9 +45,10 @@ contract FeesPlug is IFeesPlug, PlugBase, AccessControl { event TokenRemovedFromWhitelist(address token); /// @notice Modifier to check if the balance of a token is enough to withdraw - modifier isBalanceEnough(address feeToken_, uint256 fee_) { - uint balance_ = ERC20(feeToken_).balanceOf(address(this)); - if (balance_ < fee_) revert InsufficientTokenBalance(feeToken_, balance_, fee_); + modifier isBalanceEnough(address feeToken_, uint256 withdrawAmount_) { + uint balance = IERC20(feeToken_).balanceOf(address(this)); + if (balance < withdrawAmount_) + revert InsufficientTokenBalance(feeToken_, balance, withdrawAmount_); _; } @@ -55,19 +60,7 @@ contract FeesPlug is IFeesPlug, PlugBase, AccessControl { _initializeOwner(owner_); } - /// @notice Withdraws fees - /// @param token_ The token address - /// @param amount_ The amount - /// @param receiver_ The receiver address - function withdrawFees( - address token_, - address receiver_, - uint256 amount_ - ) external override onlySocket isBalanceEnough(token_, amount_) { - SafeTransferLib.safeTransfer(token_, receiver_, amount_); - emit FeesWithdrawn(token_, receiver_, amount_); - } - + /////////////////////// DEPOSIT AND WITHDRAWAL /////////////////////// function depositToFee(address token_, address receiver_, uint256 amount_) external override { _deposit(token_, receiver_, amount_, 0); } @@ -78,8 +71,7 @@ contract FeesPlug is IFeesPlug, PlugBase, AccessControl { uint256 amount_ ) external override { uint256 nativeAmount_ = amount_ / 10; - uint256 creditAmount_ = amount_ - nativeAmount_; - _deposit(token_, receiver_, creditAmount_, nativeAmount_); + _deposit(token_, receiver_, amount_ - nativeAmount_, nativeAmount_); } function depositToNative(address token_, address receiver_, uint256 amount_) external override { @@ -97,12 +89,31 @@ contract FeesPlug is IFeesPlug, PlugBase, AccessControl { uint256 creditAmount_, uint256 nativeAmount_ ) internal { - uint256 totalAmount_ = creditAmount_ + nativeAmount_; if (!whitelistedTokens[token_]) revert TokenNotWhitelisted(token_); - SafeTransferLib.safeTransferFrom(token_, msg.sender, address(this), totalAmount_); + SafeTransferLib.safeTransferFrom( + token_, + msg.sender, + address(this), + creditAmount_ + nativeAmount_ + ); emit FeesDeposited(token_, receiver_, creditAmount_, nativeAmount_); } + /// @notice Withdraws fees + /// @param token_ The token address + /// @param amount_ The amount + /// @param receiver_ The receiver address + function withdrawFees( + address token_, + address receiver_, + uint256 amount_ + ) external override onlySocket isBalanceEnough(token_, amount_) { + SafeTransferLib.safeTransfer(token_, receiver_, amount_); + emit FeesWithdrawn(token_, receiver_, amount_); + } + + /////////////////////// ADMIN FUNCTIONS /////////////////////// + /// @notice Adds a token to the whitelist /// @param token_ The token address to whitelist function whitelistToken(address token_) external onlyOwner { From 2963112402791795f72f7877e1882cf23b2b1c03 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Thu, 22 May 2025 14:09:53 +0530 Subject: [PATCH 037/130] fix: fees manager --- contracts/evmx/base/AppGatewayBase.sol | 2 +- contracts/evmx/fees/Credit.sol | 122 +++++------- contracts/evmx/fees/FeesManager.sol | 184 +++--------------- contracts/evmx/fees/FeesStorage.sol | 11 +- contracts/evmx/watcher/Trigger.sol | 2 +- contracts/evmx/watcher/Watcher.sol | 40 ++-- .../WithdrawFeesArbitrumFeesPlug.s.sol | 2 +- 7 files changed, 98 insertions(+), 265 deletions(-) diff --git a/contracts/evmx/base/AppGatewayBase.sol b/contracts/evmx/base/AppGatewayBase.sol index 2e839fcf..f6773922 100644 --- a/contracts/evmx/base/AppGatewayBase.sol +++ b/contracts/evmx/base/AppGatewayBase.sol @@ -320,7 +320,7 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { function onRequestComplete( uint40, bytes calldata onCompleteData_ - ) external override onlyDeliveryHelper { + ) external override onlyWatcher { if (onCompleteData_.length == 0) return; (uint32 chainSlug, bool isDeploy) = abi.decode(onCompleteData_, (uint32, bool)); if (isDeploy) { diff --git a/contracts/evmx/fees/Credit.sol b/contracts/evmx/fees/Credit.sol index 77ab20c6..a824e9f0 100644 --- a/contracts/evmx/fees/Credit.sol +++ b/contracts/evmx/fees/Credit.sol @@ -5,7 +5,7 @@ import "./FeesStorage.sol"; /// @title UserUtils /// @notice Contract for managing user utils -abstract contract UserUtils is FeesStorage, Initializable, Ownable, AddressResolverUtil { +abstract contract Credit is FeesStorage, Initializable, Ownable, AddressResolverUtil { /// @notice Emitted when fees deposited are updated /// @param chainSlug The chain identifier /// @param appGateway The app gateway address @@ -47,31 +47,10 @@ abstract contract UserUtils is FeesStorage, Initializable, Ownable, AddressResol emit CreditsDeposited(chainSlug_, depositTo_, token_, creditAmount_); } - /// @notice Adds the fees deposited for an app gateway on a chain - /// @param depositTo_ The app gateway address - // @dev only callable by watcher precompile - // @dev will need tokenAmount_ and creditAmount_ when introduce tokens except stables - function depositCredits( - address depositTo_, - uint32 chainSlug_, - address token_, - uint256 nativeAmount_, - uint256 creditAmount_ - ) external payable onlyWatcher { - if (creditAmount_ + nativeAmount_ != msg.value) revert InvalidAmount(); - - UserCredits storage userCredit = userCredits[depositTo_]; - userCredit.totalCredits += creditAmount_; - tokenPoolBalances[chainSlug_][token_] += creditAmount_; - payable(depositTo_).transfer(nativeAmount_); - - emit CreditsDeposited(chainSlug_, depositTo_, token_, creditAmount_); - } - - function wrap() external payable { - UserCredits storage userCredit = userCredits[msg.sender]; + function wrap(address receiver_) external payable { + UserCredits storage userCredit = userCredits[receiver_]; userCredit.totalCredits += msg.value; - emit CreditsWrapped(msg.sender, msg.value); + emit CreditsWrapped(receiver_, msg.value); } function unwrap(uint256 amount_) external { @@ -79,7 +58,6 @@ abstract contract UserUtils is FeesStorage, Initializable, Ownable, AddressResol if (userCredit.totalCredits < amount_) revert InsufficientCreditsAvailable(); userCredit.totalCredits -= amount_; - // todo-later: if contract balance not enough, take from our pool? if (address(this).balance < amount_) revert InsufficientBalance(); payable(msg.sender).transfer(amount_); @@ -114,18 +92,8 @@ abstract contract UserUtils is FeesStorage, Initializable, Ownable, AddressResol return getAvailableCredits(from_) >= amount_; } - function _updateUserCredits( - address consumeFrom_, - uint256 toConsumeFromBlocked_, - uint256 toConsumeFromTotal_ - ) internal { - UserCredits storage userCredit = userCredits[consumeFrom_]; - userCredit.blockedCredits -= toConsumeFromBlocked_; - userCredit.totalCredits -= toConsumeFromTotal_; - } - function transferCredits(address from_, address to_, uint256 amount_) external { - if (!isUserCreditsEnough(from_, to_, amount_)) revert InsufficientCreditsAvailable(); + if (!isUserCreditsEnough(from_, msg.sender, amount_)) revert InsufficientCreditsAvailable(); userCredits[from_].totalCredits -= amount_; userCredits[to_].totalCredits += amount_; @@ -149,59 +117,59 @@ abstract contract UserUtils is FeesStorage, Initializable, Ownable, AddressResol function _processFeeApprovalData( bytes memory feeApprovalData_ ) internal returns (address, address, bool) { - (address consumeFrom, address appGateway, bool isApproved, bytes memory signature_) = abi - .decode(feeApprovalData_, (address, address, bool, bytes)); - + ( + address consumeFrom, + address appGateway, + bool isApproved, + uint256 nonce, + bytes memory signature_ + ) = abi.decode(feeApprovalData_, (address, address, bool, uint256, bytes)); + + if (isNonceUsed[consumeFrom][nonce]) revert NonceUsed(); + // todo: check if (signature_.length == 0) { // If no signature, consumeFrom is appGateway return (appGateway, appGateway, isApproved); } + bytes32 digest = keccak256( - abi.encode( - address(this), - evmxSlug, - consumeFrom, - appGateway, - userNonce[consumeFrom], - isApproved - ) + abi.encode(address(this), evmxSlug, consumeFrom, appGateway, nonce, isApproved) ); if (_recoverSigner(digest, signature_) != consumeFrom) revert InvalidUserSignature(); isAppGatewayWhitelisted[consumeFrom][appGateway] = isApproved; - userNonce[consumeFrom]++; + isNonceUsed[consumeFrom][nonce] = true; return (consumeFrom, appGateway, isApproved); } /// @notice Withdraws funds to a specified receiver /// @dev This function is used to withdraw fees from the fees plug - /// @param originAppGatewayOrUser_ The address of the app gateway + /// @dev assumed that transmitter can bid for their request on AM /// @param chainSlug_ The chain identifier /// @param token_ The address of the token /// @param amount_ The amount of tokens to withdraw + /// @param maxFees_ The fees needed for the request /// @param receiver_ The address of the receiver function withdrawCredits( - address originAppGatewayOrUser_, uint32 chainSlug_, address token_, uint256 amount_, uint256 maxFees_, address receiver_ ) public { - if (msg.sender != address(deliveryHelper__())) originAppGatewayOrUser_ = msg.sender; - address source = _getCoreAppGateway(originAppGatewayOrUser_); + address consumeFrom = _getCoreAppGateway(msg.sender); // Check if amount is available in fees plug - uint256 availableAmount = getAvailableCredits(source); + uint256 availableAmount = getAvailableCredits(consumeFrom); if (availableAmount < amount_) revert InsufficientCreditsAvailable(); - _useAvailableUserCredits(source, amount_); + userCredits[consumeFrom].totalCredits -= amount_; tokenPoolBalances[chainSlug_][token_] -= amount_; // Add it to the queue and submit request _createRequest( chainSlug_, - msg.sender, + consumeFrom, maxFees_, abi.encodeCall(IFeesPlug.withdrawFees, (token_, receiver_, amount_)) ); @@ -213,25 +181,19 @@ abstract contract UserUtils is FeesStorage, Initializable, Ownable, AddressResol uint256 maxFees_, bytes memory payload_ ) internal { - QueueParams memory queueParams = QueueParams({ - overrideParams: OverrideParams({ - isPlug: IsPlug.NO, - callType: WRITE, - isParallelCall: Parallel.OFF, - gasLimit: 10000000, - value: 0, - readAtBlockNumber: 0, - writeFinality: WriteFinality.LOW, - delayInSeconds: 0 - }), - transaction: Transaction({ - chainSlug: chainSlug_, - target: _getFeesPlugAddress(chainSlug_), - payload: payload_ - }), - asyncPromise: address(0), - switchboardType: sbType + OverrideParams memory overrideParams; + overrideParams.callType = WRITE; + overrideParams.gasLimit = 10000000; + overrideParams.writeFinality = WriteFinality.LOW; + + QueueParams memory queueParams; + queueParams.overrideParams = overrideParams; + queueParams.transaction = Transaction({ + chainSlug: chainSlug_, + target: _getFeesPlugAddress(chainSlug_), + payload: payload_ }); + queueParams.switchboardType = sbType; // queue and create request watcherPrecompile__().queueAndRequest( @@ -243,11 +205,12 @@ abstract contract UserUtils is FeesStorage, Initializable, Ownable, AddressResol ); } - /// @notice hook called by watcher precompile when request is finished - function onRequestComplete(uint40 requestCount_, bytes memory) external {} - function _getFeesPlugAddress(uint32 chainSlug_) internal view returns (address) { - return watcherPrecompileConfig().feesPlug(chainSlug_); + return configuration__().feesPlug(chainSlug_); + } + + function _getRequestParams(uint40 requestCount_) internal view returns (RequestParams memory) { + return watcher__().getRequestParams(requestCount_); } function _recoverSigner( @@ -258,4 +221,7 @@ abstract contract UserUtils is FeesStorage, Initializable, Ownable, AddressResol // recovered signer is checked for the valid roles later signer = ECDSA.recover(digest, signature_); } + + /// @notice hook called by watcher precompile when request is finished + function onRequestComplete(uint40, bytes memory) external {} } diff --git a/contracts/evmx/fees/FeesManager.sol b/contracts/evmx/fees/FeesManager.sol index 6e1aa275..a3dd6001 100644 --- a/contracts/evmx/fees/FeesManager.sol +++ b/contracts/evmx/fees/FeesManager.sol @@ -5,7 +5,7 @@ import "./Credit.sol"; /// @title FeesManager /// @notice Contract for managing fees -abstract contract FeesManager is Credit, Initializable, Ownable, AddressResolverUtil { +abstract contract FeesManager is Credit { /// @notice Emitted when fees are blocked for a batch /// @param requestCount The batch identifier /// @param consumeFrom The consume from address @@ -65,6 +65,8 @@ abstract contract FeesManager is Credit, Initializable, Ownable, AddressResolver _initializeOwner(owner_); } + /////////////////////// FEES MANAGEMENT /////////////////////// + /// @notice Blocks fees for a request count /// @param consumeFrom_ The fees payer address /// @param transmitterCredits_ The total fees to block @@ -74,14 +76,14 @@ abstract contract FeesManager is Credit, Initializable, Ownable, AddressResolver uint40 requestCount_, address consumeFrom_, uint256 credits_ - ) external onlyWatcher { - if (getAvailableCredits(consumeFrom_) < credits_) revert InsufficientCreditsAvailable(); + ) external onlyRequestHandler { + address consumeFrom = _getCoreAppGateway(consumeFrom_); + if (getAvailableCredits(consumeFrom) < credits_) revert InsufficientCreditsAvailable(); - UserCredits storage userCredit = userCredits[consumeFrom_]; + UserCredits storage userCredit = userCredits[consumeFrom]; userCredit.blockedCredits += credits_; - requestCountCredits[requestCount_] = credits_; - emit CreditsBlocked(requestCount_, consumeFrom_, credits_); + emit CreditsBlocked(requestCount_, consumeFrom, credits_); } /// @notice Unblocks fees after successful execution and assigns them to the transmitter @@ -90,177 +92,43 @@ abstract contract FeesManager is Credit, Initializable, Ownable, AddressResolver function unblockAndAssignCredits( uint40 requestCount_, address assignTo_ - ) external override onlyWatcher { + ) external override onlyRequestHandler { uint256 blockedCredits = requestCountCredits[requestCount_]; if (blockedCredits == 0) return; - RequestParams memory requestParams = _getRequestParams(requestCount_); - uint256 fees = requestParams.requestFeesDetails.maxFees; - // Unblock fees from deposit - _updateUserCredits(requestParams.consumeFrom, blockedCredits, fees); + _consumeUserCredits( + _getRequestParams(requestCount_).consumeFrom, + blockedCredits, + blockedCredits + ); // Assign fees to transmitter - userCredits[assignTo_].totalCredits += fees; + userCredits[assignTo_].totalCredits += blockedCredits; // Clean up storage delete requestCountCredits[requestCount_]; - emit CreditsUnblockedAndAssigned(requestCount_, assignTo_, fees); + emit CreditsUnblockedAndAssigned(requestCount_, assignTo_, blockedCredits); } - function _useAvailableUserCredits(address consumeFrom_, uint256 toConsume_) internal { - UserCredits storage userCredit = userCredits[consumeFrom_]; - if (userCredit.totalCredits < toConsume_) revert InsufficientCreditsAvailable(); - userCredit.totalCredits -= toConsume_; - } - - function unblockCredits(uint40 requestCount_) external onlyWatcher { + function unblockCredits(uint40 requestCount_) external onlyRequestHandler { RequestParams memory r = _getRequestParams(requestCount_); uint256 blockedCredits = requestCountCredits[requestCount_]; if (blockedCredits == 0) return; // Unblock fees from deposit - _updateUserCredits(r.requestFeesDetails.consumeFrom, blockedCredits, 0); + _consumeUserCredits(r.requestFeesDetails.consumeFrom, blockedCredits, 0); delete requestCountCredits[requestCount_]; emit CreditsUnblocked(requestCount_, r.requestFeesDetails.consumeFrom); } - function _getRequestParams(uint40 requestCount_) internal view returns (RequestParams memory) { - return watcher__().getRequestParams(requestCount_); + function _consumeUserCredits( + address consumeFrom_, + uint256 toConsumeFromBlocked_, + uint256 toConsumeFromTotal_ + ) internal { + UserCredits storage userCredit = userCredits[consumeFrom_]; + userCredit.blockedCredits -= toConsumeFromBlocked_; + userCredit.totalCredits -= toConsumeFromTotal_; } } - -// /// @notice Withdraws funds to a specified receiver -// /// @param chainSlug_ The chain identifier -// /// @param token_ The address of the token -// /// @param amount_ The amount of tokens to withdraw -// /// @param receiver_ The address of the receiver -// /// @param fees_ The fees data -// function withdrawTo( -// uint32 chainSlug_, -// address token_, -// uint256 amount_, -// address receiver_, -// address auctionManager_, -// uint256 fees_ -// ) external returns (uint40) { -// feesManager__().withdrawCredits( -// msg.sender, -// chainSlug_, -// token_, -// amount_, -// receiver_ -// ); -// return _batch(msg.sender, auctionManager_, msg.sender, fees_, bytes("")); -// } - -// /// @notice Withdraws fees to a specified receiver -// /// @param chainSlug_ The chain identifier -// /// @param token_ The token address -// /// @param receiver_ The address of the receiver -// function withdrawTransmitterFees( -// uint32 chainSlug_, -// address token_, -// address receiver_, -// uint256 amount_ -// ) external returns (uint40 requestCount) { -// address transmitter = msg.sender; - -// PayloadSubmitParams[] memory payloadSubmitParamsArray = feesManager__() -// .getWithdrawTransmitterCreditsPayloadParams( -// transmitter, -// chainSlug_, -// token_, -// receiver_, -// amount_ -// ); - -// RequestMetadata memory requestMetadata = RequestMetadata({ -// appGateway: feesManager__(), -// auctionManager: address(0), -// maxFees: 0, -// winningBid: Bid({transmitter: transmitter, fee: 0, extraData: new bytes(0)}), -// onCompleteData: bytes(""), -// onlyReadRequests: false, -// consumeFrom: transmitter, -// queryCount: 0, -// finalizeCount: 1 -// }); // finalize for plug contract -// requestCount = watcherPrecompile__().submitRequest(payloadSubmitParamsArray); -// requests[requestCount] = requestMetadata; -// // same transmitter can execute requests without auction -// watcherPrecompile__().startProcessingRequest(requestCount, transmitter); -// } - - -// /// @notice Withdraws funds to a specified receiver - // /// @dev This function is used to withdraw fees from the fees plug - // /// @param originAppGatewayOrUser_ The address of the app gateway - // /// @param chainSlug_ The chain identifier - // /// @param token_ The address of the token - // /// @param amount_ The amount of tokens to withdraw - // /// @param receiver_ The address of the receiver - // function withdrawCredits( - // address originAppGatewayOrUser_, - // uint32 chainSlug_, - // address token_, - // uint256 amount_, - // address receiver_ - // ) public { - // if (msg.sender != address(deliveryHelper__())) originAppGatewayOrUser_ = msg.sender; - // address source = _getCoreAppGateway(originAppGatewayOrUser_); - - // // Check if amount is available in fees plug - // uint256 availableAmount = getAvailableCredits(source); - // if (availableAmount < amount_) revert InsufficientCreditsAvailable(); - - // _useAvailableUserCredits(source, amount_); - // tokenPoolBalances[chainSlug_][token_] -= amount_; - - // // Add it to the queue and submit request - // _queue(chainSlug_, abi.encodeCall(IFeesPlug.withdrawFees, (token_, receiver_, amount_))); - // } - - // /// @notice Withdraws fees to a specified receiver - // /// @param chainSlug_ The chain identifier - // /// @param token_ The token address - // /// @param receiver_ The address of the receiver - // function getWithdrawTransmitterCreditsPayloadParams( - // address transmitter_, - // uint32 chainSlug_, - // address token_, - // address receiver_, - // uint256 amount_ - // ) external onlyWatcher returns (PayloadSubmitParams[] memory) { - // uint256 maxCreditsAvailableForWithdraw = getMaxCreditsAvailableForWithdraw(transmitter_); - // if (amount_ > maxCreditsAvailableForWithdraw) revert InsufficientCreditsAvailable(); - - // // Clean up storage - // _useAvailableUserCredits(transmitter_, amount_); - // tokenPoolBalances[chainSlug_][token_] -= amount_; - - // bytes memory payload = abi.encodeCall(IFeesPlug.withdrawFees, (token_, receiver_, amount_)); - // PayloadSubmitParams[] memory payloadSubmitParamsArray = new PayloadSubmitParams[](1); - // payloadSubmitParamsArray[0] = PayloadSubmitParams({ - // levelNumber: 0, - // chainSlug: chainSlug_, - // callType: WRITE, - // isParallel: Parallel.OFF, - // writeFinality: WriteFinality.LOW, - // asyncPromise: address(0), - // switchboard: _getSwitchboard(chainSlug_), - // target: _getFeesPlugAddress(chainSlug_), - // appGateway: address(this), - // gasLimit: 10000000, - // value: 0, - // readAtBlockNumber: 0, - // payload: payload - // }); - // return payloadSubmitParamsArray; - // } - - // function getMaxCreditsAvailableForWithdraw(address transmitter_) public view returns (uint256) { - // uint256 watcherFees = watcherPrecompileLimits().getTotalFeesRequired(0, 1, 0, 1); - // uint256 transmitterCredits = userCredits[transmitter_].totalCredits; - // return transmitterCredits > watcherFees ? transmitterCredits - watcherFees : 0; - // } \ No newline at end of file diff --git a/contracts/evmx/fees/FeesStorage.sol b/contracts/evmx/fees/FeesStorage.sol index ce7b13dc..f8cd6f18 100644 --- a/contracts/evmx/fees/FeesStorage.sol +++ b/contracts/evmx/fees/FeesStorage.sol @@ -13,6 +13,11 @@ import "../watcher/WatcherBase.sol"; abstract contract FeesManagerStorage is IFeesManager, WatcherBase { // user credits => stores fees for user, app gateway, transmitters and watcher precompile mapping(address => UserCredits) public userCredits; + + /// @notice Mapping to track request credits details for each request count + /// @dev requestCount => RequestFee + mapping(uint40 => uint256) public requestCountCredits; + // user approved app gateways // userAddress => appGateway => isWhitelisted mapping(address => mapping(address => bool)) public isAppGatewayWhitelisted; @@ -21,12 +26,6 @@ abstract contract FeesManagerStorage is IFeesManager, WatcherBase { // chainSlug => token address => amount mapping(uint32 => mapping(address => uint256)) public tokenPoolBalances; - // slot 54 - /// @notice Mapping to track request credits details for each request count - /// @dev requestCount => RequestFee - mapping(uint40 => uint256) public requestCountCredits; - - // slot 56 /// @notice Mapping to track nonce to whether it has been used /// @dev address => signatureNonce => isNonceUsed /// @dev used by watchers or other users in signatures diff --git a/contracts/evmx/watcher/Trigger.sol b/contracts/evmx/watcher/Trigger.sol index 78bdcae3..d99d8507 100644 --- a/contracts/evmx/watcher/Trigger.sol +++ b/contracts/evmx/watcher/Trigger.sol @@ -37,7 +37,7 @@ abstract contract Trigger is WatcherStorage { if (!configurations__().isValidPlug(params_.appGatewayId, params_.chainSlug, params_.plug)) revert InvalidCallerTriggered(); - feesManager__().transferFrom(appGateway, address(this), triggerFees); + feesManager__().transferCredits(appGateway, address(this), triggerFees); triggerFromChainSlug = params_.chainSlug; triggerFromPlug = params_.plug; diff --git a/contracts/evmx/watcher/Watcher.sol b/contracts/evmx/watcher/Watcher.sol index 0f572a36..e05de886 100644 --- a/contracts/evmx/watcher/Watcher.sol +++ b/contracts/evmx/watcher/Watcher.sol @@ -21,11 +21,6 @@ contract Watcher is Trigger { addressResolver__ = addressResolver_; } - /// @notice Clears the call parameters array - function clearQueue() public { - delete queue; - } - function queueAndRequest( QueueParams memory queue_, uint256 maxFees, @@ -105,21 +100,9 @@ contract Watcher is Trigger { clearQueue(); } - /// @notice Sets the expiry time for payload execution - /// @param expiryTime_ The expiry time in seconds - /// @dev This function sets the expiry time for payload execution - /// @dev Only callable by the contract owner - function setExpiryTime(uint256 expiryTime_) external onlyOwner { - expiryTime = expiryTime_; - emit ExpiryTimeSet(expiryTime_); - } - - function getRequestParams(uint40 requestCount_) external view returns (RequestParams memory) { - return requestHandler__().getRequestParams(requestCount_); - } - - function getPayloadParams(bytes32 payloadId_) external view returns (PayloadParams memory) { - return requestHandler__().getPayloadParams(payloadId_); + /// @notice Clears the call parameters array + function clearQueue() public { + delete queue; } function callAppGateways( @@ -133,6 +116,23 @@ contract Watcher is Trigger { } } + function getRequestParams(uint40 requestCount_) external view returns (RequestParams memory) { + return requestHandler__().getRequestParams(requestCount_); + } + + function getPayloadParams(bytes32 payloadId_) external view returns (PayloadParams memory) { + return requestHandler__().getPayloadParams(payloadId_); + } + + /// @notice Sets the expiry time for payload execution + /// @param expiryTime_ The expiry time in seconds + /// @dev This function sets the expiry time for payload execution + /// @dev Only callable by the contract owner + function setExpiryTime(uint256 expiryTime_) external onlyOwner { + expiryTime = expiryTime_; + emit ExpiryTimeSet(expiryTime_); + } + function setTriggerFees( uint256 triggerFees_, uint256 nonce_, diff --git a/script/counter/WithdrawFeesArbitrumFeesPlug.s.sol b/script/counter/WithdrawFeesArbitrumFeesPlug.s.sol index 57ad117e..b69a2c9a 100644 --- a/script/counter/WithdrawFeesArbitrumFeesPlug.s.sol +++ b/script/counter/WithdrawFeesArbitrumFeesPlug.s.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.21; import {Script} from "forge-std/Script.sol"; import {console} from "forge-std/console.sol"; -import {FeesManager} from "../../contracts/evmx/payload-delivery/FeesManager.sol"; +import {FeesManager} from "../../contracts/evmx/fees/FeesManager.sol"; import {ETH_ADDRESS} from "../../contracts/utils/common/Constants.sol"; import {CounterAppGateway} from "../../test/apps/app-gateways/counter/CounterAppGateway.sol"; From 5817765a40171e0f5bbca95d8af8be26d6b5d03e Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Thu, 22 May 2025 14:12:09 +0530 Subject: [PATCH 038/130] fix: remove counter --- contracts/evmx/fees/FeesStorage.sol | 2 -- 1 file changed, 2 deletions(-) diff --git a/contracts/evmx/fees/FeesStorage.sol b/contracts/evmx/fees/FeesStorage.sol index f8cd6f18..e958a5aa 100644 --- a/contracts/evmx/fees/FeesStorage.sol +++ b/contracts/evmx/fees/FeesStorage.sol @@ -30,6 +30,4 @@ abstract contract FeesManagerStorage is IFeesManager, WatcherBase { /// @dev address => signatureNonce => isNonceUsed /// @dev used by watchers or other users in signatures mapping(address => mapping(uint256 => bool)) public isNonceUsed; - - uint256 public withdrawCounter; } From c9a80d3c31a5e6583b149022781605f8cf20d6a4 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Thu, 22 May 2025 14:38:33 +0530 Subject: [PATCH 039/130] feat: deploy forwarder --- .../evmx/app-gateways/DeployerGateway.sol | 91 ------------------- contracts/evmx/base/AppGatewayBase.sol | 47 +++++++--- contracts/evmx/helpers/DeployForwarder.sol | 61 +++++++++++++ 3 files changed, 97 insertions(+), 102 deletions(-) delete mode 100644 contracts/evmx/app-gateways/DeployerGateway.sol create mode 100644 contracts/evmx/helpers/DeployForwarder.sol diff --git a/contracts/evmx/app-gateways/DeployerGateway.sol b/contracts/evmx/app-gateways/DeployerGateway.sol deleted file mode 100644 index e69feb92..00000000 --- a/contracts/evmx/app-gateways/DeployerGateway.sol +++ /dev/null @@ -1,91 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -pragma solidity ^0.8.21; - -import {AppGatewayBase} from "../base/AppGatewayBase.sol"; -import {PayloadSubmitParams, QueuePayloadParams} from "../../utils/common/Structs.sol"; - -/// @title DeployerGateway -/// @notice App gateway contract responsible for handling deployment requests -/// @dev Extends AppGatewayBase to provide deployment queueing functionality -contract DeployerGateway is AppGatewayBase { - // slot 51 - /// @notice The counter for the salt used to generate/deploy the contract address - uint256 public saltCounter; - - /// @notice Emitted when a new deployment request is queued - /// @param bytecode The contract bytecode to deploy - /// @param salt The deployment salt - event DeploymentQueued(bytes bytecode, bytes32 salt); - - /// @notice Deploys a contract - /// @param contractId_ The contract ID - /// @param chainSlug_ The chain slug - function deploy( - bytes32 deploymentType_, - bytes32 contractId_, - uint32 chainSlug_, - OverrideParams memory overrideParams_, - bytes memory initCallData_, - bytes memory payload_ - ) external { - if (!isAsyncModifierSet) revert AsyncModifierNotUsed(); - onCompleteData = abi.encode(chainSlug_, true); - - QueuePayloadParams memory queuePayloadParams = QueuePayloadParams({ - overrideParams: overrideParams, - transaction: Transaction({ - chainSlug: chainSlug_, - target: contractFactoryPlug[chainSlug_], - payload: payload_ - }), - asyncPromise: address(0), - switchboardType: sbType - }); - - // isPlug: isPlug_, - // payload: payload_, - // initCallData: initCallData_ - - IPromise(asyncPromise).then(this.setAddress.selector, abi.encode(chainSlug_, contractId_)); - isValidPromise[asyncPromise] = true; - - if (queuePayloadParams.payload.length > PAYLOAD_SIZE_LIMIT) revert PayloadTooLarge(); - IWatcher(deliveryHelper__()).queue(queuePayloadParams); - } - - /// @notice Sets the address for a deployed contract - /// @param data_ The data - /// @param returnData_ The return data - function setAddress(bytes memory data_, bytes memory returnData_) external onlyPromises { - (uint32 chainSlug, bytes32 contractId) = abi.decode(data_, (uint32, bytes32)); - address forwarderContractAddress = addressResolver__.getOrDeployForwarderContract( - address(this), - abi.decode(returnData_, (address)), - chainSlug - ); - - forwarderAddresses[appGateway][contractId][chainSlug] = forwarderContractAddress; - } - - function _createDeployPayloadDetails( - QueuePayloadParams memory queuePayloadParams_ - ) internal returns (bytes memory payload, address target) { - bytes32 salt = keccak256( - abi.encode(queuePayloadParams_.appGateway, queuePayloadParams_.chainSlug, saltCounter++) - ); - - // app gateway is set in the plug deployed on chain - payload = abi.encodeWithSelector( - IContractFactoryPlug.deployContract.selector, - queuePayloadParams_.isPlug, - salt, - bytes32(uint256(uint160(queuePayloadParams_.appGateway))), - queuePayloadParams_.switchboard, - queuePayloadParams_.payload, - queuePayloadParams_.initCallData - ); - - // getting app gateway for deployer as the plug is connected to the app gateway - target = getDeliveryHelperPlugAddress(queuePayloadParams_.chainSlug); - } -} diff --git a/contracts/evmx/base/AppGatewayBase.sol b/contracts/evmx/base/AppGatewayBase.sol index f6773922..3a970e25 100644 --- a/contracts/evmx/base/AppGatewayBase.sol +++ b/contracts/evmx/base/AppGatewayBase.sol @@ -5,7 +5,7 @@ import "../helpers/AddressResolverUtil.sol"; import "../interfaces/IAppGateway.sol"; import "../interfaces/IForwarder.sol"; -import {InvalidPromise, FeesNotSet, AsyncModifierNotUsed} from "../../utils/common/Errors.sol"; +import {InvalidPromise, FeesNotSet, AsyncModifierNotSet} from "../../utils/common/Errors.sol"; import {FAST, READ, WRITE, SCHEDULE} from "../../utils/common/Constants.sol"; /// @title AppGatewayBase @@ -125,15 +125,47 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { /// @notice Deploys a contract /// @param contractId_ The contract ID /// @param chainSlug_ The chain slug - function _deploy(bytes32 contractId_, uint32 chainSlug_, IsPlug isPlug_) internal { - _deploy(contractId_, chainSlug_, isPlug_, new bytes(0)); + function _deploy( + bytes32 contractId_, + uint32 chainSlug_, + IsPlug isPlug_, + bytes memory initCallData_ + ) internal { + if (!isAsyncModifierSet) revert AsyncModifierNotSet(); + deployerGateway__().deploy( + contractId_, + chainSlug_, + overrideParams, + creationCodeWithArgs[contractId_], + initCallData_ + ); + IPromise(watcher__().latestAsyncPromise()).then( + this.setAddress.selector, + abi.encode(chainSlug_, contractId_) + ); + + onCompleteData = abi.encode(chainSlug_, true); + } + + /// @notice Sets the address for a deployed contract + /// @param data_ The data + /// @param returnData_ The return data + function setAddress(bytes memory data_, bytes memory returnData_) external onlyPromises { + (uint32 chainSlug, bytes32 contractId) = abi.decode(data_, (uint32, bytes32)); + address forwarderContractAddress = addressResolver__.getOrDeployForwarderContract( + address(this), + abi.decode(returnData_, (address)), + chainSlug + ); + + forwarderAddresses[appGateway][contractId][chainSlug] = forwarderContractAddress; } /// @notice Schedules a function to be called after a delay /// @param delayInSeconds_ The delay in seconds /// @dev callback function and data is set in .then call function _setTimeout(uint256 delayInSeconds_) internal { - if (!isAsyncModifierSet) revert AsyncModifierNotUsed(); + if (!isAsyncModifierSet) revert AsyncModifierNotSet(); overrideParams.callType = SCHEDULE; overrideParams.delayInSeconds = delayInSeconds_; @@ -142,13 +174,6 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { (address promise_, ) = watcherPrecompile__().queue(queueParams, address(this)); } - /// @notice Gets the socket address - /// @param chainSlug_ The chain slug - /// @return socketAddress_ The socket address - function getSocketAddress(uint32 chainSlug_) public view returns (address) { - return watcherPrecompile__().sockets(chainSlug_); - } - /// @notice Gets the on-chain address /// @param contractId_ The contract ID /// @param chainSlug_ The chain slug diff --git a/contracts/evmx/helpers/DeployForwarder.sol b/contracts/evmx/helpers/DeployForwarder.sol new file mode 100644 index 00000000..e9cab496 --- /dev/null +++ b/contracts/evmx/helpers/DeployForwarder.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import {QueueParams, OverrideParams, Transaction} from "../../utils/common/Structs.sol"; +import "./AddressResolverUtil.sol"; + +/// @title DeployerGateway +/// @notice App gateway contract responsible for handling deployment requests +/// @dev Extends AppGatewayBase to provide deployment queueing functionality +contract DeployForwarder is AddressResolverUtil { + /// @notice The counter for the salt used to generate/deploy the contract address + uint256 public saltCounter; + + /// @notice Deploys a contract + /// @param chainSlug_ The chain slug + function deploy( + address sbType_, + uint32 chainSlug_, + OverrideParams memory overrideParams_, + bytes memory initCallData_, + bytes memory payload_ + ) external { + QueueParams memory queueParams; + queueParams.overrideParams = overrideParams_; + queueParams.switchboardType = sbType_; + queueParams.transaction = Transaction({ + chainSlug: chainSlug_, + target: configurations__.contractFactoryPlug(chainSlug_), + payload: _createPayload( + msg.sender, + chainSlug_, + payload_, + initCallData_, + overrideParams_ + ) + }); + + watcher__().queue(queueParams, msg.sender); + } + + function _createPayload( + address appGateway_, + uint32 chainSlug_, + bytes memory payload_, + bytes memory initCallData_, + OverrideParams memory overrideParams_ + ) internal returns (bytes memory payload) { + bytes32 salt = keccak256(abi.encode(appGateway_, chainSlug_, saltCounter++)); + + // app gateway is set in the plug deployed on chain + payload = abi.encodeWithSelector( + IContractFactoryPlug.deployContract.selector, + overrideParams_.isPlug, + salt, + bytes32(uint256(uint160(appGateway_))), + switchboardType_, + payload_, + initCallData_ + ); + } +} From 96cf64ed6bf10438a10944c249e8fb6d56d0269a Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Thu, 22 May 2025 14:55:54 +0530 Subject: [PATCH 040/130] fix: structs and errors --- .../evmx/app-gateways/AuctionManager.sol | 2 +- contracts/evmx/base/AppGatewayBase.sol | 10 ++-- contracts/evmx/fees/FeesStorage.sol | 2 +- contracts/evmx/helpers/AsyncPromise.sol | 2 +- contracts/evmx/helpers/DeployForwarder.sol | 28 ++++----- contracts/evmx/interfaces/IWatcher.sol | 4 +- .../watcher/precompiles/WritePrecompile.sol | 2 +- contracts/protocol/Socket.sol | 4 +- contracts/utils/common/Errors.sol | 41 +++++-------- contracts/utils/common/Structs.sol | 60 ++++--------------- 10 files changed, 53 insertions(+), 102 deletions(-) diff --git a/contracts/evmx/app-gateways/AuctionManager.sol b/contracts/evmx/app-gateways/AuctionManager.sol index 6f1aa478..d0f86160 100644 --- a/contracts/evmx/app-gateways/AuctionManager.sol +++ b/contracts/evmx/app-gateways/AuctionManager.sol @@ -5,7 +5,7 @@ import {ECDSA} from "solady/utils/ECDSA.sol"; import "solady/utils/Initializable.sol"; import "../interfaces/IAuctionManager.sol"; import "../../utils/AccessControl.sol"; -import {AuctionClosed, AuctionAlreadyStarted, BidExceedsMaxFees, LowerBidAlreadyExists, InvalidTransmitter} from "../../utils/common/Errors.sol"; +import {AuctionClosed, BidExceedsMaxFees, LowerBidAlreadyExists, InvalidTransmitter} from "../../utils/common/Errors.sol"; import {TRANSMITTER_ROLE} from "../../utils/common/AccessRoles.sol"; import {AppGatewayBase} from "../base/AppGatewayBase.sol"; diff --git a/contracts/evmx/base/AppGatewayBase.sol b/contracts/evmx/base/AppGatewayBase.sol index 3a970e25..9f2da746 100644 --- a/contracts/evmx/base/AppGatewayBase.sol +++ b/contracts/evmx/base/AppGatewayBase.sol @@ -5,7 +5,7 @@ import "../helpers/AddressResolverUtil.sol"; import "../interfaces/IAppGateway.sol"; import "../interfaces/IForwarder.sol"; -import {InvalidPromise, FeesNotSet, AsyncModifierNotSet} from "../../utils/common/Errors.sol"; +import {InvalidPromise, AsyncModifierNotSet} from "../../utils/common/Errors.sol"; import {FAST, READ, WRITE, SCHEDULE} from "../../utils/common/Constants.sol"; /// @title AppGatewayBase @@ -131,13 +131,11 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { IsPlug isPlug_, bytes memory initCallData_ ) internal { - if (!isAsyncModifierSet) revert AsyncModifierNotSet(); deployerGateway__().deploy( - contractId_, + isPlug_, chainSlug_, - overrideParams, - creationCodeWithArgs[contractId_], - initCallData_ + initCallData_, + creationCodeWithArgs[contractId_] ); IPromise(watcher__().latestAsyncPromise()).then( this.setAddress.selector, diff --git a/contracts/evmx/fees/FeesStorage.sol b/contracts/evmx/fees/FeesStorage.sol index e958a5aa..5a4ac3e4 100644 --- a/contracts/evmx/fees/FeesStorage.sol +++ b/contracts/evmx/fees/FeesStorage.sol @@ -6,7 +6,7 @@ import "solady/utils/Initializable.sol"; import "solady/utils/ECDSA.sol"; import "../interfaces/IFeesManager.sol"; import {AddressResolverUtil} from "../AddressResolverUtil.sol"; -import {NotAuctionManager, InvalidWatcherSignature, NonceUsed} from "../../utils/common/Errors.sol"; +import {NonceUsed} from "../../utils/common/Errors.sol"; import {Bid, Parallel, WriteFinality, QueuePayloadParams, IsPlug, PayloadSubmitParams, RequestMetadata, UserCredits} from "../../utils/common/Structs.sol"; import "../watcher/WatcherBase.sol"; diff --git a/contracts/evmx/helpers/AsyncPromise.sol b/contracts/evmx/helpers/AsyncPromise.sol index a906a5af..a5bb4f42 100644 --- a/contracts/evmx/helpers/AsyncPromise.sol +++ b/contracts/evmx/helpers/AsyncPromise.sol @@ -8,7 +8,7 @@ import {IAppGateway} from "./interfaces/IAppGateway.sol"; import {AddressResolverUtil} from "./AddressResolverUtil.sol"; import {AsyncPromiseState} from "../utils/common/Structs.sol"; import {MAX_COPY_BYTES} from "../utils/common/Constants.sol"; - +import {RequestAlreadyExecuted} from "../utils/common/Errors.sol"; abstract contract AsyncPromiseStorage is IPromise { // slots [0-49] reserved for gap uint256[50] _gap_before; diff --git a/contracts/evmx/helpers/DeployForwarder.sol b/contracts/evmx/helpers/DeployForwarder.sol index e9cab496..272ef0be 100644 --- a/contracts/evmx/helpers/DeployForwarder.sol +++ b/contracts/evmx/helpers/DeployForwarder.sol @@ -14,43 +14,43 @@ contract DeployForwarder is AddressResolverUtil { /// @notice Deploys a contract /// @param chainSlug_ The chain slug function deploy( - address sbType_, + IsPlug isPlug_, uint32 chainSlug_, - OverrideParams memory overrideParams_, bytes memory initCallData_, bytes memory payload_ ) external { + bool isAsyncModifierSet = IAppGateway(msg.sender).isAsyncModifierSet(); + if (!isAsyncModifierSet) revert AsyncModifierNotUsed(); + + // fetch the override params from app gateway + (OverrideParams overrideParams, bytes32 sbType) = IAppGateway(msg.sender) + .getOverrideParams(); + QueueParams memory queueParams; - queueParams.overrideParams = overrideParams_; - queueParams.switchboardType = sbType_; + queueParams.overrideParams = overrideParams; + queueParams.switchboardType = sbType; queueParams.transaction = Transaction({ chainSlug: chainSlug_, target: configurations__.contractFactoryPlug(chainSlug_), - payload: _createPayload( - msg.sender, - chainSlug_, - payload_, - initCallData_, - overrideParams_ - ) + payload: _createPayload(isPlug_, msg.sender, chainSlug_, payload_, initCallData_) }); watcher__().queue(queueParams, msg.sender); } function _createPayload( + IsPlug isPlug_, address appGateway_, uint32 chainSlug_, bytes memory payload_, - bytes memory initCallData_, - OverrideParams memory overrideParams_ + bytes memory initCallData_ ) internal returns (bytes memory payload) { bytes32 salt = keccak256(abi.encode(appGateway_, chainSlug_, saltCounter++)); // app gateway is set in the plug deployed on chain payload = abi.encodeWithSelector( IContractFactoryPlug.deployContract.selector, - overrideParams_.isPlug, + isPlug_, salt, bytes32(uint256(uint160(appGateway_))), switchboardType_, diff --git a/contracts/evmx/interfaces/IWatcher.sol b/contracts/evmx/interfaces/IWatcher.sol index a9046190..82984b6a 100644 --- a/contracts/evmx/interfaces/IWatcher.sol +++ b/contracts/evmx/interfaces/IWatcher.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import {InvalidCallerTriggered, TimeoutDelayTooLarge, TimeoutAlreadyResolved, InvalidInboxCaller, ResolvingTimeoutTooEarly, CallFailed, AppGatewayAlreadyCalled, InvalidWatcherSignature, NonceUsed, RequestAlreadyExecuted} from "../../utils/common/Errors.sol"; -import {ResolvedPromises, AppGatewayConfig, LimitParams, WriteFinality, UpdateLimitParams, PlugConfig, DigestParams, QueueParams, PayloadParams, RequestParams} from "../../utils/common/Structs.sol"; +import {InvalidCallerTriggered, TimeoutAlreadyResolved, ResolvingTimeoutTooEarly, CallFailed, AppGatewayAlreadyCalled, InvalidWatcherSignature, NonceUsed} from "../../utils/common/Errors.sol"; +import {ResolvedPromises, AppGatewayConfig, WriteFinality, PlugConfig, DigestParams, QueueParams, PayloadParams, RequestParams} from "../../utils/common/Structs.sol"; /// @title IWatcher /// @notice Interface for the Watcher Precompile system that handles payload verification and execution diff --git a/contracts/evmx/watcher/precompiles/WritePrecompile.sol b/contracts/evmx/watcher/precompiles/WritePrecompile.sol index 12802c59..fc0585ba 100644 --- a/contracts/evmx/watcher/precompiles/WritePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/WritePrecompile.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import "../../../utils/common/Errors.sol"; +import {InvalidIndex} from "../../../utils/common/Errors.sol"; import "../../../utils/common/Constants.sol"; import "../../interfaces/IPrecompile.sol"; diff --git a/contracts/protocol/Socket.sol b/contracts/protocol/Socket.sol index db5b300d..a4d5189f 100644 --- a/contracts/protocol/Socket.sol +++ b/contracts/protocol/Socket.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.21; import {LibCall} from "solady/utils/LibCall.sol"; import "./SocketUtils.sol"; -import {WRITE} from "../../utils/common/Constants.sol"; +import {WRITE} from "../utils/common/Constants.sol"; /** * @title Socket @@ -52,7 +52,7 @@ contract Socket is SocketUtils { /** * @dev Error emitted when the call type is read */ - error ReadOnlyCall(); + error InvalidCallType(); /** * @notice Constructor for the Socket contract diff --git a/contracts/utils/common/Errors.sol b/contracts/utils/common/Errors.sol index 8104e85c..8f1289a8 100644 --- a/contracts/utils/common/Errors.sol +++ b/contracts/utils/common/Errors.sol @@ -1,48 +1,35 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -error NotSocket(); error ZeroAddress(); -error TimeoutDelayTooLarge(); +error InvalidTransmitter(); +error InvalidTokenAddress(); + +// Socket +error NotSocket(); +error PlugNotFound(); + +// EVMx error TimeoutAlreadyResolved(); error ResolvingTimeoutTooEarly(); -error LimitReached(); -error FeesAlreadyPaid(); -error NotAuctionManager(); error CallFailed(); -error PlugNotFound(); error InvalidAppGateway(); error AppGatewayAlreadyCalled(); -error InvalidInboxCaller(); error InvalidCallerTriggered(); -error PromisesNotResolved(); error InvalidPromise(); -error InvalidTransmitter(); -error FeesNotSet(); -error InvalidTokenAddress(); error InvalidWatcherSignature(); error NonceUsed(); +error AsyncModifierNotUsed(); +error InvalidTarget(); +error InvalidIndex(); +error InvalidPayloadSize(); +error InvalidScheduleDelay(); +error InvalidTimeoutRequest(); /// @notice Error thrown when trying to start or bid a closed auction error AuctionClosed(); -/// @notice Error thrown when trying to start an ongoing auction -error AuctionAlreadyStarted(); /// @notice Error thrown if fees exceed the maximum set fees error BidExceedsMaxFees(); /// @notice Error thrown if a lower bid already exists error LowerBidAlreadyExists(); -error AsyncModifierNotUsed(); -error InvalidIndex(); -error RequestAlreadyExecuted(); -/// @notice Error thrown when no async promise is found -error NoAsyncPromiseFound(); -/// @notice Error thrown when promise caller mismatch -error PromiseCallerMismatch(); /// @notice Error thrown when request count mismatch error RequestCountMismatch(); -/// @notice Error thrown when delivery helper is not set -error DeliveryHelperNotSet(); - -error InvalidTarget(); -error InvalidPayloadSize(); -error InvalidScheduleDelay(); -error InvalidTimeoutRequest(); diff --git a/contracts/utils/common/Structs.sol b/contracts/utils/common/Structs.sol index ef757d3e..b990f744 100644 --- a/contracts/utils/common/Structs.sol +++ b/contracts/utils/common/Structs.sol @@ -50,19 +50,6 @@ struct AppGatewayWhitelistParams { } //// STRUCTS //// -// plug: -struct LimitParams { - uint256 lastUpdateTimestamp; - uint256 ratePerSecond; - uint256 maxLimit; - uint256 lastUpdateLimit; -} -struct UpdateLimitParams { - bytes32 limitType; - address appGateway; - uint256 maxLimit; - uint256 ratePerSecond; -} struct AppGatewayConfig { PlugConfig plugConfig; @@ -115,12 +102,6 @@ struct TransmissionParams { bytes transmitterSignature; } -struct OnChainFees { - uint32 chainSlug; - address token; - uint256 amount; -} - struct UserCredits { uint256 totalCredits; uint256 blockedCredits; @@ -159,11 +140,6 @@ struct Transaction { bytes payload; } -struct DeployParam { - IsPlug isPlug; - bytes initCallData; -} - struct QueueParams { OverrideParams overrideParams; Transaction transaction; @@ -176,43 +152,33 @@ struct PayloadParams { uint40 batchCount; uint40 payloadCount; bytes4 callType; - address asyncPromise; // todo: multiple promise support? + address asyncPromise; address appGateway; bytes32 payloadId; - uint256 resolvedAt; // replaced isPromiseExecuted + uint256 resolvedAt; bytes precompileData; - - // uint256 deadline; - // OverrideParams overrideParams; - // TimeoutRequest timeoutRequest; } -// timeout: -// struct TimeoutRequest { -// uint256 delayInSeconds; -// uint256 executeAt; -// bool isResolved; -// } // request struct RequestTrackingParams { bool isRequestCancelled; - bool isRequestExecuted; // - uint40 currentBatch; // - uint256 currentBatchPayloadsLeft; // - uint256 payloadsRemaining; // + bool isRequestExecuted; + uint40 currentBatch; + uint256 currentBatchPayloadsLeft; + uint256 payloadsRemaining; } struct RequestFeesDetails { - uint256 maxFees; // - address consumeFrom; // - Bid winningBid; // + uint256 maxFees; + address consumeFrom; + Bid winningBid; } struct RequestParams { RequestTrackingParams requestTrackingParams; RequestFeesDetails requestFeesDetails; - address appGateway; // - address auctionManager; // - uint256 writeCount; // - bytes onCompleteData; // + address appGateway; + address auctionManager; + uint256 writeCount; + bytes onCompleteData; } From 89282eb0a67bc4f164f6073f146aa02a5d234ca4 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Thu, 22 May 2025 15:00:55 +0530 Subject: [PATCH 041/130] fix: id utils --- contracts/evmx/watcher/Configurations.sol | 3 +-- contracts/evmx/watcher/RequestHandler.sol | 4 ++-- .../watcher/precompiles/WritePrecompile.sol | 3 ++- contracts/protocol/Socket.sol | 9 +++++++- contracts/protocol/SocketUtils.sol | 21 ------------------- .../common/IdUtils.sol} | 6 ------ 6 files changed, 13 insertions(+), 33 deletions(-) rename contracts/{evmx/libs/WatcherIdUtils.sol => utils/common/IdUtils.sol} (79%) diff --git a/contracts/evmx/watcher/Configurations.sol b/contracts/evmx/watcher/Configurations.sol index e217d244..42a6ada3 100644 --- a/contracts/evmx/watcher/Configurations.sol +++ b/contracts/evmx/watcher/Configurations.sol @@ -4,8 +4,7 @@ pragma solidity ^0.8.21; import "solady/utils/Initializable.sol"; import "../interfaces/IConfigurations.sol"; import {AddressResolverUtil} from "../AddressResolverUtil.sol"; -import "./core/WatcherIdUtils.sol"; - +import {encodeAppGatewayId} from "../../utils/common/IdUtils.sol"; /// @title Configurations /// @notice Configuration contract for the Watcher Precompile system /// @dev Handles the mapping between networks, plugs, and app gateways for payload execution diff --git a/contracts/evmx/watcher/RequestHandler.sol b/contracts/evmx/watcher/RequestHandler.sol index 9f8eb258..084d3d23 100644 --- a/contracts/evmx/watcher/RequestHandler.sol +++ b/contracts/evmx/watcher/RequestHandler.sol @@ -5,7 +5,7 @@ import "./WatcherBase.sol"; import "../../utils/common/Structs.sol"; import "../../utils/common/Errors.sol"; import "../../utils/common/Constants.sol"; - +import "../../utils/common/IdUtils.sol"; import "../interfaces/IPrecompile.sol"; /// @title RequestHandler @@ -179,7 +179,7 @@ contract RequestHandler is WatcherBase { // create payload id uint40 payloadCount = payloadCounter++; - bytes32 payloadId = WatcherIdUtils.createPayloadId( + bytes32 payloadId = createPayloadId( requestCount_, batchCount, payloadCount, diff --git a/contracts/evmx/watcher/precompiles/WritePrecompile.sol b/contracts/evmx/watcher/precompiles/WritePrecompile.sol index fc0585ba..f075c0d1 100644 --- a/contracts/evmx/watcher/precompiles/WritePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/WritePrecompile.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.21; import {InvalidIndex} from "../../../utils/common/Errors.sol"; import "../../../utils/common/Constants.sol"; import "../../interfaces/IPrecompile.sol"; +import {encodeAppGatewayId} from "../../../utils/common/IdUtils.sol"; import "../WatcherBase.sol"; @@ -105,7 +106,7 @@ contract WritePrecompile is IPrecompile, WatcherBase { value, transaction.payload, transaction.target, - WatcherIdUtils.encodeAppGatewayId(payloadParams.appGateway), + encodeAppGatewayId(payloadParams.appGateway), prevBatchDigestHash, bytes("") ); diff --git a/contracts/protocol/Socket.sol b/contracts/protocol/Socket.sol index a4d5189f..259e08d9 100644 --- a/contracts/protocol/Socket.sol +++ b/contracts/protocol/Socket.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.21; import {LibCall} from "solady/utils/LibCall.sol"; import "./SocketUtils.sol"; import {WRITE} from "../utils/common/Constants.sol"; +import {createPayloadId} from "../utils/common/IdUtils.sol"; /** * @title Socket @@ -86,7 +87,13 @@ contract Socket is SocketUtils { if (msg.value < executeParams_.value + transmissionParams_.socketFees) revert InsufficientMsgValue(); - bytes32 payloadId = _createPayloadId(plugConfig.switchboard, executeParams_); + bytes32 payloadId = createPayloadId( + executeParams_.requestCount, + executeParams_.batchCount, + executeParams_.payloadCount, + plugConfig.switchboard, + chainSlug + ); // validate the execution status _validateExecutionStatus(payloadId); diff --git a/contracts/protocol/SocketUtils.sol b/contracts/protocol/SocketUtils.sol index ccd8db5d..eb4860ed 100644 --- a/contracts/protocol/SocketUtils.sol +++ b/contracts/protocol/SocketUtils.sol @@ -71,27 +71,6 @@ abstract contract SocketUtils is SocketConfig { ); } - /** - * @notice creates the payload ID - * @param switchboard_ The address of the switchboard - * @param executeParams_ The parameters of the payload - */ - function _createPayloadId( - address switchboard_, - ExecuteParams calldata executeParams_ - ) internal view returns (bytes32) { - return - keccak256( - abi.encode( - executeParams_.requestCount, - executeParams_.batchCount, - executeParams_.payloadCount, - chainSlug, - switchboard_ - ) - ); - } - /** * @notice recovers the signer from the signature * @param digest_ The digest of the payload diff --git a/contracts/evmx/libs/WatcherIdUtils.sol b/contracts/utils/common/IdUtils.sol similarity index 79% rename from contracts/evmx/libs/WatcherIdUtils.sol rename to contracts/utils/common/IdUtils.sol index 9b4db8eb..335bd830 100644 --- a/contracts/evmx/libs/WatcherIdUtils.sol +++ b/contracts/utils/common/IdUtils.sol @@ -1,16 +1,10 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.22; -// todo: remove watcher id util lib function encodeAppGatewayId(address appGateway_) pure returns (bytes32) { return bytes32(uint256(uint160(appGateway_))); } -function decodeAppGatewayId(bytes32 appGatewayId_) pure returns (address) { - return address(uint160(uint256(appGatewayId_))); -} - -// todo: also use in socket /// @notice Creates a payload ID from the given parameters /// @param requestCount_ The request count /// @param batchCount_ The batch count From c0a7cf7112e22b068260295690c52ef9b3e2a965 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Thu, 22 May 2025 18:29:17 +0530 Subject: [PATCH 042/130] wip: fixing build --- .../evmx/app-gateways/AuctionManager.sol | 50 +++--- contracts/evmx/base/AppGatewayBase.sol | 22 ++- contracts/evmx/fees/Credit.sol | 159 ++++++++++-------- contracts/evmx/fees/FeesManager.sol | 42 ++--- contracts/evmx/fees/FeesStorage.sol | 33 ---- contracts/evmx/helpers/AddressResolver.sol | 2 +- .../evmx/helpers/AddressResolverUtil.sol | 7 + contracts/evmx/helpers/AsyncDeployer.sol | 2 +- contracts/evmx/helpers/AsyncPromise.sol | 10 +- contracts/evmx/helpers/DeployForwarder.sol | 24 ++- contracts/evmx/helpers/Forwarder.sol | 13 +- .../evmx/interfaces/IAddressResolver.sol | 8 +- contracts/evmx/interfaces/IAuctionManager.sol | 2 +- .../evmx/interfaces/IDeployForwarder.sol | 33 ++++ contracts/evmx/interfaces/IPrecompile.sol | 10 +- contracts/evmx/interfaces/IWatcher.sol | 4 +- .../evmx/interfaces/IWatcherFeesManager.sol | 24 --- contracts/evmx/plugs/ContractFactoryPlug.sol | 11 +- contracts/evmx/plugs/FeesPlug.sol | 26 +-- contracts/evmx/watcher/Configurations.sol | 11 +- contracts/evmx/watcher/RequestHandler.sol | 6 +- contracts/evmx/watcher/Watcher.sol | 2 +- contracts/evmx/watcher/WatcherBase.sol | 2 +- .../precompiles/SchedulePrecompile.sol | 2 +- .../watcher/precompiles/WritePrecompile.sol | 34 ++-- contracts/utils/common/Errors.sol | 9 +- contracts/utils/common/Structs.sol | 5 +- 27 files changed, 276 insertions(+), 277 deletions(-) delete mode 100644 contracts/evmx/fees/FeesStorage.sol create mode 100644 contracts/evmx/interfaces/IDeployForwarder.sol delete mode 100644 contracts/evmx/interfaces/IWatcherFeesManager.sol diff --git a/contracts/evmx/app-gateways/AuctionManager.sol b/contracts/evmx/app-gateways/AuctionManager.sol index d0f86160..a718e2aa 100644 --- a/contracts/evmx/app-gateways/AuctionManager.sol +++ b/contracts/evmx/app-gateways/AuctionManager.sol @@ -5,7 +5,9 @@ import {ECDSA} from "solady/utils/ECDSA.sol"; import "solady/utils/Initializable.sol"; import "../interfaces/IAuctionManager.sol"; import "../../utils/AccessControl.sol"; -import {AuctionClosed, BidExceedsMaxFees, LowerBidAlreadyExists, InvalidTransmitter} from "../../utils/common/Errors.sol"; +import {AuctionNotOpen, AuctionClosed, BidExceedsMaxFees, LowerBidAlreadyExists, InvalidTransmitter} from "../../utils/common/Errors.sol"; +import {SCHEDULE} from "../../utils/common/Constants.sol"; + import {TRANSMITTER_ROLE} from "../../utils/common/AccessRoles.sol"; import {AppGatewayBase} from "../base/AppGatewayBase.sol"; @@ -53,6 +55,7 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, event AuctionEnded(uint40 requestCount, Bid winningBid); event BidPlaced(uint40 requestCount, Bid bid); event AuctionEndDelaySecondsSet(uint256 auctionEndDelaySeconds); + event MaxReAuctionCountSet(uint256 maxReAuctionCount); error InvalidBid(); error MaxReAuctionCountReached(); @@ -120,7 +123,7 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, if (bidFees >= winningBids[requestCount_].fee && bidFees != 0) revert LowerBidAlreadyExists(); - uint256 transmitterCredits = get(requestCount_); + uint256 transmitterCredits = getMaxFees(requestCount_); if (bidFees > transmitterCredits) revert BidExceedsMaxFees(); deductScheduleFees( @@ -182,7 +185,7 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, ); // start the request processing, it will queue the request - IWatcher(watcherPrecompile__()).assignTransmitter(requestCount_, winningBid); + watcher__().assignTransmitter(requestCount_, winningBid); } emit AuctionEnded(requestCount_, winningBid); @@ -206,7 +209,7 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, auctionStatus[requestCount_] = AuctionStatus.RESTARTED; reAuctionCount[requestCount_]++; - IWatcher(watcherPrecompile__()).assignTransmitter( + watcher__().assignTransmitter( requestCount_, Bid({fee: 0, transmitter: address(0), extraData: ""}) ); @@ -219,34 +222,21 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, address consumeFrom_, bytes memory payload_ ) internal { - QueueParams memory queueParams = QueueParams({ - overrideParams: OverrideParams({ - isPlug: IsPlug.NO, - callType: SCHEDULE, - isParallelCall: Parallel.OFF, - gasLimit: 0, - value: 0, - readAtBlockNumber: 0, - writeFinality: WriteFinality.LOW, - delayInSeconds: delayInSeconds_ - }), - transaction: Transaction({ - chainSlug: evmxSlug, - target: address(this), - payload: payload_ - }), - asyncPromise: address(0), - switchboardType: sbType + OverrideParams memory overrideParams; + overrideParams.callType = SCHEDULE; + overrideParams.delayInSeconds = delayInSeconds_; + + QueueParams memory queueParams; + queueParams.overrideParams = overrideParams; + queueParams.transaction = Transaction({ + chainSlug: evmxSlug, + target: address(this), + payload: payload_ }); + queueParams.switchboardType = sbType; // queue and create request - watcherPrecompile__().queueAndRequest( - queueParams, - maxFees_, - address(this), - address(this), - bytes("") - ); + watcher__().queueAndSubmit(queueParams, maxFees_, address(this), address(this), bytes("")); } /// @notice Returns the quoted transmitter fees for a request @@ -267,7 +257,7 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, } function _getRequestParams(uint40 requestCount_) internal view returns (RequestParams memory) { - return watcherPrecompile__().getRequestParams(requestCount_); + return watcher__().getRequestParams(requestCount_); } /// @notice Recovers the signer of a message diff --git a/contracts/evmx/base/AppGatewayBase.sol b/contracts/evmx/base/AppGatewayBase.sol index 9f2da746..55b25420 100644 --- a/contracts/evmx/base/AppGatewayBase.sol +++ b/contracts/evmx/base/AppGatewayBase.sol @@ -4,9 +4,11 @@ pragma solidity ^0.8.21; import "../helpers/AddressResolverUtil.sol"; import "../interfaces/IAppGateway.sol"; import "../interfaces/IForwarder.sol"; +import "../interfaces/IPromise.sol"; import {InvalidPromise, AsyncModifierNotSet} from "../../utils/common/Errors.sol"; import {FAST, READ, WRITE, SCHEDULE} from "../../utils/common/Constants.sol"; +import {IsPlug, QueueParams, Read, WriteFinality, Parallel} from "../../utils/common/Structs.sol"; /// @title AppGatewayBase /// @notice Abstract contract for the app gateway @@ -51,7 +53,7 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { function _postAsync() internal { isAsyncModifierSet = false; - (uint40 requestCount, address[] memory promises) = watcherPrecompile__().submitRequest( + (uint40 requestCount, address[] memory promises) = watcher__().submitRequest( maxFees, auctionManager, consumeFrom, @@ -63,16 +65,12 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { function _preAsync() internal { isAsyncModifierSet = true; _clearOverrides(); - watcherPrecompile__().clearQueue(); + watcher__().clearQueue(); } function _approveFeesWithSignature(bytes memory feesApprovalData_) internal { - _handleFeesApproval(feesApprovalData_); - } - - function _handleFeesApproval(bytes memory feesApprovalData_) internal { if (feesApprovalData_.length > 0) { - (consumeFrom, , ) = feesManager__().whitelistAppGatewayWithSignature(feesApprovalData_); + (consumeFrom, , ) = feesManager__().approveAppGatewayWithSignature(feesApprovalData_); } } @@ -92,7 +90,7 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { /// @notice Gets the current async ID /// @return uint40 The current async ID function _getCurrentAsyncId() internal view returns (uint40) { - return watcherPrecompile__().getCurrentRequestCount(); + return watcher__().getCurrentRequestCount(); } /// @notice Sets the auction manager @@ -115,7 +113,7 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { /// @dev This function retrieves the onchain address using the contractId and chainSlug, then calls the watcher precompile to update the plug's validity status function _setValidPlug(uint32 chainSlug_, bytes32 contractId, bool isValid) internal { address onchainAddress = getOnChainAddress(contractId, chainSlug_); - watcherPrecompileConfig().setIsValidPlug(chainSlug_, onchainAddress, isValid); + watcher__().setIsValidPlug(chainSlug_, onchainAddress, isValid); } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -131,7 +129,7 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { IsPlug isPlug_, bytes memory initCallData_ ) internal { - deployerGateway__().deploy( + deployForwarder__().deploy( isPlug_, chainSlug_, initCallData_, @@ -156,7 +154,7 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { chainSlug ); - forwarderAddresses[appGateway][contractId][chainSlug] = forwarderContractAddress; + forwarderAddresses[contractId][chainSlug] = forwarderContractAddress; } /// @notice Schedules a function to be called after a delay @@ -169,7 +167,7 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { QueueParams memory queueParams = new QueueParams(); queueParams.overrideParams = overrideParams; - (address promise_, ) = watcherPrecompile__().queue(queueParams, address(this)); + (address promise_, ) = watcher__().queue(queueParams, address(this)); } /// @notice Gets the on-chain address diff --git a/contracts/evmx/fees/Credit.sol b/contracts/evmx/fees/Credit.sol index a824e9f0..abfd940a 100644 --- a/contracts/evmx/fees/Credit.sol +++ b/contracts/evmx/fees/Credit.sol @@ -1,11 +1,45 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import "./FeesStorage.sol"; +import {Ownable} from "solady/auth/Ownable.sol"; +import "solady/utils/Initializable.sol"; +import "solady/utils/ECDSA.sol"; +import "../interfaces/IFeesManager.sol"; +import "../interfaces/IFeesPlug.sol"; +import "../watcher/WatcherBase.sol"; +import {AddressResolverUtil} from "../helpers/AddressResolverUtil.sol"; +import {NonceUsed, InvalidAmount, InsufficientCreditsAvailable, InsufficientBalance} from "../../utils/common/Errors.sol"; +import {WriteFinality, UserCredits, AppGatewayApprovals, OverrideParams} from "../../utils/common/Structs.sol"; +import {WRITE} from "../../utils/common/Constants.sol"; + +abstract contract FeesManagerStorage is IFeesManager, WatcherBase { + /// @notice evmx slug + uint32 public evmxSlug; + + /// @notice user credits => stores fees for user, app gateway, transmitters and watcher precompile + mapping(address => UserCredits) public userCredits; + + /// @notice Mapping to track request credits details for each request count + /// @dev requestCount => RequestFee + mapping(uint40 => uint256) public requestBlockedCredits; + + // user approved app gateways + // userAddress => appGateway => isApproved + mapping(address => mapping(address => bool)) public isApproved; + + // token pool balances + // chainSlug => token address => amount + mapping(uint32 => mapping(address => uint256)) public tokenOnChainBalances; + + /// @notice Mapping to track nonce to whether it has been used + /// @dev address => signatureNonce => isNonceUsed + /// @dev used by watchers or other users in signatures + mapping(address => mapping(uint256 => bool)) public isNonceUsed; +} /// @title UserUtils /// @notice Contract for managing user utils -abstract contract Credit is FeesStorage, Initializable, Ownable, AddressResolverUtil { +abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressResolverUtil { /// @notice Emitted when fees deposited are updated /// @param chainSlug The chain identifier /// @param appGateway The app gateway address @@ -24,6 +58,9 @@ abstract contract Credit is FeesStorage, Initializable, Ownable, AddressResolver /// @notice Emitted when credits are unwrapped event CreditsUnwrapped(address indexed consumeFrom, uint256 amount); + /// @notice Emitted when credits are transferred + event CreditsTransferred(address indexed from, address indexed to, uint256 amount); + /// @notice Deposits credits and native tokens to a user /// @param depositTo_ The address to deposit the credits to /// @param chainSlug_ The chain slug @@ -38,30 +75,31 @@ abstract contract Credit is FeesStorage, Initializable, Ownable, AddressResolver uint256 creditAmount_ ) external payable onlyWatcher { if (creditAmount_ + nativeAmount_ != msg.value) revert InvalidAmount(); + tokenOnChainBalances[chainSlug_][token_] += nativeAmount_ + creditAmount_; UserCredits storage userCredit = userCredits[depositTo_]; userCredit.totalCredits += creditAmount_; - tokenPoolBalances[chainSlug_][token_] += creditAmount_; payable(depositTo_).transfer(nativeAmount_); emit CreditsDeposited(chainSlug_, depositTo_, token_, creditAmount_); } + // todo: add safe eth transfer function wrap(address receiver_) external payable { UserCredits storage userCredit = userCredits[receiver_]; userCredit.totalCredits += msg.value; emit CreditsWrapped(receiver_, msg.value); } - function unwrap(uint256 amount_) external { + function unwrap(uint256 amount_, address receiver_) external { UserCredits storage userCredit = userCredits[msg.sender]; if (userCredit.totalCredits < amount_) revert InsufficientCreditsAvailable(); userCredit.totalCredits -= amount_; if (address(this).balance < amount_) revert InsufficientBalance(); - payable(msg.sender).transfer(amount_); + payable(receiver_).transfer(amount_); - emit CreditsUnwrapped(msg.sender, amount_); + emit CreditsUnwrapped(receiver_, amount_); } /// @notice Returns available (unblocked) credits for a gateway @@ -73,73 +111,61 @@ abstract contract Credit is FeesStorage, Initializable, Ownable, AddressResolver } /// @notice Checks if the user has enough credits - /// @param from_ The app gateway address - /// @param to_ The app gateway address - /// @param amount_ The amount + /// @param consumeFrom_ address to consume from + /// @param spender_ address to spend from + /// @param amount_ amount to spend /// @return True if the user has enough credits, false otherwise - function isUserCreditsEnough( - address from_, - address to_, + function isCreditSpendable( + address consumeFrom_, + address spender_, uint256 amount_ - ) external view returns (bool) { - // If from_ is not same as to_ or to_ is not watcher, check if it is whitelisted - if ( - to_ != address(watcherPrecompile__()) && - from_ != to_ && - !isAppGatewayWhitelisted[from_][to_] - ) revert AppGatewayNotWhitelisted(); - - return getAvailableCredits(from_) >= amount_; + ) public view returns (bool) { + // If consumeFrom_ is not same as spender_ or spender_ is not watcher, check if it is approved + if (spender_ != address(watcher__()) && consumeFrom_ != spender_) { + if (!isApproved[consumeFrom_][spender_]) return false; + } + + return getAvailableCredits(consumeFrom_) >= amount_; } function transferCredits(address from_, address to_, uint256 amount_) external { - if (!isUserCreditsEnough(from_, msg.sender, amount_)) revert InsufficientCreditsAvailable(); + if (!isCreditSpendable(from_, msg.sender, amount_)) revert InsufficientCreditsAvailable(); userCredits[from_].totalCredits -= amount_; userCredits[to_].totalCredits += amount_; emit CreditsTransferred(from_, to_, amount_); } - function whitelistAppGatewayWithSignature( - bytes memory feeApprovalData_ - ) external returns (address consumeFrom, address appGateway, bool isApproved) { - return _processFeeApprovalData(feeApprovalData_); - } - - /// @notice Whitelists multiple app gateways for the caller - /// @param params_ Array of app gateway addresses to whitelist - function whitelistAppGateways(AppGatewayWhitelistParams[] calldata params_) external { + /// @notice Approves multiple app gateways for the caller + /// @param params_ Array of app gateway addresses to approve + function approveAppGateways(AppGatewayApprovals[] calldata params_) external { for (uint256 i = 0; i < params_.length; i++) { - isAppGatewayWhitelisted[msg.sender][params_[i].appGateway] = params_[i].isApproved; + isApproved[msg.sender][params_[i].appGateway] = params_[i].approval; } } - function _processFeeApprovalData( + /// @notice Approves an app gateway for the caller + /// @dev Approval data is encoded to make app gateways compatible with future changes + /// @param feeApprovalData_ The fee approval data + /// @return consumeFrom The consume from address + /// @return spender The app gateway address + /// @return approval The approval status + function approveAppGatewayWithSignature( bytes memory feeApprovalData_ - ) internal returns (address, address, bool) { - ( - address consumeFrom, - address appGateway, - bool isApproved, - uint256 nonce, - bytes memory signature_ - ) = abi.decode(feeApprovalData_, (address, address, bool, uint256, bytes)); + ) external returns (address consumeFrom, address spender, bool approval) { + uint256 nonce; + bytes memory signature_; + (spender, approval, nonce, signature_) = abi.decode( + feeApprovalData_, + (address, address, bool, uint256, bytes) + ); + bytes32 digest = keccak256(abi.encode(address(this), evmxSlug, spender, nonce, approval)); + consumeFrom = _recoverSigner(digest, signature_); if (isNonceUsed[consumeFrom][nonce]) revert NonceUsed(); - // todo: check - if (signature_.length == 0) { - // If no signature, consumeFrom is appGateway - return (appGateway, appGateway, isApproved); - } - - bytes32 digest = keccak256( - abi.encode(address(this), evmxSlug, consumeFrom, appGateway, nonce, isApproved) - ); - if (_recoverSigner(digest, signature_) != consumeFrom) revert InvalidUserSignature(); - isAppGatewayWhitelisted[consumeFrom][appGateway] = isApproved; isNonceUsed[consumeFrom][nonce] = true; - - return (consumeFrom, appGateway, isApproved); + isApproved[consumeFrom][spender] = approval; + return (consumeFrom, spender, approval); } /// @notice Withdraws funds to a specified receiver @@ -147,31 +173,31 @@ abstract contract Credit is FeesStorage, Initializable, Ownable, AddressResolver /// @dev assumed that transmitter can bid for their request on AM /// @param chainSlug_ The chain identifier /// @param token_ The address of the token - /// @param amount_ The amount of tokens to withdraw - /// @param maxFees_ The fees needed for the request + /// @param credits_ The amount of tokens to withdraw + /// @param maxFees_ The fees needed to process the withdraw /// @param receiver_ The address of the receiver function withdrawCredits( uint32 chainSlug_, address token_, - uint256 amount_, + uint256 credits_, uint256 maxFees_, address receiver_ ) public { address consumeFrom = _getCoreAppGateway(msg.sender); // Check if amount is available in fees plug - uint256 availableAmount = getAvailableCredits(consumeFrom); - if (availableAmount < amount_) revert InsufficientCreditsAvailable(); + uint256 availableCredits = getAvailableCredits(consumeFrom); + if (availableCredits < credits_) revert InsufficientCreditsAvailable(); - userCredits[consumeFrom].totalCredits -= amount_; - tokenPoolBalances[chainSlug_][token_] -= amount_; + userCredits[consumeFrom].totalCredits -= credits_; + tokenOnChainBalances[chainSlug_][token_] -= credits_; // Add it to the queue and submit request _createRequest( chainSlug_, consumeFrom, maxFees_, - abi.encodeCall(IFeesPlug.withdrawFees, (token_, receiver_, amount_)) + abi.encodeCall(IFeesPlug.withdrawFees, (token_, receiver_, credits_)) ); } @@ -183,7 +209,6 @@ abstract contract Credit is FeesStorage, Initializable, Ownable, AddressResolver ) internal { OverrideParams memory overrideParams; overrideParams.callType = WRITE; - overrideParams.gasLimit = 10000000; overrideParams.writeFinality = WriteFinality.LOW; QueueParams memory queueParams; @@ -196,13 +221,7 @@ abstract contract Credit is FeesStorage, Initializable, Ownable, AddressResolver queueParams.switchboardType = sbType; // queue and create request - watcherPrecompile__().queueAndRequest( - queueParams, - maxFees_, - address(0), - consumeFrom_, - bytes("") - ); + watcher__().queueAndSubmit(queueParams, maxFees_, address(0), consumeFrom_, bytes("")); } function _getFeesPlugAddress(uint32 chainSlug_) internal view returns (address) { diff --git a/contracts/evmx/fees/FeesManager.sol b/contracts/evmx/fees/FeesManager.sol index a3dd6001..e6e2d9ff 100644 --- a/contracts/evmx/fees/FeesManager.sol +++ b/contracts/evmx/fees/FeesManager.sol @@ -68,21 +68,20 @@ abstract contract FeesManager is Credit { /////////////////////// FEES MANAGEMENT /////////////////////// /// @notice Blocks fees for a request count - /// @param consumeFrom_ The fees payer address - /// @param transmitterCredits_ The total fees to block /// @param requestCount_ The batch identifier + /// @param consumeFrom_ The fees payer address + /// @param credits_ The total fees to block /// @dev Only callable by delivery helper function blockCredits( uint40 requestCount_, address consumeFrom_, uint256 credits_ ) external onlyRequestHandler { - address consumeFrom = _getCoreAppGateway(consumeFrom_); if (getAvailableCredits(consumeFrom) < credits_) revert InsufficientCreditsAvailable(); UserCredits storage userCredit = userCredits[consumeFrom]; userCredit.blockedCredits += credits_; - requestCountCredits[requestCount_] = credits_; + requestBlockedCredits[requestCount_] = credits_; emit CreditsBlocked(requestCount_, consumeFrom, credits_); } @@ -93,42 +92,33 @@ abstract contract FeesManager is Credit { uint40 requestCount_, address assignTo_ ) external override onlyRequestHandler { - uint256 blockedCredits = requestCountCredits[requestCount_]; + uint256 blockedCredits = requestBlockedCredits[requestCount_]; if (blockedCredits == 0) return; + address consumeFrom = _getRequestParams(requestCount_).requestFeesDetails.consumeFrom; // Unblock fees from deposit - _consumeUserCredits( - _getRequestParams(requestCount_).consumeFrom, - blockedCredits, - blockedCredits - ); + UserCredits storage userCredit = userCredits[consumeFrom]; + userCredit.blockedCredits -= blockedCredits; + userCredit.totalCredits -= blockedCredits; // Assign fees to transmitter userCredits[assignTo_].totalCredits += blockedCredits; // Clean up storage - delete requestCountCredits[requestCount_]; - emit CreditsUnblockedAndAssigned(requestCount_, assignTo_, blockedCredits); + delete requestBlockedCredits[requestCount_]; + emit CreditsUnblockedAndAssigned(requestCount_, consumeFrom, assignTo_, blockedCredits); } function unblockCredits(uint40 requestCount_) external onlyRequestHandler { - RequestParams memory r = _getRequestParams(requestCount_); - uint256 blockedCredits = requestCountCredits[requestCount_]; + uint256 blockedCredits = requestBlockedCredits[requestCount_]; if (blockedCredits == 0) return; // Unblock fees from deposit - _consumeUserCredits(r.requestFeesDetails.consumeFrom, blockedCredits, 0); - delete requestCountCredits[requestCount_]; - emit CreditsUnblocked(requestCount_, r.requestFeesDetails.consumeFrom); - } + address consumeFrom = _getRequestParams(requestCount_).requestFeesDetails.consumeFrom; + UserCredits storage userCredit = userCredits[consumeFrom]; + userCredit.blockedCredits -= blockedCredits; - function _consumeUserCredits( - address consumeFrom_, - uint256 toConsumeFromBlocked_, - uint256 toConsumeFromTotal_ - ) internal { - UserCredits storage userCredit = userCredits[consumeFrom_]; - userCredit.blockedCredits -= toConsumeFromBlocked_; - userCredit.totalCredits -= toConsumeFromTotal_; + delete requestBlockedCredits[requestCount_]; + emit CreditsUnblocked(requestCount_, consumeFrom); } } diff --git a/contracts/evmx/fees/FeesStorage.sol b/contracts/evmx/fees/FeesStorage.sol deleted file mode 100644 index 5a4ac3e4..00000000 --- a/contracts/evmx/fees/FeesStorage.sol +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -pragma solidity ^0.8.21; - -import {Ownable} from "solady/auth/Ownable.sol"; -import "solady/utils/Initializable.sol"; -import "solady/utils/ECDSA.sol"; -import "../interfaces/IFeesManager.sol"; -import {AddressResolverUtil} from "../AddressResolverUtil.sol"; -import {NonceUsed} from "../../utils/common/Errors.sol"; -import {Bid, Parallel, WriteFinality, QueuePayloadParams, IsPlug, PayloadSubmitParams, RequestMetadata, UserCredits} from "../../utils/common/Structs.sol"; -import "../watcher/WatcherBase.sol"; - -abstract contract FeesManagerStorage is IFeesManager, WatcherBase { - // user credits => stores fees for user, app gateway, transmitters and watcher precompile - mapping(address => UserCredits) public userCredits; - - /// @notice Mapping to track request credits details for each request count - /// @dev requestCount => RequestFee - mapping(uint40 => uint256) public requestCountCredits; - - // user approved app gateways - // userAddress => appGateway => isWhitelisted - mapping(address => mapping(address => bool)) public isAppGatewayWhitelisted; - - // token pool balances - // chainSlug => token address => amount - mapping(uint32 => mapping(address => uint256)) public tokenPoolBalances; - - /// @notice Mapping to track nonce to whether it has been used - /// @dev address => signatureNonce => isNonceUsed - /// @dev used by watchers or other users in signatures - mapping(address => mapping(uint256 => bool)) public isNonceUsed; -} diff --git a/contracts/evmx/helpers/AddressResolver.sol b/contracts/evmx/helpers/AddressResolver.sol index 22f74eb4..ce00e2da 100644 --- a/contracts/evmx/helpers/AddressResolver.sol +++ b/contracts/evmx/helpers/AddressResolver.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.21; import {Ownable} from "solady/auth/Ownable.sol"; import {Initializable} from "solady/utils/Initializable.sol"; -import "./interfaces/IAddressResolver.sol"; +import "../interfaces/IAddressResolver.sol"; abstract contract AddressResolverStorage is IAddressResolver { // slots [0-49] reserved for gap diff --git a/contracts/evmx/helpers/AddressResolverUtil.sol b/contracts/evmx/helpers/AddressResolverUtil.sol index a3450e7d..697fd3ca 100644 --- a/contracts/evmx/helpers/AddressResolverUtil.sol +++ b/contracts/evmx/helpers/AddressResolverUtil.sol @@ -52,6 +52,13 @@ abstract contract AddressResolverUtil { return addressResolver__.asyncDeployer__(); } + /// @notice Gets the deploy forwarder contract interface + /// @return IDeployForwarder interface of the registered deploy forwarder + /// @dev Resolves and returns the deploy forwarder contract for interaction + function deployForwarder__() public view returns (IDeployForwarder) { + return addressResolver__.deployForwarder__(); + } + /// @notice Internal function to set the address resolver /// @param _addressResolver The address of the resolver contract /// @dev Should be called in the initialization of inheriting contracts diff --git a/contracts/evmx/helpers/AsyncDeployer.sol b/contracts/evmx/helpers/AsyncDeployer.sol index 01d9f34a..3eea10df 100644 --- a/contracts/evmx/helpers/AsyncDeployer.sol +++ b/contracts/evmx/helpers/AsyncDeployer.sol @@ -5,7 +5,7 @@ import {Ownable} from "solady/auth/Ownable.sol"; import {LibClone} from "solady/utils/LibClone.sol"; import {UpgradeableBeacon} from "solady/utils/UpgradeableBeacon.sol"; import {Initializable} from "solady/utils/Initializable.sol"; -import "./interfaces/IAsyncDeployer.sol"; +import "../interfaces/IAsyncDeployer.sol"; import {Forwarder} from "./Forwarder.sol"; import {AsyncPromise} from "./AsyncPromise.sol"; diff --git a/contracts/evmx/helpers/AsyncPromise.sol b/contracts/evmx/helpers/AsyncPromise.sol index a5bb4f42..a0b29525 100644 --- a/contracts/evmx/helpers/AsyncPromise.sol +++ b/contracts/evmx/helpers/AsyncPromise.sol @@ -3,12 +3,12 @@ pragma solidity ^0.8.21; import {Initializable} from "solady/utils/Initializable.sol"; import {LibCall} from "solady/utils/LibCall.sol"; -import {IPromise} from "./interfaces/IPromise.sol"; -import {IAppGateway} from "./interfaces/IAppGateway.sol"; import {AddressResolverUtil} from "./AddressResolverUtil.sol"; -import {AsyncPromiseState} from "../utils/common/Structs.sol"; -import {MAX_COPY_BYTES} from "../utils/common/Constants.sol"; -import {RequestAlreadyExecuted} from "../utils/common/Errors.sol"; +import {IPromise} from "../interfaces/IPromise.sol"; +import {IAppGateway} from "../interfaces/IAppGateway.sol"; +import {AsyncPromiseState} from "../../utils/common/Structs.sol"; +import {MAX_COPY_BYTES} from "../../utils/common/Constants.sol"; + abstract contract AsyncPromiseStorage is IPromise { // slots [0-49] reserved for gap uint256[50] _gap_before; diff --git a/contracts/evmx/helpers/DeployForwarder.sol b/contracts/evmx/helpers/DeployForwarder.sol index 272ef0be..84bc502f 100644 --- a/contracts/evmx/helpers/DeployForwarder.sol +++ b/contracts/evmx/helpers/DeployForwarder.sol @@ -11,6 +11,10 @@ contract DeployForwarder is AddressResolverUtil { /// @notice The counter for the salt used to generate/deploy the contract address uint256 public saltCounter; + bytes32 public deployerSwitchboardType; + + mapping(uint32 => address) public contractFactoryPlugs; + /// @notice Deploys a contract /// @param chainSlug_ The chain slug function deploy( @@ -23,16 +27,23 @@ contract DeployForwarder is AddressResolverUtil { if (!isAsyncModifierSet) revert AsyncModifierNotUsed(); // fetch the override params from app gateway - (OverrideParams overrideParams, bytes32 sbType) = IAppGateway(msg.sender) + (OverrideParams overrideParams, bytes32 plugSwitchboardType) = IAppGateway(msg.sender) .getOverrideParams(); QueueParams memory queueParams; queueParams.overrideParams = overrideParams; - queueParams.switchboardType = sbType; + queueParams.switchboardType = deployerSwitchboardType; queueParams.transaction = Transaction({ chainSlug: chainSlug_, - target: configurations__.contractFactoryPlug(chainSlug_), - payload: _createPayload(isPlug_, msg.sender, chainSlug_, payload_, initCallData_) + target: address(0), + payload: _createPayload( + isPlug_, + plugSwitchboardType, + msg.sender, + chainSlug_, + payload_, + initCallData_ + ) }); watcher__().queue(queueParams, msg.sender); @@ -40,6 +51,7 @@ contract DeployForwarder is AddressResolverUtil { function _createPayload( IsPlug isPlug_, + bytes32 plugSwitchboardType_, address appGateway_, uint32 chainSlug_, bytes memory payload_, @@ -52,8 +64,8 @@ contract DeployForwarder is AddressResolverUtil { IContractFactoryPlug.deployContract.selector, isPlug_, salt, - bytes32(uint256(uint160(appGateway_))), - switchboardType_, + encodeAppGatewayId(appGateway_), + configurations__().switchboards(chainSlug_, plugSwitchboardType_), payload_, initCallData_ ); diff --git a/contracts/evmx/helpers/Forwarder.sol b/contracts/evmx/helpers/Forwarder.sol index f37d3549..a6523480 100644 --- a/contracts/evmx/helpers/Forwarder.sol +++ b/contracts/evmx/helpers/Forwarder.sol @@ -1,13 +1,12 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import "./interfaces/IAddressResolver.sol"; -import "./interfaces/IMiddleware.sol"; -import "./interfaces/IAppGateway.sol"; -import "./interfaces/IForwarder.sol"; -import {AddressResolverUtil} from "./AddressResolverUtil.sol"; -import {AsyncModifierNotUsed, WatcherNotSet} from "../utils/common/Errors.sol"; import "solady/utils/Initializable.sol"; +import "./AddressResolverUtil.sol"; +import "../interfaces/IAddressResolver.sol"; +import "../interfaces/IAppGateway.sol"; +import "../interfaces/IForwarder.sol"; +import {AsyncModifierNotSet, WatcherNotSet} from "../../utils/common/Errors.sol"; /// @title Forwarder Storage /// @notice Storage contract for the Forwarder contract that contains the state variables @@ -69,7 +68,7 @@ contract Forwarder is ForwarderStorage, Initializable, AddressResolverUtil { // validates if the async modifier is set bool isAsyncModifierSet = IAppGateway(msg.sender).isAsyncModifierSet(); - if (!isAsyncModifierSet) revert AsyncModifierNotUsed(); + if (!isAsyncModifierSet) revert AsyncModifierNotSet(); // fetch the override params from app gateway (OverrideParams overrideParams, bytes32 sbType) = IAppGateway(msg.sender) diff --git a/contracts/evmx/interfaces/IAddressResolver.sol b/contracts/evmx/interfaces/IAddressResolver.sol index cf2f58f2..52b7250f 100644 --- a/contracts/evmx/interfaces/IAddressResolver.sol +++ b/contracts/evmx/interfaces/IAddressResolver.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.21; import "./IWatcher.sol"; import "./IFeesManager.sol"; import "./IAsyncDeployer.sol"; +import "./IDeployForwarder.sol"; /// @title IAddressResolver /// @notice Interface for resolving system contract addresses @@ -13,11 +14,6 @@ interface IAddressResolver { /// @notice Event emitted when the watcher precompile is updated event WatcherUpdated(address watcher_); - // any other address resolution - function getAddress(bytes32 name) external view returns (address); - - function setAddress(bytes32 name, address addr) external; - // System component addresses function watcher__() external view returns (IWatcher); @@ -27,6 +23,8 @@ interface IAddressResolver { function defaultAuctionManager() external view returns (address); + function deployForwarder__() external view returns (IDeployForwarder); + function setFeesManager(address feesManager_) external; function setDefaultAuctionManager(address defaultAuctionManager_) external; diff --git a/contracts/evmx/interfaces/IAuctionManager.sol b/contracts/evmx/interfaces/IAuctionManager.sol index c0ee59f7..b9836576 100644 --- a/contracts/evmx/interfaces/IAuctionManager.sol +++ b/contracts/evmx/interfaces/IAuctionManager.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import {Bid, RequestMetadata, RequestParams} from "../../utils/common/Structs.sol"; +import {QueueParams, OverrideParams, Transaction, Bid, RequestParams} from "../../utils/common/Structs.sol"; interface IAuctionManager { /// @notice Bids for an auction diff --git a/contracts/evmx/interfaces/IDeployForwarder.sol b/contracts/evmx/interfaces/IDeployForwarder.sol new file mode 100644 index 00000000..f8905a37 --- /dev/null +++ b/contracts/evmx/interfaces/IDeployForwarder.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import {IsPlug} from "../../utils/common/Structs.sol"; + +/// @title IDeployForwarder +/// @notice Interface for the DeployForwarder contract responsible for handling deployment requests +interface IDeployForwarder { + /// @notice Returns the current salt counter used for contract deployments + /// @return The salt counter + function saltCounter() external view returns (uint256); + + /// @notice Returns the deployer switchboard type + /// @return The deployer switchboard type + function deployerSwitchboardType() external view returns (bytes32); + + /// @notice Returns the contract factory plug address for a given chain slug + /// @param chainSlug The chain slug + /// @return The contract factory plug address + function contractFactoryPlugs(uint32 chainSlug) external view returns (address); + + /// @notice Deploys a contract + /// @param isPlug_ Whether the contract is a plug + /// @param chainSlug_ The chain slug + /// @param initCallData_ The initialization calldata for the contract + /// @param payload_ The payload for the contract + function deploy( + IsPlug isPlug_, + uint32 chainSlug_, + bytes calldata initCallData_, + bytes calldata payload_ + ) external; +} diff --git a/contracts/evmx/interfaces/IPrecompile.sol b/contracts/evmx/interfaces/IPrecompile.sol index 20e50ba8..61a17324 100644 --- a/contracts/evmx/interfaces/IPrecompile.sol +++ b/contracts/evmx/interfaces/IPrecompile.sol @@ -17,5 +17,13 @@ interface IPrecompile { /// @notice Handles payload processing and returns fees /// @param payloadParams The payload parameters to handle /// @return fees The fees required for processing - function handlePayload(PayloadParams calldata payloadParams) external returns (uint256 fees); + /// @return deadline The deadline for processing + function handlePayload( + PayloadParams calldata payloadParams + ) external returns (uint256 fees, uint256 deadline); + + /// @notice Resolves a payload + /// @param payloadParams The payload parameters to resolve + /// @return fees The fees required for processing + function resolvePayload(PayloadParams calldata payloadParams) external returns (uint256 fees); } diff --git a/contracts/evmx/interfaces/IWatcher.sol b/contracts/evmx/interfaces/IWatcher.sol index 82984b6a..621b0fce 100644 --- a/contracts/evmx/interfaces/IWatcher.sol +++ b/contracts/evmx/interfaces/IWatcher.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; import {InvalidCallerTriggered, TimeoutAlreadyResolved, ResolvingTimeoutTooEarly, CallFailed, AppGatewayAlreadyCalled, InvalidWatcherSignature, NonceUsed} from "../../utils/common/Errors.sol"; -import {ResolvedPromises, AppGatewayConfig, WriteFinality, PlugConfig, DigestParams, QueueParams, PayloadParams, RequestParams} from "../../utils/common/Structs.sol"; +import {Bid, ResolvedPromises, AppGatewayConfig, WriteFinality, PlugConfig, DigestParams, QueueParams, PayloadParams, RequestParams} from "../../utils/common/Structs.sol"; /// @title IWatcher /// @notice Interface for the Watcher Precompile system that handles payload verification and execution @@ -70,7 +70,7 @@ interface IWatcher { event WatcherPrecompileLimitsSet(address watcherPrecompileLimits); - event WatcherPrecompileConfigSet(address watcherPrecompileConfig); + event configurations__Set(address configurations__); event RequestCancelledFromGateway(uint40 requestCount); diff --git a/contracts/evmx/interfaces/IWatcherFeesManager.sol b/contracts/evmx/interfaces/IWatcherFeesManager.sol deleted file mode 100644 index a3d61e34..00000000 --- a/contracts/evmx/interfaces/IWatcherFeesManager.sol +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -pragma solidity ^0.8.21; - -/// @title IWatcherFeesManager -/// @notice Interface for the Watcher Precompile system that handles payload verification and execution -/// @dev Defines core functionality for payload processing and promise resolution -interface IWatcherFeesManager { - // Watcher precompile fees - function getWatcherFees(bytes32 feeType) external view returns (uint256); - - function setWatcherFees(bytes32 feeType, uint256 fees) external; - - // Watcher fees - function getTotalWatcherFeesRequired( - bytes32[] memory feeTypes_, - uint256[] memory counts_ - ) external view returns (uint256); - - function payWatcherFees( - bytes32[] memory feeTypes_, - uint256[] memory counts_, - address consumeFrom_ - ) external; -} diff --git a/contracts/evmx/plugs/ContractFactoryPlug.sol b/contracts/evmx/plugs/ContractFactoryPlug.sol index c3691374..f8a5b835 100644 --- a/contracts/evmx/plugs/ContractFactoryPlug.sol +++ b/contracts/evmx/plugs/ContractFactoryPlug.sol @@ -65,16 +65,7 @@ contract ContractFactoryPlug is PlugBase, AccessControl, IContractFactoryPlug { initCallData_ ); - if (!success) { - // Additional error logging - assembly { - let ptr := mload(0x40) - returndatacopy(ptr, 0, returndatasize()) - log0(ptr, returndatasize()) - } - - revert ExecutionFailed(); - } + if (!success) revert ExecutionFailed(appGatewayId_, returnData_); returnData = returnData_; } diff --git a/contracts/evmx/plugs/FeesPlug.sol b/contracts/evmx/plugs/FeesPlug.sol index f0a55978..198b20f7 100644 --- a/contracts/evmx/plugs/FeesPlug.sol +++ b/contracts/evmx/plugs/FeesPlug.sol @@ -44,14 +44,6 @@ contract FeesPlug is IFeesPlug, PlugBase, AccessControl { /// @notice Event emitted when a token is removed from whitelist event TokenRemovedFromWhitelist(address token); - /// @notice Modifier to check if the balance of a token is enough to withdraw - modifier isBalanceEnough(address feeToken_, uint256 withdrawAmount_) { - uint balance = IERC20(feeToken_).balanceOf(address(this)); - if (balance < withdrawAmount_) - revert InsufficientTokenBalance(feeToken_, balance, withdrawAmount_); - _; - } - /// @notice Constructor for the FeesPlug contract /// @param socket_ The socket address /// @param owner_ The owner address @@ -61,11 +53,11 @@ contract FeesPlug is IFeesPlug, PlugBase, AccessControl { } /////////////////////// DEPOSIT AND WITHDRAWAL /////////////////////// - function depositToFee(address token_, address receiver_, uint256 amount_) external override { + function depositCredit(address token_, address receiver_, uint256 amount_) external override { _deposit(token_, receiver_, amount_, 0); } - function depositToFeeAndNative( + function depositCreditAndNative( address token_, address receiver_, uint256 amount_ @@ -90,12 +82,7 @@ contract FeesPlug is IFeesPlug, PlugBase, AccessControl { uint256 nativeAmount_ ) internal { if (!whitelistedTokens[token_]) revert TokenNotWhitelisted(token_); - SafeTransferLib.safeTransferFrom( - token_, - msg.sender, - address(this), - creditAmount_ + nativeAmount_ - ); + token_.safeTransferFrom(msg.sender, address(this), creditAmount_ + nativeAmount_); emit FeesDeposited(token_, receiver_, creditAmount_, nativeAmount_); } @@ -107,8 +94,11 @@ contract FeesPlug is IFeesPlug, PlugBase, AccessControl { address token_, address receiver_, uint256 amount_ - ) external override onlySocket isBalanceEnough(token_, amount_) { - SafeTransferLib.safeTransfer(token_, receiver_, amount_); + ) external override onlySocket { + uint256 balance = IERC20(token_).balanceOf(address(this)); + if (balance < amount_) revert InsufficientTokenBalance(token_, balance, amount_); + + token_.safeTransfer(receiver_, amount_); emit FeesWithdrawn(token_, receiver_, amount_); } diff --git a/contracts/evmx/watcher/Configurations.sol b/contracts/evmx/watcher/Configurations.sol index 42a6ada3..7a315ec9 100644 --- a/contracts/evmx/watcher/Configurations.sol +++ b/contracts/evmx/watcher/Configurations.sol @@ -3,8 +3,9 @@ pragma solidity ^0.8.21; import "solady/utils/Initializable.sol"; import "../interfaces/IConfigurations.sol"; -import {AddressResolverUtil} from "../AddressResolverUtil.sol"; +import {AddressResolverUtil} from "../helpers/AddressResolverUtil.sol"; import {encodeAppGatewayId} from "../../utils/common/IdUtils.sol"; + /// @title Configurations /// @notice Configuration contract for the Watcher Precompile system /// @dev Handles the mapping between networks, plugs, and app gateways for payload execution @@ -24,7 +25,11 @@ contract Configurations is IConfigurations, Initializable, AddressResolverUtil { /// @dev chainSlug => sb type => switchboard address mapping(uint32 => mapping(bytes32 => address)) public switchboards; - // slot 104: sockets + // slot 104: deployedForwarders + /// @notice Maps contract id to their associated forwarder + /// @dev contractId => forwarder address + + // slot 105: sockets /// @notice Maps chain slug to their associated socket /// @dev chainSlug => socket address mapping(uint32 => SocketConfig) public socketConfigs; @@ -104,6 +109,7 @@ contract Configurations is IConfigurations, Initializable, AddressResolverUtil { emit OnChainContractSet( chainSlug_, socketConfig_.socket, + // todo: move in their app gateways socketConfig_.contractFactoryPlug, socketConfig_.feesPlug ); @@ -172,7 +178,6 @@ contract Configurations is IConfigurations, Initializable, AddressResolverUtil { bytes32 switchboardType_ ) external view { (bytes32 appGatewayId, address switchboard) = getPlugConfigs(chainSlug_, target_); - if (appGatewayId != encodeAppGatewayId(appGateway_)) revert InvalidGateway(); if (switchboard != switchboards[chainSlug_][switchboardType_]) revert InvalidSwitchboard(); } diff --git a/contracts/evmx/watcher/RequestHandler.sol b/contracts/evmx/watcher/RequestHandler.sol index 084d3d23..393921a1 100644 --- a/contracts/evmx/watcher/RequestHandler.sol +++ b/contracts/evmx/watcher/RequestHandler.sol @@ -67,7 +67,7 @@ contract RequestHandler is WatcherBase { if (queuePayloadParams.length > REQUEST_PAYLOAD_COUNT_LIMIT) revert RequestPayloadCountLimitExceeded(); - if (!IFeesManager(feesManager__()).isUserCreditsEnough(consumeFrom_, appGateway_, maxFees_)) + if (!IFeesManager(feesManager__()).isCreditSpendable(consumeFrom_, appGateway_, maxFees_)) revert InsufficientFees(); requestCount = nextRequestCount++; @@ -164,7 +164,7 @@ contract RequestHandler is WatcherBase { } // get the switchboard address from the watcher precompile config - address switchboard = watcherPrecompileConfig().switchboards( + address switchboard = configurations__().switchboards( queuePayloadParam.chainSlug, queuePayloadParam.switchboardType ); @@ -271,7 +271,7 @@ contract RequestHandler is WatcherBase { if (r.requestFeesDetails.maxFees >= newMaxFees_) revert NewMaxFeesLowerThanCurrent(r.requestFeesDetails.maxFees, newMaxFees_); if ( - !IFeesManager(feesManager__()).isUserCreditsEnough( + !IFeesManager(feesManager__()).isCreditSpendable( r.requestFeesDetails.consumeFrom, appGateway, newMaxFees_ diff --git a/contracts/evmx/watcher/Watcher.sol b/contracts/evmx/watcher/Watcher.sol index e05de886..accd24e4 100644 --- a/contracts/evmx/watcher/Watcher.sol +++ b/contracts/evmx/watcher/Watcher.sol @@ -21,7 +21,7 @@ contract Watcher is Trigger { addressResolver__ = addressResolver_; } - function queueAndRequest( + function queueAndSubmit( QueueParams memory queue_, uint256 maxFees, address auctionManager, diff --git a/contracts/evmx/watcher/WatcherBase.sol b/contracts/evmx/watcher/WatcherBase.sol index b79e7ed5..b36e6c31 100644 --- a/contracts/evmx/watcher/WatcherBase.sol +++ b/contracts/evmx/watcher/WatcherBase.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.21; import "../interfaces/IWatcher.sol"; - +import "../interfaces/IConfigurations.sol"; /// @title WatcherBase contract WatcherBase { // The address of the WatcherPrecompileStorage contract diff --git a/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol b/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol index 3aad1678..87b8e5af 100644 --- a/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.21; import "../../interfaces/IPrecompile.sol"; import "../../../utils/common/Structs.sol"; -import {InvalidTarget, InvalidPayloadSize, InvalidScheduleDelay, InvalidTimeoutRequest, TimeoutAlreadyResolved, ResolvingTimeoutTooEarly, CallFailed} from "../../../utils/common/Errors.sol"; +import {InvalidPayloadSize, InvalidScheduleDelay, InvalidTimeoutRequest, TimeoutAlreadyResolved, ResolvingTimeoutTooEarly, CallFailed} from "../../../utils/common/Errors.sol"; import "../WatcherBase.sol"; /// @title SchedulePrecompile diff --git a/contracts/evmx/watcher/precompiles/WritePrecompile.sol b/contracts/evmx/watcher/precompiles/WritePrecompile.sol index f075c0d1..cdbc1355 100644 --- a/contracts/evmx/watcher/precompiles/WritePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/WritePrecompile.sol @@ -22,6 +22,8 @@ contract WritePrecompile is IPrecompile, WatcherBase { /// @notice The digest hash for a payload mapping(bytes32 => bytes32) public digestHashes; + mapping(address => bool) public isContractFactoryPlug; + /// @notice The fees for a write and includes callback fees uint256 public writeFees; @@ -46,10 +48,6 @@ contract WritePrecompile is IPrecompile, WatcherBase { chainMaxMsgValueLimit[queuePayloadParams_.transaction.chainSlug] ) revert MaxMsgValueLimitExceeded(); - if (queuePayloadParams_.transaction.target != address(0)) { - revert InvalidTarget(); - } - if ( queuePayloadParams_.transaction.payload.length > 0 && queuePayloadParams_.transaction.payload.length < PAYLOAD_SIZE_LIMIT @@ -57,15 +55,23 @@ contract WritePrecompile is IPrecompile, WatcherBase { revert InvalidPayloadSize(); } - configurations__().verifyConnections( - queuePayloadParams_.transaction.chainSlug, - queuePayloadParams_.transaction.target, - appGateway_, - queuePayloadParams_.switchboardType - ); + if (queuePayloadParams_.transaction.target == address(0)) { + queuePayloadParams_.transaction.target = contractFactoryPlugs[ + queuePayloadParams_.transaction.chainSlug + ]; + appGateway_ = address(this); + } else { + configurations__().verifyConnections( + queuePayloadParams_.transaction.chainSlug, + queuePayloadParams_.transaction.target, + appGateway_, + queuePayloadParams_.switchboardType + ); + } // For write precompile, encode the payload parameters precompileData = abi.encode( + appGateway_, queuePayloadParams_.transaction, queuePayloadParams_.overrideParams.writeFinality, queuePayloadParams_.overrideParams.gasLimit, @@ -87,11 +93,15 @@ contract WritePrecompile is IPrecompile, WatcherBase { deadline = block.timestamp + expiryTime; ( + address appGateway, Transaction transaction, WriteFinality writeFinality, uint256 gasLimit, uint256 value - ) = abi.decode(payloadParams.precompileData, (Transaction, bool, uint256, uint256)); + ) = abi.decode( + payloadParams.precompileData, + (address, Transaction, bool, uint256, uint256) + ); bytes32 prevBatchDigestHash = _getPrevBatchDigestHash(payloadParams); @@ -106,7 +116,7 @@ contract WritePrecompile is IPrecompile, WatcherBase { value, transaction.payload, transaction.target, - encodeAppGatewayId(payloadParams.appGateway), + encodeAppGatewayId(appGateway), prevBatchDigestHash, bytes("") ); diff --git a/contracts/utils/common/Errors.sol b/contracts/utils/common/Errors.sol index 8f1289a8..bf981a4b 100644 --- a/contracts/utils/common/Errors.sol +++ b/contracts/utils/common/Errors.sol @@ -19,7 +19,8 @@ error InvalidCallerTriggered(); error InvalidPromise(); error InvalidWatcherSignature(); error NonceUsed(); -error AsyncModifierNotUsed(); +error AsyncModifierNotSet(); +error WatcherNotSet(); error InvalidTarget(); error InvalidIndex(); error InvalidPayloadSize(); @@ -27,9 +28,15 @@ error InvalidScheduleDelay(); error InvalidTimeoutRequest(); /// @notice Error thrown when trying to start or bid a closed auction error AuctionClosed(); +/// @notice Error thrown when trying to start or bid an auction that is not open +error AuctionNotOpen(); /// @notice Error thrown if fees exceed the maximum set fees error BidExceedsMaxFees(); /// @notice Error thrown if a lower bid already exists error LowerBidAlreadyExists(); /// @notice Error thrown when request count mismatch error RequestCountMismatch(); + +error InvalidAmount(); +error InsufficientCreditsAvailable(); +error InsufficientBalance(); diff --git a/contracts/utils/common/Structs.sol b/contracts/utils/common/Structs.sol index b990f744..4eb41af4 100644 --- a/contracts/utils/common/Structs.sol +++ b/contracts/utils/common/Structs.sol @@ -44,13 +44,12 @@ enum ExecutionStatus { Reverted } -struct AppGatewayWhitelistParams { +struct AppGatewayApprovals { address appGateway; - bool isApproved; + bool approval; } //// STRUCTS //// - struct AppGatewayConfig { PlugConfig plugConfig; address plug; From 2bd413ec676e7e0cf9f5775685557e6ec6c952dc Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Thu, 22 May 2025 23:30:33 +0530 Subject: [PATCH 043/130] fix: helpers and base build --- .../{app-gateways => }/AuctionManager.sol | 51 +++--- contracts/evmx/base/AppGatewayBase.sol | 34 ++-- contracts/evmx/helpers/AddressResolver.sol | 57 ++++-- .../evmx/helpers/AddressResolverUtil.sol | 10 +- contracts/evmx/helpers/AsyncDeployer.sol | 25 +-- contracts/evmx/helpers/AsyncPromise.sol | 29 +-- contracts/evmx/helpers/DeployForwarder.sol | 26 +-- contracts/evmx/helpers/Forwarder.sol | 14 +- .../evmx/interfaces/IAddressResolver.sol | 18 +- contracts/evmx/interfaces/IAppGateway.sol | 3 +- contracts/evmx/interfaces/IAsyncDeployer.sol | 1 - contracts/evmx/interfaces/IAuctionManager.sol | 37 ++-- contracts/evmx/interfaces/IConfigurations.sol | 17 +- .../evmx/interfaces/IDeployForwarder.sol | 4 +- contracts/evmx/interfaces/IFeesManager.sol | 68 ++++---- contracts/evmx/interfaces/IPromise.sol | 29 ++- .../evmx/interfaces/IPromiseResolver.sol | 17 ++ contracts/evmx/interfaces/IRequestHandler.sol | 28 +++ contracts/evmx/interfaces/IWatcher.sol | 165 +++++------------- contracts/protocol/Socket.sol | 4 - contracts/protocol/SocketConfig.sol | 6 +- contracts/protocol/base/PlugBase.sol | 3 +- contracts/utils/common/Errors.sol | 28 +++ contracts/utils/common/Structs.sol | 8 + 24 files changed, 363 insertions(+), 319 deletions(-) rename contracts/evmx/{app-gateways => }/AuctionManager.sol (89%) create mode 100644 contracts/evmx/interfaces/IPromiseResolver.sol create mode 100644 contracts/evmx/interfaces/IRequestHandler.sol diff --git a/contracts/evmx/app-gateways/AuctionManager.sol b/contracts/evmx/AuctionManager.sol similarity index 89% rename from contracts/evmx/app-gateways/AuctionManager.sol rename to contracts/evmx/AuctionManager.sol index a718e2aa..d34cadc1 100644 --- a/contracts/evmx/app-gateways/AuctionManager.sol +++ b/contracts/evmx/AuctionManager.sol @@ -3,25 +3,17 @@ pragma solidity ^0.8.21; import {ECDSA} from "solady/utils/ECDSA.sol"; import "solady/utils/Initializable.sol"; -import "../interfaces/IAuctionManager.sol"; -import "../../utils/AccessControl.sol"; -import {AuctionNotOpen, AuctionClosed, BidExceedsMaxFees, LowerBidAlreadyExists, InvalidTransmitter} from "../../utils/common/Errors.sol"; -import {SCHEDULE} from "../../utils/common/Constants.sol"; +import "./interfaces/IAuctionManager.sol"; +import "../utils/AccessControl.sol"; +import {AuctionNotOpen, AuctionClosed, BidExceedsMaxFees, LowerBidAlreadyExists, InvalidTransmitter, MaxReAuctionCountReached, InvalidBid} from "../utils/common/Errors.sol"; +import {SCHEDULE} from "../utils/common/Constants.sol"; -import {TRANSMITTER_ROLE} from "../../utils/common/AccessRoles.sol"; -import {AppGatewayBase} from "../base/AppGatewayBase.sol"; +import {TRANSMITTER_ROLE} from "../utils/common/AccessRoles.sol"; +import {AppGatewayBase} from "./base/AppGatewayBase.sol"; /// @title AuctionManagerStorage /// @notice Storage for the AuctionManager contract abstract contract AuctionManagerStorage is IAuctionManager { - enum AuctionStatus { - NOT_STARTED, - OPEN, - CLOSED, - RESTARTED, - EXPIRED - } - // slot 50 uint32 public evmxSlug; @@ -57,10 +49,7 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, event AuctionEndDelaySecondsSet(uint256 auctionEndDelaySeconds); event MaxReAuctionCountSet(uint256 maxReAuctionCount); - error InvalidBid(); - error MaxReAuctionCountReached(); - - constructor() { + constructor(address addressResolver_) AppGatewayBase(addressResolver_) { // todo-later: evmx slug can be immutable and set here _disableInitializers(); // disable for implementation } @@ -72,8 +61,8 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, /// @param maxReAuctionCount_ The maximum number of re-auctions allowed function initialize( uint32 evmxSlug_, + uint128 bidTimeout_, uint256 auctionEndDelaySeconds_, - uint256 bidTimeout_, uint256 maxReAuctionCount_, address addressResolver_, address owner_ @@ -98,6 +87,7 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, } /// @notice Places a bid for an auction + /// @dev transmitters should approve credits to the auction manager contract for scheduling requests /// @param requestCount_ The ID of the auction /// @param bidFees The bid amount /// @param transmitterSignature The signature of the transmitter @@ -106,7 +96,7 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, uint256 bidFees, bytes memory transmitterSignature, bytes memory extraData - ) external { + ) external override { if ( auctionStatus[requestCount_] != AuctionStatus.OPEN && auctionStatus[requestCount_] != AuctionStatus.RESTARTED @@ -126,13 +116,6 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, uint256 transmitterCredits = getMaxFees(requestCount_); if (bidFees > transmitterCredits) revert BidExceedsMaxFees(); - deductScheduleFees( - transmitter, - winningBids[requestCount_].transmitter == address(0) - ? address(this) - : winningBids[requestCount_].transmitter - ); - // create a new bid Bid memory newBid = Bid({fee: bidFees, transmitter: transmitter, extraData: extraData}); winningBids[requestCount_] = newBid; @@ -142,6 +125,12 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, _startAuction(requestCount_); _createRequest( auctionEndDelaySeconds, + deductScheduleFees( + transmitter, + winningBids[requestCount_].transmitter == address(0) + ? address(this) + : winningBids[requestCount_].transmitter + ), address(this), abi.encodeWithSelector(this.endAuction.selector, requestCount_) ); @@ -160,7 +149,7 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, /// @notice Ends an auction /// @param requestCount_ The ID of the auction - function endAuction(uint40 requestCount_) external onlyWatcher { + function endAuction(uint40 requestCount_) external override onlyWatcher { if ( auctionStatus[requestCount_] == AuctionStatus.CLOSED || auctionStatus[requestCount_] == AuctionStatus.NOT_STARTED @@ -195,7 +184,7 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, /// @dev Auction can be restarted only for `maxReAuctionCount` times. /// @dev It also unblocks the fees from last transmitter to be assigned to the new winner. /// @param requestCount_ The request id - function expireBid(uint40 requestCount_) external onlyWatcher { + function expireBid(uint40 requestCount_) external override onlyWatcher { if (reAuctionCount[requestCount_] >= maxReAuctionCount) revert MaxReAuctionCountReached(); RequestParams memory requestParams = _getRequestParams(requestCount_); @@ -236,7 +225,7 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, queueParams.switchboardType = sbType; // queue and create request - watcher__().queueAndSubmit(queueParams, maxFees_, address(this), address(this), bytes("")); + watcher__().queueAndSubmit(queueParams, maxFees_, address(this), consumeFrom_, bytes("")); } /// @notice Returns the quoted transmitter fees for a request @@ -263,7 +252,7 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, /// @notice Recovers the signer of a message /// @param digest_ The digest of the message /// @param signature_ The signature of the message - /// @return The signer of the message + /// @return signer The signer of the message function _recoverSigner( bytes32 digest_, bytes memory signature_ diff --git a/contracts/evmx/base/AppGatewayBase.sol b/contracts/evmx/base/AppGatewayBase.sol index 55b25420..359ec7e8 100644 --- a/contracts/evmx/base/AppGatewayBase.sol +++ b/contracts/evmx/base/AppGatewayBase.sol @@ -53,7 +53,7 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { function _postAsync() internal { isAsyncModifierSet = false; - (uint40 requestCount, address[] memory promises) = watcher__().submitRequest( + (, address[] memory promises) = watcher__().submitRequest( maxFees, auctionManager, consumeFrom, @@ -113,7 +113,7 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { /// @dev This function retrieves the onchain address using the contractId and chainSlug, then calls the watcher precompile to update the plug's validity status function _setValidPlug(uint32 chainSlug_, bytes32 contractId, bool isValid) internal { address onchainAddress = getOnChainAddress(contractId, chainSlug_); - watcher__().setIsValidPlug(chainSlug_, onchainAddress, isValid); + watcher__().configurations__().setIsValidPlug(isValid, chainSlug_, onchainAddress); } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -143,13 +143,16 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { onCompleteData = abi.encode(chainSlug_, true); } + function then(bytes memory data_, bytes memory returnData_) external onlyPromises { + // todo + } + /// @notice Sets the address for a deployed contract /// @param data_ The data /// @param returnData_ The return data function setAddress(bytes memory data_, bytes memory returnData_) external onlyPromises { (uint32 chainSlug, bytes32 contractId) = abi.decode(data_, (uint32, bytes32)); - address forwarderContractAddress = addressResolver__.getOrDeployForwarderContract( - address(this), + address forwarderContractAddress = asyncDeployer__().getOrDeployForwarderContract( abi.decode(returnData_, (address)), chainSlug ); @@ -165,9 +168,9 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { overrideParams.callType = SCHEDULE; overrideParams.delayInSeconds = delayInSeconds_; - QueueParams memory queueParams = new QueueParams(); + QueueParams memory queueParams; queueParams.overrideParams = overrideParams; - (address promise_, ) = watcher__().queue(queueParams, address(this)); + watcher__().queue(queueParams, address(this)); } /// @notice Gets the on-chain address @@ -186,7 +189,7 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { } function _setCallType(Read isReadCall_) internal { - overrideParams.callType = isReadCall_ ? READ : WRITE; + overrideParams.callType = isReadCall_ == Read.OFF ? WRITE : READ; } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -295,7 +298,7 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { maxFees = fees_; } - function getOverrideParams() public view returns (OverrideParams, bytes32) { + function getOverrideParams() public view returns (OverrideParams memory, bytes32) { return (overrideParams, sbType); } @@ -306,13 +309,13 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { /// @notice Reverts the transaction /// @param requestCount_ The async ID function _revertTx(uint40 requestCount_) internal { - watcher__().cancelRequest(requestCount_); + watcher__().requestHandler__().cancelRequest(requestCount_); } /// @notice increases the transaction maxFees /// @param requestCount_ The async ID function _increaseFees(uint40 requestCount_, uint256 newMaxFees_) internal { - watcher__().increaseFees(requestCount_, newMaxFees_); + watcher__().requestHandler__().increaseFees(requestCount_, newMaxFees_); } /// @notice Withdraws fee tokens @@ -325,9 +328,8 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { address token_, uint256 amount_, address receiver_ - ) internal returns (uint40) { - return - watcher__().withdrawTo(chainSlug_, token_, amount_, receiver_, auctionManager, maxFees); + ) internal { + feesManager__().withdrawCredits(chainSlug_, token_, amount_, maxFees, receiver_); } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -356,10 +358,6 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { /// @notice hook to handle the revert in callbacks or onchain executions /// @dev can be overridden by the app gateway to add custom logic - /// @param requestCount_ The async ID /// @param payloadId_ The payload ID - function handleRevert( - uint40 requestCount_, - bytes32 payloadId_ - ) external override onlyPromises {} + function handleRevert(bytes32 payloadId_) external override onlyPromises {} } diff --git a/contracts/evmx/helpers/AddressResolver.sol b/contracts/evmx/helpers/AddressResolver.sol index ce00e2da..80cf5892 100644 --- a/contracts/evmx/helpers/AddressResolver.sol +++ b/contracts/evmx/helpers/AddressResolver.sol @@ -10,10 +10,12 @@ abstract contract AddressResolverStorage is IAddressResolver { uint256[50] _gap_before; IWatcher public override watcher__; - IFeesManager public override feesManager; - IAsyncDeployer public override asyncDeployer; + IFeesManager public override feesManager__; + IAsyncDeployer public override asyncDeployer__; + IDeployForwarder public override deployForwarder__; address public override defaultAuctionManager; + mapping(bytes32 => address) public override contractAddresses; // slots [61-110] reserved for gap uint256[50] _gap_after; @@ -23,9 +25,9 @@ abstract contract AddressResolverStorage is IAddressResolver { /// @notice This contract is responsible for fetching latest core addresses and deploying Forwarder and AsyncPromise contracts. /// @dev Inherits the Ownable contract and implements the IAddressResolver interface. contract AddressResolver is AddressResolverStorage, Initializable, Ownable { - /// @notice Error thrown if AppGateway contract was already set by a different address - error InvalidAppGateway(address contractAddress_); - + /// @notice Constructor to initialize the contract + /// @dev it deploys the forwarder and async promise implementations and beacons for them + /// @dev this contract is owner of the beacons for upgrading later constructor() { _disableInitializers(); // disable for implementation } @@ -35,35 +37,52 @@ contract AddressResolver is AddressResolverStorage, Initializable, Ownable { /// @dev this contract is owner of the beacons for upgrading later /// @param owner_ The address of the contract owner function initialize(address owner_) public reinitializer(1) { - version = 1; _initializeOwner(owner_); } + /// @notice Updates the address of the watcher contract + /// @param watcher_ The address of the watcher contract + function setWatcher(address watcher_) external override onlyOwner { + watcher__ = IWatcher(watcher_); + emit WatcherUpdated(watcher_); + } + /// @notice Updates the address of the fees manager /// @param feesManager_ The address of the fees manager - function setFeesManager(address feesManager_) external onlyOwner { - feesManager = IFeesManager(feesManager_); + function setFeesManager(address feesManager_) external override onlyOwner { + feesManager__ = IFeesManager(feesManager_); emit FeesManagerUpdated(feesManager_); } + /// @notice Updates the address of the async deployer + /// @param asyncDeployer_ The address of the async deployer + function setAsyncDeployer(address asyncDeployer_) external override onlyOwner { + asyncDeployer__ = IAsyncDeployer(asyncDeployer_); + emit AsyncDeployerUpdated(asyncDeployer_); + } + /// @notice Updates the address of the default auction manager /// @param defaultAuctionManager_ The address of the default auction manager - function setDefaultAuctionManager(address defaultAuctionManager_) external onlyOwner { + function setDefaultAuctionManager(address defaultAuctionManager_) external override onlyOwner { defaultAuctionManager = defaultAuctionManager_; emit DefaultAuctionManagerUpdated(defaultAuctionManager_); } - /// @notice Updates the address of the watcher precompile contract - /// @param watcher_ The address of the watcher precompile contract - function setWatcher(address watcher_) external onlyOwner { - watcher__ = IWatcher(watcher_); - emit WatcherUpdated(watcher_); + /// @notice Updates the address of the deploy forwarder + /// @param deployForwarder_ The address of the deploy forwarder + function setDeployForwarder(address deployForwarder_) external override onlyOwner { + deployForwarder__ = IDeployForwarder(deployForwarder_); + emit DeployForwarderUpdated(deployForwarder_); } - /// @notice Returns the address of the async deployer - /// @return The address of the async deployer - function setAsyncDeployer(address asyncDeployer_) external onlyOwner { - asyncDeployer = IAsyncDeployer(asyncDeployer_); - emit AsyncDeployerUpdated(asyncDeployer_); + /// @notice Updates the address of a contract + /// @param contractId_ The id of the contract + /// @param contractAddress_ The address of the contract + function setContractAddress( + bytes32 contractId_, + address contractAddress_ + ) external override onlyOwner { + contractAddresses[contractId_] = contractAddress_; + emit ContractAddressUpdated(contractId_, contractAddress_); } } diff --git a/contracts/evmx/helpers/AddressResolverUtil.sol b/contracts/evmx/helpers/AddressResolverUtil.sol index 697fd3ca..6ba12c34 100644 --- a/contracts/evmx/helpers/AddressResolverUtil.sol +++ b/contracts/evmx/helpers/AddressResolverUtil.sol @@ -5,6 +5,7 @@ import "../interfaces/IAddressResolver.sol"; import "../interfaces/IWatcher.sol"; import "../interfaces/IFeesManager.sol"; import "../interfaces/IAsyncDeployer.sol"; +import {OnlyWatcherAllowed} from "../../utils/common/Errors.sol"; /// @title AddressResolverUtil /// @notice Utility contract for resolving system contract addresses @@ -18,14 +19,11 @@ abstract contract AddressResolverUtil { // slots 1-50 reserved for future use uint256[50] __gap_resolver_util; - /// @notice Error thrown when an invalid address attempts to call the Watcher only function - error onlyWatcherAllowed(); - /// @notice Restricts function access to the watcher precompile contract /// @dev Validates that msg.sender matches the registered watcher precompile address modifier onlyWatcher() { if (msg.sender != address(addressResolver__.watcher__())) { - revert onlyWatcherAllowed(); + revert OnlyWatcherAllowed(); } _; @@ -65,4 +63,8 @@ abstract contract AddressResolverUtil { function _setAddressResolver(address _addressResolver) internal { addressResolver__ = IAddressResolver(_addressResolver); } + + function getCoreAppGateway(address appGateway_) internal view returns (address) { + return addressResolver__.watcher__().configurations__().getCoreAppGateway(appGateway_); + } } diff --git a/contracts/evmx/helpers/AsyncDeployer.sol b/contracts/evmx/helpers/AsyncDeployer.sol index 3eea10df..04145c27 100644 --- a/contracts/evmx/helpers/AsyncDeployer.sol +++ b/contracts/evmx/helpers/AsyncDeployer.sol @@ -8,6 +8,7 @@ import {Initializable} from "solady/utils/Initializable.sol"; import "../interfaces/IAsyncDeployer.sol"; import {Forwarder} from "./Forwarder.sol"; import {AsyncPromise} from "./AsyncPromise.sol"; +import {AddressResolverUtil} from "./AddressResolverUtil.sol"; abstract contract AsyncDeployerStorage is IAsyncDeployer { // slots [0-49] reserved for gap @@ -38,7 +39,7 @@ abstract contract AsyncDeployerStorage is IAsyncDeployer { /// @title AsyncDeployer Contract /// @notice This contract is responsible for deploying Forwarder and AsyncPromise contracts. /// @dev Inherits the Ownable contract and implements the IAddressResolver interface. -contract AsyncDeployer is AsyncDeployerStorage, Initializable, Ownable { +contract AsyncDeployer is AsyncDeployerStorage, Initializable, Ownable, AddressResolverUtil { constructor(address addressResolver_) { _disableInitializers(); // disable for implementation addressResolver = addressResolver_; @@ -49,7 +50,6 @@ contract AsyncDeployer is AsyncDeployerStorage, Initializable, Ownable { /// @dev this contract is owner of the beacons for upgrading later /// @param owner_ The address of the contract owner function initialize(address owner_) public reinitializer(1) { - version = 1; _initializeOwner(owner_); forwarderImplementation = address(new Forwarder()); @@ -67,10 +67,9 @@ contract AsyncDeployer is AsyncDeployerStorage, Initializable, Ownable { /// @param chainSlug_ The chain slug /// @return newForwarder The address of the deployed Forwarder proxy contract function getOrDeployForwarderContract( - address appGateway_, address chainContractAddress_, uint32 chainSlug_ - ) public returns (address newForwarder) { + ) public override returns (address newForwarder) { // predict address address forwarderAddress = getForwarderAddress(chainContractAddress_, chainSlug_); @@ -88,9 +87,6 @@ contract AsyncDeployer is AsyncDeployerStorage, Initializable, Ownable { // deploys the proxy newForwarder = _deployProxy(salt, address(forwarderBeacon), initData); - // sets the config - _setConfig(appGateway_, newForwarder); - // emits the event emit ForwarderDeployed(newForwarder, salt); } @@ -132,7 +128,7 @@ contract AsyncDeployer is AsyncDeployerStorage, Initializable, Ownable { /// @return newAsyncPromise The address of the deployed AsyncPromise proxy contract function deployAsyncPromiseContract( address invoker_ - ) external onlyWatcher returns (address newAsyncPromise) { + ) external override onlyWatcher returns (address newAsyncPromise) { // creates init data and salt (bytes32 salt, bytes memory initData) = _createAsyncPromiseParams(invoker_); asyncPromiseCounter++; @@ -164,7 +160,7 @@ contract AsyncDeployer is AsyncDeployerStorage, Initializable, Ownable { function getForwarderAddress( address chainContractAddress_, uint32 chainSlug_ - ) public view returns (address) { + ) public view override returns (address) { (bytes32 salt, ) = _createForwarderParams(chainContractAddress_, chainSlug_); return _predictProxyAddress(salt, address(forwarderBeacon)); } @@ -172,7 +168,7 @@ contract AsyncDeployer is AsyncDeployerStorage, Initializable, Ownable { /// @notice Gets the predicted address of an AsyncPromise proxy contract /// @param invoker_ The address of the invoker /// @return The predicted address of the AsyncPromise proxy contract - function getAsyncPromiseAddress(address invoker_) public view returns (address) { + function getAsyncPromiseAddress(address invoker_) public view override returns (address) { (bytes32 salt, ) = _createAsyncPromiseParams(invoker_); return _predictProxyAddress(salt, address(asyncPromiseBeacon)); } @@ -186,21 +182,16 @@ contract AsyncDeployer is AsyncDeployerStorage, Initializable, Ownable { LibClone.predictDeterministicAddressERC1967BeaconProxy(beacon_, salt_, address(this)); } - function _setConfig(address appGateway_, address newForwarder_) internal { - address gateway = contractsToGateways[appGateway_]; - contractsToGateways[newForwarder_] = gateway; - } - /// @notice Updates the implementation contract for Forwarder /// @param implementation_ The new implementation address - function setForwarderImplementation(address implementation_) external onlyOwner { + function setForwarderImplementation(address implementation_) external override onlyOwner { forwarderBeacon.upgradeTo(implementation_); emit ImplementationUpdated("Forwarder", implementation_); } /// @notice Updates the implementation contract for AsyncPromise /// @param implementation_ The new implementation address - function setAsyncPromiseImplementation(address implementation_) external onlyOwner { + function setAsyncPromiseImplementation(address implementation_) external override onlyOwner { asyncPromiseBeacon.upgradeTo(implementation_); emit ImplementationUpdated("AsyncPromise", implementation_); } diff --git a/contracts/evmx/helpers/AsyncPromise.sol b/contracts/evmx/helpers/AsyncPromise.sol index a0b29525..a545acb5 100644 --- a/contracts/evmx/helpers/AsyncPromise.sol +++ b/contracts/evmx/helpers/AsyncPromise.sol @@ -4,30 +4,33 @@ pragma solidity ^0.8.21; import {Initializable} from "solady/utils/Initializable.sol"; import {LibCall} from "solady/utils/LibCall.sol"; import {AddressResolverUtil} from "./AddressResolverUtil.sol"; -import {IPromise} from "../interfaces/IPromise.sol"; import {IAppGateway} from "../interfaces/IAppGateway.sol"; -import {AsyncPromiseState} from "../../utils/common/Structs.sol"; -import {MAX_COPY_BYTES} from "../../utils/common/Constants.sol"; +import "../interfaces/IPromise.sol"; +import {NotInvoker, RequestCountMismatch} from "../../utils/common/Errors.sol"; abstract contract AsyncPromiseStorage is IPromise { // slots [0-49] reserved for gap uint256[50] _gap_before; - // bytes1 /// @notice The callback selector to be called on the invoker. bytes4 public callbackSelector; - // bytes8 + /// @notice The current state of the async promise. - AsyncPromiseState public state; - // bytes20 + AsyncPromiseState public override state; + /// @notice The local contract which initiated the async call. /// @dev The callback will be executed on this address - address public localInvoker; + address public override localInvoker; /// @notice The request count of the promise - uint256 public requestCount; + uint256 public override requestCount; + + /// @notice The flag to check if the promise exceeded the max copy limit + bool public override exceededMaxCopy; + + /// @notice The return data of the promise + bytes public override returnData; - // slot 52 /// @notice The callback data to be used when the promise is resolved. bytes public callbackData; @@ -42,6 +45,7 @@ abstract contract AsyncPromiseStorage is IPromise { /// This promise expires once the callback is executed contract AsyncPromise is AsyncPromiseStorage, Initializable, AddressResolverUtil { using LibCall for address; + /// @notice Error thrown when attempting to resolve an already resolved promise. error PromiseAlreadyResolved(); /// @notice Only the local invoker can set then's promise callback @@ -136,15 +140,14 @@ contract AsyncPromise is AsyncPromiseStorage, Initializable, AddressResolverUtil /// @notice Sets the callback selector and data for the promise. /// @param selector_ The function selector for the callback. /// @param data_ The data to be passed to the callback. - /// @return promise_ The address of the current promise. function then(bytes4 selector_, bytes memory data_) external override { if (msg.sender != localInvoker) revert NotInvoker(); // if the promise is already set up, revert if (state != AsyncPromiseState.WAITING_FOR_CALLBACK_SELECTOR) { revert PromiseAlreadySetUp(); } - if (watcher__().latestAsyncPromise != address(this)) revert PromiseAlreadySetUp(); - if (requestCount != watcher__().latestRequestCount) revert RequestCountMismatch(); + if (watcher__().latestAsyncPromise() != address(this)) revert PromiseAlreadySetUp(); + if (requestCount != watcher__().getCurrentRequestCount()) revert RequestCountMismatch(); // if the promise is waiting for the callback selector, set it and update the state callbackSelector = selector_; diff --git a/contracts/evmx/helpers/DeployForwarder.sol b/contracts/evmx/helpers/DeployForwarder.sol index 84bc502f..b07002cb 100644 --- a/contracts/evmx/helpers/DeployForwarder.sol +++ b/contracts/evmx/helpers/DeployForwarder.sol @@ -1,19 +1,24 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import {QueueParams, OverrideParams, Transaction} from "../../utils/common/Structs.sol"; +import {IAppGateway} from "../interfaces/IAppGateway.sol"; +import {IContractFactoryPlug} from "../interfaces/IContractFactoryPlug.sol"; +import {IDeployForwarder} from "../interfaces/IDeployForwarder.sol"; import "./AddressResolverUtil.sol"; +import {AsyncModifierNotSet} from "../../utils/common/Errors.sol"; +import {QueueParams, OverrideParams, Transaction} from "../../utils/common/Structs.sol"; +import {encodeAppGatewayId} from "../../utils/common/IdUtils.sol"; /// @title DeployerGateway /// @notice App gateway contract responsible for handling deployment requests /// @dev Extends AppGatewayBase to provide deployment queueing functionality -contract DeployForwarder is AddressResolverUtil { +contract DeployForwarder is AddressResolverUtil, IDeployForwarder { /// @notice The counter for the salt used to generate/deploy the contract address - uint256 public saltCounter; + uint256 public override saltCounter; - bytes32 public deployerSwitchboardType; + bytes32 public override deployerSwitchboardType; - mapping(uint32 => address) public contractFactoryPlugs; + mapping(uint32 => address) public override contractFactoryPlugs; /// @notice Deploys a contract /// @param chainSlug_ The chain slug @@ -23,11 +28,12 @@ contract DeployForwarder is AddressResolverUtil { bytes memory initCallData_, bytes memory payload_ ) external { - bool isAsyncModifierSet = IAppGateway(msg.sender).isAsyncModifierSet(); - if (!isAsyncModifierSet) revert AsyncModifierNotUsed(); + address msgSender = msg.sender; + bool isAsyncModifierSet = IAppGateway(msgSender).isAsyncModifierSet(); + if (!isAsyncModifierSet) revert AsyncModifierNotSet(); // fetch the override params from app gateway - (OverrideParams overrideParams, bytes32 plugSwitchboardType) = IAppGateway(msg.sender) + (OverrideParams memory overrideParams, bytes32 plugSwitchboardType) = IAppGateway(msgSender) .getOverrideParams(); QueueParams memory queueParams; @@ -39,7 +45,7 @@ contract DeployForwarder is AddressResolverUtil { payload: _createPayload( isPlug_, plugSwitchboardType, - msg.sender, + msgSender, chainSlug_, payload_, initCallData_ @@ -65,7 +71,7 @@ contract DeployForwarder is AddressResolverUtil { isPlug_, salt, encodeAppGatewayId(appGateway_), - configurations__().switchboards(chainSlug_, plugSwitchboardType_), + watcher__().configurations__().switchboards(chainSlug_, plugSwitchboardType_), payload_, initCallData_ ); diff --git a/contracts/evmx/helpers/Forwarder.sol b/contracts/evmx/helpers/Forwarder.sol index a6523480..7745bc1d 100644 --- a/contracts/evmx/helpers/Forwarder.sol +++ b/contracts/evmx/helpers/Forwarder.sol @@ -6,6 +6,7 @@ import "./AddressResolverUtil.sol"; import "../interfaces/IAddressResolver.sol"; import "../interfaces/IAppGateway.sol"; import "../interfaces/IForwarder.sol"; +import {QueueParams, OverrideParams, Transaction} from "../../utils/common/Structs.sol"; import {AsyncModifierNotSet, WatcherNotSet} from "../../utils/common/Errors.sol"; /// @title Forwarder Storage @@ -49,13 +50,13 @@ contract Forwarder is ForwarderStorage, Initializable, AddressResolverUtil { /// @notice Returns the on-chain address associated with this forwarder. /// @return The on-chain address. - function getOnChainAddress() external view returns (address) { + function getOnChainAddress() external view override returns (address) { return onChainAddress; } /// @notice Returns the chain slug on which the contract is deployed. /// @return chain slug - function getChainSlug() external view returns (uint32) { + function getChainSlug() external view override returns (uint32) { return chainSlug; } @@ -67,16 +68,17 @@ contract Forwarder is ForwarderStorage, Initializable, AddressResolverUtil { } // validates if the async modifier is set - bool isAsyncModifierSet = IAppGateway(msg.sender).isAsyncModifierSet(); + address msgSender = msg.sender; + bool isAsyncModifierSet = IAppGateway(msgSender).isAsyncModifierSet(); if (!isAsyncModifierSet) revert AsyncModifierNotSet(); // fetch the override params from app gateway - (OverrideParams overrideParams, bytes32 sbType) = IAppGateway(msg.sender) + (OverrideParams memory overrideParams, bytes32 sbType) = IAppGateway(msgSender) .getOverrideParams(); // Queue the call in the middleware. watcher__().queue( - QueuePayloadParams({ + QueueParams({ overrideParams: overrideParams, transaction: Transaction({ chainSlug: chainSlug, @@ -86,7 +88,7 @@ contract Forwarder is ForwarderStorage, Initializable, AddressResolverUtil { asyncPromise: address(0), switchboardType: sbType }), - latestPromiseCaller + msgSender ); } } diff --git a/contracts/evmx/interfaces/IAddressResolver.sol b/contracts/evmx/interfaces/IAddressResolver.sol index 52b7250f..9c226dbf 100644 --- a/contracts/evmx/interfaces/IAddressResolver.sol +++ b/contracts/evmx/interfaces/IAddressResolver.sol @@ -13,6 +13,14 @@ interface IAddressResolver { event FeesManagerUpdated(address feesManager_); /// @notice Event emitted when the watcher precompile is updated event WatcherUpdated(address watcher_); + /// @notice Event emitted when the async deployer is updated + event AsyncDeployerUpdated(address asyncDeployer_); + /// @notice Event emitted when the default auction manager is updated + event DefaultAuctionManagerUpdated(address defaultAuctionManager_); + /// @notice Event emitted when the deploy forwarder is updated + event DeployForwarderUpdated(address deployForwarder_); + /// @notice Event emitted when the contract address is updated + event ContractAddressUpdated(bytes32 contractId_, address contractAddress_); // System component addresses function watcher__() external view returns (IWatcher); @@ -25,11 +33,17 @@ interface IAddressResolver { function deployForwarder__() external view returns (IDeployForwarder); + function contractAddresses(bytes32 contractId_) external view returns (address); + + function setWatcher(address watcher_) external; + function setFeesManager(address feesManager_) external; + function setAsyncDeployer(address asyncDeployer_) external; + function setDefaultAuctionManager(address defaultAuctionManager_) external; - function setWatcher(address watcher_) external; + function setDeployForwarder(address deployForwarder_) external; - function setAsyncDeployer(address asyncDeployer_) external; + function setContractAddress(bytes32 contractId_, address contractAddress_) external; } diff --git a/contracts/evmx/interfaces/IAppGateway.sol b/contracts/evmx/interfaces/IAppGateway.sol index f6d3a2a1..6af9b399 100644 --- a/contracts/evmx/interfaces/IAppGateway.sol +++ b/contracts/evmx/interfaces/IAppGateway.sol @@ -21,9 +21,8 @@ interface IAppGateway { function onRequestComplete(uint40 requestCount_, bytes calldata onCompleteData_) external; /// @notice Handles the revert event - /// @param requestCount_ The request count /// @param payloadId_ The payload id - function handleRevert(uint40 requestCount_, bytes32 payloadId_) external; + function handleRevert(bytes32 payloadId_) external; /// @notice initialize the contracts on chain /// @param chainSlug_ The chain slug diff --git a/contracts/evmx/interfaces/IAsyncDeployer.sol b/contracts/evmx/interfaces/IAsyncDeployer.sol index 9e9fad28..e2c99c45 100644 --- a/contracts/evmx/interfaces/IAsyncDeployer.sol +++ b/contracts/evmx/interfaces/IAsyncDeployer.sol @@ -22,7 +22,6 @@ interface IAsyncDeployer { // Forwarder Management function getOrDeployForwarderContract( - address appGateway_, address chainContractAddress_, uint32 chainSlug_ ) external returns (address); diff --git a/contracts/evmx/interfaces/IAuctionManager.sol b/contracts/evmx/interfaces/IAuctionManager.sol index b9836576..5bacbf3a 100644 --- a/contracts/evmx/interfaces/IAuctionManager.sol +++ b/contracts/evmx/interfaces/IAuctionManager.sol @@ -4,31 +4,38 @@ pragma solidity ^0.8.21; import {QueueParams, OverrideParams, Transaction, Bid, RequestParams} from "../../utils/common/Structs.sol"; interface IAuctionManager { + enum AuctionStatus { + NOT_STARTED, + OPEN, + CLOSED, + RESTARTED, + EXPIRED + } + /// @notice Bids for an auction /// @param requestCount_ The request count - /// @param fee_ The fee - /// @param transmitterSignature_ The transmitter signature - /// @param extraData_ The extra data + /// @param bidFees The bid amount + /// @param transmitterSignature The signature of the transmitter + /// @param extraData The extra data function bid( uint40 requestCount_, - uint256 fee_, - address scheduleFees_, - bytes memory transmitterSignature_, - bytes memory extraData_ + uint256 bidFees, + bytes memory transmitterSignature, + bytes memory extraData ) external; /// @notice Ends an auction /// @param requestCount_ The request count - /// @param scheduleFees_ The schedule fees - function endAuction(uint40 requestCount_, uint256 scheduleFees_) external; + function endAuction(uint40 requestCount_) external; + + /// @notice Expires a bid and restarts an auction in case a request is not fully executed. + /// @dev Auction can be restarted only for `maxReAuctionCount` times. + /// @dev It also unblocks the fees from last transmitter to be assigned to the new winner. + /// @param requestCount_ The request id + function expireBid(uint40 requestCount_) external; /// @notice Checks if an auction is closed /// @param requestCount_ The request count /// @return isClosed_ Whether the auction is closed - function auctionClosed(uint40 requestCount_) external view returns (bool); - - /// @notice Checks if an auction is started - /// @param requestCount_ The request count - /// @return isStarted_ Whether the auction is started - function auctionStarted(uint40 requestCount_) external view returns (bool); + function auctionStatus(uint40 requestCount_) external view returns (AuctionStatus); } diff --git a/contracts/evmx/interfaces/IConfigurations.sol b/contracts/evmx/interfaces/IConfigurations.sol index 91d2aacd..594cdef4 100644 --- a/contracts/evmx/interfaces/IConfigurations.sol +++ b/contracts/evmx/interfaces/IConfigurations.sol @@ -7,12 +7,6 @@ import {AppGatewayConfig, PlugConfig} from "../../utils/common/Structs.sol"; /// @notice Interface for the Watcher Precompile system that handles payload verification and execution /// @dev Defines core functionality for payload processing and promise resolution interface IConfigurations { - struct SocketConfig { - address socket; - address contractFactoryPlug; - address feesPlug; - } - /// @notice Verifies connections between components function verifyConnections( uint32 chainSlug_, @@ -38,7 +32,14 @@ interface IConfigurations { ) external view returns (bytes32, address); /// @notice Maps chain slug to their associated socket - function socketConfigs(uint32 chainSlug) external view returns (SocketConfig memory); + /// @param chainSlug_ The chain slug + /// @return The socket + function socket(uint32 chainSlug_) external view returns (address); + + /// @notice Returns the socket for a given chain slug + /// @param chainSlug_ The chain slug + /// @return The socket + function switchboards(uint32 chainSlug_, bytes32 sbType_) external view returns (address); /// @notice Sets the switchboard for a network function setSwitchboard(uint32 chainSlug_, bytes32 sbType_, address switchboard_) external; @@ -49,7 +50,7 @@ interface IConfigurations { function setPlugConfigs(AppGatewayConfig[] calldata configs_) external; - function setOnChainContracts(uint32 chainSlug_, SocketConfig memory socketConfig_) external; + function setOnChainContracts(uint32 chainSlug_, address socket_) external; /// @notice Sets the core app gateway for the watcher precompile function setCoreAppGateway(address appGateway_) external; diff --git a/contracts/evmx/interfaces/IDeployForwarder.sol b/contracts/evmx/interfaces/IDeployForwarder.sol index f8905a37..c6981590 100644 --- a/contracts/evmx/interfaces/IDeployForwarder.sol +++ b/contracts/evmx/interfaces/IDeployForwarder.sol @@ -27,7 +27,7 @@ interface IDeployForwarder { function deploy( IsPlug isPlug_, uint32 chainSlug_, - bytes calldata initCallData_, - bytes calldata payload_ + bytes memory initCallData_, + bytes memory payload_ ) external; } diff --git a/contracts/evmx/interfaces/IFeesManager.sol b/contracts/evmx/interfaces/IFeesManager.sol index 178101ed..8bcdf802 100644 --- a/contracts/evmx/interfaces/IFeesManager.sol +++ b/contracts/evmx/interfaces/IFeesManager.sol @@ -1,53 +1,47 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; +import {WriteFinality, UserCredits, AppGatewayApprovals, OverrideParams, Transaction, QueueParams, RequestParams} from "../../utils/common/Structs.sol"; interface IFeesManager { - // native to credit - function wrap() external payable; + function deposit( + address depositTo_, + uint32 chainSlug_, + address token_, + uint256 nativeAmount_, + uint256 creditAmount_ + ) external payable; - function unwrap(uint256 amount) external; + function wrap(address receiver_) external payable; - // credits from vault - function depositCredits( - address token, - address from, - uint32 chainSlug, - bytes calldata watcherSignature - ) external payable; + function unwrap(uint256 amount_, address receiver_) external; - function getAvailableCredits(address user) external view returns (uint256); + function getAvailableCredits(address consumeFrom_) external view returns (uint256); - // withdraw credits onchain - // process and release sign, no AM needed, can be used by watcher and transmitter - function withdrawCreditsTo( - uint32 chainSlug, - address to, - uint256 amount, - bool needAuction - ) external; + function isCreditSpendable( + address consumeFrom_, + address spender_, + uint256 amount_ + ) external view returns (bool); - function withdrawNativeTo( - uint32 chainSlug, - address to, - uint256 amount, - bool needAuction - ) external; + function transferCredits(address from_, address to_, uint256 amount_) external; - // Fee settlement - // if addr(0) then settle to original user, onlyWatcher can call - function settleFees(uint40 requestId, address transmitter) external; + function approveAppGateways(AppGatewayApprovals[] calldata params_) external; - // onlyWatcher, request's AM can call - function blockCredits(uint40 requestId, address user, uint256 amount) external; + function approveAppGatewayWithSignature( + bytes memory feeApprovalData_ + ) external returns (address consumeFrom, address spender, bool approval); - // onlyWatcher, request's AM can call - function unblockCredits(uint40 requestId, address user, uint256 amount) external; + function withdrawCredits( + uint32 chainSlug_, + address token_, + uint256 credits_, + uint256 maxFees_, + address receiver_ + ) external; - // msg sender should be user whitelisted app gateway - function deductCredits(address user, uint256 amount) external; + function blockCredits(uint40 requestCount_, address consumeFrom_, uint256 credits_) external; - // whitelist - function whitelistAppGatewayWithSignature(bytes calldata signature) external; + function unblockAndAssignCredits(uint40 requestCount_, address assignTo_) external; - function whitelistAppGateways(address[] calldata appGateways) external; + function unblockCredits(uint40 requestCount_) external; } diff --git a/contracts/evmx/interfaces/IPromise.sol b/contracts/evmx/interfaces/IPromise.sol index 6dd3d05d..651c979d 100644 --- a/contracts/evmx/interfaces/IPromise.sol +++ b/contracts/evmx/interfaces/IPromise.sol @@ -1,24 +1,45 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; +import {AsyncPromiseState} from "../../utils/common/Structs.sol"; + /// @title IPromise interface IPromise { + /// @notice The current state of the async promise. + function state() external view returns (AsyncPromiseState); + + /// @notice The local contract which initiated the async call. + /// @dev The callback will be executed on this address + function localInvoker() external view returns (address); + + /// @notice The request count of the promise + function requestCount() external view returns (uint256); + + /// @notice The flag to check if the promise exceeded the max copy limit + function exceededMaxCopy() external view returns (bool); + + /// @notice The return data of the promise + function returnData() external view returns (bytes memory); + /// @notice Sets the callback selector and data for the promise. /// @param selector_ The function selector for the callback. /// @param data_ The data to be passed to the callback. - /// @return promise_ The address of the current promise - function then(bytes4 selector_, bytes memory data_) external returns (address promise_); + function then(bytes4 selector_, bytes memory data_) external; /// @notice Marks the promise as resolved and executes the callback if set. /// @dev Only callable by the watcher precompile. /// @param returnData_ The data returned from the async payload execution. function markResolved( - uint40 requestCount_, + bool exceededMaxCopy_, bytes32 payloadId_, bytes memory returnData_ ) external returns (bool success); /// @notice Marks the promise as onchain reverting. /// @dev Only callable by the watcher precompile. - function markOnchainRevert(uint40 requestCount_, bytes32 payloadId_) external; + function markOnchainRevert( + bool exceededMaxCopy_, + bytes32 payloadId_, + bytes memory returnData_ + ) external; } diff --git a/contracts/evmx/interfaces/IPromiseResolver.sol b/contracts/evmx/interfaces/IPromiseResolver.sol new file mode 100644 index 00000000..bbe91a00 --- /dev/null +++ b/contracts/evmx/interfaces/IPromiseResolver.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import {PayloadParams, ResolvedPromises} from "../../utils/common/Structs.sol"; + +/// @title IPromiseResolver +/// @notice Interface for resolving async promises +interface IPromiseResolver { + /// @notice Resolves a promise with the given data + /// @param resolvedPromises_ The promises to resolve + function resolvePromises(ResolvedPromises[] memory resolvedPromises_) external; + + /// @notice Rejects a promise with the given reason + /// @param isRevertingOnchain_ Whether the promise is reverting onchain + /// @param payloadId_ The ID of the promise to reject + function markRevert(bool isRevertingOnchain_, bytes32 payloadId_) external; +} diff --git a/contracts/evmx/interfaces/IRequestHandler.sol b/contracts/evmx/interfaces/IRequestHandler.sol new file mode 100644 index 00000000..decc01b2 --- /dev/null +++ b/contracts/evmx/interfaces/IRequestHandler.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import "../../utils/common/Structs.sol"; +import "../interfaces/IPrecompile.sol"; + +interface IRequestHandler { + function setPrecompile(bytes4 callType_, IPrecompile precompile_) external; + + function submitRequest( + uint256 maxFees_, + address auctionManager_, + address consumeFrom_, + address appGateway_, + QueueParams[] calldata queuePayloadParams_, + bytes memory onCompleteData_ + ) external returns (uint40 requestCount, address[] memory promiseList); + + function assignTransmitter(uint40 requestCount_, Bid memory bid_) external; + + function updateRequestAndProcessBatch(uint40 requestCount_, bytes32 payloadId_) external; + + function cancelRequest(uint40 requestCount) external; + + function handleRevert(uint40 requestCount) external; + + function increaseFees(uint40 requestCount_, uint256 newMaxFees_) external; +} diff --git a/contracts/evmx/interfaces/IWatcher.sol b/contracts/evmx/interfaces/IWatcher.sol index 621b0fce..1888b599 100644 --- a/contracts/evmx/interfaces/IWatcher.sol +++ b/contracts/evmx/interfaces/IWatcher.sol @@ -1,7 +1,12 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; import {InvalidCallerTriggered, TimeoutAlreadyResolved, ResolvingTimeoutTooEarly, CallFailed, AppGatewayAlreadyCalled, InvalidWatcherSignature, NonceUsed} from "../../utils/common/Errors.sol"; -import {Bid, ResolvedPromises, AppGatewayConfig, WriteFinality, PlugConfig, DigestParams, QueueParams, PayloadParams, RequestParams} from "../../utils/common/Structs.sol"; +import {Bid, ResolvedPromises, AppGatewayConfig, WriteFinality, PlugConfig, DigestParams, QueueParams, PayloadParams, RequestParams, WatcherMultiCallParams} from "../../utils/common/Structs.sol"; + +import "./IRequestHandler.sol"; +import "./IConfigurations.sol"; +import "./IPromiseResolver.sol"; +import "./IAddressResolver.sol"; /// @title IWatcher /// @notice Interface for the Watcher Precompile system that handles payload verification and execution @@ -15,134 +20,56 @@ interface IWatcher { /// @param triggerId The unique identifier for the trigger event AppGatewayCallFailed(bytes32 triggerId); - /// @notice Emitted when a proof upload request is made - event WriteProofRequested(bytes32 digest, PayloadParams params); - - /// @notice Emitted when a proof is uploaded - /// @param payloadId The unique identifier for the request - /// @param proof The proof from the watcher - event WriteProofUploaded(bytes32 indexed payloadId, bytes proof); - - /// @notice Emitted when a promise is resolved - /// @param payloadId The unique identifier for the resolved promise - event PromiseResolved(bytes32 indexed payloadId, address asyncPromise); - - /// @notice Emitted when a promise is not resolved - /// @param payloadId The unique identifier for the not resolved promise - event PromiseNotResolved(bytes32 indexed payloadId, address asyncPromise); - - /// @notice Emitted when a payload is marked as revert - /// @param payloadId The unique identifier for the payload - /// @param isRevertingOnchain Whether the payload is reverting onchain - event MarkedRevert(bytes32 indexed payloadId, bool isRevertingOnchain); - - /// @notice Emitted when a timeout is requested - /// @param timeoutId The unique identifier for the timeout - /// @param target The target address for the timeout callback - /// @param payload The payload data - /// @param executeAt The epoch time when the task should execute - event TimeoutRequested(bytes32 timeoutId, address target, bytes payload, uint256 executeAt); - - /// @notice Emitted when a timeout is resolved - /// @param timeoutId The unique identifier for the timeout - /// @param target The target address for the callback - /// @param payload The payload data - /// @param executedAt The epoch time when the task was executed - /// @param returnData The return data from the callback - event TimeoutResolved( - bytes32 timeoutId, - address target, - bytes payload, - uint256 executedAt, - bytes returnData - ); - - event RequestSubmitted( - bool hasWrite, - uint40 requestCount, - RequestParams requestParams, - PayloadParams[] payloadParamsArray - ); - - event MaxTimeoutDelayInSecondsSet(uint256 maxTimeoutDelayInSeconds); - - event ExpiryTimeSet(uint256 expiryTime); - - event WatcherPrecompileLimitsSet(address watcherPrecompileLimits); - - event configurations__Set(address configurations__); - - event RequestCancelledFromGateway(uint40 requestCount); - - /// @notice Error thrown when an invalid chain slug is provided - error InvalidChainSlug(); - /// @notice Error thrown when an invalid app gateway reaches a plug - error InvalidConnection(); - /// @notice Error thrown when a timeout request is invalid - error InvalidTimeoutRequest(); - /// @notice Error thrown when a payload id is invalid - error InvalidPayloadId(); - /// @notice Error thrown when a caller is invalid - error InvalidCaller(); - /// @notice Error thrown when a gateway is invalid - error InvalidGateway(); - /// @notice Error thrown when a switchboard is invalid - error InvalidSwitchboard(); - /// @notice Error thrown when a request is already cancelled - error RequestAlreadyCancelled(); - - error RequestCancelled(); - error AlreadyStarted(); - error RequestNotProcessing(); - error InvalidLevelNumber(); - error DeadlineNotPassedForOnChainRevert(); - - function queueSubmitStart(QueueParams calldata queuePayloadParams_) external; - - function queue(QueueParams calldata queuePayloadParams_) external; - - /// @notice Clears the temporary queue used to store payloads for a request - function clearQueue() external; + function requestHandler__() external view returns (IRequestHandler); - function submitRequest( - uint256 maxFees, - address auctionManager, - address consumeFrom, - bytes calldata onCompleteData - ) external returns (uint40 requestCount); - - function assignTransmitter(uint40 requestCount, Bid memory bid_) external; - - // _processBatch(); - // prev digest hash create - // create digest, deadline + function configurations__() external view returns (IConfigurations); - // handlePayload: - // emit relevant events + function promiseResolver__() external view returns (IPromiseResolver); - function _validateProcessBatch() external; + function addressResolver__() external view returns (IAddressResolver); - function _settleRequest(uint40 requestCount) external; + /// @notice Returns the request params for a given request count + /// @param requestCount_ The request count + /// @return The request params + function getRequestParams(uint40 requestCount_) external view returns (RequestParams memory); - function markPayloadResolved(uint40 requestCount, RequestParams memory requestParams) external; - - // update RequestTrackingParams - // if(_validateProcessBatch() == true) processBatch() + /// @notice Returns the current request count + /// @return The current request count + function getCurrentRequestCount() external view returns (uint40); - /// @notice Increases the fees for a request - /// @param requestCount_ The request id - /// @param fees_ The new fees - function increaseFees(uint40 requestCount_, uint256 fees_) external; + /// @notice Returns the latest async promise deployed for a payload queued + /// @return The latest async promise + function latestAsyncPromise() external view returns (address); - function uploadProof(bytes32 payloadId_, bytes calldata proof_) external; + /// @notice Queues a payload for execution + /// @param queuePayloadParams_ The parameters for the payload + function queue(QueueParams calldata queuePayloadParams_, address appGateway_) external; - function cancelRequest(uint40 requestCount) external; + /// @notice Clears the queue of payloads + function clearQueue() external; - // settleFees on FM + function submitRequest( + uint256 maxFees, + address auctionManager, + address consumeFrom, + bytes calldata onCompleteData + ) external returns (uint40 requestCount, address[] memory promises); - function getMaxFees(uint40 requestCount) external view returns (uint256); + function queueAndSubmit( + QueueParams memory queue_, + uint256 maxFees, + address auctionManager, + address consumeFrom, + bytes calldata onCompleteData + ) external returns (uint40 requestCount, address[] memory promises); - function getCurrentRequestCount() external view returns (uint40); + /// @notice Assigns a transmitter to a request + /// @param requestCount_ The request count + /// @param bid_ The bid + function assignTransmitter(uint40 requestCount_, Bid memory bid_) external; - function getRequestParams(uint40 requestCount) external view returns (RequestParams memory); + /// @notice Returns the precompile fees for a given precompile + /// @param precompile_ The precompile + /// @return The precompile fees + function getPrecompileFees(bytes4 precompile_) external view returns (uint256); } diff --git a/contracts/protocol/Socket.sol b/contracts/protocol/Socket.sol index 259e08d9..0bbe472a 100644 --- a/contracts/protocol/Socket.sol +++ b/contracts/protocol/Socket.sol @@ -38,10 +38,6 @@ contract Socket is SocketUtils { * @dev Error emitted when less gas limit is provided for execution than expected */ error LowGasLimit(); - /** - * @dev Error emitted when the chain slug is invalid - */ - error InvalidSlug(); /** * @dev Error emitted when the deadline has passed */ diff --git a/contracts/protocol/SocketConfig.sol b/contracts/protocol/SocketConfig.sol index 79e72105..19811c07 100644 --- a/contracts/protocol/SocketConfig.sol +++ b/contracts/protocol/SocketConfig.sol @@ -8,7 +8,7 @@ import "./interfaces/ISocketFeeManager.sol"; import "../utils/AccessControl.sol"; import {GOVERNANCE_ROLE, RESCUE_ROLE, SWITCHBOARD_DISABLER_ROLE} from "../utils/common/AccessRoles.sol"; import {PlugConfig, SwitchboardStatus, ExecutionStatus} from "../utils/common/Structs.sol"; -import {PlugNotFound, InvalidAppGateway, InvalidTransmitter} from "../utils/common/Errors.sol"; +import {PlugNotFound, InvalidAppGateway, InvalidTransmitter, InvalidSwitchboard} from "../utils/common/Errors.sol"; import {MAX_COPY_BYTES} from "../utils/common/Constants.sol"; /** @@ -30,10 +30,6 @@ abstract contract SocketConfig is ISocket, AccessControl { // @notice max copy bytes for socket uint16 public maxCopyBytes = 2048; // 2KB - // @notice error triggered when a connection is invalid - error InvalidConnection(); - // @notice error triggered when a switchboard is invalid - error InvalidSwitchboard(); // @notice error triggered when a switchboard already exists error SwitchboardExists(); // @notice error triggered when a switchboard already exists or is disabled diff --git a/contracts/protocol/base/PlugBase.sol b/contracts/protocol/base/PlugBase.sol index 21d22417..3bd4c160 100644 --- a/contracts/protocol/base/PlugBase.sol +++ b/contracts/protocol/base/PlugBase.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.21; import {ISocket} from "../interfaces/ISocket.sol"; import {IPlug} from "../interfaces/IPlug.sol"; -import {NotSocket} from "../../utils/common/Errors.sol"; +import {NotSocket, SocketAlreadyInitialized} from "../../utils/common/Errors.sol"; /// @title PlugBase /// @notice Abstract contract for plugs @@ -14,7 +14,6 @@ abstract contract PlugBase is IPlug { uint256 public isSocketInitialized; bytes public overrides; - error SocketAlreadyInitialized(); event ConnectorPlugDisconnected(); /// @notice Modifier to ensure only the socket can call the function diff --git a/contracts/utils/common/Errors.sol b/contracts/utils/common/Errors.sol index bf981a4b..79eae259 100644 --- a/contracts/utils/common/Errors.sol +++ b/contracts/utils/common/Errors.sol @@ -4,6 +4,8 @@ pragma solidity ^0.8.21; error ZeroAddress(); error InvalidTransmitter(); error InvalidTokenAddress(); +error InvalidSwitchboard(); +error SocketAlreadyInitialized(); // Socket error NotSocket(); @@ -23,6 +25,7 @@ error AsyncModifierNotSet(); error WatcherNotSet(); error InvalidTarget(); error InvalidIndex(); +error InvalidChainSlug(); error InvalidPayloadSize(); error InvalidScheduleDelay(); error InvalidTimeoutRequest(); @@ -40,3 +43,28 @@ error RequestCountMismatch(); error InvalidAmount(); error InsufficientCreditsAvailable(); error InsufficientBalance(); +/// @notice Error thrown when a caller is invalid +error InvalidCaller(); + +/// @notice Error thrown when a gateway is invalid +error InvalidGateway(); +/// @notice Error thrown when a request is already cancelled +error RequestAlreadyCancelled(); +error RequestCancelled(); +error DeadlineNotPassedForOnChainRevert(); + +error InvalidBid(); +error MaxReAuctionCountReached(); +error MaxMsgValueLimitExceeded(); +/// @notice Error thrown when an invalid address attempts to call the Watcher only function +error OnlyWatcherAllowed(); +error InvalidPrecompileData(); +error InvalidCallType(); +error NotRequestHandler(); +error NotInvoker(); +error NotPromiseResolver(); +error RequestPayloadCountLimitExceeded(); +error InsufficientFees(); +error RequestAlreadySettled(); +error NoWriteRequest(); +error AlreadyAssigned(); diff --git a/contracts/utils/common/Structs.sol b/contracts/utils/common/Structs.sol index 4eb41af4..71b2f0a7 100644 --- a/contracts/utils/common/Structs.sol +++ b/contracts/utils/common/Structs.sol @@ -106,6 +106,13 @@ struct UserCredits { uint256 blockedCredits; } +struct WatcherMultiCallParams { + address contracts; + bytes data_; + uint256 nonces_; + bytes signatures_; +} + // digest: struct DigestParams { address socket; @@ -155,6 +162,7 @@ struct PayloadParams { address appGateway; bytes32 payloadId; uint256 resolvedAt; + uint256 deadline; bytes precompileData; } From 140c48da2a60f14a10a02e68bb2b3b4d991a7522 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Fri, 23 May 2025 00:58:36 +0530 Subject: [PATCH 044/130] fix: build --- contracts/evmx/AuctionManager.sol | 17 ++- contracts/evmx/fees/Credit.sol | 36 +++-- contracts/evmx/fees/FeesManager.sol | 17 ++- contracts/evmx/interfaces/IConfigurations.sol | 7 +- contracts/evmx/interfaces/IFeesPlug.sol | 18 ++- contracts/evmx/interfaces/IPrecompile.sol | 16 +- .../evmx/interfaces/IPromiseResolver.sol | 13 +- contracts/evmx/interfaces/IRequestHandler.sol | 16 +- contracts/evmx/interfaces/IWatcher.sol | 30 ++-- contracts/evmx/plugs/ContractFactoryPlug.sol | 2 +- contracts/evmx/plugs/FeesPlug.sol | 14 -- contracts/evmx/watcher/Configurations.sol | 57 +++---- contracts/evmx/watcher/PromiseResolver.sol | 66 ++++---- contracts/evmx/watcher/RequestHandler.sol | 142 ++++++++++-------- contracts/evmx/watcher/Trigger.sol | 12 +- contracts/evmx/watcher/Watcher.sol | 94 ++++++------ contracts/evmx/watcher/WatcherBase.sol | 44 ++++-- contracts/evmx/watcher/WatcherStorage.sol | 9 +- .../watcher/precompiles/ReadPrecompile.sol | 39 +++-- .../precompiles/SchedulePrecompile.sol | 50 +++++- .../watcher/precompiles/WritePrecompile.sol | 93 ++++++++---- contracts/utils/common/Errors.sol | 8 +- contracts/utils/common/IdUtils.sol | 4 + contracts/utils/common/Structs.sol | 3 +- foundry.toml | 2 +- 25 files changed, 491 insertions(+), 318 deletions(-) diff --git a/contracts/evmx/AuctionManager.sol b/contracts/evmx/AuctionManager.sol index d34cadc1..96091d27 100644 --- a/contracts/evmx/AuctionManager.sol +++ b/contracts/evmx/AuctionManager.sol @@ -129,7 +129,8 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, transmitter, winningBids[requestCount_].transmitter == address(0) ? address(this) - : winningBids[requestCount_].transmitter + : winningBids[requestCount_].transmitter, + auctionEndDelaySeconds ), address(this), abi.encodeWithSelector(this.endAuction.selector, requestCount_) @@ -168,13 +169,13 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, // useful in case a transmitter did bid but did not execute payloads _createRequest( bidTimeout, - deductScheduleFees(winningBid.transmitter, address(this)), + deductScheduleFees(winningBid.transmitter, address(this), bidTimeout), winningBid.transmitter, abi.encodeWithSelector(this.expireBid.selector, requestCount_) ); // start the request processing, it will queue the request - watcher__().assignTransmitter(requestCount_, winningBid); + watcher__().requestHandler__().assignTransmitter(requestCount_, winningBid); } emit AuctionEnded(requestCount_, winningBid); @@ -198,7 +199,7 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, auctionStatus[requestCount_] = AuctionStatus.RESTARTED; reAuctionCount[requestCount_]++; - watcher__().assignTransmitter( + watcher__().requestHandler__().assignTransmitter( requestCount_, Bid({fee: 0, transmitter: address(0), extraData: ""}) ); @@ -240,8 +241,12 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, return requestParams.requestFeesDetails.maxFees; } - function deductScheduleFees(address from_, address to_) internal returns (uint256 watcherFees) { - watcherFees = watcher__().getPrecompileFees(SCHEDULE); + function deductScheduleFees( + address from_, + address to_, + uint256 delayInSeconds_ + ) internal returns (uint256 watcherFees) { + watcherFees = watcher__().getPrecompileFees(SCHEDULE, abi.encode(delayInSeconds_)); feesManager__().transferCredits(from_, to_, watcherFees); } diff --git a/contracts/evmx/fees/Credit.sol b/contracts/evmx/fees/Credit.sol index abfd940a..ad524156 100644 --- a/contracts/evmx/fees/Credit.sol +++ b/contracts/evmx/fees/Credit.sol @@ -6,16 +6,17 @@ import "solady/utils/Initializable.sol"; import "solady/utils/ECDSA.sol"; import "../interfaces/IFeesManager.sol"; import "../interfaces/IFeesPlug.sol"; -import "../watcher/WatcherBase.sol"; import {AddressResolverUtil} from "../helpers/AddressResolverUtil.sol"; -import {NonceUsed, InvalidAmount, InsufficientCreditsAvailable, InsufficientBalance} from "../../utils/common/Errors.sol"; -import {WriteFinality, UserCredits, AppGatewayApprovals, OverrideParams} from "../../utils/common/Structs.sol"; +import {NonceUsed, InvalidAmount, InsufficientCreditsAvailable, InsufficientBalance, InvalidChainSlug, NotRequestHandler} from "../../utils/common/Errors.sol"; import {WRITE} from "../../utils/common/Constants.sol"; -abstract contract FeesManagerStorage is IFeesManager, WatcherBase { +abstract contract FeesManagerStorage is IFeesManager { /// @notice evmx slug uint32 public evmxSlug; + /// @notice switchboard type + bytes32 public sbType; + /// @notice user credits => stores fees for user, app gateway, transmitters and watcher precompile mapping(address => UserCredits) public userCredits; @@ -35,6 +36,10 @@ abstract contract FeesManagerStorage is IFeesManager, WatcherBase { /// @dev address => signatureNonce => isNonceUsed /// @dev used by watchers or other users in signatures mapping(address => mapping(uint256 => bool)) public isNonceUsed; + + /// @notice Mapping to track fees plug for each chain slug + /// @dev chainSlug => fees plug address + mapping(uint32 => address) public feesPlugs; } /// @title UserUtils @@ -73,19 +78,21 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressR address token_, uint256 nativeAmount_, uint256 creditAmount_ - ) external payable onlyWatcher { + ) external payable override onlyWatcher { if (creditAmount_ + nativeAmount_ != msg.value) revert InvalidAmount(); tokenOnChainBalances[chainSlug_][token_] += nativeAmount_ + creditAmount_; UserCredits storage userCredit = userCredits[depositTo_]; userCredit.totalCredits += creditAmount_; + + // try catch: if native transfer fails, add to credit payable(depositTo_).transfer(nativeAmount_); emit CreditsDeposited(chainSlug_, depositTo_, token_, creditAmount_); } // todo: add safe eth transfer - function wrap(address receiver_) external payable { + function wrap(address receiver_) external payable override { UserCredits storage userCredit = userCredits[receiver_]; userCredit.totalCredits += msg.value; emit CreditsWrapped(receiver_, msg.value); @@ -105,7 +112,7 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressR /// @notice Returns available (unblocked) credits for a gateway /// @param consumeFrom_ The app gateway address /// @return The available credit amount - function getAvailableCredits(address consumeFrom_) public view returns (uint256) { + function getAvailableCredits(address consumeFrom_) public view override returns (uint256) { UserCredits memory userCredit = userCredits[consumeFrom_]; return userCredit.totalCredits - userCredit.blockedCredits; } @@ -119,7 +126,7 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressR address consumeFrom_, address spender_, uint256 amount_ - ) public view returns (bool) { + ) public view override returns (bool) { // If consumeFrom_ is not same as spender_ or spender_ is not watcher, check if it is approved if (spender_ != address(watcher__()) && consumeFrom_ != spender_) { if (!isApproved[consumeFrom_][spender_]) return false; @@ -128,7 +135,7 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressR return getAvailableCredits(consumeFrom_) >= amount_; } - function transferCredits(address from_, address to_, uint256 amount_) external { + function transferCredits(address from_, address to_, uint256 amount_) external override { if (!isCreditSpendable(from_, msg.sender, amount_)) revert InsufficientCreditsAvailable(); userCredits[from_].totalCredits -= amount_; userCredits[to_].totalCredits += amount_; @@ -138,7 +145,7 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressR /// @notice Approves multiple app gateways for the caller /// @param params_ Array of app gateway addresses to approve - function approveAppGateways(AppGatewayApprovals[] calldata params_) external { + function approveAppGateways(AppGatewayApprovals[] calldata params_) external override { for (uint256 i = 0; i < params_.length; i++) { isApproved[msg.sender][params_[i].appGateway] = params_[i].approval; } @@ -157,7 +164,7 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressR bytes memory signature_; (spender, approval, nonce, signature_) = abi.decode( feeApprovalData_, - (address, address, bool, uint256, bytes) + (address, bool, uint256, bytes) ); bytes32 digest = keccak256(abi.encode(address(this), evmxSlug, spender, nonce, approval)); consumeFrom = _recoverSigner(digest, signature_); @@ -182,8 +189,8 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressR uint256 credits_, uint256 maxFees_, address receiver_ - ) public { - address consumeFrom = _getCoreAppGateway(msg.sender); + ) public override { + address consumeFrom = getCoreAppGateway(msg.sender); // Check if amount is available in fees plug uint256 availableCredits = getAvailableCredits(consumeFrom); @@ -225,7 +232,8 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressR } function _getFeesPlugAddress(uint32 chainSlug_) internal view returns (address) { - return configuration__().feesPlug(chainSlug_); + if (feesPlugs[chainSlug_] == address(0)) revert InvalidChainSlug(); + return feesPlugs[chainSlug_]; } function _getRequestParams(uint40 requestCount_) internal view returns (RequestParams memory) { diff --git a/contracts/evmx/fees/FeesManager.sol b/contracts/evmx/fees/FeesManager.sol index e6e2d9ff..1a60e43a 100644 --- a/contracts/evmx/fees/FeesManager.sol +++ b/contracts/evmx/fees/FeesManager.sol @@ -25,10 +25,12 @@ abstract contract FeesManager is Credit { /// @notice Emitted when fees are unblocked and assigned to a transmitter /// @param requestCount The batch identifier + /// @param consumeFrom The consume from address /// @param transmitter The transmitter address /// @param amount The unblocked amount event CreditsUnblockedAndAssigned( uint40 indexed requestCount, + address indexed consumeFrom, address indexed transmitter, uint256 amount ); @@ -45,6 +47,11 @@ abstract contract FeesManager is Credit { address consumeFrom ); + modifier onlyRequestHandler() { + if (msg.sender != address(watcher__().requestHandler__())) revert NotRequestHandler(); + _; + } + constructor() { _disableInitializers(); // disable for implementation } @@ -76,13 +83,13 @@ abstract contract FeesManager is Credit { uint40 requestCount_, address consumeFrom_, uint256 credits_ - ) external onlyRequestHandler { - if (getAvailableCredits(consumeFrom) < credits_) revert InsufficientCreditsAvailable(); + ) external override onlyRequestHandler { + if (getAvailableCredits(consumeFrom_) < credits_) revert InsufficientCreditsAvailable(); - UserCredits storage userCredit = userCredits[consumeFrom]; + UserCredits storage userCredit = userCredits[consumeFrom_]; userCredit.blockedCredits += credits_; requestBlockedCredits[requestCount_] = credits_; - emit CreditsBlocked(requestCount_, consumeFrom, credits_); + emit CreditsBlocked(requestCount_, consumeFrom_, credits_); } /// @notice Unblocks fees after successful execution and assigns them to the transmitter @@ -109,7 +116,7 @@ abstract contract FeesManager is Credit { emit CreditsUnblockedAndAssigned(requestCount_, consumeFrom, assignTo_, blockedCredits); } - function unblockCredits(uint40 requestCount_) external onlyRequestHandler { + function unblockCredits(uint40 requestCount_) external override onlyRequestHandler { uint256 blockedCredits = requestBlockedCredits[requestCount_]; if (blockedCredits == 0) return; diff --git a/contracts/evmx/interfaces/IConfigurations.sol b/contracts/evmx/interfaces/IConfigurations.sol index 594cdef4..abde9755 100644 --- a/contracts/evmx/interfaces/IConfigurations.sol +++ b/contracts/evmx/interfaces/IConfigurations.sol @@ -12,7 +12,7 @@ interface IConfigurations { uint32 chainSlug_, address target_, address appGateway_, - address switchboard_ + bytes32 switchboardType_ ) external view; /// @notice Maps contract address to their associated app gateway @@ -34,7 +34,7 @@ interface IConfigurations { /// @notice Maps chain slug to their associated socket /// @param chainSlug_ The chain slug /// @return The socket - function socket(uint32 chainSlug_) external view returns (address); + function sockets(uint32 chainSlug_) external view returns (address); /// @notice Returns the socket for a given chain slug /// @param chainSlug_ The chain slug @@ -50,7 +50,8 @@ interface IConfigurations { function setPlugConfigs(AppGatewayConfig[] calldata configs_) external; - function setOnChainContracts(uint32 chainSlug_, address socket_) external; + /// @notice Sets the socket for a chain slug + function setSocket(uint32 chainSlug_, address socket_) external; /// @notice Sets the core app gateway for the watcher precompile function setCoreAppGateway(address appGateway_) external; diff --git a/contracts/evmx/interfaces/IFeesPlug.sol b/contracts/evmx/interfaces/IFeesPlug.sol index 46797d62..24cc719a 100644 --- a/contracts/evmx/interfaces/IFeesPlug.sol +++ b/contracts/evmx/interfaces/IFeesPlug.sol @@ -2,9 +2,23 @@ pragma solidity ^0.8.21; interface IFeesPlug { - function depositToFee(address token_, address receiver_, uint256 amount_) external; + /// @notice Event emitted when fees are deposited + event FeesDeposited( + address token, + address receiver, + uint256 creditAmount, + uint256 nativeAmount + ); + /// @notice Event emitted when fees are withdrawn + event FeesWithdrawn(address token, address receiver, uint256 amount); + /// @notice Event emitted when a token is whitelisted + event TokenWhitelisted(address token); + /// @notice Event emitted when a token is removed from whitelist + event TokenRemovedFromWhitelist(address token); - function depositToFeeAndNative(address token_, address receiver_, uint256 amount_) external; + function depositCredit(address token_, address receiver_, uint256 amount_) external; + + function depositCreditAndNative(address token_, address receiver_, uint256 amount_) external; function depositToNative(address token_, address receiver_, uint256 amount_) external; diff --git a/contracts/evmx/interfaces/IPrecompile.sol b/contracts/evmx/interfaces/IPrecompile.sol index 61a17324..929059f3 100644 --- a/contracts/evmx/interfaces/IPrecompile.sol +++ b/contracts/evmx/interfaces/IPrecompile.sol @@ -7,23 +7,25 @@ import {QueueParams, PayloadParams} from "../../utils/common/Structs.sol"; /// @notice Interface for precompile functionality interface IPrecompile { /// @notice Gets precompile data and fees for queue parameters - /// @param queuePayloadParams_ The queue parameters to process + /// @param queueParams_ The queue parameters to process /// @return precompileData The encoded precompile data - /// @return fees Estimated fees required for processing - function getPrecompileData( - QueueParams calldata queuePayloadParams_ - ) external returns (bytes memory precompileData, uint256 fees); + /// @return estimatedFees Estimated fees required for processing + function validateAndGetPrecompileData( + QueueParams calldata queueParams_, + address appGateway_ + ) external view returns (bytes memory precompileData, uint256 estimatedFees); /// @notice Handles payload processing and returns fees + /// @param transmitter The address of the transmitter /// @param payloadParams The payload parameters to handle /// @return fees The fees required for processing /// @return deadline The deadline for processing function handlePayload( + address transmitter, PayloadParams calldata payloadParams ) external returns (uint256 fees, uint256 deadline); /// @notice Resolves a payload /// @param payloadParams The payload parameters to resolve - /// @return fees The fees required for processing - function resolvePayload(PayloadParams calldata payloadParams) external returns (uint256 fees); + function resolvePayload(PayloadParams calldata payloadParams) external; } diff --git a/contracts/evmx/interfaces/IPromiseResolver.sol b/contracts/evmx/interfaces/IPromiseResolver.sol index bbe91a00..0834bf90 100644 --- a/contracts/evmx/interfaces/IPromiseResolver.sol +++ b/contracts/evmx/interfaces/IPromiseResolver.sol @@ -1,17 +1,20 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import {PayloadParams, ResolvedPromises} from "../../utils/common/Structs.sol"; +import {PayloadParams, PromiseReturnData} from "../../utils/common/Structs.sol"; /// @title IPromiseResolver /// @notice Interface for resolving async promises interface IPromiseResolver { /// @notice Resolves a promise with the given data - /// @param resolvedPromises_ The promises to resolve - function resolvePromises(ResolvedPromises[] memory resolvedPromises_) external; + /// @param promiseReturnData_ The promises to resolve + function resolvePromises(PromiseReturnData[] memory promiseReturnData_) external; /// @notice Rejects a promise with the given reason /// @param isRevertingOnchain_ Whether the promise is reverting onchain - /// @param payloadId_ The ID of the promise to reject - function markRevert(bool isRevertingOnchain_, bytes32 payloadId_) external; + /// @param resolvedPromise_ The resolved promise + function markRevert( + PromiseReturnData memory resolvedPromise_, + bool isRevertingOnchain_ + ) external; } diff --git a/contracts/evmx/interfaces/IRequestHandler.sol b/contracts/evmx/interfaces/IRequestHandler.sol index decc01b2..84ad6092 100644 --- a/contracts/evmx/interfaces/IRequestHandler.sol +++ b/contracts/evmx/interfaces/IRequestHandler.sol @@ -5,6 +5,18 @@ import "../../utils/common/Structs.sol"; import "../interfaces/IPrecompile.sol"; interface IRequestHandler { + function requestBatchIds(uint40 batchCount_) external view returns (uint40[] memory); + + function batchPayloadIds(uint40 batchCount_) external view returns (bytes32[] memory); + + function requests(uint40 requestCount_) external view returns (RequestParams memory); + + function payloads(bytes32 payloadId_) external view returns (PayloadParams memory); + + function getPrecompileFees(bytes4 precompile_, bytes memory precompileData_) external view returns (uint256); + + function nextRequestCount() external view returns (uint40); + function setPrecompile(bytes4 callType_, IPrecompile precompile_) external; function submitRequest( @@ -12,7 +24,7 @@ interface IRequestHandler { address auctionManager_, address consumeFrom_, address appGateway_, - QueueParams[] calldata queuePayloadParams_, + QueueParams[] calldata queueParams_, bytes memory onCompleteData_ ) external returns (uint40 requestCount, address[] memory promiseList); @@ -20,6 +32,8 @@ interface IRequestHandler { function updateRequestAndProcessBatch(uint40 requestCount_, bytes32 payloadId_) external; + function cancelRequestForReverts(uint40 requestCount) external; + function cancelRequest(uint40 requestCount) external; function handleRevert(uint40 requestCount) external; diff --git a/contracts/evmx/interfaces/IWatcher.sol b/contracts/evmx/interfaces/IWatcher.sol index 1888b599..5ef1b426 100644 --- a/contracts/evmx/interfaces/IWatcher.sol +++ b/contracts/evmx/interfaces/IWatcher.sol @@ -1,12 +1,11 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import {InvalidCallerTriggered, TimeoutAlreadyResolved, ResolvingTimeoutTooEarly, CallFailed, AppGatewayAlreadyCalled, InvalidWatcherSignature, NonceUsed} from "../../utils/common/Errors.sol"; -import {Bid, ResolvedPromises, AppGatewayConfig, WriteFinality, PlugConfig, DigestParams, QueueParams, PayloadParams, RequestParams, WatcherMultiCallParams} from "../../utils/common/Structs.sol"; +import "../../utils/common/Errors.sol"; +import {Bid, AppGatewayConfig, WriteFinality, PlugConfig, DigestParams, QueueParams, PayloadParams, RequestParams, WatcherMultiCallParams} from "../../utils/common/Structs.sol"; import "./IRequestHandler.sol"; import "./IConfigurations.sol"; import "./IPromiseResolver.sol"; -import "./IAddressResolver.sol"; /// @title IWatcher /// @notice Interface for the Watcher Precompile system that handles payload verification and execution @@ -26,13 +25,16 @@ interface IWatcher { function promiseResolver__() external view returns (IPromiseResolver); - function addressResolver__() external view returns (IAddressResolver); - /// @notice Returns the request params for a given request count /// @param requestCount_ The request count /// @return The request params function getRequestParams(uint40 requestCount_) external view returns (RequestParams memory); + /// @notice Returns the request params for a given request count + /// @param payloadId_ The payload id + /// @return The request params + function getPayloadParams(bytes32 payloadId_) external view returns (PayloadParams memory); + /// @notice Returns the current request count /// @return The current request count function getCurrentRequestCount() external view returns (uint40); @@ -42,8 +44,11 @@ interface IWatcher { function latestAsyncPromise() external view returns (address); /// @notice Queues a payload for execution - /// @param queuePayloadParams_ The parameters for the payload - function queue(QueueParams calldata queuePayloadParams_, address appGateway_) external; + /// @param queueParams_ The parameters for the payload + function queue( + QueueParams calldata queueParams_, + address appGateway_ + ) external returns (address, uint40); /// @notice Clears the queue of payloads function clearQueue() external; @@ -63,13 +68,12 @@ interface IWatcher { bytes calldata onCompleteData ) external returns (uint40 requestCount, address[] memory promises); - /// @notice Assigns a transmitter to a request - /// @param requestCount_ The request count - /// @param bid_ The bid - function assignTransmitter(uint40 requestCount_, Bid memory bid_) external; - /// @notice Returns the precompile fees for a given precompile /// @param precompile_ The precompile + /// @param precompileData_ The precompile data /// @return The precompile fees - function getPrecompileFees(bytes4 precompile_) external view returns (uint256); + function getPrecompileFees( + bytes4 precompile_, + bytes memory precompileData_ + ) external view returns (uint256); } diff --git a/contracts/evmx/plugs/ContractFactoryPlug.sol b/contracts/evmx/plugs/ContractFactoryPlug.sol index f8a5b835..29c8fd64 100644 --- a/contracts/evmx/plugs/ContractFactoryPlug.sol +++ b/contracts/evmx/plugs/ContractFactoryPlug.sol @@ -19,7 +19,7 @@ contract ContractFactoryPlug is PlugBase, AccessControl, IContractFactoryPlug { /// @notice Error thrown if it failed to deploy the create2 contract error DeploymentFailed(); - error ExecutionFailed(); + error ExecutionFailed(bytes32 appGatewayId, bytes returnData); /// @notice Constructor for the ContractFactoryPlug /// @param socket_ The socket address diff --git a/contracts/evmx/plugs/FeesPlug.sol b/contracts/evmx/plugs/FeesPlug.sol index 198b20f7..cc8bde5e 100644 --- a/contracts/evmx/plugs/FeesPlug.sol +++ b/contracts/evmx/plugs/FeesPlug.sol @@ -30,20 +30,6 @@ contract FeesPlug is IFeesPlug, PlugBase, AccessControl { /// @notice Error thrown when token is not whitelisted error TokenNotWhitelisted(address token_); - /// @notice Event emitted when fees are deposited - event FeesDeposited( - address token, - address receiver, - uint256 creditAmount, - uint256 nativeAmount - ); - /// @notice Event emitted when fees are withdrawn - event FeesWithdrawn(address token, address receiver, uint256 amount); - /// @notice Event emitted when a token is whitelisted - event TokenWhitelisted(address token); - /// @notice Event emitted when a token is removed from whitelist - event TokenRemovedFromWhitelist(address token); - /// @notice Constructor for the FeesPlug contract /// @param socket_ The socket address /// @param owner_ The owner address diff --git a/contracts/evmx/watcher/Configurations.sol b/contracts/evmx/watcher/Configurations.sol index 7a315ec9..21c04247 100644 --- a/contracts/evmx/watcher/Configurations.sol +++ b/contracts/evmx/watcher/Configurations.sol @@ -3,13 +3,14 @@ pragma solidity ^0.8.21; import "solady/utils/Initializable.sol"; import "../interfaces/IConfigurations.sol"; -import {AddressResolverUtil} from "../helpers/AddressResolverUtil.sol"; +import {WatcherBase} from "./WatcherBase.sol"; import {encodeAppGatewayId} from "../../utils/common/IdUtils.sol"; +import {InvalidGateway, InvalidSwitchboard} from "../../utils/common/Errors.sol"; /// @title Configurations /// @notice Configuration contract for the Watcher Precompile system /// @dev Handles the mapping between networks, plugs, and app gateways for payload execution -contract Configurations is IConfigurations, Initializable, AddressResolverUtil { +contract Configurations is IConfigurations, Initializable, WatcherBase { // slots 0-50 (51) reserved for addr resolver util // slots [51-100]: gap for future storage variables @@ -32,7 +33,7 @@ contract Configurations is IConfigurations, Initializable, AddressResolverUtil { // slot 105: sockets /// @notice Maps chain slug to their associated socket /// @dev chainSlug => socket address - mapping(uint32 => SocketConfig) public socketConfigs; + mapping(uint32 => address) public sockets; // slot 107: contractsToGateways /// @notice Maps contract address to their associated app gateway @@ -56,17 +57,10 @@ contract Configurations is IConfigurations, Initializable, AddressResolverUtil { /// @param switchboard The address of the switchboard event SwitchboardSet(uint32 chainSlug, bytes32 sbType, address switchboard); - /// @notice Emitted when contracts are set for a network + /// @notice Emitted when socket is set for a network /// @param chainSlug The identifier of the network /// @param socket The address of the socket - /// @param contractFactoryPlug The address of the contract factory plug - /// @param feesPlug The address of the fees plug - event OnChainContractSet( - uint32 chainSlug, - address socket, - address contractFactoryPlug, - address feesPlug - ); + event SocketSet(uint32 chainSlug, address socket); /// @notice Emitted when a valid plug is set for an app gateway /// @param appGateway The address of the app gateway @@ -75,13 +69,12 @@ contract Configurations is IConfigurations, Initializable, AddressResolverUtil { /// @param isValid Whether the plug is valid event IsValidPlugSet(address appGateway, uint32 chainSlug, address plug, bool isValid); - error InvalidGateway(); - error InvalidSwitchboard(); + /// @notice Emitted when a core app gateway is set for an app gateway + /// @param appGateway The address of the app gateway + /// @param coreAppGateway The address of the core app gateway + event CoreAppGatewaySet(address appGateway, address coreAppGateway); - /// @notice Initial initialization (version 1) - function initialize(address addressResolver_) public reinitializer(1) { - _setAddressResolver(addressResolver_); - } + constructor(address watcher_) WatcherBase(watcher_) {} /// @notice Configures app gateways with their respective plugs and switchboards /// @dev Only callable by the watcher @@ -91,28 +84,24 @@ contract Configurations is IConfigurations, Initializable, AddressResolverUtil { for (uint256 i = 0; i < configs_.length; i++) { // Store the plug configuration for this network and plug _plugConfigs[configs_[i].chainSlug][configs_[i].plug] = PlugConfig({ - appGatewayId: configs_[i].appGatewayId, - switchboard: configs_[i].switchboard + appGatewayId: configs_[i].plugConfig.appGatewayId, + switchboard: configs_[i].plugConfig.switchboard }); - emit PlugAdded(configs_[i].appGatewayId, configs_[i].chainSlug, configs_[i].plug); + emit PlugAdded( + configs_[i].plugConfig.appGatewayId, + configs_[i].chainSlug, + configs_[i].plug + ); } } - /// @notice Sets the socket, contract factory plug, and fees plug for a network + /// @notice Sets the socket for a network /// @param chainSlug_ The identifier of the network - function setOnChainContracts( - uint32 chainSlug_, - SocketConfig memory socketConfig_ - ) external onlyWatcher { - socketConfigs[chainSlug_] = socketConfig_; - emit OnChainContractSet( - chainSlug_, - socketConfig_.socket, - // todo: move in their app gateways - socketConfig_.contractFactoryPlug, - socketConfig_.feesPlug - ); + /// @param socket_ The address of the socket + function setSocket(uint32 chainSlug_, address socket_) external onlyWatcher { + sockets[chainSlug_] = socket_; + emit SocketSet(chainSlug_, socket_); } /// @notice Sets the switchboard for a network diff --git a/contracts/evmx/watcher/PromiseResolver.sol b/contracts/evmx/watcher/PromiseResolver.sol index 74b03f52..62feff99 100644 --- a/contracts/evmx/watcher/PromiseResolver.sol +++ b/contracts/evmx/watcher/PromiseResolver.sol @@ -1,37 +1,43 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import {PayloadParams, ResolvedPromises} from "../../utils/common/Structs.sol"; -import "../interfaces/IPromise.sol"; import "./WatcherBase.sol"; - -interface IPromiseResolver { - function resolvePromises(ResolvedPromises[] calldata resolvedPromises_) external; - - function markRevert(bool isRevertingOnchain_, bytes32 payloadId_) external; -} +import "../interfaces/IPromise.sol"; +import "../interfaces/IPromiseResolver.sol"; +import {DeadlineNotPassedForOnChainRevert} from "../../utils/common/Errors.sol"; /// @title PromiseResolver /// @notice Contract that handles promise resolution and revert marking logic /// @dev This contract interacts with the Watcher for storage access -contract PromiseResolver is IPromiseResolver { - error DeadlineNotPassedForOnChainRevert(); +contract PromiseResolver is IPromiseResolver, WatcherBase { + /// @notice Emitted when a promise is resolved + /// @param payloadId The unique identifier for the resolved promise + event PromiseResolved(bytes32 indexed payloadId, address asyncPromise); + + /// @notice Emitted when a promise is not resolved + /// @param payloadId The unique identifier for the not resolved promise + event PromiseNotResolved(bytes32 indexed payloadId, address asyncPromise); + + /// @notice Emitted when a payload is marked as revert + /// @param payloadId The unique identifier for the payload + /// @param isRevertingOnchain Whether the payload is reverting onchain + event MarkedRevert(bytes32 indexed payloadId, bool isRevertingOnchain); /// @notice Sets the Watcher address /// @param watcher_ The address of the Watcher contract constructor(address watcher_) WatcherBase(watcher_) {} /// @notice Resolves multiple promises with their return data - /// @param resolvedPromises_ Array of resolved promises and their return data + /// @param promiseReturnData_ Array of resolved promises and their return data /// @dev This function resolves multiple promises with their return data /// @dev It also processes the next batch if the current batch is complete - function resolvePromises(ResolvedPromises[] memory resolvedPromises_) external onlyWatcher { - for (uint256 i = 0; i < resolvedPromises_.length; i++) { - (uint40 requestCount, bool success) = _processPromiseResolution(resolvedPromises_[i]); + function resolvePromises(PromiseReturnData[] memory promiseReturnData_) external onlyWatcher { + for (uint256 i = 0; i < promiseReturnData_.length; i++) { + (uint40 requestCount, bool success) = _processPromiseResolution(promiseReturnData_[i]); if (success) { requestHandler__().updateRequestAndProcessBatch( requestCount, - resolvedPromises_[i].payloadId + promiseReturnData_[i].payloadId ); } } @@ -39,18 +45,15 @@ contract PromiseResolver is IPromiseResolver { // todo: add max copy bytes and update function inputs function _processPromiseResolution( - ResolvedPromises memory resolvedPromise_ + PromiseReturnData memory resolvedPromise_ ) internal returns (uint40 requestCount, bool success) { - PayloadParams memory payloadParams = requestHandler__().getPayloadParams( - resolvedPromise_.payloadId - ); - + PayloadParams memory payloadParams = watcher__.getPayloadParams(resolvedPromise_.payloadId); address asyncPromise = payloadParams.asyncPromise; requestCount = payloadParams.requestCount; if (asyncPromise != address(0)) { success = IPromise(asyncPromise).markResolved( - requestCount, + resolvedPromise_.maxCopyExceeded, resolvedPromise_.payloadId, resolvedPromise_.returnData ); @@ -68,23 +71,28 @@ contract PromiseResolver is IPromiseResolver { /// @notice Marks a request as reverting /// @param isRevertingOnchain_ Whether the request is reverting onchain - /// @param payloadId_ The unique identifier of the payload - /// @return success Whether the request was successfully marked as reverting - function markRevert(bool isRevertingOnchain_, bytes32 payloadId_) external onlyWatcher { + /// @param resolvedPromise_ The resolved promise + /// @dev This function marks a request as reverting + /// @dev It cancels the request and marks the promise as onchain reverting if the request is reverting onchain + function markRevert( + PromiseReturnData memory resolvedPromise_, + bool isRevertingOnchain_ + ) external onlyWatcher { // Get payload params from Watcher - PayloadParams memory payloadParams = requestHandler__().getPayloadParams(payloadId_); + PayloadParams memory payloadParams = watcher__.getPayloadParams(resolvedPromise_.payloadId); if (payloadParams.deadline > block.timestamp) revert DeadlineNotPassedForOnChainRevert(); // marks the request as cancelled and settles the fees - requestHandler__().cancelRequestFromPromise(payloadParams.requestCount); + requestHandler__().cancelRequestForReverts(payloadParams.requestCount); // marks the promise as onchain reverting if the request is reverting onchain if (isRevertingOnchain_ && payloadParams.asyncPromise != address(0)) IPromise(payloadParams.asyncPromise).markOnchainRevert( - payloadParams.requestCount, - payloadId_ + resolvedPromise_.maxCopyExceeded, + resolvedPromise_.payloadId, + resolvedPromise_.returnData ); - emit MarkedRevert(payloadId_, isRevertingOnchain_); + emit MarkedRevert(resolvedPromise_.payloadId, isRevertingOnchain_); } } diff --git a/contracts/evmx/watcher/RequestHandler.sol b/contracts/evmx/watcher/RequestHandler.sol index 393921a1..76b5c063 100644 --- a/contracts/evmx/watcher/RequestHandler.sol +++ b/contracts/evmx/watcher/RequestHandler.sol @@ -1,20 +1,17 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import "./WatcherBase.sol"; -import "../../utils/common/Structs.sol"; +import "../helpers/AddressResolverUtil.sol"; import "../../utils/common/Errors.sol"; import "../../utils/common/Constants.sol"; import "../../utils/common/IdUtils.sol"; -import "../interfaces/IPrecompile.sol"; +import "../interfaces/IAppGateway.sol"; /// @title RequestHandler -/// @notice Contract that handles request processing and management +/// @notice Contract that handles request processing and management, including request submission, batch processing, and request lifecycle management +/// @dev Handles request submission, batch processing, transmitter assignment, request cancellation and settlement /// @dev This contract interacts with the WatcherPrecompileStorage for storage access -contract RequestHandler is WatcherBase { - error InvalidPrecompileData(); - error InvalidCallType(); - +contract RequestHandler is AddressResolverUtil { /// @notice Counter for tracking request counts uint40 public nextRequestCount = 1; @@ -43,14 +40,32 @@ contract RequestHandler is WatcherBase { /// @notice Mapping to store if a promise is executed for each payload ID mapping(bytes32 => bool) public isPromiseExecuted; - constructor(address watcherStorage_) WatcherBase(watcherStorage_) {} + event RequestSubmitted( + bool hasWrite, + uint40 requestCount, + uint256 totalEstimatedWatcherFees, + RequestParams requestParams, + PayloadParams[] payloadParamsArray + ); + + event FeesIncreased(uint40 requestCount, uint256 newMaxFees); + event RequestSettled(uint40 requestCount, address winner); + event RequestCompletedWithErrors(uint40 requestCount); + event RequestCancelled(uint40 requestCount); modifier isRequestCancelled(uint40 requestCount_) { - if (requestParams[requestCount_].requestTrackingParams.isRequestCancelled) - revert RequestCancelled(); + if (requests[requestCount_].requestTrackingParams.isRequestCancelled) + revert RequestAlreadyCancelled(); + _; + } + + modifier onlyPromiseResolver() { + if (msg.sender != address(watcher__().promiseResolver__())) revert NotPromiseResolver(); _; } + // constructor(address watcherStorage_) WatcherBase(watcherStorage_) {} + function setPrecompile(bytes4 callType_, IPrecompile precompile_) external onlyWatcher { precompiles[callType_] = precompile_; } @@ -60,48 +75,37 @@ contract RequestHandler is WatcherBase { address auctionManager_, address consumeFrom_, address appGateway_, - QueueParams[] calldata queuePayloadParams_, + QueueParams[] calldata queueParams_, bytes memory onCompleteData_ ) external onlyWatcher returns (uint40 requestCount, address[] memory promiseList) { - if (queuePayloadParams_.length == 0) return uint40(0); - if (queuePayloadParams.length > REQUEST_PAYLOAD_COUNT_LIMIT) + if (queueParams_.length == 0) return (0, new address[](0)); + if (queueParams_.length > REQUEST_PAYLOAD_COUNT_LIMIT) revert RequestPayloadCountLimitExceeded(); - if (!IFeesManager(feesManager__()).isCreditSpendable(consumeFrom_, appGateway_, maxFees_)) + if (!feesManager__().isCreditSpendable(consumeFrom_, appGateway_, maxFees_)) revert InsufficientFees(); requestCount = nextRequestCount++; - RequestParams storage r = requestParams[requestCount]; - r = RequestParams({ - requestTrackingParams: RequestTrackingParams({ - isRequestCancelled: false, - isRequestExecuted: false, - currentBatch: nextBatchCount, - currentBatchPayloadsLeft: 0, - payloadsRemaining: queuePayloadParams_.length - }), - requestFeesDetails: RequestFeesDetails({ - maxFees: maxFees_, - consumeFrom: consumeFrom_, - winningBid: Bid({transmitter: address(0), fees: 0}) - }), - writeCount: 0, - auctionManager: _getAuctionManager(auctionManager_), - appGateway: appGateway_, - onCompleteData: onCompleteData_ - }); + RequestParams storage r = requests[requestCount]; + r.requestTrackingParams.currentBatch = nextBatchCount; + r.requestTrackingParams.payloadsRemaining = queueParams_.length; + r.requestFeesDetails.maxFees = maxFees_; + r.requestFeesDetails.consumeFrom = consumeFrom_; + r.auctionManager = _getAuctionManager(auctionManager_); + r.appGateway = appGateway_; + r.onCompleteData = onCompleteData_; PayloadParams[] memory payloadParams; uint256 totalEstimatedWatcherFees; (totalEstimatedWatcherFees, r.writeCount, promiseList, payloadParams) = _createRequest( - queuePayloadParams_, + queueParams_, appGateway_, requestCount ); if (totalEstimatedWatcherFees > maxFees_) revert InsufficientFees(); - if (r.writeCount == 0) _processBatch(requestCount, r.requestTrackingParams.currentBatch, r); + emit RequestSubmitted( r.writeCount > 0, requestCount, @@ -112,11 +116,12 @@ contract RequestHandler is WatcherBase { } // called by auction manager when a auction ends or a new transmitter is assigned (bid expiry) + // todo: add AM cases handled here function assignTransmitter( uint40 requestCount_, Bid memory bid_ ) external isRequestCancelled(requestCount_) { - RequestParams storage r = requestParams[requestCount_]; + RequestParams storage r = requests[requestCount_]; if (r.auctionManager != msg.sender) revert InvalidCaller(); if (r.requestTrackingParams.isRequestExecuted) revert RequestAlreadySettled(); @@ -130,14 +135,14 @@ contract RequestHandler is WatcherBase { r.requestFeesDetails.winningBid = bid_; if (bid_.transmitter == address(0)) return; - feesManager__().blockCredits(requestCount_, r.requestFeesDetails.consumeFrom, bid_.fees); + feesManager__().blockCredits(requestCount_, r.requestFeesDetails.consumeFrom, bid_.fee); // re-process current batch again or process the batch for the first time _processBatch(requestCount_, r.requestTrackingParams.currentBatch, r); } function _createRequest( - QueueParams[] calldata queuePayloadParams_, + QueueParams[] calldata queueParams_, address appGateway_, uint40 requestCount_ ) @@ -151,26 +156,26 @@ contract RequestHandler is WatcherBase { { // push first batch count requestBatchIds[requestCount_].push(nextBatchCount); - - for (uint256 i = 0; i < queuePayloadParams.length; i++) { - QueueParams calldata queuePayloadParam = queuePayloadParams_[i]; + promiseList = new address[](queueParams_.length); + payloadParams = new PayloadParams[](queueParams_.length); + for (uint256 i = 0; i < queueParams_.length; i++) { + QueueParams calldata queuePayloadParam = queueParams_[i]; bytes4 callType = queuePayloadParam.overrideParams.callType; if (callType == WRITE) writeCount++; // decide batch count - if (i > 0 && queuePayloadParams[i].isParallel != Parallel.ON) { + if (i > 0 && queueParams_[i].overrideParams.isParallelCall != Parallel.ON) { nextBatchCount++; - requestBatchCounts[requestCount_].push(nextBatchCount); + requestBatchIds[requestCount_].push(nextBatchCount); } // get the switchboard address from the watcher precompile config - address switchboard = configurations__().switchboards( - queuePayloadParam.chainSlug, - queuePayloadParam.switchboardType + address switchboard = watcher__().configurations__().sockets( + queuePayloadParam.transaction.chainSlug ); // process payload data and store - (uint256 estimatedFees, bytes memory precompileData) = _validateAndGetPrecompileData( + (bytes memory precompileData, uint256 estimatedFees) = _validateAndGetPrecompileData( queuePayloadParam, appGateway_, callType @@ -181,28 +186,28 @@ contract RequestHandler is WatcherBase { uint40 payloadCount = payloadCounter++; bytes32 payloadId = createPayloadId( requestCount_, - batchCount, + nextBatchCount, payloadCount, switchboard, - queuePayloadParam.chainSlug + queuePayloadParam.transaction.chainSlug ); - batchPayloadIds[batchCount].push(payloadId); + batchPayloadIds[nextBatchCount].push(payloadId); // create prev digest hash PayloadParams memory p = PayloadParams({ requestCount: requestCount_, - batchCount: batchCount, + batchCount: nextBatchCount, payloadCount: payloadCount, callType: callType, - asyncPromise: queuePayloadParams_.asyncPromise, - appGateway: queuePayloadParams_.appGateway, + asyncPromise: queueParams_[i].asyncPromise, + appGateway: appGateway_, payloadId: payloadId, resolvedAt: 0, deadline: 0, precompileData: precompileData }); - promiseList.push(queuePayloadParams_.asyncPromise); - payloadParams.push(p); + promiseList[i] = queueParams_[i].asyncPromise; + payloadParams[i] = p; payloads[payloadId] = p; } @@ -213,7 +218,7 @@ contract RequestHandler is WatcherBase { QueueParams calldata payloadParams_, address appGateway_, bytes4 callType_ - ) internal returns (uint256, bytes memory) { + ) internal view returns (bytes memory precompileData, uint256 estimatedFees) { if (address(precompiles[callType_]) == address(0)) revert InvalidCallType(); return IPrecompile(precompiles[callType_]).validateAndGetPrecompileData( @@ -225,7 +230,7 @@ contract RequestHandler is WatcherBase { function _getAuctionManager(address auctionManager_) internal view returns (address) { return auctionManager_ == address(0) - ? addressResolver__().defaultAuctionManager() + ? addressResolver__.defaultAuctionManager() : auctionManager_; } @@ -242,7 +247,6 @@ contract RequestHandler is WatcherBase { // check needed for re-process, in case a payload is already executed by last transmitter if (!isPromiseExecuted[payloadId]) continue; - PayloadParams storage payloadParams = payloads[payloadId]; (uint256 fees, uint256 deadline) = IPrecompile(precompiles[payloadParams.callType]) @@ -261,7 +265,7 @@ contract RequestHandler is WatcherBase { /// @param requestCount_ The ID of the request /// @param newMaxFees_ The new maximum fees function increaseFees(uint40 requestCount_, uint256 newMaxFees_) external { - RequestParams storage r = requestParams[requestCount_]; + RequestParams storage r = requests[requestCount_]; address appGateway = getCoreAppGateway(msg.sender); if (r.requestTrackingParams.isRequestCancelled) revert RequestAlreadyCancelled(); @@ -288,7 +292,7 @@ contract RequestHandler is WatcherBase { uint40 requestCount_, bytes32 payloadId_ ) external onlyPromiseResolver isRequestCancelled(requestCount_) { - RequestParams storage r = requestParams[requestCount_]; + RequestParams storage r = requests[requestCount_]; PayloadParams storage payloadParams = payloads[payloadId_]; IPrecompile(precompiles[payloadParams.callType]).resolvePayload(payloadParams); @@ -307,18 +311,26 @@ contract RequestHandler is WatcherBase { } } + /// @notice Cancels a request + /// @param requestCount The request count to cancel + /// @dev This function cancels a request + /// @dev It verifies that the caller is the middleware and that the request hasn't been cancelled yet + function cancelRequestForReverts(uint40 requestCount) external onlyPromiseResolver { + _cancelRequest(requestCount, requests[requestCount]); + } + /// @notice Cancels a request /// @param requestCount The request count to cancel /// @dev This function cancels a request /// @dev It verifies that the caller is the middleware and that the request hasn't been cancelled yet function cancelRequest(uint40 requestCount) external { - RequestParams storage r = requestParams[requestCount]; + RequestParams storage r = requests[requestCount]; if (r.appGateway != getCoreAppGateway(msg.sender)) revert InvalidCaller(); _cancelRequest(requestCount, r); } function handleRevert(uint40 requestCount) external onlyPromiseResolver { - _cancelRequest(requestCount, requestParams[requestCount]); + _cancelRequest(requestCount, requests[requestCount]); } function _cancelRequest(uint40 requestCount_, RequestParams storage r) internal { @@ -326,8 +338,8 @@ contract RequestHandler is WatcherBase { if (r.requestTrackingParams.isRequestExecuted) revert RequestAlreadySettled(); r.requestTrackingParams.isRequestCancelled = true; - _settleRequest(requestCount, r); - emit RequestCancelled(requestCount); + _settleRequest(requestCount_, r); + emit RequestCancelled(requestCount_); } function _settleRequest(uint40 requestCount_, RequestParams storage r) internal { diff --git a/contracts/evmx/watcher/Trigger.sol b/contracts/evmx/watcher/Trigger.sol index d99d8507..6be8c464 100644 --- a/contracts/evmx/watcher/Trigger.sol +++ b/contracts/evmx/watcher/Trigger.sol @@ -1,12 +1,16 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; +import {LibCall} from "solady/utils/LibCall.sol"; import "./WatcherStorage.sol"; +import {decodeAppGatewayId} from "../../utils/common/IdUtils.sol"; /// @title Trigger /// @notice Contract that handles trigger validation and execution logic /// @dev This contract interacts with the WatcherPrecompileStorage for storage access abstract contract Trigger is WatcherStorage { + using LibCall for address; + /// @notice stores temporary chainSlug of the trigger from a chain uint32 public triggerFromChainSlug; /// @notice stores temporary plug of the trigger from a chain @@ -20,10 +24,15 @@ abstract contract Trigger is WatcherStorage { /// @dev callId => bool mapping(bytes32 => bool) public isAppGatewayCalled; + event TriggerFeesSet(uint256 triggerFees); + event TriggerFailed(bytes32 triggerId); + event TriggerSucceeded(bytes32 triggerId); + /// @notice Sets the trigger fees /// @param triggerFees_ The amount of fees to set function _setTriggerFees(uint256 triggerFees_) internal { triggerFees = triggerFees_; + emit TriggerFeesSet(triggerFees_); } /// @notice Calls app gateways with the specified parameters @@ -34,7 +43,8 @@ abstract contract Trigger is WatcherStorage { function _callAppGateways(TriggerParams memory params_) internal { if (isAppGatewayCalled[params_.triggerId]) revert AppGatewayAlreadyCalled(); - if (!configurations__().isValidPlug(params_.appGatewayId, params_.chainSlug, params_.plug)) + address appGateway = decodeAppGatewayId(params_.appGatewayId); + if (!configurations__.isValidPlug(appGateway, params_.chainSlug, params_.plug)) revert InvalidCallerTriggered(); feesManager__().transferCredits(appGateway, address(this), triggerFees); diff --git a/contracts/evmx/watcher/Watcher.sol b/contracts/evmx/watcher/Watcher.sol index accd24e4..f7f02d23 100644 --- a/contracts/evmx/watcher/Watcher.sol +++ b/contracts/evmx/watcher/Watcher.sol @@ -4,30 +4,29 @@ pragma solidity ^0.8.21; import "./Trigger.sol"; contract Watcher is Trigger { - IRequestHandler public requestHandler__; - IConfigManager public configManager__; - IPromiseResolver public promiseResolver__; - IAddressResolver public addressResolver__; - constructor( address requestHandler_, address configManager_, address promiseResolver_, - address addressResolver_ + address addressResolver_, + address owner_ ) { - requestHandler__ = requestHandler_; - configManager__ = configManager_; - promiseResolver__ = promiseResolver_; - addressResolver__ = addressResolver_; + requestHandler__ = IRequestHandler(requestHandler_); + configurations__ = IConfigurations(configManager_); + promiseResolver__ = IPromiseResolver(promiseResolver_); + addressResolver__ = IAddressResolver(addressResolver_); + _initializeOwner(owner_); } + // todo: add withdraw credit function + function queueAndSubmit( QueueParams memory queue_, uint256 maxFees, address auctionManager, address consumeFrom, - bytes onCompleteData - ) internal returns (uint40, address[] memory) { + bytes memory onCompleteData + ) external returns (uint40, address[] memory) { _queue(queue_, msg.sender); return _submitRequest(maxFees, auctionManager, consumeFrom, onCompleteData); } @@ -54,12 +53,9 @@ contract Watcher is Trigger { if (appGatewayTemp != coreAppGateway || coreAppGateway == address(0)) revert InvalidAppGateway(); - uint40 requestCount = requestHandler__.nextRequestCount(); + uint40 requestCount = getCurrentRequestCount(); // Deploy a new async promise contract. - latestAsyncPromise = asyncDeployer__().deployAsyncPromiseContract( - appGateway_, - requestCount - ); + latestAsyncPromise = asyncDeployer__().deployAsyncPromiseContract(appGateway_); appGatewayTemp = coreAppGateway; queue_.asyncPromise = latestAsyncPromise; @@ -73,7 +69,7 @@ contract Watcher is Trigger { uint256 maxFees, address auctionManager, address consumeFrom, - bytes onCompleteData + bytes memory onCompleteData ) external returns (uint40, address[] memory) { return _submitRequest(maxFees, auctionManager, consumeFrom, onCompleteData); } @@ -82,11 +78,11 @@ contract Watcher is Trigger { uint256 maxFees, address auctionManager, address consumeFrom, - bytes onCompleteData + bytes memory onCompleteData ) internal returns (uint40 requestCount, address[] memory promiseList) { // this check is to verify that msg.sender (app gateway base) belongs to correct app gateway address coreAppGateway = getCoreAppGateway(msg.sender); - if (coreAppGateway != appGatewayTemp) revert InvalidAppGateways(); + if (coreAppGateway != appGatewayTemp) revert InvalidAppGateway(); latestAsyncPromise = address(0); (requestCount, promiseList) = requestHandler__.submitRequest( @@ -102,35 +98,34 @@ contract Watcher is Trigger { /// @notice Clears the call parameters array function clearQueue() public { - delete queue; + delete payloadQueue; } - function callAppGateways( - TriggerParams[] memory params_, - uint256 nonce_, - bytes memory signature_ - ) external { - _validateSignature(abi.encode(params_), nonce_, signature_); - for (uint40 i = 0; i < params_.length; i++) { - _callAppGateways(params_[i]); - } + // function callAppGateways(WatcherMultiCallParams[] memory params_) external { + // // todo: + // // _validateSignature(params_[i].data_, params_[i].nonces_, params_[i].signatures_); + // for (uint40 i = 0; i < params_.length; i++) { + // _callAppGateways(params_[i]); + // } + // } + + function getCurrentRequestCount() public view returns (uint40) { + return requestHandler__.nextRequestCount(); } function getRequestParams(uint40 requestCount_) external view returns (RequestParams memory) { - return requestHandler__().getRequestParams(requestCount_); + return requestHandler__.requests(requestCount_); } function getPayloadParams(bytes32 payloadId_) external view returns (PayloadParams memory) { - return requestHandler__().getPayloadParams(payloadId_); + return requestHandler__.payloads(payloadId_); } - /// @notice Sets the expiry time for payload execution - /// @param expiryTime_ The expiry time in seconds - /// @dev This function sets the expiry time for payload execution - /// @dev Only callable by the contract owner - function setExpiryTime(uint256 expiryTime_) external onlyOwner { - expiryTime = expiryTime_; - emit ExpiryTimeSet(expiryTime_); + function getPrecompileFees( + bytes4 precompile_, + bytes memory precompileData_ + ) external view returns (uint256) { + return requestHandler__.getPrecompileFees(precompile_, precompileData_); } function setTriggerFees( @@ -143,17 +138,14 @@ contract Watcher is Trigger { } // all function from watcher requiring signature - function watcherMultiCall( - address[] memory contracts, - bytes[] memory data_, - uint256[] memory nonces_, - bytes[] memory signatures_ - ) external payable { - for (uint40 i = 0; i < contracts.length; i++) { - if (contracts[i] == address(0)) revert InvalidContract(); - _validateSignature(data_[i], nonces_[i], signatures_[i]); + function watcherMultiCall(WatcherMultiCallParams[] memory params_) external payable { + for (uint40 i = 0; i < params_.length; i++) { + if (params_[i].contracts == address(0)) revert InvalidContract(); + _validateSignature(params_[i].data_, params_[i].nonces_, params_[i].signatures_); + // call the contract - (bool success, bytes memory result) = contracts[i].call{value: msg.value}(data_[i]); + // todo: add msg value to its struct params + (bool success, ) = params_[i].contracts.call{value: msg.value}(params_[i].data_); if (!success) revert CallFailed(); } } @@ -180,7 +172,7 @@ contract Watcher is Trigger { uint256 signatureNonce_, bytes memory inputData_, bytes memory signature_ - ) internal { + ) internal returns (bool) { if (isNonceUsed[signatureNonce_]) revert NonceUsed(); isNonceUsed[signatureNonce_] = true; @@ -191,6 +183,6 @@ contract Watcher is Trigger { // recovered signer is checked for the valid roles later address signer = ECDSA.recover(digest, signature_); - if (signer != owner()) revert InvalidWatcherSignature(); + return signer == owner(); } } diff --git a/contracts/evmx/watcher/WatcherBase.sol b/contracts/evmx/watcher/WatcherBase.sol index b36e6c31..005b389f 100644 --- a/contracts/evmx/watcher/WatcherBase.sol +++ b/contracts/evmx/watcher/WatcherBase.sol @@ -3,36 +3,48 @@ pragma solidity ^0.8.21; import "../interfaces/IWatcher.sol"; import "../interfaces/IConfigurations.sol"; +import "../interfaces/IPromiseResolver.sol"; +import "../interfaces/IRequestHandler.sol"; + /// @title WatcherBase +/// @notice Base contract for the Watcher contract contract WatcherBase { - // The address of the WatcherPrecompileStorage contract - address public watcher; + // The address of the Watcher contract + IWatcher public watcher__; - // Only WatcherPrecompileStorage can call functions + // Only Watcher can call functions modifier onlyWatcher() { - require(msg.sender == watcher, "Only Watcher can call"); + require(msg.sender == address(watcher__), "Only Watcher can call"); _; } - /// @notice Sets the WatcherPrecompileStorage address - /// @param watcher_ The address of the WatcherPrecompileStorage contract + /// @notice Sets the Watcher address + /// @param watcher_ The address of the Watcher contract constructor(address watcher_) { - watcher = watcher_; + watcher__ = IWatcher(watcher_); } - /// @notice Updates the WatcherPrecompileStorage address - /// @param watcher_ The new address of the WatcherPrecompileStorage contract + /// @notice Updates the Watcher address + /// @param watcher_ The new address of the Watcher contract function setWatcher(address watcher_) external onlyWatcher { - watcher = watcher_; + watcher__ = IWatcher(watcher_); + } + + /// @notice Returns the configurations of the Watcher contract + /// @return configurations The configurations of the Watcher contract + function configurations__() internal view returns (IConfigurations) { + return watcher__.configurations__(); } - /// @notice Returns the configurations of the WatcherPrecompileStorage contract - /// @return configurations The configurations of the WatcherPrecompileStorage contract - function configurations__() external view returns (IConfigurations) { - return IWatcher(watcher).configurations__(); + /// @notice Returns the promise resolver of the Watcher contract + /// @return promiseResolver The promise resolver of the Watcher contract + function promiseResolver__() internal view returns (IPromiseResolver) { + return watcher__.promiseResolver__(); } - function getCoreAppGateway(address appGateway_) external view returns (address) { - return IWatcher(watcher).configurations__().getCoreAppGateway(appGateway_); + /// @notice Returns the request handler of the Watcher contract + /// @return requestHandler The request handler of the Watcher contract + function requestHandler__() internal view returns (IRequestHandler) { + return watcher__.requestHandler__(); } } diff --git a/contracts/evmx/watcher/WatcherStorage.sol b/contracts/evmx/watcher/WatcherStorage.sol index 91336b93..996c39e9 100644 --- a/contracts/evmx/watcher/WatcherStorage.sol +++ b/contracts/evmx/watcher/WatcherStorage.sol @@ -2,12 +2,15 @@ pragma solidity ^0.8.21; import "../interfaces/IWatcher.sol"; +import "../helpers/AddressResolverUtil.sol"; +import "solady/utils/ECDSA.sol"; +import {Ownable} from "solady/auth/Ownable.sol"; /// @title WatcherStorage /// @notice Storage contract for the WatcherPrecompile system /// @dev This contract contains all the storage variables used by the WatcherPrecompile system /// @dev It is inherited by WatcherPrecompileCore and WatcherPrecompile -abstract contract WatcherStorage is IWatcher { +abstract contract WatcherStorage is IWatcher, AddressResolverUtil, Ownable { // slots [0-49]: gap for future storage variables uint256[50] _gap_before; @@ -30,6 +33,10 @@ abstract contract WatcherStorage is IWatcher { address public latestAsyncPromise; address public appGatewayTemp; + IRequestHandler public override requestHandler__; + IConfigurations public override configurations__; + IPromiseResolver public override promiseResolver__; + // slots [51-100]: gap for future storage variables uint256[50] _gap_after; diff --git a/contracts/evmx/watcher/precompiles/ReadPrecompile.sol b/contracts/evmx/watcher/precompiles/ReadPrecompile.sol index 1a2d63a5..33fbc762 100644 --- a/contracts/evmx/watcher/precompiles/ReadPrecompile.sol +++ b/contracts/evmx/watcher/precompiles/ReadPrecompile.sol @@ -10,26 +10,38 @@ import "../WatcherBase.sol"; /// @notice Handles read precompile logic contract ReadPrecompile is IPrecompile, WatcherBase { /// @notice Emitted when a new read is requested - event ReadRequested(PayloadParams params); + event ReadRequested(Transaction transaction, uint256 readAtBlockNumber, bytes32 payloadId); + event ExpiryTimeSet(uint256 expiryTime); + event ReadFeesSet(uint256 readFees); /// @notice The fees for a read and includes callback fees uint256 public readFees; + uint256 public expiryTime; + + constructor(address watcher_, uint256 readFees_, uint256 expiryTime_) WatcherBase(watcher_) { + readFees = readFees_; + expiryTime = expiryTime_; + } + + function getPrecompileFees(bytes memory) external view returns (uint256) { + return readFees; + } /// @notice Gets precompile data and fees for queue parameters - /// @param queuePayloadParams_ The queue parameters to process + /// @param queueParams_ The queue parameters to process /// @return precompileData The encoded precompile data /// @return estimatedFees Estimated fees required for processing function validateAndGetPrecompileData( - QueueParams calldata queuePayloadParams_, + QueueParams calldata queueParams_, address ) external view returns (bytes memory precompileData, uint256 estimatedFees) { - if (queuePayloadParams_.transaction.target != address(0)) revert InvalidTarget(); - if (queuePayloadParams_.transaction.payload.length > 0) revert InvalidPayloadSize(); + if (queueParams_.transaction.target != address(0)) revert InvalidTarget(); + if (queueParams_.transaction.payload.length > 0) revert InvalidPayloadSize(); // For read precompile, encode the payload parameters precompileData = abi.encode( - queuePayloadParams_.transaction, - queuePayloadParams_.overrideParams.readAtBlockNumber + queueParams_.transaction, + queueParams_.overrideParams.readAtBlockNumber ); estimatedFees = readFees; } @@ -40,7 +52,7 @@ contract ReadPrecompile is IPrecompile, WatcherBase { function handlePayload( address, PayloadParams calldata payloadParams - ) external pure returns (uint256 fees, uint256 deadline) { + ) external onlyWatcher returns (uint256 fees, uint256 deadline) { fees = readFees; deadline = block.timestamp + expiryTime; @@ -55,6 +67,15 @@ contract ReadPrecompile is IPrecompile, WatcherBase { function setFees(uint256 readFees_) external onlyWatcher { readFees = readFees_; - emit FeesSet(readFees_); + emit ReadFeesSet(readFees_); + } + + /// @notice Sets the expiry time for payload execution + /// @param expiryTime_ The expiry time in seconds + /// @dev This function sets the expiry time for payload execution + /// @dev Only callable by the contract owner + function setExpiryTime(uint256 expiryTime_) external onlyWatcher { + expiryTime = expiryTime_; + emit ExpiryTimeSet(expiryTime_); } } diff --git a/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol b/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol index 87b8e5af..4f97092a 100644 --- a/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.21; import "../../interfaces/IPrecompile.sol"; import "../../../utils/common/Structs.sol"; -import {InvalidPayloadSize, InvalidScheduleDelay, InvalidTimeoutRequest, TimeoutAlreadyResolved, ResolvingTimeoutTooEarly, CallFailed} from "../../../utils/common/Errors.sol"; +import {InvalidScheduleDelay, ResolvingTimeoutTooEarly} from "../../../utils/common/Errors.sol"; import "../WatcherBase.sol"; /// @title SchedulePrecompile @@ -19,6 +19,8 @@ contract SchedulePrecompile is IPrecompile, WatcherBase { uint256 public scheduleFeesPerSecond; /// @notice The callback fees for a schedule uint256 public scheduleCallbackFees; + /// @notice The expiry time for a schedule + uint256 public expiryTime; /// @notice Emitted when the maximum schedule delay in seconds is set event MaxScheduleDelayInSecondsSet(uint256 maxScheduleDelayInSeconds_); @@ -26,6 +28,30 @@ contract SchedulePrecompile is IPrecompile, WatcherBase { event ScheduleFeesPerSecondSet(uint256 scheduleFeesPerSecond_); /// @notice Emitted when the callback fees for a schedule is set event ScheduleCallbackFeesSet(uint256 scheduleCallbackFees_); + /// @notice Emitted when the expiry time for a schedule is set + event ExpiryTimeSet(uint256 expiryTime_); + /// @notice Emitted when a schedule is requested + event ScheduleRequested(bytes32 payloadId, uint256 deadline); + /// @notice Emitted when a schedule is resolved + event ScheduleResolved(bytes32 payloadId); + + constructor( + address watcher_, + uint256 maxScheduleDelayInSeconds_, + uint256 scheduleFeesPerSecond_, + uint256 scheduleCallbackFees_, + uint256 expiryTime_ + ) WatcherBase(watcher_) { + maxScheduleDelayInSeconds = maxScheduleDelayInSeconds_; + scheduleFeesPerSecond = scheduleFeesPerSecond_; + scheduleCallbackFees = scheduleCallbackFees_; + expiryTime = expiryTime_; + } + + function getPrecompileFees(bytes memory precompileData_) external view returns (uint256) { + uint256 delayInSeconds = abi.decode(precompileData_, (uint256)); + return scheduleFeesPerSecond * delayInSeconds + scheduleCallbackFees; + } /// @notice Sets the maximum schedule delay in seconds /// @param maxScheduleDelayInSeconds_ The maximum schedule delay in seconds @@ -57,17 +83,17 @@ contract SchedulePrecompile is IPrecompile, WatcherBase { /// @notice Validates schedule parameters and return data with fees /// @dev assuming that tx is executed on EVMx chain function validateAndGetPrecompileData( - QueueParams calldata queuePayloadParams_, - address appGateway_ + QueueParams calldata queueParams_, + address ) external view returns (bytes memory precompileData, uint256 estimatedFees) { - if (queuePayloadParams_.overrideParams.delayInSeconds > maxScheduleDelayInSeconds) + if (queueParams_.overrideParams.delayInSeconds > maxScheduleDelayInSeconds) revert InvalidScheduleDelay(); // For schedule precompile, encode the payload parameters - precompileData = abi.encode(queuePayloadParams_.overrideParams.delayInSeconds); + precompileData = abi.encode(queueParams_.overrideParams.delayInSeconds); estimatedFees = scheduleFeesPerSecond * - queuePayloadParams_.overrideParams.delayInSeconds + + queueParams_.overrideParams.delayInSeconds + scheduleCallbackFees; } @@ -77,10 +103,11 @@ contract SchedulePrecompile is IPrecompile, WatcherBase { function handlePayload( address, PayloadParams calldata payloadParams - ) external pure returns (uint256 fees, uint256 deadline) { + ) external onlyWatcher returns (uint256 fees, uint256 deadline) { uint256 delayInSeconds = abi.decode(payloadParams.precompileData, (uint256)); // expiryTime is very low, to account for infra delay deadline = block.timestamp + delayInSeconds + expiryTime; + fees = scheduleFeesPerSecond * delayInSeconds + scheduleCallbackFees; // emits event for watcher to track timeout and resolve when timeout is reached emit ScheduleRequested(payloadParams.payloadId, deadline); @@ -91,4 +118,13 @@ contract SchedulePrecompile is IPrecompile, WatcherBase { emit ScheduleResolved(payloadParams_.payloadId); } + + /// @notice Sets the expiry time for payload execution + /// @param expiryTime_ The expiry time in seconds + /// @dev This function sets the expiry time for payload execution + /// @dev Only callable by the contract owner + function setExpiryTime(uint256 expiryTime_) external onlyWatcher { + expiryTime = expiryTime_; + emit ExpiryTimeSet(expiryTime_); + } } diff --git a/contracts/evmx/watcher/precompiles/WritePrecompile.sol b/contracts/evmx/watcher/precompiles/WritePrecompile.sol index cdbc1355..0d80e78b 100644 --- a/contracts/evmx/watcher/precompiles/WritePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/WritePrecompile.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import {InvalidIndex} from "../../../utils/common/Errors.sol"; +import {InvalidIndex, MaxMsgValueLimitExceeded, InvalidPayloadSize} from "../../../utils/common/Errors.sol"; import "../../../utils/common/Constants.sol"; import "../../interfaces/IPrecompile.sol"; import {encodeAppGatewayId} from "../../../utils/common/IdUtils.sol"; @@ -22,60 +22,82 @@ contract WritePrecompile is IPrecompile, WatcherBase { /// @notice The digest hash for a payload mapping(bytes32 => bytes32) public digestHashes; - mapping(address => bool) public isContractFactoryPlug; + mapping(uint32 => address) public contractFactoryPlugs; /// @notice The fees for a write and includes callback fees uint256 public writeFees; - - error MaxMsgValueLimitExceeded(); + uint256 public expiryTime; /// @notice Emitted when fees are set - event FeesSet(uint256 writeFees, uint256 callbackFees); + event FeesSet(uint256 writeFees); event ChainMaxMsgValueLimitsUpdated(uint32[] chainSlugs, uint256[] maxMsgValueLimits); event WriteRequested(bytes32 digest, PayloadParams payloadParams); - event Finalized(bytes32 payloadId, bytes proof); + /// @notice Emitted when a proof upload request is made + event WriteProofRequested( + bytes32 digest, + Transaction transaction, + WriteFinality writeFinality, + uint256 gasLimit, + uint256 value + ); + + /// @notice Emitted when a proof is uploaded + /// @param payloadId The unique identifier for the request + /// @param proof The proof from the watcher + event WriteProofUploaded(bytes32 indexed payloadId, bytes proof); + event ExpiryTimeSet(uint256 expiryTime); + + constructor(address watcher_, uint256 writeFees_, uint256 expiryTime_) WatcherBase(watcher_) { + writeFees = writeFees_; + expiryTime = expiryTime_; + } + + function getPrecompileFees(bytes memory) external view returns (uint256) { + return writeFees; + } /// @notice Gets precompile data and fees for queue parameters - /// @param queuePayloadParams_ The queue parameters to process + /// @param queueParams_ The queue parameters to process /// @return precompileData The encoded precompile data /// @return estimatedFees Estimated fees required for processing function validateAndGetPrecompileData( - QueueParams calldata queuePayloadParams_, + QueueParams memory queueParams_, address appGateway_ - ) external view returns (bytes memory precompileData, uint256 estimatedFees) { + ) external view override returns (bytes memory precompileData, uint256 estimatedFees) { if ( - queuePayloadParams_.value > - chainMaxMsgValueLimit[queuePayloadParams_.transaction.chainSlug] + queueParams_.overrideParams.value > + chainMaxMsgValueLimit[queueParams_.transaction.chainSlug] ) revert MaxMsgValueLimitExceeded(); if ( - queuePayloadParams_.transaction.payload.length > 0 && - queuePayloadParams_.transaction.payload.length < PAYLOAD_SIZE_LIMIT + queueParams_.transaction.payload.length > 0 && + queueParams_.transaction.payload.length < PAYLOAD_SIZE_LIMIT ) { revert InvalidPayloadSize(); } - if (queuePayloadParams_.transaction.target == address(0)) { - queuePayloadParams_.transaction.target = contractFactoryPlugs[ - queuePayloadParams_.transaction.chainSlug + if (queueParams_.transaction.target == address(0)) { + queueParams_.transaction.target = contractFactoryPlugs[ + queueParams_.transaction.chainSlug ]; appGateway_ = address(this); } else { configurations__().verifyConnections( - queuePayloadParams_.transaction.chainSlug, - queuePayloadParams_.transaction.target, + queueParams_.transaction.chainSlug, + queueParams_.transaction.target, appGateway_, - queuePayloadParams_.switchboardType + queueParams_.switchboardType ); } // For write precompile, encode the payload parameters precompileData = abi.encode( appGateway_, - queuePayloadParams_.transaction, - queuePayloadParams_.overrideParams.writeFinality, - queuePayloadParams_.overrideParams.gasLimit, - queuePayloadParams_.overrideParams.value + queueParams_.transaction, + queueParams_.overrideParams.writeFinality, + queueParams_.overrideParams.gasLimit, + queueParams_.overrideParams.value + // todo: add sb ); estimatedFees = writeFees; @@ -84,30 +106,30 @@ contract WritePrecompile is IPrecompile, WatcherBase { /// @notice Handles payload processing and returns fees /// @param payloadParams The payload parameters to handle /// @return fees The fees required for processing - /// @return precompileData The precompile data + /// @return deadline The deadline for the payload function handlePayload( address transmitter_, PayloadParams calldata payloadParams - ) external pure returns (uint256 fees, uint256 deadline) { - fees = writeFees + callbackFees; + ) external onlyWatcher returns (uint256 fees, uint256 deadline) { + fees = writeFees; deadline = block.timestamp + expiryTime; ( address appGateway, - Transaction transaction, + Transaction memory transaction, WriteFinality writeFinality, uint256 gasLimit, uint256 value ) = abi.decode( payloadParams.precompileData, - (address, Transaction, bool, uint256, uint256) + (address, Transaction, WriteFinality, uint256, uint256) ); - bytes32 prevBatchDigestHash = _getPrevBatchDigestHash(payloadParams); + bytes32 prevBatchDigestHash = _getPrevBatchDigestHash(payloadParams.batchCount); // create digest DigestParams memory digestParams_ = DigestParams( - configManager__().sockets(transaction.chainSlug), + configurations__().sockets(transaction.chainSlug), transmitter_, payloadParams.payloadId, payloadParams.deadline, @@ -200,5 +222,14 @@ contract WritePrecompile is IPrecompile, WatcherBase { emit FeesSet(writeFees_); } - function resolvePayload(PayloadParams calldata payloadParams_) external {} + /// @notice Sets the expiry time for payload execution + /// @param expiryTime_ The expiry time in seconds + /// @dev This function sets the expiry time for payload execution + /// @dev Only callable by the contract owner + function setExpiryTime(uint256 expiryTime_) external onlyWatcher { + expiryTime = expiryTime_; + emit ExpiryTimeSet(expiryTime_); + } + + function resolvePayload(PayloadParams calldata payloadParams_) external override {} } diff --git a/contracts/utils/common/Errors.sol b/contracts/utils/common/Errors.sol index 79eae259..e605b88e 100644 --- a/contracts/utils/common/Errors.sol +++ b/contracts/utils/common/Errors.sol @@ -50,7 +50,6 @@ error InvalidCaller(); error InvalidGateway(); /// @notice Error thrown when a request is already cancelled error RequestAlreadyCancelled(); -error RequestCancelled(); error DeadlineNotPassedForOnChainRevert(); error InvalidBid(); @@ -68,3 +67,10 @@ error InsufficientFees(); error RequestAlreadySettled(); error NoWriteRequest(); error AlreadyAssigned(); + +error OnlyAppGateway(); +error NewMaxFeesLowerThanCurrent(uint256 currentMaxFees, uint256 newMaxFees); +error InvalidContract(); +error InvalidData(); +error InvalidNonce(); +error InvalidSignature(); diff --git a/contracts/utils/common/IdUtils.sol b/contracts/utils/common/IdUtils.sol index 335bd830..899abc5e 100644 --- a/contracts/utils/common/IdUtils.sol +++ b/contracts/utils/common/IdUtils.sol @@ -5,6 +5,10 @@ function encodeAppGatewayId(address appGateway_) pure returns (bytes32) { return bytes32(uint256(uint160(appGateway_))); } +function decodeAppGatewayId(bytes32 appGatewayId_) pure returns (address) { + return address(uint160(uint256(appGatewayId_))); +} + /// @notice Creates a payload ID from the given parameters /// @param requestCount_ The request count /// @param batchCount_ The batch count diff --git a/contracts/utils/common/Structs.sol b/contracts/utils/common/Structs.sol index 71b2f0a7..b319e1d9 100644 --- a/contracts/utils/common/Structs.sol +++ b/contracts/utils/common/Structs.sol @@ -69,7 +69,8 @@ struct TriggerParams { bytes overrides; bytes payload; } -struct ResolvedPromises { +struct PromiseReturnData { + bool maxCopyExceeded; bytes32 payloadId; bytes returnData; } diff --git a/foundry.toml b/foundry.toml index 6c926318..44d70bc0 100644 --- a/foundry.toml +++ b/foundry.toml @@ -7,4 +7,4 @@ ffi = true optimizer = true optimizer_runs = 200 evm_version = 'paris' -via_ir = false +via_ir = true From dda34ebe7e50e871a3b0461d4dc478ff4402cdf6 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Fri, 23 May 2025 01:07:31 +0530 Subject: [PATCH 045/130] fix: todo --- contracts/evmx/base/AppGatewayBase.sol | 10 ++++------ contracts/evmx/fees/Credit.sol | 10 ++++++---- contracts/evmx/watcher/PromiseResolver.sol | 1 - contracts/evmx/watcher/RequestHandler.sol | 20 +++++++++++++------- contracts/evmx/watcher/Watcher.sol | 10 +++++----- contracts/utils/common/Structs.sol | 3 ++- 6 files changed, 30 insertions(+), 24 deletions(-) diff --git a/contracts/evmx/base/AppGatewayBase.sol b/contracts/evmx/base/AppGatewayBase.sol index 359ec7e8..19cb3495 100644 --- a/contracts/evmx/base/AppGatewayBase.sol +++ b/contracts/evmx/base/AppGatewayBase.sol @@ -135,16 +135,14 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { initCallData_, creationCodeWithArgs[contractId_] ); - IPromise(watcher__().latestAsyncPromise()).then( - this.setAddress.selector, - abi.encode(chainSlug_, contractId_) - ); + + then(this.setAddress.selector, abi.encode(chainSlug_, contractId_)); onCompleteData = abi.encode(chainSlug_, true); } - function then(bytes memory data_, bytes memory returnData_) external onlyPromises { - // todo + function then(bytes4 selector_, bytes memory data_) internal { + IPromise(watcher__().latestAsyncPromise()).then(selector_, data_); } /// @notice Sets the address for a deployed contract diff --git a/contracts/evmx/fees/Credit.sol b/contracts/evmx/fees/Credit.sol index ad524156..5166af32 100644 --- a/contracts/evmx/fees/Credit.sol +++ b/contracts/evmx/fees/Credit.sol @@ -4,6 +4,8 @@ pragma solidity ^0.8.21; import {Ownable} from "solady/auth/Ownable.sol"; import "solady/utils/Initializable.sol"; import "solady/utils/ECDSA.sol"; +import "solady/utils/SafeTransferLib.sol"; + import "../interfaces/IFeesManager.sol"; import "../interfaces/IFeesPlug.sol"; import {AddressResolverUtil} from "../helpers/AddressResolverUtil.sol"; @@ -85,13 +87,13 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressR UserCredits storage userCredit = userCredits[depositTo_]; userCredit.totalCredits += creditAmount_; - // try catch: if native transfer fails, add to credit - payable(depositTo_).transfer(nativeAmount_); + // if native transfer fails, add to credit + bool success = SafeTransferLib.trySafeTransferETH(depositTo_, nativeAmount_); + if (!success) userCredit.totalCredits += nativeAmount_; emit CreditsDeposited(chainSlug_, depositTo_, token_, creditAmount_); } - // todo: add safe eth transfer function wrap(address receiver_) external payable override { UserCredits storage userCredit = userCredits[receiver_]; userCredit.totalCredits += msg.value; @@ -104,7 +106,7 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressR userCredit.totalCredits -= amount_; if (address(this).balance < amount_) revert InsufficientBalance(); - payable(receiver_).transfer(amount_); + SafeTransferLib.safeTransferETH(receiver_, amount_); emit CreditsUnwrapped(receiver_, amount_); } diff --git a/contracts/evmx/watcher/PromiseResolver.sol b/contracts/evmx/watcher/PromiseResolver.sol index 62feff99..f0f9a5a2 100644 --- a/contracts/evmx/watcher/PromiseResolver.sol +++ b/contracts/evmx/watcher/PromiseResolver.sol @@ -43,7 +43,6 @@ contract PromiseResolver is IPromiseResolver, WatcherBase { } } - // todo: add max copy bytes and update function inputs function _processPromiseResolution( PromiseReturnData memory resolvedPromise_ ) internal returns (uint40 requestCount, bool success) { diff --git a/contracts/evmx/watcher/RequestHandler.sol b/contracts/evmx/watcher/RequestHandler.sol index 76b5c063..f3916d20 100644 --- a/contracts/evmx/watcher/RequestHandler.sol +++ b/contracts/evmx/watcher/RequestHandler.sol @@ -6,6 +6,7 @@ import "../../utils/common/Errors.sol"; import "../../utils/common/Constants.sol"; import "../../utils/common/IdUtils.sol"; import "../interfaces/IAppGateway.sol"; +import "../interfaces/IPromise.sol"; /// @title RequestHandler /// @notice Contract that handles request processing and management, including request submission, batch processing, and request lifecycle management @@ -37,9 +38,6 @@ contract RequestHandler is AddressResolverUtil { /// @notice The metadata for a request mapping(uint40 => RequestParams) public requests; - /// @notice Mapping to store if a promise is executed for each payload ID - mapping(bytes32 => bool) public isPromiseExecuted; - event RequestSubmitted( bool hasWrite, uint40 requestCount, @@ -116,7 +114,6 @@ contract RequestHandler is AddressResolverUtil { } // called by auction manager when a auction ends or a new transmitter is assigned (bid expiry) - // todo: add AM cases handled here function assignTransmitter( uint40 requestCount_, Bid memory bid_ @@ -126,15 +123,22 @@ contract RequestHandler is AddressResolverUtil { if (r.requestTrackingParams.isRequestExecuted) revert RequestAlreadySettled(); if (r.writeCount == 0) revert NoWriteRequest(); + + // If same transmitter is reassigned, revert if (r.requestFeesDetails.winningBid.transmitter == bid_.transmitter) revert AlreadyAssigned(); + // If a transmitter was already assigned previously, unblock the credits if (r.requestFeesDetails.winningBid.transmitter != address(0)) { feesManager__().unblockCredits(requestCount_); } r.requestFeesDetails.winningBid = bid_; + + // If a transmitter changed to address(0), return after unblocking the credits if (bid_.transmitter == address(0)) return; + + // Block the credits for the new transmitter feesManager__().blockCredits(requestCount_, r.requestFeesDetails.consumeFrom, bid_.fee); // re-process current batch again or process the batch for the first time @@ -246,7 +250,7 @@ contract RequestHandler is AddressResolverUtil { bytes32 payloadId = payloadIds[i]; // check needed for re-process, in case a payload is already executed by last transmitter - if (!isPromiseExecuted[payloadId]) continue; + if (!_isPromiseResolved(payloads[payloadId].asyncPromise)) continue; PayloadParams storage payloadParams = payloads[payloadId]; (uint256 fees, uint256 deadline) = IPrecompile(precompiles[payloadParams.callType]) @@ -297,8 +301,6 @@ contract RequestHandler is AddressResolverUtil { PayloadParams storage payloadParams = payloads[payloadId_]; IPrecompile(precompiles[payloadParams.callType]).resolvePayload(payloadParams); - // todo: read the status from promise here - isPromiseExecuted[payloadId_] = true; payloadParams.resolvedAt = block.timestamp; if (r.requestTrackingParams.currentBatchPayloadsLeft != 0) return; @@ -311,6 +313,10 @@ contract RequestHandler is AddressResolverUtil { } } + function _isPromiseResolved(address promise_) internal view returns (bool) { + return IPromise(promise_).state() == AsyncPromiseState.RESOLVED; + } + /// @notice Cancels a request /// @param requestCount The request count to cancel /// @dev This function cancels a request diff --git a/contracts/evmx/watcher/Watcher.sol b/contracts/evmx/watcher/Watcher.sol index f7f02d23..a9a34f32 100644 --- a/contracts/evmx/watcher/Watcher.sol +++ b/contracts/evmx/watcher/Watcher.sol @@ -31,8 +31,6 @@ contract Watcher is Trigger { return _submitRequest(maxFees, auctionManager, consumeFrom, onCompleteData); } - // todo: delegate call? - // todo: check app gateway input auth /// @notice Queues a new payload /// @param queue_ The call parameters function queue( @@ -101,8 +99,8 @@ contract Watcher is Trigger { delete payloadQueue; } + // todo: add this function // function callAppGateways(WatcherMultiCallParams[] memory params_) external { - // // todo: // // _validateSignature(params_[i].data_, params_[i].nonces_, params_[i].signatures_); // for (uint40 i = 0; i < params_.length; i++) { // _callAppGateways(params_[i]); @@ -144,8 +142,10 @@ contract Watcher is Trigger { _validateSignature(params_[i].data_, params_[i].nonces_, params_[i].signatures_); // call the contract - // todo: add msg value to its struct params - (bool success, ) = params_[i].contracts.call{value: msg.value}(params_[i].data_); + // trusting watcher to send enough value for all calls + (bool success, ) = params_[i].contracts.call{value: params_[i].value_}( + params_[i].data_ + ); if (!success) revert CallFailed(); } } diff --git a/contracts/utils/common/Structs.sol b/contracts/utils/common/Structs.sol index b319e1d9..97b494c3 100644 --- a/contracts/utils/common/Structs.sol +++ b/contracts/utils/common/Structs.sol @@ -109,8 +109,9 @@ struct UserCredits { struct WatcherMultiCallParams { address contracts; - bytes data_; uint256 nonces_; + uint256 value_; + bytes data_; bytes signatures_; } From 2fc53c124be95791ace5e35dbbafdf1c1c6fcf38 Mon Sep 17 00:00:00 2001 From: Akash Date: Fri, 23 May 2025 14:57:56 +0530 Subject: [PATCH 046/130] chroe: refactor updates, WIP --- hardhat-scripts/constants/enums.ts | 6 ++-- hardhat-scripts/deploy/1.deploy.ts | 22 +++++++-------- hardhat-scripts/deploy/2.roles.ts | 2 +- hardhat-scripts/deploy/3.upgradeManagers.ts | 4 +-- hardhat-scripts/deploy/4.connect.ts | 4 +-- hardhat-scripts/deploy/6.setupEnv.ts | 2 +- package.json | 2 +- src/constants.ts | 5 ++++ src/enums.ts | 31 +++++++++++---------- src/events.ts | 21 +++++++------- src/index.ts | 1 + src/types.ts | 11 +++++--- 12 files changed, 61 insertions(+), 50 deletions(-) create mode 100644 src/constants.ts diff --git a/hardhat-scripts/constants/enums.ts b/hardhat-scripts/constants/enums.ts index 011570b2..9a349056 100644 --- a/hardhat-scripts/constants/enums.ts +++ b/hardhat-scripts/constants/enums.ts @@ -9,9 +9,9 @@ export enum CORE_CONTRACTS { } export enum EVMxCoreContracts { - WatcherPrecompile = "WatcherPrecompile", - WatcherPrecompileLimits = "WatcherPrecompileLimits", - WatcherPrecompileConfig = "WatcherPrecompileConfig", + Watcher = "Watcher", + ReqestHandler = "ReqestHandler", + Configurations = "Configurations", AuctionManager = "AuctionManager", FeesManager = "FeesManager", DeliveryHelper = "DeliveryHelper", diff --git a/hardhat-scripts/deploy/1.deploy.ts b/hardhat-scripts/deploy/1.deploy.ts index fdb51e5a..0f452059 100644 --- a/hardhat-scripts/deploy/1.deploy.ts +++ b/hardhat-scripts/deploy/1.deploy.ts @@ -125,31 +125,31 @@ const deployEVMxContracts = async () => { ); deployUtils = await deployContractWithProxy( - EVMxCoreContracts.WatcherPrecompileLimits, - `contracts/protocol/watcherPrecompile/WatcherPrecompileLimits.sol`, + EVMxCoreContracts.ReqestHandler, + `contracts/protocol/watcherPrecompile/ReqestHandler.sol`, [EVMxOwner, addressResolver.address, DEFAULT_MAX_LIMIT], proxyFactory, deployUtils ); deployUtils = await deployContractWithProxy( - EVMxCoreContracts.WatcherPrecompileConfig, - `contracts/protocol/watcherPrecompile/WatcherPrecompileConfig.sol`, + EVMxCoreContracts.Configurations, + `contracts/protocol/watcherPrecompile/Configurations.sol`, [EVMxOwner, addressResolver.address, EVMX_CHAIN_ID], proxyFactory, deployUtils ); deployUtils = await deployContractWithProxy( - EVMxCoreContracts.WatcherPrecompile, - `contracts/protocol/watcherPrecompile/core/WatcherPrecompile.sol`, + EVMxCoreContracts.Watcher, + `contracts/protocol/watcherPrecompile/core/Watcher.sol`, [ EVMxOwner, addressResolver.address, EXPIRY_TIME, EVMX_CHAIN_ID, - deployUtils.addresses[EVMxCoreContracts.WatcherPrecompileLimits], - deployUtils.addresses[EVMxCoreContracts.WatcherPrecompileConfig], + deployUtils.addresses[EVMxCoreContracts.ReqestHandler], + deployUtils.addresses[EVMxCoreContracts.Configurations], ], proxyFactory, deployUtils @@ -222,13 +222,13 @@ const deployEVMxContracts = async () => { addressResolver, "watcherPrecompile__", "setWatcherPrecompile", - deployUtils.addresses[EVMxCoreContracts.WatcherPrecompile], + deployUtils.addresses[EVMxCoreContracts.Watcher], deployUtils.signer ); let watcherPrecompileLimits = await getInstance( - EVMxCoreContracts.WatcherPrecompileLimits, - deployUtils.addresses[EVMxCoreContracts.WatcherPrecompileLimits] + EVMxCoreContracts.ReqestHandler, + deployUtils.addresses[EVMxCoreContracts.ReqestHandler] ); watcherPrecompileLimits = watcherPrecompileLimits.connect( deployUtils.signer diff --git a/hardhat-scripts/deploy/2.roles.ts b/hardhat-scripts/deploy/2.roles.ts index 8ef83acc..d313e104 100644 --- a/hardhat-scripts/deploy/2.roles.ts +++ b/hardhat-scripts/deploy/2.roles.ts @@ -108,7 +108,7 @@ async function setRolesForEVMx(addresses: DeploymentAddresses) { {}) as ChainAddressesObj; const signer = await getSigner(EVMX_CHAIN_ID, true); - const contractAddress = chainAddresses[EVMxCoreContracts.WatcherPrecompile]; + const contractAddress = chainAddresses[EVMxCoreContracts.Watcher]; if (!contractAddress) return; await setRoleForContract( diff --git a/hardhat-scripts/deploy/3.upgradeManagers.ts b/hardhat-scripts/deploy/3.upgradeManagers.ts index 2c3a261c..92c24b1e 100644 --- a/hardhat-scripts/deploy/3.upgradeManagers.ts +++ b/hardhat-scripts/deploy/3.upgradeManagers.ts @@ -60,8 +60,8 @@ async function setOnchainContracts(chain: number, addresses) { const chainAddresses = addresses[chain] as ChainAddressesObj; const watcherPrecompileConfig = ( await getInstance( - EVMxCoreContracts.WatcherPrecompileConfig, - EVMxAddresses[EVMxCoreContracts.WatcherPrecompileConfig] + EVMxCoreContracts.Configurations, + EVMxAddresses[EVMxCoreContracts.Configurations] ) ).connect(signer); diff --git a/hardhat-scripts/deploy/4.connect.ts b/hardhat-scripts/deploy/4.connect.ts index 71223808..59efc2a6 100644 --- a/hardhat-scripts/deploy/4.connect.ts +++ b/hardhat-scripts/deploy/4.connect.ts @@ -165,8 +165,8 @@ export const updateConfigEVMx = async () => { const EVMxAddresses = addresses[EVMX_CHAIN_ID]!; const watcherPrecompileConfig = ( await getInstance( - EVMxCoreContracts.WatcherPrecompileConfig, - EVMxAddresses[EVMxCoreContracts.WatcherPrecompileConfig] + EVMxCoreContracts.Configurations, + EVMxAddresses[EVMxCoreContracts.Configurations] ) ).connect(signer); diff --git a/hardhat-scripts/deploy/6.setupEnv.ts b/hardhat-scripts/deploy/6.setupEnv.ts index 1fe5cc72..02e27607 100644 --- a/hardhat-scripts/deploy/6.setupEnv.ts +++ b/hardhat-scripts/deploy/6.setupEnv.ts @@ -22,7 +22,7 @@ const updatedLines = lines.map((line) => { if (line.startsWith("ADDRESS_RESOLVER=")) { return `ADDRESS_RESOLVER=${latestEVMxAddresses["AddressResolver"]}`; } else if (line.startsWith("WATCHER_PRECOMPILE=")) { - return `WATCHER_PRECOMPILE=${latestEVMxAddresses["WatcherPrecompile"]}`; + return `WATCHER_PRECOMPILE=${latestEVMxAddresses["Watcher"]}`; } else if (line.startsWith("AUCTION_MANAGER=")) { return `AUCTION_MANAGER=${latestEVMxAddresses["AuctionManager"]}`; } else if (line.startsWith("FEES_MANAGER=")) { diff --git a/package.json b/package.json index 86bf9215..edac1f42 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "publishConfig": { "access": "public" }, - "version": "1.1.15", + "version": "1.1.15-solana-test.1", "description": "socket protocol", "scripts": { "build": "yarn abi && tsc --project lib.tsconfig.json", diff --git a/src/constants.ts b/src/constants.ts new file mode 100644 index 00000000..6e5164bb --- /dev/null +++ b/src/constants.ts @@ -0,0 +1,5 @@ +import { keccak256 } from "ethers/lib/utils"; + +export const READ = keccak256(Buffer.from("READ")).substring(0, 10); +export const WRITE = keccak256(Buffer.from("WRITE")).substring(0, 10); +export const SCHEDULE = keccak256(Buffer.from("SCHEDULE")).substring(0, 10); diff --git a/src/enums.ts b/src/enums.ts index 689543ce..ad2efefb 100644 --- a/src/enums.ts +++ b/src/enums.ts @@ -16,7 +16,7 @@ export enum Events { // FeesPlug FeesDeposited = "FeesDeposited", - // WatcherPrecompile + // Watcher CalledAppGateway = "CalledAppGateway", QueryRequested = "QueryRequested", FinalizeRequested = "FinalizeRequested", @@ -27,6 +27,9 @@ export enum Events { RequestSubmitted = "RequestSubmitted", Finalized = "Finalized", MarkedRevert = "MarkedRevert", + ReadRequested = "ReadRequested", + WriteProofRequested = "WriteProofRequested", + WriteProofUploaded = "WriteProofUploaded", // AuctionManager AuctionEnded = "AuctionEnded", AuctionRestarted = "AuctionRestarted", @@ -41,25 +44,25 @@ export enum Events { export enum Contracts { Socket = "Socket", FeesPlug = "FeesPlug", - WatcherPrecompile = "WatcherPrecompile", - WatcherPrecompileLimits = "WatcherPrecompileLimits", - WatcherPrecompileConfig = "WatcherPrecompileConfig", - AuctionManager = "AuctionManager", - DeliveryHelper = "DeliveryHelper", -} + ContractFactoryPlug = "ContractFactoryPlug", + FastSwitchboard = "FastSwitchboard", + SocketBatcher = "SocketBatcher", -export enum CallType { - READ, - WRITE, - DEPLOY, - WITHDRAW, + AddressResolver = "AddressResolver", + Watcher = "Watcher", + RequestHandler = "RequestHandler", + Configurations = "Configurations", + PromiseResolver = "PromiseResolver", + AuctionManager = "AuctionManager", + FeesManager = "FeesManager", + WritePrecompile = "WritePrecompile", + ReadPrecompile = "ReadPrecompile", } export enum CallTypeNames { READ = "READ", WRITE = "WRITE", - DEPLOY = "DEPLOY", - WITHDRAW = "WITHDRAW", + SCHEDULE = "SCHEDULE", } export enum FinalityBucket { diff --git a/src/events.ts b/src/events.ts index b12fa610..d9649775 100644 --- a/src/events.ts +++ b/src/events.ts @@ -9,26 +9,25 @@ export const socketEvents = [ export const feesPlugEvents = [Events.FeesDeposited]; -export const watcherPrecompileEvents = [ +export const watcherEvents = [ Events.CalledAppGateway, Events.AppGatewayCallFailed, - Events.RequestSubmitted, - Events.QueryRequested, - Events.FinalizeRequested, - Events.Finalized, - Events.PromiseResolved, - Events.PromiseNotResolved, Events.TimeoutRequested, Events.TimeoutResolved, - Events.MarkedRevert, ]; -export const deliveryHelperEvents = [ - Events.PayloadSubmitted, +export const requestHandlerEvents = [ + Events.RequestSubmitted, Events.FeesIncreased, - Events.RequestCancelled, + Events.RequestCancelled ]; +export const writePrecompileEvents = [Events.Finalized]; + +export const readPrecompileEvents = [Events.ReadRequested]; + +export const promiseResolverEvents = [Events.PromiseResolved, Events.PromiseNotResolved]; + export const auctionManagerEvents = [ Events.AuctionEnded, Events.AuctionRestarted, diff --git a/src/index.ts b/src/index.ts index 24e89c47..29579d68 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,3 +3,4 @@ export * from "./enums"; export * from "./events"; export * from "./finality"; export * from "./types"; +export * from "./constants"; \ No newline at end of file diff --git a/src/types.ts b/src/types.ts index 8a738fbd..87cfc9d9 100644 --- a/src/types.ts +++ b/src/types.ts @@ -21,17 +21,20 @@ export type ChainAddressesObj = { FastSwitchboard: string; FeesPlug: string; ContractFactoryPlug: string; + TestUSDC: string; startBlock: number; }; export type EVMxAddressesObj = { AddressResolver: string; - WatcherPrecompile: string; - WatcherPrecompileLimits: string; - WatcherPrecompileConfig: string; + RequestHandler: string; + Configurations: string; + PromiseResolver: string; AuctionManager: string; FeesManager: string; - DeliveryHelper: string; + WritePrecompile: string; + ReadPrecompile: string; + Watcher: string; startBlock: number; }; From 750374232ccdab4104ebb58cbc7332ae135f0420 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Mon, 26 May 2025 12:03:14 +0530 Subject: [PATCH 047/130] fix: allow transfer for all watcher contracts --- contracts/evmx/fees/Credit.sol | 2 +- contracts/evmx/helpers/AddressResolverUtil.sol | 9 +++++---- contracts/evmx/interfaces/IWatcher.sol | 2 ++ contracts/evmx/watcher/Watcher.sol | 7 ++++++- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/contracts/evmx/fees/Credit.sol b/contracts/evmx/fees/Credit.sol index 5166af32..7c2583a9 100644 --- a/contracts/evmx/fees/Credit.sol +++ b/contracts/evmx/fees/Credit.sol @@ -130,7 +130,7 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressR uint256 amount_ ) public view override returns (bool) { // If consumeFrom_ is not same as spender_ or spender_ is not watcher, check if it is approved - if (spender_ != address(watcher__()) && consumeFrom_ != spender_) { + if (!_isWatcher(spender_) && consumeFrom_ != spender_) { if (!isApproved[consumeFrom_][spender_]) return false; } diff --git a/contracts/evmx/helpers/AddressResolverUtil.sol b/contracts/evmx/helpers/AddressResolverUtil.sol index 6ba12c34..bebf71cf 100644 --- a/contracts/evmx/helpers/AddressResolverUtil.sol +++ b/contracts/evmx/helpers/AddressResolverUtil.sol @@ -22,13 +22,14 @@ abstract contract AddressResolverUtil { /// @notice Restricts function access to the watcher precompile contract /// @dev Validates that msg.sender matches the registered watcher precompile address modifier onlyWatcher() { - if (msg.sender != address(addressResolver__.watcher__())) { - revert OnlyWatcherAllowed(); - } - + if (!_isWatcher(msg.sender)) revert OnlyWatcherAllowed(); _; } + function _isWatcher(address account_) internal view returns (bool) { + return (watcher__().isWatcher(account_) || account_ == address(watcher__())); + } + /// @notice Gets the watcher precompile contract interface /// @return IWatcher interface of the registered watcher precompile /// @dev Resolves and returns the watcher precompile contract for interaction diff --git a/contracts/evmx/interfaces/IWatcher.sol b/contracts/evmx/interfaces/IWatcher.sol index 5ef1b426..6831e19d 100644 --- a/contracts/evmx/interfaces/IWatcher.sol +++ b/contracts/evmx/interfaces/IWatcher.sol @@ -76,4 +76,6 @@ interface IWatcher { bytes4 precompile_, bytes memory precompileData_ ) external view returns (uint256); + + function isWatcher(address account_) external view returns (bool); } diff --git a/contracts/evmx/watcher/Watcher.sol b/contracts/evmx/watcher/Watcher.sol index a9a34f32..3b646c1b 100644 --- a/contracts/evmx/watcher/Watcher.sol +++ b/contracts/evmx/watcher/Watcher.sol @@ -18,7 +18,12 @@ contract Watcher is Trigger { _initializeOwner(owner_); } - // todo: add withdraw credit function + function isWatcher(address account_) public view override returns (bool) { + return + account_ == address(requestHandler__) || + account_ == address(configurations__) || + account_ == address(promiseResolver__); + } function queueAndSubmit( QueueParams memory queue_, From 00f25972bd0ad9d796e09133b7407a3f3dc06f8c Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Mon, 26 May 2025 12:23:51 +0530 Subject: [PATCH 048/130] fix: script build --- contracts/evmx/base/AppGatewayBase.sol | 9 +++++++-- contracts/evmx/fees/Credit.sol | 4 ++-- script/admin/RescueFunds.s.sol | 2 +- script/counter/DeployEVMxCounterApp.s.sol | 1 - script/counter/DeployOnchainCounters.s.sol | 1 - script/counter/SetFees.s.sol | 1 - script/counter/WithdrawFeesArbitrumFeesPlug.s.sol | 12 +++++++++--- ...yFeeBalance.s.sol => CheckDepositedCredits.s.sol} | 5 ++--- ...ayFeesInArbitrumETH.s.sol => DepositCredit.s.sol} | 11 ++++++----- ...umTestUSDC.s.sol => DepositCreditAndNative.s.sol} | 12 ++++++------ 10 files changed, 33 insertions(+), 25 deletions(-) rename script/helpers/{AppGatewayFeeBalance.s.sol => CheckDepositedCredits.s.sol} (81%) rename script/helpers/{PayFeesInArbitrumETH.s.sol => DepositCredit.s.sol} (68%) rename script/helpers/{PayFeesInArbitrumTestUSDC.s.sol => DepositCreditAndNative.s.sol} (73%) diff --git a/contracts/evmx/base/AppGatewayBase.sol b/contracts/evmx/base/AppGatewayBase.sol index 19cb3495..b4181e02 100644 --- a/contracts/evmx/base/AppGatewayBase.sol +++ b/contracts/evmx/base/AppGatewayBase.sol @@ -120,6 +120,10 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { ///////////////////////////////// DEPLOY HELPERS /////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// + function _deploy(bytes32 contractId_, uint32 chainSlug_, IsPlug isPlug_) internal { + _deploy(contractId_, chainSlug_, isPlug_, bytes("")); + } + /// @notice Deploys a contract /// @param contractId_ The contract ID /// @param chainSlug_ The chain slug @@ -321,13 +325,14 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { /// @param token_ The token address /// @param amount_ The amount /// @param receiver_ The receiver address - function _withdrawFeeTokens( + function _withdrawCredits( uint32 chainSlug_, address token_, uint256 amount_, + uint256 maxFees_, address receiver_ ) internal { - feesManager__().withdrawCredits(chainSlug_, token_, amount_, maxFees, receiver_); + feesManager__().withdrawCredits(chainSlug_, token_, amount_, maxFees_, receiver_); } //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/contracts/evmx/fees/Credit.sol b/contracts/evmx/fees/Credit.sol index 7c2583a9..c3bb856f 100644 --- a/contracts/evmx/fees/Credit.sol +++ b/contracts/evmx/fees/Credit.sol @@ -88,7 +88,7 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressR userCredit.totalCredits += creditAmount_; // if native transfer fails, add to credit - bool success = SafeTransferLib.trySafeTransferETH(depositTo_, nativeAmount_); + bool success = SafeTransferLib.trySafeTransferETH(depositTo_, nativeAmount_, gasleft()); if (!success) userCredit.totalCredits += nativeAmount_; emit CreditsDeposited(chainSlug_, depositTo_, token_, creditAmount_); @@ -196,7 +196,7 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressR // Check if amount is available in fees plug uint256 availableCredits = getAvailableCredits(consumeFrom); - if (availableCredits < credits_) revert InsufficientCreditsAvailable(); + if (availableCredits < credits_ + maxFees_) revert InsufficientCreditsAvailable(); userCredits[consumeFrom].totalCredits -= credits_; tokenOnChainBalances[chainSlug_][token_] -= credits_; diff --git a/script/admin/RescueFunds.s.sol b/script/admin/RescueFunds.s.sol index d1268058..a880b61c 100644 --- a/script/admin/RescueFunds.s.sol +++ b/script/admin/RescueFunds.s.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; import {Script} from "forge-std/Script.sol"; import {console} from "forge-std/console.sol"; -import {FeesPlug} from "../../contracts/evmx/payload-delivery/FeesPlug.sol"; +import {FeesPlug} from "../../contracts/evmx/plugs/FeesPlug.sol"; contract RescueFundsScript is Script { address constant NATIVE_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; diff --git a/script/counter/DeployEVMxCounterApp.s.sol b/script/counter/DeployEVMxCounterApp.s.sol index 79c916c8..96111337 100644 --- a/script/counter/DeployEVMxCounterApp.s.sol +++ b/script/counter/DeployEVMxCounterApp.s.sol @@ -4,7 +4,6 @@ pragma solidity ^0.8.21; import {Script} from "forge-std/Script.sol"; import {console} from "forge-std/console.sol"; import {CounterAppGateway} from "../../test/apps/app-gateways/counter/CounterAppGateway.sol"; -import {ETH_ADDRESS} from "../../contracts/utils/common/Constants.sol"; // source .env && forge script script/counter/deployEVMxCounterApp.s.sol --broadcast --skip-simulation --legacy --gas-price 0 contract CounterDeploy is Script { diff --git a/script/counter/DeployOnchainCounters.s.sol b/script/counter/DeployOnchainCounters.s.sol index 3edb7b78..a6a30757 100644 --- a/script/counter/DeployOnchainCounters.s.sol +++ b/script/counter/DeployOnchainCounters.s.sol @@ -3,7 +3,6 @@ pragma solidity ^0.8.21; import {Script} from "forge-std/Script.sol"; import {console} from "forge-std/console.sol"; -import {ETH_ADDRESS} from "../../contracts/utils/common/Constants.sol"; import {CounterAppGateway} from "../../test/apps/app-gateways/counter/CounterAppGateway.sol"; // source .env && forge script script/counter/DeployCounterOnchain.s.sol --broadcast --skip-simulation --legacy --gas-price 0 diff --git a/script/counter/SetFees.s.sol b/script/counter/SetFees.s.sol index b365f64b..a52b1cb8 100644 --- a/script/counter/SetFees.s.sol +++ b/script/counter/SetFees.s.sol @@ -3,7 +3,6 @@ pragma solidity ^0.8.21; import {Script} from "forge-std/Script.sol"; import {console} from "forge-std/console.sol"; -import {ETH_ADDRESS} from "../../contracts/utils/common/Constants.sol"; import {CounterAppGateway} from "../../test/apps/app-gateways/counter/CounterAppGateway.sol"; // source .env && forge script script/counter/DeployCounterOnchain.s.sol --broadcast --skip-simulation --legacy --gas-price 0 diff --git a/script/counter/WithdrawFeesArbitrumFeesPlug.s.sol b/script/counter/WithdrawFeesArbitrumFeesPlug.s.sol index b69a2c9a..dc8834ed 100644 --- a/script/counter/WithdrawFeesArbitrumFeesPlug.s.sol +++ b/script/counter/WithdrawFeesArbitrumFeesPlug.s.sol @@ -4,7 +4,6 @@ pragma solidity ^0.8.21; import {Script} from "forge-std/Script.sol"; import {console} from "forge-std/console.sol"; import {FeesManager} from "../../contracts/evmx/fees/FeesManager.sol"; -import {ETH_ADDRESS} from "../../contracts/utils/common/Constants.sol"; import {CounterAppGateway} from "../../test/apps/app-gateways/counter/CounterAppGateway.sol"; // @notice This script is used to withdraw fees from EVMX to Arbitrum Sepolia @@ -15,9 +14,10 @@ contract WithdrawFees is Script { vm.createSelectFork(vm.envString("EVMX_RPC")); FeesManager feesManager = FeesManager(payable(vm.envAddress("FEES_MANAGER"))); address appGatewayAddress = vm.envAddress("APP_GATEWAY"); + address token = vm.envAddress("USDC"); CounterAppGateway appGateway = CounterAppGateway(appGatewayAddress); - uint256 availableFees = feesManager.getMaxCreditsAvailableForWithdraw(appGatewayAddress); + uint256 availableFees = feesManager.getAvailableCredits(appGatewayAddress); console.log("Available fees:", availableFees); if (availableFees > 0) { @@ -45,7 +45,13 @@ contract WithdrawFees is Script { vm.createSelectFork(vm.envString("EVMX_RPC")); vm.startBroadcast(privateKey); console.log("Withdrawing amount:", amountToWithdraw); - appGateway.withdrawFeeTokens(421614, ETH_ADDRESS, amountToWithdraw, sender); + appGateway.withdrawCredits( + 421614, + token, + amountToWithdraw, + estimatedGasCost, + sender + ); vm.stopBroadcast(); // Switch back to Arbitrum Sepolia to check final balance diff --git a/script/helpers/AppGatewayFeeBalance.s.sol b/script/helpers/CheckDepositedCredits.s.sol similarity index 81% rename from script/helpers/AppGatewayFeeBalance.s.sol rename to script/helpers/CheckDepositedCredits.s.sol index 2911c527..ad9bca71 100644 --- a/script/helpers/AppGatewayFeeBalance.s.sol +++ b/script/helpers/CheckDepositedCredits.s.sol @@ -3,10 +3,9 @@ pragma solidity ^0.8.21; import {Script} from "forge-std/Script.sol"; import {console} from "forge-std/console.sol"; -import {FeesManager} from "../../contracts/evmx/payload-delivery/FeesManager.sol"; -import {ETH_ADDRESS} from "../../contracts/utils/common/Constants.sol"; +import {FeesManager} from "../../contracts/evmx/fees/FeesManager.sol"; -contract CheckDepositedFees is Script { +contract CheckDepositedCredits is Script { function run() external { vm.createSelectFork(vm.envString("EVMX_RPC")); FeesManager feesManager = FeesManager(payable(vm.envAddress("FEES_MANAGER"))); diff --git a/script/helpers/PayFeesInArbitrumETH.s.sol b/script/helpers/DepositCredit.s.sol similarity index 68% rename from script/helpers/PayFeesInArbitrumETH.s.sol rename to script/helpers/DepositCredit.s.sol index b7d5b887..4088d142 100644 --- a/script/helpers/PayFeesInArbitrumETH.s.sol +++ b/script/helpers/DepositCredit.s.sol @@ -3,17 +3,18 @@ pragma solidity ^0.8.21; import {Script} from "forge-std/Script.sol"; import {console} from "forge-std/console.sol"; -import {FeesPlug} from "../../contracts/evmx/payload-delivery/FeesPlug.sol"; -import {ETH_ADDRESS} from "../../contracts/utils/common/Constants.sol"; +import {FeesPlug} from "../../contracts/evmx/plugs/FeesPlug.sol"; +import {TestUSDC} from "../../contracts/evmx/mocks/TestUSDC.sol"; -// source .env && forge script script/helpers/PayFeesInArbitrumETH.s.sol --broadcast --skip-simulation -contract DepositFees is Script { +// source .env && forge script script/helpers/DepositCredit.s.sol --broadcast --skip-simulation +contract DepositCredit is Script { function run() external { vm.createSelectFork(vm.envString("ARBITRUM_SEPOLIA_RPC")); uint256 privateKey = vm.envUint("PRIVATE_KEY"); vm.startBroadcast(privateKey); FeesPlug feesPlug = FeesPlug(payable(vm.envAddress("ARBITRUM_FEES_PLUG"))); + TestUSDC token = TestUSDC(vm.envAddress("USDC")); address appGateway = vm.envAddress("APP_GATEWAY"); address sender = vm.addr(privateKey); @@ -23,6 +24,6 @@ contract DepositFees is Script { console.log("App Gateway:", appGateway); console.log("Fees Plug:", address(feesPlug)); uint feesAmount = 0.001 ether; - feesPlug.depositToFeeAndNative(ETH_ADDRESS, appGateway, feesAmount); + feesPlug.depositCredit(address(token), appGateway, feesAmount); } } diff --git a/script/helpers/PayFeesInArbitrumTestUSDC.s.sol b/script/helpers/DepositCreditAndNative.s.sol similarity index 73% rename from script/helpers/PayFeesInArbitrumTestUSDC.s.sol rename to script/helpers/DepositCreditAndNative.s.sol index daf9b08e..a9eb6c2f 100644 --- a/script/helpers/PayFeesInArbitrumTestUSDC.s.sol +++ b/script/helpers/DepositCreditAndNative.s.sol @@ -3,11 +3,11 @@ pragma solidity ^0.8.21; import {Script} from "forge-std/Script.sol"; import {console} from "forge-std/console.sol"; -import {FeesPlug} from "../../contracts/evmx/payload-delivery/FeesPlug.sol"; -import {ETH_ADDRESS} from "../../contracts/utils/common/Constants.sol"; -import {TestUSDC} from "../../contracts/evmx/helpers/TestUSDC.sol"; -// source .env && forge script script/helpers/PayFeesInArbitrumETH.s.sol --broadcast --skip-simulation -contract DepositFees is Script { +import {FeesPlug} from "../../contracts/evmx/plugs/FeesPlug.sol"; +import {TestUSDC} from "../../contracts/evmx/mocks/TestUSDC.sol"; + +// source .env && forge script script/helpers/DepositCreditAndNative.s.sol --broadcast --skip-simulation +contract DepositCreditAndNative is Script { function run() external { uint256 feesAmount = 100000000; vm.createSelectFork(vm.envString("ARBITRUM_SEPOLIA_RPC")); @@ -30,6 +30,6 @@ contract DepositFees is Script { console.log("App Gateway:", appGateway); console.log("Fees Plug:", address(feesPlug)); console.log("Fees Amount:", feesAmount); - feesPlug.depositToFeeAndNative(address(testUSDCContract), appGateway, feesAmount); + feesPlug.depositCreditAndNative(address(testUSDCContract), appGateway, feesAmount); } } From 42f5be3e6d660e7c4ab0c499f9c00e01f468244e Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Mon, 26 May 2025 12:24:05 +0530 Subject: [PATCH 049/130] fix: test imports --- test/DeliveryHelper.t.sol | 37 +++-- test/Migration.t.sol | 10 +- test/SetupTest.t.sol | 141 ++++++++---------- test/SocketFeeManager.t.sol | 4 +- test/apps/SuperToken.t.sol | 1 - .../counter/CounterAppGateway.sol | 29 ++-- .../super-token/SuperTokenAppGateway.sol | 4 +- test/mock/MockFastSwitchboard.sol | 4 +- test/mock/MockSocket.sol | 4 +- test/mock/MockWatcherPrecompile.sol | 118 +-------------- test/mock/MockWatcherPrecompileImpl.sol | 13 -- 11 files changed, 112 insertions(+), 253 deletions(-) delete mode 100644 test/mock/MockWatcherPrecompileImpl.sol diff --git a/test/DeliveryHelper.t.sol b/test/DeliveryHelper.t.sol index a14321b7..f051ce3d 100644 --- a/test/DeliveryHelper.t.sol +++ b/test/DeliveryHelper.t.sol @@ -1,13 +1,15 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import "../contracts/evmx/payload-delivery/app-gateway/DeliveryHelper.sol"; -import "../contracts/evmx/payload-delivery/FeesManager.sol"; -import "../contracts/evmx/payload-delivery/AuctionManager.sol"; - -import "../contracts/evmx/Forwarder.sol"; +import "../contracts/evmx/watcher/Watcher.sol"; +import "../contracts/evmx/fees/Credit.sol"; +import "../contracts/evmx/watcher/Watcher.sol"; +import "../contracts/evmx/AuctionManager.sol"; +import "../contracts/evmx/helpers/Forwarder.sol"; import "../contracts/evmx/interfaces/IAppGateway.sol"; +import "../contracts/evmx/fees/FeesManager.sol"; + import "./SetupTest.t.sol"; interface IAppGatewayDeployer { @@ -23,14 +25,13 @@ contract DeliveryHelperTest is SetupTest { uint256 public auctionEndDelaySeconds = 0; uint256 public bidTimeout = 86400; - DeliveryHelper deliveryHelper; FeesManager feesManager; AuctionManager auctionManager; event PayloadSubmitted( uint40 indexed requestCount, address indexed appGateway, - PayloadSubmitParams[] payloadSubmitParams, + PayloadParams[] payloadParams, uint256 maxFees, address auctionManager, bool onlyReadRequests @@ -186,7 +187,7 @@ contract DeliveryHelperTest is SetupTest { //////////////////////////////////// Fees //////////////////////////////////// - function depositUSDCFees(address appGateway_, OnChainFees memory fees_) internal { + function depositUSDCFees(address appGateway_, uint256 fees_) internal { SocketContracts memory socketConfig = getSocketConfig(fees_.chainSlug); vm.startPrank(owner); ERC20(fees_.token).approve(address(socketConfig.feesPlug), fees_.amount); @@ -394,35 +395,31 @@ contract DeliveryHelperTest is SetupTest { //////////////////////////////////// Validators //////////////////////////////////// function checkPayloadRequestAndDetails( - PayloadSubmitParams[] memory payloadSubmitParams, + PayloadParams[] memory payloadParams, uint40 requestCount, address appGateway_ ) internal view { - for (uint i = 0; i < payloadSubmitParams.length; i++) { - PayloadSubmitParams memory payloadSubmitParam = payloadSubmitParams[i]; + for (uint i = 0; i < payloadParams.length; i++) { + PayloadParams memory payloadSubmitParam = payloadParams[i]; assertEq( payloadSubmitParam.chainSlug, - payloadSubmitParams[i].chainSlug, + payloadParams[i].chainSlug, "ChainSlug mismatch" ); // todo - assertEq(payloadSubmitParam.target, payloadSubmitParams[i].target, "Target mismatch"); + assertEq(payloadSubmitParam.target, payloadParams[i].target, "Target mismatch"); assertEq( keccak256(payloadSubmitParam.payload), - keccak256(payloadSubmitParams[i].payload), + keccak256(payloadParams[i].payload), "Payload mismatch" ); assertEq( uint(payloadSubmitParam.callType), - uint(payloadSubmitParams[i].callType), + uint(payloadParams[i].callType), "CallType mismatch" ); - assertEq( - payloadSubmitParam.gasLimit, - payloadSubmitParams[i].gasLimit, - "gasLimit mismatch" - ); + assertEq(payloadSubmitParam.gasLimit, payloadParams[i].gasLimit, "gasLimit mismatch"); } RequestMetadata memory payloadRequest = deliveryHelper.getRequestMetadata(requestCount); diff --git a/test/Migration.t.sol b/test/Migration.t.sol index fa7b05cb..45f8c4f6 100644 --- a/test/Migration.t.sol +++ b/test/Migration.t.sol @@ -2,12 +2,10 @@ pragma solidity ^0.8.21; import "./SetupTest.t.sol"; -import "../contracts/evmx/AddressResolver.sol"; -import "../contracts/evmx/watcherPrecompile/core/WatcherPrecompile.sol"; -import "../contracts/evmx/watcherPrecompile/WatcherPrecompileLimits.sol"; -import "../contracts/evmx/watcherPrecompile/WatcherPrecompileConfig.sol"; -import "../contracts/evmx/Forwarder.sol"; -import "../contracts/evmx/AsyncPromise.sol"; +import "../contracts/evmx/helpers/AddressResolver.sol"; +import "../contracts/evmx/watcher/Watcher.sol"; +import "../contracts/evmx/helpers/Forwarder.sol"; +import "../contracts/evmx/helpers/AsyncPromise.sol"; import "./mock/MockWatcherPrecompileImpl.sol"; contract MigrationTest is SetupTest { diff --git a/test/SetupTest.t.sol b/test/SetupTest.t.sol index 8153cd27..6a01c30c 100644 --- a/test/SetupTest.t.sol +++ b/test/SetupTest.t.sol @@ -5,27 +5,25 @@ import "forge-std/Test.sol"; import "../contracts/utils/common/Structs.sol"; import "../contracts/utils/common/Errors.sol"; import "../contracts/utils/common/Constants.sol"; -import "../contracts/evmx/watcherPrecompile/core/WatcherPrecompile.sol"; -import "../contracts/evmx/watcherPrecompile/WatcherPrecompileConfig.sol"; -import "../contracts/evmx/watcherPrecompile/WatcherPrecompileLimits.sol"; -import "../contracts/evmx/watcherPrecompile/PayloadHeaderDecoder.sol"; +import "../contracts/evmx/watcher/Watcher.sol"; +import "../contracts/evmx/watcher/Configurations.sol"; import "../contracts/evmx/interfaces/IForwarder.sol"; import "../contracts/utils/common/AccessRoles.sol"; import {Socket} from "../contracts/protocol/Socket.sol"; import "../contracts/protocol/switchboard/FastSwitchboard.sol"; import "../contracts/protocol/SocketBatcher.sol"; -import "../contracts/evmx/AddressResolver.sol"; -import {ContractFactoryPlug} from "../contracts/evmx/payload-delivery/ContractFactoryPlug.sol"; -import {FeesPlug} from "../contracts/evmx/payload-delivery/FeesPlug.sol"; +import "../contracts/evmx/helpers/AddressResolver.sol"; +import {ContractFactoryPlug} from "../contracts/evmx/plugs/ContractFactoryPlug.sol"; +import {FeesPlug} from "../contracts/evmx/plugs/FeesPlug.sol"; import {SocketFeeManager} from "../contracts/protocol/SocketFeeManager.sol"; -import {ETH_ADDRESS} from "../contracts/utils/common/Constants.sol"; -import {ResolvedPromises, OnChainFees} from "../contracts/utils/common/Structs.sol"; +import "../contracts/utils/common/Structs.sol"; + +import "../contracts/evmx/helpers/AsyncDeployer.sol"; import "solady/utils/ERC1967Factory.sol"; import "./apps/app-gateways/USDC.sol"; contract SetupTest is Test { - using PayloadHeaderDecoder for bytes32; uint public c = 1; address owner = address(uint160(c++)); @@ -63,17 +61,19 @@ contract SetupTest is Test { } AddressResolver public addressResolver; - WatcherPrecompile public watcherPrecompile; - WatcherPrecompileConfig public watcherPrecompileConfig; - WatcherPrecompileLimits public watcherPrecompileLimits; + Watcher public watcher; + Configurations public configurations; + AsyncDeployer public asyncDeployer; + AsyncPromise public asyncPromise; SocketContracts public arbConfig; SocketContracts public optConfig; // Add new variables for proxy admin and implementation contracts - WatcherPrecompile public watcherPrecompileImpl; - WatcherPrecompileConfig public watcherPrecompileConfigImpl; - WatcherPrecompileLimits public watcherPrecompileLimitsImpl; + Watcher public watcherImpl; + Configurations public configurationsImpl; + AsyncDeployer public asyncDeployerImpl; + AsyncPromise public asyncPromiseImpl; AddressResolver public addressResolverImpl; ERC1967Factory public proxyFactory; @@ -102,15 +102,14 @@ contract SetupTest is Test { vm.stopPrank(); hoax(watcherEOA); - watcherPrecompileConfig.setOnChainContracts( - chainSlug_, - address(socket), - address(contractFactoryPlug), - address(feesPlug) - ); + configurations.setSocket(chainSlug_, address(socket)); + + // todo: setters + // address(contractFactoryPlug), + // address(feesPlug) SocketFeeManager socketFeeManager = new SocketFeeManager(owner, socketFees); hoax(watcherEOA); - watcherPrecompileConfig.setSwitchboard(chainSlug_, FAST, address(switchboard)); + configurations.setSwitchboard(chainSlug_, FAST, address(switchboard)); return SocketContracts({ @@ -128,9 +127,10 @@ contract SetupTest is Test { function deployEVMxCore() internal { // Deploy implementations addressResolverImpl = new AddressResolver(); - watcherPrecompileImpl = new WatcherPrecompile(); - watcherPrecompileConfigImpl = new WatcherPrecompileConfig(); - watcherPrecompileLimitsImpl = new WatcherPrecompileLimits(); + watcherImpl = new Watcher(); + configurationsImpl = new Configurations(); + asyncDeployerImpl = new AsyncDeployer(); + asyncPromiseImpl = new AsyncPromise(); proxyFactory = new ERC1967Factory(); // Deploy and initialize proxies @@ -146,63 +146,49 @@ contract SetupTest is Test { addressResolverData ); - bytes memory watcherPrecompileLimitsData = abi.encodeWithSelector( - WatcherPrecompileLimits.initialize.selector, - watcherEOA, - address(addressResolverProxy), - defaultLimit - ); - vm.expectEmit(true, true, true, false); - emit Initialized(version); - address watcherPrecompileLimitsProxy = proxyFactory.deployAndCall( - address(watcherPrecompileLimitsImpl), - watcherEOA, - watcherPrecompileLimitsData - ); - - bytes memory watcherPrecompileConfigData = abi.encodeWithSelector( - WatcherPrecompileConfig.initialize.selector, + bytes memory configurationsData = abi.encodeWithSelector( + Configurations.initialize.selector, watcherEOA, address(addressResolverProxy), evmxSlug ); vm.expectEmit(true, true, true, false); emit Initialized(version); - address watcherPrecompileConfigProxy = proxyFactory.deployAndCall( - address(watcherPrecompileConfigImpl), + address configurationsProxy = proxyFactory.deployAndCall( + address(configurationsImpl), watcherEOA, - watcherPrecompileConfigData + configurationsData ); - bytes memory watcherPrecompileData = abi.encodeWithSelector( - WatcherPrecompile.initialize.selector, + bytes memory watcherData = abi.encodeWithSelector( + Watcher.initialize.selector, watcherEOA, address(addressResolverProxy), expiryTime, evmxSlug, - address(watcherPrecompileLimitsProxy), - address(watcherPrecompileConfigProxy) + address(configurationsProxy) ); vm.expectEmit(true, true, true, false); emit Initialized(version); - address watcherPrecompileProxy = proxyFactory.deployAndCall( - address(watcherPrecompileImpl), + address watcherProxy = proxyFactory.deployAndCall( + address(watcherImpl), watcherEOA, - watcherPrecompileData + watcherData ); // Assign proxy addresses to public variables addressResolver = AddressResolver(address(addressResolverProxy)); - watcherPrecompile = WatcherPrecompile(address(watcherPrecompileProxy)); - watcherPrecompileConfig = WatcherPrecompileConfig(address(watcherPrecompileConfigProxy)); - watcherPrecompileLimits = WatcherPrecompileLimits(address(watcherPrecompileLimitsProxy)); + watcher = Watcher(address(watcherProxy)); + configurations = Configurations(address(configurationsProxy)); + // asyncDeployer = AsyncDeployer(address(asyncDeployerProxy)); + // asyncPromise = AsyncPromise(address(asyncPromiseProxy)); vm.startPrank(watcherEOA); - addressResolver.setWatcherPrecompile(address(watcherPrecompile)); - watcherPrecompileLimits.setCallBackFees(1); - watcherPrecompileLimits.setFinalizeFees(1); - watcherPrecompileLimits.setQueryFees(1); - watcherPrecompileLimits.setTimeoutFees(1); + addressResolver.setWatcher(address(watcher)); + watcher.setCallBackFees(1); + watcher.setFinalizeFees(1); + watcher.setQueryFees(1); + watcher.setTimeoutFees(1); vm.stopPrank(); } @@ -210,11 +196,11 @@ contract SetupTest is Test { //////////////////////////////////// Watcher precompiles //////////////////////////////////// function _checkIfOnlyReads(uint40 batchCount_) internal view returns (bool) { - bytes32[] memory payloadIds = watcherPrecompile.getBatchPayloadIds(batchCount_); + bytes32[] memory payloadIds = watcher.getBatchPayloadIds(batchCount_); for (uint i = 0; i < payloadIds.length; i++) { - PayloadParams memory payloadParams = watcherPrecompile.getPayloadParams(payloadIds[i]); - if (payloadParams.payloadHeader.getCallType() != CallType.READ) { + PayloadParams memory payloadParams = watcher.getPayloadParams(payloadIds[i]); + if (payloadParams.payloadHeader.getCallType() != READ) { return false; } } @@ -242,13 +228,13 @@ contract SetupTest is Test { uint256 readCount_, bool hasMoreBatches ) internal returns (uint256) { - bytes32[] memory payloadIds = watcherPrecompile.getBatchPayloadIds(batchCount_); + bytes32[] memory payloadIds = watcher.getBatchPayloadIds(batchCount_); for (uint i = 0; i < payloadIds.length; i++) { - PayloadParams memory payloadParams = watcherPrecompile.getPayloadParams(payloadIds[i]); + PayloadParams memory payloadParams = watcher.getPayloadParams(payloadIds[i]); bool isLastPayload = i == payloadIds.length - 1 && hasMoreBatches; - if (payloadParams.payloadHeader.getCallType() == CallType.READ) { + if (payloadParams.payloadHeader.getCallType() == READ) { _resolveAndExpectFinalizeRequested( payloadParams.payloadId, payloadParams, @@ -321,7 +307,7 @@ contract SetupTest is Test { _encodeAppGatewayId(params_.appGateway), params_.prevDigestsHash ); - bytes32 digest = watcherPrecompile.getDigest(digestParams_); + bytes32 digest = watcher.getDigest(digestParams_); bytes32 sigDigest = keccak256( abi.encode(address(socketConfig.switchboard), socketConfig.chainSlug, digest) @@ -332,16 +318,13 @@ contract SetupTest is Test { function _writeProof(bytes32 payloadId_, bytes memory watcherProof_) internal { bytes memory bytesInput = abi.encode( - IWatcherPrecompile.finalized.selector, + IWatcher.finalized.selector, payloadId_, watcherProof_ ); - bytes memory watcherSignature = _createWatcherSignature( - address(watcherPrecompile), - bytesInput - ); - watcherPrecompile.finalized(payloadId_, watcherProof_, signatureNonce++, watcherSignature); - assertEq(watcherPrecompile.watcherProofs(payloadId_), watcherProof_); + bytes memory watcherSignature = _createWatcherSignature(address(watcher), bytesInput); + watcher.finalized(payloadId_, watcherProof_, signatureNonce++, watcherSignature); + assertEq(watcher.watcherProofs(payloadId_), watcherProof_); } function _getExecuteParams( @@ -385,14 +368,14 @@ contract SetupTest is Test { } function _resolvePromise(bytes32 payloadId, bytes memory returnData) internal { - ResolvedPromises[] memory resolvedPromises = new ResolvedPromises[](1); - resolvedPromises[0] = ResolvedPromises({payloadId: payloadId, returnData: returnData}); + PromiseReturnData[] memory promiseReturnData = new PromiseReturnData[](1); + promiseReturnData[0] = PromiseReturnData({payloadId: payloadId, returnData: returnData}); bytes memory watcherSignature = _createWatcherSignature( - address(watcherPrecompile), - abi.encode(WatcherPrecompile.resolvePromises.selector, resolvedPromises) + address(watcher), + abi.encode(Watcher.resolvePromises.selector, promiseReturnData) ); - watcherPrecompile.resolvePromises(resolvedPromises, signatureNonce++, watcherSignature); + watcher.resolvePromises(promiseReturnData, signatureNonce++, watcherSignature); } function _createWatcherSignature( diff --git a/test/SocketFeeManager.t.sol b/test/SocketFeeManager.t.sol index e81132ca..15dd67bf 100644 --- a/test/SocketFeeManager.t.sol +++ b/test/SocketFeeManager.t.sol @@ -6,7 +6,7 @@ import {Counter} from "./apps/app-gateways/counter/Counter.sol"; import "./SetupTest.t.sol"; import {SocketFeeManager} from "../contracts/protocol/SocketFeeManager.sol"; import {MockFastSwitchboard} from "./mock/MockFastSwitchboard.sol"; -import {ExecuteParams, TransmissionParams, CallType} from "../contracts/utils/common/Structs.sol"; +import {ExecuteParams, TransmissionParams} from "../contracts/utils/common/Structs.sol"; import {GOVERNANCE_ROLE, RESCUE_ROLE} from "../contracts/utils/common/AccessRoles.sol"; import {Test} from "forge-std/Test.sol"; @@ -126,7 +126,7 @@ contract SocketFeeManagerTest is SetupTest { bytes memory payload ) internal view returns (ExecuteParams memory, TransmissionParams memory) { ExecuteParams memory executeParams = ExecuteParams({ - callType: CallType.WRITE, + callType: WRITE, deadline: block.timestamp + 1 days, gasLimit: 100000, value: 0, diff --git a/test/apps/SuperToken.t.sol b/test/apps/SuperToken.t.sol index 9a5a4897..1454e13c 100644 --- a/test/apps/SuperToken.t.sol +++ b/test/apps/SuperToken.t.sol @@ -4,7 +4,6 @@ pragma solidity ^0.8.21; import {SuperTokenAppGateway} from "./app-gateways/super-token/SuperTokenAppGateway.sol"; import {SuperToken} from "./app-gateways/super-token/SuperToken.sol"; import "../DeliveryHelper.t.sol"; -import {QUERY, FINALIZE, SCHEDULE} from "../../contracts/utils/common/Constants.sol"; /** * @title SuperToken Test diff --git a/test/apps/app-gateways/counter/CounterAppGateway.sol b/test/apps/app-gateways/counter/CounterAppGateway.sol index fc87483d..258e18d4 100644 --- a/test/apps/app-gateways/counter/CounterAppGateway.sol +++ b/test/apps/app-gateways/counter/CounterAppGateway.sol @@ -25,7 +25,7 @@ contract CounterAppGateway is AppGatewayBase, Ownable { } // deploy contracts - function deployContracts(uint32 chainSlug_) external async(bytes("")) { + function deployContracts(uint32 chainSlug_) external async { _deploy(counter, chainSlug_, IsPlug.YES); } @@ -33,14 +33,14 @@ contract CounterAppGateway is AppGatewayBase, Ownable { _deploy(counter, chainSlug_, IsPlug.YES); } - function deployParallelContracts(uint32 chainSlug_) external async(bytes("")) { + function deployParallelContracts(uint32 chainSlug_) external async { _setOverrides(Parallel.ON); _deploy(counter, chainSlug_, IsPlug.YES); _deploy(counter1, chainSlug_, IsPlug.YES); _setOverrides(Parallel.OFF); } - function deployMultiChainContracts(uint32[] memory chainSlugs_) external async(bytes("")) { + function deployMultiChainContracts(uint32[] memory chainSlugs_) external async { _setOverrides(Parallel.ON); for (uint32 i = 0; i < chainSlugs_.length; i++) { _deploy(counter, chainSlugs_[i], IsPlug.YES); @@ -53,7 +53,7 @@ contract CounterAppGateway is AppGatewayBase, Ownable { return; } - function incrementCounters(address[] memory instances_) public async(bytes("")) { + function incrementCounters(address[] memory instances_) public async { // the increase function is called on given list of instances // this for (uint256 i = 0; i < instances_.length; i++) { @@ -69,7 +69,7 @@ contract CounterAppGateway is AppGatewayBase, Ownable { } } - function readCounters(address[] memory instances_) public async(bytes("")) { + function readCounters(address[] memory instances_) public async { // the increase function is called on given list of instances _setOverrides(Read.ON, Parallel.ON); for (uint256 i = 0; i < instances_.length; i++) { @@ -80,7 +80,7 @@ contract CounterAppGateway is AppGatewayBase, Ownable { _setOverrides(Read.OFF, Parallel.OFF); } - function readCounterAtBlock(address instance_, uint256 blockNumber_) public async(bytes("")) { + function readCounterAtBlock(address instance_, uint256 blockNumber_) public async { uint32 chainSlug = IForwarder(instance_).getChainSlug(); _setOverrides(Read.ON, Parallel.ON, blockNumber_); ICounter(instance_).getCounter(); @@ -99,7 +99,7 @@ contract CounterAppGateway is AppGatewayBase, Ownable { // trigger from a chain function setIsValidPlug(uint32 chainSlug_, address plug_) public { - watcherPrecompileConfig().setIsValidPlug(chainSlug_, plug_, true); + watcher__().configurations__().setIsValidPlug(true, chainSlug_, plug_); } function increase(uint256 value_) external onlyWatcher { @@ -107,7 +107,7 @@ contract CounterAppGateway is AppGatewayBase, Ownable { } // TIMEOUT - function setTimeout(uint256 delayInSeconds_) public async(bytes("")) { + function setTimeout(uint256 delayInSeconds_) public async { _setTimeout(delayInSeconds_); then(this.resolveTimeout.selector, abi.encode(block.timestamp)); } @@ -121,27 +121,28 @@ contract CounterAppGateway is AppGatewayBase, Ownable { maxFees = fees_; } - function withdrawFeeTokens( + function withdrawCredits( uint32 chainSlug_, address token_, uint256 amount_, + uint256 maxFees_, address receiver_ - ) external returns (uint40) { - return _withdrawFeeTokens(chainSlug_, token_, amount_, receiver_); + ) external { + _withdrawCredits(chainSlug_, token_, amount_, maxFees_, receiver_); } - function testOnChainRevert(uint32 chainSlug) public async(bytes("")) { + function testOnChainRevert(uint32 chainSlug) public async { address instance = forwarderAddresses[counter][chainSlug]; ICounter(instance).wrongFunction(); } - function testCallBackRevert(uint32 chainSlug) public async(bytes("")) { + function testCallBackRevert(uint32 chainSlug) public async { // the increase function is called on given list of instances _setOverrides(Read.ON, Parallel.ON); address instance = forwarderAddresses[counter][chainSlug]; ICounter(instance).getCounter(); // wrong function call in callback so it reverts - IPromise(instance).then(this.withdrawFeeTokens.selector, abi.encode(chainSlug)); + IPromise(instance).then(this.withdrawCredits.selector, abi.encode(chainSlug)); _setOverrides(Read.OFF, Parallel.OFF); } diff --git a/test/apps/app-gateways/super-token/SuperTokenAppGateway.sol b/test/apps/app-gateways/super-token/SuperTokenAppGateway.sol index aa88756f..5a362ccd 100644 --- a/test/apps/app-gateways/super-token/SuperTokenAppGateway.sol +++ b/test/apps/app-gateways/super-token/SuperTokenAppGateway.sol @@ -49,7 +49,7 @@ contract SuperTokenAppGateway is AppGatewayBase, Ownable { _initializeOwner(owner_); } - function deployContracts(uint32 chainSlug_) external async(bytes("")) { + function deployContracts(uint32 chainSlug_) external async { bytes memory initData = abi.encodeWithSelector(SuperToken.setOwner.selector, owner()); _deploy(superToken, chainSlug_, IsPlug.YES, initData); } @@ -60,7 +60,7 @@ contract SuperTokenAppGateway is AppGatewayBase, Ownable { return; } - function transfer(bytes memory order_) external async(bytes("")) { + function transfer(bytes memory order_) external async { TransferOrder memory order = abi.decode(order_, (TransferOrder)); ISuperToken(order.srcToken).burn(order.user, order.srcAmount); ISuperToken(order.dstToken).mint(order.user, order.srcAmount); diff --git a/test/mock/MockFastSwitchboard.sol b/test/mock/MockFastSwitchboard.sol index e516fe3d..284e88ca 100644 --- a/test/mock/MockFastSwitchboard.sol +++ b/test/mock/MockFastSwitchboard.sol @@ -22,9 +22,7 @@ contract MockFastSwitchboard is ISwitchboard { owner = owner_; } - function attest(bytes32, bytes calldata) external { - // TODO: implement - } + function attest(bytes32, bytes calldata) external {} function allowPayload(bytes32, bytes32) external pure returns (bool) { // digest has enough attestations diff --git a/test/mock/MockSocket.sol b/test/mock/MockSocket.sol index 027d3c27..fbe737a8 100644 --- a/test/mock/MockSocket.sol +++ b/test/mock/MockSocket.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import {InvalidAppGateway} from "../../contracts/utils/common/Errors.sol"; -import "../../contracts/protocol/interfaces/ISwitchboard.sol"; +import "../../contracts/utils/common/Errors.sol"; import "../../contracts/protocol/interfaces/ISocket.sol"; +import "../../contracts/protocol/interfaces/ISwitchboard.sol"; /** * @title SocketDst diff --git a/test/mock/MockWatcherPrecompile.sol b/test/mock/MockWatcherPrecompile.sol index af96fceb..6de1c37e 100644 --- a/test/mock/MockWatcherPrecompile.sol +++ b/test/mock/MockWatcherPrecompile.sol @@ -5,26 +5,19 @@ import "../../contracts/evmx/interfaces/IAppGateway.sol"; import "../../contracts/evmx/interfaces/IWatcher.sol"; import "../../contracts/evmx/interfaces/IPromise.sol"; -import {TimeoutRequest, TriggerParams, PlugConfig, ResolvedPromises, AppGatewayConfig} from "../../contracts/utils/common/Structs.sol"; -import {QUERY, FINALIZE, SCHEDULE} from "../../contracts/utils/common/Constants.sol"; -import {TimeoutDelayTooLarge, TimeoutAlreadyResolved, ResolvingTimeoutTooEarly, CallFailed, AppGatewayAlreadyCalled} from "../../contracts/utils/common/Errors.sol"; +import "../../contracts/utils/common/Structs.sol"; +import "../../contracts/utils/common/Constants.sol"; +import "../../contracts/utils/common/Errors.sol"; import "solady/utils/ERC1967Factory.sol"; /// @title WatcherPrecompile /// @notice Contract that handles payload verification, execution and app configurations contract MockWatcherPrecompile { - uint256 public maxTimeoutDelayInSeconds = 24 * 60 * 60; // 24 hours /// @notice Counter for tracking payload execution requests uint256 public payloadCounter; - /// @notice Mapping to store timeout requests - /// @dev timeoutId => TimeoutRequest struct - mapping(bytes32 => TimeoutRequest) public timeoutRequests; mapping(uint32 => mapping(address => PlugConfig)) internal _plugConfigs; - /// @notice Error thrown when an invalid chain slug is provided - error InvalidChainSlug(); - event CalledAppGateway(bytes32 triggerId); /// @notice Emitted when a new query is requested @@ -64,82 +57,12 @@ contract MockWatcherPrecompile { /// @param _owner Address of the contract owner constructor(address _owner, address addressResolver_) {} - // ================== Timeout functions ================== - - /// @notice Sets a timeout for a payload execution on app gateway - /// @param payload_ The payload data - /// @param delayInSeconds_ The delay in seconds - function setTimeout(bytes calldata payload_, uint256 delayInSeconds_) external { - uint256 executeAt = block.timestamp + delayInSeconds_; - bytes32 timeoutId = _encodeTimeoutId(); - timeoutRequests[timeoutId] = TimeoutRequest( - msg.sender, - delayInSeconds_, - executeAt, - 0, - false, - payload_ - ); - emit TimeoutRequested(timeoutId, msg.sender, payload_, executeAt); - } - - /// @notice Ends the timeouts and calls the target address with the callback payload - /// @param timeoutId The unique identifier for the timeout - /// @dev Only callable by the contract owner - function resolveTimeout(bytes32 timeoutId) external { - TimeoutRequest storage timeoutRequest = timeoutRequests[timeoutId]; - - (bool success, ) = address(timeoutRequest.target).call(timeoutRequest.payload); - if (!success) revert CallFailed(); - emit TimeoutResolved( - timeoutId, - timeoutRequest.target, - timeoutRequest.payload, - block.timestamp - ); - } - - // ================== Finalize functions ================== - - /// @notice Finalizes a payload request, requests the watcher to release the proofs to execute on chain - /// @param params_ The finalization parameters - /// @return digest The digest of the payload parameters - function finalize(PayloadParams memory params_) external returns (bytes32 digest) { - digest = keccak256(abi.encode(block.timestamp)); - // Generate a unique payload ID by combining chain, target, and counter - emit FinalizeRequested(digest, params_); - } - - // ================== Query functions ================== - /// @notice Creates a new query request - /// @param chainSlug The identifier of the destination chain - /// @param targetAddress The address of the target contract - /// @param payload The query payload data - /// @return payloadId The unique identifier for the query - function query( - uint32 chainSlug, - address targetAddress, - address[] memory, - bytes memory payload - ) public returns (bytes32 payloadId) { - payloadId = bytes32(payloadCounter++); - emit QueryRequested(chainSlug, targetAddress, payloadId, payload); - } - - /// @notice Marks a request as finalized with a proof - /// @param payloadId_ The unique identifier of the request - /// @param proof_ The watcher's proof - /// @dev Only callable by the contract owner - function finalized(bytes32 payloadId_, bytes calldata proof_) external { - emit Finalized(payloadId_, proof_); - } - /// @notice Resolves multiple promises with their return data - /// @param resolvedPromises_ Array of resolved promises and their return data + /// @param promiseReturnData_ Array of resolved promises and their return data /// @dev Only callable by the contract owner - function resolvePromises(ResolvedPromises[] calldata resolvedPromises_) external { - for (uint256 i = 0; i < resolvedPromises_.length; i++) { - emit PromiseResolved(resolvedPromises_[i].payloadId); + function resolvePromises(PromiseReturnData[] calldata promiseReturnData_) external { + for (uint256 i = 0; i < promiseReturnData_.length; i++) { + emit PromiseResolved(promiseReturnData_[i].payloadId); } } @@ -151,33 +74,6 @@ contract MockWatcherPrecompile { } } - /// @notice Encodes a unique payload ID from chain slug, plug address, and counter - /// @param chainSlug_ The identifier of the chain - /// @param plug_ The plug address - /// @param counter_ The current counter value - /// @return The encoded payload ID as bytes32 - /// @dev Reverts if chainSlug is 0 - function encodePayloadId( - uint32 chainSlug_, - address plug_, - uint256 counter_ - ) internal view returns (bytes32) { - if (chainSlug_ == 0) revert InvalidChainSlug(); - (, address switchboard) = getPlugConfigs(chainSlug_, plug_); - // Encode payload ID by bit-shifting and combining: - // chainSlug (32 bits) | switchboard address (160 bits) | counter (64 bits) - - return - bytes32( - (uint256(chainSlug_) << 224) | (uint256(uint160(switchboard)) << 64) | counter_ - ); - } - - function _encodeTimeoutId() internal returns (bytes32) { - // watcher address (160 bits) | counter (64 bits) - return bytes32((uint256(uint160(address(this))) << 64) | payloadCounter++); - } - /// @notice Retrieves the configuration for a specific plug on a network /// @param chainSlug_ The identifier of the network /// @param plug_ The address of the plug diff --git a/test/mock/MockWatcherPrecompileImpl.sol b/test/mock/MockWatcherPrecompileImpl.sol deleted file mode 100644 index 59cbfb87..00000000 --- a/test/mock/MockWatcherPrecompileImpl.sol +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -pragma solidity ^0.8.21; - -import "../../contracts/evmx/watcherPrecompile/core/WatcherPrecompile.sol"; - -contract MockWatcherPrecompileImpl is WatcherPrecompile { - // Mock function to test reinitialization with version 2 - function mockReinitialize(address owner_, address addressResolver_) external reinitializer(2) { - _setAddressResolver(addressResolver_); - _initializeOwner(owner_); - maxTimeoutDelayInSeconds = 24 * 60 * 60; // 24 hours - } -} From 755094ff46a2b17d5aafe29375629108d87ae149 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Mon, 26 May 2025 12:30:28 +0530 Subject: [PATCH 050/130] fix: stack too deep --- contracts/evmx/watcher/RequestHandler.sol | 59 ++++++++++------------- foundry.toml | 2 +- 2 files changed, 26 insertions(+), 35 deletions(-) diff --git a/contracts/evmx/watcher/RequestHandler.sol b/contracts/evmx/watcher/RequestHandler.sol index f3916d20..9a53cd04 100644 --- a/contracts/evmx/watcher/RequestHandler.sol +++ b/contracts/evmx/watcher/RequestHandler.sol @@ -68,6 +68,14 @@ contract RequestHandler is AddressResolverUtil { precompiles[callType_] = precompile_; } + // Add this struct at the top of the contract (after events, before functions) + struct CreateRequestResult { + uint256 totalEstimatedWatcherFees; + uint256 writeCount; + address[] promiseList; + PayloadParams[] payloadParams; + } + function submitRequest( uint256 maxFees_, address auctionManager_, @@ -93,23 +101,18 @@ contract RequestHandler is AddressResolverUtil { r.appGateway = appGateway_; r.onCompleteData = onCompleteData_; - PayloadParams[] memory payloadParams; - uint256 totalEstimatedWatcherFees; - (totalEstimatedWatcherFees, r.writeCount, promiseList, payloadParams) = _createRequest( - queueParams_, - appGateway_, - requestCount - ); - - if (totalEstimatedWatcherFees > maxFees_) revert InsufficientFees(); - if (r.writeCount == 0) _processBatch(requestCount, r.requestTrackingParams.currentBatch, r); + CreateRequestResult memory result = _createRequest(queueParams_, appGateway_, requestCount); + r.writeCount = result.writeCount; + promiseList = result.promiseList; + if (result.totalEstimatedWatcherFees > maxFees_) revert InsufficientFees(); + if (r.writeCount == 0) _processBatch(r.requestTrackingParams.currentBatch, r); emit RequestSubmitted( r.writeCount > 0, requestCount, - totalEstimatedWatcherFees, + result.totalEstimatedWatcherFees, r, - payloadParams + result.payloadParams ); } @@ -142,30 +145,22 @@ contract RequestHandler is AddressResolverUtil { feesManager__().blockCredits(requestCount_, r.requestFeesDetails.consumeFrom, bid_.fee); // re-process current batch again or process the batch for the first time - _processBatch(requestCount_, r.requestTrackingParams.currentBatch, r); + _processBatch(r.requestTrackingParams.currentBatch, r); } function _createRequest( QueueParams[] calldata queueParams_, address appGateway_, uint40 requestCount_ - ) - internal - returns ( - uint256 totalEstimatedWatcherFees, - uint256 writeCount, - address[] memory promiseList, - PayloadParams[] memory payloadParams - ) - { + ) internal returns (CreateRequestResult memory result) { // push first batch count requestBatchIds[requestCount_].push(nextBatchCount); - promiseList = new address[](queueParams_.length); - payloadParams = new PayloadParams[](queueParams_.length); + result.promiseList = new address[](queueParams_.length); + result.payloadParams = new PayloadParams[](queueParams_.length); for (uint256 i = 0; i < queueParams_.length; i++) { QueueParams calldata queuePayloadParam = queueParams_[i]; bytes4 callType = queuePayloadParam.overrideParams.callType; - if (callType == WRITE) writeCount++; + if (callType == WRITE) result.writeCount++; // decide batch count if (i > 0 && queueParams_[i].overrideParams.isParallelCall != Parallel.ON) { @@ -184,7 +179,7 @@ contract RequestHandler is AddressResolverUtil { appGateway_, callType ); - totalEstimatedWatcherFees += estimatedFees; + result.totalEstimatedWatcherFees += estimatedFees; // create payload id uint40 payloadCount = payloadCounter++; @@ -210,8 +205,8 @@ contract RequestHandler is AddressResolverUtil { deadline: 0, precompileData: precompileData }); - promiseList[i] = queueParams_[i].asyncPromise; - payloadParams[i] = p; + result.promiseList[i] = queueParams_[i].asyncPromise; + result.payloadParams[i] = p; payloads[payloadId] = p; } @@ -238,11 +233,7 @@ contract RequestHandler is AddressResolverUtil { : auctionManager_; } - function _processBatch( - uint40 requestCount_, - uint40 batchCount_, - RequestParams storage r - ) internal { + function _processBatch(uint40 batchCount_, RequestParams storage r) internal { bytes32[] memory payloadIds = batchPayloadIds[batchCount_]; uint256 totalFees = 0; @@ -309,7 +300,7 @@ contract RequestHandler is AddressResolverUtil { _settleRequest(requestCount_, r); } else { r.requestTrackingParams.currentBatch++; - _processBatch(requestCount_, r.requestTrackingParams.currentBatch, r); + _processBatch(r.requestTrackingParams.currentBatch, r); } } diff --git a/foundry.toml b/foundry.toml index 44d70bc0..6c926318 100644 --- a/foundry.toml +++ b/foundry.toml @@ -7,4 +7,4 @@ ffi = true optimizer = true optimizer_runs = 200 evm_version = 'paris' -via_ir = true +via_ir = false From a4ef3e05c78560307040e7075a74bec288d0f29e Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Mon, 26 May 2025 13:08:00 +0530 Subject: [PATCH 051/130] fix: todos --- contracts/evmx/AuctionManager.sol | 6 +++-- contracts/evmx/helpers/AsyncPromise.sol | 2 +- contracts/evmx/watcher/RequestHandler.sol | 15 ++++++------ contracts/evmx/watcher/Watcher.sol | 23 ++++++++++--------- .../watcher/precompiles/WritePrecompile.sol | 18 ++++++++++----- contracts/utils/common/Structs.sol | 10 ++++---- script/counter/SetFees.s.sol | 2 +- test/DeliveryHelper.t.sol | 2 -- test/Migration.t.sol | 1 - 9 files changed, 42 insertions(+), 37 deletions(-) diff --git a/contracts/evmx/AuctionManager.sol b/contracts/evmx/AuctionManager.sol index 96091d27..4f768ccf 100644 --- a/contracts/evmx/AuctionManager.sol +++ b/contracts/evmx/AuctionManager.sol @@ -50,7 +50,7 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, event MaxReAuctionCountSet(uint256 maxReAuctionCount); constructor(address addressResolver_) AppGatewayBase(addressResolver_) { - // todo-later: evmx slug can be immutable and set here + // todo-tests: evmx slug can be immutable and set here _disableInitializers(); // disable for implementation } @@ -164,7 +164,9 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, auctionStatus[requestCount_] = AuctionStatus.CLOSED; if (winningBid.transmitter != address(0)) { - // todo-later: might block the request processing if transmitter don't have enough balance + // todo: might block the request processing if transmitter don't have enough balance for this schedule + // this case can hit when bid timeout is more than 0 + // set the timeout for the bid expiration // useful in case a transmitter did bid but did not execute payloads _createRequest( diff --git a/contracts/evmx/helpers/AsyncPromise.sol b/contracts/evmx/helpers/AsyncPromise.sol index a545acb5..2144f540 100644 --- a/contracts/evmx/helpers/AsyncPromise.sol +++ b/contracts/evmx/helpers/AsyncPromise.sol @@ -132,7 +132,7 @@ contract AsyncPromise is AsyncPromiseStorage, Initializable, AddressResolverUtil /// @dev handleRevert function can be retried till it succeeds function _handleRevert(bytes32 payloadId_) internal { try IAppGateway(localInvoker).handleRevert(payloadId_) {} catch { - // todo-later: in this case, promise will stay unresolved + // todo: in this case, promise will stay unresolved revert PromiseRevertFailed(); } } diff --git a/contracts/evmx/watcher/RequestHandler.sol b/contracts/evmx/watcher/RequestHandler.sol index 9a53cd04..58a083a5 100644 --- a/contracts/evmx/watcher/RequestHandler.sol +++ b/contracts/evmx/watcher/RequestHandler.sol @@ -37,6 +37,12 @@ contract RequestHandler is AddressResolverUtil { /// @notice The metadata for a request mapping(uint40 => RequestParams) public requests; + struct CreateRequestResult { + uint256 totalEstimatedWatcherFees; + uint256 writeCount; + address[] promiseList; + PayloadParams[] payloadParams; + } event RequestSubmitted( bool hasWrite, @@ -68,14 +74,6 @@ contract RequestHandler is AddressResolverUtil { precompiles[callType_] = precompile_; } - // Add this struct at the top of the contract (after events, before functions) - struct CreateRequestResult { - uint256 totalEstimatedWatcherFees; - uint256 writeCount; - address[] promiseList; - PayloadParams[] payloadParams; - } - function submitRequest( uint256 maxFees_, address auctionManager_, @@ -155,6 +153,7 @@ contract RequestHandler is AddressResolverUtil { ) internal returns (CreateRequestResult memory result) { // push first batch count requestBatchIds[requestCount_].push(nextBatchCount); + result.promiseList = new address[](queueParams_.length); result.payloadParams = new PayloadParams[](queueParams_.length); for (uint256 i = 0; i < queueParams_.length; i++) { diff --git a/contracts/evmx/watcher/Watcher.sol b/contracts/evmx/watcher/Watcher.sol index 3b646c1b..19bd028f 100644 --- a/contracts/evmx/watcher/Watcher.sol +++ b/contracts/evmx/watcher/Watcher.sol @@ -104,13 +104,13 @@ contract Watcher is Trigger { delete payloadQueue; } - // todo: add this function - // function callAppGateways(WatcherMultiCallParams[] memory params_) external { - // // _validateSignature(params_[i].data_, params_[i].nonces_, params_[i].signatures_); - // for (uint40 i = 0; i < params_.length; i++) { - // _callAppGateways(params_[i]); - // } - // } + function callAppGateways(WatcherMultiCallParams[] memory params_) external { + for (uint40 i = 0; i < params_.length; i++) { + _validateSignature(params_[i].data, params_[i].nonce, params_[i].signature); + TriggerParams memory params = abi.decode(params_[i].data, (TriggerParams)); + _callAppGateways(params); + } + } function getCurrentRequestCount() public view returns (uint40) { return requestHandler__.nextRequestCount(); @@ -141,15 +141,16 @@ contract Watcher is Trigger { } // all function from watcher requiring signature + // can be also used to do msg.sender check related function in other contracts like withdraw credits from fees manager and set core app-gateways in configurations function watcherMultiCall(WatcherMultiCallParams[] memory params_) external payable { for (uint40 i = 0; i < params_.length; i++) { - if (params_[i].contracts == address(0)) revert InvalidContract(); - _validateSignature(params_[i].data_, params_[i].nonces_, params_[i].signatures_); + if (params_[i].contractAddress == address(0)) revert InvalidContract(); + _validateSignature(params_[i].data, params_[i].nonce, params_[i].signature); // call the contract // trusting watcher to send enough value for all calls - (bool success, ) = params_[i].contracts.call{value: params_[i].value_}( - params_[i].data_ + (bool success, ) = params_[i].contractAddress.call{value: params_[i].value}( + params_[i].data ); if (!success) revert CallFailed(); } diff --git a/contracts/evmx/watcher/precompiles/WritePrecompile.sol b/contracts/evmx/watcher/precompiles/WritePrecompile.sol index 0d80e78b..57011ddf 100644 --- a/contracts/evmx/watcher/precompiles/WritePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/WritePrecompile.sol @@ -32,13 +32,15 @@ contract WritePrecompile is IPrecompile, WatcherBase { event FeesSet(uint256 writeFees); event ChainMaxMsgValueLimitsUpdated(uint32[] chainSlugs, uint256[] maxMsgValueLimits); event WriteRequested(bytes32 digest, PayloadParams payloadParams); + /// @notice Emitted when a proof upload request is made event WriteProofRequested( bytes32 digest, Transaction transaction, WriteFinality writeFinality, uint256 gasLimit, - uint256 value + uint256 value, + address switchboard ); /// @notice Emitted when a proof is uploaded @@ -96,8 +98,11 @@ contract WritePrecompile is IPrecompile, WatcherBase { queueParams_.transaction, queueParams_.overrideParams.writeFinality, queueParams_.overrideParams.gasLimit, - queueParams_.overrideParams.value - // todo: add sb + queueParams_.overrideParams.value, + configurations__().switchboards( + queueParams_.transaction.chainSlug, + queueParams_.switchboardType + ) ); estimatedFees = writeFees; @@ -119,10 +124,11 @@ contract WritePrecompile is IPrecompile, WatcherBase { Transaction memory transaction, WriteFinality writeFinality, uint256 gasLimit, - uint256 value + uint256 value, + address switchboard ) = abi.decode( payloadParams.precompileData, - (address, Transaction, WriteFinality, uint256, uint256) + (address, Transaction, WriteFinality, uint256, uint256, address) ); bytes32 prevBatchDigestHash = _getPrevBatchDigestHash(payloadParams.batchCount); @@ -147,7 +153,7 @@ contract WritePrecompile is IPrecompile, WatcherBase { bytes32 digest = getDigest(digestParams_); digestHashes[payloadParams.payloadId] = digest; - emit WriteProofRequested(digest, transaction, writeFinality, gasLimit, value); + emit WriteProofRequested(digest, transaction, writeFinality, gasLimit, value, switchboard); } function _getPrevBatchDigestHash(uint40 batchCount_) internal view returns (bytes32) { diff --git a/contracts/utils/common/Structs.sol b/contracts/utils/common/Structs.sol index 97b494c3..c99d7ee5 100644 --- a/contracts/utils/common/Structs.sol +++ b/contracts/utils/common/Structs.sol @@ -108,11 +108,11 @@ struct UserCredits { } struct WatcherMultiCallParams { - address contracts; - uint256 nonces_; - uint256 value_; - bytes data_; - bytes signatures_; + address contractAddress; + uint256 value; + bytes data; + uint256 nonce; + bytes signature; } // digest: diff --git a/script/counter/SetFees.s.sol b/script/counter/SetFees.s.sol index a52b1cb8..758ff54a 100644 --- a/script/counter/SetFees.s.sol +++ b/script/counter/SetFees.s.sol @@ -20,7 +20,7 @@ contract CounterSetFees is Script { console.log("Setting fees..."); // Setting fee payment on Arbitrum Sepolia - uint256 fees = 0.00001 ether; + // uint256 fees = 0.00001 ether; // appGateway.setFees(fees); } } diff --git a/test/DeliveryHelper.t.sol b/test/DeliveryHelper.t.sol index f051ce3d..679066f5 100644 --- a/test/DeliveryHelper.t.sol +++ b/test/DeliveryHelper.t.sol @@ -47,7 +47,6 @@ contract DeliveryHelperTest is SetupTest { deployEVMxCore(); // Deploy implementations FeesManager feesManagerImpl = new FeesManager(); - DeliveryHelper deliveryHelperImpl = new DeliveryHelper(); AuctionManager auctionManagerImpl = new AuctionManager(); // Deploy and initialize proxies @@ -407,7 +406,6 @@ contract DeliveryHelperTest is SetupTest { payloadParams[i].chainSlug, "ChainSlug mismatch" ); - // todo assertEq(payloadSubmitParam.target, payloadParams[i].target, "Target mismatch"); assertEq( keccak256(payloadSubmitParam.payload), diff --git a/test/Migration.t.sol b/test/Migration.t.sol index 45f8c4f6..d6ed6d7f 100644 --- a/test/Migration.t.sol +++ b/test/Migration.t.sol @@ -6,7 +6,6 @@ import "../contracts/evmx/helpers/AddressResolver.sol"; import "../contracts/evmx/watcher/Watcher.sol"; import "../contracts/evmx/helpers/Forwarder.sol"; import "../contracts/evmx/helpers/AsyncPromise.sol"; -import "./mock/MockWatcherPrecompileImpl.sol"; contract MigrationTest is SetupTest { // ERC1967Factory emits this event with both proxy and implementation addresses From c87c8a1809a5d33abf326e34b17a0b4904ccc1cc Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Mon, 26 May 2025 14:20:25 +0530 Subject: [PATCH 052/130] fix: watcher and owner auth --- contracts/evmx/fees/Credit.sol | 8 +++++++ contracts/evmx/fees/FeesManager.sol | 2 +- contracts/evmx/helpers/DeployForwarder.sol | 2 -- .../evmx/interfaces/IDeployForwarder.sol | 5 ----- contracts/evmx/interfaces/IPrecompile.sol | 5 +++++ contracts/evmx/watcher/Configurations.sol | 11 ++++++---- contracts/evmx/watcher/RequestHandler.sol | 10 ++++++--- contracts/evmx/watcher/Watcher.sol | 14 +++++++----- contracts/evmx/watcher/WatcherBase.sol | 6 ----- contracts/evmx/watcher/WatcherStorage.sol | 5 ----- .../watcher/precompiles/WritePrecompile.sol | 22 ++++++++++++++++--- 11 files changed, 56 insertions(+), 34 deletions(-) diff --git a/contracts/evmx/fees/Credit.sol b/contracts/evmx/fees/Credit.sol index c3bb856f..4ee9a10f 100644 --- a/contracts/evmx/fees/Credit.sol +++ b/contracts/evmx/fees/Credit.sol @@ -68,6 +68,14 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressR /// @notice Emitted when credits are transferred event CreditsTransferred(address indexed from, address indexed to, uint256 amount); + /// @notice Emitted when fees plug is set + event FeesPlugSet(uint32 indexed chainSlug, address indexed feesPlug); + + function setFeesPlug(uint32 chainSlug_, address feesPlug_) external onlyOwner { + feesPlugs[chainSlug_] = feesPlug_; + emit FeesPlugSet(chainSlug_, feesPlug_); + } + /// @notice Deposits credits and native tokens to a user /// @param depositTo_ The address to deposit the credits to /// @param chainSlug_ The chain slug diff --git a/contracts/evmx/fees/FeesManager.sol b/contracts/evmx/fees/FeesManager.sol index 1a60e43a..a39dc159 100644 --- a/contracts/evmx/fees/FeesManager.sol +++ b/contracts/evmx/fees/FeesManager.sol @@ -61,9 +61,9 @@ abstract contract FeesManager is Credit { /// @param owner_ The address of the owner /// @param evmxSlug_ The evmx chain slug function initialize( + uint32 evmxSlug_, address addressResolver_, address owner_, - uint32 evmxSlug_, bytes32 sbType_ ) public reinitializer(1) { evmxSlug = evmxSlug_; diff --git a/contracts/evmx/helpers/DeployForwarder.sol b/contracts/evmx/helpers/DeployForwarder.sol index b07002cb..c31d8c2c 100644 --- a/contracts/evmx/helpers/DeployForwarder.sol +++ b/contracts/evmx/helpers/DeployForwarder.sol @@ -18,8 +18,6 @@ contract DeployForwarder is AddressResolverUtil, IDeployForwarder { bytes32 public override deployerSwitchboardType; - mapping(uint32 => address) public override contractFactoryPlugs; - /// @notice Deploys a contract /// @param chainSlug_ The chain slug function deploy( diff --git a/contracts/evmx/interfaces/IDeployForwarder.sol b/contracts/evmx/interfaces/IDeployForwarder.sol index c6981590..71b1e72d 100644 --- a/contracts/evmx/interfaces/IDeployForwarder.sol +++ b/contracts/evmx/interfaces/IDeployForwarder.sol @@ -14,11 +14,6 @@ interface IDeployForwarder { /// @return The deployer switchboard type function deployerSwitchboardType() external view returns (bytes32); - /// @notice Returns the contract factory plug address for a given chain slug - /// @param chainSlug The chain slug - /// @return The contract factory plug address - function contractFactoryPlugs(uint32 chainSlug) external view returns (address); - /// @notice Deploys a contract /// @param isPlug_ Whether the contract is a plug /// @param chainSlug_ The chain slug diff --git a/contracts/evmx/interfaces/IPrecompile.sol b/contracts/evmx/interfaces/IPrecompile.sol index 929059f3..96beec8a 100644 --- a/contracts/evmx/interfaces/IPrecompile.sol +++ b/contracts/evmx/interfaces/IPrecompile.sol @@ -6,6 +6,11 @@ import {QueueParams, PayloadParams} from "../../utils/common/Structs.sol"; /// @title IPrecompile /// @notice Interface for precompile functionality interface IPrecompile { + /// @notice Gets precompile fees + /// @param precompileData_ The precompile data + /// @return fees The fees required for processing + function getPrecompileFees(bytes memory precompileData_) external view returns (uint256 fees); + /// @notice Gets precompile data and fees for queue parameters /// @param queueParams_ The queue parameters to process /// @return precompileData The encoded precompile data diff --git a/contracts/evmx/watcher/Configurations.sol b/contracts/evmx/watcher/Configurations.sol index 21c04247..8445126c 100644 --- a/contracts/evmx/watcher/Configurations.sol +++ b/contracts/evmx/watcher/Configurations.sol @@ -6,11 +6,12 @@ import "../interfaces/IConfigurations.sol"; import {WatcherBase} from "./WatcherBase.sol"; import {encodeAppGatewayId} from "../../utils/common/IdUtils.sol"; import {InvalidGateway, InvalidSwitchboard} from "../../utils/common/Errors.sol"; +import "solady/auth/Ownable.sol"; /// @title Configurations /// @notice Configuration contract for the Watcher Precompile system /// @dev Handles the mapping between networks, plugs, and app gateways for payload execution -contract Configurations is IConfigurations, Initializable, WatcherBase { +contract Configurations is IConfigurations, Initializable, WatcherBase, Ownable { // slots 0-50 (51) reserved for addr resolver util // slots [51-100]: gap for future storage variables @@ -74,7 +75,9 @@ contract Configurations is IConfigurations, Initializable, WatcherBase { /// @param coreAppGateway The address of the core app gateway event CoreAppGatewaySet(address appGateway, address coreAppGateway); - constructor(address watcher_) WatcherBase(watcher_) {} + constructor(address watcher_) WatcherBase(watcher_) { + _initializeOwner(msg.sender); + } /// @notice Configures app gateways with their respective plugs and switchboards /// @dev Only callable by the watcher @@ -99,7 +102,7 @@ contract Configurations is IConfigurations, Initializable, WatcherBase { /// @notice Sets the socket for a network /// @param chainSlug_ The identifier of the network /// @param socket_ The address of the socket - function setSocket(uint32 chainSlug_, address socket_) external onlyWatcher { + function setSocket(uint32 chainSlug_, address socket_) external onlyOwner { sockets[chainSlug_] = socket_; emit SocketSet(chainSlug_, socket_); } @@ -112,7 +115,7 @@ contract Configurations is IConfigurations, Initializable, WatcherBase { uint32 chainSlug_, bytes32 sbType_, address switchboard_ - ) external onlyWatcher { + ) external onlyOwner { switchboards[chainSlug_][sbType_] = switchboard_; emit SwitchboardSet(chainSlug_, sbType_, switchboard_); } diff --git a/contracts/evmx/watcher/RequestHandler.sol b/contracts/evmx/watcher/RequestHandler.sol index 58a083a5..80149d91 100644 --- a/contracts/evmx/watcher/RequestHandler.sol +++ b/contracts/evmx/watcher/RequestHandler.sol @@ -7,12 +7,13 @@ import "../../utils/common/Constants.sol"; import "../../utils/common/IdUtils.sol"; import "../interfaces/IAppGateway.sol"; import "../interfaces/IPromise.sol"; +import "solady/auth/Ownable.sol"; /// @title RequestHandler /// @notice Contract that handles request processing and management, including request submission, batch processing, and request lifecycle management /// @dev Handles request submission, batch processing, transmitter assignment, request cancellation and settlement /// @dev This contract interacts with the WatcherPrecompileStorage for storage access -contract RequestHandler is AddressResolverUtil { +contract RequestHandler is AddressResolverUtil, Ownable { /// @notice Counter for tracking request counts uint40 public nextRequestCount = 1; @@ -68,9 +69,12 @@ contract RequestHandler is AddressResolverUtil { _; } - // constructor(address watcherStorage_) WatcherBase(watcherStorage_) {} + constructor(address owner_, address addressResolver_) { + _initializeOwner(owner_); + _setAddressResolver(addressResolver_); + } - function setPrecompile(bytes4 callType_, IPrecompile precompile_) external onlyWatcher { + function setPrecompile(bytes4 callType_, IPrecompile precompile_) external onlyOwner { precompiles[callType_] = precompile_; } diff --git a/contracts/evmx/watcher/Watcher.sol b/contracts/evmx/watcher/Watcher.sol index 19bd028f..f70a2e7b 100644 --- a/contracts/evmx/watcher/Watcher.sol +++ b/contracts/evmx/watcher/Watcher.sol @@ -4,18 +4,22 @@ pragma solidity ^0.8.21; import "./Trigger.sol"; contract Watcher is Trigger { - constructor( + constructor(uint32 evmxSlug_, address owner_, uint256 triggerFees_) { + evmxSlug = evmxSlug_; + triggerFees = triggerFees_; + _initializeOwner(owner_); + } + + function setCoreContracts( address requestHandler_, address configManager_, address promiseResolver_, - address addressResolver_, - address owner_ - ) { + address addressResolver_ + ) external onlyOwner { requestHandler__ = IRequestHandler(requestHandler_); configurations__ = IConfigurations(configManager_); promiseResolver__ = IPromiseResolver(promiseResolver_); addressResolver__ = IAddressResolver(addressResolver_); - _initializeOwner(owner_); } function isWatcher(address account_) public view override returns (bool) { diff --git a/contracts/evmx/watcher/WatcherBase.sol b/contracts/evmx/watcher/WatcherBase.sol index 005b389f..2e3108e8 100644 --- a/contracts/evmx/watcher/WatcherBase.sol +++ b/contracts/evmx/watcher/WatcherBase.sol @@ -24,12 +24,6 @@ contract WatcherBase { watcher__ = IWatcher(watcher_); } - /// @notice Updates the Watcher address - /// @param watcher_ The new address of the Watcher contract - function setWatcher(address watcher_) external onlyWatcher { - watcher__ = IWatcher(watcher_); - } - /// @notice Returns the configurations of the Watcher contract /// @return configurations The configurations of the Watcher contract function configurations__() internal view returns (IConfigurations) { diff --git a/contracts/evmx/watcher/WatcherStorage.sol b/contracts/evmx/watcher/WatcherStorage.sol index 996c39e9..e1c40d62 100644 --- a/contracts/evmx/watcher/WatcherStorage.sol +++ b/contracts/evmx/watcher/WatcherStorage.sol @@ -18,11 +18,6 @@ abstract contract WatcherStorage is IWatcher, AddressResolverUtil, Ownable { /// @notice The chain slug of the watcher precompile uint32 public evmxSlug; - // Payload Params - /// @notice The time from queue for the payload to be executed - /// @dev Expiry time in seconds for payload execution - uint256 public expiryTime; - /// @notice Maps nonce to whether it has been used /// @dev Used to prevent replay attacks with signature nonces /// @dev signatureNonce => isValid diff --git a/contracts/evmx/watcher/precompiles/WritePrecompile.sol b/contracts/evmx/watcher/precompiles/WritePrecompile.sol index 57011ddf..1126411a 100644 --- a/contracts/evmx/watcher/precompiles/WritePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/WritePrecompile.sol @@ -7,10 +7,11 @@ import "../../interfaces/IPrecompile.sol"; import {encodeAppGatewayId} from "../../../utils/common/IdUtils.sol"; import "../WatcherBase.sol"; +import "solady/auth/Ownable.sol"; /// @title WritePrecompile /// @notice Handles write precompile logic -contract WritePrecompile is IPrecompile, WatcherBase { +contract WritePrecompile is IPrecompile, WatcherBase, Ownable { /// @notice Mapping to store watcher proofs /// @dev Maps payload ID to proof bytes /// @dev payloadId => proof bytes @@ -32,6 +33,7 @@ contract WritePrecompile is IPrecompile, WatcherBase { event FeesSet(uint256 writeFees); event ChainMaxMsgValueLimitsUpdated(uint32[] chainSlugs, uint256[] maxMsgValueLimits); event WriteRequested(bytes32 digest, PayloadParams payloadParams); + event ContractFactoryPlugSet(uint32 chainSlug, address contractFactoryPlug); /// @notice Emitted when a proof upload request is made event WriteProofRequested( @@ -49,7 +51,13 @@ contract WritePrecompile is IPrecompile, WatcherBase { event WriteProofUploaded(bytes32 indexed payloadId, bytes proof); event ExpiryTimeSet(uint256 expiryTime); - constructor(address watcher_, uint256 writeFees_, uint256 expiryTime_) WatcherBase(watcher_) { + constructor( + address owner_, + address watcher_, + uint256 writeFees_, + uint256 expiryTime_ + ) WatcherBase(watcher_) { + _initializeOwner(owner_); writeFees = writeFees_; expiryTime = expiryTime_; } @@ -213,7 +221,7 @@ contract WritePrecompile is IPrecompile, WatcherBase { function updateChainMaxMsgValueLimits( uint32[] calldata chainSlugs_, uint256[] calldata maxMsgValueLimits_ - ) external onlyWatcher { + ) external onlyOwner { if (chainSlugs_.length != maxMsgValueLimits_.length) revert InvalidIndex(); for (uint256 i = 0; i < chainSlugs_.length; i++) { @@ -228,6 +236,14 @@ contract WritePrecompile is IPrecompile, WatcherBase { emit FeesSet(writeFees_); } + function setContractFactoryPlugs( + uint32 chainSlug_, + address contractFactoryPlug_ + ) external onlyOwner { + contractFactoryPlugs[chainSlug_] = contractFactoryPlug_; + emit ContractFactoryPlugSet(chainSlug_, contractFactoryPlug_); + } + /// @notice Sets the expiry time for payload execution /// @param expiryTime_ The expiry time in seconds /// @dev This function sets the expiry time for payload execution From a0bda704bcd57ca82fbfc2a231e71c705d23763b Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Mon, 26 May 2025 14:31:54 +0530 Subject: [PATCH 053/130] rm: old tests --- {test/apps => test-old}/Counter.t.sol | 0 {test => test-old}/DeliveryHelper.t.sol | 99 +-------- {test => test-old}/FeesTest.t.sol | 0 {test => test-old}/Inbox.t.sol | 0 {test => test-old}/Migration.t.sol | 0 {test/apps => test-old}/ParallelCounter.t.sol | 0 {test => test-old}/SocketFeeManager.t.sol | 0 {test => test-old}/Storage.t.sol | 0 {test/apps => test-old}/SuperToken.t.sol | 0 test/SetupTest.t.sol | 198 +++++++++++------- 10 files changed, 128 insertions(+), 169 deletions(-) rename {test/apps => test-old}/Counter.t.sol (100%) rename {test => test-old}/DeliveryHelper.t.sol (78%) rename {test => test-old}/FeesTest.t.sol (100%) rename {test => test-old}/Inbox.t.sol (100%) rename {test => test-old}/Migration.t.sol (100%) rename {test/apps => test-old}/ParallelCounter.t.sol (100%) rename {test => test-old}/SocketFeeManager.t.sol (100%) rename {test => test-old}/Storage.t.sol (100%) rename {test/apps => test-old}/SuperToken.t.sol (100%) diff --git a/test/apps/Counter.t.sol b/test-old/Counter.t.sol similarity index 100% rename from test/apps/Counter.t.sol rename to test-old/Counter.t.sol diff --git a/test/DeliveryHelper.t.sol b/test-old/DeliveryHelper.t.sol similarity index 78% rename from test/DeliveryHelper.t.sol rename to test-old/DeliveryHelper.t.sol index 679066f5..f59a504a 100644 --- a/test/DeliveryHelper.t.sol +++ b/test-old/DeliveryHelper.t.sol @@ -1,15 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import "../contracts/evmx/watcher/Watcher.sol"; -import "../contracts/evmx/fees/Credit.sol"; -import "../contracts/evmx/watcher/Watcher.sol"; -import "../contracts/evmx/AuctionManager.sol"; -import "../contracts/evmx/helpers/Forwarder.sol"; -import "../contracts/evmx/interfaces/IAppGateway.sol"; - -import "../contracts/evmx/fees/FeesManager.sol"; - import "./SetupTest.t.sol"; interface IAppGatewayDeployer { @@ -21,12 +12,8 @@ contract DeliveryHelperTest is SetupTest { uint256 public bidAmount = maxFees / 100; uint256 public deployCounter; uint256 public asyncPromiseCounterLocal = 0; - uint256 public asyncCounterTest; - uint256 public auctionEndDelaySeconds = 0; - uint256 public bidTimeout = 86400; + bytes public asyncPromiseBytecode = type(AsyncPromise).creationCode; - FeesManager feesManager; - AuctionManager auctionManager; event PayloadSubmitted( uint40 indexed requestCount, @@ -41,90 +28,6 @@ contract DeliveryHelperTest is SetupTest { event RequestCancelled(uint40 indexed requestCount); event QueryRequested(uint32 chainSlug, address targetAddress, bytes32 payloadId, bytes payload); - //////////////////////////////////// Setup //////////////////////////////////// - function setUpDeliveryHelper() internal { - // core - deployEVMxCore(); - // Deploy implementations - FeesManager feesManagerImpl = new FeesManager(); - AuctionManager auctionManagerImpl = new AuctionManager(); - - // Deploy and initialize proxies - bytes memory feesManagerData = abi.encodeWithSelector( - FeesManager.initialize.selector, - address(addressResolver), - watcherEOA, - evmxSlug, - FAST - ); - - vm.expectEmit(true, true, true, false); - emit Initialized(version); - address feesManagerProxy = proxyFactory.deployAndCall( - address(feesManagerImpl), - watcherEOA, - feesManagerData - ); - - bytes memory auctionManagerData = abi.encodeWithSelector( - AuctionManager.initialize.selector, - evmxSlug, - auctionEndDelaySeconds, - address(addressResolver), - owner, - maxReAuctionCount - ); - vm.expectEmit(true, true, true, false); - emit Initialized(version); - address auctionManagerProxy = proxyFactory.deployAndCall( - address(auctionManagerImpl), - watcherEOA, - auctionManagerData - ); - - bytes memory deliveryHelperData = abi.encodeWithSelector( - DeliveryHelper.initialize.selector, - address(addressResolver), - owner, - bidTimeout - ); - - vm.expectEmit(true, true, true, false); - emit Initialized(version); - address deliveryHelperProxy = proxyFactory.deployAndCall( - address(deliveryHelperImpl), - watcherEOA, - deliveryHelperData - ); - - // Assign proxy addresses to contract variables - feesManager = FeesManager(address(feesManagerProxy)); - deliveryHelper = DeliveryHelper(address(deliveryHelperProxy)); - auctionManager = AuctionManager(address(auctionManagerProxy)); - - vm.startPrank(watcherEOA); - addressResolver.setDeliveryHelper(address(deliveryHelper)); - addressResolver.setDefaultAuctionManager(address(auctionManager)); - addressResolver.setFeesManager(address(feesManager)); - vm.stopPrank(); - - hoax(owner); - auctionManager.grantRole(TRANSMITTER_ROLE, transmitterEOA); - - // chain core contracts - arbConfig = deploySocket(arbChainSlug); - optConfig = deploySocket(optChainSlug); - connectDeliveryHelper(); - - depositUSDCFees( - address(auctionManager), - OnChainFees({ - chainSlug: arbChainSlug, - token: address(arbConfig.feesTokenUSDC), - amount: 1 ether - }) - ); - } function connectDeliveryHelper() internal { vm.startPrank(owner); diff --git a/test/FeesTest.t.sol b/test-old/FeesTest.t.sol similarity index 100% rename from test/FeesTest.t.sol rename to test-old/FeesTest.t.sol diff --git a/test/Inbox.t.sol b/test-old/Inbox.t.sol similarity index 100% rename from test/Inbox.t.sol rename to test-old/Inbox.t.sol diff --git a/test/Migration.t.sol b/test-old/Migration.t.sol similarity index 100% rename from test/Migration.t.sol rename to test-old/Migration.t.sol diff --git a/test/apps/ParallelCounter.t.sol b/test-old/ParallelCounter.t.sol similarity index 100% rename from test/apps/ParallelCounter.t.sol rename to test-old/ParallelCounter.t.sol diff --git a/test/SocketFeeManager.t.sol b/test-old/SocketFeeManager.t.sol similarity index 100% rename from test/SocketFeeManager.t.sol rename to test-old/SocketFeeManager.t.sol diff --git a/test/Storage.t.sol b/test-old/Storage.t.sol similarity index 100% rename from test/Storage.t.sol rename to test-old/Storage.t.sol diff --git a/test/apps/SuperToken.t.sol b/test-old/SuperToken.t.sol similarity index 100% rename from test/apps/SuperToken.t.sol rename to test-old/SuperToken.t.sol diff --git a/test/SetupTest.t.sol b/test/SetupTest.t.sol index 6a01c30c..cb7f4286 100644 --- a/test/SetupTest.t.sol +++ b/test/SetupTest.t.sol @@ -5,50 +5,55 @@ import "forge-std/Test.sol"; import "../contracts/utils/common/Structs.sol"; import "../contracts/utils/common/Errors.sol"; import "../contracts/utils/common/Constants.sol"; -import "../contracts/evmx/watcher/Watcher.sol"; -import "../contracts/evmx/watcher/Configurations.sol"; -import "../contracts/evmx/interfaces/IForwarder.sol"; import "../contracts/utils/common/AccessRoles.sol"; -import {Socket} from "../contracts/protocol/Socket.sol"; + +import "../contracts/protocol/Socket.sol"; import "../contracts/protocol/switchboard/FastSwitchboard.sol"; import "../contracts/protocol/SocketBatcher.sol"; -import "../contracts/evmx/helpers/AddressResolver.sol"; -import {ContractFactoryPlug} from "../contracts/evmx/plugs/ContractFactoryPlug.sol"; -import {FeesPlug} from "../contracts/evmx/plugs/FeesPlug.sol"; -import {SocketFeeManager} from "../contracts/protocol/SocketFeeManager.sol"; -import "../contracts/utils/common/Structs.sol"; +import "../contracts/protocol/SocketFeeManager.sol"; +import "../contracts/evmx/watcher/Watcher.sol"; +import "../contracts/evmx/watcher/Configurations.sol"; +import "../contracts/evmx/watcher/RequestHandler.sol"; +import "../contracts/evmx/watcher/PromiseResolver.sol"; +import "../contracts/evmx/watcher/precompiles/WritePrecompile.sol"; +import "../contracts/evmx/watcher/precompiles/ReadPrecompile.sol"; +import "../contracts/evmx/watcher/precompiles/SchedulePrecompile.sol"; + +import "../contracts/evmx/helpers/AddressResolver.sol"; import "../contracts/evmx/helpers/AsyncDeployer.sol"; +import "../contracts/evmx/helpers/DeployForwarder.sol"; +import "../contracts/evmx/plugs/ContractFactoryPlug.sol"; +import "../contracts/evmx/fees/FeesManager.sol"; +import "../contracts/evmx/plugs/FeesPlug.sol"; +import "../contracts/evmx/AuctionManager.sol"; import "solady/utils/ERC1967Factory.sol"; import "./apps/app-gateways/USDC.sol"; contract SetupTest is Test { - uint public c = 1; - address owner = address(uint160(c++)); + uint256 c = 1; uint256 watcherPrivateKey = 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80; uint256 transmitterPrivateKey = 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d; - address watcherEOA = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266; address transmitterEOA = 0x70997970C51812dc3A010C7d01b50e0d17dc79C8; + address owner = address(uint160(c++)); uint32 arbChainSlug = 421614; uint32 optChainSlug = 11155420; uint32 evmxSlug = 1; + uint256 expiryTime = 10000000; + uint256 bidTimeout = 86400; uint256 maxReAuctionCount = 10; + uint256 auctionEndDelaySeconds = 0; uint256 socketFees = 0.01 ether; + uint256 public signatureNonce; uint256 public payloadIdCounter; - uint256 public timeoutIdCounter; uint256 public triggerCounter; - uint256 public defaultLimit = 1000; - - bytes public asyncPromiseBytecode = type(AsyncPromise).creationCode; - uint64 public version = 1; - struct SocketContracts { uint32 chainSlug; Socket socket; @@ -59,57 +64,61 @@ contract SetupTest is Test { FeesPlug feesPlug; ERC20 feesTokenUSDC; } - - AddressResolver public addressResolver; - Watcher public watcher; - Configurations public configurations; - AsyncDeployer public asyncDeployer; - AsyncPromise public asyncPromise; - SocketContracts public arbConfig; SocketContracts public optConfig; - // Add new variables for proxy admin and implementation contracts - Watcher public watcherImpl; - Configurations public configurationsImpl; - AsyncDeployer public asyncDeployerImpl; - AsyncPromise public asyncPromiseImpl; - AddressResolver public addressResolverImpl; ERC1967Factory public proxyFactory; + FeesManager feesManager; + AddressResolver public addressResolver; + AsyncDeployer public asyncDeployer; + DeployForwarder public deployForwarder; + AuctionManager auctionManager; + + Watcher public watcher; + Configurations public configurations; + RequestHandler public requestHandler; + PromiseResolver public promiseResolver; + WritePrecompile public writePrecompile; + ReadPrecompile public readPrecompile; + SchedulePrecompile public schedulePrecompile; event Initialized(uint64 version); event FinalizeRequested(bytes32 digest, PayloadParams payloadParams); //////////////////////////////////// Setup //////////////////////////////////// - function deploySocket(uint32 chainSlug_) internal returns (SocketContracts memory) { + function _deploySocket(uint32 chainSlug_) internal returns (SocketContracts memory) { + // socket Socket socket = new Socket(chainSlug_, owner, "test"); + SocketFeeManager socketFeeManager = new SocketFeeManager(owner, socketFees); SocketBatcher socketBatcher = new SocketBatcher(owner, socket); - FastSwitchboard switchboard = new FastSwitchboard(chainSlug_, socket, owner); + // switchboard ERC20 feesTokenUSDC = new USDC("USDC", "USDC", 6, owner, 1000000000000000000000000); + FastSwitchboard switchboard = new FastSwitchboard(chainSlug_, socket, owner); + + // plugs FeesPlug feesPlug = new FeesPlug(address(socket), owner); ContractFactoryPlug contractFactoryPlug = new ContractFactoryPlug(address(socket), owner); + vm.startPrank(owner); - // feePlug whitelist token - feesPlug.whitelistToken(address(feesTokenUSDC)); // socket socket.grantRole(GOVERNANCE_ROLE, address(owner)); // switchboard switchboard.registerSwitchboard(); switchboard.grantRole(WATCHER_ROLE, watcherEOA); + + // plugs + feesPlug.whitelistToken(address(feesTokenUSDC)); + feesManager.setFeesPlug(chainSlug_, address(feesPlug)); + writePrecompile.setContractFactoryPlugs(chainSlug_, address(contractFactoryPlug)); vm.stopPrank(); - hoax(watcherEOA); + vm.startPrank(watcherEOA); configurations.setSocket(chainSlug_, address(socket)); - - // todo: setters - // address(contractFactoryPlug), - // address(feesPlug) - SocketFeeManager socketFeeManager = new SocketFeeManager(owner, socketFees); - hoax(watcherEOA); configurations.setSwitchboard(chainSlug_, FAST, address(switchboard)); + vm.stopPrank(); return SocketContracts({ @@ -124,15 +133,17 @@ contract SetupTest is Test { }); } - function deployEVMxCore() internal { - // Deploy implementations - addressResolverImpl = new AddressResolver(); - watcherImpl = new Watcher(); - configurationsImpl = new Configurations(); - asyncDeployerImpl = new AsyncDeployer(); - asyncPromiseImpl = new AsyncPromise(); + function _deployEVMxCore() internal { proxyFactory = new ERC1967Factory(); + // Deploy implementations for upgradeable contracts + FeesManager feesManagerImpl = new FeesManager(); + AddressResolver addressResolverImpl = new AddressResolver(); + AsyncDeployer asyncDeployerImpl = new AsyncDeployer(); + DeployForwarder deployForwarderImpl = new DeployForwarder(); + AuctionManager auctionManagerImpl = new AuctionManager(); + Watcher watcherImpl = new Watcher(); + // Deploy and initialize proxies bytes memory addressResolverData = abi.encodeWithSelector( AddressResolver.initialize.selector, @@ -146,20 +157,6 @@ contract SetupTest is Test { addressResolverData ); - bytes memory configurationsData = abi.encodeWithSelector( - Configurations.initialize.selector, - watcherEOA, - address(addressResolverProxy), - evmxSlug - ); - vm.expectEmit(true, true, true, false); - emit Initialized(version); - address configurationsProxy = proxyFactory.deployAndCall( - address(configurationsImpl), - watcherEOA, - configurationsData - ); - bytes memory watcherData = abi.encodeWithSelector( Watcher.initialize.selector, watcherEOA, @@ -176,21 +173,80 @@ contract SetupTest is Test { watcherData ); + bytes memory feesManagerData = abi.encodeWithSelector( + FeesManager.initialize.selector, + address(addressResolver), + watcherEOA, + evmxSlug, + FAST + ); + + vm.expectEmit(true, true, true, false); + emit Initialized(version); + address feesManagerProxy = proxyFactory.deployAndCall( + address(feesManagerImpl), + watcherEOA, + feesManagerData + ); + + bytes memory auctionManagerData = abi.encodeWithSelector( + AuctionManager.initialize.selector, + evmxSlug, + auctionEndDelaySeconds, + address(addressResolver), + owner, + maxReAuctionCount + ); + vm.expectEmit(true, true, true, false); + emit Initialized(version); + address auctionManagerProxy = proxyFactory.deployAndCall( + address(auctionManagerImpl), + watcherEOA, + auctionManagerData + ); + // Assign proxy addresses to public variables + feesManager = FeesManager(address(feesManagerProxy)); addressResolver = AddressResolver(address(addressResolverProxy)); + asyncDeployer = AsyncDeployer(address(asyncDeployerProxy)); + deployForwarder = DeployForwarder(address(deployForwarderProxy)); + auctionManager = AuctionManager(address(auctionManagerProxy)); watcher = Watcher(address(watcherProxy)); - configurations = Configurations(address(configurationsProxy)); - // asyncDeployer = AsyncDeployer(address(asyncDeployerProxy)); - // asyncPromise = AsyncPromise(address(asyncPromiseProxy)); + + configurations = new Configurations(watcher); + requestHandler = new RequestHandler(watcher); + promiseResolver = new PromiseResolver(watcher); + writePrecompile = new WritePrecompile(watcher); + readPrecompile = new ReadPrecompile(watcher); + schedulePrecompile = new SchedulePrecompile(watcher); + } + + function deploy() internal { + _deployEVMxCore(); vm.startPrank(watcherEOA); addressResolver.setWatcher(address(watcher)); - watcher.setCallBackFees(1); - watcher.setFinalizeFees(1); - watcher.setQueryFees(1); - watcher.setTimeoutFees(1); - + addressResolver.setDeliveryHelper(address(deliveryHelper)); + addressResolver.setDefaultAuctionManager(address(auctionManager)); + addressResolver.setFeesManager(address(feesManager)); vm.stopPrank(); + + hoax(owner); + auctionManager.grantRole(TRANSMITTER_ROLE, transmitterEOA); + + // chain core contracts + arbConfig = _deploySocket(arbChainSlug); + optConfig = _deploySocket(optChainSlug); + _connectDeliveryHelper(); + + _depositUSDCFees( + address(auctionManager), + OnChainFees({ + chainSlug: arbChainSlug, + token: address(arbConfig.feesTokenUSDC), + amount: 1 ether + }) + ); } //////////////////////////////////// Watcher precompiles //////////////////////////////////// From 05a88fd739c847f393a2a9e4383a1cd07a82509f Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Mon, 26 May 2025 16:09:20 +0530 Subject: [PATCH 054/130] fix: deploy setup --- contracts/evmx/AuctionManager.sol | 8 +- contracts/evmx/helpers/AsyncDeployer.sol | 59 ++-- contracts/evmx/helpers/AsyncPromise.sol | 16 +- contracts/evmx/helpers/DeployForwarder.sol | 5 + contracts/evmx/watcher/Configurations.sol | 19 +- contracts/evmx/watcher/Watcher.sol | 34 ++- contracts/evmx/watcher/WatcherStorage.sol | 3 +- .../precompiles/SchedulePrecompile.sol | 22 +- .../watcher/precompiles/WritePrecompile.sol | 15 +- test/SetupTest.t.sol | 256 ++++++++++-------- 10 files changed, 236 insertions(+), 201 deletions(-) diff --git a/contracts/evmx/AuctionManager.sol b/contracts/evmx/AuctionManager.sol index 4f768ccf..7fd52959 100644 --- a/contracts/evmx/AuctionManager.sol +++ b/contracts/evmx/AuctionManager.sol @@ -55,15 +55,17 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, } /// @notice Initializer function to replace constructor + /// @param evmxSlug_ The evmx chain slug + /// @param bidTimeout_ The timeout after which a bid expires + /// @param maxReAuctionCount_ The maximum number of re-auctions allowed /// @param auctionEndDelaySeconds_ The delay in seconds before an auction can end /// @param addressResolver_ The address of the address resolver /// @param owner_ The address of the contract owner - /// @param maxReAuctionCount_ The maximum number of re-auctions allowed function initialize( uint32 evmxSlug_, uint128 bidTimeout_, - uint256 auctionEndDelaySeconds_, uint256 maxReAuctionCount_, + uint256 auctionEndDelaySeconds_, address addressResolver_, address owner_ ) public reinitializer(1) { @@ -71,9 +73,9 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, _initializeOwner(owner_); evmxSlug = evmxSlug_; - auctionEndDelaySeconds = auctionEndDelaySeconds_; bidTimeout = bidTimeout_; maxReAuctionCount = maxReAuctionCount_; + auctionEndDelaySeconds = auctionEndDelaySeconds_; } function setAuctionEndDelaySeconds(uint256 auctionEndDelaySeconds_) external onlyOwner { diff --git a/contracts/evmx/helpers/AsyncDeployer.sol b/contracts/evmx/helpers/AsyncDeployer.sol index 04145c27..71fec06e 100644 --- a/contracts/evmx/helpers/AsyncDeployer.sol +++ b/contracts/evmx/helpers/AsyncDeployer.sol @@ -29,9 +29,6 @@ abstract contract AsyncDeployerStorage is IAsyncDeployer { // slot 58 uint256 public asyncPromiseCounter; - // slot 59 - address public addressResolver; - // slots [61-110] reserved for gap uint256[50] _gap_after; } @@ -40,17 +37,17 @@ abstract contract AsyncDeployerStorage is IAsyncDeployer { /// @notice This contract is responsible for deploying Forwarder and AsyncPromise contracts. /// @dev Inherits the Ownable contract and implements the IAddressResolver interface. contract AsyncDeployer is AsyncDeployerStorage, Initializable, Ownable, AddressResolverUtil { - constructor(address addressResolver_) { + constructor() { _disableInitializers(); // disable for implementation - addressResolver = addressResolver_; } /// @notice Initializer to replace constructor for upgradeable contracts /// @dev it deploys the forwarder and async promise implementations and beacons for them /// @dev this contract is owner of the beacons for upgrading later /// @param owner_ The address of the contract owner - function initialize(address owner_) public reinitializer(1) { + function initialize(address owner_, address addressResolver_) public reinitializer(1) { _initializeOwner(owner_); + _setAddressResolver(addressResolver_); forwarderImplementation = address(new Forwarder()); asyncPromiseImplementation = address(new AsyncPromise()); @@ -91,16 +88,35 @@ contract AsyncDeployer is AsyncDeployerStorage, Initializable, Ownable, AddressR emit ForwarderDeployed(newForwarder, salt); } + /// @notice Deploys an AsyncPromise proxy contract + /// @param invoker_ The address of the invoker + /// @return newAsyncPromise The address of the deployed AsyncPromise proxy contract + function deployAsyncPromiseContract( + address invoker_ + ) external override onlyWatcher returns (address newAsyncPromise) { + // creates init data and salt + (bytes32 salt, bytes memory initData) = _createAsyncPromiseParams(invoker_); + asyncPromiseCounter++; + + // deploys the proxy + newAsyncPromise = _deployProxy(salt, address(asyncPromiseBeacon), initData); + emit AsyncPromiseDeployed(newAsyncPromise, salt); + } + function _createForwarderParams( address chainContractAddress_, uint32 chainSlug_ ) internal view returns (bytes32 salt, bytes memory initData) { - bytes memory constructorArgs = abi.encode(chainSlug_, chainContractAddress_, address(this)); + bytes memory constructorArgs = abi.encode( + chainSlug_, + chainContractAddress_, + address(addressResolver__) + ); initData = abi.encodeWithSelector( Forwarder.initialize.selector, chainSlug_, chainContractAddress_, - address(this) + address(addressResolver__) ); // creates salt with constructor args @@ -108,36 +124,27 @@ contract AsyncDeployer is AsyncDeployerStorage, Initializable, Ownable, AddressR } function _createAsyncPromiseParams( - address invoker_ + address invoker_, + uint40 requestCount_ ) internal view returns (bytes32 salt, bytes memory initData) { - bytes memory constructorArgs = abi.encode(invoker_, addressResolver); + bytes memory constructorArgs = abi.encode( + requestCount_, + invoker_, + address(addressResolver__) + ); // creates init data initData = abi.encodeWithSelector( AsyncPromise.initialize.selector, + requestCount_, invoker_, - addressResolver + address(addressResolver__) ); // creates salt with a counter salt = keccak256(abi.encodePacked(constructorArgs, asyncPromiseCounter)); } - /// @notice Deploys an AsyncPromise proxy contract - /// @param invoker_ The address of the invoker - /// @return newAsyncPromise The address of the deployed AsyncPromise proxy contract - function deployAsyncPromiseContract( - address invoker_ - ) external override onlyWatcher returns (address newAsyncPromise) { - // creates init data and salt - (bytes32 salt, bytes memory initData) = _createAsyncPromiseParams(invoker_); - asyncPromiseCounter++; - - // deploys the proxy - newAsyncPromise = _deployProxy(salt, address(asyncPromiseBeacon), initData); - emit AsyncPromiseDeployed(newAsyncPromise, salt); - } - function _deployProxy( bytes32 salt_, address beacon_, diff --git a/contracts/evmx/helpers/AsyncPromise.sol b/contracts/evmx/helpers/AsyncPromise.sol index 2144f540..e44bc16f 100644 --- a/contracts/evmx/helpers/AsyncPromise.sol +++ b/contracts/evmx/helpers/AsyncPromise.sol @@ -15,19 +15,19 @@ abstract contract AsyncPromiseStorage is IPromise { /// @notice The callback selector to be called on the invoker. bytes4 public callbackSelector; + /// @notice The flag to check if the promise exceeded the max copy limit + bool public override exceededMaxCopy; + /// @notice The current state of the async promise. AsyncPromiseState public override state; + /// @notice The request count of the promise + uint40 public override requestCount; + /// @notice The local contract which initiated the async call. /// @dev The callback will be executed on this address address public override localInvoker; - /// @notice The request count of the promise - uint256 public override requestCount; - - /// @notice The flag to check if the promise exceeded the max copy limit - bool public override exceededMaxCopy; - /// @notice The return data of the promise bytes public override returnData; @@ -63,9 +63,9 @@ contract AsyncPromise is AsyncPromiseStorage, Initializable, AddressResolverUtil /// @param invoker_ The address of the local invoker /// @param addressResolver_ The address resolver contract address function initialize( + uint40 requestCount_, address invoker_, - address addressResolver_, - uint256 requestCount_ + address addressResolver_ ) public initializer { localInvoker = invoker_; requestCount = requestCount_; diff --git a/contracts/evmx/helpers/DeployForwarder.sol b/contracts/evmx/helpers/DeployForwarder.sol index c31d8c2c..1a222ed2 100644 --- a/contracts/evmx/helpers/DeployForwarder.sol +++ b/contracts/evmx/helpers/DeployForwarder.sol @@ -18,6 +18,11 @@ contract DeployForwarder is AddressResolverUtil, IDeployForwarder { bytes32 public override deployerSwitchboardType; + constructor(address addressResolver_, bytes32 deployerSwitchboardType_) { + _setAddressResolver(addressResolver_); + deployerSwitchboardType = deployerSwitchboardType_; + } + /// @notice Deploys a contract /// @param chainSlug_ The chain slug function deploy( diff --git a/contracts/evmx/watcher/Configurations.sol b/contracts/evmx/watcher/Configurations.sol index 8445126c..27ccac83 100644 --- a/contracts/evmx/watcher/Configurations.sol +++ b/contracts/evmx/watcher/Configurations.sol @@ -36,11 +36,6 @@ contract Configurations is IConfigurations, Initializable, WatcherBase, Ownable /// @dev chainSlug => socket address mapping(uint32 => address) public sockets; - // slot 107: contractsToGateways - /// @notice Maps contract address to their associated app gateway - /// @dev contractAddress => appGateway - mapping(address => address) public coreAppGateways; - // slot 109: isValidPlug /// @notice Maps app gateway, chain slug, and plug to whether it is valid /// @dev appGateway => chainSlug => plug => isValid @@ -75,9 +70,7 @@ contract Configurations is IConfigurations, Initializable, WatcherBase, Ownable /// @param coreAppGateway The address of the core app gateway event CoreAppGatewaySet(address appGateway, address coreAppGateway); - constructor(address watcher_) WatcherBase(watcher_) { - _initializeOwner(msg.sender); - } + constructor(address watcher_) WatcherBase(watcher_) {} /// @notice Configures app gateways with their respective plugs and switchboards /// @dev Only callable by the watcher @@ -131,16 +124,6 @@ contract Configurations is IConfigurations, Initializable, WatcherBase, Ownable emit IsValidPlugSet(msg.sender, chainSlug_, plug_, isValid_); } - function setCoreAppGateway(address appGateway_) external { - coreAppGateways[appGateway_] = msg.sender; - emit CoreAppGatewaySet(appGateway_, msg.sender); - } - - function getCoreAppGateway(address appGateway_) external view returns (address coreAppGateway) { - coreAppGateway = coreAppGateways[appGateway_]; - if (coreAppGateway == address(0)) coreAppGateway = appGateway_; - } - /// @notice Retrieves the configuration for a specific plug on a network /// @dev Returns zero addresses if configuration doesn't exist /// @param chainSlug_ The identifier of the network diff --git a/contracts/evmx/watcher/Watcher.sol b/contracts/evmx/watcher/Watcher.sol index f70a2e7b..3cb2a758 100644 --- a/contracts/evmx/watcher/Watcher.sol +++ b/contracts/evmx/watcher/Watcher.sol @@ -4,22 +4,39 @@ pragma solidity ^0.8.21; import "./Trigger.sol"; contract Watcher is Trigger { - constructor(uint32 evmxSlug_, address owner_, uint256 triggerFees_) { + constructor() { + _disableInitializers(); // disable for implementation + } + + function initialize( + uint32 evmxSlug_, + uint256 triggerFees_, + address owner_, + address addressResolver_ + ) public reinitializer(1) { evmxSlug = evmxSlug_; triggerFees = triggerFees_; _initializeOwner(owner_); + _setAddressResolver(addressResolver_); } function setCoreContracts( address requestHandler_, address configManager_, - address promiseResolver_, - address addressResolver_ + address promiseResolver_ ) external onlyOwner { requestHandler__ = IRequestHandler(requestHandler_); configurations__ = IConfigurations(configManager_); promiseResolver__ = IPromiseResolver(promiseResolver_); - addressResolver__ = IAddressResolver(addressResolver_); + } + + function setTriggerFees( + uint256 triggerFees_, + uint256 nonce_, + bytes memory signature_ + ) external { + _validateSignature(abi.encode(triggerFees_), nonce_, signature_); + _setTriggerFees(triggerFees_); } function isWatcher(address account_) public view override returns (bool) { @@ -135,15 +152,6 @@ contract Watcher is Trigger { return requestHandler__.getPrecompileFees(precompile_, precompileData_); } - function setTriggerFees( - uint256 triggerFees_, - uint256 nonce_, - bytes memory signature_ - ) external { - _validateSignature(abi.encode(triggerFees_), nonce_, signature_); - _setTriggerFees(triggerFees_); - } - // all function from watcher requiring signature // can be also used to do msg.sender check related function in other contracts like withdraw credits from fees manager and set core app-gateways in configurations function watcherMultiCall(WatcherMultiCallParams[] memory params_) external payable { diff --git a/contracts/evmx/watcher/WatcherStorage.sol b/contracts/evmx/watcher/WatcherStorage.sol index e1c40d62..3037e517 100644 --- a/contracts/evmx/watcher/WatcherStorage.sol +++ b/contracts/evmx/watcher/WatcherStorage.sol @@ -4,13 +4,14 @@ pragma solidity ^0.8.21; import "../interfaces/IWatcher.sol"; import "../helpers/AddressResolverUtil.sol"; import "solady/utils/ECDSA.sol"; +import {Initializable} from "solady/utils/Initializable.sol"; import {Ownable} from "solady/auth/Ownable.sol"; /// @title WatcherStorage /// @notice Storage contract for the WatcherPrecompile system /// @dev This contract contains all the storage variables used by the WatcherPrecompile system /// @dev It is inherited by WatcherPrecompileCore and WatcherPrecompile -abstract contract WatcherStorage is IWatcher, AddressResolverUtil, Ownable { +abstract contract WatcherStorage is IWatcher, Initializable, AddressResolverUtil, Ownable { // slots [0-49]: gap for future storage variables uint256[50] _gap_before; diff --git a/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol b/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol index 4f97092a..aa7840ba 100644 --- a/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol @@ -45,6 +45,8 @@ contract SchedulePrecompile is IPrecompile, WatcherBase { maxScheduleDelayInSeconds = maxScheduleDelayInSeconds_; scheduleFeesPerSecond = scheduleFeesPerSecond_; scheduleCallbackFees = scheduleCallbackFees_; + + if (maxScheduleDelayInSeconds < expiryTime) revert InvalidScheduleDelay(); expiryTime = expiryTime_; } @@ -58,6 +60,7 @@ contract SchedulePrecompile is IPrecompile, WatcherBase { /// @dev This function sets the maximum schedule delay in seconds /// @dev Only callable by the contract owner function setMaxScheduleDelayInSeconds(uint256 maxScheduleDelayInSeconds_) external onlyWatcher { + if (maxScheduleDelayInSeconds < expiryTime) revert InvalidScheduleDelay(); maxScheduleDelayInSeconds = maxScheduleDelayInSeconds_; emit MaxScheduleDelayInSecondsSet(maxScheduleDelayInSeconds_); } @@ -80,6 +83,16 @@ contract SchedulePrecompile is IPrecompile, WatcherBase { emit ScheduleCallbackFeesSet(scheduleCallbackFees_); } + /// @notice Sets the expiry time for payload execution + /// @param expiryTime_ The expiry time in seconds + /// @dev This function sets the expiry time for payload execution + /// @dev Only callable by the contract owner + function setExpiryTime(uint256 expiryTime_) external onlyWatcher { + if (maxScheduleDelayInSeconds < expiryTime) revert InvalidScheduleDelay(); + expiryTime = expiryTime_; + emit ExpiryTimeSet(expiryTime_); + } + /// @notice Validates schedule parameters and return data with fees /// @dev assuming that tx is executed on EVMx chain function validateAndGetPrecompileData( @@ -118,13 +131,4 @@ contract SchedulePrecompile is IPrecompile, WatcherBase { emit ScheduleResolved(payloadParams_.payloadId); } - - /// @notice Sets the expiry time for payload execution - /// @param expiryTime_ The expiry time in seconds - /// @dev This function sets the expiry time for payload execution - /// @dev Only callable by the contract owner - function setExpiryTime(uint256 expiryTime_) external onlyWatcher { - expiryTime = expiryTime_; - emit ExpiryTimeSet(expiryTime_); - } } diff --git a/contracts/evmx/watcher/precompiles/WritePrecompile.sol b/contracts/evmx/watcher/precompiles/WritePrecompile.sol index 1126411a..0014da00 100644 --- a/contracts/evmx/watcher/precompiles/WritePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/WritePrecompile.sol @@ -31,7 +31,7 @@ contract WritePrecompile is IPrecompile, WatcherBase, Ownable { /// @notice Emitted when fees are set event FeesSet(uint256 writeFees); - event ChainMaxMsgValueLimitsUpdated(uint32[] chainSlugs, uint256[] maxMsgValueLimits); + event ChainMaxMsgValueLimitsUpdated(uint32 chainSlug, uint256 maxMsgValueLimit); event WriteRequested(bytes32 digest, PayloadParams payloadParams); event ContractFactoryPlugSet(uint32 chainSlug, address contractFactoryPlug); @@ -219,16 +219,11 @@ contract WritePrecompile is IPrecompile, WatcherBase, Ownable { /// @param chainSlugs_ Array of chain identifiers /// @param maxMsgValueLimits_ Array of corresponding maximum message value limits function updateChainMaxMsgValueLimits( - uint32[] calldata chainSlugs_, - uint256[] calldata maxMsgValueLimits_ + uint32 chainSlug_, + uint256 maxMsgValueLimit_ ) external onlyOwner { - if (chainSlugs_.length != maxMsgValueLimits_.length) revert InvalidIndex(); - - for (uint256 i = 0; i < chainSlugs_.length; i++) { - chainMaxMsgValueLimit[chainSlugs_[i]] = maxMsgValueLimits_[i]; - } - - emit ChainMaxMsgValueLimitsUpdated(chainSlugs_, maxMsgValueLimits_); + chainMaxMsgValueLimit[chainSlug_] = maxMsgValueLimit_; + emit ChainMaxMsgValueLimitsUpdated(chainSlug_, maxMsgValueLimit_); } function setFees(uint256 writeFees_) external onlyWatcher { diff --git a/test/SetupTest.t.sol b/test/SetupTest.t.sol index cb7f4286..44a4bc06 100644 --- a/test/SetupTest.t.sol +++ b/test/SetupTest.t.sol @@ -6,6 +6,7 @@ import "../contracts/utils/common/Structs.sol"; import "../contracts/utils/common/Errors.sol"; import "../contracts/utils/common/Constants.sol"; import "../contracts/utils/common/AccessRoles.sol"; +import "../contracts/utils/common/IdUtils.sol"; import "../contracts/protocol/Socket.sol"; import "../contracts/protocol/switchboard/FastSwitchboard.sol"; @@ -31,24 +32,33 @@ import "../contracts/evmx/AuctionManager.sol"; import "solady/utils/ERC1967Factory.sol"; import "./apps/app-gateways/USDC.sol"; -contract SetupTest is Test { +contract SetupStore is Test { uint256 c = 1; + uint256 version = 1; uint256 watcherPrivateKey = 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80; uint256 transmitterPrivateKey = 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d; address watcherEOA = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266; address transmitterEOA = 0x70997970C51812dc3A010C7d01b50e0d17dc79C8; - address owner = address(uint160(c++)); + address socketOwner = address(uint160(c++)); uint32 arbChainSlug = 421614; uint32 optChainSlug = 11155420; uint32 evmxSlug = 1; - uint256 expiryTime = 10000000; + uint256 expiryTime = 864000; uint256 bidTimeout = 86400; uint256 maxReAuctionCount = 10; uint256 auctionEndDelaySeconds = 0; + uint256 maxScheduleDelayInSeconds = 86400; + uint256 maxMsgValueLimit = 1 ether; + + uint256 writeFees = 0.01 ether; + uint256 readFees = 0.01 ether; + uint256 scheduleCallbackFees = 0.01 ether; + uint256 scheduleFeesPerSecond = 0.01 ether; + uint256 triggerFees = 0.01 ether; uint256 socketFees = 0.01 ether; uint256 public signatureNonce; @@ -81,7 +91,9 @@ contract SetupTest is Test { WritePrecompile public writePrecompile; ReadPrecompile public readPrecompile; SchedulePrecompile public schedulePrecompile; +} +contract SetupTest is SetupStore { event Initialized(uint64 version); event FinalizeRequested(bytes32 digest, PayloadParams payloadParams); @@ -89,48 +101,64 @@ contract SetupTest is Test { function _deploySocket(uint32 chainSlug_) internal returns (SocketContracts memory) { // socket - Socket socket = new Socket(chainSlug_, owner, "test"); - SocketFeeManager socketFeeManager = new SocketFeeManager(owner, socketFees); - SocketBatcher socketBatcher = new SocketBatcher(owner, socket); + Socket socket = new Socket(chainSlug_, socketOwner, "test"); - // switchboard - ERC20 feesTokenUSDC = new USDC("USDC", "USDC", 6, owner, 1000000000000000000000000); - FastSwitchboard switchboard = new FastSwitchboard(chainSlug_, socket, owner); + return + SocketContracts({ + chainSlug: chainSlug_, + socket: socket, + socketFeeManager: new SocketFeeManager(socketOwner, socketFees), + switchboard: new FastSwitchboard(chainSlug_, socket, socketOwner), + socketBatcher: new SocketBatcher(socketOwner, socket), + contractFactoryPlug: new ContractFactoryPlug(address(socket), socketOwner), + feesPlug: new FeesPlug(address(socket), socketOwner), + feesTokenUSDC: new USDC("USDC", "USDC", 6, socketOwner, 1000000000000000000000000) + }); + } - // plugs - FeesPlug feesPlug = new FeesPlug(address(socket), owner); - ContractFactoryPlug contractFactoryPlug = new ContractFactoryPlug(address(socket), owner); + function _configureChain(uint32 chainSlug_) internal { + SocketContracts memory socketConfig = getSocketConfig(chainSlug_); + Socket socket = socketConfig.socket; + FastSwitchboard switchboard = socketConfig.switchboard; + FeesPlug feesPlug = socketConfig.feesPlug; + ERC20 feesTokenUSDC = socketConfig.feesTokenUSDC; - vm.startPrank(owner); + vm.startPrank(socketOwner); // socket - socket.grantRole(GOVERNANCE_ROLE, address(owner)); + socket.grantRole(GOVERNANCE_ROLE, address(socketOwner)); // switchboard switchboard.registerSwitchboard(); switchboard.grantRole(WATCHER_ROLE, watcherEOA); - - // plugs - feesPlug.whitelistToken(address(feesTokenUSDC)); - feesManager.setFeesPlug(chainSlug_, address(feesPlug)); - writePrecompile.setContractFactoryPlugs(chainSlug_, address(contractFactoryPlug)); vm.stopPrank(); vm.startPrank(watcherEOA); + configurations.setSocket(chainSlug_, address(socket)); configurations.setSwitchboard(chainSlug_, FAST, address(switchboard)); + + // plugs + feesPlug.whitelistToken(address(feesTokenUSDC)); + feesManager.setFeesPlug(chainSlug_, address(feesPlug)); + + // precompiles + writePrecompile.updateChainMaxMsgValueLimits(chainSlug_, maxMsgValueLimit); + writePrecompile.setContractFactoryPlugs( + chainSlug_, + address(socketConfig.contractFactoryPlug) + ); + vm.stopPrank(); + } - return - SocketContracts({ - chainSlug: chainSlug_, - socket: socket, - socketFeeManager: socketFeeManager, - switchboard: switchboard, - socketBatcher: socketBatcher, - contractFactoryPlug: contractFactoryPlug, - feesPlug: feesPlug, - feesTokenUSDC: feesTokenUSDC - }); + function _deployAndVerifyProxy( + address implementation_, + address owner_, + bytes memory data_ + ) internal returns (address) { + vm.expectEmit(true, true, true, false); + emit Initialized(version); + return address(proxyFactory.deployAndCall(implementation_, owner_, data_)); } function _deployEVMxCore() internal { @@ -140,117 +168,127 @@ contract SetupTest is Test { FeesManager feesManagerImpl = new FeesManager(); AddressResolver addressResolverImpl = new AddressResolver(); AsyncDeployer asyncDeployerImpl = new AsyncDeployer(); - DeployForwarder deployForwarderImpl = new DeployForwarder(); AuctionManager auctionManagerImpl = new AuctionManager(); Watcher watcherImpl = new Watcher(); // Deploy and initialize proxies - bytes memory addressResolverData = abi.encodeWithSelector( - AddressResolver.initialize.selector, - watcherEOA - ); - vm.expectEmit(true, true, true, false); - emit Initialized(version); - address addressResolverProxy = proxyFactory.deployAndCall( + address addressResolverProxy = _deployAndVerifyProxy( address(addressResolverImpl), watcherEOA, - addressResolverData + abi.encodeWithSelector(AddressResolver.initialize.selector, watcherEOA) ); + addressResolver = AddressResolver(addressResolverProxy); - bytes memory watcherData = abi.encodeWithSelector( - Watcher.initialize.selector, - watcherEOA, - address(addressResolverProxy), - expiryTime, - evmxSlug, - address(configurationsProxy) - ); - vm.expectEmit(true, true, true, false); - emit Initialized(version); - address watcherProxy = proxyFactory.deployAndCall( - address(watcherImpl), + address feesManagerProxy = _deployAndVerifyProxy( + address(feesManagerImpl), watcherEOA, - watcherData + abi.encodeWithSelector( + FeesManager.initialize.selector, + address(addressResolver), + watcherEOA, + evmxSlug, + FAST + ) ); + feesManager = FeesManager(feesManagerProxy); - bytes memory feesManagerData = abi.encodeWithSelector( - FeesManager.initialize.selector, - address(addressResolver), + address asyncDeployerProxy = _deployAndVerifyProxy( + address(asyncDeployerImpl), watcherEOA, - evmxSlug, - FAST + abi.encodeWithSelector( + AsyncDeployer.initialize.selector, + watcherEOA, + address(addressResolver) + ) ); + asyncDeployer = AsyncDeployer(asyncDeployerProxy); - vm.expectEmit(true, true, true, false); - emit Initialized(version); - address feesManagerProxy = proxyFactory.deployAndCall( - address(feesManagerImpl), + address auctionManagerProxy = _deployAndVerifyProxy( + address(auctionManagerImpl), watcherEOA, - feesManagerData + abi.encodeWithSelector( + AuctionManager.initialize.selector, + evmxSlug, + bidTimeout, + maxReAuctionCount, + auctionEndDelaySeconds, + address(addressResolver), + watcherEOA + ) ); + auctionManager = AuctionManager(auctionManagerProxy); - bytes memory auctionManagerData = abi.encodeWithSelector( - AuctionManager.initialize.selector, - evmxSlug, - auctionEndDelaySeconds, - address(addressResolver), - owner, - maxReAuctionCount - ); - vm.expectEmit(true, true, true, false); - emit Initialized(version); - address auctionManagerProxy = proxyFactory.deployAndCall( - address(auctionManagerImpl), + address watcherProxy = _deployAndVerifyProxy( + address(watcherImpl), watcherEOA, - auctionManagerData + abi.encodeWithSelector( + Watcher.initialize.selector, + evmxSlug, + triggerFees, + watcherEOA, + address(addressResolver) + ) + ); + watcher = Watcher(watcherProxy); + + // non proxy contracts + deployForwarder = new DeployForwarder(address(addressResolver), FAST); + configurations = new Configurations(address(watcher)); + requestHandler = new RequestHandler(watcherEOA, address(addressResolver)); + promiseResolver = new PromiseResolver(address(watcher)); + writePrecompile = new WritePrecompile(watcherEOA, address(watcher), writeFees, expiryTime); + readPrecompile = new ReadPrecompile(address(watcher), readFees, expiryTime); + schedulePrecompile = new SchedulePrecompile( + address(watcher), + maxScheduleDelayInSeconds, + scheduleFeesPerSecond, + scheduleCallbackFees, + expiryTime ); - - // Assign proxy addresses to public variables - feesManager = FeesManager(address(feesManagerProxy)); - addressResolver = AddressResolver(address(addressResolverProxy)); - asyncDeployer = AsyncDeployer(address(asyncDeployerProxy)); - deployForwarder = DeployForwarder(address(deployForwarderProxy)); - auctionManager = AuctionManager(address(auctionManagerProxy)); - watcher = Watcher(address(watcherProxy)); - - configurations = new Configurations(watcher); - requestHandler = new RequestHandler(watcher); - promiseResolver = new PromiseResolver(watcher); - writePrecompile = new WritePrecompile(watcher); - readPrecompile = new ReadPrecompile(watcher); - schedulePrecompile = new SchedulePrecompile(watcher); } function deploy() internal { _deployEVMxCore(); vm.startPrank(watcherEOA); + auctionManager.grantRole(TRANSMITTER_ROLE, transmitterEOA); + + // setup address resolver addressResolver.setWatcher(address(watcher)); - addressResolver.setDeliveryHelper(address(deliveryHelper)); + addressResolver.setAsyncDeployer(address(asyncDeployer)); addressResolver.setDefaultAuctionManager(address(auctionManager)); addressResolver.setFeesManager(address(feesManager)); + addressResolver.setDeployForwarder(address(deployForwarder)); + + requestHandler.setPrecompile(WRITE, address(writePrecompile)); + requestHandler.setPrecompile(READ, address(readPrecompile)); + requestHandler.setPrecompile(SCHEDULE, address(schedulePrecompile)); + + watcher.setCoreContracts( + address(requestHandler), + address(configurations), + address(promiseResolver) + ); vm.stopPrank(); - hoax(owner); - auctionManager.grantRole(TRANSMITTER_ROLE, transmitterEOA); + hoax(transmitterEOA); + arbConfig.feesPlug.depositCreditAndNative( + arbConfig.feesTokenUSDC, + address(transmitterEOA), + 100 ether + ); + + feesManager.approveAppGateways( + [AppGatewayApprovals({appGateway: address(auctionManager), approval: true})] + ); // chain core contracts arbConfig = _deploySocket(arbChainSlug); + _configureChain(arbChainSlug); optConfig = _deploySocket(optChainSlug); - _connectDeliveryHelper(); - - _depositUSDCFees( - address(auctionManager), - OnChainFees({ - chainSlug: arbChainSlug, - token: address(arbConfig.feesTokenUSDC), - amount: 1 ether - }) - ); + _configureChain(optChainSlug); } - //////////////////////////////////// Watcher precompiles //////////////////////////////////// - function _checkIfOnlyReads(uint40 batchCount_) internal view returns (bool) { bytes32[] memory payloadIds = watcher.getBatchPayloadIds(batchCount_); @@ -459,12 +497,4 @@ contract SetupTest is Test { mstore(add(sig, 64), sigS) } } - - function _encodeAppGatewayId(address appGateway_) internal pure returns (bytes32) { - return bytes32(uint256(uint160(appGateway_))); - } - - function _decodeAppGatewayId(bytes32 appGatewayId_) internal pure returns (address) { - return address(uint160(uint256(appGatewayId_))); - } } From 6b375394cbb19c6c7ad2a84a42cf0d2f27264215 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Mon, 26 May 2025 16:11:54 +0530 Subject: [PATCH 055/130] feat: remove core appgateway feature --- contracts/evmx/fees/Credit.sol | 2 +- contracts/evmx/helpers/AddressResolverUtil.sol | 4 ---- contracts/evmx/interfaces/IConfigurations.sol | 6 ------ contracts/evmx/watcher/Configurations.sol | 6 ------ contracts/evmx/watcher/RequestHandler.sol | 4 ++-- contracts/evmx/watcher/Watcher.sol | 12 +++++------- .../evmx/watcher/precompiles/WritePrecompile.sol | 4 ++-- test/SetupTest.t.sol | 2 +- 8 files changed, 11 insertions(+), 29 deletions(-) diff --git a/contracts/evmx/fees/Credit.sol b/contracts/evmx/fees/Credit.sol index 4ee9a10f..14a553d2 100644 --- a/contracts/evmx/fees/Credit.sol +++ b/contracts/evmx/fees/Credit.sol @@ -200,7 +200,7 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressR uint256 maxFees_, address receiver_ ) public override { - address consumeFrom = getCoreAppGateway(msg.sender); + address consumeFrom = msg.sender; // Check if amount is available in fees plug uint256 availableCredits = getAvailableCredits(consumeFrom); diff --git a/contracts/evmx/helpers/AddressResolverUtil.sol b/contracts/evmx/helpers/AddressResolverUtil.sol index bebf71cf..550ece71 100644 --- a/contracts/evmx/helpers/AddressResolverUtil.sol +++ b/contracts/evmx/helpers/AddressResolverUtil.sol @@ -64,8 +64,4 @@ abstract contract AddressResolverUtil { function _setAddressResolver(address _addressResolver) internal { addressResolver__ = IAddressResolver(_addressResolver); } - - function getCoreAppGateway(address appGateway_) internal view returns (address) { - return addressResolver__.watcher__().configurations__().getCoreAppGateway(appGateway_); - } } diff --git a/contracts/evmx/interfaces/IConfigurations.sol b/contracts/evmx/interfaces/IConfigurations.sol index abde9755..964633cf 100644 --- a/contracts/evmx/interfaces/IConfigurations.sol +++ b/contracts/evmx/interfaces/IConfigurations.sol @@ -15,9 +15,6 @@ interface IConfigurations { bytes32 switchboardType_ ) external view; - /// @notice Maps contract address to their associated app gateway - function getCoreAppGateway(address contractAddress) external view returns (address); - /// @notice Maps app gateway, chain slug and plug to validity function isValidPlug( address appGateway, @@ -52,7 +49,4 @@ interface IConfigurations { /// @notice Sets the socket for a chain slug function setSocket(uint32 chainSlug_, address socket_) external; - - /// @notice Sets the core app gateway for the watcher precompile - function setCoreAppGateway(address appGateway_) external; } diff --git a/contracts/evmx/watcher/Configurations.sol b/contracts/evmx/watcher/Configurations.sol index 27ccac83..0e9e5ec2 100644 --- a/contracts/evmx/watcher/Configurations.sol +++ b/contracts/evmx/watcher/Configurations.sol @@ -64,12 +64,6 @@ contract Configurations is IConfigurations, Initializable, WatcherBase, Ownable /// @param plug The address of the plug /// @param isValid Whether the plug is valid event IsValidPlugSet(address appGateway, uint32 chainSlug, address plug, bool isValid); - - /// @notice Emitted when a core app gateway is set for an app gateway - /// @param appGateway The address of the app gateway - /// @param coreAppGateway The address of the core app gateway - event CoreAppGatewaySet(address appGateway, address coreAppGateway); - constructor(address watcher_) WatcherBase(watcher_) {} /// @notice Configures app gateways with their respective plugs and switchboards diff --git a/contracts/evmx/watcher/RequestHandler.sol b/contracts/evmx/watcher/RequestHandler.sol index 80149d91..16cc3270 100644 --- a/contracts/evmx/watcher/RequestHandler.sol +++ b/contracts/evmx/watcher/RequestHandler.sol @@ -264,7 +264,7 @@ contract RequestHandler is AddressResolverUtil, Ownable { /// @param newMaxFees_ The new maximum fees function increaseFees(uint40 requestCount_, uint256 newMaxFees_) external { RequestParams storage r = requests[requestCount_]; - address appGateway = getCoreAppGateway(msg.sender); + address appGateway = msg.sender; if (r.requestTrackingParams.isRequestCancelled) revert RequestAlreadyCancelled(); if (r.requestTrackingParams.isRequestExecuted) revert RequestAlreadySettled(); @@ -325,7 +325,7 @@ contract RequestHandler is AddressResolverUtil, Ownable { /// @dev It verifies that the caller is the middleware and that the request hasn't been cancelled yet function cancelRequest(uint40 requestCount) external { RequestParams storage r = requests[requestCount]; - if (r.appGateway != getCoreAppGateway(msg.sender)) revert InvalidCaller(); + if (r.appGateway != msg.sender) revert InvalidCaller(); _cancelRequest(requestCount, r); } diff --git a/contracts/evmx/watcher/Watcher.sol b/contracts/evmx/watcher/Watcher.sol index 3cb2a758..55c76371 100644 --- a/contracts/evmx/watcher/Watcher.sol +++ b/contracts/evmx/watcher/Watcher.sol @@ -70,17 +70,15 @@ contract Watcher is Trigger { QueueParams memory queue_, address appGateway_ ) internal returns (address, uint40) { - address coreAppGateway = getCoreAppGateway(appGateway_); - // checks if app gateway passed by forwarder is coming from same core app gateway group if (appGatewayTemp != address(0)) - if (appGatewayTemp != coreAppGateway || coreAppGateway == address(0)) + if (appGatewayTemp != appGateway_ || appGateway_ == address(0)) revert InvalidAppGateway(); uint40 requestCount = getCurrentRequestCount(); // Deploy a new async promise contract. latestAsyncPromise = asyncDeployer__().deployAsyncPromiseContract(appGateway_); - appGatewayTemp = coreAppGateway; + appGatewayTemp = appGateway_; queue_.asyncPromise = latestAsyncPromise; // Add the promise to the queue. @@ -105,15 +103,15 @@ contract Watcher is Trigger { bytes memory onCompleteData ) internal returns (uint40 requestCount, address[] memory promiseList) { // this check is to verify that msg.sender (app gateway base) belongs to correct app gateway - address coreAppGateway = getCoreAppGateway(msg.sender); - if (coreAppGateway != appGatewayTemp) revert InvalidAppGateway(); + address appGateway = msg.sender; + if (appGateway != appGatewayTemp) revert InvalidAppGateway(); latestAsyncPromise = address(0); (requestCount, promiseList) = requestHandler__.submitRequest( maxFees, auctionManager, consumeFrom, - coreAppGateway, + appGateway, payloadQueue, onCompleteData ); diff --git a/contracts/evmx/watcher/precompiles/WritePrecompile.sol b/contracts/evmx/watcher/precompiles/WritePrecompile.sol index 0014da00..55e5dfc7 100644 --- a/contracts/evmx/watcher/precompiles/WritePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/WritePrecompile.sol @@ -216,8 +216,8 @@ contract WritePrecompile is IPrecompile, WatcherBase, Ownable { } /// @notice Updates the maximum message value limit for multiple chains - /// @param chainSlugs_ Array of chain identifiers - /// @param maxMsgValueLimits_ Array of corresponding maximum message value limits + /// @param chainSlug_ The chain identifier + /// @param maxMsgValueLimit_ The maximum message value limit function updateChainMaxMsgValueLimits( uint32 chainSlug_, uint256 maxMsgValueLimit_ diff --git a/test/SetupTest.t.sol b/test/SetupTest.t.sol index 44a4bc06..bd7d1155 100644 --- a/test/SetupTest.t.sol +++ b/test/SetupTest.t.sol @@ -398,7 +398,7 @@ contract SetupTest is SetupStore { params_.value, params_.payload, params_.target, - _encodeAppGatewayId(params_.appGateway), + encodeAppGatewayId(params_.appGateway), params_.prevDigestsHash ); bytes32 digest = watcher.getDigest(digestParams_); From 1ab76ead1fbf43a09bb8a3d410cf6c46294f9ed7 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Mon, 26 May 2025 16:58:27 +0530 Subject: [PATCH 056/130] test: deploy setup --- contracts/evmx/AuctionManager.sol | 17 +- contracts/evmx/fees/FeesManager.sol | 2 +- contracts/evmx/helpers/AsyncDeployer.sol | 12 +- contracts/evmx/interfaces/IAsyncDeployer.sol | 10 +- contracts/evmx/interfaces/IPromise.sol | 2 +- contracts/evmx/watcher/Configurations.sol | 5 +- contracts/evmx/watcher/Watcher.sol | 5 +- .../watcher/precompiles/WritePrecompile.sol | 1 - test/SetupTest.t.sol | 627 ++++++++++-------- test/apps/app-gateways/USDC.sol | 41 -- 10 files changed, 377 insertions(+), 345 deletions(-) delete mode 100644 test/apps/app-gateways/USDC.sol diff --git a/contracts/evmx/AuctionManager.sol b/contracts/evmx/AuctionManager.sol index 7fd52959..98c12a67 100644 --- a/contracts/evmx/AuctionManager.sol +++ b/contracts/evmx/AuctionManager.sol @@ -2,7 +2,6 @@ pragma solidity ^0.8.21; import {ECDSA} from "solady/utils/ECDSA.sol"; -import "solady/utils/Initializable.sol"; import "./interfaces/IAuctionManager.sol"; import "../utils/AccessControl.sol"; import {AuctionNotOpen, AuctionClosed, BidExceedsMaxFees, LowerBidAlreadyExists, InvalidTransmitter, MaxReAuctionCountReached, InvalidBid} from "../utils/common/Errors.sol"; @@ -15,7 +14,7 @@ import {AppGatewayBase} from "./base/AppGatewayBase.sol"; /// @notice Storage for the AuctionManager contract abstract contract AuctionManagerStorage is IAuctionManager { // slot 50 - uint32 public evmxSlug; + uint32 public immutable evmxSlug; // slot 50 /// @notice The timeout after which a bid expires @@ -41,7 +40,7 @@ abstract contract AuctionManagerStorage is IAuctionManager { /// @title AuctionManager /// @notice Contract for managing auctions and placing bids -contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, AppGatewayBase { +contract AuctionManager is AuctionManagerStorage, AccessControl, AppGatewayBase { event AuctionRestarted(uint40 requestCount); event AuctionStarted(uint40 requestCount); event AuctionEnded(uint40 requestCount, Bid winningBid); @@ -49,27 +48,21 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AccessControl, event AuctionEndDelaySecondsSet(uint256 auctionEndDelaySeconds); event MaxReAuctionCountSet(uint256 maxReAuctionCount); - constructor(address addressResolver_) AppGatewayBase(addressResolver_) { - // todo-tests: evmx slug can be immutable and set here - _disableInitializers(); // disable for implementation - } - - /// @notice Initializer function to replace constructor /// @param evmxSlug_ The evmx chain slug /// @param bidTimeout_ The timeout after which a bid expires /// @param maxReAuctionCount_ The maximum number of re-auctions allowed /// @param auctionEndDelaySeconds_ The delay in seconds before an auction can end /// @param addressResolver_ The address of the address resolver /// @param owner_ The address of the contract owner - function initialize( + + constructor( uint32 evmxSlug_, uint128 bidTimeout_, uint256 maxReAuctionCount_, uint256 auctionEndDelaySeconds_, address addressResolver_, address owner_ - ) public reinitializer(1) { - _setAddressResolver(addressResolver_); + ) AppGatewayBase(addressResolver_) { _initializeOwner(owner_); evmxSlug = evmxSlug_; diff --git a/contracts/evmx/fees/FeesManager.sol b/contracts/evmx/fees/FeesManager.sol index a39dc159..fd54e4c0 100644 --- a/contracts/evmx/fees/FeesManager.sol +++ b/contracts/evmx/fees/FeesManager.sol @@ -5,7 +5,7 @@ import "./Credit.sol"; /// @title FeesManager /// @notice Contract for managing fees -abstract contract FeesManager is Credit { +contract FeesManager is Credit { /// @notice Emitted when fees are blocked for a batch /// @param requestCount The batch identifier /// @param consumeFrom The consume from address diff --git a/contracts/evmx/helpers/AsyncDeployer.sol b/contracts/evmx/helpers/AsyncDeployer.sol index 71fec06e..0cf93eb9 100644 --- a/contracts/evmx/helpers/AsyncDeployer.sol +++ b/contracts/evmx/helpers/AsyncDeployer.sol @@ -92,10 +92,11 @@ contract AsyncDeployer is AsyncDeployerStorage, Initializable, Ownable, AddressR /// @param invoker_ The address of the invoker /// @return newAsyncPromise The address of the deployed AsyncPromise proxy contract function deployAsyncPromiseContract( - address invoker_ + address invoker_, + uint40 requestCount_ ) external override onlyWatcher returns (address newAsyncPromise) { // creates init data and salt - (bytes32 salt, bytes memory initData) = _createAsyncPromiseParams(invoker_); + (bytes32 salt, bytes memory initData) = _createAsyncPromiseParams(invoker_, requestCount_); asyncPromiseCounter++; // deploys the proxy @@ -175,8 +176,11 @@ contract AsyncDeployer is AsyncDeployerStorage, Initializable, Ownable, AddressR /// @notice Gets the predicted address of an AsyncPromise proxy contract /// @param invoker_ The address of the invoker /// @return The predicted address of the AsyncPromise proxy contract - function getAsyncPromiseAddress(address invoker_) public view override returns (address) { - (bytes32 salt, ) = _createAsyncPromiseParams(invoker_); + function getAsyncPromiseAddress( + address invoker_, + uint40 requestCount_ + ) public view override returns (address) { + (bytes32 salt, ) = _createAsyncPromiseParams(invoker_, requestCount_); return _predictProxyAddress(salt, address(asyncPromiseBeacon)); } diff --git a/contracts/evmx/interfaces/IAsyncDeployer.sol b/contracts/evmx/interfaces/IAsyncDeployer.sol index e2c99c45..9023db36 100644 --- a/contracts/evmx/interfaces/IAsyncDeployer.sol +++ b/contracts/evmx/interfaces/IAsyncDeployer.sol @@ -34,9 +34,15 @@ interface IAsyncDeployer { function setForwarderImplementation(address implementation_) external; // Async Promise Management - function deployAsyncPromiseContract(address invoker_) external returns (address); + function deployAsyncPromiseContract( + address invoker_, + uint40 requestCount_ + ) external returns (address); - function getAsyncPromiseAddress(address invoker_) external view returns (address); + function getAsyncPromiseAddress( + address invoker_, + uint40 requestCount_ + ) external view returns (address); function setAsyncPromiseImplementation(address implementation_) external; } diff --git a/contracts/evmx/interfaces/IPromise.sol b/contracts/evmx/interfaces/IPromise.sol index 651c979d..0d1c34ec 100644 --- a/contracts/evmx/interfaces/IPromise.sol +++ b/contracts/evmx/interfaces/IPromise.sol @@ -13,7 +13,7 @@ interface IPromise { function localInvoker() external view returns (address); /// @notice The request count of the promise - function requestCount() external view returns (uint256); + function requestCount() external view returns (uint40); /// @notice The flag to check if the promise exceeded the max copy limit function exceededMaxCopy() external view returns (bool); diff --git a/contracts/evmx/watcher/Configurations.sol b/contracts/evmx/watcher/Configurations.sol index 0e9e5ec2..39267a67 100644 --- a/contracts/evmx/watcher/Configurations.sol +++ b/contracts/evmx/watcher/Configurations.sol @@ -64,7 +64,10 @@ contract Configurations is IConfigurations, Initializable, WatcherBase, Ownable /// @param plug The address of the plug /// @param isValid Whether the plug is valid event IsValidPlugSet(address appGateway, uint32 chainSlug, address plug, bool isValid); - constructor(address watcher_) WatcherBase(watcher_) {} + + constructor(address watcher_, address owner_) WatcherBase(watcher_) { + _initializeOwner(owner_); + } /// @notice Configures app gateways with their respective plugs and switchboards /// @dev Only callable by the watcher diff --git a/contracts/evmx/watcher/Watcher.sol b/contracts/evmx/watcher/Watcher.sol index 55c76371..332bd09f 100644 --- a/contracts/evmx/watcher/Watcher.sol +++ b/contracts/evmx/watcher/Watcher.sol @@ -77,7 +77,10 @@ contract Watcher is Trigger { uint40 requestCount = getCurrentRequestCount(); // Deploy a new async promise contract. - latestAsyncPromise = asyncDeployer__().deployAsyncPromiseContract(appGateway_); + latestAsyncPromise = asyncDeployer__().deployAsyncPromiseContract( + appGateway_, + requestCount + ); appGatewayTemp = appGateway_; queue_.asyncPromise = latestAsyncPromise; diff --git a/contracts/evmx/watcher/precompiles/WritePrecompile.sol b/contracts/evmx/watcher/precompiles/WritePrecompile.sol index 55e5dfc7..afaa0302 100644 --- a/contracts/evmx/watcher/precompiles/WritePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/WritePrecompile.sol @@ -32,7 +32,6 @@ contract WritePrecompile is IPrecompile, WatcherBase, Ownable { /// @notice Emitted when fees are set event FeesSet(uint256 writeFees); event ChainMaxMsgValueLimitsUpdated(uint32 chainSlug, uint256 maxMsgValueLimit); - event WriteRequested(bytes32 digest, PayloadParams payloadParams); event ContractFactoryPlugSet(uint32 chainSlug, address contractFactoryPlug); /// @notice Emitted when a proof upload request is made diff --git a/test/SetupTest.t.sol b/test/SetupTest.t.sol index bd7d1155..f90ca7e9 100644 --- a/test/SetupTest.t.sol +++ b/test/SetupTest.t.sol @@ -28,13 +28,13 @@ import "../contracts/evmx/plugs/ContractFactoryPlug.sol"; import "../contracts/evmx/fees/FeesManager.sol"; import "../contracts/evmx/plugs/FeesPlug.sol"; import "../contracts/evmx/AuctionManager.sol"; +import "../contracts/evmx/mocks/TestUSDC.sol"; import "solady/utils/ERC1967Factory.sol"; -import "./apps/app-gateways/USDC.sol"; contract SetupStore is Test { uint256 c = 1; - uint256 version = 1; + uint64 version = 1; uint256 watcherPrivateKey = 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80; uint256 transmitterPrivateKey = @@ -72,7 +72,7 @@ contract SetupStore is Test { SocketBatcher socketBatcher; ContractFactoryPlug contractFactoryPlug; FeesPlug feesPlug; - ERC20 feesTokenUSDC; + TestUSDC testUSDC; } SocketContracts public arbConfig; SocketContracts public optConfig; @@ -93,11 +93,97 @@ contract SetupStore is Test { SchedulePrecompile public schedulePrecompile; } -contract SetupTest is SetupStore { +contract DeployAndSetupTest is SetupStore { event Initialized(uint64 version); event FinalizeRequested(bytes32 digest, PayloadParams payloadParams); //////////////////////////////////// Setup //////////////////////////////////// + function deploy() internal { + _deployEVMxCore(); + + // chain core contracts + arbConfig = _deploySocket(arbChainSlug); + _configureChain(arbChainSlug); + optConfig = _deploySocket(optChainSlug); + _configureChain(optChainSlug); + + vm.startPrank(watcherEOA); + auctionManager.grantRole(TRANSMITTER_ROLE, transmitterEOA); + + // setup address resolver + addressResolver.setWatcher(address(watcher)); + addressResolver.setAsyncDeployer(address(asyncDeployer)); + addressResolver.setDefaultAuctionManager(address(auctionManager)); + addressResolver.setFeesManager(address(feesManager)); + addressResolver.setDeployForwarder(address(deployForwarder)); + + requestHandler.setPrecompile(WRITE, writePrecompile); + requestHandler.setPrecompile(READ, readPrecompile); + requestHandler.setPrecompile(SCHEDULE, schedulePrecompile); + + watcher.setCoreContracts( + address(requestHandler), + address(configurations), + address(promiseResolver) + ); + vm.stopPrank(); + + _connectPlugs(); + + vm.startPrank(transmitterEOA); + arbConfig.testUSDC.mint(address(transmitterEOA), 100 ether); + arbConfig.testUSDC.approve(address(arbConfig.feesPlug), 100 ether); + + arbConfig.feesPlug.depositCreditAndNative( + address(arbConfig.testUSDC), + address(transmitterEOA), + 100 ether + ); + + AppGatewayApprovals[] memory approvals = new AppGatewayApprovals[](1); + approvals[0] = AppGatewayApprovals({appGateway: address(auctionManager), approval: true}); + feesManager.approveAppGateways(approvals); + vm.stopPrank(); + } + + function _connectPlugs() internal { + AppGatewayConfig[] memory configs = new AppGatewayConfig[](4); + configs[0] = AppGatewayConfig({ + chainSlug: arbChainSlug, + plug: address(arbConfig.feesPlug), + plugConfig: PlugConfig({ + appGatewayId: encodeAppGatewayId(address(feesManager)), + switchboard: address(arbConfig.switchboard) + }) + }); + configs[1] = AppGatewayConfig({ + chainSlug: optChainSlug, + plug: address(optConfig.feesPlug), + plugConfig: PlugConfig({ + appGatewayId: encodeAppGatewayId(address(feesManager)), + switchboard: address(optConfig.switchboard) + }) + }); + configs[0] = AppGatewayConfig({ + chainSlug: arbChainSlug, + plug: address(arbConfig.contractFactoryPlug), + plugConfig: PlugConfig({ + appGatewayId: encodeAppGatewayId(address(writePrecompile)), + switchboard: address(arbConfig.switchboard) + }) + }); + configs[1] = AppGatewayConfig({ + chainSlug: optChainSlug, + plug: address(optConfig.contractFactoryPlug), + plugConfig: PlugConfig({ + appGatewayId: encodeAppGatewayId(address(writePrecompile)), + switchboard: address(optConfig.switchboard) + }) + }); + + hoax(address(watcher)); + configurations.setPlugConfigs(configs); + } function _deploySocket(uint32 chainSlug_) internal returns (SocketContracts memory) { // socket @@ -112,7 +198,7 @@ contract SetupTest is SetupStore { socketBatcher: new SocketBatcher(socketOwner, socket), contractFactoryPlug: new ContractFactoryPlug(address(socket), socketOwner), feesPlug: new FeesPlug(address(socket), socketOwner), - feesTokenUSDC: new USDC("USDC", "USDC", 6, socketOwner, 1000000000000000000000000) + testUSDC: new TestUSDC("USDC", "USDC", 6, socketOwner, 1000000000000000000000000) }); } @@ -121,7 +207,8 @@ contract SetupTest is SetupStore { Socket socket = socketConfig.socket; FastSwitchboard switchboard = socketConfig.switchboard; FeesPlug feesPlug = socketConfig.feesPlug; - ERC20 feesTokenUSDC = socketConfig.feesTokenUSDC; + ERC20 testUSDC = socketConfig.testUSDC; + ContractFactoryPlug contractFactoryPlug = socketConfig.contractFactoryPlug; vm.startPrank(socketOwner); // socket @@ -130,37 +217,37 @@ contract SetupTest is SetupStore { // switchboard switchboard.registerSwitchboard(); switchboard.grantRole(WATCHER_ROLE, watcherEOA); + + feesPlug.whitelistToken(address(testUSDC)); + + feesPlug.connectSocket( + encodeAppGatewayId(address(auctionManager)), + address(socket), + address(switchboard) + ); + + contractFactoryPlug.connectSocket( + encodeAppGatewayId(address(writePrecompile)), + address(socket), + address(switchboard) + ); + vm.stopPrank(); vm.startPrank(watcherEOA); - configurations.setSocket(chainSlug_, address(socket)); configurations.setSwitchboard(chainSlug_, FAST, address(switchboard)); // plugs - feesPlug.whitelistToken(address(feesTokenUSDC)); feesManager.setFeesPlug(chainSlug_, address(feesPlug)); // precompiles writePrecompile.updateChainMaxMsgValueLimits(chainSlug_, maxMsgValueLimit); - writePrecompile.setContractFactoryPlugs( - chainSlug_, - address(socketConfig.contractFactoryPlug) - ); + writePrecompile.setContractFactoryPlugs(chainSlug_, address(contractFactoryPlug)); vm.stopPrank(); } - function _deployAndVerifyProxy( - address implementation_, - address owner_, - bytes memory data_ - ) internal returns (address) { - vm.expectEmit(true, true, true, false); - emit Initialized(version); - return address(proxyFactory.deployAndCall(implementation_, owner_, data_)); - } - function _deployEVMxCore() internal { proxyFactory = new ERC1967Factory(); @@ -168,7 +255,6 @@ contract SetupTest is SetupStore { FeesManager feesManagerImpl = new FeesManager(); AddressResolver addressResolverImpl = new AddressResolver(); AsyncDeployer asyncDeployerImpl = new AsyncDeployer(); - AuctionManager auctionManagerImpl = new AuctionManager(); Watcher watcherImpl = new Watcher(); // Deploy and initialize proxies @@ -184,9 +270,9 @@ contract SetupTest is SetupStore { watcherEOA, abi.encodeWithSelector( FeesManager.initialize.selector, + evmxSlug, address(addressResolver), watcherEOA, - evmxSlug, FAST ) ); @@ -203,21 +289,6 @@ contract SetupTest is SetupStore { ); asyncDeployer = AsyncDeployer(asyncDeployerProxy); - address auctionManagerProxy = _deployAndVerifyProxy( - address(auctionManagerImpl), - watcherEOA, - abi.encodeWithSelector( - AuctionManager.initialize.selector, - evmxSlug, - bidTimeout, - maxReAuctionCount, - auctionEndDelaySeconds, - address(addressResolver), - watcherEOA - ) - ); - auctionManager = AuctionManager(auctionManagerProxy); - address watcherProxy = _deployAndVerifyProxy( address(watcherImpl), watcherEOA, @@ -232,8 +303,16 @@ contract SetupTest is SetupStore { watcher = Watcher(watcherProxy); // non proxy contracts + auctionManager = new AuctionManager( + evmxSlug, + uint128(bidTimeout), + maxReAuctionCount, + auctionEndDelaySeconds, + address(addressResolver), + watcherEOA + ); deployForwarder = new DeployForwarder(address(addressResolver), FAST); - configurations = new Configurations(address(watcher)); + configurations = new Configurations(address(watcher), watcherEOA); requestHandler = new RequestHandler(watcherEOA, address(addressResolver)); promiseResolver = new PromiseResolver(address(watcher)); writePrecompile = new WritePrecompile(watcherEOA, address(watcher), writeFees, expiryTime); @@ -247,254 +326,240 @@ contract SetupTest is SetupStore { ); } - function deploy() internal { - _deployEVMxCore(); - - vm.startPrank(watcherEOA); - auctionManager.grantRole(TRANSMITTER_ROLE, transmitterEOA); - - // setup address resolver - addressResolver.setWatcher(address(watcher)); - addressResolver.setAsyncDeployer(address(asyncDeployer)); - addressResolver.setDefaultAuctionManager(address(auctionManager)); - addressResolver.setFeesManager(address(feesManager)); - addressResolver.setDeployForwarder(address(deployForwarder)); - - requestHandler.setPrecompile(WRITE, address(writePrecompile)); - requestHandler.setPrecompile(READ, address(readPrecompile)); - requestHandler.setPrecompile(SCHEDULE, address(schedulePrecompile)); - - watcher.setCoreContracts( - address(requestHandler), - address(configurations), - address(promiseResolver) - ); - vm.stopPrank(); - - hoax(transmitterEOA); - arbConfig.feesPlug.depositCreditAndNative( - arbConfig.feesTokenUSDC, - address(transmitterEOA), - 100 ether - ); - - feesManager.approveAppGateways( - [AppGatewayApprovals({appGateway: address(auctionManager), approval: true})] - ); - - // chain core contracts - arbConfig = _deploySocket(arbChainSlug); - _configureChain(arbChainSlug); - optConfig = _deploySocket(optChainSlug); - _configureChain(optChainSlug); - } - - function _checkIfOnlyReads(uint40 batchCount_) internal view returns (bool) { - bytes32[] memory payloadIds = watcher.getBatchPayloadIds(batchCount_); - - for (uint i = 0; i < payloadIds.length; i++) { - PayloadParams memory payloadParams = watcher.getPayloadParams(payloadIds[i]); - if (payloadParams.payloadHeader.getCallType() != READ) { - return false; - } - } - - return true; - } - - function _resolveAndExpectFinalizeRequested( - bytes32 payloadId_, - PayloadParams memory payloadParams, - bytes memory returnData, - bool isLastPayload - ) internal { - if (isLastPayload) { - vm.expectEmit(false, false, false, false); - emit FinalizeRequested(payloadId_, payloadParams); - } - - _resolvePromise(payloadId_, returnData); - } - - function _finalizeBatch( - uint40 batchCount_, - bytes[] memory readReturnData_, - uint256 readCount_, - bool hasMoreBatches - ) internal returns (uint256) { - bytes32[] memory payloadIds = watcher.getBatchPayloadIds(batchCount_); - - for (uint i = 0; i < payloadIds.length; i++) { - PayloadParams memory payloadParams = watcher.getPayloadParams(payloadIds[i]); - bool isLastPayload = i == payloadIds.length - 1 && hasMoreBatches; - - if (payloadParams.payloadHeader.getCallType() == READ) { - _resolveAndExpectFinalizeRequested( - payloadParams.payloadId, - payloadParams, - readReturnData_[readCount_++], - isLastPayload - ); - } else { - (, bytes memory returnData) = _uploadProofAndExecute(payloadParams); - _resolveAndExpectFinalizeRequested( - payloadParams.payloadId, - payloadParams, - returnData, - isLastPayload - ); - } - } - return readCount_; - } - - function _uploadProofAndExecute( - PayloadParams memory payloadParams - ) internal returns (bool, bytes memory) { - (bytes memory watcherProof, bytes32 digest) = _generateWatcherProof(payloadParams); - _writeProof(payloadParams.payloadId, watcherProof); - - ( - ExecuteParams memory params, - SocketBatcher socketBatcher, - , - bytes memory transmitterSig, - address refundAddress - ) = _getExecuteParams(payloadParams); - - return - socketBatcher.attestAndExecute( - params, - payloadParams.switchboard, - digest, - watcherProof, - transmitterSig, - refundAddress - ); - } - - function resolvePromises(bytes32[] memory payloadIds, bytes[] memory returnData) internal { - for (uint i = 0; i < payloadIds.length; i++) { - _resolvePromise(payloadIds[i], returnData[i]); - } + function _deployAndVerifyProxy( + address implementation_, + address owner_, + bytes memory data_ + ) internal returns (address) { + vm.expectEmit(true, true, true, false); + emit Initialized(version); + return address(proxyFactory.deployAndCall(implementation_, owner_, data_)); } - //////////////////////////////////// Helpers //////////////////////////////////// function getSocketConfig(uint32 chainSlug_) internal view returns (SocketContracts memory) { return chainSlug_ == arbChainSlug ? arbConfig : optConfig; } - function _generateWatcherProof( - PayloadParams memory params_ - ) internal view returns (bytes memory, bytes32) { - SocketContracts memory socketConfig = getSocketConfig(params_.payloadHeader.getChainSlug()); - DigestParams memory digestParams_ = DigestParams( - address(socketConfig.socket), - transmitterEOA, - params_.payloadId, - params_.deadline, - params_.payloadHeader.getCallType(), - params_.gasLimit, - params_.value, - params_.payload, - params_.target, - encodeAppGatewayId(params_.appGateway), - params_.prevDigestsHash - ); - bytes32 digest = watcher.getDigest(digestParams_); + function testDeployAndSetup() public { + deploy(); - bytes32 sigDigest = keccak256( - abi.encode(address(socketConfig.switchboard), socketConfig.chainSlug, digest) - ); - bytes memory proof = _createSignature(sigDigest, watcherPrivateKey); - return (proof, digest); - } + vm.assertEq(address(arbConfig.feesPlug.socket__()), address(arbConfig.socket)); + vm.assertEq(address(optConfig.feesPlug.socket__()), address(optConfig.socket)); - function _writeProof(bytes32 payloadId_, bytes memory watcherProof_) internal { - bytes memory bytesInput = abi.encode( - IWatcher.finalized.selector, - payloadId_, - watcherProof_ - ); - bytes memory watcherSignature = _createWatcherSignature(address(watcher), bytesInput); - watcher.finalized(payloadId_, watcherProof_, signatureNonce++, watcherSignature); - assertEq(watcher.watcherProofs(payloadId_), watcherProof_); - } - - function _getExecuteParams( - PayloadParams memory payloadParams - ) - internal - view - returns ( - ExecuteParams memory params, - SocketBatcher socketBatcher, - uint256 value, - bytes memory transmitterSig, - address refundAddress - ) - { - SocketContracts memory socketConfig = getSocketConfig( - payloadParams.payloadHeader.getChainSlug() - ); - bytes32 transmitterDigest = keccak256( - abi.encode(address(socketConfig.socket), payloadParams.payloadId) - ); - transmitterSig = _createSignature(transmitterDigest, transmitterPrivateKey); - - params = ExecuteParams({ - callType: payloadParams.payloadHeader.getCallType(), - deadline: payloadParams.deadline, - gasLimit: payloadParams.gasLimit, - value: payloadParams.value, - payload: payloadParams.payload, - target: payloadParams.target, - requestCount: payloadParams.payloadHeader.getRequestCount(), - batchCount: payloadParams.payloadHeader.getBatchCount(), - payloadCount: payloadParams.payloadHeader.getPayloadCount(), - prevDigestsHash: payloadParams.prevDigestsHash, - extraData: bytes("") - }); - - value = payloadParams.value; - socketBatcher = socketConfig.socketBatcher; - refundAddress = transmitterEOA; - } - - function _resolvePromise(bytes32 payloadId, bytes memory returnData) internal { - PromiseReturnData[] memory promiseReturnData = new PromiseReturnData[](1); - promiseReturnData[0] = PromiseReturnData({payloadId: payloadId, returnData: returnData}); - - bytes memory watcherSignature = _createWatcherSignature( - address(watcher), - abi.encode(Watcher.resolvePromises.selector, promiseReturnData) - ); - watcher.resolvePromises(promiseReturnData, signatureNonce++, watcherSignature); - } - - function _createWatcherSignature( - address watcherPrecompile_, - bytes memory params_ - ) internal view returns (bytes memory) { - bytes32 digest = keccak256( - abi.encode(watcherPrecompile_, evmxSlug, signatureNonce, params_) - ); - return _createSignature(digest, watcherPrivateKey); - } - - function _createSignature( - bytes32 digest_, - uint256 privateKey_ - ) internal pure returns (bytes memory sig) { - bytes32 digest = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", digest_)); - (uint8 sigV, bytes32 sigR, bytes32 sigS) = vm.sign(privateKey_, digest); - sig = new bytes(65); - bytes1 v32 = bytes1(sigV); - - assembly { - mstore(add(sig, 96), v32) - mstore(add(sig, 32), sigR) - mstore(add(sig, 64), sigS) - } + vm.assertEq(address(arbConfig.contractFactoryPlug.socket__()), address(arbConfig.socket)); + vm.assertEq(address(optConfig.contractFactoryPlug.socket__()), address(optConfig.socket)); } } + +// contract SetupUtilsTest is DeployAndSetupTest { +// function setUp() public { +// deploy(); +// } + +// function _checkIfOnlyReads(uint40 batchCount_) internal view returns (bool) { +// (bytes32[] memory payloadIds, ) = watcher.getBatchPayloadIds(batchCount_); + +// for (uint i = 0; i < payloadIds.length; i++) { +// PayloadParams memory payloadParams = watcher.getPayloadParams(payloadIds[i]); +// if (payloadParams.payloadHeader.getCallType() != READ) { +// return false; +// } +// } + +// return true; +// } + +// function _resolveAndExpectFinalizeRequested( +// bytes32 payloadId_, +// PayloadParams memory payloadParams, +// bytes memory returnData, +// bool isLastPayload +// ) internal { +// if (isLastPayload) { +// vm.expectEmit(false, false, false, false); +// emit FinalizeRequested(payloadId_, payloadParams); +// } + +// _resolvePromise(payloadId_, returnData); +// } + +// function _finalizeBatch( +// uint40 batchCount_, +// bytes[] memory readReturnData_, +// uint256 readCount_, +// bool hasMoreBatches +// ) internal returns (uint256) { +// bytes32[] memory payloadIds = watcher.getBatchPayloadIds(batchCount_); + +// for (uint i = 0; i < payloadIds.length; i++) { +// PayloadParams memory payloadParams = watcher.getPayloadParams(payloadIds[i]); +// bool isLastPayload = i == payloadIds.length - 1 && hasMoreBatches; + +// if (payloadParams.payloadHeader.getCallType() == READ) { +// _resolveAndExpectFinalizeRequested( +// payloadParams.payloadId, +// payloadParams, +// readReturnData_[readCount_++], +// isLastPayload +// ); +// } else { +// (, bytes memory returnData) = _uploadProofAndExecute(payloadParams); +// _resolveAndExpectFinalizeRequested( +// payloadParams.payloadId, +// payloadParams, +// returnData, +// isLastPayload +// ); +// } +// } +// return readCount_; +// } + +// function _uploadProofAndExecute( +// PayloadParams memory payloadParams +// ) internal returns (bool, bytes memory) { +// (bytes memory watcherProof, bytes32 digest) = _generateWatcherProof(payloadParams); +// _writeProof(payloadParams.payloadId, watcherProof); + +// ( +// ExecuteParams memory params, +// SocketBatcher socketBatcher, +// , +// bytes memory transmitterSig, +// address refundAddress +// ) = _getExecuteParams(payloadParams); + +// return +// socketBatcher.attestAndExecute( +// params, +// payloadParams.switchboard, +// digest, +// watcherProof, +// transmitterSig, +// refundAddress +// ); +// } + +// function resolvePromises(bytes32[] memory payloadIds, bytes[] memory returnData) internal { +// for (uint i = 0; i < payloadIds.length; i++) { +// _resolvePromise(payloadIds[i], returnData[i]); +// } +// } + +// //////////////////////////////////// Helpers //////////////////////////////////// +// + +// function _generateWatcherProof( +// PayloadParams memory params_ +// ) internal view returns (bytes memory, bytes32) { +// SocketContracts memory socketConfig = getSocketConfig(params_.payloadHeader.getChainSlug()); +// DigestParams memory digestParams_ = DigestParams( +// address(socketConfig.socket), +// transmitterEOA, +// params_.payloadId, +// params_.deadline, +// params_.payloadHeader.getCallType(), +// params_.gasLimit, +// params_.value, +// params_.payload, +// params_.target, +// encodeAppGatewayId(params_.appGateway), +// params_.prevDigestsHash +// ); +// bytes32 digest = watcher.getDigest(digestParams_); + +// bytes32 sigDigest = keccak256( +// abi.encode(address(socketConfig.switchboard), socketConfig.chainSlug, digest) +// ); +// bytes memory proof = _createSignature(sigDigest, watcherPrivateKey); +// return (proof, digest); +// } + +// function _writeProof(bytes32 payloadId_, bytes memory watcherProof_) internal { +// bytes memory bytesInput = abi.encode( +// IWatcher.finalized.selector, +// payloadId_, +// watcherProof_ +// ); +// bytes memory watcherSignature = _createWatcherSignature(address(watcher), bytesInput); +// watcher.finalized(payloadId_, watcherProof_, signatureNonce++, watcherSignature); +// assertEq(watcher.watcherProofs(payloadId_), watcherProof_); +// } + +// function _getExecuteParams( +// PayloadParams memory payloadParams +// ) +// internal +// view +// returns ( +// ExecuteParams memory params, +// SocketBatcher socketBatcher, +// uint256 value, +// bytes memory transmitterSig, +// address refundAddress +// ) +// { +// SocketContracts memory socketConfig = getSocketConfig( +// payloadParams.payloadHeader.getChainSlug() +// ); +// bytes32 transmitterDigest = keccak256( +// abi.encode(address(socketConfig.socket), payloadParams.payloadId) +// ); +// transmitterSig = _createSignature(transmitterDigest, transmitterPrivateKey); + +// params = ExecuteParams({ +// callType: payloadParams.payloadHeader.getCallType(), +// deadline: payloadParams.deadline, +// gasLimit: payloadParams.gasLimit, +// value: payloadParams.value, +// payload: payloadParams.payload, +// target: payloadParams.target, +// requestCount: payloadParams.payloadHeader.getRequestCount(), +// batchCount: payloadParams.payloadHeader.getBatchCount(), +// payloadCount: payloadParams.payloadHeader.getPayloadCount(), +// prevDigestsHash: payloadParams.prevDigestsHash, +// extraData: bytes("") +// }); + +// value = payloadParams.value; +// socketBatcher = socketConfig.socketBatcher; +// refundAddress = transmitterEOA; +// } + +// function _resolvePromise(bytes32 payloadId, bytes memory returnData) internal { +// PromiseReturnData[] memory promiseReturnData = new PromiseReturnData[](1); +// promiseReturnData[0] = PromiseReturnData({payloadId: payloadId, returnData: returnData}); + +// bytes memory watcherSignature = _createWatcherSignature( +// address(watcher), +// abi.encode(Watcher.resolvePromises.selector, promiseReturnData) +// ); +// watcher.resolvePromises(promiseReturnData, signatureNonce++, watcherSignature); +// } + +// function _createWatcherSignature( +// address watcherPrecompile_, +// bytes memory params_ +// ) internal view returns (bytes memory) { +// bytes32 digest = keccak256( +// abi.encode(watcherPrecompile_, evmxSlug, signatureNonce, params_) +// ); +// return _createSignature(digest, watcherPrivateKey); +// } + +// function _createSignature( +// bytes32 digest_, +// uint256 privateKey_ +// ) internal pure returns (bytes memory sig) { +// bytes32 digest = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", digest_)); +// (uint8 sigV, bytes32 sigR, bytes32 sigS) = vm.sign(privateKey_, digest); +// sig = new bytes(65); +// bytes1 v32 = bytes1(sigV); + +// assembly { +// mstore(add(sig, 96), v32) +// mstore(add(sig, 32), sigR) +// mstore(add(sig, 64), sigS) +// } +// } +// } diff --git a/test/apps/app-gateways/USDC.sol b/test/apps/app-gateways/USDC.sol deleted file mode 100644 index df08d360..00000000 --- a/test/apps/app-gateways/USDC.sol +++ /dev/null @@ -1,41 +0,0 @@ -pragma solidity ^0.8.21; - -import "solady/tokens/ERC20.sol"; - -contract USDC is ERC20 { - string private _name; - string private _symbol; - uint8 private _decimals; - - constructor( - string memory name_, - string memory symbol_, - uint8 decimals_, - address initialSupplyHolder_, - uint256 initialSupply_ - ) { - _name = name_; - _symbol = symbol_; - _decimals = decimals_; - _mint(initialSupplyHolder_, initialSupply_); - } - function name() public view virtual override returns (string memory) { - return _name; - } - - function symbol() public view virtual override returns (string memory) { - return _symbol; - } - - function decimals() public view virtual override returns (uint8) { - return _decimals; - } - - function mint(address to, uint256 amount) external { - _mint(to, amount); - } - - function burn(address from, uint256 amount) external { - _burn(from, amount); - } -} From cffbc7074a9c81266dd6dbf6e381ed77812af657 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Mon, 26 May 2025 17:17:37 +0530 Subject: [PATCH 057/130] fix: write requested --- .../watcher/precompiles/WritePrecompile.sol | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/contracts/evmx/watcher/precompiles/WritePrecompile.sol b/contracts/evmx/watcher/precompiles/WritePrecompile.sol index afaa0302..89c37816 100644 --- a/contracts/evmx/watcher/precompiles/WritePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/WritePrecompile.sol @@ -33,15 +33,13 @@ contract WritePrecompile is IPrecompile, WatcherBase, Ownable { event FeesSet(uint256 writeFees); event ChainMaxMsgValueLimitsUpdated(uint32 chainSlug, uint256 maxMsgValueLimit); event ContractFactoryPlugSet(uint32 chainSlug, address contractFactoryPlug); - /// @notice Emitted when a proof upload request is made event WriteProofRequested( + address transmitter, bytes32 digest, - Transaction transaction, - WriteFinality writeFinality, - uint256 gasLimit, - uint256 value, - address switchboard + bytes32 prevBatchDigestHash, + uint256 deadline, + PayloadParams payloadParams ); /// @notice Emitted when a proof is uploaded @@ -160,7 +158,13 @@ contract WritePrecompile is IPrecompile, WatcherBase, Ownable { bytes32 digest = getDigest(digestParams_); digestHashes[payloadParams.payloadId] = digest; - emit WriteProofRequested(digest, transaction, writeFinality, gasLimit, value, switchboard); + emit WriteProofRequested( + transmitter_, + digest, + prevBatchDigestHash, + deadline, + payloadParams + ); } function _getPrevBatchDigestHash(uint40 batchCount_) internal view returns (bytes32) { From 5416ddc7e143736e3f701f3f6e3dabd87b3d7cee Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Mon, 26 May 2025 17:18:55 +0530 Subject: [PATCH 058/130] fix: stack too deep --- contracts/evmx/watcher/precompiles/WritePrecompile.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/evmx/watcher/precompiles/WritePrecompile.sol b/contracts/evmx/watcher/precompiles/WritePrecompile.sol index 89c37816..7efc487f 100644 --- a/contracts/evmx/watcher/precompiles/WritePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/WritePrecompile.sol @@ -119,7 +119,7 @@ contract WritePrecompile is IPrecompile, WatcherBase, Ownable { /// @return deadline The deadline for the payload function handlePayload( address transmitter_, - PayloadParams calldata payloadParams + PayloadParams memory payloadParams ) external onlyWatcher returns (uint256 fees, uint256 deadline) { fees = writeFees; deadline = block.timestamp + expiryTime; @@ -130,7 +130,7 @@ contract WritePrecompile is IPrecompile, WatcherBase, Ownable { WriteFinality writeFinality, uint256 gasLimit, uint256 value, - address switchboard + ) = abi.decode( payloadParams.precompileData, (address, Transaction, WriteFinality, uint256, uint256, address) From 137ddc4f72695da6dd38467001b732a24501dc1b Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 27 May 2025 16:11:56 +0530 Subject: [PATCH 059/130] fix: renames --- contracts/evmx/AuctionManager.sol | 4 +- contracts/evmx/base/AppGatewayBase.sol | 15 +- contracts/evmx/fees/FeesManager.sol | 24 +- contracts/evmx/helpers/AsyncPromise.sol | 2 +- contracts/evmx/interfaces/IRequestHandler.sol | 5 +- .../precompiles/SchedulePrecompile.sol | 6 +- contracts/utils/common/Errors.sol | 4 +- test-old/DeliveryHelper.t.sol | 337 ------------------ test-old/FeesTest.t.sol | 2 +- {test-old => test/apps}/Counter.t.sol | 4 +- {test-old => test/apps}/ParallelCounter.t.sol | 4 +- {test-old => test/apps}/SuperToken.t.sol | 6 +- .../counter/CounterAppGateway.sol | 15 +- .../super-token/SuperTokenAppGateway.sol | 2 +- test/mock/MockWatcherPrecompile.sol | 31 +- 15 files changed, 50 insertions(+), 411 deletions(-) delete mode 100644 test-old/DeliveryHelper.t.sol rename {test-old => test/apps}/Counter.t.sol (98%) rename {test-old => test/apps}/ParallelCounter.t.sol (98%) rename {test-old => test/apps}/SuperToken.t.sol (97%) diff --git a/contracts/evmx/AuctionManager.sol b/contracts/evmx/AuctionManager.sol index 98c12a67..794ea10e 100644 --- a/contracts/evmx/AuctionManager.sol +++ b/contracts/evmx/AuctionManager.sol @@ -17,7 +17,7 @@ abstract contract AuctionManagerStorage is IAuctionManager { uint32 public immutable evmxSlug; // slot 50 - /// @notice The timeout after which a bid expires + /// @notice The time after which a bid expires uint128 public bidTimeout; // slot 51 @@ -162,7 +162,7 @@ contract AuctionManager is AuctionManagerStorage, AccessControl, AppGatewayBase // todo: might block the request processing if transmitter don't have enough balance for this schedule // this case can hit when bid timeout is more than 0 - // set the timeout for the bid expiration + // set the bid expiration time // useful in case a transmitter did bid but did not execute payloads _createRequest( bidTimeout, diff --git a/contracts/evmx/base/AppGatewayBase.sol b/contracts/evmx/base/AppGatewayBase.sol index b4181e02..506f8e53 100644 --- a/contracts/evmx/base/AppGatewayBase.sol +++ b/contracts/evmx/base/AppGatewayBase.sol @@ -87,9 +87,9 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { return keccak256(abi.encode(contractName_)); } - /// @notice Gets the current async ID - /// @return uint40 The current async ID - function _getCurrentAsyncId() internal view returns (uint40) { + /// @notice Gets the current request count + /// @return uint40 The current request count + function _getCurrentRequestCount() internal view returns (uint40) { return watcher__().getCurrentRequestCount(); } @@ -165,7 +165,7 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { /// @notice Schedules a function to be called after a delay /// @param delayInSeconds_ The delay in seconds /// @dev callback function and data is set in .then call - function _setTimeout(uint256 delayInSeconds_) internal { + function _setSchedule(uint256 delayInSeconds_) internal { if (!isAsyncModifierSet) revert AsyncModifierNotSet(); overrideParams.callType = SCHEDULE; overrideParams.delayInSeconds = delayInSeconds_; @@ -187,7 +187,8 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { return address(0); } - onChainAddress = IForwarder(forwarderAddresses[contractId_][chainSlug_]).getOnChainAddress(); + onChainAddress = IForwarder(forwarderAddresses[contractId_][chainSlug_]) + .getOnChainAddress(); } function _setCallType(Read isReadCall_) internal { @@ -309,13 +310,13 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { //////////////////////////////////////////////////////////////////////////////////////////////// /// @notice Reverts the transaction - /// @param requestCount_ The async ID + /// @param requestCount_ The request count function _revertTx(uint40 requestCount_) internal { watcher__().requestHandler__().cancelRequest(requestCount_); } /// @notice increases the transaction maxFees - /// @param requestCount_ The async ID + /// @param requestCount_ The request count function _increaseFees(uint40 requestCount_, uint256 newMaxFees_) internal { watcher__().requestHandler__().increaseFees(requestCount_, newMaxFees_); } diff --git a/contracts/evmx/fees/FeesManager.sol b/contracts/evmx/fees/FeesManager.sol index fd54e4c0..845822a0 100644 --- a/contracts/evmx/fees/FeesManager.sol +++ b/contracts/evmx/fees/FeesManager.sol @@ -12,17 +12,6 @@ contract FeesManager is Credit { /// @param amount The blocked amount event CreditsBlocked(uint40 indexed requestCount, address indexed consumeFrom, uint256 amount); - /// @notice Emitted when transmitter fees are updated - /// @param requestCount The batch identifier - /// @param transmitter The transmitter address - /// @param amount The new amount deposited - event TransmitterCreditsUpdated( - uint40 indexed requestCount, - address indexed transmitter, - uint256 amount - ); - event WatcherPrecompileCreditsAssigned(uint256 amount, address consumeFrom); - /// @notice Emitted when fees are unblocked and assigned to a transmitter /// @param requestCount The batch identifier /// @param consumeFrom The consume from address @@ -37,15 +26,8 @@ contract FeesManager is Credit { /// @notice Emitted when fees are unblocked /// @param requestCount The batch identifier - /// @param appGateway The app gateway address - event CreditsUnblocked(uint40 indexed requestCount, address indexed appGateway); - - /// @notice Emitted when insufficient watcher precompile fees are available - event InsufficientWatcherPrecompileCreditsAvailable( - uint32 chainSlug, - address token, - address consumeFrom - ); + /// @param consumeFrom The consume from address + event CreditsUnblocked(uint40 indexed requestCount, address indexed consumeFrom); modifier onlyRequestHandler() { if (msg.sender != address(watcher__().requestHandler__())) revert NotRequestHandler(); @@ -93,7 +75,7 @@ contract FeesManager is Credit { } /// @notice Unblocks fees after successful execution and assigns them to the transmitter - /// @param requestCount_ The async ID of the executed batch + /// @param requestCount_ The request count of the executed batch /// @param assignTo_ The address of the transmitter function unblockAndAssignCredits( uint40 requestCount_, diff --git a/contracts/evmx/helpers/AsyncPromise.sol b/contracts/evmx/helpers/AsyncPromise.sol index e44bc16f..bd23bca0 100644 --- a/contracts/evmx/helpers/AsyncPromise.sol +++ b/contracts/evmx/helpers/AsyncPromise.sol @@ -24,7 +24,7 @@ abstract contract AsyncPromiseStorage is IPromise { /// @notice The request count of the promise uint40 public override requestCount; - /// @notice The local contract which initiated the async call. + /// @notice The local contract which initiated the call. /// @dev The callback will be executed on this address address public override localInvoker; diff --git a/contracts/evmx/interfaces/IRequestHandler.sol b/contracts/evmx/interfaces/IRequestHandler.sol index 84ad6092..b224a825 100644 --- a/contracts/evmx/interfaces/IRequestHandler.sol +++ b/contracts/evmx/interfaces/IRequestHandler.sol @@ -13,7 +13,10 @@ interface IRequestHandler { function payloads(bytes32 payloadId_) external view returns (PayloadParams memory); - function getPrecompileFees(bytes4 precompile_, bytes memory precompileData_) external view returns (uint256); + function getPrecompileFees( + bytes4 precompile_, + bytes memory precompileData_ + ) external view returns (uint256); function nextRequestCount() external view returns (uint40); diff --git a/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol b/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol index aa7840ba..85b185ca 100644 --- a/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.21; import "../../interfaces/IPrecompile.sol"; import "../../../utils/common/Structs.sol"; -import {InvalidScheduleDelay, ResolvingTimeoutTooEarly} from "../../../utils/common/Errors.sol"; +import {InvalidScheduleDelay, ResolvingScheduleTooEarly} from "../../../utils/common/Errors.sol"; import "../WatcherBase.sol"; /// @title SchedulePrecompile @@ -122,12 +122,12 @@ contract SchedulePrecompile is IPrecompile, WatcherBase { deadline = block.timestamp + delayInSeconds + expiryTime; fees = scheduleFeesPerSecond * delayInSeconds + scheduleCallbackFees; - // emits event for watcher to track timeout and resolve when timeout is reached + // emits event for watcher to track schedule and resolve when deadline is reached emit ScheduleRequested(payloadParams.payloadId, deadline); } function resolvePayload(PayloadParams calldata payloadParams_) external { - if (block.timestamp < payloadParams_.deadline) revert ResolvingTimeoutTooEarly(); + if (block.timestamp < payloadParams_.deadline) revert ResolvingScheduleTooEarly(); emit ScheduleResolved(payloadParams_.payloadId); } diff --git a/contracts/utils/common/Errors.sol b/contracts/utils/common/Errors.sol index e605b88e..896c820d 100644 --- a/contracts/utils/common/Errors.sol +++ b/contracts/utils/common/Errors.sol @@ -12,8 +12,7 @@ error NotSocket(); error PlugNotFound(); // EVMx -error TimeoutAlreadyResolved(); -error ResolvingTimeoutTooEarly(); +error ResolvingScheduleTooEarly(); error CallFailed(); error InvalidAppGateway(); error AppGatewayAlreadyCalled(); @@ -28,7 +27,6 @@ error InvalidIndex(); error InvalidChainSlug(); error InvalidPayloadSize(); error InvalidScheduleDelay(); -error InvalidTimeoutRequest(); /// @notice Error thrown when trying to start or bid a closed auction error AuctionClosed(); /// @notice Error thrown when trying to start or bid an auction that is not open diff --git a/test-old/DeliveryHelper.t.sol b/test-old/DeliveryHelper.t.sol deleted file mode 100644 index f59a504a..00000000 --- a/test-old/DeliveryHelper.t.sol +++ /dev/null @@ -1,337 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -pragma solidity ^0.8.21; - -import "./SetupTest.t.sol"; - -interface IAppGatewayDeployer { - function deployContracts(uint32 chainSlug_) external; -} - -contract DeliveryHelperTest is SetupTest { - uint256 public maxFees = 0.0001 ether; - uint256 public bidAmount = maxFees / 100; - uint256 public deployCounter; - uint256 public asyncPromiseCounterLocal = 0; - bytes public asyncPromiseBytecode = type(AsyncPromise).creationCode; - - - event PayloadSubmitted( - uint40 indexed requestCount, - address indexed appGateway, - PayloadParams[] payloadParams, - uint256 maxFees, - address auctionManager, - bool onlyReadRequests - ); - event BidPlaced(uint40 requestCount, Bid bid); - event AuctionEnded(uint40 indexed requestCount, Bid winningBid); - event RequestCancelled(uint40 indexed requestCount); - event QueryRequested(uint32 chainSlug, address targetAddress, bytes32 payloadId, bytes payload); - - - function connectDeliveryHelper() internal { - vm.startPrank(owner); - arbConfig.contractFactoryPlug.initSocket( - _encodeAppGatewayId(address(deliveryHelper)), - address(arbConfig.socket), - address(arbConfig.switchboard) - ); - optConfig.contractFactoryPlug.initSocket( - _encodeAppGatewayId(address(deliveryHelper)), - address(optConfig.socket), - address(optConfig.switchboard) - ); - - arbConfig.feesPlug.initSocket( - _encodeAppGatewayId(address(feesManager)), - address(arbConfig.socket), - address(arbConfig.switchboard) - ); - optConfig.feesPlug.initSocket( - _encodeAppGatewayId(address(feesManager)), - address(optConfig.socket), - address(optConfig.switchboard) - ); - vm.stopPrank(); - - AppGatewayConfig[] memory gateways = new AppGatewayConfig[](4); - gateways[0] = AppGatewayConfig({ - plug: address(arbConfig.contractFactoryPlug), - chainSlug: arbChainSlug, - appGatewayId: _encodeAppGatewayId(address(deliveryHelper)), - switchboard: address(arbConfig.switchboard) - }); - gateways[1] = AppGatewayConfig({ - plug: address(optConfig.contractFactoryPlug), - chainSlug: optChainSlug, - appGatewayId: _encodeAppGatewayId(address(deliveryHelper)), - switchboard: address(optConfig.switchboard) - }); - gateways[2] = AppGatewayConfig({ - plug: address(arbConfig.feesPlug), - chainSlug: arbChainSlug, - appGatewayId: _encodeAppGatewayId(address(feesManager)), - switchboard: address(arbConfig.switchboard) - }); - gateways[3] = AppGatewayConfig({ - plug: address(optConfig.feesPlug), - chainSlug: optChainSlug, - appGatewayId: _encodeAppGatewayId(address(feesManager)), - switchboard: address(optConfig.switchboard) - }); - - bytes memory watcherSignature = _createWatcherSignature( - address(watcherPrecompileConfig), - abi.encode(IWatcherPrecompileConfig.setAppGateways.selector, gateways) - ); - watcherPrecompileConfig.setAppGateways(gateways, signatureNonce++, watcherSignature); - } - - //////////////////////////////////// Fees //////////////////////////////////// - - function depositUSDCFees(address appGateway_, uint256 fees_) internal { - SocketContracts memory socketConfig = getSocketConfig(fees_.chainSlug); - vm.startPrank(owner); - ERC20(fees_.token).approve(address(socketConfig.feesPlug), fees_.amount); - socketConfig.feesPlug.depositToFeeAndNative(fees_.token, appGateway_, fees_.amount); - vm.stopPrank(); - - bytes32 digest = keccak256( - abi.encode( - appGateway_, - fees_.chainSlug, - fees_.token, - fees_.amount, - address(feesManager), - evmxSlug - ) - ); - - feesManager.depositCredits{value: fees_.amount}( - appGateway_, - fees_.chainSlug, - fees_.token, - signatureNonce++, - _createSignature(digest, watcherPrivateKey) - ); - } - - function whitelistAppGateway( - address appGateway_, - address user_, - uint256 userPrivateKey_, - uint32 chainSlug_ - ) internal { - SocketContracts memory socketConfig = getSocketConfig(chainSlug_); - // Create fee approval data with signature - bytes32 digest = keccak256( - abi.encode( - address(feesManager), - evmxSlug, - user_, - appGateway_, - feesManager.userNonce(user_), - true - ) - ); - - // Sign with consumeFrom's private key - bytes memory signature = _createSignature(digest, userPrivateKey_); - - // Encode approval data - bytes memory feeApprovalData = abi.encode(user_, appGateway_, true, signature); - - // Call whitelistAppGatewayWithSignature with approval data - feesManager.whitelistAppGatewayWithSignature(feeApprovalData); - } - - ////////////////////////////////// Deployment helpers //////////////////////////////////// - function _deploy( - uint32 chainSlug_, - IAppGateway appGateway_, - bytes32[] memory contractIds_ - ) internal returns (uint40 requestCount) { - requestCount = watcherPrecompile.nextRequestCount(); - IAppGatewayDeployer(address(appGateway_)).deployContracts(chainSlug_); - - finalizeRequest(requestCount, new bytes[](0)); - setupGatewayAndPlugs(chainSlug_, appGateway_, contractIds_); - } - - function finalizeRequest(uint40 requestCount_, bytes[] memory readReturnData_) internal { - uint40[] memory batches = watcherPrecompile.getBatches(requestCount_); - - bool onlyReads = _checkIfOnlyReads(batches[0]); - if (!(onlyReads && batches.length == 1)) { - bidAndEndAuction(requestCount_); - } - - uint256 readCount = 0; - for (uint i = 0; i < batches.length; i++) { - bool hasMoreBatches = i < batches.length - 1; - readCount = _finalizeBatch(batches[i], readReturnData_, readCount, hasMoreBatches); - } - } - - function executeRequest(bytes[] memory readReturnData_) internal { - uint40 requestCount = watcherPrecompile.nextRequestCount(); - requestCount = requestCount == 0 ? 0 : requestCount - 1; - finalizeRequest(requestCount, readReturnData_); - } - - function setupGatewayAndPlugs( - uint32 chainSlug_, - IAppGateway appGateway_, - bytes32[] memory contractIds_ - ) internal { - AppGatewayConfig[] memory gateways = new AppGatewayConfig[](contractIds_.length); - - SocketContracts memory socketConfig = getSocketConfig(chainSlug_); - for (uint i = 0; i < contractIds_.length; i++) { - address plug = appGateway_.getOnChainAddress(contractIds_[i], chainSlug_); - - gateways[i] = AppGatewayConfig({ - plug: plug, - chainSlug: chainSlug_, - appGatewayId: _encodeAppGatewayId(address(appGateway_)), - switchboard: address(socketConfig.switchboard) - }); - } - - bytes memory watcherSignature = _createWatcherSignature( - address(watcherPrecompileConfig), - abi.encode(IWatcherPrecompileConfig.setAppGateways.selector, gateways) - ); - watcherPrecompileConfig.setAppGateways(gateways, signatureNonce++, watcherSignature); - } - - //////////////////////////////////// Auction //////////////////////////////////// - function placeBid(uint40 requestCount) internal { - bytes memory transmitterSignature = _createSignature( - keccak256(abi.encode(address(auctionManager), evmxSlug, requestCount, bidAmount, "")), - transmitterPrivateKey - ); - - vm.expectEmit(false, false, false, false); - emit BidPlaced( - requestCount, - Bid({transmitter: transmitterEOA, fee: bidAmount, extraData: bytes("")}) - ); - auctionManager.bid(requestCount, bidAmount, transmitterSignature, bytes("")); - } - - function endAuction(uint40 requestCount_) internal { - if (auctionEndDelaySeconds == 0) return; - bytes32 timeoutId = _encodeTimeoutId( - evmxSlug, - address(watcherPrecompile), - timeoutIdCounter++ - ); - - bytes memory watcherSignature = _createWatcherSignature( - address(watcherPrecompile), - abi.encode(IWatcherPrecompile.resolveTimeout.selector, timeoutId) - ); - - vm.expectEmit(true, true, true, true); - emit AuctionEnded( - requestCount_, - Bid({fee: bidAmount, transmitter: transmitterEOA, extraData: ""}) - ); - watcherPrecompile.resolveTimeout(timeoutId, signatureNonce++, watcherSignature); - } - - function bidAndEndAuction(uint40 requestCount) internal { - placeBid(requestCount); - endAuction(requestCount); - } - - //////////////////////////////////// Utils /////////////////////////////////// - function _encodeTimeoutId( - uint32 chainSlug_, - address sbOrWatcher_, - uint256 counter_ - ) internal pure returns (bytes32) { - return - bytes32( - (uint256(chainSlug_) << 224) | (uint256(uint160(sbOrWatcher_)) << 64) | counter_ - ); - } - - function getOnChainAndForwarderAddresses( - uint32 chainSlug_, - bytes32 contractId_, - IAppGateway appGateway_ - ) internal view returns (address, address) { - address app = appGateway_.getOnChainAddress(contractId_, chainSlug_); - address forwarder = appGateway_.forwarderAddresses(contractId_, chainSlug_); - return (app, forwarder); - } - - function getContractFactoryPlug(uint32 chainSlug_) internal view returns (address) { - return address(getSocketConfig(chainSlug_).contractFactoryPlug); - } - - //////////////////////////////////// Helpers //////////////////////////////////// - function predictAsyncPromiseAddress( - address invoker_, - address forwarder_ - ) internal returns (address) { - bytes memory constructorArgs = abi.encode(invoker_, forwarder_, address(addressResolver)); - bytes memory combinedBytecode = abi.encodePacked(asyncPromiseBytecode, constructorArgs); - - bytes32 salt = keccak256(abi.encodePacked(constructorArgs, asyncPromiseCounterLocal++)); - - bytes32 hash = keccak256( - abi.encodePacked( - bytes1(0xff), - address(addressResolver), - salt, - keccak256(combinedBytecode) - ) - ); - - return address(uint160(uint256(hash))); - } - - //////////////////////////////////// Validators //////////////////////////////////// - - function checkPayloadRequestAndDetails( - PayloadParams[] memory payloadParams, - uint40 requestCount, - address appGateway_ - ) internal view { - for (uint i = 0; i < payloadParams.length; i++) { - PayloadParams memory payloadSubmitParam = payloadParams[i]; - - assertEq( - payloadSubmitParam.chainSlug, - payloadParams[i].chainSlug, - "ChainSlug mismatch" - ); - assertEq(payloadSubmitParam.target, payloadParams[i].target, "Target mismatch"); - assertEq( - keccak256(payloadSubmitParam.payload), - keccak256(payloadParams[i].payload), - "Payload mismatch" - ); - assertEq( - uint(payloadSubmitParam.callType), - uint(payloadParams[i].callType), - "CallType mismatch" - ); - assertEq(payloadSubmitParam.gasLimit, payloadParams[i].gasLimit, "gasLimit mismatch"); - } - - RequestMetadata memory payloadRequest = deliveryHelper.getRequestMetadata(requestCount); - - assertEq(payloadRequest.appGateway, appGateway_, "AppGateway mismatch"); - assertEq(payloadRequest.auctionManager, address(auctionManager), "AuctionManager mismatch"); - assertEq(payloadRequest.winningBid.fee, bidAmount, "WinningBid mismatch"); - assertEq( - payloadRequest.winningBid.transmitter, - transmitterEOA, - "WinningBid transmitter mismatch" - ); - } -} diff --git a/test-old/FeesTest.t.sol b/test-old/FeesTest.t.sol index 1f6a0ba0..323b3f7d 100644 --- a/test-old/FeesTest.t.sol +++ b/test-old/FeesTest.t.sol @@ -56,7 +56,7 @@ contract FeesTest is DeliveryHelperTest { ); vm.stopPrank(); uint40[] memory batches = watcherPrecompile.getBatches(requestCount); - _finalizeBatch(batches[0], new bytes[](0), 0, false); + _processBatch(batches[0], new bytes[](0), 0, false); assertEq( transmitterReceiverBalanceBefore + withdrawAmount, feesConfig.feesTokenUSDC.balanceOf(receiver), diff --git a/test-old/Counter.t.sol b/test/apps/Counter.t.sol similarity index 98% rename from test-old/Counter.t.sol rename to test/apps/Counter.t.sol index f2c58c2c..3185baf1 100644 --- a/test-old/Counter.t.sol +++ b/test/apps/Counter.t.sol @@ -3,9 +3,9 @@ pragma solidity ^0.8.21; import {CounterAppGateway} from "./app-gateways/counter/CounterAppGateway.sol"; import {Counter} from "./app-gateways/counter/Counter.sol"; -import "../DeliveryHelper.t.sol"; +import "../SetupTest.t.sol"; -contract CounterTest is DeliveryHelperTest { +contract CounterTest is AppGatewayBaseSetup { uint256 feesAmount = 0.01 ether; bytes32 counterId; diff --git a/test-old/ParallelCounter.t.sol b/test/apps/ParallelCounter.t.sol similarity index 98% rename from test-old/ParallelCounter.t.sol rename to test/apps/ParallelCounter.t.sol index 5e7e193f..d1d386ce 100644 --- a/test-old/ParallelCounter.t.sol +++ b/test/apps/ParallelCounter.t.sol @@ -2,9 +2,9 @@ pragma solidity ^0.8.21; import {CounterAppGateway} from "./app-gateways/counter/CounterAppGateway.sol"; -import "../DeliveryHelper.t.sol"; +import "../SetupTest.t.sol"; -contract ParallelCounterTest is DeliveryHelperTest { +contract ParallelCounterTest is AppGatewayBaseSetup { uint256 feesAmount = 0.01 ether; bytes32 counterId1; diff --git a/test-old/SuperToken.t.sol b/test/apps/SuperToken.t.sol similarity index 97% rename from test-old/SuperToken.t.sol rename to test/apps/SuperToken.t.sol index 1454e13c..d23ba50a 100644 --- a/test-old/SuperToken.t.sol +++ b/test/apps/SuperToken.t.sol @@ -3,13 +3,13 @@ pragma solidity ^0.8.21; import {SuperTokenAppGateway} from "./app-gateways/super-token/SuperTokenAppGateway.sol"; import {SuperToken} from "./app-gateways/super-token/SuperToken.sol"; -import "../DeliveryHelper.t.sol"; +import "../SetupTest.t.sol"; /** * @title SuperToken Test * @notice Test contract for verifying the functionality of the SuperToken system, which enables * multi-chain token bridging capabilities. - * @dev Inherits from DeliveryHelperTest to utilize multi-chain messaging infrastructure + * @dev Inherits from AppGatewayBaseSetup to utilize multi-chain messaging infrastructure * * The test suite validates: * - Contract deployment across different chains @@ -17,7 +17,7 @@ import "../DeliveryHelper.t.sol"; * - Proper balance updates * - Integration with the delivery and auction system */ -contract SuperTokenTest is DeliveryHelperTest { +contract SuperTokenTest is AppGatewayBaseSetup { /** * @notice Groups the main contracts needed for SuperToken functionality * @param superTokenApp The gateway contract that handles multi-chain token operations diff --git a/test/apps/app-gateways/counter/CounterAppGateway.sol b/test/apps/app-gateways/counter/CounterAppGateway.sol index 258e18d4..cd7f69df 100644 --- a/test/apps/app-gateways/counter/CounterAppGateway.sol +++ b/test/apps/app-gateways/counter/CounterAppGateway.sol @@ -15,7 +15,7 @@ contract CounterAppGateway is AppGatewayBase, Ownable { uint256 public arbCounter; uint256 public optCounter; - event TimeoutResolved(uint256 creationTimestamp, uint256 executionTimestamp); + event ScheduleResolved(uint256 creationTimestamp, uint256 executionTimestamp); constructor(address addressResolver_, uint256 fees_) AppGatewayBase(addressResolver_) { creationCodeWithArgs[counter] = abi.encodePacked(type(Counter).creationCode); @@ -55,7 +55,6 @@ contract CounterAppGateway is AppGatewayBase, Ownable { function incrementCounters(address[] memory instances_) public async { // the increase function is called on given list of instances - // this for (uint256 i = 0; i < instances_.length; i++) { ICounter(instances_[i]).increase(); } @@ -106,14 +105,14 @@ contract CounterAppGateway is AppGatewayBase, Ownable { counterVal += value_; } - // TIMEOUT - function setTimeout(uint256 delayInSeconds_) public async { - _setTimeout(delayInSeconds_); - then(this.resolveTimeout.selector, abi.encode(block.timestamp)); + // Schedule + function setSchedule(uint256 delayInSeconds_) public async { + _setSchedule(delayInSeconds_); + then(this.resolveSchedule.selector, abi.encode(block.timestamp)); } - function resolveTimeout(uint256 creationTimestamp_) external onlyPromises { - emit TimeoutResolved(creationTimestamp_, block.timestamp); + function resolveSchedule(uint256 creationTimestamp_) external onlyPromises { + emit ScheduleResolved(creationTimestamp_, block.timestamp); } // UTILS diff --git a/test/apps/app-gateways/super-token/SuperTokenAppGateway.sol b/test/apps/app-gateways/super-token/SuperTokenAppGateway.sol index 5a362ccd..77657fd7 100644 --- a/test/apps/app-gateways/super-token/SuperTokenAppGateway.sol +++ b/test/apps/app-gateways/super-token/SuperTokenAppGateway.sol @@ -65,6 +65,6 @@ contract SuperTokenAppGateway is AppGatewayBase, Ownable { ISuperToken(order.srcToken).burn(order.user, order.srcAmount); ISuperToken(order.dstToken).mint(order.user, order.srcAmount); - emit Transferred(_getCurrentAsyncId()); + emit Transferred(_getCurrentRequestCount()); } } diff --git a/test/mock/MockWatcherPrecompile.sol b/test/mock/MockWatcherPrecompile.sol index 6de1c37e..3ef3a50a 100644 --- a/test/mock/MockWatcherPrecompile.sol +++ b/test/mock/MockWatcherPrecompile.sol @@ -20,38 +20,31 @@ contract MockWatcherPrecompile { event CalledAppGateway(bytes32 triggerId); - /// @notice Emitted when a new query is requested + /// @notice Emitted when a new read is requested /// @param chainSlug The identifier of the destination chain /// @param targetAddress The address of the target contract - /// @param payloadId The unique identifier for the query - /// @param payload The query data - event QueryRequested(uint32 chainSlug, address targetAddress, bytes32 payloadId, bytes payload); + /// @param payloadId The unique identifier for the read + /// @param payload The read data + event ReadRequested(uint32 chainSlug, address targetAddress, bytes32 payloadId, bytes payload); - /// @notice Emitted when a finalize request is made - event FinalizeRequested(bytes32 digest, PayloadParams params); + /// @notice Emitted when a write proof is requested + event WriteProofRequested(bytes32 digest, PayloadParams params); - /// @notice Emitted when a request is finalized + /// @notice Emitted when a request proof is uploaded /// @param payloadId The unique identifier for the request /// @param proof The proof from the watcher - event Finalized(bytes32 indexed payloadId, bytes proof); + event WriteProofUploaded(bytes32 indexed payloadId, bytes proof); /// @notice Emitted when a promise is resolved /// @param payloadId The unique identifier for the resolved promise event PromiseResolved(bytes32 indexed payloadId); - event TimeoutRequested( - bytes32 timeoutId, - address target, - bytes payload, - uint256 executeAt // Epoch time when the task should execute - ); - - /// @notice Emitted when a timeout is resolved - /// @param timeoutId The unique identifier for the timeout - /// @param target The target address for the timeout + /// @notice Emitted when a Schedule is resolved + /// @param scheduleId The unique identifier for the Schedule + /// @param target The target address for the Schedule /// @param payload The payload data /// @param executedAt The epoch time when the task was executed - event TimeoutResolved(bytes32 timeoutId, address target, bytes payload, uint256 executedAt); + event ScheduleResolved(bytes32 scheduleId, address target, bytes payload, uint256 executedAt); /// @notice Contract constructor /// @param _owner Address of the contract owner From 098a2f5cb248aad296f8513f0f2178bb485df951 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 27 May 2025 17:41:04 +0530 Subject: [PATCH 060/130] fix: interface --- contracts/evmx/base/AppGatewayBase.sol | 7 +- contracts/evmx/interfaces/IRequestHandler.sol | 12 +-- contracts/evmx/interfaces/IWatcher.sol | 6 ++ contracts/evmx/watcher/RequestHandler.sol | 96 +++++++++++-------- contracts/evmx/watcher/Watcher.sol | 20 +++- .../watcher/precompiles/WritePrecompile.sol | 10 +- contracts/protocol/SocketUtils.sol | 5 +- contracts/utils/common/Structs.sol | 7 ++ 8 files changed, 105 insertions(+), 58 deletions(-) diff --git a/contracts/evmx/base/AppGatewayBase.sol b/contracts/evmx/base/AppGatewayBase.sol index 506f8e53..877ed2c9 100644 --- a/contracts/evmx/base/AppGatewayBase.sol +++ b/contracts/evmx/base/AppGatewayBase.sol @@ -187,8 +187,7 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { return address(0); } - onChainAddress = IForwarder(forwarderAddresses[contractId_][chainSlug_]) - .getOnChainAddress(); + onChainAddress = IForwarder(forwarderAddresses[contractId_][chainSlug_]).getOnChainAddress(); } function _setCallType(Read isReadCall_) internal { @@ -312,13 +311,13 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { /// @notice Reverts the transaction /// @param requestCount_ The request count function _revertTx(uint40 requestCount_) internal { - watcher__().requestHandler__().cancelRequest(requestCount_); + watcher__().cancelRequest(requestCount_); } /// @notice increases the transaction maxFees /// @param requestCount_ The request count function _increaseFees(uint40 requestCount_, uint256 newMaxFees_) internal { - watcher__().requestHandler__().increaseFees(requestCount_, newMaxFees_); + watcher__().increaseFees(requestCount_, newMaxFees_); } /// @notice Withdraws fee tokens diff --git a/contracts/evmx/interfaces/IRequestHandler.sol b/contracts/evmx/interfaces/IRequestHandler.sol index b224a825..e2871ef1 100644 --- a/contracts/evmx/interfaces/IRequestHandler.sol +++ b/contracts/evmx/interfaces/IRequestHandler.sol @@ -5,13 +5,13 @@ import "../../utils/common/Structs.sol"; import "../interfaces/IPrecompile.sol"; interface IRequestHandler { - function requestBatchIds(uint40 batchCount_) external view returns (uint40[] memory); + function getRequestBatchIds(uint40 requestCount_) external view returns (uint40[] memory); - function batchPayloadIds(uint40 batchCount_) external view returns (bytes32[] memory); + function getBatchPayloadIds(uint40 batchCount_) external view returns (bytes32[] memory); - function requests(uint40 requestCount_) external view returns (RequestParams memory); + function getRequest(uint40 requestCount_) external view returns (RequestParams memory); - function payloads(bytes32 payloadId_) external view returns (PayloadParams memory); + function getPayload(bytes32 payloadId_) external view returns (PayloadParams memory); function getPrecompileFees( bytes4 precompile_, @@ -37,9 +37,9 @@ interface IRequestHandler { function cancelRequestForReverts(uint40 requestCount) external; - function cancelRequest(uint40 requestCount) external; + function cancelRequest(uint40 requestCount, address appGateway_) external; function handleRevert(uint40 requestCount) external; - function increaseFees(uint40 requestCount_, uint256 newMaxFees_) external; + function increaseFees(uint40 requestCount_, uint256 newMaxFees_, address appGateway_) external; } diff --git a/contracts/evmx/interfaces/IWatcher.sol b/contracts/evmx/interfaces/IWatcher.sol index 6831e19d..a0eac8fa 100644 --- a/contracts/evmx/interfaces/IWatcher.sol +++ b/contracts/evmx/interfaces/IWatcher.sol @@ -77,5 +77,11 @@ interface IWatcher { bytes memory precompileData_ ) external view returns (uint256); + function cancelRequest(uint40 requestCount_) external; + + function increaseFees(uint40 requestCount_, uint256 newFees_) external; + + function setIsValidPlug(bool isValid_, uint32 chainSlug_, address onchainAddress_) external; + function isWatcher(address account_) external view returns (bool); } diff --git a/contracts/evmx/watcher/RequestHandler.sol b/contracts/evmx/watcher/RequestHandler.sol index 16cc3270..19de5293 100644 --- a/contracts/evmx/watcher/RequestHandler.sol +++ b/contracts/evmx/watcher/RequestHandler.sol @@ -7,43 +7,38 @@ import "../../utils/common/Constants.sol"; import "../../utils/common/IdUtils.sol"; import "../interfaces/IAppGateway.sol"; import "../interfaces/IPromise.sol"; +import "../interfaces/IRequestHandler.sol"; import "solady/auth/Ownable.sol"; /// @title RequestHandler /// @notice Contract that handles request processing and management, including request submission, batch processing, and request lifecycle management /// @dev Handles request submission, batch processing, transmitter assignment, request cancellation and settlement /// @dev This contract interacts with the WatcherPrecompileStorage for storage access -contract RequestHandler is AddressResolverUtil, Ownable { +contract RequestHandler is AddressResolverUtil, Ownable, IRequestHandler { /// @notice Counter for tracking request counts uint40 public nextRequestCount = 1; - /// @notice Counter for tracking payload requests + /// @notice Counter for tracking payload _requests uint40 public payloadCounter; /// @notice Counter for tracking batch counts uint40 public nextBatchCount; + /// @notice Mapping to store the precompiles for each call type + mapping(bytes4 => IPrecompile) public precompiles; + /// @notice Mapping to store the list of payload IDs for each batch - mapping(uint40 => bytes32[]) public batchPayloadIds; + mapping(uint40 => bytes32[]) internal _batchPayloadIds; /// @notice Mapping to store the batch IDs for each request - mapping(uint40 => uint40[]) public requestBatchIds; - - /// @notice Mapping to store the precompiles for each call type - mapping(bytes4 => IPrecompile) public precompiles; + mapping(uint40 => uint40[]) internal _requestBatchIds; // queue => update to payloadParams, assign id, store in payloadParams map /// @notice Mapping to store the payload parameters for each payload ID - mapping(bytes32 => PayloadParams) public payloads; + mapping(bytes32 => PayloadParams) internal _payloads; /// @notice The metadata for a request - mapping(uint40 => RequestParams) public requests; - struct CreateRequestResult { - uint256 totalEstimatedWatcherFees; - uint256 writeCount; - address[] promiseList; - PayloadParams[] payloadParams; - } + mapping(uint40 => RequestParams) internal _requests; event RequestSubmitted( bool hasWrite, @@ -59,7 +54,7 @@ contract RequestHandler is AddressResolverUtil, Ownable { event RequestCancelled(uint40 requestCount); modifier isRequestCancelled(uint40 requestCount_) { - if (requests[requestCount_].requestTrackingParams.isRequestCancelled) + if (_requests[requestCount_].requestTrackingParams.isRequestCancelled) revert RequestAlreadyCancelled(); _; } @@ -78,6 +73,29 @@ contract RequestHandler is AddressResolverUtil, Ownable { precompiles[callType_] = precompile_; } + function getPrecompileFees( + bytes4 callType_, + bytes memory precompileData_ + ) external view returns (uint256) { + return precompiles[callType_].getPrecompileFees(precompileData_); + } + + function getRequestBatchIds(uint40 batchCount_) external view returns (uint40[] memory) { + return _requestBatchIds[batchCount_]; + } + + function getBatchPayloadIds(uint40 batchCount_) external view returns (bytes32[] memory) { + return _batchPayloadIds[batchCount_]; + } + + function getRequest(uint40 requestCount_) external view returns (RequestParams memory) { + return _requests[requestCount_]; + } + + function getPayload(bytes32 payloadId_) external view returns (PayloadParams memory) { + return _payloads[payloadId_]; + } + function submitRequest( uint256 maxFees_, address auctionManager_, @@ -94,7 +112,7 @@ contract RequestHandler is AddressResolverUtil, Ownable { revert InsufficientFees(); requestCount = nextRequestCount++; - RequestParams storage r = requests[requestCount]; + RequestParams storage r = _requests[requestCount]; r.requestTrackingParams.currentBatch = nextBatchCount; r.requestTrackingParams.payloadsRemaining = queueParams_.length; r.requestFeesDetails.maxFees = maxFees_; @@ -123,7 +141,7 @@ contract RequestHandler is AddressResolverUtil, Ownable { uint40 requestCount_, Bid memory bid_ ) external isRequestCancelled(requestCount_) { - RequestParams storage r = requests[requestCount_]; + RequestParams storage r = _requests[requestCount_]; if (r.auctionManager != msg.sender) revert InvalidCaller(); if (r.requestTrackingParams.isRequestExecuted) revert RequestAlreadySettled(); @@ -156,7 +174,7 @@ contract RequestHandler is AddressResolverUtil, Ownable { uint40 requestCount_ ) internal returns (CreateRequestResult memory result) { // push first batch count - requestBatchIds[requestCount_].push(nextBatchCount); + _requestBatchIds[requestCount_].push(nextBatchCount); result.promiseList = new address[](queueParams_.length); result.payloadParams = new PayloadParams[](queueParams_.length); @@ -168,7 +186,7 @@ contract RequestHandler is AddressResolverUtil, Ownable { // decide batch count if (i > 0 && queueParams_[i].overrideParams.isParallelCall != Parallel.ON) { nextBatchCount++; - requestBatchIds[requestCount_].push(nextBatchCount); + _requestBatchIds[requestCount_].push(nextBatchCount); } // get the switchboard address from the watcher precompile config @@ -193,7 +211,7 @@ contract RequestHandler is AddressResolverUtil, Ownable { switchboard, queuePayloadParam.transaction.chainSlug ); - batchPayloadIds[nextBatchCount].push(payloadId); + _batchPayloadIds[nextBatchCount].push(payloadId); // create prev digest hash PayloadParams memory p = PayloadParams({ @@ -210,7 +228,7 @@ contract RequestHandler is AddressResolverUtil, Ownable { }); result.promiseList[i] = queueParams_[i].asyncPromise; result.payloadParams[i] = p; - payloads[payloadId] = p; + _payloads[payloadId] = p; } nextBatchCount++; @@ -237,15 +255,15 @@ contract RequestHandler is AddressResolverUtil, Ownable { } function _processBatch(uint40 batchCount_, RequestParams storage r) internal { - bytes32[] memory payloadIds = batchPayloadIds[batchCount_]; + bytes32[] memory payloadIds = _batchPayloadIds[batchCount_]; uint256 totalFees = 0; for (uint40 i = 0; i < payloadIds.length; i++) { bytes32 payloadId = payloadIds[i]; // check needed for re-process, in case a payload is already executed by last transmitter - if (!_isPromiseResolved(payloads[payloadId].asyncPromise)) continue; - PayloadParams storage payloadParams = payloads[payloadId]; + if (!_isPromiseResolved(_payloads[payloadId].asyncPromise)) continue; + PayloadParams storage payloadParams = _payloads[payloadId]; (uint256 fees, uint256 deadline) = IPrecompile(precompiles[payloadParams.callType]) .handlePayload(r.requestFeesDetails.winningBid.transmitter, payloadParams); @@ -262,20 +280,22 @@ contract RequestHandler is AddressResolverUtil, Ownable { /// @notice Increases the fees for a request if no bid is placed /// @param requestCount_ The ID of the request /// @param newMaxFees_ The new maximum fees - function increaseFees(uint40 requestCount_, uint256 newMaxFees_) external { - RequestParams storage r = requests[requestCount_]; - address appGateway = msg.sender; - + function increaseFees( + uint40 requestCount_, + uint256 newMaxFees_, + address appGateway_ + ) external onlyWatcher { + RequestParams storage r = _requests[requestCount_]; if (r.requestTrackingParams.isRequestCancelled) revert RequestAlreadyCancelled(); if (r.requestTrackingParams.isRequestExecuted) revert RequestAlreadySettled(); - if (appGateway != r.appGateway) revert OnlyAppGateway(); + if (appGateway_ != r.appGateway) revert OnlyAppGateway(); if (r.requestFeesDetails.maxFees >= newMaxFees_) revert NewMaxFeesLowerThanCurrent(r.requestFeesDetails.maxFees, newMaxFees_); if ( !IFeesManager(feesManager__()).isCreditSpendable( r.requestFeesDetails.consumeFrom, - appGateway, + appGateway_, newMaxFees_ ) ) revert InsufficientFees(); @@ -290,9 +310,9 @@ contract RequestHandler is AddressResolverUtil, Ownable { uint40 requestCount_, bytes32 payloadId_ ) external onlyPromiseResolver isRequestCancelled(requestCount_) { - RequestParams storage r = requests[requestCount_]; + RequestParams storage r = _requests[requestCount_]; - PayloadParams storage payloadParams = payloads[payloadId_]; + PayloadParams storage payloadParams = _payloads[payloadId_]; IPrecompile(precompiles[payloadParams.callType]).resolvePayload(payloadParams); payloadParams.resolvedAt = block.timestamp; @@ -316,21 +336,21 @@ contract RequestHandler is AddressResolverUtil, Ownable { /// @dev This function cancels a request /// @dev It verifies that the caller is the middleware and that the request hasn't been cancelled yet function cancelRequestForReverts(uint40 requestCount) external onlyPromiseResolver { - _cancelRequest(requestCount, requests[requestCount]); + _cancelRequest(requestCount, _requests[requestCount]); } /// @notice Cancels a request /// @param requestCount The request count to cancel /// @dev This function cancels a request /// @dev It verifies that the caller is the middleware and that the request hasn't been cancelled yet - function cancelRequest(uint40 requestCount) external { - RequestParams storage r = requests[requestCount]; - if (r.appGateway != msg.sender) revert InvalidCaller(); + function cancelRequest(uint40 requestCount, address appGateway_) external onlyWatcher { + RequestParams storage r = _requests[requestCount]; + if (appGateway_ != r.appGateway) revert InvalidCaller(); _cancelRequest(requestCount, r); } function handleRevert(uint40 requestCount) external onlyPromiseResolver { - _cancelRequest(requestCount, requests[requestCount]); + _cancelRequest(requestCount, _requests[requestCount]); } function _cancelRequest(uint40 requestCount_, RequestParams storage r) internal { diff --git a/contracts/evmx/watcher/Watcher.sol b/contracts/evmx/watcher/Watcher.sol index 332bd09f..f3faeb1c 100644 --- a/contracts/evmx/watcher/Watcher.sol +++ b/contracts/evmx/watcher/Watcher.sol @@ -139,11 +139,27 @@ contract Watcher is Trigger { } function getRequestParams(uint40 requestCount_) external view returns (RequestParams memory) { - return requestHandler__.requests(requestCount_); + return requestHandler__.getRequest(requestCount_); } function getPayloadParams(bytes32 payloadId_) external view returns (PayloadParams memory) { - return requestHandler__.payloads(payloadId_); + return requestHandler__.getPayload(payloadId_); + } + + function setIsValidPlug( + bool isValid_, + uint32 chainSlug_, + address onchainAddress_ + ) external override { + configurations__.setIsValidPlug(isValid_, chainSlug_, onchainAddress_); + } + + function cancelRequest(uint40 requestCount_) external override { + requestHandler__.cancelRequest(requestCount_, msg.sender); + } + + function increaseFees(uint40 requestCount_, uint256 newFees_) external override { + requestHandler__.increaseFees(requestCount_, newFees_, msg.sender); } function getPrecompileFees( diff --git a/contracts/evmx/watcher/precompiles/WritePrecompile.sol b/contracts/evmx/watcher/precompiles/WritePrecompile.sol index 7efc487f..31dc5540 100644 --- a/contracts/evmx/watcher/precompiles/WritePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/WritePrecompile.sol @@ -136,14 +136,14 @@ contract WritePrecompile is IPrecompile, WatcherBase, Ownable { (address, Transaction, WriteFinality, uint256, uint256, address) ); - bytes32 prevBatchDigestHash = _getPrevBatchDigestHash(payloadParams.batchCount); + bytes32 prevBatchDigestHash = getPrevBatchDigestHash(payloadParams.batchCount); // create digest DigestParams memory digestParams_ = DigestParams( configurations__().sockets(transaction.chainSlug), transmitter_, payloadParams.payloadId, - payloadParams.deadline, + deadline, payloadParams.callType, gasLimit, value, @@ -167,16 +167,16 @@ contract WritePrecompile is IPrecompile, WatcherBase, Ownable { ); } - function _getPrevBatchDigestHash(uint40 batchCount_) internal view returns (bytes32) { + function getPrevBatchDigestHash(uint40 batchCount_) public view returns (bytes32) { if (batchCount_ == 0) return bytes32(0); // if first batch, return bytes32(0) - uint40[] memory requestBatchIds = requestHandler__().requestBatchIds(batchCount_); + uint40[] memory requestBatchIds = requestHandler__().getRequestBatchIds(batchCount_); if (requestBatchIds[0] == batchCount_) return bytes32(0); uint40 prevBatchCount = batchCount_ - 1; - bytes32[] memory payloadIds = requestHandler__().batchPayloadIds(prevBatchCount); + bytes32[] memory payloadIds = requestHandler__().getBatchPayloadIds(prevBatchCount); bytes32 prevDigestsHash = bytes32(0); for (uint40 i = 0; i < payloadIds.length; i++) { prevDigestsHash = keccak256( diff --git a/contracts/protocol/SocketUtils.sol b/contracts/protocol/SocketUtils.sol index eb4860ed..34a967eb 100644 --- a/contracts/protocol/SocketUtils.sol +++ b/contracts/protocol/SocketUtils.sol @@ -14,13 +14,12 @@ abstract contract SocketUtils is SocketConfig { ////////////////////// State Vars ////////////////////////// //////////////////////////////////////////////////////////// + // Prefix for trigger ID containing chain slug and address bits + uint256 private immutable triggerPrefix; // Version string for this socket instance bytes32 public immutable version; // ChainSlug for this deployed socket instance uint32 public immutable chainSlug; - // Prefix for trigger ID containing chain slug and address bits - uint256 private immutable triggerPrefix; - // @notice counter for trigger id uint64 public triggerCounter; diff --git a/contracts/utils/common/Structs.sol b/contracts/utils/common/Structs.sol index c99d7ee5..01e8cf19 100644 --- a/contracts/utils/common/Structs.sol +++ b/contracts/utils/common/Structs.sol @@ -115,6 +115,13 @@ struct WatcherMultiCallParams { bytes signature; } +struct CreateRequestResult { + uint256 totalEstimatedWatcherFees; + uint256 writeCount; + address[] promiseList; + PayloadParams[] payloadParams; +} + // digest: struct DigestParams { address socket; From 07442e6f8e9d9c2f68491b806982040c9104fdd8 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 27 May 2025 17:41:22 +0530 Subject: [PATCH 061/130] fix: test gateway setup --- test/SetupTest.t.sol | 828 +++++++++++++++++++++++--------- test/apps/Counter.t.sol | 15 +- test/apps/ParallelCounter.t.sol | 11 +- test/apps/SuperToken.t.sol | 19 +- 4 files changed, 623 insertions(+), 250 deletions(-) diff --git a/test/SetupTest.t.sol b/test/SetupTest.t.sol index f90ca7e9..1ac29296 100644 --- a/test/SetupTest.t.sol +++ b/test/SetupTest.t.sol @@ -8,6 +8,8 @@ import "../contracts/utils/common/Constants.sol"; import "../contracts/utils/common/AccessRoles.sol"; import "../contracts/utils/common/IdUtils.sol"; +import "../contracts/evmx/interfaces/IForwarder.sol"; + import "../contracts/protocol/Socket.sol"; import "../contracts/protocol/switchboard/FastSwitchboard.sol"; import "../contracts/protocol/SocketBatcher.sol"; @@ -64,6 +66,7 @@ contract SetupStore is Test { uint256 public signatureNonce; uint256 public payloadIdCounter; uint256 public triggerCounter; + uint256 public asyncPromiseCounter; struct SocketContracts { uint32 chainSlug; Socket socket; @@ -93,9 +96,8 @@ contract SetupStore is Test { SchedulePrecompile public schedulePrecompile; } -contract DeployAndSetupTest is SetupStore { +contract DeploySetup is SetupStore { event Initialized(uint64 version); - event FinalizeRequested(bytes32 digest, PayloadParams payloadParams); //////////////////////////////////// Setup //////////////////////////////////// function deploy() internal { @@ -128,7 +130,7 @@ contract DeployAndSetupTest is SetupStore { ); vm.stopPrank(); - _connectPlugs(); + _connectCorePlugs(); vm.startPrank(transmitterEOA); arbConfig.testUSDC.mint(address(transmitterEOA), 100 ether); @@ -146,7 +148,7 @@ contract DeployAndSetupTest is SetupStore { vm.stopPrank(); } - function _connectPlugs() internal { + function _connectCorePlugs() internal { AppGatewayConfig[] memory configs = new AppGatewayConfig[](4); configs[0] = AppGatewayConfig({ chainSlug: arbChainSlug, @@ -207,7 +209,6 @@ contract DeployAndSetupTest is SetupStore { Socket socket = socketConfig.socket; FastSwitchboard switchboard = socketConfig.switchboard; FeesPlug feesPlug = socketConfig.feesPlug; - ERC20 testUSDC = socketConfig.testUSDC; ContractFactoryPlug contractFactoryPlug = socketConfig.contractFactoryPlug; vm.startPrank(socketOwner); @@ -218,7 +219,7 @@ contract DeployAndSetupTest is SetupStore { switchboard.registerSwitchboard(); switchboard.grantRole(WATCHER_ROLE, watcherEOA); - feesPlug.whitelistToken(address(testUSDC)); + feesPlug.whitelistToken(address(socketConfig.testUSDC)); feesPlug.connectSocket( encodeAppGatewayId(address(auctionManager)), @@ -340,6 +341,53 @@ contract DeployAndSetupTest is SetupStore { return chainSlug_ == arbChainSlug ? arbConfig : optConfig; } + function _createWatcherSignature( + address watcherPrecompile_, + bytes memory params_ + ) internal view returns (bytes memory) { + bytes32 digest = keccak256( + abi.encode(watcherPrecompile_, evmxSlug, signatureNonce, params_) + ); + return _createSignature(digest, watcherPrivateKey); + } + + function _createSignature( + bytes32 digest_, + uint256 privateKey_ + ) internal pure returns (bytes memory sig) { + bytes32 digest = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", digest_)); + (uint8 sigV, bytes32 sigR, bytes32 sigS) = vm.sign(privateKey_, digest); + sig = new bytes(65); + bytes1 v32 = bytes1(sigV); + assembly { + mstore(add(sig, 96), v32) + mstore(add(sig, 32), sigR) + mstore(add(sig, 64), sigS) + } + } + + function predictAsyncPromiseAddress( + address invoker_, + address forwarder_ + ) internal returns (address) { + bytes memory asyncPromiseBytecode = type(AsyncPromise).creationCode; + bytes memory constructorArgs = abi.encode(invoker_, forwarder_, address(addressResolver)); + bytes memory combinedBytecode = abi.encodePacked(asyncPromiseBytecode, constructorArgs); + + bytes32 salt = keccak256(abi.encodePacked(constructorArgs, asyncPromiseCounter++)); + + bytes32 hash = keccak256( + abi.encodePacked( + bytes1(0xff), + address(addressResolver), + salt, + keccak256(combinedBytecode) + ) + ); + + return address(uint160(uint256(hash))); + } + function testDeployAndSetup() public { deploy(); @@ -351,215 +399,559 @@ contract DeployAndSetupTest is SetupStore { } } -// contract SetupUtilsTest is DeployAndSetupTest { -// function setUp() public { -// deploy(); -// } - -// function _checkIfOnlyReads(uint40 batchCount_) internal view returns (bool) { -// (bytes32[] memory payloadIds, ) = watcher.getBatchPayloadIds(batchCount_); - -// for (uint i = 0; i < payloadIds.length; i++) { -// PayloadParams memory payloadParams = watcher.getPayloadParams(payloadIds[i]); -// if (payloadParams.payloadHeader.getCallType() != READ) { -// return false; -// } -// } - -// return true; -// } - -// function _resolveAndExpectFinalizeRequested( -// bytes32 payloadId_, -// PayloadParams memory payloadParams, -// bytes memory returnData, -// bool isLastPayload -// ) internal { -// if (isLastPayload) { -// vm.expectEmit(false, false, false, false); -// emit FinalizeRequested(payloadId_, payloadParams); -// } - -// _resolvePromise(payloadId_, returnData); -// } - -// function _finalizeBatch( -// uint40 batchCount_, -// bytes[] memory readReturnData_, -// uint256 readCount_, -// bool hasMoreBatches -// ) internal returns (uint256) { -// bytes32[] memory payloadIds = watcher.getBatchPayloadIds(batchCount_); - -// for (uint i = 0; i < payloadIds.length; i++) { -// PayloadParams memory payloadParams = watcher.getPayloadParams(payloadIds[i]); -// bool isLastPayload = i == payloadIds.length - 1 && hasMoreBatches; - -// if (payloadParams.payloadHeader.getCallType() == READ) { -// _resolveAndExpectFinalizeRequested( -// payloadParams.payloadId, -// payloadParams, -// readReturnData_[readCount_++], -// isLastPayload -// ); -// } else { -// (, bytes memory returnData) = _uploadProofAndExecute(payloadParams); -// _resolveAndExpectFinalizeRequested( -// payloadParams.payloadId, -// payloadParams, -// returnData, -// isLastPayload -// ); -// } -// } -// return readCount_; -// } - -// function _uploadProofAndExecute( -// PayloadParams memory payloadParams -// ) internal returns (bool, bytes memory) { -// (bytes memory watcherProof, bytes32 digest) = _generateWatcherProof(payloadParams); -// _writeProof(payloadParams.payloadId, watcherProof); - -// ( -// ExecuteParams memory params, -// SocketBatcher socketBatcher, -// , -// bytes memory transmitterSig, -// address refundAddress -// ) = _getExecuteParams(payloadParams); - -// return -// socketBatcher.attestAndExecute( -// params, -// payloadParams.switchboard, -// digest, -// watcherProof, -// transmitterSig, -// refundAddress -// ); -// } - -// function resolvePromises(bytes32[] memory payloadIds, bytes[] memory returnData) internal { -// for (uint i = 0; i < payloadIds.length; i++) { -// _resolvePromise(payloadIds[i], returnData[i]); -// } -// } - -// //////////////////////////////////// Helpers //////////////////////////////////// -// - -// function _generateWatcherProof( -// PayloadParams memory params_ -// ) internal view returns (bytes memory, bytes32) { -// SocketContracts memory socketConfig = getSocketConfig(params_.payloadHeader.getChainSlug()); -// DigestParams memory digestParams_ = DigestParams( -// address(socketConfig.socket), -// transmitterEOA, -// params_.payloadId, -// params_.deadline, -// params_.payloadHeader.getCallType(), -// params_.gasLimit, -// params_.value, -// params_.payload, -// params_.target, -// encodeAppGatewayId(params_.appGateway), -// params_.prevDigestsHash -// ); -// bytes32 digest = watcher.getDigest(digestParams_); - -// bytes32 sigDigest = keccak256( -// abi.encode(address(socketConfig.switchboard), socketConfig.chainSlug, digest) -// ); -// bytes memory proof = _createSignature(sigDigest, watcherPrivateKey); -// return (proof, digest); -// } - -// function _writeProof(bytes32 payloadId_, bytes memory watcherProof_) internal { -// bytes memory bytesInput = abi.encode( -// IWatcher.finalized.selector, -// payloadId_, -// watcherProof_ -// ); -// bytes memory watcherSignature = _createWatcherSignature(address(watcher), bytesInput); -// watcher.finalized(payloadId_, watcherProof_, signatureNonce++, watcherSignature); -// assertEq(watcher.watcherProofs(payloadId_), watcherProof_); -// } - -// function _getExecuteParams( -// PayloadParams memory payloadParams -// ) -// internal -// view -// returns ( -// ExecuteParams memory params, -// SocketBatcher socketBatcher, -// uint256 value, -// bytes memory transmitterSig, -// address refundAddress -// ) -// { -// SocketContracts memory socketConfig = getSocketConfig( -// payloadParams.payloadHeader.getChainSlug() -// ); -// bytes32 transmitterDigest = keccak256( -// abi.encode(address(socketConfig.socket), payloadParams.payloadId) -// ); -// transmitterSig = _createSignature(transmitterDigest, transmitterPrivateKey); - -// params = ExecuteParams({ -// callType: payloadParams.payloadHeader.getCallType(), -// deadline: payloadParams.deadline, -// gasLimit: payloadParams.gasLimit, -// value: payloadParams.value, -// payload: payloadParams.payload, -// target: payloadParams.target, -// requestCount: payloadParams.payloadHeader.getRequestCount(), -// batchCount: payloadParams.payloadHeader.getBatchCount(), -// payloadCount: payloadParams.payloadHeader.getPayloadCount(), -// prevDigestsHash: payloadParams.prevDigestsHash, -// extraData: bytes("") -// }); - -// value = payloadParams.value; -// socketBatcher = socketConfig.socketBatcher; -// refundAddress = transmitterEOA; -// } - -// function _resolvePromise(bytes32 payloadId, bytes memory returnData) internal { -// PromiseReturnData[] memory promiseReturnData = new PromiseReturnData[](1); -// promiseReturnData[0] = PromiseReturnData({payloadId: payloadId, returnData: returnData}); - -// bytes memory watcherSignature = _createWatcherSignature( -// address(watcher), -// abi.encode(Watcher.resolvePromises.selector, promiseReturnData) -// ); -// watcher.resolvePromises(promiseReturnData, signatureNonce++, watcherSignature); -// } - -// function _createWatcherSignature( -// address watcherPrecompile_, -// bytes memory params_ -// ) internal view returns (bytes memory) { -// bytes32 digest = keccak256( -// abi.encode(watcherPrecompile_, evmxSlug, signatureNonce, params_) -// ); -// return _createSignature(digest, watcherPrivateKey); -// } - -// function _createSignature( -// bytes32 digest_, -// uint256 privateKey_ -// ) internal pure returns (bytes memory sig) { -// bytes32 digest = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", digest_)); -// (uint8 sigV, bytes32 sigR, bytes32 sigS) = vm.sign(privateKey_, digest); -// sig = new bytes(65); -// bytes1 v32 = bytes1(sigV); - -// assembly { -// mstore(add(sig, 96), v32) -// mstore(add(sig, 32), sigR) -// mstore(add(sig, 64), sigS) -// } -// } -// } +contract FeesSetup is DeploySetup { + event CreditsDeposited( + uint32 indexed chainSlug, + address indexed appGateway, + address indexed token, + uint256 amount + ); + event CreditsWrapped(address indexed consumeFrom, uint256 amount); + event CreditsUnwrapped(address indexed consumeFrom, uint256 amount); + event CreditsTransferred(address indexed from, address indexed to, uint256 amount); + + // mints test token and deposits the given native and credits to given `user_` + function depositNativeAndCredits( + uint32 chainSlug_, + uint256 credits_, + uint256 native_, + address user_ + ) internal { + SocketContracts memory socketConfig = getSocketConfig(chainSlug_); + TestUSDC token = socketConfig.testUSDC; + + uint256 userBalance = token.balanceOf(user_); + uint256 feesPlugBalance = token.balanceOf(address(socketConfig.feesPlug)); + + token.mint(address(user_), 100 ether); + assertEq( + token.balanceOf(user_), + userBalance + 100 ether, + "User should have 100 more test tokens" + ); + + vm.startPrank(user_); + token.approve(address(socketConfig.feesPlug), 100 ether); + socketConfig.feesPlug.depositCreditAndNative(address(token), address(user_), 100 ether); + vm.stopPrank(); + + assertEq( + token.balanceOf(address(socketConfig.feesPlug)), + feesPlugBalance + 100 ether, + "Fees plug should have 100 more test tokens" + ); + + uint256 currentCredits = feesManager.getAvailableCredits(user_); + uint256 currentNative = address(feesManager).balance; + + hoax(address(watcher)); + feesManager.deposit{value: native_ + credits_}( + user_, + chainSlug_, + address(token), + native_, + credits_ + ); + + assertEq( + feesManager.getAvailableCredits(user_), + currentCredits + credits_, + "User should have more credits" + ); + assertEq( + address(feesManager).balance, + currentNative + native_ + credits_, + "Fees manager should have more credits" + ); + } + + function approveAppGateway( + address appGateway_, + address user_, + uint256 userPrivateKey_ + ) internal { + bool approval = feesManager.isApproved(user_, appGateway_); + if (approval) return; + + // Create fee approval data with signature + bytes32 digest = keccak256( + abi.encode(address(feesManager), evmxSlug, appGateway_, block.timestamp, true) + ); + + // Sign with consumeFrom's private key + bytes memory signature = _createSignature(digest, userPrivateKey_); + + // Encode approval data + bytes memory feeApprovalData = abi.encode(appGateway_, true, block.timestamp, signature); + + // Call whitelistAppGatewayWithSignature with approval data + feesManager.approveAppGatewayWithSignature(feeApprovalData); + assertEq( + feesManager.isApproved(user_, appGateway_), + true, + "App gateway should be approved" + ); + } +} + +contract AuctionSetup is FeesSetup { + uint256 public bidAmount = 100 ether; + + event BidPlaced(uint40 requestCount, Bid bid); + event AuctionStarted(uint40 requestCount); + event AuctionEnded(uint40 requestCount, Bid winningBid); + + function placeBid(uint40 requestCount) internal { + bytes memory transmitterSignature = _createSignature( + keccak256(abi.encode(address(auctionManager), evmxSlug, requestCount, bidAmount, "")), + transmitterPrivateKey + ); + + vm.expectEmit(true, true, true, false); + emit AuctionStarted(requestCount); + + if (auctionEndDelaySeconds == 0) { + vm.expectEmit(true, true, true, true); + emit AuctionEnded( + requestCount, + Bid({fee: bidAmount, transmitter: transmitterEOA, extraData: ""}) + ); + } + + vm.expectEmit(true, true, true, true); + emit BidPlaced( + requestCount, + Bid({transmitter: transmitterEOA, fee: bidAmount, extraData: bytes("")}) + ); + auctionManager.bid(requestCount, bidAmount, transmitterSignature, bytes("")); + } + + function endAuction(uint40 requestCount_) internal { + if (auctionEndDelaySeconds == 0) return; + + // todo: handle other cases + bytes memory watcherSignature = _createSignature( + keccak256(abi.encode(address(watcher), evmxSlug, requestCount_, bidAmount, "")), + watcherPrivateKey + ); + + vm.expectEmit(true, true, true, true); + emit AuctionEnded( + requestCount_, + Bid({fee: bidAmount, transmitter: transmitterEOA, extraData: ""}) + ); + + // promiseResolver.resolvePromises(); + } + + function bidAndEndAuction(uint40 requestCount) internal { + placeBid(requestCount); + endAuction(requestCount); + } + + // tests: + // bid and end auction with delay + // bid and end auction with delay and expire bid +} + +contract WatcherSetup is AuctionSetup { + event ReadRequested(Transaction transaction, uint256 readAtBlockNumber, bytes32 payloadId); + event ScheduleRequested(bytes32 payloadId, uint256 deadline); + event ScheduleResolved(bytes32 payloadId); + event WriteProofRequested( + address transmitter, + bytes32 digest, + bytes32 prevBatchDigestHash, + uint256 deadline, + PayloadParams payloadParams + ); + event WriteProofUploaded(bytes32 indexed payloadId, bytes proof); + + function deploy( + uint32 chainSlug_, + IAppGateway appGateway_, + bytes32[] memory contractIds_ + ) internal returns (uint40 requestCount) { + executeRequest(new bytes[](0)); + setupGatewayAndPlugs(chainSlug_, appGateway_, contractIds_); + } + + function _checkIfOnlyReadBatch(uint40 batchCount_) internal view returns (bool) { + bytes32[] memory payloadIds = requestHandler.getBatchPayloadIds(batchCount_); + for (uint i = 0; i < payloadIds.length; i++) { + if (requestHandler.getPayload(payloadIds[i]).callType != READ) return false; + } + return true; + } + + function executeRequest(bytes[] memory readReturnData_) internal { + uint40 requestCount = watcher.getCurrentRequestCount(); + requestCount = requestCount == 0 ? 0 : requestCount - 1; + uint40[] memory batches = requestHandler.getRequestBatchIds(requestCount); + + bool onlyReads = _checkIfOnlyReadBatch(batches[0]); + if (!(onlyReads && batches.length == 1)) { + bidAndEndAuction(requestCount); + } + + uint256 readCount = 0; + for (uint i = 0; i < batches.length; i++) { + bool hasMoreBatches = i < batches.length - 1; + readCount = _processBatch(batches[i], readReturnData_, readCount, hasMoreBatches); + } + } + + function _processBatch( + uint40 batchCount_, + bytes[] memory readReturnData_, + uint256 readCount_, + bool hasMoreBatches + ) internal returns (uint256) { + bytes32[] memory payloadIds = requestHandler.getBatchPayloadIds(batchCount_); + for (uint i = 0; i < payloadIds.length; i++) { + PayloadParams memory payloadParams = watcher.getPayloadParams(payloadIds[i]); + bool isLastPayload = i == payloadIds.length - 1 && hasMoreBatches; + if (payloadParams.callType == READ) { + _resolveAndExpectWriteProofRequested( + payloadParams.payloadId, + payloadParams, + readReturnData_[readCount_++], + isLastPayload + ); + } else { + (, bytes memory returnData) = _uploadProofAndExecute(payloadParams); + _resolveAndExpectWriteProofRequested( + payloadParams.payloadId, + payloadParams, + returnData, + isLastPayload + ); + } + } + return readCount_; + } + + function _resolveAndExpectWriteProofRequested( + bytes32 payloadId_, + PayloadParams memory payloadParams, + bytes memory returnData, + bool isLastPayload + ) internal { + if (isLastPayload) { + vm.expectEmit(false, false, false, false); + emit WriteProofRequested( + transmitterEOA, + writePrecompile.digestHashes(payloadParams.payloadId), + writePrecompile.getPrevBatchDigestHash(payloadParams.batchCount), + payloadParams.deadline, + payloadParams + ); + } + _resolvePromise(payloadId_, returnData); + } + + function _uploadProofAndExecute( + PayloadParams memory payloadParams + ) internal returns (bool, bytes memory) { + (bytes memory watcherProof, bytes32 digest) = _generateWatcherProof(payloadParams); + _writeProof(payloadParams.payloadId, watcherProof); + ( + ExecuteParams memory params, + SocketBatcher socketBatcher, + , + bytes memory transmitterSig, + address refundAddress + ) = _getExecuteParams(payloadParams); + return + socketBatcher.attestAndExecute( + params, + address(1), // todo: fix this socketConfig.switchboard, + digest, + watcherProof, + transmitterSig, + refundAddress + ); + } + + function resolvePromises(bytes32[] memory payloadIds, bytes[] memory returnData) internal { + for (uint i = 0; i < payloadIds.length; i++) { + _resolvePromise(payloadIds[i], returnData[i]); + } + } + + //////////////////////////////////// Helpers //////////////////////////////////// + + function _generateWatcherProof( + PayloadParams memory params_ + ) internal view returns (bytes memory, bytes32) { + ( + address appGateway, + Transaction memory transaction, + WriteFinality writeFinality, + uint256 gasLimit, + uint256 value, + address switchboard + ) = abi.decode( + params_.precompileData, + (address, Transaction, WriteFinality, uint256, uint256, address) + ); + SocketContracts memory socketConfig = getSocketConfig(transaction.chainSlug); + DigestParams memory digestParams_ = DigestParams( + address(socketConfig.socket), + transmitterEOA, + params_.payloadId, + params_.deadline, + params_.callType, + gasLimit, + value, + transaction.payload, + transaction.target, + encodeAppGatewayId(appGateway), + writePrecompile.getPrevBatchDigestHash(params_.batchCount), + bytes("") + ); + bytes32 digest = writePrecompile.getDigest(digestParams_); + bytes32 sigDigest = keccak256( + abi.encode(address(socketConfig.switchboard), socketConfig.chainSlug, digest) + ); + bytes memory proof = _createSignature(sigDigest, watcherPrivateKey); + return (proof, digest); + } + + function _writeProof(bytes32 payloadId_, bytes memory watcherProof_) internal { + bytes memory bytesInput = abi.encode( + WritePrecompile.uploadProof.selector, + payloadId_, + watcherProof_ + ); + bytes memory watcherSignature = _createWatcherSignature(address(watcher), bytesInput); + writePrecompile.uploadProof(payloadId_, watcherProof_); + assertEq(writePrecompile.watcherProofs(payloadId_), watcherProof_); + } + + function _getExecuteParams( + PayloadParams memory payloadParams + ) + internal + view + returns ( + ExecuteParams memory params, + SocketBatcher socketBatcher, + uint256 value, + bytes memory transmitterSig, + address refundAddress + ) + { + SocketContracts memory socketConfig = getSocketConfig(payloadParams.transaction.chainSlug); + bytes32 transmitterDigest = keccak256( + abi.encode(address(socketConfig.socket), payloadParams.payloadId) + ); + transmitterSig = _createSignature(transmitterDigest, transmitterPrivateKey); + params = ExecuteParams({ + callType: payloadParams.payloadHeader.getCallType(), + deadline: payloadParams.deadline, + gasLimit: payloadParams.gasLimit, + value: payloadParams.value, + payload: payloadParams.payload, + target: payloadParams.target, + requestCount: payloadParams.payloadHeader.getRequestCount(), + batchCount: payloadParams.payloadHeader.getBatchCount(), + payloadCount: payloadParams.payloadHeader.getPayloadCount(), + prevDigestsHash: payloadParams.prevDigestsHash, + extraData: bytes("") + }); + value = payloadParams.value; + socketBatcher = socketConfig.socketBatcher; + refundAddress = transmitterEOA; + } + + function _resolvePromise(bytes32 payloadId, bytes memory returnData) internal { + PromiseReturnData[] memory promiseReturnData = new PromiseReturnData[](1); + promiseReturnData[0] = PromiseReturnData({payloadId: payloadId, returnData: returnData}); + bytes memory watcherSignature = _createWatcherSignature( + address(watcher), + abi.encode(Watcher.resolvePromises.selector, promiseReturnData) + ); + watcher.resolvePromises(promiseReturnData, signatureNonce++, watcherSignature); + } + + function setupGatewayAndPlugs( + uint32 chainSlug_, + IAppGateway appGateway_, + bytes32[] memory contractIds_ + ) internal { + AppGatewayConfig[] memory gateways = new AppGatewayConfig[](contractIds_.length); + + SocketContracts memory socketConfig = getSocketConfig(chainSlug_); + for (uint i = 0; i < contractIds_.length; i++) { + address plug = appGateway_.getOnChainAddress(contractIds_[i], chainSlug_); + + gateways[i] = AppGatewayConfig({ + plug: plug, + chainSlug: chainSlug_, + appGatewayId: encodeAppGatewayId(address(appGateway_)), + switchboard: address(socketConfig.switchboard) + }); + } + + bytes memory watcherSignature = _createWatcherSignature( + address(configurations), + abi.encode(IConfigurations.setAppGateways.selector, gateways) + ); + configurations.setAppGateways(gateways, signatureNonce++, watcherSignature); + } +} + +contract AppGatewayBaseSetup is WatcherSetup { + function getOnChainAndForwarderAddresses( + uint32 chainSlug_, + bytes32 contractId_, + IAppGateway appGateway_ + ) internal view returns (address, address) { + address app = appGateway_.getOnChainAddress(contractId_, chainSlug_); + address forwarder = appGateway_.forwarderAddresses(contractId_, chainSlug_); + return (app, forwarder); + } + + // todo: add checks for request params and payload params created to match what is expected + + function checkRequestParams( + uint40 requestCount, + RequestParams memory expectedRequest + ) internal view { + RequestParams memory actualRequest = watcher.getRequestParams(requestCount); + // RequestParams checks + assertEq( + actualRequest.appGateway, + expectedRequest.appGateway, + "Request: appGateway mismatch" + ); + assertEq( + actualRequest.auctionManager, + expectedRequest.auctionManager, + "Request: auctionManager mismatch" + ); + assertEq( + actualRequest.writeCount, + expectedRequest.writeCount, + "Request: writeCount mismatch" + ); + assertEq( + keccak256(actualRequest.onCompleteData), + keccak256(expectedRequest.onCompleteData), + "Request: onCompleteData mismatch" + ); + // Nested struct checks (RequestTrackingParams) + assertEq( + actualRequest.requestTrackingParams.isRequestCancelled, + expectedRequest.requestTrackingParams.isRequestCancelled, + "RequestTrackingParams: isRequestCancelled mismatch" + ); + assertEq( + actualRequest.requestTrackingParams.isRequestExecuted, + expectedRequest.requestTrackingParams.isRequestExecuted, + "RequestTrackingParams: isRequestExecuted mismatch" + ); + assertEq( + actualRequest.requestTrackingParams.currentBatch, + expectedRequest.requestTrackingParams.currentBatch, + "RequestTrackingParams: currentBatch mismatch" + ); + assertEq( + actualRequest.requestTrackingParams.currentBatchPayloadsLeft, + expectedRequest.requestTrackingParams.currentBatchPayloadsLeft, + "RequestTrackingParams: currentBatchPayloadsLeft mismatch" + ); + assertEq( + actualRequest.requestTrackingParams.payloadsRemaining, + expectedRequest.requestTrackingParams.payloadsRemaining, + "RequestTrackingParams: payloadsRemaining mismatch" + ); + // Nested struct checks (RequestFeesDetails) + assertEq( + actualRequest.requestFeesDetails.maxFees, + expectedRequest.requestFeesDetails.maxFees, + "RequestFeesDetails: maxFees mismatch" + ); + assertEq( + actualRequest.requestFeesDetails.consumeFrom, + expectedRequest.requestFeesDetails.consumeFrom, + "RequestFeesDetails: consumeFrom mismatch" + ); + assertEq( + actualRequest.requestFeesDetails.winningBid.fee, + expectedRequest.requestFeesDetails.winningBid.fee, + "RequestFeesDetails: winningBid.fee mismatch" + ); + assertEq( + actualRequest.requestFeesDetails.winningBid.transmitter, + expectedRequest.requestFeesDetails.winningBid.transmitter, + "RequestFeesDetails: winningBid.transmitter mismatch" + ); + assertEq( + keccak256(actualRequest.requestFeesDetails.winningBid.extraData), + keccak256(expectedRequest.requestFeesDetails.winningBid.extraData), + "RequestFeesDetails: winningBid.extraData mismatch" + ); + } + + function checkPayloadParams(PayloadParams[] memory expectedPayloads) internal view { + for (uint i = 0; i < expectedPayloads.length; i++) { + PayloadParams memory expectedPayload = expectedPayloads[i]; + PayloadParams memory actualPayload = watcher.getPayloadParams( + expectedPayload.payloadId + ); + // PayloadParams checks + assertEq( + actualPayload.requestCount, + expectedPayload.requestCount, + "Payload: requestCount mismatch" + ); + assertEq( + actualPayload.batchCount, + expectedPayload.batchCount, + "Payload: batchCount mismatch" + ); + assertEq( + actualPayload.payloadCount, + expectedPayload.payloadCount, + "Payload: payloadCount mismatch" + ); + assertEq( + actualPayload.callType, + expectedPayload.callType, + "Payload: callType mismatch" + ); + assertEq( + actualPayload.asyncPromise, + expectedPayload.asyncPromise, + "Payload: asyncPromise mismatch" + ); + assertEq( + actualPayload.appGateway, + expectedPayload.appGateway, + "Payload: appGateway mismatch" + ); + assertEq( + actualPayload.payloadId, + expectedPayload.payloadId, + "Payload: payloadId mismatch" + ); + assertEq( + actualPayload.resolvedAt, + expectedPayload.resolvedAt, + "Payload: resolvedAt mismatch" + ); + assertEq( + actualPayload.deadline, + expectedPayload.deadline, + "Payload: deadline mismatch" + ); + assertEq( + keccak256(actualPayload.precompileData), + keccak256(expectedPayload.precompileData), + "Payload: precompileData mismatch" + ); + } + } +} diff --git a/test/apps/Counter.t.sol b/test/apps/Counter.t.sol index 3185baf1..3c489c63 100644 --- a/test/apps/Counter.t.sol +++ b/test/apps/Counter.t.sol @@ -14,24 +14,17 @@ contract CounterTest is AppGatewayBaseSetup { CounterAppGateway counterGateway; function deploySetup() internal { - setUpDeliveryHelper(); + deploy(); counterGateway = new CounterAppGateway(address(addressResolver), feesAmount); - depositUSDCFees( - address(counterGateway), - OnChainFees({ - chainSlug: arbChainSlug, - token: address(arbConfig.feesTokenUSDC), - amount: 1 ether - }) - ); + depositNativeAndCredits(arbChainSlug, 1 ether, 1 ether, address(counterGateway)); counterId = counterGateway.counter(); contractIds[0] = counterId; } function deployCounterApp(uint32 chainSlug) internal returns (uint40 requestCount) { - requestCount = _deploy(chainSlug, counterGateway, contractIds); + requestCount = deploy(chainSlug, counterGateway, contractIds); } function testCounterDeployment() external { @@ -59,7 +52,7 @@ contract CounterTest is AppGatewayBaseSetup { function testCounterDeploymentWithoutAsync() external { deploySetup(); - vm.expectRevert(abi.encodeWithSelector(AsyncModifierNotUsed.selector)); + vm.expectRevert(abi.encodeWithSelector(AsyncModifierNotSet.selector)); counterGateway.deployContractsWithoutAsync(arbChainSlug); } diff --git a/test/apps/ParallelCounter.t.sol b/test/apps/ParallelCounter.t.sol index d1d386ce..c3cd1c1d 100644 --- a/test/apps/ParallelCounter.t.sol +++ b/test/apps/ParallelCounter.t.sol @@ -14,17 +14,10 @@ contract ParallelCounterTest is AppGatewayBaseSetup { CounterAppGateway parallelCounterGateway; function deploySetup() internal { - setUpDeliveryHelper(); + deploy(); parallelCounterGateway = new CounterAppGateway(address(addressResolver), feesAmount); - depositUSDCFees( - address(parallelCounterGateway), - OnChainFees({ - chainSlug: arbChainSlug, - token: address(arbConfig.feesTokenUSDC), - amount: 1 ether - }) - ); + depositNativeAndCredits(arbChainSlug, 1 ether, 1 ether, address(parallelCounterGateway)); counterId1 = parallelCounterGateway.counter1(); counterId2 = parallelCounterGateway.counter(); contractIds[0] = counterId1; diff --git a/test/apps/SuperToken.t.sol b/test/apps/SuperToken.t.sol index d23ba50a..3773c736 100644 --- a/test/apps/SuperToken.t.sol +++ b/test/apps/SuperToken.t.sol @@ -28,6 +28,8 @@ contract SuperTokenTest is AppGatewayBaseSetup { SuperTokenAppGateway superTokenApp; bytes32 superToken; } + address owner = address(uint160(c++)); + uint256 maxFees = 0.01 ether; /// @dev Main contracts used throughout the tests AppContracts appContracts; @@ -48,7 +50,7 @@ contract SuperTokenTest is AppGatewayBaseSetup { * 3. Initializes contract IDs array */ function setUp() public { - setUpDeliveryHelper(); + deploy(); deploySuperTokenApp(); contractIds[0] = appContracts.superToken; } @@ -75,14 +77,7 @@ contract SuperTokenTest is AppGatewayBaseSetup { ); // Enable app gateways to do all operations in the Watcher: Read, Write and Schedule on EVMx // Watcher sets the limits for apps in this SOCKET protocol version - depositUSDCFees( - address(superTokenApp), - OnChainFees({ - chainSlug: arbChainSlug, - token: address(arbConfig.feesTokenUSDC), - amount: 1 ether - }) - ); + depositNativeAndCredits(arbChainSlug, 1 ether, 1 ether, address(superTokenApp)); appContracts = AppContracts({ superTokenApp: superTokenApp, @@ -98,7 +93,7 @@ contract SuperTokenTest is AppGatewayBaseSetup { * - Correct setup of forwarder contracts for multi-chain communication */ function testContractDeployment() public { - _deploy(arbChainSlug, IAppGateway(appContracts.superTokenApp), contractIds); + deploy(arbChainSlug, IAppGateway(appContracts.superTokenApp), contractIds); (address onChain, address forwarder) = getOnChainAndForwarderAddresses( arbChainSlug, @@ -129,8 +124,8 @@ contract SuperTokenTest is AppGatewayBaseSetup { * @dev Deploys necessary contracts on both Arbitrum and Optimism chains */ function beforeTransfer() internal { - _deploy(arbChainSlug, IAppGateway(appContracts.superTokenApp), contractIds); - _deploy(optChainSlug, IAppGateway(appContracts.superTokenApp), contractIds); + deploy(arbChainSlug, IAppGateway(appContracts.superTokenApp), contractIds); + deploy(optChainSlug, IAppGateway(appContracts.superTokenApp), contractIds); } /** From 827d951fd93574b18b6f7c3e9da07d1cafb2a048 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 27 May 2025 17:48:15 +0530 Subject: [PATCH 062/130] fix: handle payload interface --- contracts/evmx/interfaces/IPrecompile.sol | 3 ++- contracts/evmx/watcher/PromiseResolver.sol | 2 ++ contracts/evmx/watcher/RequestHandler.sol | 7 +++++-- contracts/evmx/watcher/precompiles/ReadPrecompile.sol | 2 +- contracts/evmx/watcher/precompiles/WritePrecompile.sol | 2 +- contracts/protocol/Socket.sol | 8 -------- contracts/protocol/SocketConfig.sol | 2 +- contracts/utils/common/Errors.sol | 2 ++ 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/contracts/evmx/interfaces/IPrecompile.sol b/contracts/evmx/interfaces/IPrecompile.sol index 96beec8a..6241434c 100644 --- a/contracts/evmx/interfaces/IPrecompile.sol +++ b/contracts/evmx/interfaces/IPrecompile.sol @@ -25,10 +25,11 @@ interface IPrecompile { /// @param payloadParams The payload parameters to handle /// @return fees The fees required for processing /// @return deadline The deadline for processing + /// @return precompileData The encoded precompile data function handlePayload( address transmitter, PayloadParams calldata payloadParams - ) external returns (uint256 fees, uint256 deadline); + ) external returns (uint256 fees, uint256 deadline, bytes memory precompileData); /// @notice Resolves a payload /// @param payloadParams The payload parameters to resolve diff --git a/contracts/evmx/watcher/PromiseResolver.sol b/contracts/evmx/watcher/PromiseResolver.sol index f0f9a5a2..e626669b 100644 --- a/contracts/evmx/watcher/PromiseResolver.sol +++ b/contracts/evmx/watcher/PromiseResolver.sol @@ -47,6 +47,8 @@ contract PromiseResolver is IPromiseResolver, WatcherBase { PromiseReturnData memory resolvedPromise_ ) internal returns (uint40 requestCount, bool success) { PayloadParams memory payloadParams = watcher__.getPayloadParams(resolvedPromise_.payloadId); + if (payloadParams.deadline < block.timestamp) revert DeadlinePassed(); + address asyncPromise = payloadParams.asyncPromise; requestCount = payloadParams.requestCount; diff --git a/contracts/evmx/watcher/RequestHandler.sol b/contracts/evmx/watcher/RequestHandler.sol index 19de5293..4a687eab 100644 --- a/contracts/evmx/watcher/RequestHandler.sol +++ b/contracts/evmx/watcher/RequestHandler.sol @@ -265,10 +265,13 @@ contract RequestHandler is AddressResolverUtil, Ownable, IRequestHandler { if (!_isPromiseResolved(_payloads[payloadId].asyncPromise)) continue; PayloadParams storage payloadParams = _payloads[payloadId]; - (uint256 fees, uint256 deadline) = IPrecompile(precompiles[payloadParams.callType]) - .handlePayload(r.requestFeesDetails.winningBid.transmitter, payloadParams); + (uint256 fees, uint256 deadline, bytes memory precompileData) = IPrecompile( + precompiles[payloadParams.callType] + ).handlePayload(r.requestFeesDetails.winningBid.transmitter, payloadParams); + totalFees += fees; payloadParams.deadline = deadline; + payloadParams.precompileData = precompileData; } address watcherFeesPayer = r.requestFeesDetails.winningBid.transmitter == address(0) diff --git a/contracts/evmx/watcher/precompiles/ReadPrecompile.sol b/contracts/evmx/watcher/precompiles/ReadPrecompile.sol index 33fbc762..e0ef0700 100644 --- a/contracts/evmx/watcher/precompiles/ReadPrecompile.sol +++ b/contracts/evmx/watcher/precompiles/ReadPrecompile.sol @@ -52,7 +52,7 @@ contract ReadPrecompile is IPrecompile, WatcherBase { function handlePayload( address, PayloadParams calldata payloadParams - ) external onlyWatcher returns (uint256 fees, uint256 deadline) { + ) external onlyWatcher returns (uint256 fees, uint256 deadline, bytes memory) { fees = readFees; deadline = block.timestamp + expiryTime; diff --git a/contracts/evmx/watcher/precompiles/WritePrecompile.sol b/contracts/evmx/watcher/precompiles/WritePrecompile.sol index 31dc5540..a7fc96be 100644 --- a/contracts/evmx/watcher/precompiles/WritePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/WritePrecompile.sol @@ -120,7 +120,7 @@ contract WritePrecompile is IPrecompile, WatcherBase, Ownable { function handlePayload( address transmitter_, PayloadParams memory payloadParams - ) external onlyWatcher returns (uint256 fees, uint256 deadline) { + ) external onlyWatcher returns (uint256 fees, uint256 deadline, bytes memory) { fees = writeFees; deadline = block.timestamp + expiryTime; diff --git a/contracts/protocol/Socket.sol b/contracts/protocol/Socket.sol index 0bbe472a..c0dcd7df 100644 --- a/contracts/protocol/Socket.sol +++ b/contracts/protocol/Socket.sol @@ -38,18 +38,10 @@ contract Socket is SocketUtils { * @dev Error emitted when less gas limit is provided for execution than expected */ error LowGasLimit(); - /** - * @dev Error emitted when the deadline has passed - */ - error DeadlinePassed(); /** * @dev Error emitted when the message value is insufficient */ error InsufficientMsgValue(); - /** - * @dev Error emitted when the call type is read - */ - error InvalidCallType(); /** * @notice Constructor for the Socket contract diff --git a/contracts/protocol/SocketConfig.sol b/contracts/protocol/SocketConfig.sol index 19811c07..22528f5d 100644 --- a/contracts/protocol/SocketConfig.sol +++ b/contracts/protocol/SocketConfig.sol @@ -8,7 +8,7 @@ import "./interfaces/ISocketFeeManager.sol"; import "../utils/AccessControl.sol"; import {GOVERNANCE_ROLE, RESCUE_ROLE, SWITCHBOARD_DISABLER_ROLE} from "../utils/common/AccessRoles.sol"; import {PlugConfig, SwitchboardStatus, ExecutionStatus} from "../utils/common/Structs.sol"; -import {PlugNotFound, InvalidAppGateway, InvalidTransmitter, InvalidSwitchboard} from "../utils/common/Errors.sol"; +import "../utils/common/Errors.sol"; import {MAX_COPY_BYTES} from "../utils/common/Constants.sol"; /** diff --git a/contracts/utils/common/Errors.sol b/contracts/utils/common/Errors.sol index 896c820d..0522ec48 100644 --- a/contracts/utils/common/Errors.sol +++ b/contracts/utils/common/Errors.sol @@ -72,3 +72,5 @@ error InvalidContract(); error InvalidData(); error InvalidNonce(); error InvalidSignature(); + +error DeadlinePassed(); From 0ee8494212880af604bd4154bb50a2906d6afb9e Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 27 May 2025 17:48:26 +0530 Subject: [PATCH 063/130] feat: execute at in precompile data --- .../watcher/precompiles/SchedulePrecompile.sol | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol b/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol index 85b185ca..d62aa2a4 100644 --- a/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol @@ -31,7 +31,7 @@ contract SchedulePrecompile is IPrecompile, WatcherBase { /// @notice Emitted when the expiry time for a schedule is set event ExpiryTimeSet(uint256 expiryTime_); /// @notice Emitted when a schedule is requested - event ScheduleRequested(bytes32 payloadId, uint256 deadline); + event ScheduleRequested(bytes32 payloadId, uint256 executeAt, uint256 deadline); /// @notice Emitted when a schedule is resolved event ScheduleResolved(bytes32 payloadId); @@ -103,7 +103,7 @@ contract SchedulePrecompile is IPrecompile, WatcherBase { revert InvalidScheduleDelay(); // For schedule precompile, encode the payload parameters - precompileData = abi.encode(queueParams_.overrideParams.delayInSeconds); + precompileData = abi.encode(queueParams_.overrideParams.delayInSeconds, 0); estimatedFees = scheduleFeesPerSecond * queueParams_.overrideParams.delayInSeconds + @@ -116,19 +116,21 @@ contract SchedulePrecompile is IPrecompile, WatcherBase { function handlePayload( address, PayloadParams calldata payloadParams - ) external onlyWatcher returns (uint256 fees, uint256 deadline) { + ) external onlyWatcher returns (uint256 fees, uint256 deadline, bytes memory precompileData) { uint256 delayInSeconds = abi.decode(payloadParams.precompileData, (uint256)); + // expiryTime is very low, to account for infra delay - deadline = block.timestamp + delayInSeconds + expiryTime; + uint256 executeAt = block.timestamp + delayInSeconds; + deadline = executeAt + expiryTime; + precompileData = abi.encode(delayInSeconds, executeAt); fees = scheduleFeesPerSecond * delayInSeconds + scheduleCallbackFees; // emits event for watcher to track schedule and resolve when deadline is reached - emit ScheduleRequested(payloadParams.payloadId, deadline); + emit ScheduleRequested(payloadParams.payloadId, executeAt, deadline); } function resolvePayload(PayloadParams calldata payloadParams_) external { - if (block.timestamp < payloadParams_.deadline) revert ResolvingScheduleTooEarly(); - + if (payloadParams_.deadline > block.timestamp) revert ResolvingScheduleTooEarly(); emit ScheduleResolved(payloadParams_.payloadId); } } From 71c5142eaae440bb454a786c76ede2ec17aab634 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 27 May 2025 20:21:51 +0530 Subject: [PATCH 064/130] feat: add fees pool --- contracts/evmx/fees/Credit.sol | 19 ++++++++-- contracts/evmx/fees/FeesManager.sol | 2 + contracts/evmx/fees/FeesPool.sol | 49 +++++++++++++++++++++++++ contracts/evmx/interfaces/IFeesPool.sol | 11 ++++++ contracts/utils/common/AccessRoles.sol | 2 + contracts/utils/common/Errors.sol | 1 - 6 files changed, 79 insertions(+), 5 deletions(-) create mode 100644 contracts/evmx/fees/FeesPool.sol create mode 100644 contracts/evmx/interfaces/IFeesPool.sol diff --git a/contracts/evmx/fees/Credit.sol b/contracts/evmx/fees/Credit.sol index 14a553d2..191c9c81 100644 --- a/contracts/evmx/fees/Credit.sol +++ b/contracts/evmx/fees/Credit.sol @@ -8,6 +8,8 @@ import "solady/utils/SafeTransferLib.sol"; import "../interfaces/IFeesManager.sol"; import "../interfaces/IFeesPlug.sol"; +import "../interfaces/IFeesPool.sol"; + import {AddressResolverUtil} from "../helpers/AddressResolverUtil.sol"; import {NonceUsed, InvalidAmount, InsufficientCreditsAvailable, InsufficientBalance, InvalidChainSlug, NotRequestHandler} from "../../utils/common/Errors.sol"; import {WRITE} from "../../utils/common/Constants.sol"; @@ -19,6 +21,8 @@ abstract contract FeesManagerStorage is IFeesManager { /// @notice switchboard type bytes32 public sbType; + IFeesPool public feesPool; + /// @notice user credits => stores fees for user, app gateway, transmitters and watcher precompile mapping(address => UserCredits) public userCredits; @@ -71,11 +75,19 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressR /// @notice Emitted when fees plug is set event FeesPlugSet(uint32 indexed chainSlug, address indexed feesPlug); + /// @notice Emitted when fees pool is set + event FeesPoolSet(address indexed feesPool); + function setFeesPlug(uint32 chainSlug_, address feesPlug_) external onlyOwner { feesPlugs[chainSlug_] = feesPlug_; emit FeesPlugSet(chainSlug_, feesPlug_); } + function setFeesPool(address feesPool_) external onlyOwner { + feesPool = IFeesPool(feesPool_); + emit FeesPoolSet(feesPool_); + } + /// @notice Deposits credits and native tokens to a user /// @param depositTo_ The address to deposit the credits to /// @param chainSlug_ The chain slug @@ -88,15 +100,14 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressR address token_, uint256 nativeAmount_, uint256 creditAmount_ - ) external payable override onlyWatcher { - if (creditAmount_ + nativeAmount_ != msg.value) revert InvalidAmount(); - tokenOnChainBalances[chainSlug_][token_] += nativeAmount_ + creditAmount_; + ) external override onlyWatcher { + tokenOnChainBalances[chainSlug_][token_] += creditAmount_ + nativeAmount_; UserCredits storage userCredit = userCredits[depositTo_]; userCredit.totalCredits += creditAmount_; // if native transfer fails, add to credit - bool success = SafeTransferLib.trySafeTransferETH(depositTo_, nativeAmount_, gasleft()); + bool success = feesPool.withdraw(depositTo_, nativeAmount_); if (!success) userCredit.totalCredits += nativeAmount_; emit CreditsDeposited(chainSlug_, depositTo_, token_, creditAmount_); diff --git a/contracts/evmx/fees/FeesManager.sol b/contracts/evmx/fees/FeesManager.sol index 845822a0..6e1fea3c 100644 --- a/contracts/evmx/fees/FeesManager.sol +++ b/contracts/evmx/fees/FeesManager.sol @@ -45,11 +45,13 @@ contract FeesManager is Credit { function initialize( uint32 evmxSlug_, address addressResolver_, + address feesPool_, address owner_, bytes32 sbType_ ) public reinitializer(1) { evmxSlug = evmxSlug_; sbType = sbType_; + feesPool = IFeesPool(feesPool_); _setAddressResolver(addressResolver_); _initializeOwner(owner_); } diff --git a/contracts/evmx/fees/FeesPool.sol b/contracts/evmx/fees/FeesPool.sol new file mode 100644 index 00000000..e0b09fad --- /dev/null +++ b/contracts/evmx/fees/FeesPool.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import "../../utils/AccessControl.sol"; +import "../../utils/common/AccessRoles.sol"; +import "../interfaces/IFeesPool.sol"; + +/** + * @title FeesPool + * @notice Contract to store native fees that can be pulled by fees manager + */ +contract FeesPool is IFeesPool, AccessControl { + error TransferFailed(); + + /** + * @param owner_ The address of the owner + */ + constructor(address owner_) { + _setOwner(owner_); + + // to rescue funds + _grantRole(FEE_MANAGER_ROLE, owner_); + } + + /** + * @notice Allows fees manager to withdraw native tokens + * @param to_ The address to withdraw to + * @param amount_ The amount to withdraw + * @return success Whether the withdrawal was successful + */ + function withdraw( + address to_, + uint256 amount_ + ) external onlyRole(FEE_MANAGER_ROLE) returns (bool success) { + (success, ) = to_.call{value: amount_}(""); + emit NativeWithdrawn(success, to_, amount_); + } + + /** + * @notice Returns the current balance of native tokens in the pool + */ + function getBalance() external view returns (uint256) { + return address(this).balance; + } + + receive() external payable { + emit NativeDeposited(msg.sender, msg.value); + } +} diff --git a/contracts/evmx/interfaces/IFeesPool.sol b/contracts/evmx/interfaces/IFeesPool.sol new file mode 100644 index 00000000..b2dcf1a1 --- /dev/null +++ b/contracts/evmx/interfaces/IFeesPool.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +interface IFeesPool { + event NativeDeposited(address indexed from, uint256 amount); + event NativeWithdrawn(bool success, address indexed to, uint256 amount); + + function withdraw(address to_, uint256 amount_) external returns (bool success); + + function getBalance() external view returns (uint256); +} diff --git a/contracts/utils/common/AccessRoles.sol b/contracts/utils/common/AccessRoles.sol index e1406a49..1ca5ab61 100644 --- a/contracts/utils/common/AccessRoles.sol +++ b/contracts/utils/common/AccessRoles.sol @@ -12,3 +12,5 @@ bytes32 constant TRANSMITTER_ROLE = keccak256("TRANSMITTER_ROLE"); bytes32 constant WATCHER_ROLE = keccak256("WATCHER_ROLE"); // used to disable switchboard bytes32 constant SWITCHBOARD_DISABLER_ROLE = keccak256("SWITCHBOARD_DISABLER_ROLE"); +// used by fees manager to withdraw native tokens +bytes32 constant FEE_MANAGER_ROLE = keccak256("FEE_MANAGER_ROLE"); diff --git a/contracts/utils/common/Errors.sol b/contracts/utils/common/Errors.sol index 0522ec48..83a002ef 100644 --- a/contracts/utils/common/Errors.sol +++ b/contracts/utils/common/Errors.sol @@ -70,7 +70,6 @@ error OnlyAppGateway(); error NewMaxFeesLowerThanCurrent(uint256 currentMaxFees, uint256 newMaxFees); error InvalidContract(); error InvalidData(); -error InvalidNonce(); error InvalidSignature(); error DeadlinePassed(); From 677c36bcac28702d82cd6f35a769e21fe999cb2f Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 27 May 2025 20:22:02 +0530 Subject: [PATCH 065/130] fix: remove payable from deposit --- contracts/evmx/interfaces/IFeesManager.sol | 2 +- contracts/evmx/watcher/Watcher.sol | 39 ++++++++----------- .../watcher/precompiles/ReadPrecompile.sol | 1 + .../watcher/precompiles/WritePrecompile.sol | 17 +++----- contracts/utils/common/Structs.sol | 2 +- 5 files changed, 25 insertions(+), 36 deletions(-) diff --git a/contracts/evmx/interfaces/IFeesManager.sol b/contracts/evmx/interfaces/IFeesManager.sol index 8bcdf802..71ab5009 100644 --- a/contracts/evmx/interfaces/IFeesManager.sol +++ b/contracts/evmx/interfaces/IFeesManager.sol @@ -9,7 +9,7 @@ interface IFeesManager { address token_, uint256 nativeAmount_, uint256 creditAmount_ - ) external payable; + ) external; function wrap(address receiver_) external payable; diff --git a/contracts/evmx/watcher/Watcher.sol b/contracts/evmx/watcher/Watcher.sol index f3faeb1c..82bd965d 100644 --- a/contracts/evmx/watcher/Watcher.sol +++ b/contracts/evmx/watcher/Watcher.sol @@ -177,47 +177,42 @@ contract Watcher is Trigger { _validateSignature(params_[i].data, params_[i].nonce, params_[i].signature); // call the contract - // trusting watcher to send enough value for all calls - (bool success, ) = params_[i].contractAddress.call{value: params_[i].value}( - params_[i].data - ); + (bool success, ) = params_[i].contractAddress.call(params_[i].data); if (!success) revert CallFailed(); } } + /// @notice Verifies that a watcher signature is valid + /// @param data_ The data to verify + /// @param nonce_ The nonce of the signature + /// @param signature_ The signature to verify function _validateSignature( bytes memory data_, uint256 nonce_, bytes memory signature_ ) internal { if (data_.length == 0) revert InvalidData(); - if (nonce_ == 0) revert InvalidNonce(); if (signature_.length == 0) revert InvalidSignature(); + if (isNonceUsed[nonce_]) revert NonceUsed(); + isNonceUsed[nonce_] = true; + + bytes32 digest = keccak256(abi.encode(address(this), evmxSlug, nonce_, data_)); // check if signature is valid - if (!_isWatcherSignatureValid(nonce_, data_, signature_)) revert InvalidSignature(); + if (_recoverSigner(digest, signature_) != owner()) revert InvalidSignature(); } - /// @notice Verifies that a watcher signature is valid - /// @param signatureNonce_ The nonce of the signature - /// @param inputData_ The input data to verify + /// @notice Recovers the signer of a message + /// @param digest_ The digest of the input data /// @param signature_ The signature to verify /// @dev This function verifies that the signature was created by the watcher and that the nonce has not been used before - function _isWatcherSignatureValid( - uint256 signatureNonce_, - bytes memory inputData_, + function _recoverSigner( + bytes32 digest_, bytes memory signature_ - ) internal returns (bool) { - if (isNonceUsed[signatureNonce_]) revert NonceUsed(); - isNonceUsed[signatureNonce_] = true; - - bytes32 digest = keccak256( - abi.encode(address(this), evmxSlug, signatureNonce_, inputData_) - ); - digest = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", digest)); + ) internal view returns (address signer) { + bytes32 digest = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", digest_)); // recovered signer is checked for the valid roles later - address signer = ECDSA.recover(digest, signature_); - return signer == owner(); + signer = ECDSA.recover(digest, signature_); } } diff --git a/contracts/evmx/watcher/precompiles/ReadPrecompile.sol b/contracts/evmx/watcher/precompiles/ReadPrecompile.sol index e0ef0700..7fb22c94 100644 --- a/contracts/evmx/watcher/precompiles/ReadPrecompile.sol +++ b/contracts/evmx/watcher/precompiles/ReadPrecompile.sol @@ -49,6 +49,7 @@ contract ReadPrecompile is IPrecompile, WatcherBase { /// @notice Handles payload processing and returns fees /// @param payloadParams The payload parameters to handle /// @return fees The fees required for processing + /// @return deadline The deadline for the payload function handlePayload( address, PayloadParams calldata payloadParams diff --git a/contracts/evmx/watcher/precompiles/WritePrecompile.sol b/contracts/evmx/watcher/precompiles/WritePrecompile.sol index a7fc96be..1ccac9c4 100644 --- a/contracts/evmx/watcher/precompiles/WritePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/WritePrecompile.sol @@ -124,17 +124,10 @@ contract WritePrecompile is IPrecompile, WatcherBase, Ownable { fees = writeFees; deadline = block.timestamp + expiryTime; - ( - address appGateway, - Transaction memory transaction, - WriteFinality writeFinality, - uint256 gasLimit, - uint256 value, - - ) = abi.decode( - payloadParams.precompileData, - (address, Transaction, WriteFinality, uint256, uint256, address) - ); + (, Transaction memory transaction, , uint256 gasLimit, uint256 value, ) = abi.decode( + payloadParams.precompileData, + (address, Transaction, WriteFinality, uint256, uint256, address) + ); bytes32 prevBatchDigestHash = getPrevBatchDigestHash(payloadParams.batchCount); @@ -149,7 +142,7 @@ contract WritePrecompile is IPrecompile, WatcherBase, Ownable { value, transaction.payload, transaction.target, - encodeAppGatewayId(appGateway), + encodeAppGatewayId(payloadParams.appGateway), prevBatchDigestHash, bytes("") ); diff --git a/contracts/utils/common/Structs.sol b/contracts/utils/common/Structs.sol index 01e8cf19..bb72bd71 100644 --- a/contracts/utils/common/Structs.sol +++ b/contracts/utils/common/Structs.sol @@ -69,6 +69,7 @@ struct TriggerParams { bytes overrides; bytes payload; } + struct PromiseReturnData { bool maxCopyExceeded; bytes32 payloadId; @@ -109,7 +110,6 @@ struct UserCredits { struct WatcherMultiCallParams { address contractAddress; - uint256 value; bytes data; uint256 nonce; bytes signature; From fc1e3c0f704c272a0c3f63134057f3b970e26b0b Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 27 May 2025 22:14:59 +0530 Subject: [PATCH 066/130] fix: fees test --- contracts/evmx/fees/Credit.sol | 34 +- contracts/evmx/fees/FeesPool.sol | 4 +- contracts/evmx/interfaces/IFeesManager.sol | 2 +- test/SetupTest.t.sol | 397 +++++++++++---------- 4 files changed, 235 insertions(+), 202 deletions(-) diff --git a/contracts/evmx/fees/Credit.sol b/contracts/evmx/fees/Credit.sol index 191c9c81..ebe728f1 100644 --- a/contracts/evmx/fees/Credit.sol +++ b/contracts/evmx/fees/Credit.sol @@ -4,7 +4,6 @@ pragma solidity ^0.8.21; import {Ownable} from "solady/auth/Ownable.sol"; import "solady/utils/Initializable.sol"; import "solady/utils/ECDSA.sol"; -import "solady/utils/SafeTransferLib.sol"; import "../interfaces/IFeesManager.sol"; import "../interfaces/IFeesPlug.sol"; @@ -53,14 +52,16 @@ abstract contract FeesManagerStorage is IFeesManager { abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressResolverUtil { /// @notice Emitted when fees deposited are updated /// @param chainSlug The chain identifier - /// @param appGateway The app gateway address /// @param token The token address - /// @param amount The new amount deposited - event CreditsDeposited( + /// @param depositTo The address to deposit to + /// @param creditAmount The credit amount added + /// @param nativeAmount The native amount transferred + event Deposited( uint32 indexed chainSlug, - address indexed appGateway, address indexed token, - uint256 amount + address indexed depositTo, + uint256 creditAmount, + uint256 nativeAmount ); /// @notice Emitted when credits are wrapped @@ -95,9 +96,9 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressR /// @param nativeAmount_ The native amount /// @param creditAmount_ The credit amount function deposit( - address depositTo_, uint32 chainSlug_, address token_, + address depositTo_, uint256 nativeAmount_, uint256 creditAmount_ ) external override onlyWatcher { @@ -106,11 +107,18 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressR UserCredits storage userCredit = userCredits[depositTo_]; userCredit.totalCredits += creditAmount_; - // if native transfer fails, add to credit - bool success = feesPool.withdraw(depositTo_, nativeAmount_); - if (!success) userCredit.totalCredits += nativeAmount_; + if (nativeAmount_ > 0) { + // if native transfer fails, add to credit + bool success = feesPool.withdraw(depositTo_, nativeAmount_); + + if (!success) { + userCredit.totalCredits += nativeAmount_; + nativeAmount_ = 0; + creditAmount_ += nativeAmount_; + } + } - emit CreditsDeposited(chainSlug_, depositTo_, token_, creditAmount_); + emit Deposited(chainSlug_, token_, depositTo_, creditAmount_, nativeAmount_); } function wrap(address receiver_) external payable override { @@ -124,8 +132,8 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressR if (userCredit.totalCredits < amount_) revert InsufficientCreditsAvailable(); userCredit.totalCredits -= amount_; - if (address(this).balance < amount_) revert InsufficientBalance(); - SafeTransferLib.safeTransferETH(receiver_, amount_); + bool success = feesPool.withdraw(receiver_, amount_); + if (!success) revert InsufficientBalance(); emit CreditsUnwrapped(receiver_, amount_); } diff --git a/contracts/evmx/fees/FeesPool.sol b/contracts/evmx/fees/FeesPool.sol index e0b09fad..f7aeb73d 100644 --- a/contracts/evmx/fees/FeesPool.sol +++ b/contracts/evmx/fees/FeesPool.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.21; import "../../utils/AccessControl.sol"; import "../../utils/common/AccessRoles.sol"; import "../interfaces/IFeesPool.sol"; +import "solady/utils/SafeTransferLib.sol"; /** * @title FeesPool @@ -32,7 +33,8 @@ contract FeesPool is IFeesPool, AccessControl { address to_, uint256 amount_ ) external onlyRole(FEE_MANAGER_ROLE) returns (bool success) { - (success, ) = to_.call{value: amount_}(""); + if (amount_ == 0) return true; + success = SafeTransferLib.trySafeTransferETH(to_, amount_, gasleft()); emit NativeWithdrawn(success, to_, amount_); } diff --git a/contracts/evmx/interfaces/IFeesManager.sol b/contracts/evmx/interfaces/IFeesManager.sol index 71ab5009..8e4a495b 100644 --- a/contracts/evmx/interfaces/IFeesManager.sol +++ b/contracts/evmx/interfaces/IFeesManager.sol @@ -4,9 +4,9 @@ import {WriteFinality, UserCredits, AppGatewayApprovals, OverrideParams, Transac interface IFeesManager { function deposit( - address depositTo_, uint32 chainSlug_, address token_, + address depositTo_, uint256 nativeAmount_, uint256 creditAmount_ ) external; diff --git a/test/SetupTest.t.sol b/test/SetupTest.t.sol index 1ac29296..ebab5058 100644 --- a/test/SetupTest.t.sol +++ b/test/SetupTest.t.sol @@ -28,6 +28,7 @@ import "../contracts/evmx/helpers/AsyncDeployer.sol"; import "../contracts/evmx/helpers/DeployForwarder.sol"; import "../contracts/evmx/plugs/ContractFactoryPlug.sol"; import "../contracts/evmx/fees/FeesManager.sol"; +import "../contracts/evmx/fees/FeesPool.sol"; import "../contracts/evmx/plugs/FeesPlug.sol"; import "../contracts/evmx/AuctionManager.sol"; import "../contracts/evmx/mocks/TestUSDC.sol"; @@ -63,7 +64,7 @@ contract SetupStore is Test { uint256 triggerFees = 0.01 ether; uint256 socketFees = 0.01 ether; - uint256 public signatureNonce; + uint256 public watcherNonce; uint256 public payloadIdCounter; uint256 public triggerCounter; uint256 public asyncPromiseCounter; @@ -82,6 +83,7 @@ contract SetupStore is Test { ERC1967Factory public proxyFactory; FeesManager feesManager; + FeesPool feesPool; AddressResolver public addressResolver; AsyncDeployer public asyncDeployer; DeployForwarder public deployForwarder; @@ -109,8 +111,12 @@ contract DeploySetup is SetupStore { optConfig = _deploySocket(optChainSlug); _configureChain(optChainSlug); + // transfer eth to fees pool for native fee payouts + vm.deal(address(feesPool), 100000 ether); + vm.startPrank(watcherEOA); auctionManager.grantRole(TRANSMITTER_ROLE, transmitterEOA); + feesPool.grantRole(FEE_MANAGER_ROLE, address(feesManager)); // setup address resolver addressResolver.setWatcher(address(watcher)); @@ -183,8 +189,10 @@ contract DeploySetup is SetupStore { }) }); - hoax(address(watcher)); - configurations.setPlugConfigs(configs); + watcherMultiCall( + address(configurations), + abi.encodeWithSelector(Configurations.setPlugConfigs.selector, configs) + ); } function _deploySocket(uint32 chainSlug_) internal returns (SocketContracts memory) { @@ -251,6 +259,7 @@ contract DeploySetup is SetupStore { function _deployEVMxCore() internal { proxyFactory = new ERC1967Factory(); + feesPool = new FeesPool(watcherEOA); // Deploy implementations for upgradeable contracts FeesManager feesManagerImpl = new FeesManager(); @@ -273,6 +282,7 @@ contract DeploySetup is SetupStore { FeesManager.initialize.selector, evmxSlug, address(addressResolver), + address(feesPool), watcherEOA, FAST ) @@ -341,13 +351,20 @@ contract DeploySetup is SetupStore { return chainSlug_ == arbChainSlug ? arbConfig : optConfig; } - function _createWatcherSignature( - address watcherPrecompile_, - bytes memory params_ - ) internal view returns (bytes memory) { - bytes32 digest = keccak256( - abi.encode(watcherPrecompile_, evmxSlug, signatureNonce, params_) - ); + function watcherMultiCall(address contractAddress_, bytes memory data_) internal { + WatcherMultiCallParams[] memory params = new WatcherMultiCallParams[](1); + params[0] = WatcherMultiCallParams({ + contractAddress: contractAddress_, + data: data_, + nonce: watcherNonce, + signature: _createWatcherSignature(data_) + }); + watcherNonce++; + watcher.watcherMultiCall(params); + } + + function _createWatcherSignature(bytes memory data_) internal view returns (bytes memory) { + bytes32 digest = keccak256(abi.encode(address(watcher), evmxSlug, watcherNonce, data_)); return _createSignature(digest, watcherPrivateKey); } @@ -387,24 +404,15 @@ contract DeploySetup is SetupStore { return address(uint160(uint256(hash))); } - - function testDeployAndSetup() public { - deploy(); - - vm.assertEq(address(arbConfig.feesPlug.socket__()), address(arbConfig.socket)); - vm.assertEq(address(optConfig.feesPlug.socket__()), address(optConfig.socket)); - - vm.assertEq(address(arbConfig.contractFactoryPlug.socket__()), address(arbConfig.socket)); - vm.assertEq(address(optConfig.contractFactoryPlug.socket__()), address(optConfig.socket)); - } } contract FeesSetup is DeploySetup { - event CreditsDeposited( + event Deposited( uint32 indexed chainSlug, - address indexed appGateway, address indexed token, - uint256 amount + address indexed appGateway, + uint256 creditAmount, + uint256 nativeAmount ); event CreditsWrapped(address indexed consumeFrom, uint256 amount); event CreditsUnwrapped(address indexed consumeFrom, uint256 amount); @@ -417,6 +425,7 @@ contract FeesSetup is DeploySetup { uint256 native_, address user_ ) internal { + console.log(user_); SocketContracts memory socketConfig = getSocketConfig(chainSlug_); TestUSDC token = socketConfig.testUSDC; @@ -442,27 +451,33 @@ contract FeesSetup is DeploySetup { ); uint256 currentCredits = feesManager.getAvailableCredits(user_); - uint256 currentNative = address(feesManager).balance; + uint256 currentNative = address(user_).balance; - hoax(address(watcher)); - feesManager.deposit{value: native_ + credits_}( - user_, - chainSlug_, - address(token), - native_, - credits_ + vm.expectEmit(true, true, true, false); + emit Deposited(chainSlug_, address(token), user_, credits_, native_); + + // todo: try to call this with hoax watcher + watcherMultiCall( + address(feesManager), + abi.encodeWithSelector( + Credit.deposit.selector, + chainSlug_, + address(token), + user_, + native_, + credits_ + ) ); + // hoax(address(watcher)); + // feesManager.deposit(chainSlug_, address(token), user_, native_, credits_); + assertEq( feesManager.getAvailableCredits(user_), currentCredits + credits_, "User should have more credits" ); - assertEq( - address(feesManager).balance, - currentNative + native_ + credits_, - "Fees manager should have more credits" - ); + assertEq(address(user_).balance, currentNative + native_, "User should have more native"); } function approveAppGateway( @@ -572,118 +587,75 @@ contract WatcherSetup is AuctionSetup { IAppGateway appGateway_, bytes32[] memory contractIds_ ) internal returns (uint40 requestCount) { - executeRequest(new bytes[](0)); + requestCount = executeRequest(); setupGatewayAndPlugs(chainSlug_, appGateway_, contractIds_); } - function _checkIfOnlyReadBatch(uint40 batchCount_) internal view returns (bool) { - bytes32[] memory payloadIds = requestHandler.getBatchPayloadIds(batchCount_); - for (uint i = 0; i < payloadIds.length; i++) { - if (requestHandler.getPayload(payloadIds[i]).callType != READ) return false; - } - return true; - } - - function executeRequest(bytes[] memory readReturnData_) internal { - uint40 requestCount = watcher.getCurrentRequestCount(); + function executeRequest() internal returns (uint40 requestCount) { + requestCount = watcher.getCurrentRequestCount(); requestCount = requestCount == 0 ? 0 : requestCount - 1; + + RequestParams memory requestParams = requestHandler.getRequest(requestCount); uint40[] memory batches = requestHandler.getRequestBatchIds(requestCount); - bool onlyReads = _checkIfOnlyReadBatch(batches[0]); - if (!(onlyReads && batches.length == 1)) { - bidAndEndAuction(requestCount); - } + // bids and executes schedule request if created for endAuction + if (requestParams.writeCount != 0) bidAndEndAuction(requestCount); + for (uint i = 0; i < batches.length; i++) _processBatch(batches[i]); - uint256 readCount = 0; - for (uint i = 0; i < batches.length; i++) { - bool hasMoreBatches = i < batches.length - 1; - readCount = _processBatch(batches[i], readReturnData_, readCount, hasMoreBatches); - } + requestParams = requestHandler.getRequest(requestCount); + assertEq(requestParams.requestTrackingParams.isRequestExecuted, true); } - function _processBatch( - uint40 batchCount_, - bytes[] memory readReturnData_, - uint256 readCount_, - bool hasMoreBatches - ) internal returns (uint256) { + function _processBatch(uint40 batchCount_) internal { bytes32[] memory payloadIds = requestHandler.getBatchPayloadIds(batchCount_); + + PromiseReturnData[] memory promiseReturnData = new PromiseReturnData[](1); + bool success; for (uint i = 0; i < payloadIds.length; i++) { PayloadParams memory payloadParams = watcher.getPayloadParams(payloadIds[i]); - bool isLastPayload = i == payloadIds.length - 1 && hasMoreBatches; + if (payloadParams.callType == READ) { - _resolveAndExpectWriteProofRequested( - payloadParams.payloadId, - payloadParams, - readReturnData_[readCount_++], - isLastPayload - ); - } else { - (, bytes memory returnData) = _uploadProofAndExecute(payloadParams); - _resolveAndExpectWriteProofRequested( - payloadParams.payloadId, - payloadParams, - returnData, - isLastPayload - ); + (success, promiseReturnData[0]) = _processRead(payloadParams); + } else if (payloadParams.callType == WRITE) { + (success, promiseReturnData[0]) = _processWrite(payloadParams); + } else if (payloadParams.callType == SCHEDULE) { + // todo: update time to delay + promiseReturnData[0] = PromiseReturnData({ + maxCopyExceeded: false, + payloadId: payloadParams.payloadId, + returnData: bytes("") + }); + success = true; } - } - return readCount_; - } - function _resolveAndExpectWriteProofRequested( - bytes32 payloadId_, - PayloadParams memory payloadParams, - bytes memory returnData, - bool isLastPayload - ) internal { - if (isLastPayload) { - vm.expectEmit(false, false, false, false); - emit WriteProofRequested( - transmitterEOA, - writePrecompile.digestHashes(payloadParams.payloadId), - writePrecompile.getPrevBatchDigestHash(payloadParams.batchCount), - payloadParams.deadline, - payloadParams - ); + if (success) { + _resolvePromise(promiseReturnData[0].payloadId, promiseReturnData[0].returnData); + } else { + // _markRevert(promiseReturnData); + } } - _resolvePromise(payloadId_, returnData); } - function _uploadProofAndExecute( + function _processRead( PayloadParams memory payloadParams - ) internal returns (bool, bytes memory) { - (bytes memory watcherProof, bytes32 digest) = _generateWatcherProof(payloadParams); - _writeProof(payloadParams.payloadId, watcherProof); - ( - ExecuteParams memory params, - SocketBatcher socketBatcher, - , - bytes memory transmitterSig, - address refundAddress - ) = _getExecuteParams(payloadParams); - return - socketBatcher.attestAndExecute( - params, - address(1), // todo: fix this socketConfig.switchboard, - digest, - watcherProof, - transmitterSig, - refundAddress - ); - } - - function resolvePromises(bytes32[] memory payloadIds, bytes[] memory returnData) internal { - for (uint i = 0; i < payloadIds.length; i++) { - _resolvePromise(payloadIds[i], returnData[i]); - } + ) internal returns (bool success, PromiseReturnData memory promiseReturnData_) { + (Transaction memory transaction, ) = abi.decode( + payloadParams.precompileData, + (Transaction, uint256) + ); + + bytes memory returnData; + (success, returnData) = transaction.target.call(transaction.payload); + promiseReturnData_ = PromiseReturnData({ + maxCopyExceeded: false, + payloadId: payloadParams.payloadId, + returnData: returnData + }); } - //////////////////////////////////// Helpers //////////////////////////////////// - - function _generateWatcherProof( - PayloadParams memory params_ - ) internal view returns (bytes memory, bytes32) { + function _processWrite( + PayloadParams memory payloadParams + ) internal returns (bool success, PromiseReturnData memory promiseReturnData_) { ( address appGateway, Transaction memory transaction, @@ -692,22 +664,25 @@ contract WatcherSetup is AuctionSetup { uint256 value, address switchboard ) = abi.decode( - params_.precompileData, + payloadParams.precompileData, (address, Transaction, WriteFinality, uint256, uint256, address) ); + + bytes32 payloadId = payloadParams.payloadId; + SocketContracts memory socketConfig = getSocketConfig(transaction.chainSlug); DigestParams memory digestParams_ = DigestParams( address(socketConfig.socket), transmitterEOA, - params_.payloadId, - params_.deadline, - params_.callType, + payloadId, + payloadParams.deadline, + payloadParams.callType, gasLimit, value, transaction.payload, transaction.target, encodeAppGatewayId(appGateway), - writePrecompile.getPrevBatchDigestHash(params_.batchCount), + writePrecompile.getPrevBatchDigestHash(payloadParams.batchCount), bytes("") ); bytes32 digest = writePrecompile.getDigest(digestParams_); @@ -715,64 +690,112 @@ contract WatcherSetup is AuctionSetup { abi.encode(address(socketConfig.switchboard), socketConfig.chainSlug, digest) ); bytes memory proof = _createSignature(sigDigest, watcherPrivateKey); - return (proof, digest); + + watcherMultiCall( + address(writePrecompile), + abi.encodeWithSelector(WritePrecompile.uploadProof.selector, payloadId, proof) + ); + assertEq(writePrecompile.watcherProofs(payloadId), proof); + // _resolveAndExpectWriteProofRequested( + // payloadId, + // payloadParams, + // promiseReturnData_, + // + // ); } - function _writeProof(bytes32 payloadId_, bytes memory watcherProof_) internal { - bytes memory bytesInput = abi.encode( - WritePrecompile.uploadProof.selector, - payloadId_, - watcherProof_ + function _uploadProofAndExecute( + PayloadParams memory payloadParams, + bytes memory watcherProof, + bytes32 digest + ) internal returns (bool, bytes memory) { + // ( + // ExecuteParams memory params, + // SocketBatcher socketBatcher, + // , + // bytes memory transmitterSig, + // address refundAddress + // ) = _getExecuteParams(payloadParams); + // return + // socketBatcher.attestAndExecute( + // params, + // address(1), // todo: fix this socketConfig.switchboard, + // digest, + // watcherProof, + // transmitterSig, + // refundAddress + // ); + } + + function _resolveAndExpectWriteProofRequested(PayloadParams memory payloadParams) internal { + vm.expectEmit(false, false, false, false); + emit WriteProofRequested( + transmitterEOA, + writePrecompile.digestHashes(payloadParams.payloadId), + writePrecompile.getPrevBatchDigestHash(payloadParams.batchCount), + payloadParams.deadline, + payloadParams ); - bytes memory watcherSignature = _createWatcherSignature(address(watcher), bytesInput); - writePrecompile.uploadProof(payloadId_, watcherProof_); - assertEq(writePrecompile.watcherProofs(payloadId_), watcherProof_); } - function _getExecuteParams( - PayloadParams memory payloadParams - ) - internal - view - returns ( - ExecuteParams memory params, - SocketBatcher socketBatcher, - uint256 value, - bytes memory transmitterSig, - address refundAddress - ) - { - SocketContracts memory socketConfig = getSocketConfig(payloadParams.transaction.chainSlug); - bytes32 transmitterDigest = keccak256( - abi.encode(address(socketConfig.socket), payloadParams.payloadId) - ); - transmitterSig = _createSignature(transmitterDigest, transmitterPrivateKey); - params = ExecuteParams({ - callType: payloadParams.payloadHeader.getCallType(), - deadline: payloadParams.deadline, - gasLimit: payloadParams.gasLimit, - value: payloadParams.value, - payload: payloadParams.payload, - target: payloadParams.target, - requestCount: payloadParams.payloadHeader.getRequestCount(), - batchCount: payloadParams.payloadHeader.getBatchCount(), - payloadCount: payloadParams.payloadHeader.getPayloadCount(), - prevDigestsHash: payloadParams.prevDigestsHash, - extraData: bytes("") - }); - value = payloadParams.value; - socketBatcher = socketConfig.socketBatcher; - refundAddress = transmitterEOA; + function resolvePromises(bytes32[] memory payloadIds, bytes[] memory returnData) internal { + for (uint i = 0; i < payloadIds.length; i++) { + _resolvePromise(payloadIds[i], returnData[i]); + } } + //////////////////////////////////// Helpers //////////////////////////////////// + // function _getExecuteParams( + // PayloadParams memory payloadParams + // ) + // internal + // view + // returns ( + // ExecuteParams memory params, + // SocketBatcher socketBatcher, + // uint256 value, + // bytes memory transmitterSig, + // address refundAddress + // ) + // { + // RequestParams memory requestParams = watcher.getRequestParams(payloadParams.requestCount); + // // SocketContracts memory socketConfig = getSocketConfig(requestParams.chainSlug); + + // bytes32 transmitterDigest = keccak256( + // abi.encode(address(socketConfig.socket), payloadParams.payloadId) + // ); + // transmitterSig = _createSignature(transmitterDigest, transmitterPrivateKey); + // params = ExecuteParams({ + // callType: payloadParams.payloadHeader.getCallType(), + // deadline: payloadParams.deadline, + // gasLimit: payloadParams.gasLimit, + // value: payloadParams.value, + // payload: payloadParams.payload, + // target: payloadParams.target, + // requestCount: payloadParams.payloadHeader.getRequestCount(), + // batchCount: payloadParams.payloadHeader.getBatchCount(), + // payloadCount: payloadParams.payloadHeader.getPayloadCount(), + // prevDigestsHash: payloadParams.prevDigestsHash, + // extraData: bytes("") + // }); + + // value = payloadParams.value; + // socketBatcher = socketConfig.socketBatcher; + // refundAddress = transmitterEOA; + // } + function _resolvePromise(bytes32 payloadId, bytes memory returnData) internal { PromiseReturnData[] memory promiseReturnData = new PromiseReturnData[](1); - promiseReturnData[0] = PromiseReturnData({payloadId: payloadId, returnData: returnData}); - bytes memory watcherSignature = _createWatcherSignature( + promiseReturnData[0] = PromiseReturnData({ + maxCopyExceeded: false, + payloadId: payloadId, + returnData: returnData + }); + + watcherMultiCall( address(watcher), - abi.encode(Watcher.resolvePromises.selector, promiseReturnData) + abi.encodeWithSelector(PromiseResolver.resolvePromises.selector, promiseReturnData) ); - watcher.resolvePromises(promiseReturnData, signatureNonce++, watcherSignature); } function setupGatewayAndPlugs( @@ -780,25 +803,25 @@ contract WatcherSetup is AuctionSetup { IAppGateway appGateway_, bytes32[] memory contractIds_ ) internal { - AppGatewayConfig[] memory gateways = new AppGatewayConfig[](contractIds_.length); + AppGatewayConfig[] memory configs = new AppGatewayConfig[](contractIds_.length); SocketContracts memory socketConfig = getSocketConfig(chainSlug_); for (uint i = 0; i < contractIds_.length; i++) { address plug = appGateway_.getOnChainAddress(contractIds_[i], chainSlug_); - gateways[i] = AppGatewayConfig({ + configs[i] = AppGatewayConfig({ plug: plug, chainSlug: chainSlug_, - appGatewayId: encodeAppGatewayId(address(appGateway_)), - switchboard: address(socketConfig.switchboard) + plugConfig: PlugConfig({ + appGatewayId: encodeAppGatewayId(address(appGateway_)), + switchboard: address(socketConfig.switchboard) + }) }); } - - bytes memory watcherSignature = _createWatcherSignature( + watcherMultiCall( address(configurations), - abi.encode(IConfigurations.setAppGateways.selector, gateways) + abi.encodeWithSelector(Configurations.setPlugConfigs.selector, configs) ); - configurations.setAppGateways(gateways, signatureNonce++, watcherSignature); } } From 7eb654f59b0367b60e2c8dec84fca863f22eb8a9 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 27 May 2025 23:54:12 +0530 Subject: [PATCH 067/130] test: process batch --- contracts/evmx/AuctionManager.sol | 10 +- contracts/evmx/watcher/RequestHandler.sol | 3 +- contracts/evmx/watcher/Watcher.sol | 5 +- contracts/evmx/watcher/WatcherBase.sol | 10 + .../watcher/precompiles/ReadPrecompile.sol | 11 +- .../precompiles/SchedulePrecompile.sol | 8 +- .../watcher/precompiles/WritePrecompile.sol | 15 +- test/Core.t.sol | 16 + test/SetupTest.t.sol | 289 +++++++++--------- test/apps/Counter.t.sol | 51 ++-- test/apps/ParallelCounter.t.sol | 7 +- test/apps/SuperToken.t.sol | 10 +- 12 files changed, 253 insertions(+), 182 deletions(-) create mode 100644 test/Core.t.sol diff --git a/contracts/evmx/AuctionManager.sol b/contracts/evmx/AuctionManager.sol index 794ea10e..33e2057e 100644 --- a/contracts/evmx/AuctionManager.sol +++ b/contracts/evmx/AuctionManager.sol @@ -92,7 +92,13 @@ contract AuctionManager is AuctionManagerStorage, AccessControl, AppGatewayBase bytes memory transmitterSignature, bytes memory extraData ) external override { - if ( + if (auctionEndDelaySeconds == 0) { + // todo: temp fix, can be called for random request + if ( + auctionStatus[requestCount_] != AuctionStatus.NOT_STARTED && + auctionStatus[requestCount_] != AuctionStatus.RESTARTED + ) revert AuctionNotOpen(); + } else if ( auctionStatus[requestCount_] != AuctionStatus.OPEN && auctionStatus[requestCount_] != AuctionStatus.RESTARTED ) revert AuctionNotOpen(); @@ -105,7 +111,7 @@ contract AuctionManager is AuctionManagerStorage, AccessControl, AppGatewayBase if (!_hasRole(TRANSMITTER_ROLE, transmitter)) revert InvalidTransmitter(); // check if the bid is lower than the existing bid - if (bidFees >= winningBids[requestCount_].fee && bidFees != 0) + if (bidFees > 0 && winningBids[requestCount_].fee >= bidFees) revert LowerBidAlreadyExists(); uint256 transmitterCredits = getMaxFees(requestCount_); diff --git a/contracts/evmx/watcher/RequestHandler.sol b/contracts/evmx/watcher/RequestHandler.sol index 4a687eab..f88c703d 100644 --- a/contracts/evmx/watcher/RequestHandler.sol +++ b/contracts/evmx/watcher/RequestHandler.sol @@ -9,6 +9,7 @@ import "../interfaces/IAppGateway.sol"; import "../interfaces/IPromise.sol"; import "../interfaces/IRequestHandler.sol"; import "solady/auth/Ownable.sol"; +import "forge-std/console.sol"; /// @title RequestHandler /// @notice Contract that handles request processing and management, including request submission, batch processing, and request lifecycle management @@ -262,7 +263,7 @@ contract RequestHandler is AddressResolverUtil, Ownable, IRequestHandler { bytes32 payloadId = payloadIds[i]; // check needed for re-process, in case a payload is already executed by last transmitter - if (!_isPromiseResolved(_payloads[payloadId].asyncPromise)) continue; + if (_isPromiseResolved(_payloads[payloadId].asyncPromise)) continue; PayloadParams storage payloadParams = _payloads[payloadId]; (uint256 fees, uint256 deadline, bytes memory precompileData) = IPrecompile( diff --git a/contracts/evmx/watcher/Watcher.sol b/contracts/evmx/watcher/Watcher.sol index 82bd965d..db3ea41b 100644 --- a/contracts/evmx/watcher/Watcher.sol +++ b/contracts/evmx/watcher/Watcher.sol @@ -105,10 +105,12 @@ contract Watcher is Trigger { address consumeFrom, bytes memory onCompleteData ) internal returns (uint40 requestCount, address[] memory promiseList) { - // this check is to verify that msg.sender (app gateway base) belongs to correct app gateway address appGateway = msg.sender; + + // this check is to verify that msg.sender (app gateway base) belongs to correct app gateway if (appGateway != appGatewayTemp) revert InvalidAppGateway(); latestAsyncPromise = address(0); + appGatewayTemp = address(0); (requestCount, promiseList) = requestHandler__.submitRequest( maxFees, @@ -118,6 +120,7 @@ contract Watcher is Trigger { payloadQueue, onCompleteData ); + clearQueue(); } diff --git a/contracts/evmx/watcher/WatcherBase.sol b/contracts/evmx/watcher/WatcherBase.sol index 2e3108e8..9c3949a9 100644 --- a/contracts/evmx/watcher/WatcherBase.sol +++ b/contracts/evmx/watcher/WatcherBase.sol @@ -18,6 +18,16 @@ contract WatcherBase { _; } + modifier onlyRequestHandler() { + require(msg.sender == address(requestHandler__()), "Only RequestHandler can call"); + _; + } + + modifier onlyPromiseResolver() { + require(msg.sender == address(promiseResolver__()), "Only PromiseResolver can call"); + _; + } + /// @notice Sets the Watcher address /// @param watcher_ The address of the Watcher contract constructor(address watcher_) { diff --git a/contracts/evmx/watcher/precompiles/ReadPrecompile.sol b/contracts/evmx/watcher/precompiles/ReadPrecompile.sol index 7fb22c94..393ee63b 100644 --- a/contracts/evmx/watcher/precompiles/ReadPrecompile.sol +++ b/contracts/evmx/watcher/precompiles/ReadPrecompile.sol @@ -36,7 +36,7 @@ contract ReadPrecompile is IPrecompile, WatcherBase { address ) external view returns (bytes memory precompileData, uint256 estimatedFees) { if (queueParams_.transaction.target != address(0)) revert InvalidTarget(); - if (queueParams_.transaction.payload.length > 0) revert InvalidPayloadSize(); + if (queueParams_.transaction.payload.length == 0) revert InvalidPayloadSize(); // For read precompile, encode the payload parameters precompileData = abi.encode( @@ -53,9 +53,14 @@ contract ReadPrecompile is IPrecompile, WatcherBase { function handlePayload( address, PayloadParams calldata payloadParams - ) external onlyWatcher returns (uint256 fees, uint256 deadline, bytes memory) { + ) + external + onlyRequestHandler + returns (uint256 fees, uint256 deadline, bytes memory precompileData) + { fees = readFees; deadline = block.timestamp + expiryTime; + precompileData = payloadParams.precompileData; (Transaction memory transaction, uint256 readAtBlockNumber) = abi.decode( payloadParams.precompileData, @@ -64,7 +69,7 @@ contract ReadPrecompile is IPrecompile, WatcherBase { emit ReadRequested(transaction, readAtBlockNumber, payloadParams.payloadId); } - function resolvePayload(PayloadParams calldata payloadParams_) external {} + function resolvePayload(PayloadParams calldata payloadParams_) external onlyPromiseResolver {} function setFees(uint256 readFees_) external onlyWatcher { readFees = readFees_; diff --git a/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol b/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol index d62aa2a4..048f2314 100644 --- a/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol @@ -116,7 +116,11 @@ contract SchedulePrecompile is IPrecompile, WatcherBase { function handlePayload( address, PayloadParams calldata payloadParams - ) external onlyWatcher returns (uint256 fees, uint256 deadline, bytes memory precompileData) { + ) + external + onlyRequestHandler + returns (uint256 fees, uint256 deadline, bytes memory precompileData) + { uint256 delayInSeconds = abi.decode(payloadParams.precompileData, (uint256)); // expiryTime is very low, to account for infra delay @@ -129,7 +133,7 @@ contract SchedulePrecompile is IPrecompile, WatcherBase { emit ScheduleRequested(payloadParams.payloadId, executeAt, deadline); } - function resolvePayload(PayloadParams calldata payloadParams_) external { + function resolvePayload(PayloadParams calldata payloadParams_) external onlyPromiseResolver { if (payloadParams_.deadline > block.timestamp) revert ResolvingScheduleTooEarly(); emit ScheduleResolved(payloadParams_.payloadId); } diff --git a/contracts/evmx/watcher/precompiles/WritePrecompile.sol b/contracts/evmx/watcher/precompiles/WritePrecompile.sol index 1ccac9c4..c38815f1 100644 --- a/contracts/evmx/watcher/precompiles/WritePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/WritePrecompile.sol @@ -77,8 +77,8 @@ contract WritePrecompile is IPrecompile, WatcherBase, Ownable { ) revert MaxMsgValueLimitExceeded(); if ( - queueParams_.transaction.payload.length > 0 && - queueParams_.transaction.payload.length < PAYLOAD_SIZE_LIMIT + queueParams_.transaction.payload.length == 0 || + queueParams_.transaction.payload.length > PAYLOAD_SIZE_LIMIT ) { revert InvalidPayloadSize(); } @@ -120,7 +120,11 @@ contract WritePrecompile is IPrecompile, WatcherBase, Ownable { function handlePayload( address transmitter_, PayloadParams memory payloadParams - ) external onlyWatcher returns (uint256 fees, uint256 deadline, bytes memory) { + ) + external + onlyRequestHandler + returns (uint256 fees, uint256 deadline, bytes memory precompileData) + { fees = writeFees; deadline = block.timestamp + expiryTime; @@ -128,6 +132,7 @@ contract WritePrecompile is IPrecompile, WatcherBase, Ownable { payloadParams.precompileData, (address, Transaction, WriteFinality, uint256, uint256, address) ); + precompileData = payloadParams.precompileData; bytes32 prevBatchDigestHash = getPrevBatchDigestHash(payloadParams.batchCount); @@ -244,5 +249,7 @@ contract WritePrecompile is IPrecompile, WatcherBase, Ownable { emit ExpiryTimeSet(expiryTime_); } - function resolvePayload(PayloadParams calldata payloadParams_) external override {} + function resolvePayload( + PayloadParams calldata payloadParams_ + ) external override onlyPromiseResolver {} } diff --git a/test/Core.t.sol b/test/Core.t.sol new file mode 100644 index 00000000..09b0a672 --- /dev/null +++ b/test/Core.t.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import "./SetupTest.t.sol"; + +contract CoreTest is AppGatewayBaseSetup { + function testDeployAndSetup() public { + deploy(); + + vm.assertEq(address(arbConfig.feesPlug.socket__()), address(arbConfig.socket)); + vm.assertEq(address(optConfig.feesPlug.socket__()), address(optConfig.socket)); + + vm.assertEq(address(arbConfig.contractFactoryPlug.socket__()), address(arbConfig.socket)); + vm.assertEq(address(optConfig.contractFactoryPlug.socket__()), address(optConfig.socket)); + } +} diff --git a/test/SetupTest.t.sol b/test/SetupTest.t.sol index ebab5058..f1ea4516 100644 --- a/test/SetupTest.t.sol +++ b/test/SetupTest.t.sol @@ -57,12 +57,12 @@ contract SetupStore is Test { uint256 maxScheduleDelayInSeconds = 86400; uint256 maxMsgValueLimit = 1 ether; - uint256 writeFees = 0.01 ether; - uint256 readFees = 0.01 ether; - uint256 scheduleCallbackFees = 0.01 ether; - uint256 scheduleFeesPerSecond = 0.01 ether; - uint256 triggerFees = 0.01 ether; - uint256 socketFees = 0.01 ether; + uint256 writeFees = 10000; + uint256 readFees = 10000; + uint256 scheduleCallbackFees = 10000; + uint256 scheduleFeesPerSecond = 10000; + uint256 triggerFees = 10000; + uint256 socketFees = 0; uint256 public watcherNonce; uint256 public payloadIdCounter; @@ -102,7 +102,7 @@ contract DeploySetup is SetupStore { event Initialized(uint64 version); //////////////////////////////////// Setup //////////////////////////////////// - function deploy() internal { + function _deploy() internal { _deployEVMxCore(); // chain core contracts @@ -418,6 +418,13 @@ contract FeesSetup is DeploySetup { event CreditsUnwrapped(address indexed consumeFrom, uint256 amount); event CreditsTransferred(address indexed from, address indexed to, uint256 amount); + function deploy() internal { + _deploy(); + + depositNativeAndCredits(arbChainSlug, 100 ether, 100 ether, address(transmitterEOA)); + approveAppGateway(address(auctionManager), address(transmitterEOA), transmitterPrivateKey); + } + // mints test token and deposits the given native and credits to given `user_` function depositNativeAndCredits( uint32 chainSlug_, @@ -425,7 +432,6 @@ contract FeesSetup is DeploySetup { uint256 native_, address user_ ) internal { - console.log(user_); SocketContracts memory socketConfig = getSocketConfig(chainSlug_); TestUSDC token = socketConfig.testUSDC; @@ -456,7 +462,6 @@ contract FeesSetup is DeploySetup { vm.expectEmit(true, true, true, false); emit Deposited(chainSlug_, address(token), user_, credits_, native_); - // todo: try to call this with hoax watcher watcherMultiCall( address(feesManager), abi.encodeWithSelector( @@ -469,9 +474,6 @@ contract FeesSetup is DeploySetup { ) ); - // hoax(address(watcher)); - // feesManager.deposit(chainSlug_, address(token), user_, native_, credits_); - assertEq( feesManager.getAvailableCredits(user_), currentCredits + credits_, @@ -510,30 +512,34 @@ contract FeesSetup is DeploySetup { } contract AuctionSetup is FeesSetup { - uint256 public bidAmount = 100 ether; - event BidPlaced(uint40 requestCount, Bid bid); event AuctionStarted(uint40 requestCount); event AuctionEnded(uint40 requestCount, Bid winningBid); + function getBidAmount(uint40 requestCount) internal view returns (uint256) { + return watcher.getRequestParams(requestCount).requestFeesDetails.maxFees / 2; + } + function placeBid(uint40 requestCount) internal { + uint256 bidAmount = getBidAmount(requestCount); + bytes memory transmitterSignature = _createSignature( keccak256(abi.encode(address(auctionManager), evmxSlug, requestCount, bidAmount, "")), transmitterPrivateKey ); - vm.expectEmit(true, true, true, false); - emit AuctionStarted(requestCount); - if (auctionEndDelaySeconds == 0) { - vm.expectEmit(true, true, true, true); + vm.expectEmit(true, true, true, false); emit AuctionEnded( requestCount, - Bid({fee: bidAmount, transmitter: transmitterEOA, extraData: ""}) + Bid({fee: bidAmount, transmitter: transmitterEOA, extraData: bytes("")}) ); + } else { + vm.expectEmit(true, true, true, false); + emit AuctionStarted(requestCount); } - vm.expectEmit(true, true, true, true); + vm.expectEmit(true, true, true, false); emit BidPlaced( requestCount, Bid({transmitter: transmitterEOA, fee: bidAmount, extraData: bytes("")}) @@ -545,6 +551,8 @@ contract AuctionSetup is FeesSetup { if (auctionEndDelaySeconds == 0) return; // todo: handle other cases + + uint256 bidAmount = getBidAmount(requestCount_); bytes memory watcherSignature = _createSignature( keccak256(abi.encode(address(watcher), evmxSlug, requestCount_, bidAmount, "")), watcherPrivateKey @@ -582,7 +590,7 @@ contract WatcherSetup is AuctionSetup { ); event WriteProofUploaded(bytes32 indexed payloadId, bytes proof); - function deploy( + function executeDeploy( uint32 chainSlug_, IAppGateway appGateway_, bytes32[] memory contractIds_ @@ -600,8 +608,8 @@ contract WatcherSetup is AuctionSetup { // bids and executes schedule request if created for endAuction if (requestParams.writeCount != 0) bidAndEndAuction(requestCount); - for (uint i = 0; i < batches.length; i++) _processBatch(batches[i]); + for (uint i = 0; i < batches.length; i++) _processBatch(batches[i]); requestParams = requestHandler.getRequest(requestCount); assertEq(requestParams.requestTrackingParams.isRequestExecuted, true); } @@ -629,16 +637,16 @@ contract WatcherSetup is AuctionSetup { } if (success) { - _resolvePromise(promiseReturnData[0].payloadId, promiseReturnData[0].returnData); + _resolvePromise(promiseReturnData); } else { - // _markRevert(promiseReturnData); + _markRevert(promiseReturnData[0], true); } } } function _processRead( PayloadParams memory payloadParams - ) internal returns (bool success, PromiseReturnData memory promiseReturnData_) { + ) internal returns (bool success, PromiseReturnData memory promiseReturnData) { (Transaction memory transaction, ) = abi.decode( payloadParams.precompileData, (Transaction, uint256) @@ -646,7 +654,7 @@ contract WatcherSetup is AuctionSetup { bytes memory returnData; (success, returnData) = transaction.target.call(transaction.payload); - promiseReturnData_ = PromiseReturnData({ + promiseReturnData = PromiseReturnData({ maxCopyExceeded: false, payloadId: payloadParams.payloadId, returnData: returnData @@ -655,149 +663,158 @@ contract WatcherSetup is AuctionSetup { function _processWrite( PayloadParams memory payloadParams - ) internal returns (bool success, PromiseReturnData memory promiseReturnData_) { + ) internal returns (bool success, PromiseReturnData memory promiseReturnData) { + bytes32 payloadId = payloadParams.payloadId; + + ( + uint32 chainSlug, + address switchboard, + bytes32 digest, + DigestParams memory digestParams + ) = _validateAndGetDigest(payloadParams); + + bytes memory watcherProof = _uploadProof(payloadId, digest, switchboard, chainSlug); + + return + _executeWrite( + chainSlug, + switchboard, + digest, + digestParams, + payloadParams, + watcherProof, + _createSignature( + keccak256( + abi.encode(address(getSocketConfig(chainSlug).socket), chainSlug, payloadId) + ), + transmitterPrivateKey + ) + ); + } + + function _uploadProof( + bytes32 payloadId, + bytes32 digest, + address switchboard, + uint32 chainSlug + ) internal returns (bytes memory proof) { + proof = _createSignature( + keccak256(abi.encode(address(switchboard), chainSlug, digest)), + watcherPrivateKey + ); + watcherMultiCall( + address(writePrecompile), + abi.encodeWithSelector(WritePrecompile.uploadProof.selector, payloadId, proof) + ); + assertEq(writePrecompile.watcherProofs(payloadId), proof); + } + + function _validateAndGetDigest( + PayloadParams memory payloadParams + ) + internal + view + returns ( + uint32 chainSlug, + address switchboard, + bytes32 digest, + DigestParams memory digestParams + ) + { ( - address appGateway, + , Transaction memory transaction, - WriteFinality writeFinality, + , uint256 gasLimit, uint256 value, - address switchboard + address switchboard_ ) = abi.decode( payloadParams.precompileData, (address, Transaction, WriteFinality, uint256, uint256, address) ); - bytes32 payloadId = payloadParams.payloadId; + chainSlug = transaction.chainSlug; + switchboard = switchboard_; - SocketContracts memory socketConfig = getSocketConfig(transaction.chainSlug); - DigestParams memory digestParams_ = DigestParams( - address(socketConfig.socket), + bytes32 prevDigestsHash = writePrecompile.getPrevBatchDigestHash(payloadParams.batchCount); + digestParams = DigestParams( + address(getSocketConfig(transaction.chainSlug).socket), transmitterEOA, - payloadId, + payloadParams.payloadId, payloadParams.deadline, payloadParams.callType, gasLimit, value, transaction.payload, transaction.target, - encodeAppGatewayId(appGateway), - writePrecompile.getPrevBatchDigestHash(payloadParams.batchCount), + encodeAppGatewayId(payloadParams.appGateway), + prevDigestsHash, bytes("") ); - bytes32 digest = writePrecompile.getDigest(digestParams_); - bytes32 sigDigest = keccak256( - abi.encode(address(socketConfig.switchboard), socketConfig.chainSlug, digest) - ); - bytes memory proof = _createSignature(sigDigest, watcherPrivateKey); - watcherMultiCall( - address(writePrecompile), - abi.encodeWithSelector(WritePrecompile.uploadProof.selector, payloadId, proof) - ); - assertEq(writePrecompile.watcherProofs(payloadId), proof); - // _resolveAndExpectWriteProofRequested( - // payloadId, - // payloadParams, - // promiseReturnData_, - // - // ); + digest = writePrecompile.getDigest(digestParams); + assertEq(writePrecompile.digestHashes(payloadParams.payloadId), digest); } - function _uploadProofAndExecute( + function _executeWrite( + uint32 chainSlug, + address switchboard, + bytes32 digest, + DigestParams memory digestParams, PayloadParams memory payloadParams, bytes memory watcherProof, - bytes32 digest - ) internal returns (bool, bytes memory) { - // ( - // ExecuteParams memory params, - // SocketBatcher socketBatcher, - // , - // bytes memory transmitterSig, - // address refundAddress - // ) = _getExecuteParams(payloadParams); - // return - // socketBatcher.attestAndExecute( - // params, - // address(1), // todo: fix this socketConfig.switchboard, - // digest, - // watcherProof, - // transmitterSig, - // refundAddress - // ); - } - - function _resolveAndExpectWriteProofRequested(PayloadParams memory payloadParams) internal { - vm.expectEmit(false, false, false, false); - emit WriteProofRequested( - transmitterEOA, - writePrecompile.digestHashes(payloadParams.payloadId), - writePrecompile.getPrevBatchDigestHash(payloadParams.batchCount), - payloadParams.deadline, - payloadParams - ); - } - - function resolvePromises(bytes32[] memory payloadIds, bytes[] memory returnData) internal { - for (uint i = 0; i < payloadIds.length; i++) { - _resolvePromise(payloadIds[i], returnData[i]); - } - } - - //////////////////////////////////// Helpers //////////////////////////////////// - // function _getExecuteParams( - // PayloadParams memory payloadParams - // ) - // internal - // view - // returns ( - // ExecuteParams memory params, - // SocketBatcher socketBatcher, - // uint256 value, - // bytes memory transmitterSig, - // address refundAddress - // ) - // { - // RequestParams memory requestParams = watcher.getRequestParams(payloadParams.requestCount); - // // SocketContracts memory socketConfig = getSocketConfig(requestParams.chainSlug); - - // bytes32 transmitterDigest = keccak256( - // abi.encode(address(socketConfig.socket), payloadParams.payloadId) - // ); - // transmitterSig = _createSignature(transmitterDigest, transmitterPrivateKey); - // params = ExecuteParams({ - // callType: payloadParams.payloadHeader.getCallType(), - // deadline: payloadParams.deadline, - // gasLimit: payloadParams.gasLimit, - // value: payloadParams.value, - // payload: payloadParams.payload, - // target: payloadParams.target, - // requestCount: payloadParams.payloadHeader.getRequestCount(), - // batchCount: payloadParams.payloadHeader.getBatchCount(), - // payloadCount: payloadParams.payloadHeader.getPayloadCount(), - // prevDigestsHash: payloadParams.prevDigestsHash, - // extraData: bytes("") - // }); - - // value = payloadParams.value; - // socketBatcher = socketConfig.socketBatcher; - // refundAddress = transmitterEOA; - // } - - function _resolvePromise(bytes32 payloadId, bytes memory returnData) internal { - PromiseReturnData[] memory promiseReturnData = new PromiseReturnData[](1); - promiseReturnData[0] = PromiseReturnData({ + bytes memory transmitterSig + ) internal returns (bool success, PromiseReturnData memory promiseReturnData) { + bytes memory returnData; + (success, returnData) = getSocketConfig(chainSlug).socketBatcher.attestAndExecute( + ExecuteParams({ + callType: digestParams.callType, + deadline: digestParams.deadline, + gasLimit: digestParams.gasLimit, + value: digestParams.value, + payload: digestParams.payload, + target: digestParams.target, + requestCount: payloadParams.requestCount, + batchCount: payloadParams.batchCount, + payloadCount: payloadParams.payloadCount, + prevDigestsHash: digestParams.prevDigestsHash, + extraData: digestParams.extraData + }), + switchboard, + digest, + watcherProof, + transmitterSig, + transmitterEOA + ); + + promiseReturnData = PromiseReturnData({ maxCopyExceeded: false, - payloadId: payloadId, + payloadId: payloadParams.payloadId, returnData: returnData }); + } + function _resolvePromise(PromiseReturnData[] memory promiseReturnData) internal { watcherMultiCall( - address(watcher), + address(promiseResolver), abi.encodeWithSelector(PromiseResolver.resolvePromises.selector, promiseReturnData) ); } + function _markRevert( + PromiseReturnData memory promiseReturnData, + bool isRevertingOnchain_ + ) internal { + watcherMultiCall( + address(promiseResolver), + abi.encodeWithSelector( + PromiseResolver.markRevert.selector, + promiseReturnData, + isRevertingOnchain_ + ) + ); + } + function setupGatewayAndPlugs( uint32 chainSlug_, IAppGateway appGateway_, diff --git a/test/apps/Counter.t.sol b/test/apps/Counter.t.sol index 3c489c63..69754b21 100644 --- a/test/apps/Counter.t.sol +++ b/test/apps/Counter.t.sol @@ -17,36 +17,37 @@ contract CounterTest is AppGatewayBaseSetup { deploy(); counterGateway = new CounterAppGateway(address(addressResolver), feesAmount); - depositNativeAndCredits(arbChainSlug, 1 ether, 1 ether, address(counterGateway)); + depositNativeAndCredits(arbChainSlug, 1 ether, 0, address(counterGateway)); counterId = counterGateway.counter(); contractIds[0] = counterId; } function deployCounterApp(uint32 chainSlug) internal returns (uint40 requestCount) { - requestCount = deploy(chainSlug, counterGateway, contractIds); + counterGateway.deployContracts(chainSlug); + requestCount = executeDeploy(chainSlug, counterGateway, contractIds); } - function testCounterDeployment() external { + function testCounterDeployment1() external { deploySetup(); deployCounterApp(arbChainSlug); - (address onChain, address forwarder) = getOnChainAndForwarderAddresses( - arbChainSlug, - counterId, - counterGateway - ); - - assertEq( - IForwarder(forwarder).getChainSlug(), - arbChainSlug, - "Forwarder chainSlug should be correct" - ); - assertEq( - IForwarder(forwarder).getOnChainAddress(), - onChain, - "Forwarder onChainAddress should be correct" - ); + // (address onChain, address forwarder) = getOnChainAndForwarderAddresses( + // arbChainSlug, + // counterId, + // counterGateway + // ); + + // assertEq( + // IForwarder(forwarder).getChainSlug(), + // arbChainSlug, + // "Forwarder chainSlug should be correct" + // ); + // assertEq( + // IForwarder(forwarder).getOnChainAddress(), + // onChain, + // "Forwarder onChainAddress should be correct" + // ); } function testCounterDeploymentWithoutAsync() external { @@ -71,7 +72,7 @@ contract CounterTest is AppGatewayBaseSetup { address[] memory instances = new address[](1); instances[0] = arbCounterForwarder; counterGateway.incrementCounters(instances); - executeRequest(new bytes[](0)); + executeRequest(); assertEq(Counter(arbCounter).counter(), arbCounterBefore + 1); } @@ -104,7 +105,7 @@ contract CounterTest is AppGatewayBaseSetup { chains[0] = arbChainSlug; chains[1] = optChainSlug; - executeRequest(new bytes[](0)); + executeRequest(); assertEq(Counter(arbCounter).counter(), arbCounterBefore + 1); assertEq(Counter(optCounter).counter(), optCounterBefore + 1); } @@ -129,10 +130,10 @@ contract CounterTest is AppGatewayBaseSetup { counterGateway.readCounters(instances); - bytes[] memory readReturnData = new bytes[](2); - readReturnData[0] = abi.encode(10); - readReturnData[1] = abi.encode(10); + // bytes[] memory readReturnData = new bytes[](2); + // readReturnData[0] = abi.encode(10); + // readReturnData[1] = abi.encode(10); - executeRequest(readReturnData); + executeRequest(); } } diff --git a/test/apps/ParallelCounter.t.sol b/test/apps/ParallelCounter.t.sol index c3cd1c1d..f04a95ae 100644 --- a/test/apps/ParallelCounter.t.sol +++ b/test/apps/ParallelCounter.t.sol @@ -17,16 +17,17 @@ contract ParallelCounterTest is AppGatewayBaseSetup { deploy(); parallelCounterGateway = new CounterAppGateway(address(addressResolver), feesAmount); - depositNativeAndCredits(arbChainSlug, 1 ether, 1 ether, address(parallelCounterGateway)); - counterId1 = parallelCounterGateway.counter1(); + depositNativeAndCredits(arbChainSlug, 1 ether, 0, address(parallelCounterGateway)); + counterId2 = parallelCounterGateway.counter(); + counterId1 = parallelCounterGateway.counter1(); contractIds[0] = counterId1; contractIds[1] = counterId2; } function deployCounterApps(uint32[] memory chainSlugs) internal { parallelCounterGateway.deployMultiChainContracts(chainSlugs); - executeRequest(new bytes[](0)); + executeRequest(); } function testParallelCounterDeployment() external { diff --git a/test/apps/SuperToken.t.sol b/test/apps/SuperToken.t.sol index 3773c736..ff935afb 100644 --- a/test/apps/SuperToken.t.sol +++ b/test/apps/SuperToken.t.sol @@ -77,7 +77,7 @@ contract SuperTokenTest is AppGatewayBaseSetup { ); // Enable app gateways to do all operations in the Watcher: Read, Write and Schedule on EVMx // Watcher sets the limits for apps in this SOCKET protocol version - depositNativeAndCredits(arbChainSlug, 1 ether, 1 ether, address(superTokenApp)); + depositNativeAndCredits(arbChainSlug, 1 ether, 0, address(superTokenApp)); appContracts = AppContracts({ superTokenApp: superTokenApp, @@ -93,7 +93,7 @@ contract SuperTokenTest is AppGatewayBaseSetup { * - Correct setup of forwarder contracts for multi-chain communication */ function testContractDeployment() public { - deploy(arbChainSlug, IAppGateway(appContracts.superTokenApp), contractIds); + executeDeploy(arbChainSlug, IAppGateway(appContracts.superTokenApp), contractIds); (address onChain, address forwarder) = getOnChainAndForwarderAddresses( arbChainSlug, @@ -124,8 +124,8 @@ contract SuperTokenTest is AppGatewayBaseSetup { * @dev Deploys necessary contracts on both Arbitrum and Optimism chains */ function beforeTransfer() internal { - deploy(arbChainSlug, IAppGateway(appContracts.superTokenApp), contractIds); - deploy(optChainSlug, IAppGateway(appContracts.superTokenApp), contractIds); + executeDeploy(arbChainSlug, IAppGateway(appContracts.superTokenApp), contractIds); + executeDeploy(optChainSlug, IAppGateway(appContracts.superTokenApp), contractIds); } /** @@ -164,7 +164,7 @@ contract SuperTokenTest is AppGatewayBaseSetup { bytes memory encodedOrder = abi.encode(transferOrder); appContracts.superTokenApp.transfer(encodedOrder); - executeRequest(new bytes[](0)); + executeRequest(); assertEq( SuperToken(onChainArb).balanceOf(owner), From d0c7f3e34e14918a708651ce69b5230b5524970b Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Wed, 28 May 2025 13:53:07 +0530 Subject: [PATCH 068/130] fix: deploy tests --- contracts/evmx/watcher/RequestHandler.sol | 31 +++++++++++------ .../watcher/precompiles/ReadPrecompile.sol | 2 +- .../precompiles/SchedulePrecompile.sol | 2 +- .../watcher/precompiles/WritePrecompile.sol | 24 +++++++++---- contracts/protocol/SocketBatcher.sol | 2 +- test/SetupTest.t.sol | 30 ++++++++-------- test/apps/Counter.t.sol | 34 +++++++++---------- 7 files changed, 74 insertions(+), 51 deletions(-) diff --git a/contracts/evmx/watcher/RequestHandler.sol b/contracts/evmx/watcher/RequestHandler.sol index f88c703d..450d5acb 100644 --- a/contracts/evmx/watcher/RequestHandler.sol +++ b/contracts/evmx/watcher/RequestHandler.sol @@ -9,7 +9,6 @@ import "../interfaces/IAppGateway.sol"; import "../interfaces/IPromise.sol"; import "../interfaces/IRequestHandler.sol"; import "solady/auth/Ownable.sol"; -import "forge-std/console.sol"; /// @title RequestHandler /// @notice Contract that handles request processing and management, including request submission, batch processing, and request lifecycle management @@ -123,8 +122,13 @@ contract RequestHandler is AddressResolverUtil, Ownable, IRequestHandler { r.onCompleteData = onCompleteData_; CreateRequestResult memory result = _createRequest(queueParams_, appGateway_, requestCount); + + r.requestTrackingParams.currentBatchPayloadsLeft = _batchPayloadIds[ + r.requestTrackingParams.currentBatch + ].length; r.writeCount = result.writeCount; promiseList = result.promiseList; + if (result.totalEstimatedWatcherFees > maxFees_) revert InsufficientFees(); if (r.writeCount == 0) _processBatch(r.requestTrackingParams.currentBatch, r); @@ -190,9 +194,10 @@ contract RequestHandler is AddressResolverUtil, Ownable, IRequestHandler { _requestBatchIds[requestCount_].push(nextBatchCount); } - // get the switchboard address from the watcher precompile config - address switchboard = watcher__().configurations__().sockets( - queuePayloadParam.transaction.chainSlug + // get the switchboard address from the configurations + address switchboard = watcher__().configurations__().switchboards( + queuePayloadParam.transaction.chainSlug, + queuePayloadParam.switchboardType ); // process payload data and store @@ -317,17 +322,21 @@ contract RequestHandler is AddressResolverUtil, Ownable, IRequestHandler { RequestParams storage r = _requests[requestCount_]; PayloadParams storage payloadParams = _payloads[payloadId_]; - IPrecompile(precompiles[payloadParams.callType]).resolvePayload(payloadParams); - payloadParams.resolvedAt = block.timestamp; - if (r.requestTrackingParams.currentBatchPayloadsLeft != 0) return; - if (r.requestTrackingParams.payloadsRemaining == 0) { - r.requestTrackingParams.isRequestExecuted = true; + RequestTrackingParams storage trackingParams = r.requestTrackingParams; + trackingParams.currentBatchPayloadsLeft--; + trackingParams.payloadsRemaining--; + + IPrecompile(precompiles[payloadParams.callType]).resolvePayload(payloadParams); + + if (trackingParams.currentBatchPayloadsLeft != 0) return; + if (trackingParams.payloadsRemaining == 0) { + trackingParams.isRequestExecuted = true; _settleRequest(requestCount_, r); } else { - r.requestTrackingParams.currentBatch++; - _processBatch(r.requestTrackingParams.currentBatch, r); + trackingParams.currentBatch++; + _processBatch(trackingParams.currentBatch, r); } } diff --git a/contracts/evmx/watcher/precompiles/ReadPrecompile.sol b/contracts/evmx/watcher/precompiles/ReadPrecompile.sol index 393ee63b..4cd6489b 100644 --- a/contracts/evmx/watcher/precompiles/ReadPrecompile.sol +++ b/contracts/evmx/watcher/precompiles/ReadPrecompile.sol @@ -69,7 +69,7 @@ contract ReadPrecompile is IPrecompile, WatcherBase { emit ReadRequested(transaction, readAtBlockNumber, payloadParams.payloadId); } - function resolvePayload(PayloadParams calldata payloadParams_) external onlyPromiseResolver {} + function resolvePayload(PayloadParams calldata payloadParams_) external onlyRequestHandler {} function setFees(uint256 readFees_) external onlyWatcher { readFees = readFees_; diff --git a/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol b/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol index 048f2314..042d94ee 100644 --- a/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol @@ -133,7 +133,7 @@ contract SchedulePrecompile is IPrecompile, WatcherBase { emit ScheduleRequested(payloadParams.payloadId, executeAt, deadline); } - function resolvePayload(PayloadParams calldata payloadParams_) external onlyPromiseResolver { + function resolvePayload(PayloadParams calldata payloadParams_) external onlyRequestHandler { if (payloadParams_.deadline > block.timestamp) revert ResolvingScheduleTooEarly(); emit ScheduleResolved(payloadParams_.payloadId); } diff --git a/contracts/evmx/watcher/precompiles/WritePrecompile.sol b/contracts/evmx/watcher/precompiles/WritePrecompile.sol index c38815f1..eedb3e89 100644 --- a/contracts/evmx/watcher/precompiles/WritePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/WritePrecompile.sol @@ -97,6 +97,11 @@ contract WritePrecompile is IPrecompile, WatcherBase, Ownable { ); } + // todo: can be used to set the default gas limit for each chain + if (queueParams_.overrideParams.gasLimit == 0) { + queueParams_.overrideParams.gasLimit = 1000000; + } + // For write precompile, encode the payload parameters precompileData = abi.encode( appGateway_, @@ -128,10 +133,17 @@ contract WritePrecompile is IPrecompile, WatcherBase, Ownable { fees = writeFees; deadline = block.timestamp + expiryTime; - (, Transaction memory transaction, , uint256 gasLimit, uint256 value, ) = abi.decode( - payloadParams.precompileData, - (address, Transaction, WriteFinality, uint256, uint256, address) - ); + ( + address appGateway, + Transaction memory transaction, + , + uint256 gasLimit, + uint256 value, + + ) = abi.decode( + payloadParams.precompileData, + (address, Transaction, WriteFinality, uint256, uint256, address) + ); precompileData = payloadParams.precompileData; bytes32 prevBatchDigestHash = getPrevBatchDigestHash(payloadParams.batchCount); @@ -147,7 +159,7 @@ contract WritePrecompile is IPrecompile, WatcherBase, Ownable { value, transaction.payload, transaction.target, - encodeAppGatewayId(payloadParams.appGateway), + encodeAppGatewayId(appGateway), prevBatchDigestHash, bytes("") ); @@ -251,5 +263,5 @@ contract WritePrecompile is IPrecompile, WatcherBase, Ownable { function resolvePayload( PayloadParams calldata payloadParams_ - ) external override onlyPromiseResolver {} + ) external override onlyRequestHandler {} } diff --git a/contracts/protocol/SocketBatcher.sol b/contracts/protocol/SocketBatcher.sol index e8313f08..1013af2f 100644 --- a/contracts/protocol/SocketBatcher.sol +++ b/contracts/protocol/SocketBatcher.sol @@ -49,7 +49,7 @@ contract SocketBatcher is ISocketBatcher, Ownable { TransmissionParams({ transmitterSignature: transmitterSignature_, socketFees: 0, - extraData: "", + extraData: executeParams_.extraData, refundAddress: refundAddress_ }) ); diff --git a/test/SetupTest.t.sol b/test/SetupTest.t.sol index f1ea4516..a44dfa96 100644 --- a/test/SetupTest.t.sol +++ b/test/SetupTest.t.sol @@ -172,7 +172,7 @@ contract DeploySetup is SetupStore { switchboard: address(optConfig.switchboard) }) }); - configs[0] = AppGatewayConfig({ + configs[2] = AppGatewayConfig({ chainSlug: arbChainSlug, plug: address(arbConfig.contractFactoryPlug), plugConfig: PlugConfig({ @@ -180,7 +180,7 @@ contract DeploySetup is SetupStore { switchboard: address(arbConfig.switchboard) }) }); - configs[1] = AppGatewayConfig({ + configs[3] = AppGatewayConfig({ chainSlug: optChainSlug, plug: address(optConfig.contractFactoryPlug), plugConfig: PlugConfig({ @@ -230,7 +230,7 @@ contract DeploySetup is SetupStore { feesPlug.whitelistToken(address(socketConfig.testUSDC)); feesPlug.connectSocket( - encodeAppGatewayId(address(auctionManager)), + encodeAppGatewayId(address(feesManager)), address(socket), address(switchboard) ); @@ -682,13 +682,7 @@ contract WatcherSetup is AuctionSetup { digest, digestParams, payloadParams, - watcherProof, - _createSignature( - keccak256( - abi.encode(address(getSocketConfig(chainSlug).socket), chainSlug, payloadId) - ), - transmitterPrivateKey - ) + watcherProof ); } @@ -702,6 +696,9 @@ contract WatcherSetup is AuctionSetup { keccak256(abi.encode(address(switchboard), chainSlug, digest)), watcherPrivateKey ); + + vm.expectEmit(true, true, true, false); + emit WriteProofUploaded(payloadId, proof); watcherMultiCall( address(writePrecompile), abi.encodeWithSelector(WritePrecompile.uploadProof.selector, payloadId, proof) @@ -722,7 +719,7 @@ contract WatcherSetup is AuctionSetup { ) { ( - , + address appGateway, Transaction memory transaction, , uint256 gasLimit, @@ -747,7 +744,7 @@ contract WatcherSetup is AuctionSetup { value, transaction.payload, transaction.target, - encodeAppGatewayId(payloadParams.appGateway), + encodeAppGatewayId(appGateway), prevDigestsHash, bytes("") ); @@ -762,9 +759,14 @@ contract WatcherSetup is AuctionSetup { bytes32 digest, DigestParams memory digestParams, PayloadParams memory payloadParams, - bytes memory watcherProof, - bytes memory transmitterSig + bytes memory watcherProof ) internal returns (bool success, PromiseReturnData memory promiseReturnData) { + bytes memory transmitterSig = _createSignature( + keccak256( + abi.encode(address(getSocketConfig(chainSlug).socket), payloadParams.payloadId) + ), + transmitterPrivateKey + ); bytes memory returnData; (success, returnData) = getSocketConfig(chainSlug).socketBatcher.attestAndExecute( ExecuteParams({ diff --git a/test/apps/Counter.t.sol b/test/apps/Counter.t.sol index 69754b21..c2e2b1e7 100644 --- a/test/apps/Counter.t.sol +++ b/test/apps/Counter.t.sol @@ -28,26 +28,26 @@ contract CounterTest is AppGatewayBaseSetup { requestCount = executeDeploy(chainSlug, counterGateway, contractIds); } - function testCounterDeployment1() external { + function testCounterDeployment() external { deploySetup(); deployCounterApp(arbChainSlug); - // (address onChain, address forwarder) = getOnChainAndForwarderAddresses( - // arbChainSlug, - // counterId, - // counterGateway - // ); - - // assertEq( - // IForwarder(forwarder).getChainSlug(), - // arbChainSlug, - // "Forwarder chainSlug should be correct" - // ); - // assertEq( - // IForwarder(forwarder).getOnChainAddress(), - // onChain, - // "Forwarder onChainAddress should be correct" - // ); + (address onChain, address forwarder) = getOnChainAndForwarderAddresses( + arbChainSlug, + counterId, + counterGateway + ); + + assertEq( + IForwarder(forwarder).getChainSlug(), + arbChainSlug, + "Forwarder chainSlug should be correct" + ); + assertEq( + IForwarder(forwarder).getOnChainAddress(), + onChain, + "Forwarder onChainAddress should be correct" + ); } function testCounterDeploymentWithoutAsync() external { From 3b5e2183a5bd981dbc770d760a60d7b628a83712 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Wed, 28 May 2025 14:15:19 +0530 Subject: [PATCH 069/130] fix: build --- test-old/FeesTest.t.sol | 121 ------------------ test/FeesTest.t.sol | 105 +++++++++++++++ {test-old => test}/SocketFeeManager.t.sol | 17 ++- .../Inbox.t.sol => test/TriggerTest.t.sol | 60 +++++---- test/{Core.t.sol => Watcher.t.sol} | 4 +- 5 files changed, 144 insertions(+), 163 deletions(-) delete mode 100644 test-old/FeesTest.t.sol create mode 100644 test/FeesTest.t.sol rename {test-old => test}/SocketFeeManager.t.sol (90%) rename test-old/Inbox.t.sol => test/TriggerTest.t.sol (62%) rename test/{Core.t.sol => Watcher.t.sol} (84%) diff --git a/test-old/FeesTest.t.sol b/test-old/FeesTest.t.sol deleted file mode 100644 index 323b3f7d..00000000 --- a/test-old/FeesTest.t.sol +++ /dev/null @@ -1,121 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -pragma solidity ^0.8.21; - -import "./DeliveryHelper.t.sol"; -import {Counter} from "./apps/app-gateways/counter/Counter.sol"; -import {CounterAppGateway} from "./apps/app-gateways/counter/CounterAppGateway.sol"; - -contract FeesTest is DeliveryHelperTest { - uint256 constant depositAmount = 1 ether; - uint256 constant feesAmount = 0.01 ether; - address receiver = address(uint160(c++)); - address user = address(uint160(c++)); - uint32 feesChainSlug = arbChainSlug; - SocketContracts feesConfig; - - CounterAppGateway counterGateway; - - function setUp() public { - setUpDeliveryHelper(); - feesConfig = getSocketConfig(feesChainSlug); - - counterGateway = new CounterAppGateway(address(addressResolver), feesAmount); - depositUSDCFees( - address(counterGateway), - OnChainFees({ - chainSlug: feesChainSlug, - token: address(feesConfig.feesTokenUSDC), - amount: depositAmount - }) - ); - - bytes32[] memory contractIds = new bytes32[](1); - contractIds[0] = counterGateway.counter(); - _deploy(feesChainSlug, IAppGateway(counterGateway), contractIds); - } - - function testWithdrawTransmitterFees() public { - uint256 initialFeesPlugBalance = feesConfig.feesTokenUSDC.balanceOf( - address(feesConfig.feesPlug) - ); - - assertEq( - initialFeesPlugBalance, - feesConfig.feesTokenUSDC.balanceOf(address(feesConfig.feesPlug)), - "FeesPlug Balance should be correct" - ); - - uint256 transmitterReceiverBalanceBefore = feesConfig.feesTokenUSDC.balanceOf(receiver); - uint256 withdrawAmount = feesManager.getMaxCreditsAvailableForWithdraw(transmitterEOA); - vm.startPrank(transmitterEOA); - uint40 requestCount = deliveryHelper.withdrawTransmitterFees( - feesChainSlug, - address(feesConfig.feesTokenUSDC), - address(receiver), - withdrawAmount - ); - vm.stopPrank(); - uint40[] memory batches = watcherPrecompile.getBatches(requestCount); - _processBatch(batches[0], new bytes[](0), 0, false); - assertEq( - transmitterReceiverBalanceBefore + withdrawAmount, - feesConfig.feesTokenUSDC.balanceOf(receiver), - "Transmitter Balance should be correct" - ); - assertEq( - initialFeesPlugBalance - withdrawAmount, - feesConfig.feesTokenUSDC.balanceOf(address(feesConfig.feesPlug)), - "FeesPlug Balance should be correct" - ); - } - - function testWithdrawFeeTokensAppGateway() public { - uint256 receiverBalanceBefore = feesConfig.feesTokenUSDC.balanceOf(receiver); - uint256 withdrawAmount = 0.5 ether; - - counterGateway.withdrawFeeTokens( - feesChainSlug, - address(feesConfig.feesTokenUSDC), - withdrawAmount, - receiver - ); - executeRequest(new bytes[](0)); - - assertEq( - receiverBalanceBefore + withdrawAmount, - feesConfig.feesTokenUSDC.balanceOf(receiver), - "Receiver Balance should be correct" - ); - } - - function testWithdrawFeeTokensUser() public { - depositUSDCFees( - user, - OnChainFees({ - chainSlug: feesChainSlug, - token: address(feesConfig.feesTokenUSDC), - amount: depositAmount - }) - ); - - uint256 receiverBalanceBefore = feesConfig.feesTokenUSDC.balanceOf(user); - uint256 withdrawAmount = 0.5 ether; - - vm.prank(user); - deliveryHelper.withdrawTo( - feesChainSlug, - address(feesConfig.feesTokenUSDC), - withdrawAmount, - user, - address(auctionManager), - maxFees - ); - executeRequest(new bytes[](0)); - - assertEq( - receiverBalanceBefore + withdrawAmount, - feesConfig.feesTokenUSDC.balanceOf(user), - "Receiver Balance should be correct" - ); - } -} diff --git a/test/FeesTest.t.sol b/test/FeesTest.t.sol new file mode 100644 index 00000000..61cfe64e --- /dev/null +++ b/test/FeesTest.t.sol @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import "./apps/Counter.t.sol"; +import "./SetupTest.t.sol"; + +contract FeesTest is AppGatewayBaseSetup { + uint256 constant depositAmount = 1 ether; + uint256 constant feesAmount = 0.01 ether; + address receiver = address(uint160(c++)); + address user = address(uint160(c++)); + uint32 feesChainSlug = arbChainSlug; + SocketContracts feesConfig; + + CounterAppGateway counterGateway; + + function setUp() public { + deploy(); + feesConfig = getSocketConfig(feesChainSlug); + + counterGateway = new CounterAppGateway(address(addressResolver), feesAmount); + depositNativeAndCredits(feesChainSlug, 1 ether, 0, address(counterGateway)); + + bytes32[] memory contractIds = new bytes32[](1); + contractIds[0] = counterGateway.counter(); + executeDeploy(feesChainSlug, IAppGateway(counterGateway), contractIds); + } + + function testWithdrawTransmitterFees() public { + uint256 initialFeesPlugBalance = address(feesConfig.feesPlug).balance; + + assertEq( + initialFeesPlugBalance, + address(feesConfig.feesPlug).balance, + "FeesPlug Balance should be correct" + ); + + uint256 transmitterReceiverBalanceBefore = address(receiver).balance; + uint256 withdrawAmount = feesManager.getAvailableCredits(transmitterEOA); + vm.startPrank(transmitterEOA); + feesManager.withdrawCredits( + feesChainSlug, + address(feesConfig.testUSDC), + withdrawAmount, + feesAmount, + address(receiver) + ); + vm.stopPrank(); + executeRequest(); + + assertEq( + transmitterReceiverBalanceBefore + withdrawAmount, + feesConfig.testUSDC.balanceOf(receiver), + "Transmitter Balance should be correct" + ); + assertEq( + initialFeesPlugBalance - withdrawAmount, + feesConfig.testUSDC.balanceOf(address(feesConfig.feesPlug)), + "FeesPlug Balance should be correct" + ); + } + + function testWithdrawFeeTokensAppGateway() public { + uint256 receiverBalanceBefore = feesConfig.testUSDC.balanceOf(receiver); + uint256 withdrawAmount = 0.5 ether; + + counterGateway.withdrawCredits( + feesChainSlug, + address(feesConfig.testUSDC), + withdrawAmount, + feesAmount, + receiver + ); + executeRequest(); + + assertEq( + receiverBalanceBefore + withdrawAmount, + feesConfig.testUSDC.balanceOf(receiver), + "Receiver Balance should be correct" + ); + } + + function testWithdrawFeeTokensUser() public { + depositNativeAndCredits(feesChainSlug, 1 ether, 0, user); + + uint256 receiverBalanceBefore = feesConfig.testUSDC.balanceOf(user); + uint256 withdrawAmount = 0.5 ether; + + vm.prank(user); + feesManager.withdrawCredits( + feesChainSlug, + address(feesConfig.testUSDC), + withdrawAmount, + feesAmount, + address(receiver) + ); + executeRequest(); + + assertEq( + receiverBalanceBefore + withdrawAmount, + feesConfig.testUSDC.balanceOf(user), + "Receiver Balance should be correct" + ); + } +} diff --git a/test-old/SocketFeeManager.t.sol b/test/SocketFeeManager.t.sol similarity index 90% rename from test-old/SocketFeeManager.t.sol rename to test/SocketFeeManager.t.sol index 15dd67bf..8c924951 100644 --- a/test-old/SocketFeeManager.t.sol +++ b/test/SocketFeeManager.t.sol @@ -1,18 +1,17 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import {CounterAppGateway} from "./apps/app-gateways/counter/CounterAppGateway.sol"; -import {Counter} from "./apps/app-gateways/counter/Counter.sol"; -import "./SetupTest.t.sol"; import {SocketFeeManager} from "../contracts/protocol/SocketFeeManager.sol"; import {MockFastSwitchboard} from "./mock/MockFastSwitchboard.sol"; -import {ExecuteParams, TransmissionParams} from "../contracts/utils/common/Structs.sol"; -import {GOVERNANCE_ROLE, RESCUE_ROLE} from "../contracts/utils/common/AccessRoles.sol"; -import {Test} from "forge-std/Test.sol"; +import "./SetupTest.t.sol"; +import "./apps/Counter.t.sol"; -contract SocketFeeManagerTest is SetupTest { +contract SocketFeeManagerTest is AppGatewayBaseSetup { Counter public counter; - address public gateway = address(5); + + address public owner = address(uint160(c++)); + address public gateway = address(uint160(c++)); + MockFastSwitchboard public mockSwitchboard; Socket public socket; SocketFeeManager public socketFeeManager; @@ -26,7 +25,7 @@ contract SocketFeeManagerTest is SetupTest { mockSwitchboard.registerSwitchboard(); counter = new Counter(); - counter.initSocket(_encodeAppGatewayId(gateway), address(socket), address(mockSwitchboard)); + counter.initSocket(encodeAppGatewayId(gateway), address(socket), address(mockSwitchboard)); } function testSuccessfulExecutionWithFeeManagerNotSet() public { diff --git a/test-old/Inbox.t.sol b/test/TriggerTest.t.sol similarity index 62% rename from test-old/Inbox.t.sol rename to test/TriggerTest.t.sol index c9306913..59005314 100644 --- a/test-old/Inbox.t.sol +++ b/test/TriggerTest.t.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import {CounterAppGateway} from "./apps/app-gateways/counter/CounterAppGateway.sol"; -import {Counter} from "./apps/app-gateways/counter/Counter.sol"; -import "./DeliveryHelper.t.sol"; +import {CounterAppGateway} from "./apps/Counter.t.sol"; +import {Counter} from "./apps/Counter.t.sol"; +import "./SetupTest.t.sol"; -contract TriggerTest is DeliveryHelperTest { +contract TriggerTest is AppGatewayBaseSetup { uint256 constant feesAmount = 0.01 ether; CounterAppGateway public gateway; Counter public counter; @@ -21,7 +21,7 @@ contract TriggerTest is DeliveryHelperTest { function setUp() public { // Setup core test infrastructure - setUpDeliveryHelper(); + deploy(); // Deploy the counter contract counter = new Counter(); @@ -32,42 +32,40 @@ contract TriggerTest is DeliveryHelperTest { // Connect the counter to the gateway and socket counter.initSocket( - _encodeAppGatewayId(address(gateway)), + encodeAppGatewayId(address(gateway)), address(arbConfig.socket), address(arbConfig.switchboard) ); // Setup gateway config for the watcher - AppGatewayConfig[] memory gateways = new AppGatewayConfig[](1); - gateways[0] = AppGatewayConfig({ - plug: address(counter), + AppGatewayConfig[] memory configs = new AppGatewayConfig[](1); + configs[0] = AppGatewayConfig({ chainSlug: arbChainSlug, - appGatewayId: _encodeAppGatewayId(address(gateway)), - switchboard: address(arbConfig.switchboard) + plug: address(counter), + plugConfig: PlugConfig({ + appGatewayId: encodeAppGatewayId(address(gateway)), + switchboard: address(arbConfig.switchboard) + }) }); - bytes memory watcherSignature = _createWatcherSignature( - address(watcherPrecompileConfig), - abi.encode(IWatcherPrecompileConfig.setAppGateways.selector, gateways) + watcherMultiCall( + address(configurations), + abi.encodeWithSelector(Configurations.setPlugConfigs.selector, configs) ); - watcherPrecompileConfig.setAppGateways(gateways, signatureNonce++, watcherSignature); - hoax(watcherEOA); - watcherPrecompileConfig.setIsValidPlug(arbChainSlug, address(counter), true); + configurations.setIsValidPlug(true, arbChainSlug, address(counter)); } function testIncrementAfterTrigger() public { // Initial counter value should be 0 assertEq(gateway.counterVal(), 0, "Initial gateway counter should be 0"); - depositUSDCFees( - address(gateway), - OnChainFees({ - chainSlug: arbChainSlug, - token: address(arbConfig.feesTokenUSDC), - amount: 1 ether - }) - ); + depositNativeAndCredits(arbChainSlug, 1 ether, 0, address(gateway)); + + bytes32[] memory contractIds = new bytes32[](1); + contractIds[0] = gateway.counter(); + executeDeploy(arbChainSlug, IAppGateway(gateway), contractIds); + // Simulate a message from another chain through the watcher uint256 incrementValue = 5; bytes32 triggerId = _encodeTriggerId(address(arbConfig.socket), arbChainSlug); @@ -79,7 +77,7 @@ contract TriggerTest is DeliveryHelperTest { vm.expectEmit(true, true, true, true); emit AppGatewayCallRequested( triggerId, - _encodeAppGatewayId(address(gateway)), + encodeAppGatewayId(address(gateway)), address(arbConfig.switchboard), address(counter), bytes(""), @@ -91,17 +89,17 @@ contract TriggerTest is DeliveryHelperTest { params[0] = TriggerParams({ triggerId: triggerId, chainSlug: arbChainSlug, - appGatewayId: _encodeAppGatewayId(address(gateway)), + appGatewayId: encodeAppGatewayId(address(gateway)), plug: address(counter), payload: payload, overrides: bytes("") }); - bytes memory watcherSignature = _createWatcherSignature( - address(watcherPrecompile), - abi.encode(IWatcherPrecompile.callAppGateways.selector, params) + watcherMultiCall( + address(watcher), + abi.encodeWithSelector(Watcher.callAppGateways.selector, params) ); - watcherPrecompile.callAppGateways(params, signatureNonce++, watcherSignature); + // Check counter was incremented assertEq(gateway.counterVal(), incrementValue, "Gateway counter should be incremented"); } diff --git a/test/Core.t.sol b/test/Watcher.t.sol similarity index 84% rename from test/Core.t.sol rename to test/Watcher.t.sol index 09b0a672..bc8eb07b 100644 --- a/test/Core.t.sol +++ b/test/Watcher.t.sol @@ -3,8 +3,8 @@ pragma solidity ^0.8.21; import "./SetupTest.t.sol"; -contract CoreTest is AppGatewayBaseSetup { - function testDeployAndSetup() public { +contract WatcherTest is AppGatewayBaseSetup { + function testWatcherDeployment() public { deploy(); vm.assertEq(address(arbConfig.feesPlug.socket__()), address(arbConfig.socket)); From 04d4898fbd2a1447afe4ef484f30bcdbb7fe7df4 Mon Sep 17 00:00:00 2001 From: Akash Date: Wed, 28 May 2025 15:03:03 +0530 Subject: [PATCH 070/130] feat: added simulator support, updated types, events --- contracts/evmx/watcher/PromiseResolver.sol | 4 +- contracts/protocol/Socket.sol | 1 - contracts/protocol/SocketUtils.sol | 47 ++++++++++++++++++++++ contracts/utils/common/Structs.sol | 2 +- package.json | 2 +- src/enums.ts | 39 ++++++++++-------- src/events.ts | 15 ++++--- src/types.ts | 7 ++-- 8 files changed, 88 insertions(+), 29 deletions(-) diff --git a/contracts/evmx/watcher/PromiseResolver.sol b/contracts/evmx/watcher/PromiseResolver.sol index f0f9a5a2..251f4906 100644 --- a/contracts/evmx/watcher/PromiseResolver.sol +++ b/contracts/evmx/watcher/PromiseResolver.sol @@ -52,7 +52,7 @@ contract PromiseResolver is IPromiseResolver, WatcherBase { if (asyncPromise != address(0)) { success = IPromise(asyncPromise).markResolved( - resolvedPromise_.maxCopyExceeded, + resolvedPromise_.exceededMaxCopy, resolvedPromise_.payloadId, resolvedPromise_.returnData ); @@ -87,7 +87,7 @@ contract PromiseResolver is IPromiseResolver, WatcherBase { // marks the promise as onchain reverting if the request is reverting onchain if (isRevertingOnchain_ && payloadParams.asyncPromise != address(0)) IPromise(payloadParams.asyncPromise).markOnchainRevert( - resolvedPromise_.maxCopyExceeded, + resolvedPromise_.exceededMaxCopy, resolvedPromise_.payloadId, resolvedPromise_.returnData ); diff --git a/contracts/protocol/Socket.sol b/contracts/protocol/Socket.sol index 0bbe472a..0ce73560 100644 --- a/contracts/protocol/Socket.sol +++ b/contracts/protocol/Socket.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import {LibCall} from "solady/utils/LibCall.sol"; import "./SocketUtils.sol"; import {WRITE} from "../utils/common/Constants.sol"; import {createPayloadId} from "../utils/common/IdUtils.sol"; diff --git a/contracts/protocol/SocketUtils.sol b/contracts/protocol/SocketUtils.sol index eb4860ed..f19c1142 100644 --- a/contracts/protocol/SocketUtils.sol +++ b/contracts/protocol/SocketUtils.sol @@ -4,16 +4,29 @@ pragma solidity ^0.8.21; import {ECDSA} from "solady/utils/ECDSA.sol"; import "../utils/RescueFundsLib.sol"; import "./SocketConfig.sol"; +import {LibCall} from "solady/utils/LibCall.sol"; /** * @title SocketUtils * @notice Utility functions for socket */ abstract contract SocketUtils is SocketConfig { + using LibCall for address; + //////////////////////////////////////////////////////////// ////////////////////// State Vars ////////////////////////// //////////////////////////////////////////////////////////// + struct SimulateParams { + address target; + uint256 value; + uint256 gasLimit; + bytes payload; + } + + + address public constant OFF_CHAIN_CALLER = address(0xDEAD); + // Version string for this socket instance bytes32 public immutable version; // ChainSlug for this deployed socket instance @@ -24,6 +37,15 @@ abstract contract SocketUtils is SocketConfig { // @notice counter for trigger id uint64 public triggerCounter; + error OnlyOffChain(); + error SimulationFailed(); + + modifier onlyOffChain() { + if (msg.sender != OFF_CHAIN_CALLER) revert OnlyOffChain(); + _; + } + + /* * @notice constructor for creating a new Socket contract instance. * @param chainSlug_ The unique identifier of the chain this socket is deployed on. @@ -94,6 +116,31 @@ abstract contract SocketUtils is SocketConfig { return bytes32(triggerPrefix | triggerCounter++); } + + struct SimulationResult { + bool success; + bytes returnData; + bool exceededMaxCopy; + } + + function simulate( + SimulateParams[] calldata params + ) external payable onlyOffChain returns (SimulationResult[] memory) { + SimulationResult[] memory results = new SimulationResult[](params.length); + + for (uint256 i = 0; i < params.length; i++) { + (bool success, bool exceededMaxCopy, bytes memory returnData) = params[i].target.tryCall( + params[i].value, + params[i].gasLimit, + maxCopyBytes, + params[i].payload + ); + results[i] = SimulationResult(success, returnData, exceededMaxCopy); + } + + return results; + } + ////////////////////////////////////////////// //////////// Rescue role actions //////////// ///////////////////////////////////////////// diff --git a/contracts/utils/common/Structs.sol b/contracts/utils/common/Structs.sol index c99d7ee5..6a45dbfd 100644 --- a/contracts/utils/common/Structs.sol +++ b/contracts/utils/common/Structs.sol @@ -70,7 +70,7 @@ struct TriggerParams { bytes payload; } struct PromiseReturnData { - bool maxCopyExceeded; + bool exceededMaxCopy; bytes32 payloadId; bytes returnData; } diff --git a/package.json b/package.json index edac1f42..2df9297e 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "publishConfig": { "access": "public" }, - "version": "1.1.15-solana-test.1", + "version": "1.1.17", "description": "socket protocol", "scripts": { "build": "yarn abi && tsc --project lib.tsconfig.json", diff --git a/src/enums.ts b/src/enums.ts index ad2efefb..2802846e 100644 --- a/src/enums.ts +++ b/src/enums.ts @@ -11,34 +11,40 @@ export enum Events { ExecutionFailed = "ExecutionFailed", PlugConnected = "PlugConnected", AppGatewayCallRequested = "AppGatewayCallRequested", - AppGatewayCallFailed = "AppGatewayCallFailed", - + // FeesPlug FeesDeposited = "FeesDeposited", - + // Watcher CalledAppGateway = "CalledAppGateway", - QueryRequested = "QueryRequested", - FinalizeRequested = "FinalizeRequested", + AppGatewayCallFailed = "AppGatewayCallFailed", + + // PromiseResolver PromiseResolved = "PromiseResolved", PromiseNotResolved = "PromiseNotResolved", - TimeoutRequested = "TimeoutRequested", - TimeoutResolved = "TimeoutResolved", - RequestSubmitted = "RequestSubmitted", - Finalized = "Finalized", MarkedRevert = "MarkedRevert", - ReadRequested = "ReadRequested", + + + // RequestHandler + RequestSubmitted = "RequestSubmitted", + RequestCancelled = "RequestCancelled", + FeesIncreased = "FeesIncreased", + + // WritePrecompile WriteProofRequested = "WriteProofRequested", WriteProofUploaded = "WriteProofUploaded", + + // ReadPrecompile + ReadRequested = "ReadRequested", + + // SchedulePrecompile + ScheduleRequested = "ScheduleRequested", + ScheduleResolved = "ScheduleResolved", + + // AuctionManager AuctionEnded = "AuctionEnded", AuctionRestarted = "AuctionRestarted", - - // DeliveryHelper - PayloadSubmitted = "PayloadSubmitted", - PayloadAsyncRequested = "PayloadAsyncRequested", - FeesIncreased = "FeesIncreased", - RequestCancelled = "RequestCancelled", } export enum Contracts { @@ -57,6 +63,7 @@ export enum Contracts { FeesManager = "FeesManager", WritePrecompile = "WritePrecompile", ReadPrecompile = "ReadPrecompile", + SchedulePrecompile = "SchedulePrecompile", } export enum CallTypeNames { diff --git a/src/events.ts b/src/events.ts index d9649775..27bc802a 100644 --- a/src/events.ts +++ b/src/events.ts @@ -11,22 +11,27 @@ export const feesPlugEvents = [Events.FeesDeposited]; export const watcherEvents = [ Events.CalledAppGateway, - Events.AppGatewayCallFailed, - Events.TimeoutRequested, - Events.TimeoutResolved, + Events.AppGatewayCallFailed ]; +export const promiseResolverEvents = [Events.PromiseResolved, Events.PromiseNotResolved, Events.MarkedRevert]; + + export const requestHandlerEvents = [ Events.RequestSubmitted, Events.FeesIncreased, Events.RequestCancelled ]; -export const writePrecompileEvents = [Events.Finalized]; +export const writePrecompileEvents = [Events.WriteProofRequested, Events.WriteProofUploaded]; export const readPrecompileEvents = [Events.ReadRequested]; -export const promiseResolverEvents = [Events.PromiseResolved, Events.PromiseNotResolved]; +export const schedulePrecompileEvents = [ + Events.ScheduleRequested, + Events.ScheduleResolved, +]; + export const auctionManagerEvents = [ Events.AuctionEnded, diff --git a/src/types.ts b/src/types.ts index 87cfc9d9..b22f3711 100644 --- a/src/types.ts +++ b/src/types.ts @@ -27,14 +27,15 @@ export type ChainAddressesObj = { export type EVMxAddressesObj = { AddressResolver: string; + Watcher: string; RequestHandler: string; Configurations: string; PromiseResolver: string; - AuctionManager: string; - FeesManager: string; WritePrecompile: string; ReadPrecompile: string; - Watcher: string; + SchedulePrecompile: string; + AuctionManager: string; + FeesManager: string; startBlock: number; }; From 5681fe57c63ed92ea3223b226b9d9ea06fe4f342 Mon Sep 17 00:00:00 2001 From: Akash Date: Wed, 28 May 2025 15:07:16 +0530 Subject: [PATCH 071/130] chore : exceededMaxCopy rename --- test/SetupTest.t.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/SetupTest.t.sol b/test/SetupTest.t.sol index a44dfa96..3fd89df2 100644 --- a/test/SetupTest.t.sol +++ b/test/SetupTest.t.sol @@ -629,7 +629,7 @@ contract WatcherSetup is AuctionSetup { } else if (payloadParams.callType == SCHEDULE) { // todo: update time to delay promiseReturnData[0] = PromiseReturnData({ - maxCopyExceeded: false, + exceededMaxCopy: false, payloadId: payloadParams.payloadId, returnData: bytes("") }); @@ -655,7 +655,7 @@ contract WatcherSetup is AuctionSetup { bytes memory returnData; (success, returnData) = transaction.target.call(transaction.payload); promiseReturnData = PromiseReturnData({ - maxCopyExceeded: false, + exceededMaxCopy: false, payloadId: payloadParams.payloadId, returnData: returnData }); @@ -790,7 +790,7 @@ contract WatcherSetup is AuctionSetup { ); promiseReturnData = PromiseReturnData({ - maxCopyExceeded: false, + exceededMaxCopy: false, payloadId: payloadParams.payloadId, returnData: returnData }); From 67500b4272889b4eaec2ec09690941fecaa0b8b7 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Wed, 28 May 2025 14:44:09 +0530 Subject: [PATCH 072/130] fix: fees manager tests --- test/SocketFeeManager.t.sol | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/test/SocketFeeManager.t.sol b/test/SocketFeeManager.t.sol index 8c924951..1d7d7810 100644 --- a/test/SocketFeeManager.t.sol +++ b/test/SocketFeeManager.t.sol @@ -17,15 +17,18 @@ contract SocketFeeManagerTest is AppGatewayBaseSetup { SocketFeeManager public socketFeeManager; function setUp() public { + socketFees = 0.001 ether; + socket = new Socket(arbChainSlug, owner, "test"); - vm.prank(owner); - socket.grantRole(GOVERNANCE_ROLE, address(owner)); socketFeeManager = new SocketFeeManager(owner, socketFees); mockSwitchboard = new MockFastSwitchboard(arbChainSlug, address(socket), owner); - mockSwitchboard.registerSwitchboard(); - counter = new Counter(); + + mockSwitchboard.registerSwitchboard(); counter.initSocket(encodeAppGatewayId(gateway), address(socket), address(mockSwitchboard)); + + vm.prank(owner); + socket.grantRole(GOVERNANCE_ROLE, address(owner)); } function testSuccessfulExecutionWithFeeManagerNotSet() public { From cb49c7c6ee117559dfba5be2277105a6c50c3a61 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Wed, 28 May 2025 15:01:19 +0530 Subject: [PATCH 073/130] fix: trigger --- test/TriggerTest.t.sol | 63 +++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 38 deletions(-) diff --git a/test/TriggerTest.t.sol b/test/TriggerTest.t.sol index 59005314..e5c02f28 100644 --- a/test/TriggerTest.t.sol +++ b/test/TriggerTest.t.sol @@ -23,48 +23,30 @@ contract TriggerTest is AppGatewayBaseSetup { // Setup core test infrastructure deploy(); - // Deploy the counter contract - counter = new Counter(); - // Deploy the gateway with fees gateway = new CounterAppGateway(address(addressResolver), feesAmount); - gateway.setIsValidPlug(arbChainSlug, address(counter)); + depositNativeAndCredits(arbChainSlug, 1 ether, 0, address(gateway)); - // Connect the counter to the gateway and socket - counter.initSocket( - encodeAppGatewayId(address(gateway)), - address(arbConfig.socket), - address(arbConfig.switchboard) - ); + bytes32[] memory contractIds = new bytes32[](1); + bytes32 counterId = gateway.counter(); + contractIds[0] = counterId; - // Setup gateway config for the watcher - AppGatewayConfig[] memory configs = new AppGatewayConfig[](1); - configs[0] = AppGatewayConfig({ - chainSlug: arbChainSlug, - plug: address(counter), - plugConfig: PlugConfig({ - appGatewayId: encodeAppGatewayId(address(gateway)), - switchboard: address(arbConfig.switchboard) - }) - }); + // Deploy the counter contract + gateway.deployContracts(arbChainSlug); + executeDeploy(arbChainSlug, gateway, contractIds); - watcherMultiCall( - address(configurations), - abi.encodeWithSelector(Configurations.setPlugConfigs.selector, configs) + (address counterAddress, ) = getOnChainAndForwarderAddresses( + arbChainSlug, + counterId, + gateway ); - - hoax(watcherEOA); - configurations.setIsValidPlug(true, arbChainSlug, address(counter)); + counter = Counter(counterAddress); + gateway.setIsValidPlug(arbChainSlug, counterAddress); } function testIncrementAfterTrigger() public { // Initial counter value should be 0 assertEq(gateway.counterVal(), 0, "Initial gateway counter should be 0"); - depositNativeAndCredits(arbChainSlug, 1 ether, 0, address(gateway)); - - bytes32[] memory contractIds = new bytes32[](1); - contractIds[0] = gateway.counter(); - executeDeploy(arbChainSlug, IAppGateway(gateway), contractIds); // Simulate a message from another chain through the watcher uint256 incrementValue = 5; @@ -85,8 +67,7 @@ contract TriggerTest is AppGatewayBaseSetup { ); counter.increaseOnGateway(incrementValue); - TriggerParams[] memory params = new TriggerParams[](1); - params[0] = TriggerParams({ + TriggerParams memory params = TriggerParams({ triggerId: triggerId, chainSlug: arbChainSlug, appGatewayId: encodeAppGatewayId(address(gateway)), @@ -94,11 +75,17 @@ contract TriggerTest is AppGatewayBaseSetup { payload: payload, overrides: bytes("") }); - - watcherMultiCall( - address(watcher), - abi.encodeWithSelector(Watcher.callAppGateways.selector, params) - ); + bytes memory data = abi.encode(params); + + WatcherMultiCallParams[] memory watcherParams = new WatcherMultiCallParams[](1); + watcherParams[0] = WatcherMultiCallParams({ + contractAddress: address(watcher), + data: data, + nonce: watcherNonce, + signature: _createWatcherSignature(data) + }); + watcherNonce++; + watcher.callAppGateways(watcherParams); // Check counter was incremented assertEq(gateway.counterVal(), incrementValue, "Gateway counter should be incremented"); From ff913ba7bfc3ba75c1cb6ca2de541463b32a132d Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Wed, 28 May 2025 19:10:30 +0530 Subject: [PATCH 074/130] fix: promise inputs --- contracts/evmx/base/AppGatewayBase.sol | 7 +++---- contracts/evmx/helpers/AsyncPromise.sol | 24 +++++++++------------- contracts/evmx/interfaces/IPromise.sol | 14 ++++--------- contracts/evmx/watcher/PromiseResolver.sol | 24 ++++++++-------------- 4 files changed, 26 insertions(+), 43 deletions(-) diff --git a/contracts/evmx/base/AppGatewayBase.sol b/contracts/evmx/base/AppGatewayBase.sol index 877ed2c9..d6f4dcac 100644 --- a/contracts/evmx/base/AppGatewayBase.sol +++ b/contracts/evmx/base/AppGatewayBase.sol @@ -154,12 +154,10 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { /// @param returnData_ The return data function setAddress(bytes memory data_, bytes memory returnData_) external onlyPromises { (uint32 chainSlug, bytes32 contractId) = abi.decode(data_, (uint32, bytes32)); - address forwarderContractAddress = asyncDeployer__().getOrDeployForwarderContract( + forwarderAddresses[contractId][chainSlug] = asyncDeployer__().getOrDeployForwarderContract( abi.decode(returnData_, (address)), chainSlug ); - - forwarderAddresses[contractId][chainSlug] = forwarderContractAddress; } /// @notice Schedules a function to be called after a delay @@ -187,7 +185,8 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { return address(0); } - onChainAddress = IForwarder(forwarderAddresses[contractId_][chainSlug_]).getOnChainAddress(); + onChainAddress = IForwarder(forwarderAddresses[contractId_][chainSlug_]) + .getOnChainAddress(); } function _setCallType(Read isReadCall_) internal { diff --git a/contracts/evmx/helpers/AsyncPromise.sol b/contracts/evmx/helpers/AsyncPromise.sol index bd23bca0..0ad7ec42 100644 --- a/contracts/evmx/helpers/AsyncPromise.sol +++ b/contracts/evmx/helpers/AsyncPromise.sol @@ -74,11 +74,9 @@ contract AsyncPromise is AsyncPromiseStorage, Initializable, AddressResolverUtil /// @notice Marks the promise as resolved and executes the callback if set. /// @dev Only callable by the watcher precompile. - /// @param returnData_ The data returned from the async payload execution. + /// @param resolvedPromise_ The data returned from the async payload execution. function markResolved( - bool exceededMaxCopy_, - bytes32 payloadId_, - bytes memory returnData_ + PromiseReturnData memory resolvedPromise_ ) external override onlyWatcher returns (bool success) { if ( state == AsyncPromiseState.CALLBACK_REVERTING || @@ -91,18 +89,18 @@ contract AsyncPromise is AsyncPromiseStorage, Initializable, AddressResolverUtil if (callbackSelector == bytes4(0)) { success = true; } else { - exceededMaxCopy = exceededMaxCopy_; - returnData = returnData_; + exceededMaxCopy = resolvedPromise_.maxCopyExceeded; + returnData = resolvedPromise_.returnData; bytes memory combinedCalldata = abi.encodePacked( callbackSelector, - abi.encode(callbackData, returnData_) + abi.encode(callbackData, resolvedPromise_.returnData) ); (success, , ) = localInvoker.tryCall(0, gasleft(), 0, combinedCalldata); if (!success) { state = AsyncPromiseState.CALLBACK_REVERTING; - _handleRevert(payloadId_); + _handleRevert(resolvedPromise_.payloadId); } } } @@ -110,9 +108,7 @@ contract AsyncPromise is AsyncPromiseStorage, Initializable, AddressResolverUtil /// @notice Marks the promise as onchain reverting. /// @dev Only callable by the watcher precompile. function markOnchainRevert( - bool exceededMaxCopy_, - bytes32 payloadId_, - bytes memory returnData_ + PromiseReturnData memory resolvedPromise_ ) external override onlyWatcher { if ( state == AsyncPromiseState.CALLBACK_REVERTING || @@ -122,9 +118,9 @@ contract AsyncPromise is AsyncPromiseStorage, Initializable, AddressResolverUtil // to update the state in case selector is bytes(0) but reverting onchain state = AsyncPromiseState.ONCHAIN_REVERTING; - exceededMaxCopy_ = exceededMaxCopy_; - returnData_ = returnData_; - _handleRevert(payloadId_); + exceededMaxCopy = resolvedPromise_.maxCopyExceeded; + returnData = resolvedPromise_.returnData; + _handleRevert(resolvedPromise_.payloadId); } /// @notice Handles the revert of the promise. diff --git a/contracts/evmx/interfaces/IPromise.sol b/contracts/evmx/interfaces/IPromise.sol index 0d1c34ec..9809d549 100644 --- a/contracts/evmx/interfaces/IPromise.sol +++ b/contracts/evmx/interfaces/IPromise.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import {AsyncPromiseState} from "../../utils/common/Structs.sol"; +import {AsyncPromiseState, PromiseReturnData} from "../../utils/common/Structs.sol"; /// @title IPromise interface IPromise { @@ -28,18 +28,12 @@ interface IPromise { /// @notice Marks the promise as resolved and executes the callback if set. /// @dev Only callable by the watcher precompile. - /// @param returnData_ The data returned from the async payload execution. + /// @param resolvedPromise_ The data returned from the async payload execution. function markResolved( - bool exceededMaxCopy_, - bytes32 payloadId_, - bytes memory returnData_ + PromiseReturnData memory resolvedPromise_ ) external returns (bool success); /// @notice Marks the promise as onchain reverting. /// @dev Only callable by the watcher precompile. - function markOnchainRevert( - bool exceededMaxCopy_, - bytes32 payloadId_, - bytes memory returnData_ - ) external; + function markOnchainRevert(PromiseReturnData memory resolvedPromise_) external; } diff --git a/contracts/evmx/watcher/PromiseResolver.sol b/contracts/evmx/watcher/PromiseResolver.sol index bbd80815..7a4c85ac 100644 --- a/contracts/evmx/watcher/PromiseResolver.sol +++ b/contracts/evmx/watcher/PromiseResolver.sol @@ -46,28 +46,25 @@ contract PromiseResolver is IPromiseResolver, WatcherBase { function _processPromiseResolution( PromiseReturnData memory resolvedPromise_ ) internal returns (uint40 requestCount, bool success) { - PayloadParams memory payloadParams = watcher__.getPayloadParams(resolvedPromise_.payloadId); + bytes32 payloadId = resolvedPromise_.payloadId; + PayloadParams memory payloadParams = watcher__.getPayloadParams(payloadId); if (payloadParams.deadline < block.timestamp) revert DeadlinePassed(); address asyncPromise = payloadParams.asyncPromise; requestCount = payloadParams.requestCount; if (asyncPromise != address(0)) { - success = IPromise(asyncPromise).markResolved( - resolvedPromise_.exceededMaxCopy, - resolvedPromise_.payloadId, - resolvedPromise_.returnData - ); + success = IPromise(asyncPromise).markResolved(resolvedPromise_); if (!success) { - emit PromiseNotResolved(resolvedPromise_.payloadId, asyncPromise); + emit PromiseNotResolved(payloadId, asyncPromise); return (requestCount, false); } } else { success = true; } - emit PromiseResolved(resolvedPromise_.payloadId, asyncPromise); + emit PromiseResolved(payloadId, asyncPromise); } /// @notice Marks a request as reverting @@ -80,7 +77,8 @@ contract PromiseResolver is IPromiseResolver, WatcherBase { bool isRevertingOnchain_ ) external onlyWatcher { // Get payload params from Watcher - PayloadParams memory payloadParams = watcher__.getPayloadParams(resolvedPromise_.payloadId); + bytes32 payloadId = resolvedPromise_.payloadId; + PayloadParams memory payloadParams = watcher__.getPayloadParams(payloadId); if (payloadParams.deadline > block.timestamp) revert DeadlineNotPassedForOnChainRevert(); // marks the request as cancelled and settles the fees @@ -88,12 +86,8 @@ contract PromiseResolver is IPromiseResolver, WatcherBase { // marks the promise as onchain reverting if the request is reverting onchain if (isRevertingOnchain_ && payloadParams.asyncPromise != address(0)) - IPromise(payloadParams.asyncPromise).markOnchainRevert( - resolvedPromise_.exceededMaxCopy, - resolvedPromise_.payloadId, - resolvedPromise_.returnData - ); + IPromise(payloadParams.asyncPromise).markOnchainRevert(resolvedPromise_); - emit MarkedRevert(resolvedPromise_.payloadId, isRevertingOnchain_); + emit MarkedRevert(payloadId, isRevertingOnchain_); } } From d5db9e58dcb60e64d1ababe0e6f32869daa17be4 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Wed, 28 May 2025 19:38:06 +0530 Subject: [PATCH 075/130] fix: write tests --- contracts/evmx/AuctionManager.sol | 2 +- contracts/evmx/watcher/RequestHandler.sol | 26 +++--- test/FeesTest.t.sol | 2 +- test/SetupTest.t.sol | 22 ++++- test/TriggerTest.t.sol | 2 +- test/apps/Counter.t.sol | 15 +-- test/apps/ParallelCounter.t.sol | 106 +++++++++------------- test/apps/SuperToken.t.sol | 6 +- 8 files changed, 87 insertions(+), 94 deletions(-) diff --git a/contracts/evmx/AuctionManager.sol b/contracts/evmx/AuctionManager.sol index 33e2057e..dc6a9e27 100644 --- a/contracts/evmx/AuctionManager.sol +++ b/contracts/evmx/AuctionManager.sol @@ -192,7 +192,7 @@ contract AuctionManager is AuctionManagerStorage, AccessControl, AppGatewayBase if (reAuctionCount[requestCount_] >= maxReAuctionCount) revert MaxReAuctionCountReached(); RequestParams memory requestParams = _getRequestParams(requestCount_); - // if executed, bid is not expired + // if executed or cancelled, bid is not expired if ( requestParams.requestTrackingParams.payloadsRemaining == 0 || requestParams.requestTrackingParams.isRequestCancelled diff --git a/contracts/evmx/watcher/RequestHandler.sol b/contracts/evmx/watcher/RequestHandler.sol index 450d5acb..60cc4341 100644 --- a/contracts/evmx/watcher/RequestHandler.sol +++ b/contracts/evmx/watcher/RequestHandler.sol @@ -112,8 +112,8 @@ contract RequestHandler is AddressResolverUtil, Ownable, IRequestHandler { revert InsufficientFees(); requestCount = nextRequestCount++; + uint40 currentBatch = nextBatchCount; RequestParams storage r = _requests[requestCount]; - r.requestTrackingParams.currentBatch = nextBatchCount; r.requestTrackingParams.payloadsRemaining = queueParams_.length; r.requestFeesDetails.maxFees = maxFees_; r.requestFeesDetails.consumeFrom = consumeFrom_; @@ -123,14 +123,15 @@ contract RequestHandler is AddressResolverUtil, Ownable, IRequestHandler { CreateRequestResult memory result = _createRequest(queueParams_, appGateway_, requestCount); - r.requestTrackingParams.currentBatchPayloadsLeft = _batchPayloadIds[ - r.requestTrackingParams.currentBatch - ].length; + // initialize tracking params + r.requestTrackingParams.currentBatch = currentBatch; + r.requestTrackingParams.currentBatchPayloadsLeft = _batchPayloadIds[currentBatch].length; + r.writeCount = result.writeCount; promiseList = result.promiseList; if (result.totalEstimatedWatcherFees > maxFees_) revert InsufficientFees(); - if (r.writeCount == 0) _processBatch(r.requestTrackingParams.currentBatch, r); + if (r.writeCount == 0) _processBatch(currentBatch, r); emit RequestSubmitted( r.writeCount > 0, @@ -293,14 +294,14 @@ contract RequestHandler is AddressResolverUtil, Ownable, IRequestHandler { uint40 requestCount_, uint256 newMaxFees_, address appGateway_ - ) external onlyWatcher { + ) external onlyWatcher isRequestCancelled(requestCount_) { RequestParams storage r = _requests[requestCount_]; - if (r.requestTrackingParams.isRequestCancelled) revert RequestAlreadyCancelled(); if (r.requestTrackingParams.isRequestExecuted) revert RequestAlreadySettled(); if (appGateway_ != r.appGateway) revert OnlyAppGateway(); if (r.requestFeesDetails.maxFees >= newMaxFees_) revert NewMaxFeesLowerThanCurrent(r.requestFeesDetails.maxFees, newMaxFees_); + if ( !IFeesManager(feesManager__()).isCreditSpendable( r.requestFeesDetails.consumeFrom, @@ -335,8 +336,9 @@ contract RequestHandler is AddressResolverUtil, Ownable, IRequestHandler { trackingParams.isRequestExecuted = true; _settleRequest(requestCount_, r); } else { - trackingParams.currentBatch++; - _processBatch(trackingParams.currentBatch, r); + uint40 currentBatch = ++trackingParams.currentBatch; + trackingParams.currentBatchPayloadsLeft = _batchPayloadIds[currentBatch].length; + _processBatch(currentBatch, r); } } @@ -366,8 +368,10 @@ contract RequestHandler is AddressResolverUtil, Ownable, IRequestHandler { _cancelRequest(requestCount, _requests[requestCount]); } - function _cancelRequest(uint40 requestCount_, RequestParams storage r) internal { - if (r.requestTrackingParams.isRequestCancelled) revert RequestAlreadyCancelled(); + function _cancelRequest( + uint40 requestCount_, + RequestParams storage r + ) internal isRequestCancelled(requestCount_) { if (r.requestTrackingParams.isRequestExecuted) revert RequestAlreadySettled(); r.requestTrackingParams.isRequestCancelled = true; diff --git a/test/FeesTest.t.sol b/test/FeesTest.t.sol index 61cfe64e..374c66ce 100644 --- a/test/FeesTest.t.sol +++ b/test/FeesTest.t.sol @@ -23,7 +23,7 @@ contract FeesTest is AppGatewayBaseSetup { bytes32[] memory contractIds = new bytes32[](1); contractIds[0] = counterGateway.counter(); - executeDeploy(feesChainSlug, IAppGateway(counterGateway), contractIds); + executeDeploy(IAppGateway(counterGateway), feesChainSlug, contractIds); } function testWithdrawTransmitterFees() public { diff --git a/test/SetupTest.t.sol b/test/SetupTest.t.sol index 3fd89df2..7de5bb05 100644 --- a/test/SetupTest.t.sol +++ b/test/SetupTest.t.sol @@ -590,13 +590,33 @@ contract WatcherSetup is AuctionSetup { ); event WriteProofUploaded(bytes32 indexed payloadId, bytes proof); + function executeDeployMultiChain( + IAppGateway appGateway_, + uint32[] memory chainSlugs_, + bytes32[] memory contractIds_ + ) internal returns (uint40 requestCount) { + return _executeDeploy(appGateway_, chainSlugs_, contractIds_); + } + function executeDeploy( + IAppGateway appGateway_, uint32 chainSlug_, + bytes32[] memory contractIds_ + ) internal returns (uint40 requestCount) { + uint32[] memory chainSlugs = new uint32[](1); + chainSlugs[0] = chainSlug_; + return _executeDeploy(appGateway_, chainSlugs, contractIds_); + } + + function _executeDeploy( IAppGateway appGateway_, + uint32[] memory chainSlugs_, bytes32[] memory contractIds_ ) internal returns (uint40 requestCount) { requestCount = executeRequest(); - setupGatewayAndPlugs(chainSlug_, appGateway_, contractIds_); + for (uint i = 0; i < chainSlugs_.length; i++) { + setupGatewayAndPlugs(chainSlugs_[i], appGateway_, contractIds_); + } } function executeRequest() internal returns (uint40 requestCount) { diff --git a/test/TriggerTest.t.sol b/test/TriggerTest.t.sol index e5c02f28..b4633de9 100644 --- a/test/TriggerTest.t.sol +++ b/test/TriggerTest.t.sol @@ -33,7 +33,7 @@ contract TriggerTest is AppGatewayBaseSetup { // Deploy the counter contract gateway.deployContracts(arbChainSlug); - executeDeploy(arbChainSlug, gateway, contractIds); + executeDeploy(gateway, arbChainSlug, contractIds); (address counterAddress, ) = getOnChainAndForwarderAddresses( arbChainSlug, diff --git a/test/apps/Counter.t.sol b/test/apps/Counter.t.sol index c2e2b1e7..83d1120b 100644 --- a/test/apps/Counter.t.sol +++ b/test/apps/Counter.t.sol @@ -13,23 +13,21 @@ contract CounterTest is AppGatewayBaseSetup { CounterAppGateway counterGateway; - function deploySetup() internal { + function setUp() public { deploy(); counterGateway = new CounterAppGateway(address(addressResolver), feesAmount); depositNativeAndCredits(arbChainSlug, 1 ether, 0, address(counterGateway)); - counterId = counterGateway.counter(); contractIds[0] = counterId; } function deployCounterApp(uint32 chainSlug) internal returns (uint40 requestCount) { counterGateway.deployContracts(chainSlug); - requestCount = executeDeploy(chainSlug, counterGateway, contractIds); + requestCount = executeDeploy(counterGateway, chainSlug, contractIds); } function testCounterDeployment() external { - deploySetup(); deployCounterApp(arbChainSlug); (address onChain, address forwarder) = getOnChainAndForwarderAddresses( @@ -51,14 +49,11 @@ contract CounterTest is AppGatewayBaseSetup { } function testCounterDeploymentWithoutAsync() external { - deploySetup(); - vm.expectRevert(abi.encodeWithSelector(AsyncModifierNotSet.selector)); counterGateway.deployContractsWithoutAsync(arbChainSlug); } function testCounterIncrement() external { - deploySetup(); deployCounterApp(arbChainSlug); (address arbCounter, address arbCounterForwarder) = getOnChainAndForwarderAddresses( @@ -78,7 +73,6 @@ contract CounterTest is AppGatewayBaseSetup { } function testCounterIncrementMultipleChains() public { - deploySetup(); deployCounterApp(arbChainSlug); deployCounterApp(optChainSlug); @@ -129,11 +123,6 @@ contract CounterTest is AppGatewayBaseSetup { instances[1] = optCounterForwarder; counterGateway.readCounters(instances); - - // bytes[] memory readReturnData = new bytes[](2); - // readReturnData[0] = abi.encode(10); - // readReturnData[1] = abi.encode(10); - executeRequest(); } } diff --git a/test/apps/ParallelCounter.t.sol b/test/apps/ParallelCounter.t.sol index f04a95ae..fda14b52 100644 --- a/test/apps/ParallelCounter.t.sol +++ b/test/apps/ParallelCounter.t.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.21; import {CounterAppGateway} from "./app-gateways/counter/CounterAppGateway.sol"; +import {Counter} from "./app-gateways/counter/Counter.sol"; import "../SetupTest.t.sol"; contract ParallelCounterTest is AppGatewayBaseSetup { @@ -13,7 +14,7 @@ contract ParallelCounterTest is AppGatewayBaseSetup { CounterAppGateway parallelCounterGateway; - function deploySetup() internal { + function setUp() public { deploy(); parallelCounterGateway = new CounterAppGateway(address(addressResolver), feesAmount); @@ -25,17 +26,16 @@ contract ParallelCounterTest is AppGatewayBaseSetup { contractIds[1] = counterId2; } - function deployCounterApps(uint32[] memory chainSlugs) internal { + function deployCounterApp(uint32[] memory chainSlugs) internal { parallelCounterGateway.deployMultiChainContracts(chainSlugs); - executeRequest(); + executeDeployMultiChain(parallelCounterGateway, chainSlugs, contractIds); } function testParallelCounterDeployment() external { - deploySetup(); uint32[] memory chainSlugs = new uint32[](2); chainSlugs[0] = arbChainSlug; chainSlugs[1] = optChainSlug; - deployCounterApps(chainSlugs); + deployCounterApp(chainSlugs); (address onChainArb1, address forwarderArb1) = getOnChainAndForwarderAddresses( arbChainSlug, @@ -101,75 +101,55 @@ contract ParallelCounterTest is AppGatewayBaseSetup { ); } - function testAsyncModifierNotSet() external { - deploySetup(); + function testCounterIncrement() external { uint32[] memory chainSlugs = new uint32[](1); chainSlugs[0] = arbChainSlug; - deployCounterApps(chainSlugs); + deployCounterApp(chainSlugs); - (, address arbCounterForwarder) = getOnChainAndForwarderAddresses( + (address arbCounter, address arbCounterForwarder) = getOnChainAndForwarderAddresses( arbChainSlug, counterId1, parallelCounterGateway ); + uint256 arbCounterBefore = Counter(arbCounter).counter(); + address[] memory instances = new address[](1); instances[0] = arbCounterForwarder; + parallelCounterGateway.incrementCounters(instances); - // Should revert with AsyncModifierNotUsed error - vm.expectRevert(abi.encodeWithSignature("AsyncModifierNotUsed()")); - parallelCounterGateway.incrementCountersWithoutAsync(instances); + executeRequest(); + assertEq(Counter(arbCounter).counter(), arbCounterBefore + 1); } - // function testCounterIncrement() external { - // deploySetup(); - // deployCounterApp(arbChainSlug); - - // (address arbCounter, address arbCounterForwarder) = getOnChainAndForwarderAddresses( - // arbChainSlug, - // counterId, - // counterDeployer - // ); - - // uint256 arbCounterBefore = Counter(arbCounter).counter(); - - // address[] memory instances = new address[](1); - // instances[0] = arbCounterForwarder; - // counterGateway.incrementCounters(instances); - - // _executeRequestSingleChain(arbChainSlug, 1); - // assertEq(Counter(arbCounter).counter(), arbCounterBefore + 1); - // } - - // function testCounterIncrementMultipleChains() external { - // deploySetup(); - // deployCounterApp(arbChainSlug); - // deployCounterApp(optChainSlug); - - // (address arbCounter, address arbCounterForwarder) = getOnChainAndForwarderAddresses( - // arbChainSlug, - // counterId, - // counterDeployer - // ); - // (address optCounter, address optCounterForwarder) = getOnChainAndForwarderAddresses( - // optChainSlug, - // counterId, - // counterDeployer - // ); - - // uint256 arbCounterBefore = Counter(arbCounter).counter(); - // uint256 optCounterBefore = Counter(optCounter).counter(); - - // address[] memory instances = new address[](2); - // instances[0] = arbCounterForwarder; - // instances[1] = optCounterForwarder; - // counterGateway.incrementCounters(instances); - - // uint32[] memory chains = new uint32[](2); - // chains[0] = arbChainSlug; - // chains[1] = optChainSlug; - // _executeRequestMultiChain(chains); - // assertEq(Counter(arbCounter).counter(), arbCounterBefore + 1); - // assertEq(Counter(optCounter).counter(), optCounterBefore + 1); - // } + function testCounterIncrementMultipleChains() external { + uint32[] memory chainSlugs = new uint32[](2); + chainSlugs[0] = arbChainSlug; + chainSlugs[1] = optChainSlug; + deployCounterApp(chainSlugs); + + (address arbCounter, address arbCounterForwarder) = getOnChainAndForwarderAddresses( + arbChainSlug, + counterId1, + parallelCounterGateway + ); + (address optCounter, address optCounterForwarder) = getOnChainAndForwarderAddresses( + optChainSlug, + counterId1, + parallelCounterGateway + ); + + uint256 arbCounterBefore = Counter(arbCounter).counter(); + uint256 optCounterBefore = Counter(optCounter).counter(); + + address[] memory instances = new address[](2); + instances[0] = arbCounterForwarder; + instances[1] = optCounterForwarder; + parallelCounterGateway.incrementCounters(instances); + + executeRequest(); + + assertEq(Counter(arbCounter).counter(), arbCounterBefore + 1); + assertEq(Counter(optCounter).counter(), optCounterBefore + 1); + } } diff --git a/test/apps/SuperToken.t.sol b/test/apps/SuperToken.t.sol index ff935afb..6564eabb 100644 --- a/test/apps/SuperToken.t.sol +++ b/test/apps/SuperToken.t.sol @@ -93,7 +93,7 @@ contract SuperTokenTest is AppGatewayBaseSetup { * - Correct setup of forwarder contracts for multi-chain communication */ function testContractDeployment() public { - executeDeploy(arbChainSlug, IAppGateway(appContracts.superTokenApp), contractIds); + executeDeploy(IAppGateway(appContracts.superTokenApp), arbChainSlug, contractIds); (address onChain, address forwarder) = getOnChainAndForwarderAddresses( arbChainSlug, @@ -124,8 +124,8 @@ contract SuperTokenTest is AppGatewayBaseSetup { * @dev Deploys necessary contracts on both Arbitrum and Optimism chains */ function beforeTransfer() internal { - executeDeploy(arbChainSlug, IAppGateway(appContracts.superTokenApp), contractIds); - executeDeploy(optChainSlug, IAppGateway(appContracts.superTokenApp), contractIds); + executeDeploy(IAppGateway(appContracts.superTokenApp), arbChainSlug, contractIds); + executeDeploy(IAppGateway(appContracts.superTokenApp), optChainSlug, contractIds); } /** From 0d7b3d05cd59269adcb0133ed8b0bd00facb4261 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Wed, 28 May 2025 19:39:19 +0530 Subject: [PATCH 076/130] fix: build --- contracts/evmx/helpers/AsyncPromise.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/evmx/helpers/AsyncPromise.sol b/contracts/evmx/helpers/AsyncPromise.sol index 0ad7ec42..9d43f576 100644 --- a/contracts/evmx/helpers/AsyncPromise.sol +++ b/contracts/evmx/helpers/AsyncPromise.sol @@ -89,7 +89,7 @@ contract AsyncPromise is AsyncPromiseStorage, Initializable, AddressResolverUtil if (callbackSelector == bytes4(0)) { success = true; } else { - exceededMaxCopy = resolvedPromise_.maxCopyExceeded; + exceededMaxCopy = resolvedPromise_.exceededMaxCopy; returnData = resolvedPromise_.returnData; bytes memory combinedCalldata = abi.encodePacked( @@ -118,7 +118,7 @@ contract AsyncPromise is AsyncPromiseStorage, Initializable, AddressResolverUtil // to update the state in case selector is bytes(0) but reverting onchain state = AsyncPromiseState.ONCHAIN_REVERTING; - exceededMaxCopy = resolvedPromise_.maxCopyExceeded; + exceededMaxCopy = resolvedPromise_.exceededMaxCopy; returnData = resolvedPromise_.returnData; _handleRevert(resolvedPromise_.payloadId); } From 7ff1f35ff425a8dd33f0c7b04feadf0d220d6766 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Wed, 28 May 2025 19:43:18 +0530 Subject: [PATCH 077/130] fix: read validation --- contracts/evmx/watcher/precompiles/ReadPrecompile.sol | 2 +- contracts/evmx/watcher/precompiles/WritePrecompile.sol | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/evmx/watcher/precompiles/ReadPrecompile.sol b/contracts/evmx/watcher/precompiles/ReadPrecompile.sol index 4cd6489b..dc67c650 100644 --- a/contracts/evmx/watcher/precompiles/ReadPrecompile.sol +++ b/contracts/evmx/watcher/precompiles/ReadPrecompile.sol @@ -35,7 +35,7 @@ contract ReadPrecompile is IPrecompile, WatcherBase { QueueParams calldata queueParams_, address ) external view returns (bytes memory precompileData, uint256 estimatedFees) { - if (queueParams_.transaction.target != address(0)) revert InvalidTarget(); + if (queueParams_.transaction.target == address(0)) revert InvalidTarget(); if (queueParams_.transaction.payload.length == 0) revert InvalidPayloadSize(); // For read precompile, encode the payload parameters diff --git a/contracts/evmx/watcher/precompiles/WritePrecompile.sol b/contracts/evmx/watcher/precompiles/WritePrecompile.sol index eedb3e89..c2134e2b 100644 --- a/contracts/evmx/watcher/precompiles/WritePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/WritePrecompile.sol @@ -97,7 +97,7 @@ contract WritePrecompile is IPrecompile, WatcherBase, Ownable { ); } - // todo: can be used to set the default gas limit for each chain + // todo: can be changed to set the default gas limit for each chain if (queueParams_.overrideParams.gasLimit == 0) { queueParams_.overrideParams.gasLimit = 1000000; } From ffcc2eefadff37f2e08f53231536ce6283d1944b Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Wed, 28 May 2025 19:56:46 +0530 Subject: [PATCH 078/130] fix: schedule --- test/SetupTest.t.sol | 2 +- test/apps/Counter.t.sol | 16 +++++++++++++++- .../app-gateways/counter/CounterAppGateway.sol | 6 +++--- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/test/SetupTest.t.sol b/test/SetupTest.t.sol index 7de5bb05..29f4e980 100644 --- a/test/SetupTest.t.sol +++ b/test/SetupTest.t.sol @@ -647,7 +647,7 @@ contract WatcherSetup is AuctionSetup { } else if (payloadParams.callType == WRITE) { (success, promiseReturnData[0]) = _processWrite(payloadParams); } else if (payloadParams.callType == SCHEDULE) { - // todo: update time to delay + vm.warp(payloadParams.deadline); promiseReturnData[0] = PromiseReturnData({ exceededMaxCopy: false, payloadId: payloadParams.payloadId, diff --git a/test/apps/Counter.t.sol b/test/apps/Counter.t.sol index 83d1120b..0d9eb0b5 100644 --- a/test/apps/Counter.t.sol +++ b/test/apps/Counter.t.sol @@ -10,9 +10,10 @@ contract CounterTest is AppGatewayBaseSetup { bytes32 counterId; bytes32[] contractIds = new bytes32[](1); - CounterAppGateway counterGateway; + event CounterScheduleResolved(uint256 creationTimestamp, uint256 executionTimestamp); + function setUp() public { deploy(); @@ -125,4 +126,17 @@ contract CounterTest is AppGatewayBaseSetup { counterGateway.readCounters(instances); executeRequest(); } + + function testCounterSchedule() external { + deployCounterApp(arbChainSlug); + + uint256 creationTimestamp = block.timestamp; + counterGateway.setSchedule(100); + + vm.expectEmit(true, true, true, false); + emit CounterScheduleResolved(creationTimestamp, block.timestamp); + executeRequest(); + + assertEq(block.timestamp, creationTimestamp + 100 + expiryTime); + } } diff --git a/test/apps/app-gateways/counter/CounterAppGateway.sol b/test/apps/app-gateways/counter/CounterAppGateway.sol index cd7f69df..d47454dc 100644 --- a/test/apps/app-gateways/counter/CounterAppGateway.sol +++ b/test/apps/app-gateways/counter/CounterAppGateway.sol @@ -12,10 +12,10 @@ contract CounterAppGateway is AppGatewayBase, Ownable { bytes32 public counter1 = _createContractId("counter1"); uint256 public counterVal; - uint256 public arbCounter; uint256 public optCounter; - event ScheduleResolved(uint256 creationTimestamp, uint256 executionTimestamp); + + event CounterScheduleResolved(uint256 creationTimestamp, uint256 executionTimestamp); constructor(address addressResolver_, uint256 fees_) AppGatewayBase(addressResolver_) { creationCodeWithArgs[counter] = abi.encodePacked(type(Counter).creationCode); @@ -112,7 +112,7 @@ contract CounterAppGateway is AppGatewayBase, Ownable { } function resolveSchedule(uint256 creationTimestamp_) external onlyPromises { - emit ScheduleResolved(creationTimestamp_, block.timestamp); + emit CounterScheduleResolved(creationTimestamp_, block.timestamp); } // UTILS From db2e2e5f6668906a2021cfc49a453593dd594467 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Wed, 28 May 2025 19:57:02 +0530 Subject: [PATCH 079/130] fix: lint --- contracts/protocol/SocketUtils.sol | 16 +++++----------- src/enums.ts | 18 ++++++++---------- src/events.ts | 17 +++++++++++------ src/index.ts | 2 +- 4 files changed, 25 insertions(+), 28 deletions(-) diff --git a/contracts/protocol/SocketUtils.sol b/contracts/protocol/SocketUtils.sol index e2d53efa..c873d698 100644 --- a/contracts/protocol/SocketUtils.sol +++ b/contracts/protocol/SocketUtils.sol @@ -24,7 +24,6 @@ abstract contract SocketUtils is SocketConfig { bytes payload; } - address public constant OFF_CHAIN_CALLER = address(0xDEAD); // Prefix for trigger ID containing chain slug and address bits @@ -39,12 +38,11 @@ abstract contract SocketUtils is SocketConfig { error OnlyOffChain(); error SimulationFailed(); - modifier onlyOffChain() { + modifier onlyOffChain() { if (msg.sender != OFF_CHAIN_CALLER) revert OnlyOffChain(); _; } - /* * @notice constructor for creating a new Socket contract instance. * @param chainSlug_ The unique identifier of the chain this socket is deployed on. @@ -115,7 +113,6 @@ abstract contract SocketUtils is SocketConfig { return bytes32(triggerPrefix | triggerCounter++); } - struct SimulationResult { bool success; bytes returnData; @@ -126,14 +123,11 @@ abstract contract SocketUtils is SocketConfig { SimulateParams[] calldata params ) external payable onlyOffChain returns (SimulationResult[] memory) { SimulationResult[] memory results = new SimulationResult[](params.length); - + for (uint256 i = 0; i < params.length; i++) { - (bool success, bool exceededMaxCopy, bytes memory returnData) = params[i].target.tryCall( - params[i].value, - params[i].gasLimit, - maxCopyBytes, - params[i].payload - ); + (bool success, bool exceededMaxCopy, bytes memory returnData) = params[i] + .target + .tryCall(params[i].value, params[i].gasLimit, maxCopyBytes, params[i].payload); results[i] = SimulationResult(success, returnData, exceededMaxCopy); } diff --git a/src/enums.ts b/src/enums.ts index 2802846e..68f4e796 100644 --- a/src/enums.ts +++ b/src/enums.ts @@ -11,10 +11,10 @@ export enum Events { ExecutionFailed = "ExecutionFailed", PlugConnected = "PlugConnected", AppGatewayCallRequested = "AppGatewayCallRequested", - + // FeesPlug FeesDeposited = "FeesDeposited", - + // Watcher CalledAppGateway = "CalledAppGateway", AppGatewayCallFailed = "AppGatewayCallFailed", @@ -24,24 +24,22 @@ export enum Events { PromiseNotResolved = "PromiseNotResolved", MarkedRevert = "MarkedRevert", - // RequestHandler RequestSubmitted = "RequestSubmitted", RequestCancelled = "RequestCancelled", FeesIncreased = "FeesIncreased", - + // WritePrecompile WriteProofRequested = "WriteProofRequested", WriteProofUploaded = "WriteProofUploaded", - + // ReadPrecompile ReadRequested = "ReadRequested", - - // SchedulePrecompile - ScheduleRequested = "ScheduleRequested", - ScheduleResolved = "ScheduleResolved", - + // SchedulePrecompile + ScheduleRequested = "ScheduleRequested", + ScheduleResolved = "ScheduleResolved", + // AuctionManager AuctionEnded = "AuctionEnded", AuctionRestarted = "AuctionRestarted", diff --git a/src/events.ts b/src/events.ts index 27bc802a..c115e6bf 100644 --- a/src/events.ts +++ b/src/events.ts @@ -11,19 +11,25 @@ export const feesPlugEvents = [Events.FeesDeposited]; export const watcherEvents = [ Events.CalledAppGateway, - Events.AppGatewayCallFailed + Events.AppGatewayCallFailed, ]; -export const promiseResolverEvents = [Events.PromiseResolved, Events.PromiseNotResolved, Events.MarkedRevert]; - +export const promiseResolverEvents = [ + Events.PromiseResolved, + Events.PromiseNotResolved, + Events.MarkedRevert, +]; export const requestHandlerEvents = [ Events.RequestSubmitted, Events.FeesIncreased, - Events.RequestCancelled + Events.RequestCancelled, ]; -export const writePrecompileEvents = [Events.WriteProofRequested, Events.WriteProofUploaded]; +export const writePrecompileEvents = [ + Events.WriteProofRequested, + Events.WriteProofUploaded, +]; export const readPrecompileEvents = [Events.ReadRequested]; @@ -32,7 +38,6 @@ export const schedulePrecompileEvents = [ Events.ScheduleResolved, ]; - export const auctionManagerEvents = [ Events.AuctionEnded, Events.AuctionRestarted, diff --git a/src/index.ts b/src/index.ts index 29579d68..9e934473 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,4 +3,4 @@ export * from "./enums"; export * from "./events"; export * from "./finality"; export * from "./types"; -export * from "./constants"; \ No newline at end of file +export * from "./constants"; From bac3acc18203c886856978a00235ec52540d3ecc Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Wed, 28 May 2025 20:15:00 +0530 Subject: [PATCH 080/130] fix: schedule resolve before expiry --- contracts/evmx/base/AppGatewayBase.sol | 1 - .../watcher/precompiles/SchedulePrecompile.sol | 16 +++++++++------- test/SetupTest.t.sol | 3 ++- test/apps/Counter.t.sol | 2 +- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/contracts/evmx/base/AppGatewayBase.sol b/contracts/evmx/base/AppGatewayBase.sol index d6f4dcac..fa9a92e4 100644 --- a/contracts/evmx/base/AppGatewayBase.sol +++ b/contracts/evmx/base/AppGatewayBase.sol @@ -141,7 +141,6 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { ); then(this.setAddress.selector, abi.encode(chainSlug_, contractId_)); - onCompleteData = abi.encode(chainSlug_, true); } diff --git a/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol b/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol index 042d94ee..dae36ad2 100644 --- a/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol @@ -31,7 +31,7 @@ contract SchedulePrecompile is IPrecompile, WatcherBase { /// @notice Emitted when the expiry time for a schedule is set event ExpiryTimeSet(uint256 expiryTime_); /// @notice Emitted when a schedule is requested - event ScheduleRequested(bytes32 payloadId, uint256 executeAt, uint256 deadline); + event ScheduleRequested(bytes32 payloadId, uint256 executeAfter, uint256 deadline); /// @notice Emitted when a schedule is resolved event ScheduleResolved(bytes32 payloadId); @@ -121,20 +121,22 @@ contract SchedulePrecompile is IPrecompile, WatcherBase { onlyRequestHandler returns (uint256 fees, uint256 deadline, bytes memory precompileData) { - uint256 delayInSeconds = abi.decode(payloadParams.precompileData, (uint256)); + (uint256 delayInSeconds, ) = abi.decode(payloadParams.precompileData, (uint256, uint256)); // expiryTime is very low, to account for infra delay - uint256 executeAt = block.timestamp + delayInSeconds; - deadline = executeAt + expiryTime; - precompileData = abi.encode(delayInSeconds, executeAt); + uint256 executeAfter = block.timestamp + delayInSeconds; + deadline = executeAfter + expiryTime; + precompileData = abi.encode(delayInSeconds, executeAfter); fees = scheduleFeesPerSecond * delayInSeconds + scheduleCallbackFees; // emits event for watcher to track schedule and resolve when deadline is reached - emit ScheduleRequested(payloadParams.payloadId, executeAt, deadline); + emit ScheduleRequested(payloadParams.payloadId, executeAfter, deadline); } function resolvePayload(PayloadParams calldata payloadParams_) external onlyRequestHandler { - if (payloadParams_.deadline > block.timestamp) revert ResolvingScheduleTooEarly(); + (, uint256 executeAfter) = abi.decode(payloadParams_.precompileData, (uint256, uint256)); + + if (executeAfter > block.timestamp) revert ResolvingScheduleTooEarly(); emit ScheduleResolved(payloadParams_.payloadId); } } diff --git a/test/SetupTest.t.sol b/test/SetupTest.t.sol index 29f4e980..d64ad8aa 100644 --- a/test/SetupTest.t.sol +++ b/test/SetupTest.t.sol @@ -647,7 +647,7 @@ contract WatcherSetup is AuctionSetup { } else if (payloadParams.callType == WRITE) { (success, promiseReturnData[0]) = _processWrite(payloadParams); } else if (payloadParams.callType == SCHEDULE) { - vm.warp(payloadParams.deadline); + vm.warp(payloadParams.deadline - expiryTime); promiseReturnData[0] = PromiseReturnData({ exceededMaxCopy: false, payloadId: payloadParams.payloadId, @@ -659,6 +659,7 @@ contract WatcherSetup is AuctionSetup { if (success) { _resolvePromise(promiseReturnData); } else { + vm.warp(payloadParams.deadline); _markRevert(promiseReturnData[0], true); } } diff --git a/test/apps/Counter.t.sol b/test/apps/Counter.t.sol index 0d9eb0b5..e0949f07 100644 --- a/test/apps/Counter.t.sol +++ b/test/apps/Counter.t.sol @@ -137,6 +137,6 @@ contract CounterTest is AppGatewayBaseSetup { emit CounterScheduleResolved(creationTimestamp, block.timestamp); executeRequest(); - assertEq(block.timestamp, creationTimestamp + 100 + expiryTime); + assertLe(block.timestamp, creationTimestamp + 100 + expiryTime); } } From 81f55f65096af96cd94e8f2050ccd5c45c186d88 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Wed, 28 May 2025 20:18:20 +0530 Subject: [PATCH 081/130] fix: super token --- .../watcher/precompiles/WritePrecompile.sol | 2 +- test/apps/SuperToken.t.sol | 42 +++++++++---------- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/contracts/evmx/watcher/precompiles/WritePrecompile.sol b/contracts/evmx/watcher/precompiles/WritePrecompile.sol index c2134e2b..f2926ccd 100644 --- a/contracts/evmx/watcher/precompiles/WritePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/WritePrecompile.sol @@ -99,7 +99,7 @@ contract WritePrecompile is IPrecompile, WatcherBase, Ownable { // todo: can be changed to set the default gas limit for each chain if (queueParams_.overrideParams.gasLimit == 0) { - queueParams_.overrideParams.gasLimit = 1000000; + queueParams_.overrideParams.gasLimit = 10000000; } // For write precompile, encode the payload parameters diff --git a/test/apps/SuperToken.t.sol b/test/apps/SuperToken.t.sol index 6564eabb..0314b353 100644 --- a/test/apps/SuperToken.t.sol +++ b/test/apps/SuperToken.t.sol @@ -51,18 +51,7 @@ contract SuperTokenTest is AppGatewayBaseSetup { */ function setUp() public { deploy(); - deploySuperTokenApp(); - contractIds[0] = appContracts.superToken; - } - /** - * @notice Deploys the SuperToken application and its components - * @dev Creates both the deployer and gateway contracts with initial configuration - * - Sets up SuperToken with "SUPER TOKEN" name and "SUPER" symbol - * - Configures initial supply of 1 billion tokens - * - Sets up fee structure and auction manager integration - */ - function deploySuperTokenApp() internal { SuperTokenAppGateway superTokenApp = new SuperTokenAppGateway( address(addressResolver), owner, @@ -75,6 +64,7 @@ contract SuperTokenTest is AppGatewayBaseSetup { initialSupply_: 1000000000 ether }) ); + // Enable app gateways to do all operations in the Watcher: Read, Write and Schedule on EVMx // Watcher sets the limits for apps in this SOCKET protocol version depositNativeAndCredits(arbChainSlug, 1 ether, 0, address(superTokenApp)); @@ -83,6 +73,20 @@ contract SuperTokenTest is AppGatewayBaseSetup { superTokenApp: superTokenApp, superToken: superTokenApp.superToken() }); + + contractIds[0] = appContracts.superToken; + } + + /** + * @notice Deploys the SuperToken application and its components + * @dev Creates both the deployer and gateway contracts with initial configuration + * - Sets up SuperToken with "SUPER TOKEN" name and "SUPER" symbol + * - Configures initial supply of 1 billion tokens + * - Sets up fee structure and auction manager integration + */ + function deploySuperToken(uint32 chainSlug) internal { + appContracts.superTokenApp.deployContracts(chainSlug); + executeDeploy(IAppGateway(appContracts.superTokenApp), chainSlug, contractIds); } /** @@ -93,7 +97,7 @@ contract SuperTokenTest is AppGatewayBaseSetup { * - Correct setup of forwarder contracts for multi-chain communication */ function testContractDeployment() public { - executeDeploy(IAppGateway(appContracts.superTokenApp), arbChainSlug, contractIds); + deploySuperToken(arbChainSlug); (address onChain, address forwarder) = getOnChainAndForwarderAddresses( arbChainSlug, @@ -106,11 +110,13 @@ contract SuperTokenTest is AppGatewayBaseSetup { "SUPER TOKEN", "OnChain SuperToken name should be SUPER TOKEN" ); + assertEq( IForwarder(forwarder).getChainSlug(), arbChainSlug, "Forwarder SuperToken chainSlug should be arbChainSlug" ); + assertEq( IForwarder(forwarder).getOnChainAddress(), onChain, @@ -119,15 +125,6 @@ contract SuperTokenTest is AppGatewayBaseSetup { assertEq(SuperToken(onChain).owner(), owner, "SuperToken owner should be correct"); } - /** - * @notice Helper function to prepare the environment for transfer tests - * @dev Deploys necessary contracts on both Arbitrum and Optimism chains - */ - function beforeTransfer() internal { - executeDeploy(IAppGateway(appContracts.superTokenApp), arbChainSlug, contractIds); - executeDeploy(IAppGateway(appContracts.superTokenApp), optChainSlug, contractIds); - } - /** * @notice Tests multi-chain token transfers * @dev Verifies: @@ -137,7 +134,8 @@ contract SuperTokenTest is AppGatewayBaseSetup { * - Proper execution of multi-chain messaging */ function testTransfer() public { - beforeTransfer(); + deploySuperToken(arbChainSlug); + deploySuperToken(optChainSlug); (address onChainArb, address forwarderArb) = getOnChainAndForwarderAddresses( arbChainSlug, From 3fbfe360d7fc78eb69027d5a25434334729f8687 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Wed, 28 May 2025 21:52:19 +0530 Subject: [PATCH 082/130] fix: fee tests --- contracts/evmx/watcher/RequestHandler.sol | 4 +- test/FeesTest.t.sol | 64 ++++++++--------------- test/SetupTest.t.sol | 21 +++++++- 3 files changed, 44 insertions(+), 45 deletions(-) diff --git a/contracts/evmx/watcher/RequestHandler.sol b/contracts/evmx/watcher/RequestHandler.sol index 60cc4341..028726c8 100644 --- a/contracts/evmx/watcher/RequestHandler.sol +++ b/contracts/evmx/watcher/RequestHandler.sol @@ -40,6 +40,8 @@ contract RequestHandler is AddressResolverUtil, Ownable, IRequestHandler { /// @notice The metadata for a request mapping(uint40 => RequestParams) internal _requests; + error InsufficientMaxFees(); + event RequestSubmitted( bool hasWrite, uint40 requestCount, @@ -130,7 +132,7 @@ contract RequestHandler is AddressResolverUtil, Ownable, IRequestHandler { r.writeCount = result.writeCount; promiseList = result.promiseList; - if (result.totalEstimatedWatcherFees > maxFees_) revert InsufficientFees(); + if (result.totalEstimatedWatcherFees > maxFees_) revert InsufficientMaxFees(); if (r.writeCount == 0) _processBatch(currentBatch, r); emit RequestSubmitted( diff --git a/test/FeesTest.t.sol b/test/FeesTest.t.sol index 374c66ce..73016fdc 100644 --- a/test/FeesTest.t.sol +++ b/test/FeesTest.t.sol @@ -5,39 +5,34 @@ import "./apps/Counter.t.sol"; import "./SetupTest.t.sol"; contract FeesTest is AppGatewayBaseSetup { + uint32 feesChainSlug = arbChainSlug; uint256 constant depositAmount = 1 ether; uint256 constant feesAmount = 0.01 ether; + address receiver = address(uint160(c++)); address user = address(uint160(c++)); - uint32 feesChainSlug = arbChainSlug; - SocketContracts feesConfig; + SocketContracts feesConfig; CounterAppGateway counterGateway; function setUp() public { deploy(); - feesConfig = getSocketConfig(feesChainSlug); + feesConfig = getSocketConfig(feesChainSlug); counterGateway = new CounterAppGateway(address(addressResolver), feesAmount); - depositNativeAndCredits(feesChainSlug, 1 ether, 0, address(counterGateway)); + depositNativeAndCredits(feesChainSlug, 100 ether, 0, address(counterGateway)); bytes32[] memory contractIds = new bytes32[](1); contractIds[0] = counterGateway.counter(); + + // deploy counter app gateway + counterGateway.deployContracts(feesChainSlug); executeDeploy(IAppGateway(counterGateway), feesChainSlug, contractIds); } - function testWithdrawTransmitterFees() public { - uint256 initialFeesPlugBalance = address(feesConfig.feesPlug).balance; - - assertEq( - initialFeesPlugBalance, - address(feesConfig.feesPlug).balance, - "FeesPlug Balance should be correct" - ); - - uint256 transmitterReceiverBalanceBefore = address(receiver).balance; - uint256 withdrawAmount = feesManager.getAvailableCredits(transmitterEOA); - vm.startPrank(transmitterEOA); + function withdrawCredits(address from, uint256 withdrawAmount) public { + approveAppGateway(address(feesManager), from); + hoax(from); feesManager.withdrawCredits( feesChainSlug, address(feesConfig.testUSDC), @@ -45,33 +40,27 @@ contract FeesTest is AppGatewayBaseSetup { feesAmount, address(receiver) ); - vm.stopPrank(); executeRequest(); + } + + function testWithdrawTransmitterFees() public { + uint256 transmitterReceiverBalanceBefore = feesConfig.testUSDC.balanceOf(receiver); + uint256 withdrawAmount = feesManager.getAvailableCredits(transmitterEOA); + withdrawAmount = withdrawAmount - feesAmount; + withdrawCredits(transmitterEOA, withdrawAmount); assertEq( transmitterReceiverBalanceBefore + withdrawAmount, feesConfig.testUSDC.balanceOf(receiver), "Transmitter Balance should be correct" ); - assertEq( - initialFeesPlugBalance - withdrawAmount, - feesConfig.testUSDC.balanceOf(address(feesConfig.feesPlug)), - "FeesPlug Balance should be correct" - ); } function testWithdrawFeeTokensAppGateway() public { uint256 receiverBalanceBefore = feesConfig.testUSDC.balanceOf(receiver); uint256 withdrawAmount = 0.5 ether; - counterGateway.withdrawCredits( - feesChainSlug, - address(feesConfig.testUSDC), - withdrawAmount, - feesAmount, - receiver - ); - executeRequest(); + withdrawCredits(address(counterGateway), withdrawAmount); assertEq( receiverBalanceBefore + withdrawAmount, @@ -83,22 +72,13 @@ contract FeesTest is AppGatewayBaseSetup { function testWithdrawFeeTokensUser() public { depositNativeAndCredits(feesChainSlug, 1 ether, 0, user); - uint256 receiverBalanceBefore = feesConfig.testUSDC.balanceOf(user); + uint256 receiverBalanceBefore = feesConfig.testUSDC.balanceOf(receiver); uint256 withdrawAmount = 0.5 ether; - - vm.prank(user); - feesManager.withdrawCredits( - feesChainSlug, - address(feesConfig.testUSDC), - withdrawAmount, - feesAmount, - address(receiver) - ); - executeRequest(); + withdrawCredits(user, withdrawAmount); assertEq( receiverBalanceBefore + withdrawAmount, - feesConfig.testUSDC.balanceOf(user), + feesConfig.testUSDC.balanceOf(receiver), "Receiver Balance should be correct" ); } diff --git a/test/SetupTest.t.sol b/test/SetupTest.t.sol index d64ad8aa..57048049 100644 --- a/test/SetupTest.t.sol +++ b/test/SetupTest.t.sol @@ -422,7 +422,7 @@ contract FeesSetup is DeploySetup { _deploy(); depositNativeAndCredits(arbChainSlug, 100 ether, 100 ether, address(transmitterEOA)); - approveAppGateway(address(auctionManager), address(transmitterEOA), transmitterPrivateKey); + approveAppGateway(address(auctionManager), address(transmitterEOA)); } // mints test token and deposits the given native and credits to given `user_` @@ -482,7 +482,24 @@ contract FeesSetup is DeploySetup { assertEq(address(user_).balance, currentNative + native_, "User should have more native"); } - function approveAppGateway( + function approveAppGateway(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); + + assertEq( + feesManager.isApproved(user_, appGateway_), + true, + "App gateway should be approved" + ); + } + + function approveAppGatewayWithSignature( address appGateway_, address user_, uint256 userPrivateKey_ From c5ebf6044bc7f893a1c4caa593316fe7e0d998d5 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Wed, 28 May 2025 22:05:08 +0530 Subject: [PATCH 083/130] fix: old migration tests --- {test-old => test}/Migration.t.sol | 202 ++++++++++------------------- {test-old => test}/Storage.t.sol | 1 - 2 files changed, 68 insertions(+), 135 deletions(-) rename {test-old => test}/Migration.t.sol (50%) rename {test-old => test}/Storage.t.sol (99%) diff --git a/test-old/Migration.t.sol b/test/Migration.t.sol similarity index 50% rename from test-old/Migration.t.sol rename to test/Migration.t.sol index d6ed6d7f..10e4acd5 100644 --- a/test-old/Migration.t.sol +++ b/test/Migration.t.sol @@ -7,7 +7,7 @@ import "../contracts/evmx/watcher/Watcher.sol"; import "../contracts/evmx/helpers/Forwarder.sol"; import "../contracts/evmx/helpers/AsyncPromise.sol"; -contract MigrationTest is SetupTest { +contract MigrationTest is AppGatewayBaseSetup { // ERC1967Factory emits this event with both proxy and implementation addresses event Upgraded(address indexed proxy, address indexed implementation); event ImplementationUpdated(string contractName, address newImplementation); @@ -27,7 +27,7 @@ contract MigrationTest is SetupTest { bytes4 internal constant UNAUTHORIZED_SELECTOR = 0x82b42900; // bytes4(keccak256("Unauthorized()")) function setUp() public { - deployEVMxCore(); + deploy(); } function getImplementation(address proxy) internal view returns (address) { @@ -67,147 +67,87 @@ contract MigrationTest is SetupTest { // Verify state is preserved assertEq(addressResolver.owner(), watcherEOA, "Owner should be preserved after upgrade"); assertEq( - address(addressResolver.watcherPrecompile__()), - address(watcherPrecompile), - "WatcherPrecompile address should be preserved" + address(addressResolver.watcher__()), + address(watcher), + "Watcher address should be preserved" ); } - function testWatcherPrecompileUpgrade() public { + function testWatcherUpgrade() public { // Deploy new implementation - WatcherPrecompile newImpl = new WatcherPrecompile(); + Watcher newImpl = new Watcher(); // Store old implementation address - address oldImpl = getImplementation(address(watcherPrecompile)); + address oldImpl = getImplementation(address(watcher)); // Upgrade proxy to new implementation vm.startPrank(watcherEOA); vm.expectEmit(true, true, true, true, address(proxyFactory)); - emit Upgraded(address(watcherPrecompile), address(newImpl)); - proxyFactory.upgradeAndCall(address(watcherPrecompile), address(newImpl), ""); + emit Upgraded(address(watcher), address(newImpl)); + proxyFactory.upgradeAndCall(address(watcher), address(newImpl), ""); vm.stopPrank(); // Verify upgrade was successful - address newImplAddr = getImplementation(address(watcherPrecompile)); + address newImplAddr = getImplementation(address(watcher)); assertNotEq(oldImpl, newImplAddr, "Implementation should have changed"); assertEq(newImplAddr, address(newImpl), "New implementation not set correctly"); // Verify state is preserved - assertEq(watcherPrecompile.owner(), watcherEOA, "Owner should be preserved after upgrade"); + assertEq(watcher.owner(), watcherEOA, "Owner should be preserved after upgrade"); assertEq( - address(watcherPrecompile.watcherPrecompileConfig__()), - address(watcherPrecompileConfig), - "WatcherPrecompileConfig should be preserved" + address(watcher.configurations__()), + address(configurations), + "Configurations should be preserved" ); - assertEq(watcherPrecompile.evmxSlug(), evmxSlug, "EvmxSlug should be preserved"); + assertEq(watcher.evmxSlug(), evmxSlug, "EvmxSlug should be preserved"); } - function testWatcherPrecompileLimitsUpgrade() public { - // Deploy new implementation - WatcherPrecompileLimits newImpl = new WatcherPrecompileLimits(); - - // Store old implementation address - address oldImpl = getImplementation(address(watcherPrecompileLimits)); - - // Upgrade proxy to new implementation - vm.startPrank(watcherEOA); - vm.expectEmit(true, true, true, true, address(proxyFactory)); - emit Upgraded(address(watcherPrecompileLimits), address(newImpl)); - proxyFactory.upgradeAndCall(address(watcherPrecompileLimits), address(newImpl), ""); - vm.stopPrank(); - - // Verify upgrade was successful - address newImplAddr = getImplementation(address(watcherPrecompileLimits)); - assertNotEq(oldImpl, newImplAddr, "Implementation should have changed"); - assertEq(newImplAddr, address(newImpl), "New implementation not set correctly"); - - // Verify state is preserved - assertEq(watcherPrecompile.owner(), watcherEOA, "Owner should be preserved after upgrade"); - assertEq( - address(watcherPrecompileLimits.addressResolver__()), - address(addressResolver), - "AddressResolver should be preserved" - ); - } - - function testWatcherPrecompileConfigUpgrade() public { - // Deploy new implementation - WatcherPrecompileConfig newImpl = new WatcherPrecompileConfig(); - - // Store old implementation address - address oldImpl = getImplementation(address(watcherPrecompileConfig)); - - // Upgrade proxy to new implementation - vm.startPrank(watcherEOA); - vm.expectEmit(true, true, true, true, address(proxyFactory)); - emit Upgraded(address(watcherPrecompileConfig), address(newImpl)); - proxyFactory.upgradeAndCall(address(watcherPrecompileConfig), address(newImpl), ""); - vm.stopPrank(); - - // Verify upgrade was successful - address newImplAddr = getImplementation(address(watcherPrecompileConfig)); - assertNotEq(oldImpl, newImplAddr, "Implementation should have changed"); - assertEq(newImplAddr, address(newImpl), "New implementation not set correctly"); - - // Verify state is preserved - assertEq( - watcherPrecompileConfig.owner(), - watcherEOA, - "Owner should be preserved after upgrade" - ); - assertEq( - address(watcherPrecompileConfig.addressResolver__()), - address(addressResolver), - "AddressResolver should be preserved" - ); - assertEq(watcherPrecompileConfig.evmxSlug(), 1, "EvmxSlug should be preserved"); - } - - function testUpgradeWithInitializationData() public { - // Deploy new implementation - MockWatcherPrecompileImpl newImpl = new MockWatcherPrecompileImpl(); - - // Store old implementation address for verification - address oldImpl = getImplementation(address(watcherPrecompile)); - - // Prepare initialization data with new defaultLimit - uint256 newDefaultLimit = 2000; - bytes memory initData = abi.encodeWithSelector( - MockWatcherPrecompileImpl.mockReinitialize.selector, - watcherEOA, - address(addressResolver), - newDefaultLimit - ); - - // Upgrade proxy with initialization data - vm.startPrank(watcherEOA); - vm.expectEmit(true, true, true, true, address(proxyFactory)); - emit Upgraded(address(watcherPrecompile), address(newImpl)); - proxyFactory.upgradeAndCall(address(watcherPrecompile), address(newImpl), initData); - vm.stopPrank(); - - // Verify upgrade and initialization was successful - address newImplAddr = getImplementation(address(watcherPrecompile)); - assertNotEq(oldImpl, newImplAddr, "Implementation should have changed"); - assertEq(newImplAddr, address(newImpl), "New implementation not set correctly"); - assertEq(watcherPrecompile.evmxSlug(), evmxSlug, "EvmxSlug should be preserved"); - } + // function testUpgradeWithInitializationData() public { + // // Deploy new implementation + // MockWatcherImpl newImpl = new MockWatcherImpl(); + + // // Store old implementation address for verification + // address oldImpl = getImplementation(address(watcher)); + + // // Prepare initialization data with new defaultLimit + // uint256 newDefaultLimit = 2000; + // bytes memory initData = abi.encodeWithSelector( + // MockWatcherImpl.mockReinitialize.selector, + // watcherEOA, + // address(addressResolver), + // newDefaultLimit + // ); + + // // Upgrade proxy with initialization data + // vm.startPrank(watcherEOA); + // vm.expectEmit(true, true, true, true, address(proxyFactory)); + // emit Upgraded(address(watcher), address(newImpl)); + // proxyFactory.upgradeAndCall(address(watcher), address(newImpl), initData); + // vm.stopPrank(); + + // // Verify upgrade and initialization was successful + // address newImplAddr = getImplementation(address(watcher)); + // assertNotEq(oldImpl, newImplAddr, "Implementation should have changed"); + // assertEq(newImplAddr, address(newImpl), "New implementation not set correctly"); + // assertEq(watcher.evmxSlug(), evmxSlug, "EvmxSlug should be preserved"); + // } function testUnauthorizedUpgrade() public { // Deploy new implementation - WatcherPrecompile newImpl = new WatcherPrecompile(); + Watcher newImpl = new Watcher(); + address oldImpl = getImplementation(address(watcher)); // Try to upgrade from unauthorized account address unauthorizedUser = address(0xBEEF); vm.startPrank(unauthorizedUser); vm.expectRevert(UNAUTHORIZED_SELECTOR); - proxyFactory.upgradeAndCall(address(watcherPrecompile), address(newImpl), ""); + proxyFactory.upgradeAndCall(address(watcher), address(newImpl), ""); vm.stopPrank(); // Verify implementation was not changed assertEq( - getImplementation(address(watcherPrecompile)), - address(watcherPrecompileImpl), + getImplementation(address(watcher)), + oldImpl, "Implementation should not have changed" ); } @@ -217,30 +157,26 @@ contract MigrationTest is SetupTest { Forwarder newImpl = new Forwarder(); // Get current implementation from beacon - address oldImpl = getBeaconImplementation(address(addressResolver.forwarderBeacon())); + address oldImpl = getBeaconImplementation(address(asyncDeployer.forwarderBeacon())); // Upgrade beacon to new implementation vm.startPrank(watcherEOA); - vm.expectEmit(true, true, true, true, address(addressResolver)); + vm.expectEmit(true, true, true, true, address(asyncDeployer)); emit ImplementationUpdated("Forwarder", address(newImpl)); - addressResolver.setForwarderImplementation(address(newImpl)); + asyncDeployer.setForwarderImplementation(address(newImpl)); vm.stopPrank(); // Verify upgrade was successful - address newImplAddr = getBeaconImplementation(address(addressResolver.forwarderBeacon())); + address newImplAddr = getBeaconImplementation(address(asyncDeployer.forwarderBeacon())); assertNotEq(oldImpl, newImplAddr, "Implementation should have changed"); assertEq(newImplAddr, address(newImpl), "New implementation not set correctly"); // Deploy a new forwarder and verify it uses the correct beacon - address newForwarder = addressResolver.getOrDeployForwarderContract( - address(this), - address(0x123), - 1 - ); + address newForwarder = asyncDeployer.getOrDeployForwarderContract(address(0x123), 1); address beacon = getBeacon(newForwarder); assertEq( beacon, - address(addressResolver.forwarderBeacon()), + address(asyncDeployer.forwarderBeacon()), "Beacon address not set correctly" ); @@ -258,28 +194,26 @@ contract MigrationTest is SetupTest { AsyncPromise newImpl = new AsyncPromise(); // Get current implementation from beacon - address oldImpl = getBeaconImplementation(address(addressResolver.asyncPromiseBeacon())); + address oldImpl = getBeaconImplementation(address(asyncDeployer.asyncPromiseBeacon())); // Upgrade beacon to new implementation - vm.startPrank(watcherEOA); - vm.expectEmit(true, true, true, true, address(addressResolver)); + hoax(watcherEOA); + vm.expectEmit(true, true, true, false); emit ImplementationUpdated("AsyncPromise", address(newImpl)); - addressResolver.setAsyncPromiseImplementation(address(newImpl)); - vm.stopPrank(); + asyncDeployer.setAsyncPromiseImplementation(address(newImpl)); // Verify upgrade was successful - address newImplAddr = getBeaconImplementation( - address(addressResolver.asyncPromiseBeacon()) - ); + address newImplAddr = getBeaconImplementation(address(asyncDeployer.asyncPromiseBeacon())); assertNotEq(oldImpl, newImplAddr, "Implementation should have changed"); assertEq(newImplAddr, address(newImpl), "New implementation not set correctly"); // Deploy a new async promise and verify it uses the correct beacon - address newPromise = addressResolver.deployAsyncPromiseContract(address(this)); + hoax(address(watcher)); + address newPromise = asyncDeployer.deployAsyncPromiseContract(address(this), 1); address beacon = getBeacon(newPromise); assertEq( beacon, - address(addressResolver.asyncPromiseBeacon()), + address(asyncDeployer.asyncPromiseBeacon()), "Beacon address not set correctly" ); @@ -303,22 +237,22 @@ contract MigrationTest is SetupTest { vm.startPrank(unauthorizedUser); // Try upgrading forwarder beacon vm.expectRevert(abi.encodeWithSelector(Ownable.Unauthorized.selector)); - addressResolver.setForwarderImplementation(address(newForwarderImpl)); + asyncDeployer.setForwarderImplementation(address(newForwarderImpl)); // Try upgrading async promise beacon vm.expectRevert(abi.encodeWithSelector(Ownable.Unauthorized.selector)); - addressResolver.setAsyncPromiseImplementation(address(newAsyncPromiseImpl)); + asyncDeployer.setAsyncPromiseImplementation(address(newAsyncPromiseImpl)); vm.stopPrank(); // Verify implementations were not changed assertNotEq( - getBeaconImplementation(address(addressResolver.forwarderBeacon())), + getBeaconImplementation(address(asyncDeployer.forwarderBeacon())), address(newForwarderImpl), "Forwarder implementation should not have changed" ); assertNotEq( - getBeaconImplementation(address(addressResolver.asyncPromiseBeacon())), + getBeaconImplementation(address(asyncDeployer.asyncPromiseBeacon())), address(newAsyncPromiseImpl), "AsyncPromise implementation should not have changed" ); diff --git a/test-old/Storage.t.sol b/test/Storage.t.sol similarity index 99% rename from test-old/Storage.t.sol rename to test/Storage.t.sol index 523d7834..65e6c1a8 100644 --- a/test-old/Storage.t.sol +++ b/test/Storage.t.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import "./DeliveryHelper.t.sol"; // contract StorageTest is DeliveryHelperTest { // DeliveryHelper public deliveryHelperImpl; From 0f63a0a49fd82eaf104231efa50dfcd3aca70355 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Wed, 28 May 2025 23:47:32 +0530 Subject: [PATCH 084/130] fix: bugs --- contracts/evmx/AuctionManager.sol | 12 ++------- contracts/evmx/fees/Credit.sol | 12 +++++++-- contracts/evmx/helpers/DeployForwarder.sol | 2 ++ contracts/evmx/helpers/Forwarder.sol | 22 +++++++--------- contracts/evmx/interfaces/IConfigurations.sol | 2 +- contracts/evmx/interfaces/IWatcher.sol | 2 +- contracts/evmx/watcher/Configurations.sol | 7 ++--- contracts/evmx/watcher/RequestHandler.sol | 26 ++++++++++--------- .../watcher/precompiles/ReadPrecompile.sol | 6 ++--- .../precompiles/SchedulePrecompile.sol | 9 +++---- .../watcher/precompiles/WritePrecompile.sol | 10 +++---- test/SetupTest.t.sol | 4 +-- 12 files changed, 54 insertions(+), 60 deletions(-) diff --git a/contracts/evmx/AuctionManager.sol b/contracts/evmx/AuctionManager.sol index dc6a9e27..54483517 100644 --- a/contracts/evmx/AuctionManager.sol +++ b/contracts/evmx/AuctionManager.sol @@ -119,6 +119,7 @@ contract AuctionManager is AuctionManagerStorage, AccessControl, AppGatewayBase // create a new bid Bid memory newBid = Bid({fee: bidFees, transmitter: transmitter, extraData: extraData}); + address oldTransmitter = winningBids[requestCount_].transmitter; winningBids[requestCount_] = newBid; // end the auction if the no auction end delay @@ -128,9 +129,7 @@ contract AuctionManager is AuctionManagerStorage, AccessControl, AppGatewayBase auctionEndDelaySeconds, deductScheduleFees( transmitter, - winningBids[requestCount_].transmitter == address(0) - ? address(this) - : winningBids[requestCount_].transmitter, + oldTransmitter == address(0) ? address(this) : newBid.transmitter, auctionEndDelaySeconds ), address(this), @@ -221,13 +220,6 @@ contract AuctionManager is AuctionManagerStorage, AccessControl, AppGatewayBase QueueParams memory queueParams; queueParams.overrideParams = overrideParams; - queueParams.transaction = Transaction({ - chainSlug: evmxSlug, - target: address(this), - payload: payload_ - }); - queueParams.switchboardType = sbType; - // queue and create request watcher__().queueAndSubmit(queueParams, maxFees_, address(this), consumeFrom_, bytes("")); } diff --git a/contracts/evmx/fees/Credit.sol b/contracts/evmx/fees/Credit.sol index ebe728f1..164cf3eb 100644 --- a/contracts/evmx/fees/Credit.sol +++ b/contracts/evmx/fees/Credit.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.21; import {Ownable} from "solady/auth/Ownable.sol"; import "solady/utils/Initializable.sol"; import "solady/utils/ECDSA.sol"; +import "solady/utils/SafeTransferLib.sol"; import "../interfaces/IFeesManager.sol"; import "../interfaces/IFeesPlug.sol"; @@ -123,8 +124,14 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressR function wrap(address receiver_) external payable override { UserCredits storage userCredit = userCredits[receiver_]; - userCredit.totalCredits += msg.value; - emit CreditsWrapped(receiver_, msg.value); + + uint256 amount = msg.value; + if (amount == 0) revert InvalidAmount(); + userCredit.totalCredits += amount; + + // reverts if transfer fails + SafeTransferLib.safeTransferETH(address(feesPool), amount); + emit CreditsWrapped(receiver_, amount); } function unwrap(uint256 amount_, address receiver_) external { @@ -246,6 +253,7 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressR OverrideParams memory overrideParams; overrideParams.callType = WRITE; overrideParams.writeFinality = WriteFinality.LOW; + // todo: can add gas limit here QueueParams memory queueParams; queueParams.overrideParams = overrideParams; diff --git a/contracts/evmx/helpers/DeployForwarder.sol b/contracts/evmx/helpers/DeployForwarder.sol index 1a222ed2..17fd5bfa 100644 --- a/contracts/evmx/helpers/DeployForwarder.sol +++ b/contracts/evmx/helpers/DeployForwarder.sol @@ -7,6 +7,7 @@ import {IDeployForwarder} from "../interfaces/IDeployForwarder.sol"; import "./AddressResolverUtil.sol"; import {AsyncModifierNotSet} from "../../utils/common/Errors.sol"; import {QueueParams, OverrideParams, Transaction} from "../../utils/common/Structs.sol"; +import {WRITE} from "../../utils/common/Constants.sol"; import {encodeAppGatewayId} from "../../utils/common/IdUtils.sol"; /// @title DeployerGateway @@ -41,6 +42,7 @@ contract DeployForwarder is AddressResolverUtil, IDeployForwarder { QueueParams memory queueParams; queueParams.overrideParams = overrideParams; + queueParams.overrideParams.callType = WRITE; queueParams.switchboardType = deployerSwitchboardType; queueParams.transaction = Transaction({ chainSlug: chainSlug_, diff --git a/contracts/evmx/helpers/Forwarder.sol b/contracts/evmx/helpers/Forwarder.sol index 7745bc1d..ec9d6492 100644 --- a/contracts/evmx/helpers/Forwarder.sol +++ b/contracts/evmx/helpers/Forwarder.sol @@ -77,18 +77,14 @@ contract Forwarder is ForwarderStorage, Initializable, AddressResolverUtil { .getOverrideParams(); // Queue the call in the middleware. - watcher__().queue( - QueueParams({ - overrideParams: overrideParams, - transaction: Transaction({ - chainSlug: chainSlug, - target: onChainAddress, - payload: msg.data - }), - asyncPromise: address(0), - switchboardType: sbType - }), - msgSender - ); + QueueParams memory queueParams; + queueParams.overrideParams = overrideParams; + queueParams.transaction = Transaction({ + chainSlug: chainSlug, + target: onChainAddress, + payload: msg.data + }); + queueParams.switchboardType = sbType; + watcher__().queue(queueParams, msgSender); } } diff --git a/contracts/evmx/interfaces/IConfigurations.sol b/contracts/evmx/interfaces/IConfigurations.sol index 964633cf..fd7921a4 100644 --- a/contracts/evmx/interfaces/IConfigurations.sol +++ b/contracts/evmx/interfaces/IConfigurations.sol @@ -45,7 +45,7 @@ interface IConfigurations { /// @dev This function is used to verify if a plug deployed on a chain slug is valid connection to the app gateway function setIsValidPlug(bool isValid_, uint32 chainSlug_, address plug_) external; - function setPlugConfigs(AppGatewayConfig[] calldata configs_) external; + function setAppGatewayConfigs(AppGatewayConfig[] calldata configs_) external; /// @notice Sets the socket for a chain slug function setSocket(uint32 chainSlug_, address socket_) external; diff --git a/contracts/evmx/interfaces/IWatcher.sol b/contracts/evmx/interfaces/IWatcher.sol index a0eac8fa..9aea4486 100644 --- a/contracts/evmx/interfaces/IWatcher.sol +++ b/contracts/evmx/interfaces/IWatcher.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; import "../../utils/common/Errors.sol"; -import {Bid, AppGatewayConfig, WriteFinality, PlugConfig, DigestParams, QueueParams, PayloadParams, RequestParams, WatcherMultiCallParams} from "../../utils/common/Structs.sol"; +import "../../utils/common/Structs.sol"; import "./IRequestHandler.sol"; import "./IConfigurations.sol"; diff --git a/contracts/evmx/watcher/Configurations.sol b/contracts/evmx/watcher/Configurations.sol index 39267a67..ddc42307 100644 --- a/contracts/evmx/watcher/Configurations.sol +++ b/contracts/evmx/watcher/Configurations.sol @@ -73,13 +73,10 @@ contract Configurations is IConfigurations, Initializable, WatcherBase, Ownable /// @dev Only callable by the watcher /// @dev This helps in verifying that plugs are called by respective app gateways /// @param configs_ Array of configurations containing app gateway, network, plug, and switchboard details - function setPlugConfigs(AppGatewayConfig[] calldata configs_) external onlyWatcher { + function setAppGatewayConfigs(AppGatewayConfig[] calldata configs_) external onlyWatcher { for (uint256 i = 0; i < configs_.length; i++) { // Store the plug configuration for this network and plug - _plugConfigs[configs_[i].chainSlug][configs_[i].plug] = PlugConfig({ - appGatewayId: configs_[i].plugConfig.appGatewayId, - switchboard: configs_[i].plugConfig.switchboard - }); + _plugConfigs[configs_[i].chainSlug][configs_[i].plug] = configs_[i].plugConfig; emit PlugAdded( configs_[i].plugConfig.appGatewayId, diff --git a/contracts/evmx/watcher/RequestHandler.sol b/contracts/evmx/watcher/RequestHandler.sol index 028726c8..b3fcb1c8 100644 --- a/contracts/evmx/watcher/RequestHandler.sol +++ b/contracts/evmx/watcher/RequestHandler.sol @@ -115,6 +115,7 @@ contract RequestHandler is AddressResolverUtil, Ownable, IRequestHandler { requestCount = nextRequestCount++; uint40 currentBatch = nextBatchCount; + RequestParams storage r = _requests[requestCount]; r.requestTrackingParams.payloadsRemaining = queueParams_.length; r.requestFeesDetails.maxFees = maxFees_; @@ -198,6 +199,7 @@ contract RequestHandler is AddressResolverUtil, Ownable, IRequestHandler { } // get the switchboard address from the configurations + // returns address(0) for schedule precompile and reads if sb type not set address switchboard = watcher__().configurations__().switchboards( queuePayloadParam.transaction.chainSlug, queuePayloadParam.switchboardType @@ -218,23 +220,22 @@ contract RequestHandler is AddressResolverUtil, Ownable, IRequestHandler { nextBatchCount, payloadCount, switchboard, + // todo: add evmx chain slug if schedule or read? queuePayloadParam.transaction.chainSlug ); _batchPayloadIds[nextBatchCount].push(payloadId); // create prev digest hash - PayloadParams memory p = PayloadParams({ - requestCount: requestCount_, - batchCount: nextBatchCount, - payloadCount: payloadCount, - callType: callType, - asyncPromise: queueParams_[i].asyncPromise, - appGateway: appGateway_, - payloadId: payloadId, - resolvedAt: 0, - deadline: 0, - precompileData: precompileData - }); + PayloadParams memory p; + p.requestCount = requestCount_; + p.batchCount = nextBatchCount; + p.payloadCount = payloadCount; + p.callType = callType; + p.asyncPromise = queueParams_[i].asyncPromise; + p.appGateway = appGateway_; + p.payloadId = payloadId; + p.precompileData = precompileData; + result.promiseList[i] = queueParams_[i].asyncPromise; result.payloadParams[i] = p; _payloads[payloadId] = p; @@ -263,6 +264,7 @@ contract RequestHandler is AddressResolverUtil, Ownable, IRequestHandler { : auctionManager_; } + // called when processing batch first time or being retried function _processBatch(uint40 batchCount_, RequestParams storage r) internal { bytes32[] memory payloadIds = _batchPayloadIds[batchCount_]; diff --git a/contracts/evmx/watcher/precompiles/ReadPrecompile.sol b/contracts/evmx/watcher/precompiles/ReadPrecompile.sol index dc67c650..cacfb31f 100644 --- a/contracts/evmx/watcher/precompiles/ReadPrecompile.sol +++ b/contracts/evmx/watcher/precompiles/ReadPrecompile.sol @@ -23,7 +23,7 @@ contract ReadPrecompile is IPrecompile, WatcherBase { expiryTime = expiryTime_; } - function getPrecompileFees(bytes memory) external view returns (uint256) { + function getPrecompileFees(bytes memory) public view returns (uint256) { return readFees; } @@ -43,7 +43,7 @@ contract ReadPrecompile is IPrecompile, WatcherBase { queueParams_.transaction, queueParams_.overrideParams.readAtBlockNumber ); - estimatedFees = readFees; + estimatedFees = getPrecompileFees(precompileData); } /// @notice Handles payload processing and returns fees @@ -58,9 +58,9 @@ contract ReadPrecompile is IPrecompile, WatcherBase { onlyRequestHandler returns (uint256 fees, uint256 deadline, bytes memory precompileData) { - fees = readFees; deadline = block.timestamp + expiryTime; precompileData = payloadParams.precompileData; + fees = getPrecompileFees(payloadParams.precompileData); (Transaction memory transaction, uint256 readAtBlockNumber) = abi.decode( payloadParams.precompileData, diff --git a/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol b/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol index dae36ad2..92be8e0f 100644 --- a/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol @@ -50,7 +50,7 @@ contract SchedulePrecompile is IPrecompile, WatcherBase { expiryTime = expiryTime_; } - function getPrecompileFees(bytes memory precompileData_) external view returns (uint256) { + function getPrecompileFees(bytes memory precompileData_) public view returns (uint256) { uint256 delayInSeconds = abi.decode(precompileData_, (uint256)); return scheduleFeesPerSecond * delayInSeconds + scheduleCallbackFees; } @@ -104,10 +104,7 @@ contract SchedulePrecompile is IPrecompile, WatcherBase { // For schedule precompile, encode the payload parameters precompileData = abi.encode(queueParams_.overrideParams.delayInSeconds, 0); - estimatedFees = - scheduleFeesPerSecond * - queueParams_.overrideParams.delayInSeconds + - scheduleCallbackFees; + estimatedFees = getPrecompileFees(precompileData); } /// @notice Handles payload processing and returns fees @@ -127,7 +124,7 @@ contract SchedulePrecompile is IPrecompile, WatcherBase { uint256 executeAfter = block.timestamp + delayInSeconds; deadline = executeAfter + expiryTime; precompileData = abi.encode(delayInSeconds, executeAfter); - fees = scheduleFeesPerSecond * delayInSeconds + scheduleCallbackFees; + fees = getPrecompileFees(precompileData); // emits event for watcher to track schedule and resolve when deadline is reached emit ScheduleRequested(payloadParams.payloadId, executeAfter, deadline); diff --git a/contracts/evmx/watcher/precompiles/WritePrecompile.sol b/contracts/evmx/watcher/precompiles/WritePrecompile.sol index f2926ccd..6bda9002 100644 --- a/contracts/evmx/watcher/precompiles/WritePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/WritePrecompile.sol @@ -59,7 +59,7 @@ contract WritePrecompile is IPrecompile, WatcherBase, Ownable { expiryTime = expiryTime_; } - function getPrecompileFees(bytes memory) external view returns (uint256) { + function getPrecompileFees(bytes memory) public view returns (uint256) { return writeFees; } @@ -115,7 +115,7 @@ contract WritePrecompile is IPrecompile, WatcherBase, Ownable { ) ); - estimatedFees = writeFees; + estimatedFees = getPrecompileFees(precompileData); } /// @notice Handles payload processing and returns fees @@ -130,9 +130,6 @@ contract WritePrecompile is IPrecompile, WatcherBase, Ownable { onlyRequestHandler returns (uint256 fees, uint256 deadline, bytes memory precompileData) { - fees = writeFees; - deadline = block.timestamp + expiryTime; - ( address appGateway, Transaction memory transaction, @@ -144,7 +141,10 @@ contract WritePrecompile is IPrecompile, WatcherBase, Ownable { payloadParams.precompileData, (address, Transaction, WriteFinality, uint256, uint256, address) ); + precompileData = payloadParams.precompileData; + deadline = block.timestamp + expiryTime; + fees = getPrecompileFees(payloadParams.precompileData); bytes32 prevBatchDigestHash = getPrevBatchDigestHash(payloadParams.batchCount); diff --git a/test/SetupTest.t.sol b/test/SetupTest.t.sol index 57048049..185441b8 100644 --- a/test/SetupTest.t.sol +++ b/test/SetupTest.t.sol @@ -191,7 +191,7 @@ contract DeploySetup is SetupStore { watcherMultiCall( address(configurations), - abi.encodeWithSelector(Configurations.setPlugConfigs.selector, configs) + abi.encodeWithSelector(Configurations.setAppGatewayConfigs.selector, configs) ); } @@ -877,7 +877,7 @@ contract WatcherSetup is AuctionSetup { } watcherMultiCall( address(configurations), - abi.encodeWithSelector(Configurations.setPlugConfigs.selector, configs) + abi.encodeWithSelector(Configurations.setAppGatewayConfigs.selector, configs) ); } } From 1008181a507d869a3de06dbfec28b16b1b9171a9 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Thu, 29 May 2025 14:05:42 +0530 Subject: [PATCH 085/130] fix: include addr in sign --- contracts/evmx/watcher/Watcher.sol | 43 ++++++++++++++++++------------ contracts/utils/common/Structs.sol | 23 ++++++++-------- test/SetupTest.t.sol | 11 +++++--- test/TriggerTest.t.sol | 9 ++++--- 4 files changed, 51 insertions(+), 35 deletions(-) diff --git a/contracts/evmx/watcher/Watcher.sol b/contracts/evmx/watcher/Watcher.sol index db3ea41b..c6190c5d 100644 --- a/contracts/evmx/watcher/Watcher.sol +++ b/contracts/evmx/watcher/Watcher.sol @@ -30,15 +30,6 @@ contract Watcher is Trigger { promiseResolver__ = IPromiseResolver(promiseResolver_); } - function setTriggerFees( - uint256 triggerFees_, - uint256 nonce_, - bytes memory signature_ - ) external { - _validateSignature(abi.encode(triggerFees_), nonce_, signature_); - _setTriggerFees(triggerFees_); - } - function isWatcher(address account_) public view override returns (bool) { return account_ == address(requestHandler__) || @@ -129,14 +120,24 @@ contract Watcher is Trigger { delete payloadQueue; } - function callAppGateways(WatcherMultiCallParams[] memory params_) external { - for (uint40 i = 0; i < params_.length; i++) { - _validateSignature(params_[i].data, params_[i].nonce, params_[i].signature); - TriggerParams memory params = abi.decode(params_[i].data, (TriggerParams)); - _callAppGateways(params); + function callAppGateways(WatcherMultiCallParams memory params_) external { + _validateSignature(address(this), params_.data, params_.nonce, params_.signature); + TriggerParams[] memory params = abi.decode(params_.data, (TriggerParams[])); + + for (uint40 i = 0; i < params.length; i++) { + _callAppGateways(params[i]); } } + function setTriggerFees( + uint256 triggerFees_, + uint256 nonce_, + bytes memory signature_ + ) external { + _validateSignature(address(this), abi.encode(triggerFees_), nonce_, signature_); + _setTriggerFees(triggerFees_); + } + function getCurrentRequestCount() public view returns (uint40) { return requestHandler__.nextRequestCount(); } @@ -176,8 +177,12 @@ contract Watcher is Trigger { // can be also used to do msg.sender check related function in other contracts like withdraw credits from fees manager and set core app-gateways in configurations function watcherMultiCall(WatcherMultiCallParams[] memory params_) external payable { for (uint40 i = 0; i < params_.length; i++) { - if (params_[i].contractAddress == address(0)) revert InvalidContract(); - _validateSignature(params_[i].data, params_[i].nonce, params_[i].signature); + _validateSignature( + params_[i].contractAddress, + params_[i].data, + params_[i].nonce, + params_[i].signature + ); // call the contract (bool success, ) = params_[i].contractAddress.call(params_[i].data); @@ -190,16 +195,20 @@ contract Watcher is Trigger { /// @param nonce_ The nonce of the signature /// @param signature_ The signature to verify function _validateSignature( + address contractAddress_, bytes memory data_, uint256 nonce_, bytes memory signature_ ) internal { + if (contractAddress_ == address(0)) revert InvalidContract(); if (data_.length == 0) revert InvalidData(); if (signature_.length == 0) revert InvalidSignature(); if (isNonceUsed[nonce_]) revert NonceUsed(); isNonceUsed[nonce_] = true; - bytes32 digest = keccak256(abi.encode(address(this), evmxSlug, nonce_, data_)); + bytes32 digest = keccak256( + abi.encode(address(this), evmxSlug, nonce_, contractAddress_, data_) + ); // check if signature is valid if (_recoverSigner(digest, signature_) != owner()) revert InvalidSignature(); diff --git a/contracts/utils/common/Structs.sol b/contracts/utils/common/Structs.sol index 24c834d0..13cad4a0 100644 --- a/contracts/utils/common/Structs.sol +++ b/contracts/utils/common/Structs.sol @@ -76,12 +76,6 @@ struct PromiseReturnData { bytes returnData; } // AM -struct Bid { - uint256 fee; - address transmitter; - bytes extraData; -} - struct ExecuteParams { bytes4 callType; uint40 requestCount; @@ -103,11 +97,6 @@ struct TransmissionParams { bytes transmitterSignature; } -struct UserCredits { - uint256 totalCredits; - uint256 blockedCredits; -} - struct WatcherMultiCallParams { address contractAddress; bytes data; @@ -122,6 +111,17 @@ struct CreateRequestResult { PayloadParams[] payloadParams; } +struct Bid { + uint256 fee; + address transmitter; + bytes extraData; +} + +struct UserCredits { + uint256 totalCredits; + uint256 blockedCredits; +} + // digest: struct DigestParams { address socket; @@ -137,6 +137,7 @@ struct DigestParams { bytes32 prevDigestsHash; bytes extraData; } + // App gateway base: struct OverrideParams { bytes4 callType; diff --git a/test/SetupTest.t.sol b/test/SetupTest.t.sol index 185441b8..0cb38ec8 100644 --- a/test/SetupTest.t.sol +++ b/test/SetupTest.t.sol @@ -357,14 +357,19 @@ contract DeploySetup is SetupStore { contractAddress: contractAddress_, data: data_, nonce: watcherNonce, - signature: _createWatcherSignature(data_) + signature: _createWatcherSignature(contractAddress_, data_) }); watcherNonce++; watcher.watcherMultiCall(params); } - function _createWatcherSignature(bytes memory data_) internal view returns (bytes memory) { - bytes32 digest = keccak256(abi.encode(address(watcher), evmxSlug, watcherNonce, data_)); + function _createWatcherSignature( + address contractAddress_, + bytes memory data_ + ) internal view returns (bytes memory) { + bytes32 digest = keccak256( + abi.encode(address(watcher), evmxSlug, watcherNonce, contractAddress_, data_) + ); return _createSignature(digest, watcherPrivateKey); } diff --git a/test/TriggerTest.t.sol b/test/TriggerTest.t.sol index b4633de9..a4231e52 100644 --- a/test/TriggerTest.t.sol +++ b/test/TriggerTest.t.sol @@ -67,7 +67,8 @@ contract TriggerTest is AppGatewayBaseSetup { ); counter.increaseOnGateway(incrementValue); - TriggerParams memory params = TriggerParams({ + TriggerParams[] memory params = new TriggerParams[](1); + params[0] = TriggerParams({ triggerId: triggerId, chainSlug: arbChainSlug, appGatewayId: encodeAppGatewayId(address(gateway)), @@ -77,12 +78,12 @@ contract TriggerTest is AppGatewayBaseSetup { }); bytes memory data = abi.encode(params); - WatcherMultiCallParams[] memory watcherParams = new WatcherMultiCallParams[](1); - watcherParams[0] = WatcherMultiCallParams({ + WatcherMultiCallParams memory watcherParams; + watcherParams = WatcherMultiCallParams({ contractAddress: address(watcher), data: data, nonce: watcherNonce, - signature: _createWatcherSignature(data) + signature: _createWatcherSignature(address(watcher), data) }); watcherNonce++; watcher.callAppGateways(watcherParams); From 44917b03bacfee4206fdfcb6e24c307aa569d6f4 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Thu, 29 May 2025 14:27:06 +0530 Subject: [PATCH 086/130] fix: refactor --- contracts/evmx/base/AppGatewayBase.sol | 235 +++++++++--------- contracts/evmx/interfaces/IConfigurations.sol | 7 +- contracts/evmx/watcher/Configurations.sol | 11 +- contracts/evmx/watcher/Watcher.sol | 8 +- test/TriggerTest.t.sol | 2 +- .../counter/CounterAppGateway.sol | 4 +- 6 files changed, 138 insertions(+), 129 deletions(-) diff --git a/contracts/evmx/base/AppGatewayBase.sol b/contracts/evmx/base/AppGatewayBase.sol index fa9a92e4..ab78c8ca 100644 --- a/contracts/evmx/base/AppGatewayBase.sol +++ b/contracts/evmx/base/AppGatewayBase.sol @@ -14,19 +14,18 @@ import {IsPlug, QueueParams, Read, WriteFinality, Parallel} from "../../utils/co /// @notice Abstract contract for the app gateway /// @dev This contract contains helpers for contract deployment, overrides, hooks and request processing abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { - OverrideParams public overrideParams; bool public isAsyncModifierSet; address public auctionManager; + address public consumeFrom; + uint256 public maxFees; bytes32 public sbType; bytes public onCompleteData; - uint256 public maxFees; + OverrideParams public overrideParams; mapping(address => bool) public isValidPromise; mapping(bytes32 => mapping(uint32 => address)) public override forwarderAddresses; mapping(bytes32 => bytes) public creationCodeWithArgs; - address public consumeFrom; - /// @notice Modifier to treat functions async modifier async() { _preAsync(); @@ -50,6 +49,16 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { sbType = FAST; } + //////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////// ASYNC HELPERS //////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// + + function _preAsync() internal { + isAsyncModifierSet = true; + _clearOverrides(); + watcher__().clearQueue(); + } + function _postAsync() internal { isAsyncModifierSet = false; @@ -62,63 +71,24 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { _markValidPromises(promises); } - function _preAsync() internal { - isAsyncModifierSet = true; - _clearOverrides(); - watcher__().clearQueue(); - } - - function _approveFeesWithSignature(bytes memory feesApprovalData_) internal { - if (feesApprovalData_.length > 0) { - (consumeFrom, , ) = feesManager__().approveAppGatewayWithSignature(feesApprovalData_); - } - } - - /// @notice Sets the switchboard type - /// @param sbType_ The switchboard type - function _setSbType(bytes32 sbType_) internal { - sbType = sbType_; - } - - /// @notice Creates a contract ID - /// @param contractName_ The contract name - /// @return bytes32 The contract ID - function _createContractId(string memory contractName_) internal pure returns (bytes32) { - return keccak256(abi.encode(contractName_)); - } - - /// @notice Gets the current request count - /// @return uint40 The current request count - function _getCurrentRequestCount() internal view returns (uint40) { - return watcher__().getCurrentRequestCount(); - } - - /// @notice Sets the auction manager - /// @param auctionManager_ The auction manager - function _setAuctionManager(address auctionManager_) internal { - auctionManager = auctionManager_; + function then(bytes4 selector_, bytes memory data_) internal { + IPromise(watcher__().latestAsyncPromise()).then(selector_, data_); } - /// @notice Marks the promises as valid - function _markValidPromises(address[] memory promises_) internal { - for (uint256 i = 0; i < promises_.length; i++) { - isValidPromise[promises_[i]] = true; - } - } + /// @notice Schedules a function to be called after a delay + /// @param delayInSeconds_ The delay in seconds + /// @dev callback function and data is set in .then call + function _setSchedule(uint256 delayInSeconds_) internal { + if (!isAsyncModifierSet) revert AsyncModifierNotSet(); + overrideParams.callType = SCHEDULE; + overrideParams.delayInSeconds = delayInSeconds_; - /// @notice Sets the validity of an onchain contract (plug) to authorize it to send information to a specific AppGateway - /// @param chainSlug_ The unique identifier of the chain where the contract resides - /// @param contractId The bytes32 identifier of the contract to be validated - /// @param isValid Boolean flag indicating whether the contract is authorized (true) or not (false) - /// @dev This function retrieves the onchain address using the contractId and chainSlug, then calls the watcher precompile to update the plug's validity status - function _setValidPlug(uint32 chainSlug_, bytes32 contractId, bool isValid) internal { - address onchainAddress = getOnChainAddress(contractId, chainSlug_); - watcher__().configurations__().setIsValidPlug(isValid, chainSlug_, onchainAddress); + QueueParams memory queueParams; + queueParams.overrideParams = overrideParams; + watcher__().queue(queueParams, address(this)); } - //////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////// DEPLOY HELPERS /////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////////////////////// function _deploy(bytes32 contractId_, uint32 chainSlug_, IsPlug isPlug_) internal { _deploy(contractId_, chainSlug_, isPlug_, bytes("")); @@ -144,10 +114,6 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { onCompleteData = abi.encode(chainSlug_, true); } - function then(bytes4 selector_, bytes memory data_) internal { - IPromise(watcher__().latestAsyncPromise()).then(selector_, data_); - } - /// @notice Sets the address for a deployed contract /// @param data_ The data /// @param returnData_ The return data @@ -159,17 +125,16 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { ); } - /// @notice Schedules a function to be called after a delay - /// @param delayInSeconds_ The delay in seconds - /// @dev callback function and data is set in .then call - function _setSchedule(uint256 delayInSeconds_) internal { - if (!isAsyncModifierSet) revert AsyncModifierNotSet(); - overrideParams.callType = SCHEDULE; - overrideParams.delayInSeconds = delayInSeconds_; + /// @notice Reverts the transaction + /// @param requestCount_ The request count + function _revertTx(uint40 requestCount_) internal { + watcher__().cancelRequest(requestCount_); + } - QueueParams memory queueParams; - queueParams.overrideParams = overrideParams; - watcher__().queue(queueParams, address(this)); + /// @notice increases the transaction maxFees + /// @param requestCount_ The request count + function _increaseFees(uint40 requestCount_, uint256 newMaxFees_) internal { + watcher__().increaseFees(requestCount_, newMaxFees_); } /// @notice Gets the on-chain address @@ -184,18 +149,95 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { return address(0); } - onChainAddress = IForwarder(forwarderAddresses[contractId_][chainSlug_]) - .getOnChainAddress(); + onChainAddress = IForwarder(forwarderAddresses[contractId_][chainSlug_]).getOnChainAddress(); } - function _setCallType(Read isReadCall_) internal { - overrideParams.callType = isReadCall_ == Read.OFF ? WRITE : READ; + //////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////// UTILS //////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// + + /// @notice Creates a contract ID + /// @param contractName_ The contract name + /// @return bytes32 The contract ID + function _createContractId(string memory contractName_) internal pure returns (bytes32) { + return keccak256(abi.encode(contractName_)); + } + + /// @notice Gets the current request count + /// @return uint40 The current request count + function _getCurrentRequestCount() internal view returns (uint40) { + return watcher__().getCurrentRequestCount(); + } + + /// @notice Marks the promises as valid + function _markValidPromises(address[] memory promises_) internal { + for (uint256 i = 0; i < promises_.length; i++) { + isValidPromise[promises_[i]] = true; + } + } + + //////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////// ADMIN HELPERS //////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// + + /// @notice Sets the auction manager + /// @param auctionManager_ The auction manager + function _setAuctionManager(address auctionManager_) internal { + auctionManager = auctionManager_; + } + + /// @notice Sets the switchboard type + /// @param sbType_ The switchboard type + function _setSbType(bytes32 sbType_) internal { + sbType = sbType_; + } + + /// @notice Sets the validity of an onchain contract (plug) to authorize it to send information to a specific AppGateway + /// @param chainSlug_ The unique identifier of the chain where the contract resides + /// @param contractId_ The bytes32 identifier of the contract to be validated + /// @param isValid Boolean flag indicating whether the contract is authorized (true) or not (false) + /// @dev This function retrieves the onchain address using the contractId_ and chainSlug, then calls the watcher precompile to update the plug's validity status + function _setValidPlug(bool isValid, uint32 chainSlug_, bytes32 contractId_) internal { + address onchainAddress = getOnChainAddress(contractId_, chainSlug_); + watcher__().setIsValidPlug(isValid, chainSlug_, onchainAddress); + } + + function _approveFeesWithSignature(bytes memory feesApprovalData_) internal { + if (feesApprovalData_.length == 0) return; + (consumeFrom, , ) = feesManager__().approveAppGatewayWithSignature(feesApprovalData_); + } + + /// @notice Withdraws fee tokens + /// @param chainSlug_ The chain slug + /// @param token_ The token address + /// @param amount_ The amount + /// @param receiver_ The receiver address + function _withdrawCredits( + uint32 chainSlug_, + address token_, + uint256 amount_, + uint256 maxFees_, + address receiver_ + ) internal { + feesManager__().withdrawCredits(chainSlug_, token_, amount_, maxFees_, receiver_); } //////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////// TX OVERRIDE HELPERS /////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// + function _clearOverrides() internal { + overrideParams.callType = WRITE; + overrideParams.isParallelCall = Parallel.OFF; + overrideParams.gasLimit = 0; + overrideParams.value = 0; + overrideParams.readAtBlockNumber = 0; + overrideParams.writeFinality = WriteFinality.LOW; + overrideParams.delayInSeconds = 0; + consumeFrom = address(this); + onCompleteData = bytes(""); + } + /// @notice Sets multiple overrides in one call /// @param isReadCall_ The read call flag /// @param fees_ The maxFees configuration @@ -213,18 +255,6 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { maxFees = fees_; } - function _clearOverrides() internal { - overrideParams.callType = WRITE; - overrideParams.isParallelCall = Parallel.OFF; - overrideParams.gasLimit = 0; - overrideParams.value = 0; - overrideParams.readAtBlockNumber = 0; - overrideParams.writeFinality = WriteFinality.LOW; - overrideParams.delayInSeconds = 0; - consumeFrom = address(this); - onCompleteData = bytes(""); - } - /// @notice Modifier to treat functions async with consume from address function _setOverrides(address consumeFrom_) internal { consumeFrom = consumeFrom_; @@ -288,6 +318,10 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { overrideParams.gasLimit = gasLimit_; } + function _setCallType(Read isReadCall_) internal { + overrideParams.callType = isReadCall_ == Read.OFF ? WRITE : READ; + } + function _setMsgValue(uint256 value_) internal { overrideParams.value = value_; } @@ -302,37 +336,6 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { return (overrideParams, sbType); } - //////////////////////////////////////////////////////////////////////////////////////////////// - ///////////////////////////////// ASYNC BATCH HELPERS ///////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////////////////////// - - /// @notice Reverts the transaction - /// @param requestCount_ The request count - function _revertTx(uint40 requestCount_) internal { - watcher__().cancelRequest(requestCount_); - } - - /// @notice increases the transaction maxFees - /// @param requestCount_ The request count - function _increaseFees(uint40 requestCount_, uint256 newMaxFees_) internal { - watcher__().increaseFees(requestCount_, newMaxFees_); - } - - /// @notice Withdraws fee tokens - /// @param chainSlug_ The chain slug - /// @param token_ The token address - /// @param amount_ The amount - /// @param receiver_ The receiver address - function _withdrawCredits( - uint32 chainSlug_, - address token_, - uint256 amount_, - uint256 maxFees_, - address receiver_ - ) internal { - feesManager__().withdrawCredits(chainSlug_, token_, amount_, maxFees_, receiver_); - } - //////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////// HOOKS ///////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/contracts/evmx/interfaces/IConfigurations.sol b/contracts/evmx/interfaces/IConfigurations.sol index fd7921a4..eb795a76 100644 --- a/contracts/evmx/interfaces/IConfigurations.sol +++ b/contracts/evmx/interfaces/IConfigurations.sol @@ -43,7 +43,12 @@ interface IConfigurations { /// @notice Sets valid plugs for each chain slug /// @dev This function is used to verify if a plug deployed on a chain slug is valid connection to the app gateway - function setIsValidPlug(bool isValid_, uint32 chainSlug_, address plug_) external; + function setIsValidPlug( + bool isValid_, + uint32 chainSlug_, + address plug_, + address appGateway_ + ) external; function setAppGatewayConfigs(AppGatewayConfig[] calldata configs_) external; diff --git a/contracts/evmx/watcher/Configurations.sol b/contracts/evmx/watcher/Configurations.sol index ddc42307..559296bb 100644 --- a/contracts/evmx/watcher/Configurations.sol +++ b/contracts/evmx/watcher/Configurations.sol @@ -113,9 +113,14 @@ contract Configurations is IConfigurations, Initializable, WatcherBase, Ownable /// @param chainSlug_ The identifier of the network /// @param plug_ The address of the plug /// @param isValid_ Whether the plug is valid - function setIsValidPlug(bool isValid_, uint32 chainSlug_, address plug_) external { - isValidPlug[msg.sender][chainSlug_][plug_] = isValid_; - emit IsValidPlugSet(msg.sender, chainSlug_, plug_, isValid_); + function setIsValidPlug( + bool isValid_, + uint32 chainSlug_, + address plug_, + address appGateway_ + ) external onlyWatcher { + isValidPlug[appGateway_][chainSlug_][plug_] = isValid_; + emit IsValidPlugSet(appGateway_, chainSlug_, plug_, isValid_); } /// @notice Retrieves the configuration for a specific plug on a network diff --git a/contracts/evmx/watcher/Watcher.sol b/contracts/evmx/watcher/Watcher.sol index c6190c5d..863f45c3 100644 --- a/contracts/evmx/watcher/Watcher.sol +++ b/contracts/evmx/watcher/Watcher.sol @@ -150,12 +150,8 @@ contract Watcher is Trigger { return requestHandler__.getPayload(payloadId_); } - function setIsValidPlug( - bool isValid_, - uint32 chainSlug_, - address onchainAddress_ - ) external override { - configurations__.setIsValidPlug(isValid_, chainSlug_, onchainAddress_); + function setIsValidPlug(bool isValid_, uint32 chainSlug_, address plug_) external override { + configurations__.setIsValidPlug(isValid_, chainSlug_, plug_, msg.sender); } function cancelRequest(uint40 requestCount_) external override { diff --git a/test/TriggerTest.t.sol b/test/TriggerTest.t.sol index a4231e52..0ebed42f 100644 --- a/test/TriggerTest.t.sol +++ b/test/TriggerTest.t.sol @@ -41,7 +41,7 @@ contract TriggerTest is AppGatewayBaseSetup { gateway ); counter = Counter(counterAddress); - gateway.setIsValidPlug(arbChainSlug, counterAddress); + gateway.setIsValidPlug(arbChainSlug, counterId); } function testIncrementAfterTrigger() public { diff --git a/test/apps/app-gateways/counter/CounterAppGateway.sol b/test/apps/app-gateways/counter/CounterAppGateway.sol index d47454dc..9085000f 100644 --- a/test/apps/app-gateways/counter/CounterAppGateway.sol +++ b/test/apps/app-gateways/counter/CounterAppGateway.sol @@ -97,8 +97,8 @@ contract CounterAppGateway is AppGatewayBase, Ownable { } // trigger from a chain - function setIsValidPlug(uint32 chainSlug_, address plug_) public { - watcher__().configurations__().setIsValidPlug(true, chainSlug_, plug_); + function setIsValidPlug(uint32 chainSlug_, bytes32 contractId_) public { + _setValidPlug(true, chainSlug_, contractId_); } function increase(uint256 value_) external onlyWatcher { From 6ab535c32590d1dfdc776b645eb5c281240c8efd Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Thu, 29 May 2025 15:27:21 +0530 Subject: [PATCH 087/130] feat: initialize in ag base --- contracts/evmx/AuctionManager.sol | 7 ++++--- contracts/evmx/base/AppGatewayBase.sol | 6 +++--- contracts/evmx/helpers/AddressResolverUtil.sol | 4 ++-- contracts/evmx/helpers/AsyncDeployer.sol | 2 ++ contracts/evmx/helpers/DeployForwarder.sol | 5 ++--- test/apps/app-gateways/counter/CounterAppGateway.sol | 3 ++- .../apps/app-gateways/super-token/SuperTokenAppGateway.sol | 3 ++- 7 files changed, 17 insertions(+), 13 deletions(-) diff --git a/contracts/evmx/AuctionManager.sol b/contracts/evmx/AuctionManager.sol index 54483517..28dd3fcc 100644 --- a/contracts/evmx/AuctionManager.sol +++ b/contracts/evmx/AuctionManager.sol @@ -62,13 +62,14 @@ contract AuctionManager is AuctionManagerStorage, AccessControl, AppGatewayBase uint256 auctionEndDelaySeconds_, address addressResolver_, address owner_ - ) AppGatewayBase(addressResolver_) { - _initializeOwner(owner_); - + ) { evmxSlug = evmxSlug_; bidTimeout = bidTimeout_; maxReAuctionCount = maxReAuctionCount_; auctionEndDelaySeconds = auctionEndDelaySeconds_; + + _initializeOwner(owner_); + _initializeAppGateway(addressResolver_); } function setAuctionEndDelaySeconds(uint256 auctionEndDelaySeconds_) external onlyOwner { diff --git a/contracts/evmx/base/AppGatewayBase.sol b/contracts/evmx/base/AppGatewayBase.sol index ab78c8ca..25ba05cd 100644 --- a/contracts/evmx/base/AppGatewayBase.sol +++ b/contracts/evmx/base/AppGatewayBase.sol @@ -42,11 +42,11 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { _; } - /// @notice Constructor for AppGatewayBase + /// @notice Initializer for AppGatewayBase /// @param addressResolver_ The address resolver address - constructor(address addressResolver_) { - _setAddressResolver(addressResolver_); + function _initializeAppGateway(address addressResolver_) internal { sbType = FAST; + _setAddressResolver(addressResolver_); } //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/contracts/evmx/helpers/AddressResolverUtil.sol b/contracts/evmx/helpers/AddressResolverUtil.sol index 550ece71..66663c7d 100644 --- a/contracts/evmx/helpers/AddressResolverUtil.sol +++ b/contracts/evmx/helpers/AddressResolverUtil.sol @@ -16,8 +16,8 @@ abstract contract AddressResolverUtil { // slot 0 IAddressResolver public addressResolver__; - // slots 1-50 reserved for future use - uint256[50] __gap_resolver_util; + // slots 1-49 reserved for future use + uint256[49] __gap_resolver_util; /// @notice Restricts function access to the watcher precompile contract /// @dev Validates that msg.sender matches the registered watcher precompile address diff --git a/contracts/evmx/helpers/AsyncDeployer.sol b/contracts/evmx/helpers/AsyncDeployer.sol index 0cf93eb9..662d2f35 100644 --- a/contracts/evmx/helpers/AsyncDeployer.sol +++ b/contracts/evmx/helpers/AsyncDeployer.sol @@ -31,6 +31,8 @@ abstract contract AsyncDeployerStorage is IAsyncDeployer { // slots [61-110] reserved for gap uint256[50] _gap_after; + + // slots [111-160] 50 slots reserved for address resolver util } /// @title AsyncDeployer Contract diff --git a/contracts/evmx/helpers/DeployForwarder.sol b/contracts/evmx/helpers/DeployForwarder.sol index 17fd5bfa..8368b23a 100644 --- a/contracts/evmx/helpers/DeployForwarder.sol +++ b/contracts/evmx/helpers/DeployForwarder.sol @@ -10,9 +10,8 @@ import {QueueParams, OverrideParams, Transaction} from "../../utils/common/Struc import {WRITE} from "../../utils/common/Constants.sol"; import {encodeAppGatewayId} from "../../utils/common/IdUtils.sol"; -/// @title DeployerGateway -/// @notice App gateway contract responsible for handling deployment requests -/// @dev Extends AppGatewayBase to provide deployment queueing functionality +/// @title DeployForwarder +/// @notice contract responsible for handling deployment requests contract DeployForwarder is AddressResolverUtil, IDeployForwarder { /// @notice The counter for the salt used to generate/deploy the contract address uint256 public override saltCounter; diff --git a/test/apps/app-gateways/counter/CounterAppGateway.sol b/test/apps/app-gateways/counter/CounterAppGateway.sol index 9085000f..1e46eeb2 100644 --- a/test/apps/app-gateways/counter/CounterAppGateway.sol +++ b/test/apps/app-gateways/counter/CounterAppGateway.sol @@ -17,11 +17,12 @@ contract CounterAppGateway is AppGatewayBase, Ownable { event CounterScheduleResolved(uint256 creationTimestamp, uint256 executionTimestamp); - constructor(address addressResolver_, uint256 fees_) AppGatewayBase(addressResolver_) { + constructor(address addressResolver_, uint256 fees_) { creationCodeWithArgs[counter] = abi.encodePacked(type(Counter).creationCode); creationCodeWithArgs[counter1] = abi.encodePacked(type(Counter).creationCode); _setMaxFees(fees_); _initializeOwner(msg.sender); + _initializeAppGateway(addressResolver_); } // deploy contracts diff --git a/test/apps/app-gateways/super-token/SuperTokenAppGateway.sol b/test/apps/app-gateways/super-token/SuperTokenAppGateway.sol index 77657fd7..b793aeb2 100644 --- a/test/apps/app-gateways/super-token/SuperTokenAppGateway.sol +++ b/test/apps/app-gateways/super-token/SuperTokenAppGateway.sol @@ -31,7 +31,7 @@ contract SuperTokenAppGateway is AppGatewayBase, Ownable { address owner_, uint256 fees_, ConstructorParams memory params_ - ) AppGatewayBase(addressResolver_) { + ) { creationCodeWithArgs[superToken] = abi.encodePacked( type(SuperToken).creationCode, abi.encode( @@ -47,6 +47,7 @@ contract SuperTokenAppGateway is AppGatewayBase, Ownable { // they can be updated for each transfer as well _setMaxFees(fees_); _initializeOwner(owner_); + _initializeAppGateway(addressResolver_); } function deployContracts(uint32 chainSlug_) external async { From 8c4b36bc5c7afdeac0d494f3378ba0f9a1842cb2 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Thu, 29 May 2025 15:29:39 +0530 Subject: [PATCH 088/130] fix: slot number fee storage --- contracts/evmx/fees/Credit.sol | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/contracts/evmx/fees/Credit.sol b/contracts/evmx/fees/Credit.sol index 164cf3eb..625b6368 100644 --- a/contracts/evmx/fees/Credit.sol +++ b/contracts/evmx/fees/Credit.sol @@ -15,37 +15,53 @@ import {NonceUsed, InvalidAmount, InsufficientCreditsAvailable, InsufficientBala import {WRITE} from "../../utils/common/Constants.sol"; abstract contract FeesManagerStorage is IFeesManager { + // slots [0-49] reserved for gap + uint256[50] _gap_before; + + // slot 50 /// @notice evmx slug uint32 public evmxSlug; + IFeesPool public feesPool; + + // slot 51 /// @notice switchboard type bytes32 public sbType; - IFeesPool public feesPool; - + // slot 52 /// @notice user credits => stores fees for user, app gateway, transmitters and watcher precompile mapping(address => UserCredits) public userCredits; + // slot 53 /// @notice Mapping to track request credits details for each request count /// @dev requestCount => RequestFee mapping(uint40 => uint256) public requestBlockedCredits; + // slot 54 // user approved app gateways // userAddress => appGateway => isApproved mapping(address => mapping(address => bool)) public isApproved; + // slot 55 // token pool balances // chainSlug => token address => amount mapping(uint32 => mapping(address => uint256)) public tokenOnChainBalances; + // slot 56 /// @notice Mapping to track nonce to whether it has been used /// @dev address => signatureNonce => isNonceUsed /// @dev used by watchers or other users in signatures mapping(address => mapping(uint256 => bool)) public isNonceUsed; + // slot 57 /// @notice Mapping to track fees plug for each chain slug /// @dev chainSlug => fees plug address mapping(uint32 => address) public feesPlugs; + + // slots [58-107] reserved for gap + uint256[50] _gap_after; + + // slots [108-157] 50 slots reserved for address resolver util } /// @title UserUtils From 5f53164a30dac3f89504f0a748e7f2f66bd9b4c7 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Thu, 29 May 2025 15:38:13 +0530 Subject: [PATCH 089/130] fix: proxy and slots for helpers --- contracts/evmx/helpers/AddressResolver.sol | 12 +++++++++++- contracts/evmx/helpers/AsyncDeployer.sol | 10 +++++----- contracts/evmx/helpers/AsyncPromise.sol | 3 +++ contracts/evmx/helpers/DeployForwarder.sol | 21 ++++++++++++++++++--- contracts/evmx/helpers/Forwarder.sol | 4 ++-- 5 files changed, 39 insertions(+), 11 deletions(-) diff --git a/contracts/evmx/helpers/AddressResolver.sol b/contracts/evmx/helpers/AddressResolver.sol index 80cf5892..661e79e0 100644 --- a/contracts/evmx/helpers/AddressResolver.sol +++ b/contracts/evmx/helpers/AddressResolver.sol @@ -9,15 +9,25 @@ abstract contract AddressResolverStorage is IAddressResolver { // slots [0-49] reserved for gap uint256[50] _gap_before; + // slot 50 IWatcher public override watcher__; + + // slot 51 IFeesManager public override feesManager__; + + // slot 52 IAsyncDeployer public override asyncDeployer__; + + // slot 53 IDeployForwarder public override deployForwarder__; + // slot 54 address public override defaultAuctionManager; + + // slot 55 mapping(bytes32 => address) public override contractAddresses; - // slots [61-110] reserved for gap + // slots [56-105] reserved for gap uint256[50] _gap_after; } diff --git a/contracts/evmx/helpers/AsyncDeployer.sol b/contracts/evmx/helpers/AsyncDeployer.sol index 662d2f35..29b400d2 100644 --- a/contracts/evmx/helpers/AsyncDeployer.sol +++ b/contracts/evmx/helpers/AsyncDeployer.sol @@ -20,19 +20,19 @@ abstract contract AsyncDeployerStorage is IAsyncDeployer { // slot 52 UpgradeableBeacon public asyncPromiseBeacon; - // slot 55 + // slot 53 address public forwarderImplementation; - // slot 56 + // slot 54 address public asyncPromiseImplementation; - // slot 58 + // slot 55 uint256 public asyncPromiseCounter; - // slots [61-110] reserved for gap + // slots [56-105] reserved for gap uint256[50] _gap_after; - // slots [111-160] 50 slots reserved for address resolver util + // slots [106-155] 50 slots reserved for address resolver util } /// @title AsyncDeployer Contract diff --git a/contracts/evmx/helpers/AsyncPromise.sol b/contracts/evmx/helpers/AsyncPromise.sol index 9d43f576..8392acfa 100644 --- a/contracts/evmx/helpers/AsyncPromise.sol +++ b/contracts/evmx/helpers/AsyncPromise.sol @@ -12,6 +12,7 @@ abstract contract AsyncPromiseStorage is IPromise { // slots [0-49] reserved for gap uint256[50] _gap_before; + // slot 50 (4 + 8 + 8 + 40 + 160) /// @notice The callback selector to be called on the invoker. bytes4 public callbackSelector; @@ -28,9 +29,11 @@ abstract contract AsyncPromiseStorage is IPromise { /// @dev The callback will be executed on this address address public override localInvoker; + // slot 51 /// @notice The return data of the promise bytes public override returnData; + // slot 52 /// @notice The callback data to be used when the promise is resolved. bytes public callbackData; diff --git a/contracts/evmx/helpers/DeployForwarder.sol b/contracts/evmx/helpers/DeployForwarder.sol index 8368b23a..aa67d12a 100644 --- a/contracts/evmx/helpers/DeployForwarder.sol +++ b/contracts/evmx/helpers/DeployForwarder.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; +import {Initializable} from "solady/utils/Initializable.sol"; import {IAppGateway} from "../interfaces/IAppGateway.sol"; import {IContractFactoryPlug} from "../interfaces/IContractFactoryPlug.sol"; import {IDeployForwarder} from "../interfaces/IDeployForwarder.sol"; @@ -12,15 +13,29 @@ import {encodeAppGatewayId} from "../../utils/common/IdUtils.sol"; /// @title DeployForwarder /// @notice contract responsible for handling deployment requests -contract DeployForwarder is AddressResolverUtil, IDeployForwarder { +contract DeployForwarder is IDeployForwarder, Initializable, AddressResolverUtil { + // slots [0-49] 50 slots reserved for address resolver util + + // slots [50-99] reserved for gap + uint256[50] _gap_before; + + // slot 100 /// @notice The counter for the salt used to generate/deploy the contract address uint256 public override saltCounter; + // slot 101 bytes32 public override deployerSwitchboardType; - constructor(address addressResolver_, bytes32 deployerSwitchboardType_) { - _setAddressResolver(addressResolver_); + constructor() { + _disableInitializers(); // disable for implementation + } + + function initialize( + address addressResolver_, + bytes32 deployerSwitchboardType_ + ) public reinitializer(1) { deployerSwitchboardType = deployerSwitchboardType_; + _setAddressResolver(addressResolver_); } /// @notice Deploys a contract diff --git a/contracts/evmx/helpers/Forwarder.sol b/contracts/evmx/helpers/Forwarder.sol index ec9d6492..60b91b69 100644 --- a/contracts/evmx/helpers/Forwarder.sol +++ b/contracts/evmx/helpers/Forwarder.sol @@ -21,10 +21,10 @@ abstract contract ForwarderStorage is IForwarder { /// @notice on-chain address associated with this forwarder address public onChainAddress; - // slots [53-102] reserved for gap + // slots [51-100] reserved for gap uint256[50] _gap_after; - // slots 103-154 (51) reserved for addr resolver util + // slots [101-150] 50 slots reserved for address resolver util } /// @title Forwarder Contract From d547e33371b5b5c9784329f12f78af70b8845eb7 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Thu, 29 May 2025 15:43:00 +0530 Subject: [PATCH 090/130] feat: AM proxy --- contracts/evmx/AuctionManager.sol | 25 +++++++++++++++++++------ contracts/evmx/base/AppGatewayBase.sol | 19 ++++++++++++++++++- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/contracts/evmx/AuctionManager.sol b/contracts/evmx/AuctionManager.sol index 28dd3fcc..b2a03c79 100644 --- a/contracts/evmx/AuctionManager.sol +++ b/contracts/evmx/AuctionManager.sol @@ -13,10 +13,13 @@ import {AppGatewayBase} from "./base/AppGatewayBase.sol"; /// @title AuctionManagerStorage /// @notice Storage for the AuctionManager contract abstract contract AuctionManagerStorage is IAuctionManager { - // slot 50 + // slots [0-49] reserved for gap + uint256[50] _gap_before; + + // slot 50 (32 + 128) + /// @notice The evmx chain slug uint32 public immutable evmxSlug; - // slot 50 /// @notice The time after which a bid expires uint128 public bidTimeout; @@ -34,13 +37,19 @@ abstract contract AuctionManagerStorage is IAuctionManager { /// @notice The auction status for a request (requestCount => AuctionStatus) mapping(uint40 => AuctionStatus) public override auctionStatus; - // slot 56 + // slot 55 mapping(uint40 => uint256) public reAuctionCount; + + // slots [56-105] reserved for gap + uint256[50] _gap_after; + + // slots [106-164] 59 slots reserved for app gateway base + // slots [165-215] 51 slots reserved for access control } /// @title AuctionManager /// @notice Contract for managing auctions and placing bids -contract AuctionManager is AuctionManagerStorage, AccessControl, AppGatewayBase { +contract AuctionManager is AuctionManagerStorage, AppGatewayBase, AccessControl { event AuctionRestarted(uint40 requestCount); event AuctionStarted(uint40 requestCount); event AuctionEnded(uint40 requestCount, Bid winningBid); @@ -55,14 +64,18 @@ contract AuctionManager is AuctionManagerStorage, AccessControl, AppGatewayBase /// @param addressResolver_ The address of the address resolver /// @param owner_ The address of the contract owner - constructor( + constructor() { + _disableInitializers(); // disable for implementation + } + + function initialize( uint32 evmxSlug_, uint128 bidTimeout_, uint256 maxReAuctionCount_, uint256 auctionEndDelaySeconds_, address addressResolver_, address owner_ - ) { + ) external reinitializer(1) { evmxSlug = evmxSlug_; bidTimeout = bidTimeout_; maxReAuctionCount = maxReAuctionCount_; diff --git a/contracts/evmx/base/AppGatewayBase.sol b/contracts/evmx/base/AppGatewayBase.sol index 25ba05cd..a8c6e7da 100644 --- a/contracts/evmx/base/AppGatewayBase.sol +++ b/contracts/evmx/base/AppGatewayBase.sol @@ -14,16 +14,33 @@ import {IsPlug, QueueParams, Read, WriteFinality, Parallel} from "../../utils/co /// @notice Abstract contract for the app gateway /// @dev This contract contains helpers for contract deployment, overrides, hooks and request processing abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { + // 50 slots reserved for address resolver util + // slot 51 bool public isAsyncModifierSet; - address public auctionManager; address public consumeFrom; + + // slot 52 + address public auctionManager; + + // slot 53 uint256 public maxFees; + + // slot 54 bytes32 public sbType; + + // slot 55 bytes public onCompleteData; + + // slot 56 OverrideParams public overrideParams; + // slot 57 mapping(address => bool) public isValidPromise; + + // slot 58 mapping(bytes32 => mapping(uint32 => address)) public override forwarderAddresses; + + // slot 59 mapping(bytes32 => bytes) public creationCodeWithArgs; /// @notice Modifier to treat functions async From d11cdd92c51b89662e149ac0adfda8320729cc39 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Thu, 29 May 2025 16:04:13 +0530 Subject: [PATCH 091/130] feat: watcher proxy and storage slots --- contracts/evmx/watcher/Configurations.sol | 38 ++++++++------ contracts/evmx/watcher/PromiseResolver.sol | 4 +- contracts/evmx/watcher/RequestHandler.sol | 35 ++++++++++--- contracts/evmx/watcher/Trigger.sol | 15 +----- contracts/evmx/watcher/WatcherBase.sol | 3 +- contracts/evmx/watcher/WatcherStorage.sol | 50 ++++++++++++++----- .../watcher/precompiles/ReadPrecompile.sol | 3 +- .../precompiles/SchedulePrecompile.sol | 3 +- .../watcher/precompiles/WritePrecompile.sol | 49 +++++++++++++----- 9 files changed, 133 insertions(+), 67 deletions(-) diff --git a/contracts/evmx/watcher/Configurations.sol b/contracts/evmx/watcher/Configurations.sol index 559296bb..1d9ab69b 100644 --- a/contracts/evmx/watcher/Configurations.sol +++ b/contracts/evmx/watcher/Configurations.sol @@ -8,39 +8,40 @@ import {encodeAppGatewayId} from "../../utils/common/IdUtils.sol"; import {InvalidGateway, InvalidSwitchboard} from "../../utils/common/Errors.sol"; import "solady/auth/Ownable.sol"; -/// @title Configurations -/// @notice Configuration contract for the Watcher Precompile system -/// @dev Handles the mapping between networks, plugs, and app gateways for payload execution -contract Configurations is IConfigurations, Initializable, WatcherBase, Ownable { - // slots 0-50 (51) reserved for addr resolver util - - // slots [51-100]: gap for future storage variables +abstract contract ConfigurationsStorage is IConfigurations { + // slots [0-49] reserved for gap uint256[50] _gap_before; - // slot 101: _plugConfigs + // slot 50 /// @notice Maps network and plug to their configuration /// @dev chainSlug => plug => PlugConfig mapping(uint32 => mapping(address => PlugConfig)) internal _plugConfigs; - // slot 103: switchboards + // slot 51 /// @notice Maps chain slug to their associated switchboard /// @dev chainSlug => sb type => switchboard address mapping(uint32 => mapping(bytes32 => address)) public switchboards; - // slot 104: deployedForwarders - /// @notice Maps contract id to their associated forwarder - /// @dev contractId => forwarder address - - // slot 105: sockets + // slot 52 /// @notice Maps chain slug to their associated socket /// @dev chainSlug => socket address mapping(uint32 => address) public sockets; - // slot 109: isValidPlug + // slot 53 /// @notice Maps app gateway, chain slug, and plug to whether it is valid /// @dev appGateway => chainSlug => plug => isValid mapping(address => mapping(uint32 => mapping(address => bool))) public isValidPlug; + // slots [54-103] reserved for gap + uint256[50] _gap_after; + + // 1 slot reserved for watcher base +} + +/// @title Configurations +/// @notice Configuration contract for the Watcher Precompile system +/// @dev Handles the mapping between networks, plugs, and app gateways for payload execution +contract Configurations is ConfigurationsStorage, Initializable, Ownable, WatcherBase { /// @notice Emitted when a new plug is configured for an app gateway /// @param appGatewayId The id of the app gateway /// @param chainSlug The identifier of the destination network @@ -65,8 +66,13 @@ contract Configurations is IConfigurations, Initializable, WatcherBase, Ownable /// @param isValid Whether the plug is valid event IsValidPlugSet(address appGateway, uint32 chainSlug, address plug, bool isValid); - constructor(address watcher_, address owner_) WatcherBase(watcher_) { + constructor() { + _disableInitializers(); // disable for implementation + } + + function initialize(address watcher_, address owner_) external reinitializer(1) { _initializeOwner(owner_); + _initializeWatcher(watcher_); } /// @notice Configures app gateways with their respective plugs and switchboards diff --git a/contracts/evmx/watcher/PromiseResolver.sol b/contracts/evmx/watcher/PromiseResolver.sol index 7a4c85ac..a6eed239 100644 --- a/contracts/evmx/watcher/PromiseResolver.sol +++ b/contracts/evmx/watcher/PromiseResolver.sol @@ -25,7 +25,9 @@ contract PromiseResolver is IPromiseResolver, WatcherBase { /// @notice Sets the Watcher address /// @param watcher_ The address of the Watcher contract - constructor(address watcher_) WatcherBase(watcher_) {} + constructor(address watcher_) { + _initializeWatcher(watcher_); + } /// @notice Resolves multiple promises with their return data /// @param promiseReturnData_ Array of resolved promises and their return data diff --git a/contracts/evmx/watcher/RequestHandler.sol b/contracts/evmx/watcher/RequestHandler.sol index b3fcb1c8..6a1d799e 100644 --- a/contracts/evmx/watcher/RequestHandler.sol +++ b/contracts/evmx/watcher/RequestHandler.sol @@ -1,6 +1,8 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; +import "solady/utils/Initializable.sol"; +import "solady/auth/Ownable.sol"; import "../helpers/AddressResolverUtil.sol"; import "../../utils/common/Errors.sol"; import "../../utils/common/Constants.sol"; @@ -8,13 +10,12 @@ import "../../utils/common/IdUtils.sol"; import "../interfaces/IAppGateway.sol"; import "../interfaces/IPromise.sol"; import "../interfaces/IRequestHandler.sol"; -import "solady/auth/Ownable.sol"; -/// @title RequestHandler -/// @notice Contract that handles request processing and management, including request submission, batch processing, and request lifecycle management -/// @dev Handles request submission, batch processing, transmitter assignment, request cancellation and settlement -/// @dev This contract interacts with the WatcherPrecompileStorage for storage access -contract RequestHandler is AddressResolverUtil, Ownable, IRequestHandler { +abstract contract RequestHandlerStorage is IRequestHandler { + // slots [0-49] reserved for gap + uint256[50] _gap_before; + + // slot 50 (40 + 40 + 40) /// @notice Counter for tracking request counts uint40 public nextRequestCount = 1; @@ -24,22 +25,38 @@ contract RequestHandler is AddressResolverUtil, Ownable, IRequestHandler { /// @notice Counter for tracking batch counts uint40 public nextBatchCount; + // slot 51 /// @notice Mapping to store the precompiles for each call type mapping(bytes4 => IPrecompile) public precompiles; + // slot 52 /// @notice Mapping to store the list of payload IDs for each batch mapping(uint40 => bytes32[]) internal _batchPayloadIds; + // slot 53 /// @notice Mapping to store the batch IDs for each request mapping(uint40 => uint40[]) internal _requestBatchIds; // queue => update to payloadParams, assign id, store in payloadParams map + // slot 54 /// @notice Mapping to store the payload parameters for each payload ID mapping(bytes32 => PayloadParams) internal _payloads; + // slot 55 /// @notice The metadata for a request mapping(uint40 => RequestParams) internal _requests; + // slots [56-105] reserved for gap + uint256[50] _gap_after; + + // slots [106-155] 50 slots reserved for address resolver util +} + +/// @title RequestHandler +/// @notice Contract that handles request processing and management, including request submission, batch processing, and request lifecycle management +/// @dev Handles request submission, batch processing, transmitter assignment, request cancellation and settlement +/// @dev This contract interacts with the WatcherPrecompileStorage for storage access +contract RequestHandler is RequestHandlerStorage, Initializable, Ownable, AddressResolverUtil { error InsufficientMaxFees(); event RequestSubmitted( @@ -66,7 +83,11 @@ contract RequestHandler is AddressResolverUtil, Ownable, IRequestHandler { _; } - constructor(address owner_, address addressResolver_) { + constructor() { + _disableInitializers(); // disable for implementation + } + + function initialize(address owner_, address addressResolver_) external reinitializer(1) { _initializeOwner(owner_); _setAddressResolver(addressResolver_); } diff --git a/contracts/evmx/watcher/Trigger.sol b/contracts/evmx/watcher/Trigger.sol index 6be8c464..d27ff99d 100644 --- a/contracts/evmx/watcher/Trigger.sol +++ b/contracts/evmx/watcher/Trigger.sol @@ -8,22 +8,9 @@ import {decodeAppGatewayId} from "../../utils/common/IdUtils.sol"; /// @title Trigger /// @notice Contract that handles trigger validation and execution logic /// @dev This contract interacts with the WatcherPrecompileStorage for storage access -abstract contract Trigger is WatcherStorage { +abstract contract Trigger is WatcherStorage, AddressResolverUtil { using LibCall for address; - /// @notice stores temporary chainSlug of the trigger from a chain - uint32 public triggerFromChainSlug; - /// @notice stores temporary plug of the trigger from a chain - address public triggerFromPlug; - - /// @notice Stores the trigger fees - uint256 public triggerFees; - - /// @notice Mapping to store if appGateway has been called with trigger from on-chain Inbox - /// @dev Maps call ID to boolean indicating if the appGateway has been called - /// @dev callId => bool - mapping(bytes32 => bool) public isAppGatewayCalled; - event TriggerFeesSet(uint256 triggerFees); event TriggerFailed(bytes32 triggerId); event TriggerSucceeded(bytes32 triggerId); diff --git a/contracts/evmx/watcher/WatcherBase.sol b/contracts/evmx/watcher/WatcherBase.sol index 9c3949a9..468dcbcf 100644 --- a/contracts/evmx/watcher/WatcherBase.sol +++ b/contracts/evmx/watcher/WatcherBase.sol @@ -9,6 +9,7 @@ import "../interfaces/IRequestHandler.sol"; /// @title WatcherBase /// @notice Base contract for the Watcher contract contract WatcherBase { + // slots 0 // The address of the Watcher contract IWatcher public watcher__; @@ -30,7 +31,7 @@ contract WatcherBase { /// @notice Sets the Watcher address /// @param watcher_ The address of the Watcher contract - constructor(address watcher_) { + function _initializeWatcher(address watcher_) internal { watcher__ = IWatcher(watcher_); } diff --git a/contracts/evmx/watcher/WatcherStorage.sol b/contracts/evmx/watcher/WatcherStorage.sol index 3037e517..f6bdc046 100644 --- a/contracts/evmx/watcher/WatcherStorage.sol +++ b/contracts/evmx/watcher/WatcherStorage.sol @@ -11,31 +11,55 @@ import {Ownable} from "solady/auth/Ownable.sol"; /// @notice Storage contract for the WatcherPrecompile system /// @dev This contract contains all the storage variables used by the WatcherPrecompile system /// @dev It is inherited by WatcherPrecompileCore and WatcherPrecompile -abstract contract WatcherStorage is IWatcher, Initializable, AddressResolverUtil, Ownable { +abstract contract WatcherStorage is IWatcher, Initializable, Ownable { // slots [0-49]: gap for future storage variables uint256[50] _gap_before; - // slot 50 + // slot 50 (32 + 32 + 160) /// @notice The chain slug of the watcher precompile uint32 public evmxSlug; + /// @notice stores temporary chainSlug of the trigger from a chain + uint32 public triggerFromChainSlug; + /// @notice stores temporary plug of the trigger from a chain + address public triggerFromPlug; + // slot 51 + /// @notice Stores the trigger fees + uint256 public triggerFees; + + // slot 52 + IRequestHandler public override requestHandler__; + + // slot 53 + IConfigurations public override configurations__; + + // slot 54 + IPromiseResolver public override promiseResolver__; + + // slot 55 + address public latestAsyncPromise; + + // slot 56 + address public appGatewayTemp; + + // slot 57 + /// @notice The queue of payloads + QueueParams[] public payloadQueue; + + // slot 58 /// @notice Maps nonce to whether it has been used /// @dev Used to prevent replay attacks with signature nonces /// @dev signatureNonce => isValid mapping(uint256 => bool) public isNonceUsed; - /// @notice The queue of payloads - QueueParams[] public payloadQueue; - address public latestAsyncPromise; - address public appGatewayTemp; - - IRequestHandler public override requestHandler__; - IConfigurations public override configurations__; - IPromiseResolver public override promiseResolver__; + // slot 59 + /// @notice Mapping to store if appGateway has been called with trigger from on-chain Inbox + /// @dev Maps call ID to boolean indicating if the appGateway has been called + /// @dev callId => bool + mapping(bytes32 => bool) public isAppGatewayCalled; - // slots [51-100]: gap for future storage variables + // slots [60-109]: gap for future storage variables uint256[50] _gap_after; - // slots 115-165 (51) reserved for access control - // slots 166-216 (51) reserved for addr resolver util + // slots [110-159] 50 slots reserved for address resolver util } diff --git a/contracts/evmx/watcher/precompiles/ReadPrecompile.sol b/contracts/evmx/watcher/precompiles/ReadPrecompile.sol index cacfb31f..e4e1fc1f 100644 --- a/contracts/evmx/watcher/precompiles/ReadPrecompile.sol +++ b/contracts/evmx/watcher/precompiles/ReadPrecompile.sol @@ -18,9 +18,10 @@ contract ReadPrecompile is IPrecompile, WatcherBase { uint256 public readFees; uint256 public expiryTime; - constructor(address watcher_, uint256 readFees_, uint256 expiryTime_) WatcherBase(watcher_) { + constructor(address watcher_, uint256 readFees_, uint256 expiryTime_) { readFees = readFees_; expiryTime = expiryTime_; + _initializeWatcher(watcher_); } function getPrecompileFees(bytes memory) public view returns (uint256) { diff --git a/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol b/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol index 92be8e0f..0e6f7dca 100644 --- a/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol @@ -41,13 +41,14 @@ contract SchedulePrecompile is IPrecompile, WatcherBase { uint256 scheduleFeesPerSecond_, uint256 scheduleCallbackFees_, uint256 expiryTime_ - ) WatcherBase(watcher_) { + ) { maxScheduleDelayInSeconds = maxScheduleDelayInSeconds_; scheduleFeesPerSecond = scheduleFeesPerSecond_; scheduleCallbackFees = scheduleCallbackFees_; if (maxScheduleDelayInSeconds < expiryTime) revert InvalidScheduleDelay(); expiryTime = expiryTime_; + _initializeWatcher(watcher_); } function getPrecompileFees(bytes memory precompileData_) public view returns (uint256) { diff --git a/contracts/evmx/watcher/precompiles/WritePrecompile.sol b/contracts/evmx/watcher/precompiles/WritePrecompile.sol index 6bda9002..b7f1c6c6 100644 --- a/contracts/evmx/watcher/precompiles/WritePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/WritePrecompile.sol @@ -1,34 +1,52 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import {InvalidIndex, MaxMsgValueLimitExceeded, InvalidPayloadSize} from "../../../utils/common/Errors.sol"; -import "../../../utils/common/Constants.sol"; +import "solady/utils/Initializable.sol"; +import "solady/auth/Ownable.sol"; + import "../../interfaces/IPrecompile.sol"; +import {WRITE, PAYLOAD_SIZE_LIMIT} from "../../../utils/common/Constants.sol"; +import {InvalidIndex, MaxMsgValueLimitExceeded, InvalidPayloadSize} from "../../../utils/common/Errors.sol"; import {encodeAppGatewayId} from "../../../utils/common/IdUtils.sol"; - import "../WatcherBase.sol"; -import "solady/auth/Ownable.sol"; -/// @title WritePrecompile -/// @notice Handles write precompile logic -contract WritePrecompile is IPrecompile, WatcherBase, Ownable { +abstract contract WritePrecompileStorage is IPrecompile { + // slots [0-49] reserved for gap + uint256[50] _gap_before; + + // slot 50 + /// @notice The fees for a write and includes callback fees + uint256 public writeFees; + + // slot 51 + uint256 public expiryTime; + + // slot 52 /// @notice Mapping to store watcher proofs /// @dev Maps payload ID to proof bytes /// @dev payloadId => proof bytes mapping(bytes32 => bytes) public watcherProofs; + // slot 53 /// @notice The maximum message value limit for a chain mapping(uint32 => uint256) public chainMaxMsgValueLimit; + // slot 54 /// @notice The digest hash for a payload mapping(bytes32 => bytes32) public digestHashes; + // slot 55 mapping(uint32 => address) public contractFactoryPlugs; - /// @notice The fees for a write and includes callback fees - uint256 public writeFees; - uint256 public expiryTime; + // slots [56-105] reserved for gap + uint256[50] _gap_after; + + // 1 slot reserved for watcher base +} +/// @title WritePrecompile +/// @notice Handles write precompile logic +contract WritePrecompile is WritePrecompileStorage, Initializable, Ownable, WatcherBase { /// @notice Emitted when fees are set event FeesSet(uint256 writeFees); event ChainMaxMsgValueLimitsUpdated(uint32 chainSlug, uint256 maxMsgValueLimit); @@ -48,15 +66,20 @@ contract WritePrecompile is IPrecompile, WatcherBase, Ownable { event WriteProofUploaded(bytes32 indexed payloadId, bytes proof); event ExpiryTimeSet(uint256 expiryTime); - constructor( + constructor() { + _disableInitializers(); // disable for implementation + } + + function initialize( address owner_, address watcher_, uint256 writeFees_, uint256 expiryTime_ - ) WatcherBase(watcher_) { - _initializeOwner(owner_); + ) external reinitializer(1) { writeFees = writeFees_; expiryTime = expiryTime_; + _initializeOwner(owner_); + _initializeWatcher(watcher_); } function getPrecompileFees(bytes memory) public view returns (uint256) { From 4711b4ebba703912e6d2da4e6c07643cec4f2252 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Thu, 29 May 2025 16:24:36 +0530 Subject: [PATCH 092/130] fix: AM schedule queue --- contracts/evmx/AuctionManager.sol | 29 ++++++--- contracts/evmx/helpers/AsyncPromise.sol | 4 +- contracts/evmx/watcher/Watcher.sol | 4 +- test/SetupTest.t.sol | 82 ++++++++++++++++++++----- 4 files changed, 91 insertions(+), 28 deletions(-) diff --git a/contracts/evmx/AuctionManager.sol b/contracts/evmx/AuctionManager.sol index b2a03c79..be6a7a3e 100644 --- a/contracts/evmx/AuctionManager.sol +++ b/contracts/evmx/AuctionManager.sol @@ -2,7 +2,10 @@ pragma solidity ^0.8.21; import {ECDSA} from "solady/utils/ECDSA.sol"; +import "solady/utils/Initializable.sol"; +import "./interfaces/IPromise.sol"; import "./interfaces/IAuctionManager.sol"; + import "../utils/AccessControl.sol"; import {AuctionNotOpen, AuctionClosed, BidExceedsMaxFees, LowerBidAlreadyExists, InvalidTransmitter, MaxReAuctionCountReached, InvalidBid} from "../utils/common/Errors.sol"; import {SCHEDULE} from "../utils/common/Constants.sol"; @@ -18,7 +21,7 @@ abstract contract AuctionManagerStorage is IAuctionManager { // slot 50 (32 + 128) /// @notice The evmx chain slug - uint32 public immutable evmxSlug; + uint32 public evmxSlug; /// @notice The time after which a bid expires uint128 public bidTimeout; @@ -49,7 +52,7 @@ abstract contract AuctionManagerStorage is IAuctionManager { /// @title AuctionManager /// @notice Contract for managing auctions and placing bids -contract AuctionManager is AuctionManagerStorage, AppGatewayBase, AccessControl { +contract AuctionManager is AuctionManagerStorage, Initializable, AppGatewayBase, AccessControl { event AuctionRestarted(uint40 requestCount); event AuctionStarted(uint40 requestCount); event AuctionEnded(uint40 requestCount, Bid winningBid); @@ -57,6 +60,10 @@ contract AuctionManager is AuctionManagerStorage, AppGatewayBase, AccessControl event AuctionEndDelaySecondsSet(uint256 auctionEndDelaySeconds); event MaxReAuctionCountSet(uint256 maxReAuctionCount); + constructor() { + _disableInitializers(); // disable for implementation + } + /// @param evmxSlug_ The evmx chain slug /// @param bidTimeout_ The timeout after which a bid expires /// @param maxReAuctionCount_ The maximum number of re-auctions allowed @@ -64,10 +71,6 @@ contract AuctionManager is AuctionManagerStorage, AppGatewayBase, AccessControl /// @param addressResolver_ The address of the address resolver /// @param owner_ The address of the contract owner - constructor() { - _disableInitializers(); // disable for implementation - } - function initialize( uint32 evmxSlug_, uint128 bidTimeout_, @@ -147,7 +150,8 @@ contract AuctionManager is AuctionManagerStorage, AppGatewayBase, AccessControl auctionEndDelaySeconds ), address(this), - abi.encodeWithSelector(this.endAuction.selector, requestCount_) + this.endAuction.selector, + abi.encode(requestCount_) ); } else { _endAuction(requestCount_); @@ -187,7 +191,8 @@ contract AuctionManager is AuctionManagerStorage, AppGatewayBase, AccessControl bidTimeout, deductScheduleFees(winningBid.transmitter, address(this), bidTimeout), winningBid.transmitter, - abi.encodeWithSelector(this.expireBid.selector, requestCount_) + this.expireBid.selector, + abi.encode(requestCount_) ); // start the request processing, it will queue the request @@ -226,7 +231,8 @@ contract AuctionManager is AuctionManagerStorage, AppGatewayBase, AccessControl uint256 delayInSeconds_, uint256 maxFees_, address consumeFrom_, - bytes memory payload_ + bytes4 callbackSelector_, + bytes memory callbackData_ ) internal { OverrideParams memory overrideParams; overrideParams.callType = SCHEDULE; @@ -234,8 +240,11 @@ contract AuctionManager is AuctionManagerStorage, AppGatewayBase, AccessControl QueueParams memory queueParams; queueParams.overrideParams = overrideParams; + // queue and create request - watcher__().queueAndSubmit(queueParams, maxFees_, address(this), consumeFrom_, bytes("")); + watcher__().queue(queueParams, address(this)); + then(callbackSelector_, callbackData_); + watcher__().submitRequest(maxFees_, address(this), consumeFrom_, bytes("")); } /// @notice Returns the quoted transmitter fees for a request diff --git a/contracts/evmx/helpers/AsyncPromise.sol b/contracts/evmx/helpers/AsyncPromise.sol index 8392acfa..951779e7 100644 --- a/contracts/evmx/helpers/AsyncPromise.sol +++ b/contracts/evmx/helpers/AsyncPromise.sol @@ -57,6 +57,8 @@ contract AsyncPromise is AsyncPromiseStorage, Initializable, AddressResolverUtil error PromiseAlreadySetUp(); /// @notice Error thrown when the promise reverts error PromiseRevertFailed(); + /// @notice Error thrown when the promise is not the latest promise set by the watcher + error NotLatestPromise(); constructor() { _disableInitializers(); // disable for implementation @@ -145,7 +147,7 @@ contract AsyncPromise is AsyncPromiseStorage, Initializable, AddressResolverUtil if (state != AsyncPromiseState.WAITING_FOR_CALLBACK_SELECTOR) { revert PromiseAlreadySetUp(); } - if (watcher__().latestAsyncPromise() != address(this)) revert PromiseAlreadySetUp(); + if (watcher__().latestAsyncPromise() != address(this)) revert NotLatestPromise(); if (requestCount != watcher__().getCurrentRequestCount()) revert RequestCountMismatch(); // if the promise is waiting for the callback selector, set it and update the state diff --git a/contracts/evmx/watcher/Watcher.sol b/contracts/evmx/watcher/Watcher.sol index 863f45c3..ef41a9b3 100644 --- a/contracts/evmx/watcher/Watcher.sol +++ b/contracts/evmx/watcher/Watcher.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.21; import "./Trigger.sol"; +import "../interfaces/IPromise.sol"; contract Watcher is Trigger { constructor() { @@ -37,13 +38,14 @@ contract Watcher is Trigger { account_ == address(promiseResolver__); } + // can be called to submit single payload request without any callback function queueAndSubmit( QueueParams memory queue_, uint256 maxFees, address auctionManager, address consumeFrom, bytes memory onCompleteData - ) external returns (uint40, address[] memory) { + ) external returns (uint40 requestCount, address[] memory promises) { _queue(queue_, msg.sender); return _submitRequest(maxFees, auctionManager, consumeFrom, onCompleteData); } diff --git a/test/SetupTest.t.sol b/test/SetupTest.t.sol index 0cb38ec8..ff64f83e 100644 --- a/test/SetupTest.t.sol +++ b/test/SetupTest.t.sol @@ -266,6 +266,11 @@ contract DeploySetup is SetupStore { AddressResolver addressResolverImpl = new AddressResolver(); AsyncDeployer asyncDeployerImpl = new AsyncDeployer(); Watcher watcherImpl = new Watcher(); + AuctionManager auctionManagerImpl = new AuctionManager(); + DeployForwarder deployForwarderImpl = new DeployForwarder(); + Configurations configurationsImpl = new Configurations(); + RequestHandler requestHandlerImpl = new RequestHandler(); + WritePrecompile writePrecompileImpl = new WritePrecompile(); // Deploy and initialize proxies address addressResolverProxy = _deployAndVerifyProxy( @@ -300,6 +305,32 @@ contract DeploySetup is SetupStore { ); asyncDeployer = AsyncDeployer(asyncDeployerProxy); + address auctionManagerProxy = _deployAndVerifyProxy( + address(auctionManagerImpl), + watcherEOA, + abi.encodeWithSelector( + AuctionManager.initialize.selector, + evmxSlug, + uint128(bidTimeout), + maxReAuctionCount, + auctionEndDelaySeconds, + address(addressResolver), + watcherEOA + ) + ); + auctionManager = AuctionManager(auctionManagerProxy); + + address deployForwarderProxy = _deployAndVerifyProxy( + address(deployForwarderImpl), + watcherEOA, + abi.encodeWithSelector( + DeployForwarder.initialize.selector, + address(addressResolver), + FAST + ) + ); + deployForwarder = DeployForwarder(deployForwarderProxy); + address watcherProxy = _deployAndVerifyProxy( address(watcherImpl), watcherEOA, @@ -313,20 +344,39 @@ contract DeploySetup is SetupStore { ); watcher = Watcher(watcherProxy); - // non proxy contracts - auctionManager = new AuctionManager( - evmxSlug, - uint128(bidTimeout), - maxReAuctionCount, - auctionEndDelaySeconds, - address(addressResolver), - watcherEOA + address requestHandlerProxy = _deployAndVerifyProxy( + address(requestHandlerImpl), + watcherEOA, + abi.encodeWithSelector( + RequestHandler.initialize.selector, + watcherEOA, + address(addressResolver) + ) + ); + requestHandler = RequestHandler(requestHandlerProxy); + + address configurationsProxy = _deployAndVerifyProxy( + address(configurationsImpl), + watcherEOA, + abi.encodeWithSelector(Configurations.initialize.selector, address(watcher), watcherEOA) + ); + configurations = Configurations(configurationsProxy); + + address writePrecompileProxy = _deployAndVerifyProxy( + address(writePrecompileImpl), + watcherEOA, + abi.encodeWithSelector( + WritePrecompile.initialize.selector, + watcherEOA, + address(watcher), + writeFees, + expiryTime + ) ); - deployForwarder = new DeployForwarder(address(addressResolver), FAST); - configurations = new Configurations(address(watcher), watcherEOA); - requestHandler = new RequestHandler(watcherEOA, address(addressResolver)); + writePrecompile = WritePrecompile(writePrecompileProxy); + + // non proxy contracts promiseResolver = new PromiseResolver(address(watcher)); - writePrecompile = new WritePrecompile(watcherEOA, address(watcher), writeFees, expiryTime); readPrecompile = new ReadPrecompile(address(watcher), readFees, expiryTime); schedulePrecompile = new SchedulePrecompile( address(watcher), @@ -575,10 +625,10 @@ contract AuctionSetup is FeesSetup { // todo: handle other cases uint256 bidAmount = getBidAmount(requestCount_); - bytes memory watcherSignature = _createSignature( - keccak256(abi.encode(address(watcher), evmxSlug, requestCount_, bidAmount, "")), - watcherPrivateKey - ); + // bytes memory watcherSignature = _createSignature( + // keccak256(abi.encode(address(watcher), evmxSlug, requestCount_, bidAmount, "")), + // watcherPrivateKey + // ); vm.expectEmit(true, true, true, true); emit AuctionEnded( From 8036f4244d703fa22e8e69d4cf0de99e4acf78e2 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Thu, 29 May 2025 17:48:16 +0530 Subject: [PATCH 093/130] feat: rescue funds --- contracts/evmx/AuctionManager.sol | 20 ++++++++++++++-- contracts/evmx/fees/Credit.sol | 8 +++++-- contracts/evmx/fees/FeesManager.sol | 15 ++++++++++++ contracts/evmx/helpers/AddressResolver.sol | 24 +++++++++++++++++-- contracts/evmx/helpers/AsyncDeployer.sol | 24 ++++++++++++++++--- contracts/evmx/helpers/AsyncPromise.sol | 12 ++++++++++ contracts/evmx/helpers/DeployForwarder.sol | 24 +++++++++++++++++-- contracts/evmx/helpers/Forwarder.sol | 12 ++++++++++ contracts/evmx/watcher/Configurations.sol | 16 +++++++++++++ contracts/evmx/watcher/PromiseResolver.sol | 12 ++++++++++ contracts/evmx/watcher/RequestHandler.sol | 12 ++++++++++ contracts/evmx/watcher/Watcher.sol | 23 ++++++++++++++++++ contracts/evmx/watcher/WatcherStorage.sol | 3 ++- .../watcher/precompiles/ReadPrecompile.sol | 12 ++++++++++ .../precompiles/SchedulePrecompile.sol | 12 ++++++++++ .../watcher/precompiles/WritePrecompile.sol | 12 ++++++++++ contracts/utils/AccessControl.sol | 2 +- test/SetupTest.t.sol | 1 + 18 files changed, 231 insertions(+), 13 deletions(-) diff --git a/contracts/evmx/AuctionManager.sol b/contracts/evmx/AuctionManager.sol index be6a7a3e..006b4d82 100644 --- a/contracts/evmx/AuctionManager.sol +++ b/contracts/evmx/AuctionManager.sol @@ -7,10 +7,11 @@ import "./interfaces/IPromise.sol"; import "./interfaces/IAuctionManager.sol"; import "../utils/AccessControl.sol"; +import "../utils/RescueFundsLib.sol"; import {AuctionNotOpen, AuctionClosed, BidExceedsMaxFees, LowerBidAlreadyExists, InvalidTransmitter, MaxReAuctionCountReached, InvalidBid} from "../utils/common/Errors.sol"; import {SCHEDULE} from "../utils/common/Constants.sol"; -import {TRANSMITTER_ROLE} from "../utils/common/AccessRoles.sol"; +import {TRANSMITTER_ROLE, RESCUE_ROLE} from "../utils/common/AccessRoles.sol"; import {AppGatewayBase} from "./base/AppGatewayBase.sol"; /// @title AuctionManagerStorage @@ -47,7 +48,7 @@ abstract contract AuctionManagerStorage is IAuctionManager { uint256[50] _gap_after; // slots [106-164] 59 slots reserved for app gateway base - // slots [165-215] 51 slots reserved for access control + // slots [165-214] 50 slots reserved for access control } /// @title AuctionManager @@ -284,4 +285,19 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AppGatewayBase, // recovered signer is checked for the valid roles later signer = ECDSA.recover(digest, signature_); } + + /** + * @notice Rescues funds from the contract if they are locked by mistake. This contract does not + * theoretically need this function but it is added for safety. + * @param token_ The address of the token contract. + * @param rescueTo_ The address where rescued tokens need to be sent. + * @param amount_ The amount of tokens to be rescued. + */ + function rescueFunds( + address token_, + address rescueTo_, + uint256 amount_ + ) external onlyRole(RESCUE_ROLE) { + RescueFundsLib._rescueFunds(token_, rescueTo_, amount_); + } } diff --git a/contracts/evmx/fees/Credit.sol b/contracts/evmx/fees/Credit.sol index 625b6368..f74f64ba 100644 --- a/contracts/evmx/fees/Credit.sol +++ b/contracts/evmx/fees/Credit.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import {Ownable} from "solady/auth/Ownable.sol"; import "solady/utils/Initializable.sol"; import "solady/utils/ECDSA.sol"; import "solady/utils/SafeTransferLib.sol"; @@ -14,6 +13,10 @@ import {AddressResolverUtil} from "../helpers/AddressResolverUtil.sol"; import {NonceUsed, InvalidAmount, InsufficientCreditsAvailable, InsufficientBalance, InvalidChainSlug, NotRequestHandler} from "../../utils/common/Errors.sol"; import {WRITE} from "../../utils/common/Constants.sol"; +import {RESCUE_ROLE} from "../../utils/common/AccessRoles.sol"; +import "../../utils/RescueFundsLib.sol"; +import "../../utils/AccessControl.sol"; + abstract contract FeesManagerStorage is IFeesManager { // slots [0-49] reserved for gap uint256[50] _gap_before; @@ -62,11 +65,12 @@ abstract contract FeesManagerStorage is IFeesManager { uint256[50] _gap_after; // slots [108-157] 50 slots reserved for address resolver util + // slots [158-207] 50 slots reserved for access control } /// @title UserUtils /// @notice Contract for managing user utils -abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressResolverUtil { +abstract contract Credit is FeesManagerStorage, Initializable, AccessControl, AddressResolverUtil { /// @notice Emitted when fees deposited are updated /// @param chainSlug The chain identifier /// @param token The token address diff --git a/contracts/evmx/fees/FeesManager.sol b/contracts/evmx/fees/FeesManager.sol index 6e1fea3c..444cc253 100644 --- a/contracts/evmx/fees/FeesManager.sol +++ b/contracts/evmx/fees/FeesManager.sol @@ -112,4 +112,19 @@ contract FeesManager is Credit { delete requestBlockedCredits[requestCount_]; emit CreditsUnblocked(requestCount_, consumeFrom); } + + /** + * @notice Rescues funds from the contract if they are locked by mistake. This contract does not + * theoretically need this function but it is added for safety. + * @param token_ The address of the token contract. + * @param rescueTo_ The address where rescued tokens need to be sent. + * @param amount_ The amount of tokens to be rescued. + */ + function rescueFunds( + address token_, + address rescueTo_, + uint256 amount_ + ) external onlyRole(RESCUE_ROLE) { + RescueFundsLib._rescueFunds(token_, rescueTo_, amount_); + } } diff --git a/contracts/evmx/helpers/AddressResolver.sol b/contracts/evmx/helpers/AddressResolver.sol index 661e79e0..efc113f9 100644 --- a/contracts/evmx/helpers/AddressResolver.sol +++ b/contracts/evmx/helpers/AddressResolver.sol @@ -1,8 +1,11 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import {Ownable} from "solady/auth/Ownable.sol"; import {Initializable} from "solady/utils/Initializable.sol"; +import {RESCUE_ROLE} from "../../utils/common/AccessRoles.sol"; +import "../../utils/RescueFundsLib.sol"; +import "../../utils/AccessControl.sol"; + import "../interfaces/IAddressResolver.sol"; abstract contract AddressResolverStorage is IAddressResolver { @@ -29,12 +32,14 @@ abstract contract AddressResolverStorage is IAddressResolver { // slots [56-105] reserved for gap uint256[50] _gap_after; + + // slots [106-155] 50 slots reserved for access control } /// @title AddressResolver Contract /// @notice This contract is responsible for fetching latest core addresses and deploying Forwarder and AsyncPromise contracts. /// @dev Inherits the Ownable contract and implements the IAddressResolver interface. -contract AddressResolver is AddressResolverStorage, Initializable, Ownable { +contract AddressResolver is AddressResolverStorage, Initializable, AccessControl { /// @notice Constructor to initialize the contract /// @dev it deploys the forwarder and async promise implementations and beacons for them /// @dev this contract is owner of the beacons for upgrading later @@ -95,4 +100,19 @@ contract AddressResolver is AddressResolverStorage, Initializable, Ownable { contractAddresses[contractId_] = contractAddress_; emit ContractAddressUpdated(contractId_, contractAddress_); } + + /** + * @notice Rescues funds from the contract if they are locked by mistake. This contract does not + * theoretically need this function but it is added for safety. + * @param token_ The address of the token contract. + * @param rescueTo_ The address where rescued tokens need to be sent. + * @param amount_ The amount of tokens to be rescued. + */ + function rescueFunds( + address token_, + address rescueTo_, + uint256 amount_ + ) external onlyRole(RESCUE_ROLE) { + RescueFundsLib._rescueFunds(token_, rescueTo_, amount_); + } } diff --git a/contracts/evmx/helpers/AsyncDeployer.sol b/contracts/evmx/helpers/AsyncDeployer.sol index 29b400d2..3f204cf1 100644 --- a/contracts/evmx/helpers/AsyncDeployer.sol +++ b/contracts/evmx/helpers/AsyncDeployer.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import {Ownable} from "solady/auth/Ownable.sol"; import {LibClone} from "solady/utils/LibClone.sol"; import {UpgradeableBeacon} from "solady/utils/UpgradeableBeacon.sol"; import {Initializable} from "solady/utils/Initializable.sol"; @@ -9,6 +8,9 @@ import "../interfaces/IAsyncDeployer.sol"; import {Forwarder} from "./Forwarder.sol"; import {AsyncPromise} from "./AsyncPromise.sol"; import {AddressResolverUtil} from "./AddressResolverUtil.sol"; +import {RESCUE_ROLE} from "../../utils/common/AccessRoles.sol"; +import "../../utils/RescueFundsLib.sol"; +import "../../utils/AccessControl.sol"; abstract contract AsyncDeployerStorage is IAsyncDeployer { // slots [0-49] reserved for gap @@ -33,12 +35,13 @@ abstract contract AsyncDeployerStorage is IAsyncDeployer { uint256[50] _gap_after; // slots [106-155] 50 slots reserved for address resolver util + // slots [156-205] 50 slots reserved for access control } /// @title AsyncDeployer Contract /// @notice This contract is responsible for deploying Forwarder and AsyncPromise contracts. -/// @dev Inherits the Ownable contract and implements the IAddressResolver interface. -contract AsyncDeployer is AsyncDeployerStorage, Initializable, Ownable, AddressResolverUtil { +/// @dev Inherits the AccessControl contract and implements the IAddressResolver interface. +contract AsyncDeployer is AsyncDeployerStorage, Initializable, AddressResolverUtil, AccessControl { constructor() { _disableInitializers(); // disable for implementation } @@ -208,4 +211,19 @@ contract AsyncDeployer is AsyncDeployerStorage, Initializable, Ownable, AddressR asyncPromiseBeacon.upgradeTo(implementation_); emit ImplementationUpdated("AsyncPromise", implementation_); } + + /** + * @notice Rescues funds from the contract if they are locked by mistake. This contract does not + * theoretically need this function but it is added for safety. + * @param token_ The address of the token contract. + * @param rescueTo_ The address where rescued tokens need to be sent. + * @param amount_ The amount of tokens to be rescued. + */ + function rescueFunds( + address token_, + address rescueTo_, + uint256 amount_ + ) external onlyRole(RESCUE_ROLE) { + RescueFundsLib._rescueFunds(token_, rescueTo_, amount_); + } } diff --git a/contracts/evmx/helpers/AsyncPromise.sol b/contracts/evmx/helpers/AsyncPromise.sol index 951779e7..dcf009da 100644 --- a/contracts/evmx/helpers/AsyncPromise.sol +++ b/contracts/evmx/helpers/AsyncPromise.sol @@ -7,6 +7,7 @@ import {AddressResolverUtil} from "./AddressResolverUtil.sol"; import {IAppGateway} from "../interfaces/IAppGateway.sol"; import "../interfaces/IPromise.sol"; import {NotInvoker, RequestCountMismatch} from "../../utils/common/Errors.sol"; +import "../../utils/RescueFundsLib.sol"; abstract contract AsyncPromiseStorage is IPromise { // slots [0-49] reserved for gap @@ -155,4 +156,15 @@ contract AsyncPromise is AsyncPromiseStorage, Initializable, AddressResolverUtil callbackData = data_; state = AsyncPromiseState.WAITING_FOR_CALLBACK_EXECUTION; } + + /** + * @notice Rescues funds from the contract if they are locked by mistake. This contract does not + * theoretically need this function but it is added for safety. + * @param token_ The address of the token contract. + * @param rescueTo_ The address where rescued tokens need to be sent. + * @param amount_ The amount of tokens to be rescued. + */ + function rescueFunds(address token_, address rescueTo_, uint256 amount_) external onlyWatcher { + RescueFundsLib._rescueFunds(token_, rescueTo_, amount_); + } } diff --git a/contracts/evmx/helpers/DeployForwarder.sol b/contracts/evmx/helpers/DeployForwarder.sol index aa67d12a..b26f5415 100644 --- a/contracts/evmx/helpers/DeployForwarder.sol +++ b/contracts/evmx/helpers/DeployForwarder.sol @@ -5,15 +5,18 @@ import {Initializable} from "solady/utils/Initializable.sol"; import {IAppGateway} from "../interfaces/IAppGateway.sol"; import {IContractFactoryPlug} from "../interfaces/IContractFactoryPlug.sol"; import {IDeployForwarder} from "../interfaces/IDeployForwarder.sol"; -import "./AddressResolverUtil.sol"; import {AsyncModifierNotSet} from "../../utils/common/Errors.sol"; import {QueueParams, OverrideParams, Transaction} from "../../utils/common/Structs.sol"; import {WRITE} from "../../utils/common/Constants.sol"; import {encodeAppGatewayId} from "../../utils/common/IdUtils.sol"; +import {RESCUE_ROLE} from "../../utils/common/AccessRoles.sol"; +import "../../utils/RescueFundsLib.sol"; +import "../../utils/AccessControl.sol"; +import "./AddressResolverUtil.sol"; /// @title DeployForwarder /// @notice contract responsible for handling deployment requests -contract DeployForwarder is IDeployForwarder, Initializable, AddressResolverUtil { +contract DeployForwarder is IDeployForwarder, Initializable, AddressResolverUtil, AccessControl { // slots [0-49] 50 slots reserved for address resolver util // slots [50-99] reserved for gap @@ -31,11 +34,13 @@ contract DeployForwarder is IDeployForwarder, Initializable, AddressResolverUtil } function initialize( + address owner_, address addressResolver_, bytes32 deployerSwitchboardType_ ) public reinitializer(1) { deployerSwitchboardType = deployerSwitchboardType_; _setAddressResolver(addressResolver_); + _initializeOwner(owner_); } /// @notice Deploys a contract @@ -95,4 +100,19 @@ contract DeployForwarder is IDeployForwarder, Initializable, AddressResolverUtil initCallData_ ); } + + /** + * @notice Rescues funds from the contract if they are locked by mistake. This contract does not + * theoretically need this function but it is added for safety. + * @param token_ The address of the token contract. + * @param rescueTo_ The address where rescued tokens need to be sent. + * @param amount_ The amount of tokens to be rescued. + */ + function rescueFunds( + address token_, + address rescueTo_, + uint256 amount_ + ) external onlyRole(RESCUE_ROLE) { + RescueFundsLib._rescueFunds(token_, rescueTo_, amount_); + } } diff --git a/contracts/evmx/helpers/Forwarder.sol b/contracts/evmx/helpers/Forwarder.sol index 60b91b69..aa227942 100644 --- a/contracts/evmx/helpers/Forwarder.sol +++ b/contracts/evmx/helpers/Forwarder.sol @@ -8,6 +8,7 @@ import "../interfaces/IAppGateway.sol"; import "../interfaces/IForwarder.sol"; import {QueueParams, OverrideParams, Transaction} from "../../utils/common/Structs.sol"; import {AsyncModifierNotSet, WatcherNotSet} from "../../utils/common/Errors.sol"; +import "../../utils/RescueFundsLib.sol"; /// @title Forwarder Storage /// @notice Storage contract for the Forwarder contract that contains the state variables @@ -60,6 +61,17 @@ contract Forwarder is ForwarderStorage, Initializable, AddressResolverUtil { return chainSlug; } + /** + * @notice Rescues funds from the contract if they are locked by mistake. This contract does not + * theoretically need this function but it is added for safety. + * @param token_ The address of the token contract. + * @param rescueTo_ The address where rescued tokens need to be sent. + * @param amount_ The amount of tokens to be rescued. + */ + function rescueFunds(address token_, address rescueTo_, uint256 amount_) external onlyWatcher { + RescueFundsLib._rescueFunds(token_, rescueTo_, amount_); + } + /// @notice Fallback function to process the contract calls to onChainAddress /// @dev It queues the calls in the middleware and deploys the promise contract fallback() external { diff --git a/contracts/evmx/watcher/Configurations.sol b/contracts/evmx/watcher/Configurations.sol index 1d9ab69b..21c2b4ea 100644 --- a/contracts/evmx/watcher/Configurations.sol +++ b/contracts/evmx/watcher/Configurations.sol @@ -7,6 +7,7 @@ import {WatcherBase} from "./WatcherBase.sol"; import {encodeAppGatewayId} from "../../utils/common/IdUtils.sol"; import {InvalidGateway, InvalidSwitchboard} from "../../utils/common/Errors.sol"; import "solady/auth/Ownable.sol"; +import "../../utils/RescueFundsLib.sol"; abstract contract ConfigurationsStorage is IConfigurations { // slots [0-49] reserved for gap @@ -161,4 +162,19 @@ contract Configurations is ConfigurationsStorage, Initializable, Ownable, Watche if (appGatewayId != encodeAppGatewayId(appGateway_)) revert InvalidGateway(); if (switchboard != switchboards[chainSlug_][switchboardType_]) revert InvalidSwitchboard(); } + + /** + * @notice Rescues funds from the contract if they are locked by mistake. This contract does not + * theoretically need this function but it is added for safety. + * @param token_ The address of the token contract. + * @param rescueTo_ The address where rescued tokens need to be sent. + * @param amount_ The amount of tokens to be rescued. + */ + function rescueFunds( + address token_, + address rescueTo_, + uint256 amount_ + ) external onlyWatcher { + RescueFundsLib._rescueFunds(token_, rescueTo_, amount_); + } } diff --git a/contracts/evmx/watcher/PromiseResolver.sol b/contracts/evmx/watcher/PromiseResolver.sol index a6eed239..d226492c 100644 --- a/contracts/evmx/watcher/PromiseResolver.sol +++ b/contracts/evmx/watcher/PromiseResolver.sol @@ -5,6 +5,7 @@ import "./WatcherBase.sol"; import "../interfaces/IPromise.sol"; import "../interfaces/IPromiseResolver.sol"; import {DeadlineNotPassedForOnChainRevert} from "../../utils/common/Errors.sol"; +import "../../utils/RescueFundsLib.sol"; /// @title PromiseResolver /// @notice Contract that handles promise resolution and revert marking logic @@ -92,4 +93,15 @@ contract PromiseResolver is IPromiseResolver, WatcherBase { emit MarkedRevert(payloadId, isRevertingOnchain_); } + + /** + * @notice Rescues funds from the contract if they are locked by mistake. This contract does not + * theoretically need this function but it is added for safety. + * @param token_ The address of the token contract. + * @param rescueTo_ The address where rescued tokens need to be sent. + * @param amount_ The amount of tokens to be rescued. + */ + function rescueFunds(address token_, address rescueTo_, uint256 amount_) external onlyWatcher { + RescueFundsLib._rescueFunds(token_, rescueTo_, amount_); + } } diff --git a/contracts/evmx/watcher/RequestHandler.sol b/contracts/evmx/watcher/RequestHandler.sol index 6a1d799e..230e49d9 100644 --- a/contracts/evmx/watcher/RequestHandler.sol +++ b/contracts/evmx/watcher/RequestHandler.sol @@ -10,6 +10,7 @@ import "../../utils/common/IdUtils.sol"; import "../interfaces/IAppGateway.sol"; import "../interfaces/IPromise.sol"; import "../interfaces/IRequestHandler.sol"; +import "../../utils/RescueFundsLib.sol"; abstract contract RequestHandlerStorage is IRequestHandler { // slots [0-49] reserved for gap @@ -420,4 +421,15 @@ contract RequestHandler is RequestHandlerStorage, Initializable, Ownable, Addres emit RequestSettled(requestCount_, r.requestFeesDetails.winningBid.transmitter); } + + /** + * @notice Rescues funds from the contract if they are locked by mistake. This contract does not + * theoretically need this function but it is added for safety. + * @param token_ The address of the token contract. + * @param rescueTo_ The address where rescued tokens need to be sent. + * @param amount_ The amount of tokens to be rescued. + */ + function rescueFunds(address token_, address rescueTo_, uint256 amount_) external onlyWatcher { + RescueFundsLib._rescueFunds(token_, rescueTo_, amount_); + } } diff --git a/contracts/evmx/watcher/Watcher.sol b/contracts/evmx/watcher/Watcher.sol index ef41a9b3..05586c90 100644 --- a/contracts/evmx/watcher/Watcher.sol +++ b/contracts/evmx/watcher/Watcher.sol @@ -225,4 +225,27 @@ contract Watcher is Trigger { // recovered signer is checked for the valid roles later signer = ECDSA.recover(digest, signature_); } + + /** + * @notice Rescues funds from the contract if they are locked by mistake. This contract does not + * theoretically need this function but it is added for safety. + * @param token_ The address of the token contract. + * @param rescueTo_ The address where rescued tokens need to be sent. + * @param amount_ The amount of tokens to be rescued. + */ + function rescueFunds( + address token_, + address rescueTo_, + uint256 amount_, + uint256 nonce_, + bytes memory signature_ + ) external { + _validateSignature( + address(this), + abi.encode(token_, rescueTo_, amount_), + nonce_, + signature_ + ); + RescueFundsLib._rescueFunds(token_, rescueTo_, amount_); + } } diff --git a/contracts/evmx/watcher/WatcherStorage.sol b/contracts/evmx/watcher/WatcherStorage.sol index f6bdc046..4811d600 100644 --- a/contracts/evmx/watcher/WatcherStorage.sol +++ b/contracts/evmx/watcher/WatcherStorage.sol @@ -5,7 +5,8 @@ import "../interfaces/IWatcher.sol"; import "../helpers/AddressResolverUtil.sol"; import "solady/utils/ECDSA.sol"; import {Initializable} from "solady/utils/Initializable.sol"; -import {Ownable} from "solady/auth/Ownable.sol"; +import "../../utils/RescueFundsLib.sol"; +import "solady/auth/Ownable.sol"; /// @title WatcherStorage /// @notice Storage contract for the WatcherPrecompile system diff --git a/contracts/evmx/watcher/precompiles/ReadPrecompile.sol b/contracts/evmx/watcher/precompiles/ReadPrecompile.sol index e4e1fc1f..e8c7f2e8 100644 --- a/contracts/evmx/watcher/precompiles/ReadPrecompile.sol +++ b/contracts/evmx/watcher/precompiles/ReadPrecompile.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.21; import "../../interfaces/IPrecompile.sol"; import "../../../utils/common/Structs.sol"; import "../../../utils/common/Errors.sol"; +import "../../../utils/RescueFundsLib.sol"; import "../WatcherBase.sol"; /// @title Read @@ -85,4 +86,15 @@ contract ReadPrecompile is IPrecompile, WatcherBase { expiryTime = expiryTime_; emit ExpiryTimeSet(expiryTime_); } + + /** + * @notice Rescues funds from the contract if they are locked by mistake. This contract does not + * theoretically need this function but it is added for safety. + * @param token_ The address of the token contract. + * @param rescueTo_ The address where rescued tokens need to be sent. + * @param amount_ The amount of tokens to be rescued. + */ + function rescueFunds(address token_, address rescueTo_, uint256 amount_) external onlyWatcher { + RescueFundsLib._rescueFunds(token_, rescueTo_, amount_); + } } diff --git a/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol b/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol index 0e6f7dca..597928c7 100644 --- a/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/SchedulePrecompile.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.21; import "../../interfaces/IPrecompile.sol"; import "../../../utils/common/Structs.sol"; import {InvalidScheduleDelay, ResolvingScheduleTooEarly} from "../../../utils/common/Errors.sol"; +import "../../../utils/RescueFundsLib.sol"; import "../WatcherBase.sol"; /// @title SchedulePrecompile @@ -137,4 +138,15 @@ contract SchedulePrecompile is IPrecompile, WatcherBase { if (executeAfter > block.timestamp) revert ResolvingScheduleTooEarly(); emit ScheduleResolved(payloadParams_.payloadId); } + + /** + * @notice Rescues funds from the contract if they are locked by mistake. This contract does not + * theoretically need this function but it is added for safety. + * @param token_ The address of the token contract. + * @param rescueTo_ The address where rescued tokens need to be sent. + * @param amount_ The amount of tokens to be rescued. + */ + function rescueFunds(address token_, address rescueTo_, uint256 amount_) external onlyWatcher { + RescueFundsLib._rescueFunds(token_, rescueTo_, amount_); + } } diff --git a/contracts/evmx/watcher/precompiles/WritePrecompile.sol b/contracts/evmx/watcher/precompiles/WritePrecompile.sol index b7f1c6c6..7b2434b5 100644 --- a/contracts/evmx/watcher/precompiles/WritePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/WritePrecompile.sol @@ -8,6 +8,7 @@ import "../../interfaces/IPrecompile.sol"; import {WRITE, PAYLOAD_SIZE_LIMIT} from "../../../utils/common/Constants.sol"; import {InvalidIndex, MaxMsgValueLimitExceeded, InvalidPayloadSize} from "../../../utils/common/Errors.sol"; import {encodeAppGatewayId} from "../../../utils/common/IdUtils.sol"; +import "../../../utils/RescueFundsLib.sol"; import "../WatcherBase.sol"; abstract contract WritePrecompileStorage is IPrecompile { @@ -287,4 +288,15 @@ contract WritePrecompile is WritePrecompileStorage, Initializable, Ownable, Watc function resolvePayload( PayloadParams calldata payloadParams_ ) external override onlyRequestHandler {} + + /** + * @notice Rescues funds from the contract if they are locked by mistake. This contract does not + * theoretically need this function but it is added for safety. + * @param token_ The address of the token contract. + * @param rescueTo_ The address where rescued tokens need to be sent. + * @param amount_ The amount of tokens to be rescued. + */ + function rescueFunds(address token_, address rescueTo_, uint256 amount_) external onlyWatcher { + RescueFundsLib._rescueFunds(token_, rescueTo_, amount_); + } } diff --git a/contracts/utils/AccessControl.sol b/contracts/utils/AccessControl.sol index c25f0645..29225404 100644 --- a/contracts/utils/AccessControl.sol +++ b/contracts/utils/AccessControl.sol @@ -17,7 +17,7 @@ abstract contract AccessControl is Ownable { mapping(bytes32 => mapping(address => bool)) private _permits; // slots 1-50: gap for future storage variables - uint256[50] _gap_access_control; + uint256[49] _gap_access_control; /** * @dev Emitted when a role is granted to an address. diff --git a/test/SetupTest.t.sol b/test/SetupTest.t.sol index ff64f83e..204f69eb 100644 --- a/test/SetupTest.t.sol +++ b/test/SetupTest.t.sol @@ -325,6 +325,7 @@ contract DeploySetup is SetupStore { watcherEOA, abi.encodeWithSelector( DeployForwarder.initialize.selector, + watcherEOA, address(addressResolver), FAST ) From 8feef74311f9e8e26399523c2bb3ab00fc25c3d4 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Fri, 30 May 2025 12:48:04 +0530 Subject: [PATCH 094/130] fix: owner auth --- contracts/evmx/AuctionManager.sol | 4 ++-- contracts/evmx/fees/Credit.sol | 6 ++---- contracts/evmx/fees/FeesManager.sol | 6 +----- contracts/evmx/helpers/AddressResolver.sol | 20 +++++++++----------- 4 files changed, 14 insertions(+), 22 deletions(-) diff --git a/contracts/evmx/AuctionManager.sol b/contracts/evmx/AuctionManager.sol index 006b4d82..9e2c8db0 100644 --- a/contracts/evmx/AuctionManager.sol +++ b/contracts/evmx/AuctionManager.sol @@ -89,12 +89,12 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AppGatewayBase, _initializeAppGateway(addressResolver_); } - function setAuctionEndDelaySeconds(uint256 auctionEndDelaySeconds_) external onlyOwner { + function setAuctionEndDelaySeconds(uint256 auctionEndDelaySeconds_) external onlyWatcher { auctionEndDelaySeconds = auctionEndDelaySeconds_; emit AuctionEndDelaySecondsSet(auctionEndDelaySeconds_); } - function setMaxReAuctionCount(uint256 maxReAuctionCount_) external onlyOwner { + function setMaxReAuctionCount(uint256 maxReAuctionCount_) external onlyWatcher { maxReAuctionCount = maxReAuctionCount_; emit MaxReAuctionCountSet(maxReAuctionCount_); } diff --git a/contracts/evmx/fees/Credit.sol b/contracts/evmx/fees/Credit.sol index f74f64ba..1ad0f7a4 100644 --- a/contracts/evmx/fees/Credit.sol +++ b/contracts/evmx/fees/Credit.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.21; import "solady/utils/Initializable.sol"; import "solady/utils/ECDSA.sol"; import "solady/utils/SafeTransferLib.sol"; +import "solady/auth/Ownable.sol"; import "../interfaces/IFeesManager.sol"; import "../interfaces/IFeesPlug.sol"; @@ -12,10 +13,7 @@ import "../interfaces/IFeesPool.sol"; import {AddressResolverUtil} from "../helpers/AddressResolverUtil.sol"; import {NonceUsed, InvalidAmount, InsufficientCreditsAvailable, InsufficientBalance, InvalidChainSlug, NotRequestHandler} from "../../utils/common/Errors.sol"; import {WRITE} from "../../utils/common/Constants.sol"; - -import {RESCUE_ROLE} from "../../utils/common/AccessRoles.sol"; import "../../utils/RescueFundsLib.sol"; -import "../../utils/AccessControl.sol"; abstract contract FeesManagerStorage is IFeesManager { // slots [0-49] reserved for gap @@ -70,7 +68,7 @@ abstract contract FeesManagerStorage is IFeesManager { /// @title UserUtils /// @notice Contract for managing user utils -abstract contract Credit is FeesManagerStorage, Initializable, AccessControl, AddressResolverUtil { +abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressResolverUtil { /// @notice Emitted when fees deposited are updated /// @param chainSlug The chain identifier /// @param token The token address diff --git a/contracts/evmx/fees/FeesManager.sol b/contracts/evmx/fees/FeesManager.sol index 444cc253..306b27c2 100644 --- a/contracts/evmx/fees/FeesManager.sol +++ b/contracts/evmx/fees/FeesManager.sol @@ -120,11 +120,7 @@ contract FeesManager is Credit { * @param rescueTo_ The address where rescued tokens need to be sent. * @param amount_ The amount of tokens to be rescued. */ - function rescueFunds( - address token_, - address rescueTo_, - uint256 amount_ - ) external onlyRole(RESCUE_ROLE) { + function rescueFunds(address token_, address rescueTo_, uint256 amount_) external onlyWatcher { RescueFundsLib._rescueFunds(token_, rescueTo_, amount_); } } diff --git a/contracts/evmx/helpers/AddressResolver.sol b/contracts/evmx/helpers/AddressResolver.sol index efc113f9..429b6d15 100644 --- a/contracts/evmx/helpers/AddressResolver.sol +++ b/contracts/evmx/helpers/AddressResolver.sol @@ -2,10 +2,9 @@ pragma solidity ^0.8.21; import {Initializable} from "solady/utils/Initializable.sol"; -import {RESCUE_ROLE} from "../../utils/common/AccessRoles.sol"; +import "solady/auth/Ownable.sol"; import "../../utils/RescueFundsLib.sol"; -import "../../utils/AccessControl.sol"; - +import "../../utils/common/Errors.sol"; import "../interfaces/IAddressResolver.sol"; abstract contract AddressResolverStorage is IAddressResolver { @@ -32,14 +31,17 @@ abstract contract AddressResolverStorage is IAddressResolver { // slots [56-105] reserved for gap uint256[50] _gap_after; - - // slots [106-155] 50 slots reserved for access control } /// @title AddressResolver Contract /// @notice This contract is responsible for fetching latest core addresses and deploying Forwarder and AsyncPromise contracts. /// @dev Inherits the Ownable contract and implements the IAddressResolver interface. -contract AddressResolver is AddressResolverStorage, Initializable, AccessControl { +contract AddressResolver is AddressResolverStorage, Initializable, Ownable { + modifier onlyWatcher() { + if (msg.sender != address(watcher__)) revert OnlyWatcherAllowed(); + _; + } + /// @notice Constructor to initialize the contract /// @dev it deploys the forwarder and async promise implementations and beacons for them /// @dev this contract is owner of the beacons for upgrading later @@ -108,11 +110,7 @@ contract AddressResolver is AddressResolverStorage, Initializable, AccessControl * @param rescueTo_ The address where rescued tokens need to be sent. * @param amount_ The amount of tokens to be rescued. */ - function rescueFunds( - address token_, - address rescueTo_, - uint256 amount_ - ) external onlyRole(RESCUE_ROLE) { + function rescueFunds(address token_, address rescueTo_, uint256 amount_) external onlyWatcher { RescueFundsLib._rescueFunds(token_, rescueTo_, amount_); } } From d38d13ca4278668ebb0c8b5ee402a0c48532b847 Mon Sep 17 00:00:00 2001 From: Akash Date: Fri, 30 May 2025 15:22:53 +0530 Subject: [PATCH 095/130] fix: deploy scripts --- Errors.md | 227 ++---- EventTopics.md | 350 ++++---- FunctionSignatures.md | 763 +++++++++--------- contracts/evmx/base/AppGatewayBase.sol | 3 +- hardhat-scripts/config/config.ts | 22 +- hardhat-scripts/constants/enums.ts | 21 - hardhat-scripts/constants/index.ts | 1 - hardhat-scripts/constants/roles.ts | 1 + hardhat-scripts/constants/types.ts | 7 + hardhat-scripts/deploy/1.deploy.ts | 379 +++------ hardhat-scripts/deploy/2.roles.ts | 29 +- hardhat-scripts/deploy/3.configureChains.ts | 182 +++++ hardhat-scripts/deploy/3.upgradeManagers.ts | 143 ---- hardhat-scripts/deploy/4.configureEVMx.ts | 162 ++++ hardhat-scripts/deploy/5.fundTransfers.ts | 47 ++ .../deploy/{4.connect.ts => 6.connect.ts} | 98 ++- .../deploy/{5.upload.ts => 7.upload.ts} | 0 .../deploy/{6.setupEnv.ts => 8.setupEnv.ts} | 20 +- hardhat-scripts/deploy/9.setupTransmitter.ts | 110 +++ hardhat-scripts/utils/deployUtils.ts | 44 +- hardhat-scripts/utils/overrides.ts | 2 +- hardhat-scripts/utils/sign.ts | 75 +- lib.tsconfig.json | 2 +- package.json | 9 +- script/helpers/DepositCredit.s.sol | 16 +- script/helpers/DepositCreditAndNative.s.sol | 4 +- setupInfraContracts.sh | 11 +- src/enums.ts | 5 + src/index.ts | 1 + src/signer.ts | 25 + src/types.ts | 1 + test/Storage.t.sol | 1 - 32 files changed, 1570 insertions(+), 1191 deletions(-) delete mode 100644 hardhat-scripts/constants/enums.ts create mode 100644 hardhat-scripts/deploy/3.configureChains.ts delete mode 100644 hardhat-scripts/deploy/3.upgradeManagers.ts create mode 100644 hardhat-scripts/deploy/4.configureEVMx.ts create mode 100644 hardhat-scripts/deploy/5.fundTransfers.ts rename hardhat-scripts/deploy/{4.connect.ts => 6.connect.ts} (77%) rename hardhat-scripts/deploy/{5.upload.ts => 7.upload.ts} (100%) rename hardhat-scripts/deploy/{6.setupEnv.ts => 8.setupEnv.ts} (68%) create mode 100644 hardhat-scripts/deploy/9.setupTransmitter.ts create mode 100644 src/signer.ts diff --git a/Errors.md b/Errors.md index e374a824..00d099e1 100644 --- a/Errors.md +++ b/Errors.md @@ -1,73 +1,29 @@ # Custom Error Codes -## base/PlugBase.sol - -| Error | Signature | -| ---------------------------- | ------------ | -| `SocketAlreadyInitialized()` | `0xc9500b00` | - -## interfaces/IWatcherPrecompile.sol - -| Error | Signature | -| ------------------------------------- | ------------ | -| `InvalidChainSlug()` | `0xbff6b106` | -| `InvalidConnection()` | `0x63228f29` | -| `InvalidTimeoutRequest()` | `0x600ca372` | -| `InvalidPayloadId()` | `0xfa0b8c86` | -| `InvalidCaller()` | `0x48f5c3ed` | -| `InvalidGateway()` | `0xfc9dfe85` | -| `InvalidSwitchboard()` | `0xf63c9e4d` | -| `RequestAlreadyCancelled()` | `0xc70f47d8` | -| `RequestCancelled()` | `0xe3cf2258` | -| `AlreadyStarted()` | `0x1fbde445` | -| `RequestNotProcessing()` | `0x07ba8aaa` | -| `InvalidLevelNumber()` | `0x5022f14b` | -| `DeadlineNotPassedForOnChainRevert()` | `0x7006aa10` | - -## protocol/AddressResolver.sol - -| Error | Signature | -| ---------------------------- | ------------ | -| `InvalidAppGateway(address)` | `0x0e66940d` | - -## protocol/AsyncPromise.sol +## evmx/fees/FeesPool.sol -| Error | Signature | -| ------------------------------- | ------------ | -| `PromiseAlreadyResolved()` | `0x56b63537` | -| `OnlyForwarderOrLocalInvoker()` | `0xa9fb0b28` | -| `PromiseAlreadySetUp()` | `0x927c53d5` | -| `PromiseRevertFailed()` | `0x0175b9de` | - -## protocol/payload-delivery/AuctionManager.sol +| Error | Signature | +| ------------------ | ------------ | +| `TransferFailed()` | `0x90b8ec18` | -| Error | Signature | -| ---------------------------- | ------------ | -| `InvalidBid()` | `0xc6388ef7` | -| `MaxReAuctionCountReached()` | `0xf2b4388c` | - -## protocol/payload-delivery/ContractFactoryPlug.sol +## evmx/helpers/AsyncPromise.sol | Error | Signature | | -------------------------- | ------------ | -| `DeploymentFailed()` | `0x30116425` | -| `ExecutionFailed()` | `0xacfdb444` | -| `information(bool,,bytes)` | `0x3a82a1f3` | +| `PromiseAlreadyResolved()` | `0x56b63537` | +| `OnlyInvoker()` | `0x74ed21f5` | +| `PromiseAlreadySetUp()` | `0x927c53d5` | +| `PromiseRevertFailed()` | `0x0175b9de` | -## protocol/payload-delivery/FeesManager.sol +## evmx/plugs/ContractFactoryPlug.sol | Error | Signature | | -------------------------------- | ------------ | -| `InsufficientCreditsAvailable()` | `0xe61dc0aa` | -| `NoFeesForTransmitter()` | `0x248bac55` | -| `NoCreditsBlocked()` | `0xada9eb4c` | -| `InvalidCaller()` | `0x48f5c3ed` | -| `InvalidUserSignature()` | `0xe3fb657c` | -| `AppGatewayNotWhitelisted()` | `0x84e5309f` | -| `InvalidAmount()` | `0x2c5211c6` | -| `InsufficientBalance()` | `0xf4d678b8` | +| `DeploymentFailed()` | `0x30116425` | +| `ExecutionFailed(bytes32,bytes)` | `0xd255d8a3` | +| `information(bool,,bytes)` | `0x3a82a1f3` | -## protocol/payload-delivery/FeesPlug.sol +## evmx/plugs/FeesPlug.sol | Error | Signature | | --------------------------------------------------- | ------------ | @@ -75,119 +31,110 @@ | `InvalidDepositAmount()` | `0xfe9ba5cd` | | `TokenNotWhitelisted(address)` | `0xea3bff2e` | -## protocol/payload-delivery/app-gateway/DeliveryUtils.sol - -| Error | Signature | -| ------------------------------------ | ------------ | -| `PayloadTooLarge()` | `0x492f620d` | -| `OnlyAppGateway()` | `0xfec944ea` | -| `WinningBidExists()` | `0xe8733654` | -| `InsufficientFees()` | `0x8d53e553` | -| `ReadOnlyRequests()` | `0x5f16b0e6` | -| `RequestPayloadCountLimitExceeded()` | `0xcbef144b` | -| `MaxMsgValueLimitExceeded()` | `0x97b4e8ce` | +## evmx/watcher/RequestHandler.sol -## protocol/payload-delivery/app-gateway/FeesHelpers.sol - -| Error | Signature | -| --------------------------------------------- | ------------ | -| `NewMaxFeesLowerThanCurrent(uint256,uint256)` | `0x1345dda1` | +| Error | Signature | +| ----------------------- | ------------ | +| `InsufficientMaxFees()` | `0x0e5bc492` | -## protocol/socket/Socket.sol +## protocol/Socket.sol | Error | Signature | | ----------------------------------------- | ------------ | | `PayloadAlreadyExecuted(ExecutionStatus)` | `0xf4c54edd` | | `VerificationFailed()` | `0x439cc0cd` | | `LowGasLimit()` | `0xd38edae0` | -| `InvalidSlug()` | `0x290a8315` | -| `DeadlinePassed()` | `0x70f65caa` | | `InsufficientMsgValue()` | `0x78f38f76` | -| `ReadOnlyCall()` | `0xcf8fd6f1` | -## protocol/socket/SocketConfig.sol +## protocol/SocketConfig.sol | Error | Signature | | ------------------------------- | ------------ | -| `InvalidConnection()` | `0x63228f29` | -| `InvalidSwitchboard()` | `0xf63c9e4d` | | `SwitchboardExists()` | `0x2dff8555` | | `SwitchboardExistsOrDisabled()` | `0x1c7d2487` | -## protocol/socket/SocketFeeManager.sol +## protocol/SocketFeeManager.sol | Error | Signature | | -------------------- | ------------ | | `InsufficientFees()` | `0x8d53e553` | | `FeeTooLow()` | `0x732f9413` | -## protocol/socket/switchboard/FastSwitchboard.sol +## protocol/SocketUtils.sol + +| Error | Signature | +| -------------------- | ------------ | +| `OnlyOffChain()` | `0x9cbfe066` | +| `SimulationFailed()` | `0x2fbab3ac` | + +## protocol/switchboard/FastSwitchboard.sol | Error | Signature | | ------------------- | ------------ | | `AlreadyAttested()` | `0x35d90805` | | `WatcherNotFound()` | `0xa278e4ad` | -## protocol/utils/AccessControl.sol +## utils/AccessControl.sol | Error | Signature | | ------------------- | ------------ | | `NoPermit(bytes32)` | `0x962f6333` | -## protocol/utils/AddressResolverUtil.sol +## utils/common/Errors.sol -| Error | Signature | -| ----------------------------------------- | ------------ | -| `OnlyPayloadDelivery()` | `0x7ccc3a43` | -| `OnlyWatcherPrecompile()` | `0x663a892a` | -| `OnlyWatcherPrecompileOrDeliveryHelper()` | `0xe93a2814` | - -## protocol/utils/common/Errors.sol - -| Error | Signature | -| ---------------------------- | ------------ | -| `NotSocket()` | `0xc59f8f7c` | -| `ZeroAddress()` | `0xd92e233d` | -| `TimeoutDelayTooLarge()` | `0xc10bfe64` | -| `TimeoutAlreadyResolved()` | `0x7dc8be06` | -| `ResolvingTimeoutTooEarly()` | `0x28fd4c50` | -| `LimitReached()` | `0x3dd19101` | -| `FeesAlreadyPaid()` | `0xd3b1ad69` | -| `NotAuctionManager()` | `0x87944c26` | -| `CallFailed()` | `0x3204506f` | -| `PlugNotFound()` | `0x5f1ac76a` | -| `InvalidAppGateway()` | `0x82ded261` | -| `AppGatewayAlreadyCalled()` | `0xb224683f` | -| `InvalidInboxCaller()` | `0x4f1aa61e` | -| `InvalidCallerTriggered()` | `0x3292d247` | -| `PromisesNotResolved()` | `0xb91dbe7d` | -| `InvalidPromise()` | `0x45f2d176` | -| `InvalidTransmitter()` | `0x58a70a0a` | -| `FeesNotSet()` | `0x2a831034` | -| `InvalidTokenAddress()` | `0x1eb00b06` | -| `InvalidWatcherSignature()` | `0x5029f14f` | -| `NonceUsed()` | `0x1f6d5aef` | -| `AuctionClosed()` | `0x36b6b46d` | -| `AuctionAlreadyStarted()` | `0x628e3883` | -| `BidExceedsMaxFees()` | `0x4c923f3c` | -| `LowerBidAlreadyExists()` | `0xaaa1f709` | -| `AsyncModifierNotUsed()` | `0xb9521e1a` | -| `InvalidIndex()` | `0x63df8171` | -| `RequestAlreadyExecuted()` | `0xd6f1f946` | -| `NoAsyncPromiseFound()` | `0xa2928f68` | -| `PromiseCallerMismatch()` | `0x2b87f115` | -| `RequestCountMismatch()` | `0x98bbcbff` | -| `DeliveryHelperNotSet()` | `0x07e6c946` | - -## protocol/watcherPrecompile/WatcherPrecompileConfig.sol - -| Error | Signature | -| ---------------------- | ------------ | -| `InvalidGateway()` | `0xfc9dfe85` | -| `InvalidSwitchboard()` | `0xf63c9e4d` | - -## protocol/watcherPrecompile/WatcherPrecompileLimits.sol - -| Error | Signature | -| ---------------------------- | ------------ | -| `WatcherFeesNotSet(bytes32)` | `0x1ce1de3f` | +| Error | Signature | +| --------------------------------------------- | ------------ | +| `ZeroAddress()` | `0xd92e233d` | +| `InvalidTransmitter()` | `0x58a70a0a` | +| `InvalidTokenAddress()` | `0x1eb00b06` | +| `InvalidSwitchboard()` | `0xf63c9e4d` | +| `SocketAlreadyInitialized()` | `0xc9500b00` | +| `NotSocket()` | `0xc59f8f7c` | +| `PlugNotFound()` | `0x5f1ac76a` | +| `ResolvingScheduleTooEarly()` | `0x207e8731` | +| `CallFailed()` | `0x3204506f` | +| `InvalidAppGateway()` | `0x82ded261` | +| `AppGatewayAlreadyCalled()` | `0xb224683f` | +| `InvalidCallerTriggered()` | `0x3292d247` | +| `InvalidPromise()` | `0x45f2d176` | +| `InvalidWatcherSignature()` | `0x5029f14f` | +| `NonceUsed()` | `0x1f6d5aef` | +| `AsyncModifierNotSet()` | `0xcae106f9` | +| `WatcherNotSet()` | `0x42d473a7` | +| `InvalidTarget()` | `0x82d5d76a` | +| `InvalidIndex()` | `0x63df8171` | +| `InvalidChainSlug()` | `0xbff6b106` | +| `InvalidPayloadSize()` | `0xfbdf7954` | +| `InvalidScheduleDelay()` | `0x9a993219` | +| `AuctionClosed()` | `0x36b6b46d` | +| `AuctionNotOpen()` | `0xf0460077` | +| `BidExceedsMaxFees()` | `0x4c923f3c` | +| `LowerBidAlreadyExists()` | `0xaaa1f709` | +| `RequestCountMismatch()` | `0x98bbcbff` | +| `InvalidAmount()` | `0x2c5211c6` | +| `InsufficientCreditsAvailable()` | `0xe61dc0aa` | +| `InsufficientBalance()` | `0xf4d678b8` | +| `InvalidCaller()` | `0x48f5c3ed` | +| `InvalidGateway()` | `0xfc9dfe85` | +| `RequestAlreadyCancelled()` | `0xc70f47d8` | +| `DeadlineNotPassedForOnChainRevert()` | `0x7006aa10` | +| `InvalidBid()` | `0xc6388ef7` | +| `MaxReAuctionCountReached()` | `0xf2b4388c` | +| `MaxMsgValueLimitExceeded()` | `0x97b4e8ce` | +| `OnlyWatcherAllowed()` | `0xdf7d227c` | +| `InvalidPrecompileData()` | `0x320062c0` | +| `InvalidCallType()` | `0x39d2eb55` | +| `NotRequestHandler()` | `0x8f8cba5b` | +| `NotInvoker()` | `0x8a6353d1` | +| `NotPromiseResolver()` | `0x86d876b2` | +| `RequestPayloadCountLimitExceeded()` | `0xcbef144b` | +| `InsufficientFees()` | `0x8d53e553` | +| `RequestAlreadySettled()` | `0x66fad465` | +| `NoWriteRequest()` | `0x9dcd3065` | +| `AlreadyAssigned()` | `0x9688dc51` | +| `OnlyAppGateway()` | `0xfec944ea` | +| `NewMaxFeesLowerThanCurrent(uint256,uint256)` | `0x1345dda1` | +| `InvalidContract()` | `0x6eefed20` | +| `InvalidData()` | `0x5cb045db` | +| `InvalidSignature()` | `0x8baa579f` | +| `DeadlinePassed()` | `0x70f65caa` | diff --git a/EventTopics.md b/EventTopics.md index cb976877..34f5e4bb 100644 --- a/EventTopics.md +++ b/EventTopics.md @@ -1,38 +1,114 @@ # Event Topics -## ProxyFactory +## AuctionManager -| Event | Arguments | Topic | -| -------------- | ----------------------------------------------------------- | -------------------------------------------------------------------- | -| `AdminChanged` | `(proxy: address, admin: address)` | `0x7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f` | -| `Deployed` | `(proxy: address, implementation: address, admin: address)` | `0xc95935a66d15e0da5e412aca0ad27ae891d20b2fb91cf3994b6a3bf2b8178082` | -| `Upgraded` | `(proxy: address, implementation: address)` | `0x5d611f318680d00598bb735d61bacf0c514c6b50e1e5ad30040a4df2b12791c7` | +| Event | Arguments | Topic | +| ---------------------------- | ------------------------------------------- | -------------------------------------------------------------------- | +| `AuctionEndDelaySecondsSet` | `(auctionEndDelaySeconds: uint256)` | `0xf38f0d9dc8459cf5426728c250d115196a4c065ebc1a6c29da24764a8c0da722` | +| `AuctionEnded` | `(requestCount: uint40, winningBid: tuple)` | `0xede4ec1efc469fac10dcb4930f70be4cd21f3700ed61c91967c19a7cd7c0d86e` | +| `AuctionRestarted` | `(requestCount: uint40)` | `0x071867b21946ec4655665f0d4515d3757a5a52f144c762ecfdfb11e1da542b82` | +| `AuctionStarted` | `(requestCount: uint40)` | `0xcd040613cf8ef0cfcaa3af0d711783e827a275fc647c116b74595bf17cb9364f` | +| `BidPlaced` | `(requestCount: uint40, bid: tuple)` | `0x7f79485e4c9aeea5d4899bc6f7c63b22ac1f4c01d2d28c801e94732fee657b5d` | +| `MaxReAuctionCountSet` | `(maxReAuctionCount: uint256)` | `0x2f6fadde7ab8ab83d21ab10c3bc09dde179f8696d47c4176581facf0c6f96bbf` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | +| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | -## TestUSDC +## Socket -| Event | Arguments | Topic | -| ---------- | ----------------------------------------------------- | -------------------------------------------------------------------- | -| `Approval` | `(owner: address, spender: address, amount: uint256)` | `0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925` | -| `Transfer` | `(from: address, to: address, amount: uint256)` | `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef` | +| Event | Arguments | Topic | +| ---------------------------- | -------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | +| `AppGatewayCallRequested` | `(triggerId: bytes32, appGatewayId: bytes32, switchboard: address, plug: address, overrides: bytes, payload: bytes)` | `0x5c88d65ab8ba22a57e582bd8ddfa9801cc0ca6be6cb3182baaedc705a612419e` | +| `ExecutionFailed` | `(payloadId: bytes32, exceededMaxCopy: bool, returnData: bytes)` | `0x385334bc68a32c4d164625189adc7633e6074eb1b837fb4d11d768245151e4ce` | +| `ExecutionSuccess` | `(payloadId: bytes32, exceededMaxCopy: bool, returnData: bytes)` | `0x324d63a433b21a12b90e79cd2ba736b2a5238be6165e03b750fa4a7d5193d5d9` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `PlugConnected` | `(plug: address, appGatewayId: bytes32, switchboard: address)` | `0x90c5924e27cfb6e3a688e729083681f30494ae2615ae14aac3bc807a0c436a88` | +| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | +| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | +| `SocketFeeManagerUpdated` | `(oldSocketFeeManager: address, newSocketFeeManager: address)` | `0xdcb02e10d5220346a4638aa2826eaab1897306623bc40a427049e4ebd12255b4` | +| `SwitchboardAdded` | `(switchboard: address)` | `0x1595852923edfbbf906f09fc8523e4cfb022a194773c4d1509446b614146ee88` | +| `SwitchboardDisabled` | `(switchboard: address)` | `0x1b4ee41596b4e754e5665f01ed6122b356f7b36ea0a02030804fac7fa0fdddfc` | +| `SwitchboardEnabled` | `(switchboard: address)` | `0x6909a9974e3eec619bc479ba882d30a5ef1219b72ab1ce6a354516e91be317b8` | + +## SocketBatcher + +| Event | Arguments | Topic | +| ---------------------------- | ---------------------------------------- | -------------------------------------------------------------------- | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | + +## SocketFeeManager + +| Event | Arguments | Topic | +| ---------------------------- | ---------------------------------------- | -------------------------------------------------------------------- | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | +| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | +| `SocketFeesUpdated` | `(oldFees: uint256, newFees: uint256)` | `0xcbd4d756fb6198bbcc2e4013cce929f504ad46e9d97c543ef9a8dfea3e407053` | + +## FeesManager + +| Event | Arguments | Topic | +| ----------------------------- | ------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | +| `CreditsBlocked` | `(requestCount: uint40, consumeFrom: address, amount: uint256)` | `0xf037c15aef41440aa823cf1fdeaea332105d8b23d52557f6670189b5d76f1eed` | +| `CreditsTransferred` | `(from: address, to: address, amount: uint256)` | `0xed198cadddd93e734cbf04cb1c3226d9bafaeb504cedbd8ee36b830b0cb9e7a5` | +| `CreditsUnblocked` | `(requestCount: uint40, consumeFrom: address)` | `0x45db29ef2701319155cac058aa2f56ce1f73e0e238161d3db9f8c9a47655210d` | +| `CreditsUnblockedAndAssigned` | `(requestCount: uint40, consumeFrom: address, transmitter: address, amount: uint256)` | `0x38fd327622576a468e1b2818b00f50c8854703633ef8e583e1f31662888ffac2` | +| `CreditsUnwrapped` | `(consumeFrom: address, amount: uint256)` | `0xdcc9473b722b4c953617ab373840b365298a520bc7f20ce94fa7314f4a857774` | +| `CreditsWrapped` | `(consumeFrom: address, amount: uint256)` | `0x40246503613721eb4acf4020c6c56b6a16e5d08713316db0bea5210e8819c592` | +| `Deposited` | `(chainSlug: uint32, token: address, depositTo: address, creditAmount: uint256, nativeAmount: uint256)` | `0x72aedd284699bbd7a987e6942b824cfd6c627e354cb5a0760ac5768acd473f4a` | +| `FeesPlugSet` | `(chainSlug: uint32, feesPlug: address)` | `0xa8c4be32b96cca895f1f0f4684e6b377b2c4513bc35eb57a13afb6b5efb2c0ce` | +| `FeesPoolSet` | `(feesPool: address)` | `0xd07af3fd70b48ab3c077a8d45c3a288498d905d0e3d1e65bc171f6c2e890d8ef` | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | + +## FeesPool + +| Event | Arguments | Topic | +| ---------------------------- | ----------------------------------------------- | -------------------------------------------------------------------- | +| `NativeDeposited` | `(from: address, amount: uint256)` | `0xb5d7700fb0cf415158b8db7cc7c39f0eab16a825c92e221404b4c8bb099b4bbb` | +| `NativeWithdrawn` | `(success: bool, to: address, amount: uint256)` | `0xa81f1c8490022ee829d2e1a231053f5dbecad46caee71f6ea38a9db663a3f12b` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | +| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | ## AddressResolver -| Event | Arguments | Topic | -| ------------------------------ | ----------------------------------------------------------- | -------------------------------------------------------------------- | -| `AddressSet` | `(name: bytes32, oldAddress: address, newAddress: address)` | `0x9ef0e8c8e52743bb38b83b17d9429141d494b8041ca6d616a6c77cebae9cd8b7` | -| `AsyncPromiseDeployed` | `(newAsyncPromise: address, salt: bytes32)` | `0xb6c5491cf83e09749b1a4dd6a9f07b0e925fcb0a915ac8c2b40e8ab28191c270` | -| `ContractsToGatewaysUpdated` | `(contractAddress_: address, appGateway_: address)` | `0xb870bb0c6b5ea24214ae6c653af6c2a8b6240d5838f82132703ee5c069b14b4c` | -| `DefaultAuctionManagerUpdated` | `(defaultAuctionManager_: address)` | `0x60f296739208a505ead7fb622df0f76b7791b824481b120a2300bdaf85e3e3d6` | -| `DeliveryHelperUpdated` | `(deliveryHelper_: address)` | `0xc792471d30bbabcf9dc9fdba5bfa74f8872ff3c28f6e65e122bdb82a71b83c1c` | -| `FeesManagerUpdated` | `(feesManager_: address)` | `0x94e67aa1341a65767dfde81e62fd265bfbade1f5744bfd3cd73f99a6eca0572a` | -| `ForwarderDeployed` | `(newForwarder: address, salt: bytes32)` | `0x4dbbecb9cf9c8b93da9743a2b48ea52efe68d69230ab1c1b711891d9d223b29f` | -| `ImplementationUpdated` | `(contractName: string, newImplementation: address)` | `0xa1e41aa2c2f3f20d9b63ac06b634d2788768d6034f3d9192cdf7d07374bb16f4` | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `PlugAdded` | `(appGateway: address, chainSlug: uint32, plug: address)` | `0x2cb8d865028f9abf3dc064724043264907615fadc8615a3699a85edb66472273` | -| `WatcherPrecompileUpdated` | `(watcherPrecompile_: address)` | `0xb00972c0b5c3d3d9ddc6d6a6db612abeb109653a3424d5d972510fa20bff4972` | +| Event | Arguments | Topic | +| ------------------------------ | --------------------------------------------------- | -------------------------------------------------------------------- | +| `AsyncDeployerUpdated` | `(asyncDeployer_: address)` | `0x4df9cdd01544e8f6b0326650bc0b55611f47ce5ba2faa522d21fb675e9fc1f73` | +| `ContractAddressUpdated` | `(contractId_: bytes32, contractAddress_: address)` | `0xdf5ec2c15e11ce657bb21bc09c0b5ba95e315b4dba9934c6e311f47559babf28` | +| `DefaultAuctionManagerUpdated` | `(defaultAuctionManager_: address)` | `0x60f296739208a505ead7fb622df0f76b7791b824481b120a2300bdaf85e3e3d6` | +| `DeployForwarderUpdated` | `(deployForwarder_: address)` | `0x237b9bc9fef7508a02ca9ccca81f6965e500064a58024cae1218035da865fd2b` | +| `FeesManagerUpdated` | `(feesManager_: address)` | `0x94e67aa1341a65767dfde81e62fd265bfbade1f5744bfd3cd73f99a6eca0572a` | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `WatcherUpdated` | `(watcher_: address)` | `0xc13081d38d92b454cdb6ca20bbc65c12fa43a7a14a1529204ced5b6350052bb0` | + +## AsyncDeployer + +| Event | Arguments | Topic | +| ---------------------------- | ---------------------------------------------------- | -------------------------------------------------------------------- | +| `AsyncPromiseDeployed` | `(newAsyncPromise: address, salt: bytes32)` | `0xb6c5491cf83e09749b1a4dd6a9f07b0e925fcb0a915ac8c2b40e8ab28191c270` | +| `ForwarderDeployed` | `(newForwarder: address, salt: bytes32)` | `0x4dbbecb9cf9c8b93da9743a2b48ea52efe68d69230ab1c1b711891d9d223b29f` | +| `ImplementationUpdated` | `(contractName: string, newImplementation: address)` | `0xa1e41aa2c2f3f20d9b63ac06b634d2788768d6034f3d9192cdf7d07374bb16f4` | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | ## AsyncPromise @@ -40,27 +116,31 @@ | ------------- | ------------------- | -------------------------------------------------------------------- | | `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +## DeployForwarder + +| Event | Arguments | Topic | +| ----- | --------- | ----- | + ## Forwarder | Event | Arguments | Topic | | ------------- | ------------------- | -------------------------------------------------------------------- | | `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -## AuctionManager +## ProxyFactory -| Event | Arguments | Topic | -| ---------------------------- | ------------------------------------------- | -------------------------------------------------------------------- | -| `AuctionEndDelaySecondsSet` | `(auctionEndDelaySeconds: uint256)` | `0xf38f0d9dc8459cf5426728c250d115196a4c065ebc1a6c29da24764a8c0da722` | -| `AuctionEnded` | `(requestCount: uint40, winningBid: tuple)` | `0xede4ec1efc469fac10dcb4930f70be4cd21f3700ed61c91967c19a7cd7c0d86e` | -| `AuctionRestarted` | `(requestCount: uint40)` | `0x071867b21946ec4655665f0d4515d3757a5a52f144c762ecfdfb11e1da542b82` | -| `AuctionStarted` | `(requestCount: uint40)` | `0xcd040613cf8ef0cfcaa3af0d711783e827a275fc647c116b74595bf17cb9364f` | -| `BidPlaced` | `(requestCount: uint40, bid: tuple)` | `0x7f79485e4c9aeea5d4899bc6f7c63b22ac1f4c01d2d28c801e94732fee657b5d` | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | -| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | +| Event | Arguments | Topic | +| -------------- | ----------------------------------------------------------- | -------------------------------------------------------------------- | +| `AdminChanged` | `(proxy: address, admin: address)` | `0x7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f` | +| `Deployed` | `(proxy: address, implementation: address, admin: address)` | `0xc95935a66d15e0da5e412aca0ad27ae891d20b2fb91cf3994b6a3bf2b8178082` | +| `Upgraded` | `(proxy: address, implementation: address)` | `0x5d611f318680d00598bb735d61bacf0c514c6b50e1e5ad30040a4df2b12791c7` | + +## TestUSDC + +| Event | Arguments | Topic | +| ---------- | ----------------------------------------------------- | -------------------------------------------------------------------- | +| `Approval` | `(owner: address, spender: address, amount: uint256)` | `0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925` | +| `Transfer` | `(from: address, to: address, amount: uint256)` | `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef` | ## ContractFactoryPlug @@ -74,24 +154,6 @@ | `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | | `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | -## FeesManager - -| Event | Arguments | Topic | -| ----------------------------------------------- | --------------------------------------------------------------------------- | -------------------------------------------------------------------- | -| `CreditsBlocked` | `(requestCount: uint40, consumeFrom: address, amount: uint256)` | `0xf037c15aef41440aa823cf1fdeaea332105d8b23d52557f6670189b5d76f1eed` | -| `CreditsDeposited` | `(chainSlug: uint32, appGateway: address, token: address, amount: uint256)` | `0x7254d040844de2dac4225a23f81bb54acb13d1eadb6e8b369dd251d36a9e8552` | -| `CreditsUnblocked` | `(requestCount: uint40, appGateway: address)` | `0x45db29ef2701319155cac058aa2f56ce1f73e0e238161d3db9f8c9a47655210d` | -| `CreditsUnblockedAndAssigned` | `(requestCount: uint40, transmitter: address, amount: uint256)` | `0x6f3d11270d1df9aff1aa04d1ea7797a3a572586a31437acc415ac853f625050c` | -| `CreditsUnwrapped` | `(consumeFrom: address, amount: uint256)` | `0xdcc9473b722b4c953617ab373840b365298a520bc7f20ce94fa7314f4a857774` | -| `CreditsWrapped` | `(consumeFrom: address, amount: uint256)` | `0x40246503613721eb4acf4020c6c56b6a16e5d08713316db0bea5210e8819c592` | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `InsufficientWatcherPrecompileCreditsAvailable` | `(chainSlug: uint32, token: address, consumeFrom: address)` | `0xd50bc02f94b9ef4a8aff7438da15a69e443956f56b6aa007cf2c584215e87493` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `TransmitterCreditsUpdated` | `(requestCount: uint40, transmitter: address, amount: uint256)` | `0x24790626bfbe84d1358ce3e8cb0ff6cfc9eb7ea16e597f43ab607107baf889e3` | -| `WatcherPrecompileCreditsAssigned` | `(amount: uint256, consumeFrom: address)` | `0x87eddb69736f41b812366535a59efc79b1997f2d237240d7176d210397012e1b` | - ## FeesPlug | Event | Arguments | Topic | @@ -107,85 +169,53 @@ | `TokenRemovedFromWhitelist` | `(token: address)` | `0xdd2e6d9f52cbe8f695939d018b7d4a216dc613a669876163ac548b916489d917` | | `TokenWhitelisted` | `(token: address)` | `0x6a65f90b1a644d2faac467a21e07e50e3f8fa5846e26231d30ae79a417d3d262` | -## Socket - -| Event | Arguments | Topic | -| ---------------------------- | -------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | -| `AppGatewayCallRequested` | `(triggerId: bytes32, appGatewayId: bytes32, switchboard: address, plug: address, overrides: bytes, payload: bytes)` | `0x5c88d65ab8ba22a57e582bd8ddfa9801cc0ca6be6cb3182baaedc705a612419e` | -| `ExecutionFailed` | `(payloadId: bytes32, exceededMaxCopy: bool, returnData: bytes)` | `0x385334bc68a32c4d164625189adc7633e6074eb1b837fb4d11d768245151e4ce` | -| `ExecutionSuccess` | `(payloadId: bytes32, exceededMaxCopy: bool, returnData: bytes)` | `0x324d63a433b21a12b90e79cd2ba736b2a5238be6165e03b750fa4a7d5193d5d9` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `PlugConnected` | `(plug: address, appGatewayId: bytes32, switchboard: address)` | `0x90c5924e27cfb6e3a688e729083681f30494ae2615ae14aac3bc807a0c436a88` | -| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | -| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | -| `SocketFeeManagerUpdated` | `(oldSocketFeeManager: address, newSocketFeeManager: address)` | `0xdcb02e10d5220346a4638aa2826eaab1897306623bc40a427049e4ebd12255b4` | -| `SwitchboardAdded` | `(switchboard: address)` | `0x1595852923edfbbf906f09fc8523e4cfb022a194773c4d1509446b614146ee88` | -| `SwitchboardDisabled` | `(switchboard: address)` | `0x1b4ee41596b4e754e5665f01ed6122b356f7b36ea0a02030804fac7fa0fdddfc` | -| `SwitchboardEnabled` | `(switchboard: address)` | `0x6909a9974e3eec619bc479ba882d30a5ef1219b72ab1ce6a354516e91be317b8` | - -## SocketBatcher +## Configurations + +| Event | Arguments | Topic | +| ---------------------------- | ------------------------------------------------------------------------ | -------------------------------------------------------------------- | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `IsValidPlugSet` | `(appGateway: address, chainSlug: uint32, plug: address, isValid: bool)` | `0x61cccc7387868fc741379c7acd9dd346e0ca2e5c067dc5b156fbbc55b1c2fcf5` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `PlugAdded` | `(appGatewayId: bytes32, chainSlug: uint32, plug: address)` | `0x7b3e14230a721c4737d275f9a63b92c44cb657bcfddbe6fe9b4d9cd9bd8d4a95` | +| `SocketSet` | `(chainSlug: uint32, socket: address)` | `0x5b13a5470e66a2ec5e9b32af5f9e23fe304864892918c60fffd22509ca73ac97` | +| `SwitchboardSet` | `(chainSlug: uint32, sbType: bytes32, switchboard: address)` | `0x6273f161f4a795e66ef3585d9b4442ef3796b32337157fdfb420b5281e4cf2e3` | + +## PromiseResolver + +| Event | Arguments | Topic | +| -------------------- | ------------------------------------------------ | -------------------------------------------------------------------- | +| `MarkedRevert` | `(payloadId: bytes32, isRevertingOnchain: bool)` | `0xcf1fd844cb4d32cbebb5ca6ce4ac834fe98da3ddac44deb77fffd22ad933824c` | +| `PromiseNotResolved` | `(payloadId: bytes32, asyncPromise: address)` | `0xbcf0d0c678940566e9e64f0c871439395bd5fb5c39bca3547b126fe6ee467937` | +| `PromiseResolved` | `(payloadId: bytes32, asyncPromise: address)` | `0x1b1b5810494fb3e17f7c46547e6e67cd6ad3e6001ea6fb7d12ea0241ba13c4ba` | + +## RequestHandler + +| Event | Arguments | Topic | +| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | +| `FeesIncreased` | `(requestCount: uint40, newMaxFees: uint256)` | `0xf258fca4e49b803ee2a4c2e33b6fcf18bc3982df21f111c00677025bf1ccbb6a` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `RequestCancelled` | `(requestCount: uint40)` | `0xff191657769be72fc08def44c645014c60d18cb24b9ca05c9a33406a28253245` | +| `RequestCompletedWithErrors` | `(requestCount: uint40)` | `0xd8d9915dc14b5a29b66cb263e1ea1e99e60418fc21d97f0fbf09cae1281291e2` | +| `RequestSettled` | `(requestCount: uint40, winner: address)` | `0x1234f98acbe1548b214f4528461a5377f1e2349569c04caa59325e488e7d2aa4` | +| `RequestSubmitted` | `(hasWrite: bool, requestCount: uint40, totalEstimatedWatcherFees: uint256, requestParams: tuple, payloadParamsArray: tuple[])` | `0x762bac43d5d7689b8911c5654a9d5550804373cead33bc98282067e6166e518f` | + +## Watcher | Event | Arguments | Topic | | ---------------------------- | ---------------------------------------- | -------------------------------------------------------------------- | +| `AppGatewayCallFailed` | `(triggerId: bytes32)` | `0xcaf8475fdade8465ea31672463949e6cf1797fdcdd11eeddbbaf857e1e5907b7` | +| `CalledAppGateway` | `(triggerId: bytes32)` | `0xf659ffb3875368f54fb4ab8f5412ac4518af79701a48076f7a58d4448e4bdd0b` | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | | `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | | `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | | `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | - -## SocketFeeManager - -| Event | Arguments | Topic | -| ---------------------------- | ---------------------------------------- | -------------------------------------------------------------------- | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | -| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | -| `SocketFeesUpdated` | `(oldFees: uint256, newFees: uint256)` | `0xcbd4d756fb6198bbcc2e4013cce929f504ad46e9d97c543ef9a8dfea3e407053` | - -## WatcherPrecompileConfig - -| Event | Arguments | Topic | -| ---------------------------- | --------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `IsValidPlugSet` | `(appGateway: address, chainSlug: uint32, plug: address, isValid: bool)` | `0x61cccc7387868fc741379c7acd9dd346e0ca2e5c067dc5b156fbbc55b1c2fcf5` | -| `OnChainContractSet` | `(chainSlug: uint32, socket: address, contractFactoryPlug: address, feesPlug: address)` | `0xd24cf816377e3c571e7bc798dd43d3d5fc78c32f7fc94b42898b0d37c5301a4e` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `PlugAdded` | `(appGatewayId: bytes32, chainSlug: uint32, plug: address)` | `0x7b3e14230a721c4737d275f9a63b92c44cb657bcfddbe6fe9b4d9cd9bd8d4a95` | -| `SwitchboardSet` | `(chainSlug: uint32, sbType: bytes32, switchboard: address)` | `0x6273f161f4a795e66ef3585d9b4442ef3796b32337157fdfb420b5281e4cf2e3` | - -## WatcherPrecompileLimits - -| Event | Arguments | Topic | -| --------------------------------- | ------------------------------------------------------------------ | -------------------------------------------------------------------- | -| `AppGatewayActivated` | `(appGateway: address, maxLimit: uint256, ratePerSecond: uint256)` | `0x44628d7d5628b9fbc2c84ea9bf3bd3987fa9cde8d2b28e2d5ceb451f916cb8b9` | -| `CallBackFeesSet` | `(callBackFees: uint256)` | `0x667c97afffb32265f3b4e026d31b81dc223275ff8bb9819e67012197f5799faf` | -| `DefaultLimitAndRatePerSecondSet` | `(defaultLimit: uint256, defaultRatePerSecond: uint256)` | `0x39def16be1ce80876ad0b0936cfdf88b8be7a1790b6c1da16ba8bdee53367e8e` | -| `FinalizeFeesSet` | `(finalizeFees: uint256)` | `0x0b710f92aabbdda2e8c347f802353f34ef27845d79db79efb4884e8790a0d5fb` | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `LimitParamsUpdated` | `(updates: tuple[])` | `0x81576b12f4d507fd0543afd25a86785573a595334c2c7eb8ca8ec1b0a56a55b3` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `QueryFeesSet` | `(queryFees: uint256)` | `0x19569faa0df733d4b0806372423e828b05a5257eb7652da812b90f662bed5cfb` | -| `TimeoutFeesSet` | `(timeoutFees: uint256)` | `0xe8a5b23529bc11019d6df86a1ee0d043571d464902a3fa98e7e3e67dbd5981ca` | - -## DeliveryHelper - -| Event | Arguments | Topic | -| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | -| `BidTimeoutUpdated` | `(newBidTimeout: uint256)` | `0xd4552e666d0e4e343fb2b13682972a8f0c7f1a86e252d6433b356f0c0e817c3d` | -| `ChainMaxMsgValueLimitsUpdated` | `(chainSlugs: uint32[], maxMsgValueLimits: uint256[])` | `0x17e47f6f0fa0e79831bee11b7c29adc45d9a7bd25acd70b91e4b2bad0f544352` | -| `FeesIncreased` | `(appGateway: address, requestCount: uint40, newMaxFees: uint256)` | `0x63ee9e9e84d216b804cb18f51b7f7511254b0c1f11304b7a3aa34d57511aa6dc` | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `PayloadSubmitted` | `(requestCount: uint40, appGateway: address, payloadSubmitParams: tuple[], fees: uint256, auctionManager: address, onlyReadRequests: bool)` | `0xc6455dba7c07a5e75c7189040ae9e3478162f333a96365b283b434fd0e32c6b3` | -| `RequestCancelled` | `(requestCount: uint40)` | `0xff191657769be72fc08def44c645014c60d18cb24b9ca05c9a33406a28253245` | +| `TriggerFailed` | `(triggerId: bytes32)` | `0x4386783bb0f7cad4ba12f033dbec03dc3441e7757a122f3097a7a4d945c98040` | +| `TriggerFeesSet` | `(triggerFees: uint256)` | `0x7df3967b7c8727af5ac0ee9825d88aafeb899d769bc428b91f8967fa0b623084` | +| `TriggerSucceeded` | `(triggerId: bytes32)` | `0x92d20fbcbf31370b8218e10ed00c5aad0e689022da30a08905ba5ced053219eb` | ## FastSwitchboard @@ -198,27 +228,35 @@ | `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | | `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | -## WatcherPrecompile - -| Event | Arguments | Topic | -| ----------------------------- | ----------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | -| `AppGatewayCallFailed` | `(triggerId: bytes32)` | `0xcaf8475fdade8465ea31672463949e6cf1797fdcdd11eeddbbaf857e1e5907b7` | -| `CalledAppGateway` | `(triggerId: bytes32)` | `0xf659ffb3875368f54fb4ab8f5412ac4518af79701a48076f7a58d4448e4bdd0b` | -| `ExpiryTimeSet` | `(expiryTime: uint256)` | `0x07e837e13ad9a34715a6bd45f49bbf12de19f06df79cb0be12b3a7d7f2397fa9` | -| `FinalizeRequested` | `(digest: bytes32, params: tuple)` | `0x5bc623895e2e50e307b4c3ba21df61ddfe68de0e084bb85eb1d42d4596532589` | -| `Finalized` | `(payloadId: bytes32, proof: bytes)` | `0x7e6e3e411317567fb9eabe3eb86768c3e33c46e38a50790726e916939b4918d6` | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `MarkedRevert` | `(payloadId: bytes32, isRevertingOnchain: bool)` | `0xcf1fd844cb4d32cbebb5ca6ce4ac834fe98da3ddac44deb77fffd22ad933824c` | -| `MaxTimeoutDelayInSecondsSet` | `(maxTimeoutDelayInSeconds: uint256)` | `0x3564638b089495c19e7359a040be083841e11da34c22a29ea8d602c8a9805fec` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `PromiseNotResolved` | `(payloadId: bytes32, asyncPromise: address)` | `0xbcf0d0c678940566e9e64f0c871439395bd5fb5c39bca3547b126fe6ee467937` | -| `PromiseResolved` | `(payloadId: bytes32, asyncPromise: address)` | `0x1b1b5810494fb3e17f7c46547e6e67cd6ad3e6001ea6fb7d12ea0241ba13c4ba` | -| `QueryRequested` | `(params: tuple)` | `0xca81bf0029a549d7e6e3a9c668a717472f4330a6a5ec4350304a9e79bf437345` | -| `RequestCancelledFromGateway` | `(requestCount: uint40)` | `0x333619ca4a2a9c4ee292aafa3c37215d88afe358afee4a575cfed21d743091c6` | -| `RequestSubmitted` | `(middleware: address, requestCount: uint40, payloadParamsArray: tuple[])` | `0xb856562fcff2119ba754f0486f47c06087ebc1842bff464faf1b2a1f8d273b1d` | -| `TimeoutRequested` | `(timeoutId: bytes32, target: address, payload: bytes, executeAt: uint256)` | `0xdf94fed77e41734b8a17815476bbbf88e2db15d762f42a30ddb9d7870f2fb858` | -| `TimeoutResolved` | `(timeoutId: bytes32, target: address, payload: bytes, executedAt: uint256, returnData: bytes)` | `0x61122416680ac7038ca053afc2c26983f2c524e5003b1f4d9dea095fbc8f6905` | -| `WatcherPrecompileConfigSet` | `(watcherPrecompileConfig: address)` | `0xdc19bca647582b3fbf69a6ffacabf56b4f7a4551d2d0944843712f2d0987a8e5` | -| `WatcherPrecompileLimitsSet` | `(watcherPrecompileLimits: address)` | `0xcec7ba89301793a37efb418279f17f8dd77e5959e9f3fbcbc54e40615a14bd8e` | +## ReadPrecompile + +| Event | Arguments | Topic | +| --------------- | ---------------------------------------------------------------------- | -------------------------------------------------------------------- | +| `ExpiryTimeSet` | `(expiryTime: uint256)` | `0x07e837e13ad9a34715a6bd45f49bbf12de19f06df79cb0be12b3a7d7f2397fa9` | +| `ReadFeesSet` | `(readFees: uint256)` | `0xc674cb6dde3a59f84dbf226832e606ffc54ac8a169e1568fc834c7813010f926` | +| `ReadRequested` | `(transaction: tuple, readAtBlockNumber: uint256, payloadId: bytes32)` | `0x42d9c65d4f6e45462ae6206adb3e388e046b7daa1dc8699d9380cac72ff5db0b` | + +## SchedulePrecompile + +| Event | Arguments | Topic | +| ------------------------------ | ---------------------------------------------------------------- | -------------------------------------------------------------------- | +| `ExpiryTimeSet` | `(expiryTime_: uint256)` | `0x07e837e13ad9a34715a6bd45f49bbf12de19f06df79cb0be12b3a7d7f2397fa9` | +| `MaxScheduleDelayInSecondsSet` | `(maxScheduleDelayInSeconds_: uint256)` | `0xfd5e4f0e96753ffb08a583390c2f151c51001d8e560625ab93b7fa7b4dac6d75` | +| `ScheduleCallbackFeesSet` | `(scheduleCallbackFees_: uint256)` | `0x82a2f41efc81ce7bfabc0affda7354dae42a3d09bd74a6196e8904b223138a52` | +| `ScheduleFeesPerSecondSet` | `(scheduleFeesPerSecond_: uint256)` | `0x7901a21229f6d2543d8676f53e21214d15f42513e7d46e0dcb510357222bdc7c` | +| `ScheduleRequested` | `(payloadId: bytes32, executeAfter: uint256, deadline: uint256)` | `0xd099d3e3d0f0e2c9c40e0066affeea125aab71d763b7ab0a279ccec3dff70b64` | +| `ScheduleResolved` | `(payloadId: bytes32)` | `0x925dc6c3ebffa07cac89d6e9675f1a5d04e045f2ed9a4fa442665935cb73e26b` | + +## WritePrecompile + +| Event | Arguments | Topic | +| ------------------------------- | ---------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | +| `ChainMaxMsgValueLimitsUpdated` | `(chainSlug: uint32, maxMsgValueLimit: uint256)` | `0x439087d094fe7dacbba3f0c67032041952d8bd58a891e15af10ced28fed0eb91` | +| `ContractFactoryPlugSet` | `(chainSlug: uint32, contractFactoryPlug: address)` | `0x85bfa413b9e5e225278f51af2ac872988e0a9374263b118d963c50945ea888bb` | +| `ExpiryTimeSet` | `(expiryTime: uint256)` | `0x07e837e13ad9a34715a6bd45f49bbf12de19f06df79cb0be12b3a7d7f2397fa9` | +| `FeesSet` | `(writeFees: uint256)` | `0x3346af6da1932164d501f2ec28f8c5d686db5828a36b77f2da4332d89184fe7b` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `WriteProofRequested` | `(transmitter: address, digest: bytes32, prevBatchDigestHash: bytes32, deadline: uint256, payloadParams: tuple)` | `0x3247df5b4e8df4ac60c2c1f803b404ee16bc9d84a6b7649865464a8a397b9acb` | +| `WriteProofUploaded` | `(payloadId: bytes32, proof: bytes)` | `0xd8fe3a99a88c9630360418877afdf14e3e79f0f25fee162aeb230633ea740156` | diff --git a/FunctionSignatures.md b/FunctionSignatures.md index e3ef596c..ab3f68b0 100644 --- a/FunctionSignatures.md +++ b/FunctionSignatures.md @@ -1,256 +1,65 @@ # Function Signatures -## ProxyFactory - -| Function | Signature | -| ----------------------------- | ------------ | -| `adminOf` | `0x2abbef15` | -| `changeAdmin` | `0x1acfd02a` | -| `deploy` | `0x545e7c61` | -| `deployAndCall` | `0x4314f120` | -| `deployDeterministic` | `0x3729f922` | -| `deployDeterministicAndCall` | `0xa97b90d5` | -| `initCodeHash` | `0xdb4c545e` | -| `predictDeterministicAddress` | `0x5414dff0` | -| `upgrade` | `0x99a88ec4` | -| `upgradeAndCall` | `0x9623609d` | - -## TestUSDC - -| Function | Signature | -| ------------------ | ------------ | -| `DOMAIN_SEPARATOR` | `0x3644e515` | -| `allowance` | `0xdd62ed3e` | -| `approve` | `0x095ea7b3` | -| `balanceOf` | `0x70a08231` | -| `decimals` | `0x313ce567` | -| `mint` | `0x40c10f19` | -| `name` | `0x06fdde03` | -| `nonces` | `0x7ecebe00` | -| `owner` | `0x8da5cb5b` | -| `permit` | `0xd505accf` | -| `symbol` | `0x95d89b41` | -| `totalSupply` | `0x18160ddd` | -| `transfer` | `0xa9059cbb` | -| `transferFrom` | `0x23b872dd` | - -## AddressResolver - -| Function | Signature | -| ------------------------------- | ------------ | -| `asyncPromiseBeacon` | `0xc0fbc0ef` | -| `asyncPromiseCounter` | `0x97cdbf4c` | -| `asyncPromiseImplementation` | `0x59531b8d` | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `clearPromises` | `0x96e03234` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `contractsToGateways` | `0x5bc03a67` | -| `defaultAuctionManager` | `0x8f27cdc6` | -| `deliveryHelper` | `0x71eaa36f` | -| `deployAsyncPromiseContract` | `0x00afbf9d` | -| `feesManager` | `0x05a9e073` | -| `forwarderBeacon` | `0x945709ae` | -| `forwarderImplementation` | `0xe38d60a1` | -| `getAsyncPromiseAddress` | `0xb6400df5` | -| `getForwarderAddress` | `0x48c0b3e0` | -| `getOrDeployForwarderContract` | `0xe8d616a8` | -| `getPromises` | `0xa01afb0d` | -| `initialize` | `0xc4d66de8` | -| `owner` | `0x8da5cb5b` | -| `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `renounceOwnership` | `0x715018a6` | -| `requestOwnershipHandover` | `0x25692962` | -| `setAsyncPromiseImplementation` | `0xeb506eab` | -| `setContractsToGateways` | `0xb08dd08b` | -| `setDefaultAuctionManager` | `0xede8b4b5` | -| `setDeliveryHelper` | `0x75523822` | -| `setFeesManager` | `0x1c89382a` | -| `setForwarderImplementation` | `0x83b1e974` | -| `setWatcherPrecompile` | `0x5ca44c9b` | -| `transferOwnership` | `0xf2fde38b` | -| `version` | `0x54fd4d50` | -| `watcherPrecompile__` | `0x1de360c3` | - -## AsyncPromise - -| Function | Signature | -| ------------------------- | ------------ | -| `addressResolver__` | `0x6a750469` | -| `callbackData` | `0xef44c272` | -| `callbackSelector` | `0x2764f92f` | -| `deliveryHelper__` | `0xc031dfb4` | -| `forwarder` | `0xf645d4f9` | -| `initialize` | `0xc0c53b8b` | -| `localInvoker` | `0x45eb87f4` | -| `markOnchainRevert` | `0x7734a84e` | -| `markResolved` | `0xdd94d9b2` | -| `resolved` | `0x3f6fa655` | -| `state` | `0xc19d93fb` | -| `then` | `0x0bf2ba15` | -| `watcherPrecompileConfig` | `0x8618a912` | -| `watcherPrecompileLimits` | `0xa71cd97d` | -| `watcherPrecompile__` | `0x1de360c3` | - -## Forwarder - -| Function | Signature | -| ------------------------- | ------------ | -| `addressResolver__` | `0x6a750469` | -| `chainSlug` | `0xb349ba65` | -| `deliveryHelper__` | `0xc031dfb4` | -| `getChainSlug` | `0x0b8c6568` | -| `getOnChainAddress` | `0x9da48789` | -| `initialize` | `0x647c576c` | -| `latestAsyncPromise` | `0xb8a8ba52` | -| `latestPromiseCaller` | `0xdfe580a8` | -| `latestRequestCount` | `0x198b9a47` | -| `onChainAddress` | `0x8bd0b363` | -| `then` | `0x0bf2ba15` | -| `watcherPrecompileConfig` | `0x8618a912` | -| `watcherPrecompileLimits` | `0xa71cd97d` | -| `watcherPrecompile__` | `0x1de360c3` | - ## AuctionManager -| Function | Signature | -| -------------------------------- | ------------ | -| `addressResolver__` | `0x6a750469` | -| `auctionClosed` | `0x6862ebb0` | -| `auctionEndDelaySeconds` | `0x9087dfdb` | -| `auctionStarted` | `0x7c9c5bb8` | -| `bid` | `0xfcdf49c2` | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `deliveryHelper__` | `0xc031dfb4` | -| `endAuction` | `0x1212e653` | -| `evmxSlug` | `0x8bae77c2` | -| `expireBid` | `0x1dd5022c` | -| `getTransmitterMaxFeesAvailable` | `0xa70f18ea` | -| `grantRole` | `0x2f2ff15d` | -| `hasRole` | `0x91d14854` | -| `initialize` | `0x5f24043b` | -| `maxReAuctionCount` | `0xc367b376` | -| `owner` | `0x8da5cb5b` | -| `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `reAuctionCount` | `0x9b4b22d3` | -| `renounceOwnership` | `0x715018a6` | -| `requestOwnershipHandover` | `0x25692962` | -| `revokeRole` | `0xd547741f` | -| `setAuctionEndDelaySeconds` | `0x88606b1a` | -| `transferOwnership` | `0xf2fde38b` | -| `watcherPrecompileConfig` | `0x8618a912` | -| `watcherPrecompileLimits` | `0xa71cd97d` | -| `watcherPrecompile__` | `0x1de360c3` | -| `winningBids` | `0x9133f232` | - -## ContractFactoryPlug - -| Function | Signature | -| ---------------------------- | ------------ | -| `appGatewayId` | `0x1c335f49` | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `connectSocket` | `0x258d19c8` | -| `deployContract` | `0xa0695389` | -| `getAddress` | `0x94ca2cb5` | -| `grantRole` | `0x2f2ff15d` | -| `hasRole` | `0x91d14854` | -| `initSocket` | `0xa07d8545` | -| `isSocketInitialized` | `0x9a7d9a9b` | -| `overrides` | `0x4a85f041` | -| `owner` | `0x8da5cb5b` | -| `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `renounceOwnership` | `0x715018a6` | -| `requestOwnershipHandover` | `0x25692962` | -| `rescueFunds` | `0x6ccae054` | -| `revokeRole` | `0xd547741f` | -| `socket__` | `0xc6a261d2` | -| `transferOwnership` | `0xf2fde38b` | - -## FeesManager - -| Function | Signature | -| ------------------------------------------------ | ------------ | -| `addressResolver__` | `0x6a750469` | -| `assignWatcherPrecompileCreditsFromAddress` | `0xd699b6c8` | -| `assignWatcherPrecompileCreditsFromRequestCount` | `0x7a483022` | -| `blockCredits` | `0x2d64fc91` | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `deliveryHelper__` | `0xc031dfb4` | -| `depositCredits` | `0x211998c8` | -| `evmxSlug` | `0x8bae77c2` | -| `feesCounter` | `0xb94f4778` | -| `getAvailableCredits` | `0xb065a8e5` | -| `getMaxCreditsAvailableForWithdraw` | `0x6ef9efe2` | -| `getWithdrawTransmitterCreditsPayloadParams` | `0x27be4536` | -| `initialize` | `0x6f6186bd` | -| `isAppGatewayWhitelisted` | `0x2a83b813` | -| `isNonceUsed` | `0x5d00bb12` | -| `isUserCreditsEnough` | `0x5bee3a67` | -| `onRequestComplete` | `0x5ed1f959` | -| `owner` | `0x8da5cb5b` | -| `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `renounceOwnership` | `0x715018a6` | -| `requestCountCredits` | `0x0c9b8a49` | -| `requestOwnershipHandover` | `0x25692962` | -| `sbType` | `0x745de344` | -| `tokenPoolBalances` | `0x2eda3bfd` | -| `transferOwnership` | `0xf2fde38b` | -| `unblockAndAssignCredits` | `0x01958181` | -| `unblockCredits` | `0xa0b32314` | -| `unwrap` | `0xde0e9a3e` | -| `userCredits` | `0x20babb92` | -| `userNonce` | `0x2e04b8e7` | -| `watcherPrecompileConfig` | `0x8618a912` | -| `watcherPrecompileCredits` | `0x052e1f6a` | -| `watcherPrecompileLimits` | `0xa71cd97d` | -| `watcherPrecompile__` | `0x1de360c3` | -| `whitelistAppGatewayWithSignature` | `0x28cbf83d` | -| `whitelistAppGateways` | `0x6c2499e3` | -| `withdrawCredits` | `0xc22f8cf3` | -| `wrap` | `0xd46eb119` | - -## FeesPlug - | Function | Signature | | ---------------------------- | ------------ | -| `appGatewayId` | `0x1c335f49` | +| `addressResolver__` | `0x6a750469` | +| `asyncDeployer__` | `0x2a39e801` | +| `auctionEndDelaySeconds` | `0x9087dfdb` | +| `auctionManager` | `0xb0192f9a` | +| `auctionStatus` | `0xd7d5fbf6` | +| `bid` | `0xfcdf49c2` | +| `bidTimeout` | `0x94090d0b` | | `cancelOwnershipHandover` | `0x54d1f13d` | | `completeOwnershipHandover` | `0xf04e283e` | -| `connectSocket` | `0x258d19c8` | -| `depositToFee` | `0xef0db49f` | -| `depositToFeeAndNative` | `0x5f952be8` | -| `depositToNative` | `0xe2665889` | +| `consumeFrom` | `0x40dd78be` | +| `creationCodeWithArgs` | `0xc126dcc4` | +| `deployForwarder__` | `0xd4e3b034` | +| `endAuction` | `0x1212e653` | +| `evmxSlug` | `0x8bae77c2` | +| `expireBid` | `0x1dd5022c` | +| `feesManager__` | `0x70568b58` | +| `forwarderAddresses` | `0x5390fdcb` | +| `getOnChainAddress` | `0xb6abffd7` | +| `getOverrideParams` | `0x54f0a866` | | `grantRole` | `0x2f2ff15d` | +| `handleRevert` | `0x44792f25` | | `hasRole` | `0x91d14854` | -| `initSocket` | `0xa07d8545` | -| `isSocketInitialized` | `0x9a7d9a9b` | -| `overrides` | `0x4a85f041` | +| `initialize` | `0x8d8965bd` | +| `isAsyncModifierSet` | `0xb69e0c4a` | +| `isValidPromise` | `0xb690b962` | +| `maxFees` | `0xe83e34b1` | +| `maxReAuctionCount` | `0xc367b376` | +| `onCompleteData` | `0xb52fa926` | +| `onRequestComplete` | `0x5ed1f959` | +| `overrideParams` | `0xec5490fe` | | `owner` | `0x8da5cb5b` | | `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `removeTokenFromWhitelist` | `0x306275be` | +| `reAuctionCount` | `0x9b4b22d3` | | `renounceOwnership` | `0x715018a6` | | `requestOwnershipHandover` | `0x25692962` | -| `rescueFunds` | `0x6ccae054` | | `revokeRole` | `0xd547741f` | -| `socket__` | `0xc6a261d2` | +| `sbType` | `0x745de344` | +| `setAddress` | `0x85bf312c` | +| `setAuctionEndDelaySeconds` | `0x88606b1a` | +| `setMaxReAuctionCount` | `0x64c71403` | | `transferOwnership` | `0xf2fde38b` | -| `whitelistToken` | `0x6247f6f2` | -| `whitelistedTokens` | `0xdaf9c210` | -| `withdrawFees` | `0xe55dc4e6` | +| `watcher__` | `0x300bb063` | +| `winningBids` | `0x9133f232` | ## Socket | Function | Signature | | ---------------------------- | ------------ | +| `OFF_CHAIN_CALLER` | `0xcb2cb4f6` | | `cancelOwnershipHandover` | `0x54d1f13d` | | `chainSlug` | `0xb349ba65` | | `completeOwnershipHandover` | `0xf04e283e` | | `connect` | `0xb3bde1aa` | | `disableSwitchboard` | `0xe545b261` | | `enableSwitchboard` | `0xf97a498a` | -| `execute` | `0x68ef086b` | +| `execute` | `0xafa8b480` | | `getPlugConfig` | `0xf9778ee0` | | `grantRole` | `0x2f2ff15d` | | `hasRole` | `0x91d14854` | @@ -267,6 +76,7 @@ | `revokeRole` | `0xd547741f` | | `setMaxCopyBytes` | `0x4fc7d6e9` | | `setSocketFeeManager` | `0x25bd97e5` | +| `simulate` | `0x91bf8275` | | `socketFeeManager` | `0xde5b8838` | | `transferOwnership` | `0xf2fde38b` | | `triggerCounter` | `0x8b0021de` | @@ -276,7 +86,7 @@ | Function | Signature | | ---------------------------- | ------------ | -| `attestAndExecute` | `0xa11d3bdc` | +| `attestAndExecute` | `0x66c7748a` | | `cancelOwnershipHandover` | `0x54d1f13d` | | `completeOwnershipHandover` | `0xf04e283e` | | `owner` | `0x8da5cb5b` | @@ -298,7 +108,7 @@ | `hasRole` | `0x91d14854` | | `owner` | `0x8da5cb5b` | | `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `payAndCheckFees` | `0xbaa56229` | +| `payAndCheckFees` | `0xd9d29ae3` | | `renounceOwnership` | `0x715018a6` | | `requestOwnershipHandover` | `0x25692962` | | `rescueFunds` | `0x6ccae054` | @@ -307,109 +117,335 @@ | `socketFees` | `0xab1b33a8` | | `transferOwnership` | `0xf2fde38b` | -## WatcherPrecompileConfig +## FeesManager + +| Function | Signature | +| -------------------------------- | ------------ | +| `addressResolver__` | `0x6a750469` | +| `approveAppGatewayWithSignature` | `0x94b649ec` | +| `approveAppGateways` | `0x86d23ab2` | +| `asyncDeployer__` | `0x2a39e801` | +| `blockCredits` | `0x9e434307` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `deployForwarder__` | `0xd4e3b034` | +| `deposit` | `0x5671d329` | +| `evmxSlug` | `0x8bae77c2` | +| `feesManager__` | `0x70568b58` | +| `feesPlugs` | `0x23f5ee8a` | +| `feesPool` | `0x6b259690` | +| `getAvailableCredits` | `0xb065a8e5` | +| `initialize` | `0xbf2c8539` | +| `isApproved` | `0xa389783e` | +| `isCreditSpendable` | `0x4f8990fd` | +| `isNonceUsed` | `0xcab7e8eb` | +| `onRequestComplete` | `0x5ed1f959` | +| `owner` | `0x8da5cb5b` | +| `ownershipHandoverExpiresAt` | `0xfee81cf4` | +| `renounceOwnership` | `0x715018a6` | +| `requestBlockedCredits` | `0xb62d25ac` | +| `requestOwnershipHandover` | `0x25692962` | +| `sbType` | `0x745de344` | +| `setFeesPlug` | `0xeab75f36` | +| `setFeesPool` | `0xd6684588` | +| `tokenOnChainBalances` | `0x3b27866d` | +| `transferCredits` | `0xf1686c89` | +| `transferOwnership` | `0xf2fde38b` | +| `unblockAndAssignCredits` | `0x01958181` | +| `unblockCredits` | `0xa0b32314` | +| `unwrap` | `0x7647691d` | +| `userCredits` | `0x20babb92` | +| `watcher__` | `0x300bb063` | +| `withdrawCredits` | `0xcfc6dbd9` | +| `wrap` | `0x023276f0` | + +## FeesPool + +| Function | Signature | +| ---------------------------- | ------------ | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `getBalance` | `0x12065fe0` | +| `grantRole` | `0x2f2ff15d` | +| `hasRole` | `0x91d14854` | +| `owner` | `0x8da5cb5b` | +| `ownershipHandoverExpiresAt` | `0xfee81cf4` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `revokeRole` | `0xd547741f` | +| `transferOwnership` | `0xf2fde38b` | +| `withdraw` | `0xf3fef3a3` | + +## AddressResolver + +| Function | Signature | +| ---------------------------- | ------------ | +| `asyncDeployer__` | `0x2a39e801` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `contractAddresses` | `0xf689e892` | +| `defaultAuctionManager` | `0x8f27cdc6` | +| `deployForwarder__` | `0xd4e3b034` | +| `feesManager__` | `0x70568b58` | +| `initialize` | `0xc4d66de8` | +| `owner` | `0x8da5cb5b` | +| `ownershipHandoverExpiresAt` | `0xfee81cf4` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `setAsyncDeployer` | `0xcb0ffff8` | +| `setContractAddress` | `0xe001f841` | +| `setDefaultAuctionManager` | `0xede8b4b5` | +| `setDeployForwarder` | `0xaeaee8a6` | +| `setFeesManager` | `0x1c89382a` | +| `setWatcher` | `0x24f48bc5` | +| `transferOwnership` | `0xf2fde38b` | +| `watcher__` | `0x300bb063` | + +## AsyncDeployer + +| Function | Signature | +| ------------------------------- | ------------ | +| `addressResolver__` | `0x6a750469` | +| `asyncDeployer__` | `0x2a39e801` | +| `asyncPromiseBeacon` | `0xc0fbc0ef` | +| `asyncPromiseCounter` | `0x97cdbf4c` | +| `asyncPromiseImplementation` | `0x59531b8d` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `deployAsyncPromiseContract` | `0x9851be0b` | +| `deployForwarder__` | `0xd4e3b034` | +| `feesManager__` | `0x70568b58` | +| `forwarderBeacon` | `0x945709ae` | +| `forwarderImplementation` | `0xe38d60a1` | +| `getAsyncPromiseAddress` | `0x104f39b4` | +| `getForwarderAddress` | `0x48c0b3e0` | +| `getOrDeployForwarderContract` | `0x0aa178de` | +| `initialize` | `0x485cc955` | +| `owner` | `0x8da5cb5b` | +| `ownershipHandoverExpiresAt` | `0xfee81cf4` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `setAsyncPromiseImplementation` | `0xeb506eab` | +| `setForwarderImplementation` | `0x83b1e974` | +| `transferOwnership` | `0xf2fde38b` | +| `watcher__` | `0x300bb063` | + +## AsyncPromise + +| Function | Signature | +| ------------------- | ------------ | +| `addressResolver__` | `0x6a750469` | +| `asyncDeployer__` | `0x2a39e801` | +| `callbackData` | `0xef44c272` | +| `callbackSelector` | `0x2764f92f` | +| `deployForwarder__` | `0xd4e3b034` | +| `exceededMaxCopy` | `0xaf598c7c` | +| `feesManager__` | `0x70568b58` | +| `initialize` | `0x0ece6089` | +| `localInvoker` | `0x45eb87f4` | +| `markOnchainRevert` | `0xd0e7af1b` | +| `markResolved` | `0x822d5d1f` | +| `requestCount` | `0x5badbe4c` | +| `returnData` | `0xebddbaf6` | +| `state` | `0xc19d93fb` | +| `then` | `0x0bf2ba15` | +| `watcher__` | `0x300bb063` | + +## DeployForwarder + +| Function | Signature | +| ------------------------- | ------------ | +| `addressResolver__` | `0x6a750469` | +| `asyncDeployer__` | `0x2a39e801` | +| `deploy` | `0x940f11af` | +| `deployForwarder__` | `0xd4e3b034` | +| `deployerSwitchboardType` | `0xaa381f9a` | +| `feesManager__` | `0x70568b58` | +| `saltCounter` | `0xa04c6809` | +| `watcher__` | `0x300bb063` | + +## Forwarder + +| Function | Signature | +| ------------------- | ------------ | +| `addressResolver__` | `0x6a750469` | +| `asyncDeployer__` | `0x2a39e801` | +| `chainSlug` | `0xb349ba65` | +| `deployForwarder__` | `0xd4e3b034` | +| `feesManager__` | `0x70568b58` | +| `getChainSlug` | `0x0b8c6568` | +| `getOnChainAddress` | `0x9da48789` | +| `initialize` | `0x647c576c` | +| `onChainAddress` | `0x8bd0b363` | +| `watcher__` | `0x300bb063` | + +## ProxyFactory + +| Function | Signature | +| ----------------------------- | ------------ | +| `adminOf` | `0x2abbef15` | +| `changeAdmin` | `0x1acfd02a` | +| `deploy` | `0x545e7c61` | +| `deployAndCall` | `0x4314f120` | +| `deployDeterministic` | `0x3729f922` | +| `deployDeterministicAndCall` | `0xa97b90d5` | +| `initCodeHash` | `0xdb4c545e` | +| `predictDeterministicAddress` | `0x5414dff0` | +| `upgrade` | `0x99a88ec4` | +| `upgradeAndCall` | `0x9623609d` | + +## TestUSDC + +| Function | Signature | +| ------------------ | ------------ | +| `DOMAIN_SEPARATOR` | `0x3644e515` | +| `allowance` | `0xdd62ed3e` | +| `approve` | `0x095ea7b3` | +| `balanceOf` | `0x70a08231` | +| `decimals` | `0x313ce567` | +| `mint` | `0x40c10f19` | +| `name` | `0x06fdde03` | +| `nonces` | `0x7ecebe00` | +| `owner` | `0x8da5cb5b` | +| `permit` | `0xd505accf` | +| `symbol` | `0x95d89b41` | +| `totalSupply` | `0x18160ddd` | +| `transfer` | `0xa9059cbb` | +| `transferFrom` | `0x23b872dd` | + +## ContractFactoryPlug + +| Function | Signature | +| ---------------------------- | ------------ | +| `appGatewayId` | `0x1c335f49` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `connectSocket` | `0x258d19c8` | +| `deployContract` | `0xa0695389` | +| `getAddress` | `0x94ca2cb5` | +| `grantRole` | `0x2f2ff15d` | +| `hasRole` | `0x91d14854` | +| `initSocket` | `0xa07d8545` | +| `isSocketInitialized` | `0x9a7d9a9b` | +| `overrides` | `0x4a85f041` | +| `owner` | `0x8da5cb5b` | +| `ownershipHandoverExpiresAt` | `0xfee81cf4` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | +| `revokeRole` | `0xd547741f` | +| `socket__` | `0xc6a261d2` | +| `transferOwnership` | `0xf2fde38b` | + +## Configurations | Function | Signature | | ---------------------------- | ------------ | -| `addressResolver__` | `0x6a750469` | | `cancelOwnershipHandover` | `0x54d1f13d` | | `completeOwnershipHandover` | `0xf04e283e` | -| `contractFactoryPlug` | `0xd8427483` | -| `deliveryHelper__` | `0xc031dfb4` | -| `evmxSlug` | `0x8bae77c2` | -| `feesPlug` | `0xd1ba159d` | | `getPlugConfigs` | `0x8a028c38` | -| `initialize` | `0x6ecf2b22` | -| `isNonceUsed` | `0x5d00bb12` | | `isValidPlug` | `0xec8aef74` | | `owner` | `0x8da5cb5b` | | `ownershipHandoverExpiresAt` | `0xfee81cf4` | | `renounceOwnership` | `0x715018a6` | | `requestOwnershipHandover` | `0x25692962` | -| `setAppGateways` | `0xdd8539d4` | -| `setIsValidPlug` | `0xb3a6bbcf` | -| `setOnChainContracts` | `0x33fa78c2` | +| `setAppGatewayConfigs` | `0xd137fcbb` | +| `setIsValidPlug` | `0xf41332b0` | +| `setSocket` | `0x075c40be` | | `setSwitchboard` | `0x61706f1e` | | `sockets` | `0xb44a23ab` | | `switchboards` | `0xaa539546` | | `transferOwnership` | `0xf2fde38b` | -| `verifyConnections` | `0xf269ab50` | -| `watcherPrecompileConfig` | `0x8618a912` | -| `watcherPrecompileLimits` | `0xa71cd97d` | -| `watcherPrecompile__` | `0x1de360c3` | - -## WatcherPrecompileLimits - -| Function | Signature | -| --------------------------------- | ------------ | -| `addressResolver__` | `0x6a750469` | -| `callBackFees` | `0xf9554ecc` | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `consumeLimit` | `0xc22f5a13` | -| `defaultLimit` | `0xe26b013b` | -| `defaultRatePerSecond` | `0x16d7acdf` | -| `deliveryHelper__` | `0xc031dfb4` | -| `finalizeFees` | `0x09207879` | -| `getCurrentLimit` | `0x1a065507` | -| `getLimitParams` | `0x2ff81ee0` | -| `getTotalFeesRequired` | `0x964500b5` | -| `initialize` | `0x1794bb3c` | -| `limitDecimals` | `0xee185533` | -| `owner` | `0x8da5cb5b` | -| `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `queryFees` | `0xcfcbafb6` | -| `renounceOwnership` | `0x715018a6` | -| `requestOwnershipHandover` | `0x25692962` | -| `setCallBackFees` | `0x622be814` | -| `setDefaultLimitAndRatePerSecond` | `0x7e434156` | -| `setFinalizeFees` | `0xbce0a88c` | -| `setQueryFees` | `0x877135d7` | -| `setTimeoutFees` | `0x571db4f9` | -| `timeoutFees` | `0xeab12f7e` | -| `transferOwnership` | `0xf2fde38b` | -| `updateLimitParams` | `0x01b2a5a0` | -| `watcherPrecompileConfig` | `0x8618a912` | -| `watcherPrecompileLimits` | `0xa71cd97d` | -| `watcherPrecompile__` | `0x1de360c3` | - -## DeliveryHelper +| `verifyConnections` | `0xa53b6fad` | +| `watcher__` | `0x300bb063` | + +## PromiseResolver + +| Function | Signature | +| ----------------- | ------------ | +| `markRevert` | `0x56501015` | +| `resolvePromises` | `0xbf8484b8` | +| `watcher__` | `0x300bb063` | + +## RequestHandler | Function | Signature | | ------------------------------ | ------------ | | `addressResolver__` | `0x6a750469` | -| `batch` | `0xd9307dd8` | -| `bidTimeout` | `0x94090d0b` | +| `assignTransmitter` | `0xae5e9c48` | +| `asyncDeployer__` | `0x2a39e801` | | `cancelOwnershipHandover` | `0x54d1f13d` | -| `cancelRequest` | `0x50ad0779` | -| `chainMaxMsgValueLimit` | `0x01d1e126` | -| `clearQueue` | `0xf22cb874` | +| `cancelRequest` | `0x3b5fd6fb` | +| `cancelRequestForReverts` | `0x82970278` | | `completeOwnershipHandover` | `0xf04e283e` | -| `deliveryHelper__` | `0xc031dfb4` | -| `finishRequest` | `0xeab148c0` | -| `getDeliveryHelperPlugAddress` | `0xb709bd9f` | -| `getFees` | `0xfbf4ec4b` | -| `getRequestMetadata` | `0x5f1dde51` | -| `handleRequestReverts` | `0x8fe9734f` | -| `increaseFees` | `0xe9b304da` | -| `initialize` | `0x7265580f` | +| `deployForwarder__` | `0xd4e3b034` | +| `feesManager__` | `0x70568b58` | +| `getBatchPayloadIds` | `0xfd83cd1f` | +| `getPayload` | `0xb48fd0fe` | +| `getPrecompileFees` | `0xabac263c` | +| `getRequest` | `0xcf39abf6` | +| `getRequestBatchIds` | `0xe138fadb` | +| `handleRevert` | `0xcc88d3f9` | +| `increaseFees` | `0x10205541` | +| `nextBatchCount` | `0x333a3963` | +| `nextRequestCount` | `0xfef72893` | | `owner` | `0x8da5cb5b` | | `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `queue` | `0x1b9396f5` | -| `queuePayloadParams` | `0x3c362159` | +| `payloadCounter` | `0x550ce1d5` | +| `precompiles` | `0x9932450b` | | `renounceOwnership` | `0x715018a6` | | `requestOwnershipHandover` | `0x25692962` | -| `requests` | `0xb71a5e58` | -| `saltCounter` | `0xa04c6809` | -| `startRequestProcessing` | `0x5ca2100f` | +| `setPrecompile` | `0x122e0042` | +| `submitRequest` | `0xbb299a2c` | | `transferOwnership` | `0xf2fde38b` | -| `updateBidTimeout` | `0xa29f83d1` | -| `updateChainMaxMsgValueLimits` | `0x0b32de76` | -| `watcherPrecompileConfig` | `0x8618a912` | -| `watcherPrecompileLimits` | `0xa71cd97d` | -| `watcherPrecompile__` | `0x1de360c3` | -| `withdrawTo` | `0x2ba9d5bb` | -| `withdrawTransmitterFees` | `0x38ff6dd2` | +| `updateRequestAndProcessBatch` | `0x46464471` | +| `watcher__` | `0x300bb063` | + +## Watcher + +| Function | Signature | +| ---------------------------- | ------------ | +| `addressResolver__` | `0x6a750469` | +| `appGatewayTemp` | `0x1394c029` | +| `asyncDeployer__` | `0x2a39e801` | +| `callAppGateways` | `0x0050bef1` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `cancelRequest` | `0x50ad0779` | +| `clearQueue` | `0xf22cb874` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `configurations__` | `0x52a3bbeb` | +| `deployForwarder__` | `0xd4e3b034` | +| `evmxSlug` | `0x8bae77c2` | +| `feesManager__` | `0x70568b58` | +| `getCurrentRequestCount` | `0x5715abbb` | +| `getPayloadParams` | `0xae5eeb77` | +| `getPrecompileFees` | `0xabac263c` | +| `getRequestParams` | `0x71263d0d` | +| `increaseFees` | `0xe9b304da` | +| `initialize` | `0xaaf7fc1a` | +| `isAppGatewayCalled` | `0xa79da6c7` | +| `isNonceUsed` | `0x5d00bb12` | +| `isWatcher` | `0x84785ecd` | +| `latestAsyncPromise` | `0xb8a8ba52` | +| `owner` | `0x8da5cb5b` | +| `ownershipHandoverExpiresAt` | `0xfee81cf4` | +| `payloadQueue` | `0x74f00ffb` | +| `promiseResolver__` | `0xdee152be` | +| `queue` | `0xf03ca7f7` | +| `queueAndSubmit` | `0xf0fb9665` | +| `renounceOwnership` | `0x715018a6` | +| `requestHandler__` | `0x55184561` | +| `requestOwnershipHandover` | `0x25692962` | +| `setCoreContracts` | `0xefa891c4` | +| `setIsValidPlug` | `0x7fc82ff6` | +| `setTriggerFees` | `0xaeb30511` | +| `submitRequest` | `0x4890b5ef` | +| `transferOwnership` | `0xf2fde38b` | +| `triggerFees` | `0x73f76aec` | +| `triggerFromChainSlug` | `0xd12b4f12` | +| `triggerFromPlug` | `0x3b847d12` | +| `watcherMultiCall` | `0x8021e82b` | +| `watcher__` | `0x300bb063` | ## FastSwitchboard @@ -433,61 +469,64 @@ | `socket__` | `0xc6a261d2` | | `transferOwnership` | `0xf2fde38b` | -## WatcherPrecompile +## ReadPrecompile -| Function | Signature | -| ----------------------------- | ------------ | -| `addressResolver__` | `0x6a750469` | -| `appGatewayCalled` | `0xc6767cf1` | -| `appGatewayCaller` | `0x712b193a` | -| `batchPayloadIds` | `0x02b74f98` | -| `callAppGateways` | `0x5c38ded5` | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `cancelRequest` | `0x50ad0779` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `deliveryHelper__` | `0xc031dfb4` | -| `evmxSlug` | `0x8bae77c2` | -| `expiryTime` | `0x99bc0aea` | -| `finalized` | `0x81c051de` | -| `getBatchPayloadIds` | `0xfd83cd1f` | -| `getBatches` | `0xcb95b7b3` | -| `getCurrentRequestCount` | `0x5715abbb` | -| `getDigest` | `0xa7993154` | -| `getPayloadParams` | `0xae5eeb77` | -| `getRequestParams` | `0x71263d0d` | -| `initialize` | `0xb7dc6b77` | -| `isNonceUsed` | `0x5d00bb12` | -| `isPromiseExecuted` | `0x17a2cdf0` | -| `markRevert` | `0x1c75dad5` | -| `maxTimeoutDelayInSeconds` | `0x46fbc9d7` | -| `nextBatchCount` | `0x333a3963` | -| `nextRequestCount` | `0xfef72893` | -| `owner` | `0x8da5cb5b` | -| `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `payloadCounter` | `0x550ce1d5` | -| `payloads` | `0x58722672` | -| `query` | `0x16ad71bc` | -| `renounceOwnership` | `0x715018a6` | -| `requestBatchIds` | `0xf865c4a7` | -| `requestMetadata` | `0x875b3f7e` | -| `requestOwnershipHandover` | `0x25692962` | -| `requestParams` | `0x5ce2d853` | -| `resolvePromises` | `0xccb1caff` | -| `resolveTimeout` | `0xa67c0781` | -| `setExpiryTime` | `0x30fc4cff` | -| `setMaxTimeoutDelayInSeconds` | `0x65d480fc` | -| `setTimeout` | `0x9c29ec74` | -| `setWatcherPrecompileConfig` | `0x794edeb4` | -| `setWatcherPrecompileLimits` | `0x712a6f07` | -| `startProcessingRequest` | `0x77290f24` | -| `submitRequest` | `0x16b47482` | -| `timeoutIdPrefix` | `0x96ec119f` | -| `timeoutRequests` | `0xcdf85751` | -| `transferOwnership` | `0xf2fde38b` | -| `updateTransmitter` | `0xb228a22c` | -| `watcherPrecompileConfig` | `0x8618a912` | -| `watcherPrecompileConfig__` | `0xa816cbd9` | -| `watcherPrecompileLimits` | `0xa71cd97d` | -| `watcherPrecompileLimits__` | `0xb2ad6c48` | -| `watcherPrecompile__` | `0x1de360c3` | -| `watcherProofs` | `0x3fa3166b` | +| Function | Signature | +| ------------------------------ | ------------ | +| `expiryTime` | `0x99bc0aea` | +| `getPrecompileFees` | `0xb7a3d04c` | +| `handlePayload` | `0x1d5e1d98` | +| `readFees` | `0xe06357a2` | +| `resolvePayload` | `0xea92e825` | +| `setExpiryTime` | `0x30fc4cff` | +| `setFees` | `0x3d18678e` | +| `validateAndGetPrecompileData` | `0xab172aab` | +| `watcher__` | `0x300bb063` | + +## SchedulePrecompile + +| Function | Signature | +| ------------------------------ | ------------ | +| `expiryTime` | `0x99bc0aea` | +| `getPrecompileFees` | `0xb7a3d04c` | +| `handlePayload` | `0x1d5e1d98` | +| `maxScheduleDelayInSeconds` | `0x3ef01cdb` | +| `resolvePayload` | `0xea92e825` | +| `scheduleCallbackFees` | `0x4c5b6007` | +| `scheduleFeesPerSecond` | `0x852a74c1` | +| `setExpiryTime` | `0x30fc4cff` | +| `setMaxScheduleDelayInSeconds` | `0x12953318` | +| `setScheduleCallbackFees` | `0xec8fd71e` | +| `setScheduleFeesPerSecond` | `0x28e59e57` | +| `validateAndGetPrecompileData` | `0xab172aab` | +| `watcher__` | `0x300bb063` | + +## WritePrecompile + +| Function | Signature | +| ------------------------------ | ------------ | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `chainMaxMsgValueLimit` | `0x01d1e126` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `contractFactoryPlugs` | `0x35426631` | +| `digestHashes` | `0xd1a862bf` | +| `expiryTime` | `0x99bc0aea` | +| `getDigest` | `0xdd4bf97b` | +| `getPrecompileFees` | `0xb7a3d04c` | +| `getPrevBatchDigestHash` | `0x82b35b69` | +| `handlePayload` | `0x1d5e1d98` | +| `owner` | `0x8da5cb5b` | +| `ownershipHandoverExpiresAt` | `0xfee81cf4` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `resolvePayload` | `0xea92e825` | +| `setContractFactoryPlugs` | `0xc067b6dd` | +| `setExpiryTime` | `0x30fc4cff` | +| `setFees` | `0x3d18678e` | +| `transferOwnership` | `0xf2fde38b` | +| `updateChainMaxMsgValueLimits` | `0x6a7aa6ac` | +| `uploadProof` | `0x81b48fcf` | +| `validateAndGetPrecompileData` | `0xab172aab` | +| `watcherProofs` | `0x3fa3166b` | +| `watcher__` | `0x300bb063` | +| `writeFees` | `0x5c664aeb` | diff --git a/contracts/evmx/base/AppGatewayBase.sol b/contracts/evmx/base/AppGatewayBase.sol index ab78c8ca..1602e11c 100644 --- a/contracts/evmx/base/AppGatewayBase.sol +++ b/contracts/evmx/base/AppGatewayBase.sol @@ -149,7 +149,8 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { return address(0); } - onChainAddress = IForwarder(forwarderAddresses[contractId_][chainSlug_]).getOnChainAddress(); + onChainAddress = IForwarder(forwarderAddresses[contractId_][chainSlug_]) + .getOnChainAddress(); } //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/hardhat-scripts/config/config.ts b/hardhat-scripts/config/config.ts index e0964075..022727f3 100644 --- a/hardhat-scripts/config/config.ts +++ b/hardhat-scripts/config/config.ts @@ -61,13 +61,13 @@ export const transmitter = "0x138e9840861C983DC0BB9b3e941FB7C0e9Ade320"; // Chain config export const EVMX_CHAIN_ID = EVM_CHAIN_ID_MAP[mode]; export const MAX_FEES = ethers.utils.parseEther("0.001"); +export const MAX_MSG_VALUE_LIMIT = ethers.utils.parseEther("0.001"); // Auction parameters -export const auctionEndDelaySeconds = 0; +export const AUCTION_END_DELAY_SECONDS = 0; export const BID_TIMEOUT = 600; // 10 minutes export const EXPIRY_TIME = 300; // 5 minutes export const MAX_RE_AUCTION_COUNT = 5; -export const AUCTION_MANAGER_FUNDING_AMOUNT = ethers.utils.parseEther("100"); // TestUSDC export const TEST_USDC_NAME = "testUSDC"; export const TEST_USDC_SYMBOL = "testUSDC"; @@ -76,12 +76,22 @@ export const TEST_USDC_INITIAL_SUPPLY = ethers.utils.parseEther( ); export const TEST_USDC_DECIMALS = 6; +// Fees Pool Funding Amount +export const FEES_POOL_FUNDING_AMOUNT_THRESHOLD = + ethers.utils.parseEther("10000"); + // Watcher Precompile Fees -export const QUERY_FEES = utils.parseEther("0.000001"); -export const FINALIZE_FEES = utils.parseEther("0.000001"); -export const TIMEOUT_FEES = utils.parseEther("0.000001"); -export const CALLBACK_FEES = utils.parseEther("0.000001"); +export const READ_FEES = utils.parseEther("0.000001"); +export const TRIGGER_FEES = utils.parseEther("0.000001"); +export const WRITE_FEES = utils.parseEther("0.000001"); +export const SCHEDULE_FEES_PER_SECOND = utils.parseEther("0.000001"); +export const SCHEDULE_CALLBACK_FEES = utils.parseEther("0.000001"); +export const MAX_SCHEDULE_DELAY_SECONDS = 60 * 60 * 24; // Other constants export const DEFAULT_MAX_LIMIT = 100; export const UPGRADE_VERSION = 1; + +// Transmitter constants +export const TRANSMITTER_CREDIT_THRESHOLD = ethers.utils.parseEther("100"); // 100 ETH threshold +export const TRANSMITTER_NATIVE_THRESHOLD = ethers.utils.parseEther("100"); // 100 ETH threshold diff --git a/hardhat-scripts/constants/enums.ts b/hardhat-scripts/constants/enums.ts deleted file mode 100644 index 9a349056..00000000 --- a/hardhat-scripts/constants/enums.ts +++ /dev/null @@ -1,21 +0,0 @@ -export enum CORE_CONTRACTS { - Socket = "Socket", - SocketBatcher = "SocketBatcher", - FastSwitchboard = "FastSwitchboard", - FeesPlug = "FeesPlug", - ContractFactoryPlug = "ContractFactoryPlug", - TestUSDC = "TestUSDC", - SocketFeeManager = "SocketFeeManager", -} - -export enum EVMxCoreContracts { - Watcher = "Watcher", - ReqestHandler = "ReqestHandler", - Configurations = "Configurations", - AuctionManager = "AuctionManager", - FeesManager = "FeesManager", - DeliveryHelper = "DeliveryHelper", - Forwarder = "Forwarder", - AsyncPromise = "AsyncPromise", - AddressResolver = "AddressResolver", -} diff --git a/hardhat-scripts/constants/index.ts b/hardhat-scripts/constants/index.ts index e42be831..e6869b19 100644 --- a/hardhat-scripts/constants/index.ts +++ b/hardhat-scripts/constants/index.ts @@ -1,3 +1,2 @@ export * from "./constants"; -export * from "./enums"; export * from "./types"; diff --git a/hardhat-scripts/constants/roles.ts b/hardhat-scripts/constants/roles.ts index ec875446..31a4493b 100644 --- a/hardhat-scripts/constants/roles.ts +++ b/hardhat-scripts/constants/roles.ts @@ -5,4 +5,5 @@ export enum ROLES { WATCHER_ROLE = "WATCHER_ROLE", TRANSMITTER_ROLE = "TRANSMITTER_ROLE", SWITCHBOARD_DISABLER_ROLE = "SWITCHBOARD_DISABLER_ROLE", + FEE_MANAGER_ROLE = "FEE_MANAGER_ROLE", } diff --git a/hardhat-scripts/constants/types.ts b/hardhat-scripts/constants/types.ts index 0cd19bef..afb44d41 100644 --- a/hardhat-scripts/constants/types.ts +++ b/hardhat-scripts/constants/types.ts @@ -3,3 +3,10 @@ import { ChainAddressesObj, ChainSlug } from "../../src"; export type DeploymentAddresses = { [chainSlug in ChainSlug]?: ChainAddressesObj; }; + +export interface WatcherMultiCallParams { + contractAddress: string; + data: string; + nonce: number; + signature: string; +} diff --git a/hardhat-scripts/deploy/1.deploy.ts b/hardhat-scripts/deploy/1.deploy.ts index 0f452059..c6e5a877 100644 --- a/hardhat-scripts/deploy/1.deploy.ts +++ b/hardhat-scripts/deploy/1.deploy.ts @@ -1,44 +1,40 @@ -import { ChainAddressesObj, ChainSlug } from "../../src"; import { config } from "dotenv"; -import { BigNumber, Contract, Signer, utils, Wallet } from "ethers"; +import { Contract, utils, Wallet } from "ethers"; import { formatEther } from "ethers/lib/utils"; import { ethers } from "hardhat"; +import { ChainAddressesObj, ChainSlug, Contracts } from "../../src"; import { - CORE_CONTRACTS, - DeploymentAddresses, - ETH_ADDRESS, - EVMxCoreContracts, - FAST_SWITCHBOARD_TYPE, - IMPLEMENTATION_SLOT, -} from "../constants"; -import { - DeployParams, - getAddresses, - getInstance, - getOrDeploy, - storeAddresses, -} from "../utils"; -import { getSocketSigner, getWatcherSigner } from "../utils/sign"; -import { - auctionEndDelaySeconds, + AUCTION_END_DELAY_SECONDS, BID_TIMEOUT, chains, EVMX_CHAIN_ID, EXPIRY_TIME, logConfig, - DEFAULT_MAX_LIMIT, MAX_RE_AUCTION_COUNT, + MAX_SCHEDULE_DELAY_SECONDS, mode, - TEST_USDC_INITIAL_SUPPLY, + READ_FEES, + SCHEDULE_CALLBACK_FEES, + SCHEDULE_FEES_PER_SECOND, TEST_USDC_DECIMALS, + TEST_USDC_INITIAL_SUPPLY, TEST_USDC_NAME, TEST_USDC_SYMBOL, - QUERY_FEES, - FINALIZE_FEES, - TIMEOUT_FEES, - CALLBACK_FEES, - AUCTION_MANAGER_FUNDING_AMOUNT, + TRIGGER_FEES, + WRITE_FEES, } from "../config/config"; +import { + DeploymentAddresses, + FAST_SWITCHBOARD_TYPE, + IMPLEMENTATION_SLOT, +} from "../constants"; +import { + DeployParams, + getAddresses, + getOrDeploy, + storeAddresses, +} from "../utils"; +import { getSocketSigner, getWatcherSigner } from "../utils/sign"; config(); let EVMxOwner: string; @@ -111,169 +107,152 @@ const deployEVMxContracts = async () => { ); deployUtils.addresses[contractName] = proxyFactory.address; - deployUtils = await deployContractWithProxy( - EVMxCoreContracts.AddressResolver, - `contracts/protocol/AddressResolver.sol`, + const feesPool = await getOrDeploy( + Contracts.FeesPool, + Contracts.FeesPool, + "contracts/evmx/fees/FeesPool.sol", [EVMxOwner], - proxyFactory, deployUtils ); - - const addressResolver = await ethers.getContractAt( - EVMxCoreContracts.AddressResolver, - deployUtils.addresses[EVMxCoreContracts.AddressResolver] - ); + deployUtils.addresses[Contracts.FeesPool] = feesPool.address; deployUtils = await deployContractWithProxy( - EVMxCoreContracts.ReqestHandler, - `contracts/protocol/watcherPrecompile/ReqestHandler.sol`, - [EVMxOwner, addressResolver.address, DEFAULT_MAX_LIMIT], + Contracts.AddressResolver, + `contracts/evmx/helpers/AddressResolver.sol`, + [EVMxOwner], proxyFactory, deployUtils ); - deployUtils = await deployContractWithProxy( - EVMxCoreContracts.Configurations, - `contracts/protocol/watcherPrecompile/Configurations.sol`, - [EVMxOwner, addressResolver.address, EVMX_CHAIN_ID], - proxyFactory, - deployUtils + const addressResolver = await ethers.getContractAt( + Contracts.AddressResolver, + deployUtils.addresses[Contracts.AddressResolver] ); deployUtils = await deployContractWithProxy( - EVMxCoreContracts.Watcher, - `contracts/protocol/watcherPrecompile/core/Watcher.sol`, + Contracts.FeesManager, + `contracts/evmx/fees/FeesManager.sol`, [ - EVMxOwner, - addressResolver.address, - EXPIRY_TIME, EVMX_CHAIN_ID, - deployUtils.addresses[EVMxCoreContracts.ReqestHandler], - deployUtils.addresses[EVMxCoreContracts.Configurations], + addressResolver.address, + feesPool.address, + EVMxOwner, + FAST_SWITCHBOARD_TYPE, ], proxyFactory, deployUtils ); deployUtils = await deployContractWithProxy( - EVMxCoreContracts.FeesManager, - `contracts/protocol/payload-delivery/FeesManager.sol`, - [ - addressResolver.address, - EVMxOwner, - EVMX_CHAIN_ID, - FAST_SWITCHBOARD_TYPE, - ], + Contracts.AsyncDeployer, + `contracts/evmx/helpers/AsyncDeployer.sol`, + [EVMxOwner, addressResolver.address], proxyFactory, deployUtils ); - const feesManagerAddress = - deployUtils.addresses[EVMxCoreContracts.FeesManager]; - - console.log("Deploying DeliveryHelper"); deployUtils = await deployContractWithProxy( - EVMxCoreContracts.DeliveryHelper, - `contracts/protocol/payload-delivery/app-gateway/DeliveryHelper.sol`, - [addressResolver.address, EVMxOwner, BID_TIMEOUT], + Contracts.Watcher, + `contracts/evmx/watcher/Watcher.sol`, + [EVMX_CHAIN_ID, TRIGGER_FEES, EVMxOwner, addressResolver.address], proxyFactory, deployUtils ); - deployUtils = await deployContractWithProxy( - EVMxCoreContracts.AuctionManager, - `contracts/protocol/payload-delivery/AuctionManager.sol`, + const auctionManager = await getOrDeploy( + Contracts.AuctionManager, + Contracts.AuctionManager, + "contracts/evmx/AuctionManager.sol", [ EVMX_CHAIN_ID, - auctionEndDelaySeconds, + BID_TIMEOUT, + MAX_RE_AUCTION_COUNT, + AUCTION_END_DELAY_SECONDS, addressResolver.address, EVMxOwner, - MAX_RE_AUCTION_COUNT, ], - proxyFactory, deployUtils ); + deployUtils.addresses[Contracts.AuctionManager] = auctionManager.address; - await updateContractSettings( - addressResolver, - "deliveryHelper", - "setDeliveryHelper", - deployUtils.addresses[EVMxCoreContracts.DeliveryHelper], - deployUtils.signer - ); - - await updateContractSettings( - addressResolver, - "feesManager", - "setFeesManager", - feesManagerAddress, - deployUtils.signer + const deployForwarder = await getOrDeploy( + Contracts.DeployForwarder, + Contracts.DeployForwarder, + "contracts/evmx/helpers/DeployForwarder.sol", + [addressResolver.address, FAST_SWITCHBOARD_TYPE], + deployUtils ); - - await updateContractSettings( - addressResolver, - "defaultAuctionManager", - "setDefaultAuctionManager", - deployUtils.addresses[EVMxCoreContracts.AuctionManager], - deployUtils.signer + deployUtils.addresses[Contracts.DeployForwarder] = + deployForwarder.address; + + const configurations = await getOrDeploy( + Contracts.Configurations, + Contracts.Configurations, + "contracts/evmx/watcher/Configurations.sol", + [deployUtils.addresses[Contracts.Watcher], EVMxOwner], + deployUtils ); + deployUtils.addresses[Contracts.Configurations] = configurations.address; - await updateContractSettings( - addressResolver, - "watcherPrecompile__", - "setWatcherPrecompile", - deployUtils.addresses[EVMxCoreContracts.Watcher], - deployUtils.signer + const requestHandler = await getOrDeploy( + Contracts.RequestHandler, + Contracts.RequestHandler, + "contracts/evmx/watcher/RequestHandler.sol", + [EVMxOwner, addressResolver.address], + deployUtils ); + deployUtils.addresses[Contracts.RequestHandler] = requestHandler.address; - let watcherPrecompileLimits = await getInstance( - EVMxCoreContracts.ReqestHandler, - deployUtils.addresses[EVMxCoreContracts.ReqestHandler] - ); - watcherPrecompileLimits = watcherPrecompileLimits.connect( - deployUtils.signer - ); - await updateContractSettings( - watcherPrecompileLimits, - "queryFees", - "setQueryFees", - QUERY_FEES, - deployUtils.signer + const promiseResolver = await getOrDeploy( + Contracts.PromiseResolver, + Contracts.PromiseResolver, + "contracts/evmx/watcher/PromiseResolver.sol", + [deployUtils.addresses[Contracts.Watcher]], + deployUtils ); + deployUtils.addresses[Contracts.PromiseResolver] = + promiseResolver.address; - await updateContractSettings( - watcherPrecompileLimits, - "finalizeFees", - "setFinalizeFees", - FINALIZE_FEES, - deployUtils.signer + const writePrecompile = await getOrDeploy( + Contracts.WritePrecompile, + Contracts.WritePrecompile, + "contracts/evmx/watcher/precompiles/WritePrecompile.sol", + [ + EVMxOwner, + deployUtils.addresses[Contracts.Watcher], + WRITE_FEES, + EXPIRY_TIME, + ], + deployUtils ); - - await updateContractSettings( - watcherPrecompileLimits, - "timeoutFees", - "setTimeoutFees", - TIMEOUT_FEES, - deployUtils.signer + deployUtils.addresses[Contracts.WritePrecompile] = + writePrecompile.address; + + const readPrecompile = await getOrDeploy( + Contracts.ReadPrecompile, + Contracts.ReadPrecompile, + "contracts/evmx/watcher/precompiles/ReadPrecompile.sol", + [deployUtils.addresses[Contracts.Watcher], READ_FEES, EXPIRY_TIME], + deployUtils ); + deployUtils.addresses[Contracts.ReadPrecompile] = readPrecompile.address; - await updateContractSettings( - watcherPrecompileLimits, - "callBackFees", - "setCallBackFees", - CALLBACK_FEES, - deployUtils.signer + const schedulePrecompile = await getOrDeploy( + Contracts.SchedulePrecompile, + Contracts.SchedulePrecompile, + "contracts/evmx/watcher/precompiles/SchedulePrecompile.sol", + [ + deployUtils.addresses[Contracts.Watcher], + MAX_SCHEDULE_DELAY_SECONDS, + SCHEDULE_FEES_PER_SECOND, + SCHEDULE_CALLBACK_FEES, + EXPIRY_TIME, + ], + deployUtils ); + deployUtils.addresses[Contracts.SchedulePrecompile] = + schedulePrecompile.address; - const feesManager = await getInstance( - EVMxCoreContracts.FeesManager, - deployUtils.addresses[EVMxCoreContracts.FeesManager] - ); - await fundAuctionManager( - feesManager.connect(deployUtils.signer), - deployUtils.addresses[EVMxCoreContracts.AuctionManager], - deployUtils.signer - ); deployUtils.addresses.startBlock = (deployUtils.addresses.startBlock ? deployUtils.addresses.startBlock @@ -289,56 +268,6 @@ const deployEVMxContracts = async () => { } }; -export const fundAuctionManager = async ( - feesManager: Contract, - auctionManagerAddress: string, - watcherSigner: Signer -) => { - const currentCredits = await feesManager.getAvailableCredits( - auctionManagerAddress - ); - console.log("Current credits:", currentCredits.toString()); - if (currentCredits.gte(BigNumber.from(AUCTION_MANAGER_FUNDING_AMOUNT))) { - console.log( - `Auction manager ${auctionManagerAddress} already has credits, skipping funding` - ); - return; - } - const signatureNonce = Date.now(); - const digest = ethers.utils.keccak256( - ethers.utils.defaultAbiCoder.encode( - ["address", "uint32", "address", "uint256", "address", "uint32"], - [ - auctionManagerAddress, - EVMX_CHAIN_ID, - ETH_ADDRESS, - AUCTION_MANAGER_FUNDING_AMOUNT, - feesManager.address, - EVMX_CHAIN_ID, - ] - ) - ); - const signature = await watcherSigner.signMessage( - ethers.utils.arrayify(digest) - ); - const tx = await feesManager - .connect(watcherSigner) - .depositCredits( - auctionManagerAddress, - EVMX_CHAIN_ID, - ETH_ADDRESS, - signatureNonce, - signature, - { - value: AUCTION_MANAGER_FUNDING_AMOUNT, - } - ); - console.log( - `Funding auction manager ${auctionManagerAddress} with ${AUCTION_MANAGER_FUNDING_AMOUNT} ETH, txHash: `, - tx.hash - ); - await tx.wait(); -}; const deploySocketContracts = async () => { try { let addresses: DeploymentAddresses; @@ -367,42 +296,42 @@ const deploySocketContracts = async () => { currentChainSlug: chain as ChainSlug, }; - let contractName = CORE_CONTRACTS.Socket; + let contractName = Contracts.Socket; const socket: Contract = await getOrDeploy( contractName, contractName, - `contracts/protocol/socket/${contractName}.sol`, + `contracts/protocol/${contractName}.sol`, [chain as ChainSlug, socketOwner, "EVMX"], deployUtils ); deployUtils.addresses[contractName] = socket.address; - contractName = CORE_CONTRACTS.SocketBatcher; + contractName = Contracts.SocketBatcher; const batcher: Contract = await getOrDeploy( contractName, contractName, - `contracts/protocol/socket/${contractName}.sol`, + `contracts/protocol/${contractName}.sol`, [socketOwner, socket.address], deployUtils ); deployUtils.addresses[contractName] = batcher.address; - contractName = CORE_CONTRACTS.FastSwitchboard; + contractName = Contracts.FastSwitchboard; const sb: Contract = await getOrDeploy( contractName, contractName, - `contracts/protocol/socket/switchboard/${contractName}.sol`, + `contracts/protocol/switchboard/${contractName}.sol`, [chain as ChainSlug, socket.address, socketOwner], deployUtils ); deployUtils.addresses[contractName] = sb.address; - contractName = CORE_CONTRACTS.TestUSDC; + contractName = Contracts.TestUSDC; const testUSDC: Contract = await getOrDeploy( contractName, contractName, - `contracts/helpers/${contractName}.sol`, + `contracts/evmx/mocks/${contractName}.sol`, [ TEST_USDC_NAME, TEST_USDC_SYMBOL, @@ -414,23 +343,21 @@ const deploySocketContracts = async () => { ); deployUtils.addresses[contractName] = testUSDC.address; - contractName = CORE_CONTRACTS.FeesPlug; + contractName = Contracts.FeesPlug; const feesPlug: Contract = await getOrDeploy( contractName, contractName, - `contracts/protocol/payload-delivery/${contractName}.sol`, + `contracts/evmx/plugs/${contractName}.sol`, [socket.address, socketOwner], deployUtils ); deployUtils.addresses[contractName] = feesPlug.address; - await whitelistToken(feesPlug, testUSDC.address, deployUtils.signer); - - contractName = CORE_CONTRACTS.ContractFactoryPlug; + contractName = Contracts.ContractFactoryPlug; const contractFactoryPlug: Contract = await getOrDeploy( contractName, contractName, - `contracts/protocol/payload-delivery/${contractName}.sol`, + `contracts/evmx/plugs/${contractName}.sol`, [socket.address, socketOwner], deployUtils ); @@ -456,50 +383,6 @@ const deploySocketContracts = async () => { } }; -async function whitelistToken( - feesPlug: Contract, - tokenAddress: string, - signer: Signer -) { - const isWhitelisted = await feesPlug - .connect(signer) - .whitelistedTokens(tokenAddress); - if (!isWhitelisted) { - const tx = await feesPlug.connect(signer).whitelistToken(tokenAddress); - console.log( - `Whitelisting token ${tokenAddress} for ${feesPlug.address}`, - tx.hash - ); - await tx.wait(); - } -} - -async function updateContractSettings( - contract: Contract, - getterMethod: string, - setterMethod: string, - requiredValue: string | BigNumber, - signer: Signer -) { - const currentValue = await contract.connect(signer)[getterMethod](); - - if ( - (typeof currentValue === "string" && - currentValue.toLowerCase() !== String(requiredValue).toLowerCase()) || - (BigNumber.isBigNumber(currentValue) && - currentValue.toString() !== requiredValue.toString()) - ) { - console.log({ - setterMethod, - current: currentValue, - required: requiredValue, - }); - const tx = await contract.connect(signer)[setterMethod](requiredValue); - console.log(`Setting ${getterMethod} for ${contract.address} to`, tx.hash); - await tx.wait(); - } -} - /** * @notice Deploys a contract implementation and its transparent proxy, then initializes it * @param contractName The name of the contract to deploy diff --git a/hardhat-scripts/deploy/2.roles.ts b/hardhat-scripts/deploy/2.roles.ts index d313e104..a13706c0 100644 --- a/hardhat-scripts/deploy/2.roles.ts +++ b/hardhat-scripts/deploy/2.roles.ts @@ -3,11 +3,7 @@ dotenvConfig(); import { Wallet } from "ethers"; import { chains, EVMX_CHAIN_ID, mode, watcher, transmitter } from "../config"; -import { - CORE_CONTRACTS, - DeploymentAddresses, - EVMxCoreContracts, -} from "../constants"; +import { DeploymentAddresses } from "../constants"; import { getAddresses, getInstance, @@ -15,7 +11,7 @@ import { getRoleHash, overrides, } from "../utils"; -import { ChainAddressesObj, ChainSlug } from "../../src"; +import { ChainAddressesObj, ChainSlug, Contracts } from "../../src"; import { ROLES } from "../constants/roles"; import { getWatcherSigner, getSocketSigner } from "../utils/sign"; export const REQUIRED_ROLES = { @@ -30,7 +26,7 @@ export const REQUIRED_ROLES = { }; async function setRoleForContract( - contractName: CORE_CONTRACTS | EVMxCoreContracts, + contractName: Contracts, contractAddress: string | number, targetAddress: string, roleName: string, @@ -86,13 +82,13 @@ async function setRolesForOnChain( for (const roleName of roles) { const targetAddress = - contractName === CORE_CONTRACTS.FastSwitchboard && + contractName === Contracts.FastSwitchboard && roleName === ROLES.WATCHER_ROLE ? watcher : signer.address; await setRoleForContract( - contractName as CORE_CONTRACTS, + contractName as Contracts, contractAddress, targetAddress, roleName, @@ -108,17 +104,26 @@ async function setRolesForEVMx(addresses: DeploymentAddresses) { {}) as ChainAddressesObj; const signer = await getSigner(EVMX_CHAIN_ID, true); - const contractAddress = chainAddresses[EVMxCoreContracts.Watcher]; + const contractAddress = chainAddresses[Contracts.Watcher]; if (!contractAddress) return; await setRoleForContract( - EVMxCoreContracts.AuctionManager, - chainAddresses[EVMxCoreContracts.AuctionManager], + Contracts.AuctionManager, + chainAddresses[Contracts.AuctionManager], transmitter, ROLES.TRANSMITTER_ROLE, signer, EVMX_CHAIN_ID ); + + await setRoleForContract( + Contracts.FeesPool, + chainAddresses[Contracts.FeesPool], + chainAddresses[Contracts.FeesManager], + ROLES.FEE_MANAGER_ROLE, + signer, + EVMX_CHAIN_ID + ); } export const main = async () => { diff --git a/hardhat-scripts/deploy/3.configureChains.ts b/hardhat-scripts/deploy/3.configureChains.ts new file mode 100644 index 00000000..7c090c45 --- /dev/null +++ b/hardhat-scripts/deploy/3.configureChains.ts @@ -0,0 +1,182 @@ +import { config as dotenvConfig } from "dotenv"; +dotenvConfig(); + +import { Contract, Signer, Wallet } from "ethers"; +import { ChainAddressesObj, ChainSlug, Contracts } from "../../src"; +import { chains, EVMX_CHAIN_ID, MAX_MSG_VALUE_LIMIT, mode } from "../config"; +import { DeploymentAddresses, FAST_SWITCHBOARD_TYPE } from "../constants"; +import { + getAddresses, + getInstance, + getSocketSigner, + getWatcherSigner, + updateContractSettings, +} from "../utils"; + +export const main = async () => { + let addresses: DeploymentAddresses; + try { + console.log("Configuring chain contracts"); + addresses = getAddresses(mode) as unknown as DeploymentAddresses; + await configureChains(addresses); + } catch (error) { + console.log("Error:", error); + } +}; + +export const configureChains = async (addresses: DeploymentAddresses) => { + for (const chain of chains) { + let chainAddresses: ChainAddressesObj = addresses[chain] + ? (addresses[chain] as ChainAddressesObj) + : ({} as ChainAddressesObj); + + const signer: Wallet = getSocketSigner(chain as ChainSlug); + + const socketContract = ( + await getInstance(Contracts.Socket, chainAddresses[Contracts.Socket]) + ).connect(signer); + + await registerSb( + chainAddresses[Contracts.FastSwitchboard], + signer, + socketContract + ); + + await whitelistToken( + chainAddresses[Contracts.FeesPlug], + chainAddresses[Contracts.TestUSDC], + signer + ); + await setMaxMsgValueLimit(chain); + + await setOnchainContracts(chain, addresses); + } +}; + +export const setMaxMsgValueLimit = async (chain: number) => { + console.log("Setting max msg value limit"); + const signer: Wallet = getWatcherSigner(); + await updateContractSettings( + EVMX_CHAIN_ID, + Contracts.WritePrecompile, + "chainMaxMsgValueLimit", + [chain], + MAX_MSG_VALUE_LIMIT, + "updateChainMaxMsgValueLimits", + [chain, MAX_MSG_VALUE_LIMIT], + signer + ); +}; + +async function setOnchainContracts( + chain: number, + addresses: DeploymentAddresses +) { + console.log("Setting onchain contracts"); + const signer: Wallet = getWatcherSigner(); + const chainAddresses = addresses[chain] as ChainAddressesObj; + + await updateContractSettings( + EVMX_CHAIN_ID, + Contracts.Configurations, + "switchboards", + [chain, FAST_SWITCHBOARD_TYPE], + chainAddresses[Contracts.FastSwitchboard], + "setSwitchboard", + [chain, FAST_SWITCHBOARD_TYPE, chainAddresses[Contracts.FastSwitchboard]], + signer + ); + await updateContractSettings( + EVMX_CHAIN_ID, + Contracts.Configurations, + "sockets", + [chain], + chainAddresses[Contracts.Socket], + "setSocket", + [chain, chainAddresses[Contracts.Socket]], + signer + ); + + await updateContractSettings( + EVMX_CHAIN_ID, + Contracts.FeesManager, + "feesPlugs", + [chain], + chainAddresses[Contracts.FeesPlug], + "setFeesPlug", + [chain, chainAddresses[Contracts.FeesPlug]], + signer + ); + + await updateContractSettings( + EVMX_CHAIN_ID, + Contracts.WritePrecompile, + "contractFactoryPlugs", + [chain], + chainAddresses[Contracts.ContractFactoryPlug], + "setContractFactoryPlugs", + [chain, chainAddresses[Contracts.ContractFactoryPlug]], + signer + ); +} + +const registerSb = async ( + sbAddress: string, + signer: Wallet, + socket: Contract +) => { + try { + console.log("Registering switchboard"); + // used fast switchboard here as all have same function signature + const switchboard = ( + await getInstance(Contracts.FastSwitchboard, sbAddress) + ).connect(signer); + + // send overrides while reading capacitor to avoid errors on mantle chain + // some chains give balance error if gas price is used with from address as zero + // therefore override from address as well + let sb = await socket.isValidSwitchboard(sbAddress, { + from: signer.address, + }); + + if (Number(sb) == 0) { + const registerTx = await switchboard.registerSwitchboard(); + console.log(`Registering Switchboard ${sbAddress}: ${registerTx.hash}`); + await registerTx.wait(); + } + } catch (error) { + throw error; + } +}; + +export const whitelistToken = async ( + feesPlugAddress: string, + tokenAddress: string, + signer: Signer +) => { + console.log("Whitelisting token"); + const feesPlugContract = await getInstance( + Contracts.FeesPlug, + feesPlugAddress + ); + const isWhitelisted = await feesPlugContract + .connect(signer) + .whitelistedTokens(tokenAddress); + if (!isWhitelisted) { + const tx = await feesPlugContract + .connect(signer) + .whitelistToken(tokenAddress); + console.log( + `Whitelisting token ${tokenAddress} for ${feesPlugContract.address}`, + tx.hash + ); + await tx.wait(); + } +}; + +main() + .then(() => process.exit(0)) + .catch((error: Error) => { + console.error(error); + process.exit(1); + }); diff --git a/hardhat-scripts/deploy/3.upgradeManagers.ts b/hardhat-scripts/deploy/3.upgradeManagers.ts deleted file mode 100644 index 92c24b1e..00000000 --- a/hardhat-scripts/deploy/3.upgradeManagers.ts +++ /dev/null @@ -1,143 +0,0 @@ -import { ChainAddressesObj, ChainSlug, EVMxAddressesObj } from "../../src"; - -import { config as dotenvConfig } from "dotenv"; -dotenvConfig(); - -import { Wallet } from "ethers"; -import { chains, EVMX_CHAIN_ID, mode } from "../config"; -import { - CORE_CONTRACTS, - DeploymentAddresses, - EVMxCoreContracts, - FAST_SWITCHBOARD_TYPE, -} from "../constants"; -import { - getAddresses, - getInstance, - getSocketSigner, - getWatcherSigner, - storeAddresses, -} from "../utils"; - -export const main = async () => { - let addresses: DeploymentAddresses; - try { - console.log("Upgrading Managers"); - addresses = getAddresses(mode) as unknown as DeploymentAddresses; - - for (const chain of chains) { - let chainAddresses: ChainAddressesObj = addresses[chain] - ? (addresses[chain] as ChainAddressesObj) - : ({} as ChainAddressesObj); - - const signer: Wallet = getSocketSigner(chain as ChainSlug); - - const socketContract = ( - await getInstance( - CORE_CONTRACTS.Socket, - chainAddresses[CORE_CONTRACTS.Socket] - ) - ).connect(signer); - - await registerSb( - chainAddresses[CORE_CONTRACTS.FastSwitchboard], - signer, - socketContract - ); - - await setOnchainContracts(chain, addresses); - - await storeAddresses(chainAddresses, chain, mode); - } - } catch (error) { - console.log("Error:", error); - } -}; - -async function setOnchainContracts(chain: number, addresses) { - const signer: Wallet = getWatcherSigner(); - const EVMxAddresses = addresses[EVMX_CHAIN_ID] as EVMxAddressesObj; - const chainAddresses = addresses[chain] as ChainAddressesObj; - const watcherPrecompileConfig = ( - await getInstance( - EVMxCoreContracts.Configurations, - EVMxAddresses[EVMxCoreContracts.Configurations] - ) - ).connect(signer); - - const sbAddress = chainAddresses[CORE_CONTRACTS.FastSwitchboard]; - const socketAddress = chainAddresses[CORE_CONTRACTS.Socket]; - const contractFactoryPlugAddress = - chainAddresses[CORE_CONTRACTS.ContractFactoryPlug]; - const feesPlugAddress = chainAddresses[CORE_CONTRACTS.FeesPlug]; - - const currentSbAddress = await watcherPrecompileConfig.switchboards( - chain, - FAST_SWITCHBOARD_TYPE - ); - const currentSocket = await watcherPrecompileConfig.sockets(chain); - const currentContractFactoryPlug = - await watcherPrecompileConfig.contractFactoryPlug(chain); - const currentFeesPlug = await watcherPrecompileConfig.feesPlug(chain); - - console.log("Setting onchain contracts for", chain); - if ( - currentSocket.toLowerCase() !== socketAddress.toLowerCase() || - currentContractFactoryPlug.toLowerCase() !== - contractFactoryPlugAddress.toLowerCase() || - currentFeesPlug.toLowerCase() !== feesPlugAddress.toLowerCase() - ) { - const tx = await watcherPrecompileConfig - .connect(signer) - .setOnChainContracts( - chain, - socketAddress, - contractFactoryPlugAddress, - feesPlugAddress - ); - - console.log(`Setting onchain contracts for ${chain}, txHash: `, tx.hash); - await tx.wait(); - } - - console.log("Setting switchboard for", chain); - if (currentSbAddress.toLowerCase() !== sbAddress.toLowerCase()) { - const tx = await watcherPrecompileConfig - .connect(signer) - .setSwitchboard(chain, FAST_SWITCHBOARD_TYPE, sbAddress); - - console.log(`Setting switchboard for ${chain}, txHash: `, tx.hash); - await tx.wait(); - } -} - -const registerSb = async (sbAddress, signer, socket) => { - try { - // used fast switchboard here as all have same function signature - const switchboard = ( - await getInstance(CORE_CONTRACTS.FastSwitchboard, sbAddress) - ).connect(signer); - - // send overrides while reading capacitor to avoid errors on mantle chain - // some chains give balance error if gas price is used with from address as zero - // therefore override from address as well - let sb = await socket.isValidSwitchboard(sbAddress, { - from: signer.address, - }); - - if (Number(sb) == 0) { - const registerTx = await switchboard.registerSwitchboard(); - console.log(`Registering Switchboard ${sbAddress}: ${registerTx.hash}`); - await registerTx.wait(); - } - } catch (error) { - throw error; - } -}; - -main() - .then(() => process.exit(0)) - .catch((error: Error) => { - console.error(error); - process.exit(1); - }); diff --git a/hardhat-scripts/deploy/4.configureEVMx.ts b/hardhat-scripts/deploy/4.configureEVMx.ts new file mode 100644 index 00000000..e12bd950 --- /dev/null +++ b/hardhat-scripts/deploy/4.configureEVMx.ts @@ -0,0 +1,162 @@ +import { config as dotenvConfig } from "dotenv"; +dotenvConfig(); + +import { + ChainAddressesObj, + ChainSlug, + Contracts, + EVMxAddressesObj, + READ, + SCHEDULE, + WRITE, +} from "../../src"; +import { Contract, Wallet } from "ethers"; +import { chains, EVMX_CHAIN_ID, mode } from "../config"; +import { DeploymentAddresses, FAST_SWITCHBOARD_TYPE } from "../constants"; +import { + getAddresses, + getInstance, + getSocketSigner, + getWatcherSigner, + updateContractSettings, +} from "../utils"; + +export const main = async () => { + let addresses: DeploymentAddresses; + try { + console.log("Configuring EVMx contracts"); + addresses = getAddresses(mode) as unknown as DeploymentAddresses; + const evmxAddresses = addresses[EVMX_CHAIN_ID] as EVMxAddressesObj; + + await configureEVMx(evmxAddresses); + } catch (error) { + console.log("Error:", error); + } +}; + +export const configureEVMx = async (evmxAddresses: EVMxAddressesObj) => { + const signer: Wallet = getWatcherSigner(); + + await updateContractSettings( + EVMX_CHAIN_ID, + Contracts.AddressResolver, + "asyncDeployer__", + [], + evmxAddresses[Contracts.AsyncDeployer], + "setAsyncDeployer", + [evmxAddresses[Contracts.AsyncDeployer]], + signer + ); + + await updateContractSettings( + EVMX_CHAIN_ID, + Contracts.AddressResolver, + "feesManager__", + [], + evmxAddresses[Contracts.FeesManager], + "setFeesManager", + [evmxAddresses[Contracts.FeesManager]], + signer + ); + + await updateContractSettings( + EVMX_CHAIN_ID, + Contracts.AddressResolver, + "defaultAuctionManager", + [], + evmxAddresses[Contracts.AuctionManager], + "setDefaultAuctionManager", + [evmxAddresses[Contracts.AuctionManager]], + signer + ); + + await updateContractSettings( + EVMX_CHAIN_ID, + Contracts.AddressResolver, + "watcher__", + [], + evmxAddresses[Contracts.Watcher], + "setWatcher", + [evmxAddresses[Contracts.Watcher]], + signer + ); + + await updateContractSettings( + EVMX_CHAIN_ID, + Contracts.AddressResolver, + "deployForwarder__", + [], + evmxAddresses[Contracts.DeployForwarder], + "setDeployForwarder", + [evmxAddresses[Contracts.DeployForwarder]], + signer + ); + + await updateContractSettings( + EVMX_CHAIN_ID, + Contracts.RequestHandler, + "precompiles", + [READ], + evmxAddresses[Contracts.ReadPrecompile], + "setPrecompile", + [READ, evmxAddresses[Contracts.ReadPrecompile]], + signer + ); + + await updateContractSettings( + EVMX_CHAIN_ID, + Contracts.RequestHandler, + "precompiles", + [WRITE], + evmxAddresses[Contracts.WritePrecompile], + "setPrecompile", + [WRITE, evmxAddresses[Contracts.WritePrecompile]], + signer + ); + + await updateContractSettings( + EVMX_CHAIN_ID, + Contracts.RequestHandler, + "precompiles", + [SCHEDULE], + evmxAddresses[Contracts.SchedulePrecompile], + "setPrecompile", + [SCHEDULE, evmxAddresses[Contracts.SchedulePrecompile]], + signer + ); + + await setWatcherCoreContracts(evmxAddresses); +}; + +export const setWatcherCoreContracts = async ( + evmxAddresses: EVMxAddressesObj +) => { + const watcherContract = ( + await getInstance(Contracts.Watcher, evmxAddresses[Contracts.Watcher]) + ).connect(getWatcherSigner()); + const requestHandlerSet = await watcherContract.requestHandler__(); + const PromiseResolverSet = await watcherContract.promiseResolver__(); + const ConfigurationsSet = await watcherContract.configurations__(); + + if ( + requestHandlerSet !== evmxAddresses[Contracts.RequestHandler] || + PromiseResolverSet !== evmxAddresses[Contracts.PromiseResolver] || + ConfigurationsSet !== evmxAddresses[Contracts.Configurations] + ) { + console.log("Setting watcher core contracts"); + const tx = await watcherContract.setCoreContracts( + evmxAddresses[Contracts.RequestHandler], + evmxAddresses[Contracts.Configurations], + evmxAddresses[Contracts.PromiseResolver] + ); + console.log("Watcher core contracts set tx: ", tx.hash); + await tx.wait(); + } +}; + +main() + .then(() => process.exit(0)) + .catch((error: Error) => { + console.error(error); + process.exit(1); + }); diff --git a/hardhat-scripts/deploy/5.fundTransfers.ts b/hardhat-scripts/deploy/5.fundTransfers.ts new file mode 100644 index 00000000..584e2ef2 --- /dev/null +++ b/hardhat-scripts/deploy/5.fundTransfers.ts @@ -0,0 +1,47 @@ +import { config } from "dotenv"; +import { Signer } from "ethers"; +import { Contracts } from "../../src"; +import { + EVMX_CHAIN_ID, + FEES_POOL_FUNDING_AMOUNT_THRESHOLD, + mode, +} from "../config/config"; +import { getAddresses, getWatcherSigner } from "../utils"; +config(); + +export const fundFeesPool = async (watcherSigner: Signer) => { + const addresses = getAddresses(mode); + const feesPoolAddress = addresses[EVMX_CHAIN_ID][Contracts.FeesPool]; + const feesPoolBalance = await watcherSigner.provider!.getBalance( + feesPoolAddress + ); + console.log({ + feesPoolAddress, + feesPoolBalance, + FEES_POOL_FUNDING_AMOUNT_THRESHOLD, + }); + if (feesPoolBalance.gte(FEES_POOL_FUNDING_AMOUNT_THRESHOLD)) { + console.log( + `Fees pool ${feesPoolAddress} already has sufficient balance, skipping funding` + ); + return; + } + + const tx = await watcherSigner.sendTransaction({ + to: feesPoolAddress, + value: FEES_POOL_FUNDING_AMOUNT_THRESHOLD, + }); + console.log( + `Funding fees pool ${feesPoolAddress} with ${FEES_POOL_FUNDING_AMOUNT_THRESHOLD} ETH, txHash: `, + tx.hash + ); + await tx.wait(); +}; + +const main = async () => { + console.log("Fund transfers"); + const watcherSigner = getWatcherSigner(); + await fundFeesPool(watcherSigner); +}; + +main(); diff --git a/hardhat-scripts/deploy/4.connect.ts b/hardhat-scripts/deploy/6.connect.ts similarity index 77% rename from hardhat-scripts/deploy/4.connect.ts rename to hardhat-scripts/deploy/6.connect.ts index 59efc2a6..8e96da51 100644 --- a/hardhat-scripts/deploy/4.connect.ts +++ b/hardhat-scripts/deploy/6.connect.ts @@ -1,25 +1,39 @@ import { constants, Contract, ethers, Wallet } from "ethers"; -import { ChainAddressesObj, ChainSlug } from "../../src"; +import { ChainAddressesObj, ChainSlug, Contracts } from "../../src"; import { chains, EVMX_CHAIN_ID, mode } from "../config"; -import { - CORE_CONTRACTS, - DeploymentAddresses, - EVMxCoreContracts, -} from "../constants"; +import { DeploymentAddresses } from "../constants"; import { getAddresses, getInstance, getSocketSigner, overrides, } from "../utils"; -import { getWatcherSigner, signWatcherMessage } from "../utils/sign"; -const plugs = [CORE_CONTRACTS.ContractFactoryPlug, CORE_CONTRACTS.FeesPlug]; +import { + getWatcherSigner, + sendWatcherMultiCallWithNonce, + signWatcherMessage, +} from "../utils/sign"; + +const plugs = [Contracts.ContractFactoryPlug, Contracts.FeesPlug]; export type AppGatewayConfig = { + plugConfig: { + appGatewayId: string; + switchboard: string; + }; plug: string; - appGatewayId: string; - switchboard: string; chainSlug: number; }; + +// Main function to connect plugs on all chains +export const main = async () => { + try { + await connectPlugsOnSocket(); + await updateConfigEVMx(); + } catch (error) { + console.log("Error while sending transaction", error); + } +}; + // Maps plug contracts to their corresponding app gateways export const getAppGatewayId = ( plug: string, @@ -27,12 +41,12 @@ export const getAppGatewayId = ( ) => { let address: string = ""; switch (plug) { - case CORE_CONTRACTS.ContractFactoryPlug: - address = addresses?.[EVMX_CHAIN_ID]?.[EVMxCoreContracts.DeliveryHelper]; - if (!address) throw new Error(`DeliveryHelper not found on EVMX`); + case Contracts.ContractFactoryPlug: + address = addresses?.[EVMX_CHAIN_ID]?.[Contracts.WritePrecompile]; + if (!address) throw new Error(`WritePrecompile not found on EVMX`); return ethers.utils.hexZeroPad(address, 32); - case CORE_CONTRACTS.FeesPlug: - address = addresses?.[EVMX_CHAIN_ID]?.[EVMxCoreContracts.FeesManager]; + case Contracts.FeesPlug: + address = addresses?.[EVMX_CHAIN_ID]?.[Contracts.FeesManager]; if (!address) throw new Error(`FeesManager not found on EVMX`); return ethers.utils.hexZeroPad(address, 32); default: @@ -95,11 +109,11 @@ async function connectPlug( socketSigner ); const socket = ( - await getInstance(CORE_CONTRACTS.Socket, addr[CORE_CONTRACTS.Socket]) + await getInstance(Contracts.Socket, addr[Contracts.Socket]) ).connect(socketSigner); // Get switchboard and app gateway addresses - const switchboard = addr[CORE_CONTRACTS.FastSwitchboard]; + const switchboard = addr[Contracts.FastSwitchboard]; checkIfAddressExists(switchboard, "Switchboard"); const appGatewayId = getAppGatewayId(plugContract, addresses); checkIfAppGatewayIdExists(appGatewayId, "AppGatewayId"); @@ -163,10 +177,10 @@ export const updateConfigEVMx = async () => { // Set up Watcher contract const signer = getWatcherSigner(); const EVMxAddresses = addresses[EVMX_CHAIN_ID]!; - const watcherPrecompileConfig = ( + const configurationsContract = ( await getInstance( - EVMxCoreContracts.Configurations, - EVMxAddresses[EVMxCoreContracts.Configurations] + Contracts.Configurations, + EVMxAddresses[Contracts.Configurations] ) ).connect(signer); @@ -178,13 +192,13 @@ export const updateConfigEVMx = async () => { for (const plugContract of plugs) { const appGatewayId = getAppGatewayId(plugContract, addresses); - const switchboard = addr[CORE_CONTRACTS.FastSwitchboard]; + const switchboard = addr[Contracts.FastSwitchboard]; checkIfAddressExists(switchboard, "Switchboard"); checkIfAppGatewayIdExists(appGatewayId, "AppGatewayId"); if ( await isConfigSetOnEVMx( - watcherPrecompileConfig, + configurationsContract, chain, addr[plugContract], appGatewayId, @@ -195,9 +209,11 @@ export const updateConfigEVMx = async () => { continue; } appConfigs.push({ + plugConfig: { + appGatewayId: appGatewayId, + switchboard: switchboard, + }, plug: addr[plugContract], - appGatewayId: appGatewayId, - switchboard: addr[CORE_CONTRACTS.FastSwitchboard], chainSlug: chain, }); } @@ -207,25 +223,13 @@ export const updateConfigEVMx = async () => { // Update configs if any changes needed if (appConfigs.length > 0) { console.log({ appConfigs }); - const encodedMessage = ethers.utils.defaultAbiCoder.encode( - [ - "bytes4", - "tuple(address plug,bytes32 appGatewayId,address switchboard,uint32 chainSlug)[]", - ], - [ - watcherPrecompileConfig.interface.getSighash("setAppGateways"), - appConfigs, - ] - ); - const { nonce, signature } = await signWatcherMessage( - encodedMessage, - watcherPrecompileConfig.address + const calldata = configurationsContract.interface.encodeFunctionData( + "setAppGatewayConfigs", + [appConfigs] ); - const tx = await watcherPrecompileConfig.setAppGateways( - appConfigs, - nonce, - signature, - { ...overrides(EVMX_CHAIN_ID) } + const tx = await sendWatcherMultiCallWithNonce( + configurationsContract.address, + calldata ); console.log(`Updating EVMx Config tx hash: ${tx.hash}`); await tx.wait(); @@ -235,16 +239,6 @@ export const updateConfigEVMx = async () => { } }; -// Main function to connect plugs on all chains -export const main = async () => { - try { - await connectPlugsOnSocket(); - await updateConfigEVMx(); - } catch (error) { - console.log("Error while sending transaction", error); - } -}; - main() .then(() => process.exit(0)) .catch((error: Error) => { diff --git a/hardhat-scripts/deploy/5.upload.ts b/hardhat-scripts/deploy/7.upload.ts similarity index 100% rename from hardhat-scripts/deploy/5.upload.ts rename to hardhat-scripts/deploy/7.upload.ts diff --git a/hardhat-scripts/deploy/6.setupEnv.ts b/hardhat-scripts/deploy/8.setupEnv.ts similarity index 68% rename from hardhat-scripts/deploy/6.setupEnv.ts rename to hardhat-scripts/deploy/8.setupEnv.ts index 02e27607..a47d36c0 100644 --- a/hardhat-scripts/deploy/6.setupEnv.ts +++ b/hardhat-scripts/deploy/8.setupEnv.ts @@ -1,4 +1,4 @@ -import { ChainSlug } from "../../src"; +import { ChainSlug, Contracts } from "../../src"; import fs from "fs"; import path from "path"; import { EVMX_CHAIN_ID, mode } from "../config/config"; @@ -20,28 +20,28 @@ const latestEVMxAddresses = latestAddresses[EVMX_CHAIN_ID]; // Create a new array to hold the updated lines const updatedLines = lines.map((line) => { if (line.startsWith("ADDRESS_RESOLVER=")) { - return `ADDRESS_RESOLVER=${latestEVMxAddresses["AddressResolver"]}`; - } else if (line.startsWith("WATCHER_PRECOMPILE=")) { - return `WATCHER_PRECOMPILE=${latestEVMxAddresses["Watcher"]}`; + return `ADDRESS_RESOLVER=${latestEVMxAddresses[Contracts.AddressResolver]}`; + } else if (line.startsWith("WATCHER=")) { + return `WATCHER=${latestEVMxAddresses[Contracts.Watcher]}`; } else if (line.startsWith("AUCTION_MANAGER=")) { - return `AUCTION_MANAGER=${latestEVMxAddresses["AuctionManager"]}`; + return `AUCTION_MANAGER=${latestEVMxAddresses[Contracts.AuctionManager]}`; } else if (line.startsWith("FEES_MANAGER=")) { - return `FEES_MANAGER=${latestEVMxAddresses["FeesManager"]}`; + return `FEES_MANAGER=${latestEVMxAddresses[Contracts.FeesManager]}`; } else if (line.startsWith("ARBITRUM_SOCKET=")) { return `ARBITRUM_SOCKET=${ - latestAddresses[ChainSlug.ARBITRUM_SEPOLIA]["Socket"] + latestAddresses[ChainSlug.ARBITRUM_SEPOLIA][Contracts.Socket] }`; } else if (line.startsWith("ARBITRUM_SWITCHBOARD=")) { return `ARBITRUM_SWITCHBOARD=${ - latestAddresses[ChainSlug.ARBITRUM_SEPOLIA]["FastSwitchboard"] + latestAddresses[ChainSlug.ARBITRUM_SEPOLIA][Contracts.FastSwitchboard] }`; } else if (line.startsWith("ARBITRUM_FEES_PLUG=")) { return `ARBITRUM_FEES_PLUG=${ - latestAddresses[ChainSlug.ARBITRUM_SEPOLIA]["FeesPlug"] + latestAddresses[ChainSlug.ARBITRUM_SEPOLIA][Contracts.FeesPlug] }`; } else if (line.startsWith("ARBITRUM_TEST_USDC=")) { return `ARBITRUM_TEST_USDC=${ - latestAddresses[ChainSlug.ARBITRUM_SEPOLIA]["TestUSDC"] + latestAddresses[ChainSlug.ARBITRUM_SEPOLIA][Contracts.TestUSDC] }`; } return line; // Return the line unchanged if it doesn't match any of the above diff --git a/hardhat-scripts/deploy/9.setupTransmitter.ts b/hardhat-scripts/deploy/9.setupTransmitter.ts new file mode 100644 index 00000000..279be8b1 --- /dev/null +++ b/hardhat-scripts/deploy/9.setupTransmitter.ts @@ -0,0 +1,110 @@ +import { Contract, Wallet } from "ethers"; +import { ChainSlug, Contracts, EVMxAddressesObj } from "../../src"; +import { + EVMX_CHAIN_ID, + mode, + TRANSMITTER_CREDIT_THRESHOLD, + TRANSMITTER_NATIVE_THRESHOLD, +} from "../config/config"; +import { getAddresses } from "../utils/address"; +import { getInstance } from "../utils/deployUtils"; +import { overrides } from "../utils/overrides"; +import { getTransmitterSigner, getWatcherSigner } from "../utils/sign"; +import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; + +let evmxAddresses: EVMxAddressesObj; +let feesManagerContract: Contract; +let transmitterSigner: SignerWithAddress | Wallet; +let transmitterAddress: string; + +export const main = async () => { + console.log("Setting up transmitter..."); + await init(); + await approveAuctionManager(); + await checkAndDepositCredits(); + + console.log("Transmitter setup complete!"); +}; + +export const init = async () => { + const addresses = getAddresses(mode); + evmxAddresses = addresses[EVMX_CHAIN_ID] as EVMxAddressesObj; + feesManagerContract = await getInstance( + Contracts.FeesManager, + evmxAddresses[Contracts.FeesManager] + ); + transmitterSigner = getTransmitterSigner(EVMX_CHAIN_ID as ChainSlug); + transmitterAddress = await transmitterSigner.getAddress(); +}; + +export const approveAuctionManager = async () => { + console.log("Approving auction manager"); + const auctionManagerAddress = evmxAddresses[Contracts.AuctionManager]; + const isAlreadyApproved = await feesManagerContract + .connect(transmitterSigner) + .isApproved(transmitterAddress, auctionManagerAddress); + + if (!isAlreadyApproved) { + console.log("Approving auction manager"); + const tx = await feesManagerContract + .connect(transmitterSigner) + .approveAppGateways( + [ + { + appGateway: auctionManagerAddress, + approval: true, + }, + ], + await overrides(EVMX_CHAIN_ID as ChainSlug) + ); + console.log("Auction manager approval tx hash:", tx.hash); + await tx.wait(); + console.log("Auction manager approved"); + } else { + console.log("Auction manager already approved"); + } +}; + +export const checkAndDepositCredits = async () => { + console.log("Checking and depositing credits"); + const credits = await feesManagerContract + .connect(transmitterSigner) + .getAvailableCredits(transmitterAddress); + + if (credits.lt(TRANSMITTER_CREDIT_THRESHOLD)) { + console.log("Depositing credits for transmitter..."); + const tx = await feesManagerContract + .connect(getWatcherSigner()) + .wrap(transmitterAddress, { + ...(await overrides(EVMX_CHAIN_ID as ChainSlug)), + value: TRANSMITTER_CREDIT_THRESHOLD, + }); + console.log("Credits wrap tx hash:", tx.hash); + await tx.wait(); + console.log("Credits wrapped"); + } +}; + +export const checkAndDepositNative = async () => { + console.log("Checking and depositing native"); + const nativeBalance = await transmitterSigner.provider!.getBalance( + transmitterAddress + ); + + if (nativeBalance.lt(TRANSMITTER_NATIVE_THRESHOLD)) { + console.log("Depositing native for transmitter..."); + const tx = await getWatcherSigner().sendTransaction({ + to: transmitterAddress, + value: TRANSMITTER_NATIVE_THRESHOLD, + ...(await overrides(EVMX_CHAIN_ID as ChainSlug)), + }); + console.log("Native deposit tx hash:", tx.hash); + await tx.wait(); + console.log("Native deposited"); + } +}; + +main().catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/hardhat-scripts/utils/deployUtils.ts b/hardhat-scripts/utils/deployUtils.ts index 62824dcf..0b6206a5 100644 --- a/hardhat-scripts/utils/deployUtils.ts +++ b/hardhat-scripts/utils/deployUtils.ts @@ -1,4 +1,4 @@ -import { Wallet, utils } from "ethers"; +import { BigNumber, Signer, Wallet, utils } from "ethers"; import { network, ethers, run } from "hardhat"; import { ContractFactory, Contract } from "ethers"; @@ -7,9 +7,10 @@ import path from "path"; import fs from "fs"; import { ChainAddressesObj, ChainSlug, DeploymentMode } from "../../src"; import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; -import { overrides } from "../utils"; +import { getAddresses, overrides } from "../utils"; import { VerifyArgs } from "../verify"; import { DeploymentAddresses } from "../constants"; +import { EVMX_CHAIN_ID, mode } from "../config"; export const deploymentsPath = path.join(__dirname, `/../../deployments/`); @@ -318,3 +319,42 @@ export function getChainSlugFromId(chainId: number) { // avoid conflict for now return parseInt(utils.id(chainId.toString()).substring(0, 10)); } + +export const updateContractSettings = async ( + chainSlug: number, + contractName: string, + getterMethod: string, + getterArgs: any[], + requiredValue: string | BigNumber, + setterMethod: string, + setterArgs: any[], + signer: SignerWithAddress | Wallet +) => { + const addresses = getAddresses(mode); + const contractAddress = addresses[chainSlug][contractName]; + const contractInstance = await getInstance(contractName, contractAddress); + const currentValue = await contractInstance + .connect(signer) + [getterMethod](...getterArgs); + + if ( + (typeof currentValue === "string" && + currentValue.toLowerCase() !== String(requiredValue).toLowerCase()) || + (BigNumber.isBigNumber(currentValue) && + currentValue.toString() !== requiredValue.toString()) + ) { + console.log({ + setterMethod, + current: currentValue, + required: requiredValue, + }); + const tx = await contractInstance + .connect(signer) + [setterMethod](...setterArgs); + console.log( + `Setting ${getterMethod} for ${contractInstance.address} to`, + tx.hash + ); + await tx.wait(); + } +}; diff --git a/hardhat-scripts/utils/overrides.ts b/hardhat-scripts/utils/overrides.ts index d4cfdafc..94a25c12 100644 --- a/hardhat-scripts/utils/overrides.ts +++ b/hardhat-scripts/utils/overrides.ts @@ -1,5 +1,5 @@ import { ChainSlug } from "../../src"; -import { BigNumber, BigNumberish, providers } from "ethers"; +import { BigNumber, BigNumberish, Contract, providers, Signer } from "ethers"; import { EVMX_CHAIN_ID } from "../config/config"; import { getProviderFromChainSlug } from "./networks"; diff --git a/hardhat-scripts/utils/sign.ts b/hardhat-scripts/utils/sign.ts index 5f7ed311..6f569ff0 100644 --- a/hardhat-scripts/utils/sign.ts +++ b/hardhat-scripts/utils/sign.ts @@ -1,23 +1,12 @@ import { ethers } from "ethers"; -import { ChainSlug } from "../../src"; -import { EVMX_CHAIN_ID } from "../config/config"; +import { ChainSlug, Contracts } from "../../src"; +import { EVMX_CHAIN_ID, mode } from "../config/config"; import { getProviderFromChainSlug } from "./networks"; - -export const signWatcherMessage = async ( - encodedMessage: string, - watcherContractAddress: string -) => { - const signatureNonce = Date.now(); - const signer = getWatcherSigner(); - const digest = ethers.utils.keccak256( - ethers.utils.defaultAbiCoder.encode( - ["address", "uint32", "uint256", "bytes"], - [watcherContractAddress, EVMX_CHAIN_ID, signatureNonce, encodedMessage] - ) - ); - const signature = await signer.signMessage(ethers.utils.arrayify(digest)); - return { nonce: signatureNonce, signature }; -}; +import { signWatcherMultiCallMessage } from "../../src/signer"; +import { getAddresses } from "./address"; +import { getOverrides, overrides } from "./overrides"; +import { getInstance } from "./deployUtils"; +import { WatcherMultiCallParams } from "../constants/types"; export const getWatcherSigner = () => { const provider = getProviderFromChainSlug(EVMX_CHAIN_ID as ChainSlug); @@ -28,3 +17,53 @@ export const getSocketSigner = (chainSlug: ChainSlug) => { const provider = getProviderFromChainSlug(chainSlug); return new ethers.Wallet(process.env.SOCKET_SIGNER_KEY as string, provider); }; + +export const getTransmitterSigner = (chainSlug: ChainSlug) => { + const provider = getProviderFromChainSlug(chainSlug); + return new ethers.Wallet( + process.env.TRANSMITTER_PRIVATE_KEY as string, + provider + ); +}; + +export const signWatcherMessage = async ( + targetContractAddress: string, + calldata: string +) => { + const addresses = getAddresses(mode); + return await signWatcherMultiCallMessage( + addresses[EVMX_CHAIN_ID][Contracts.Watcher], + EVMX_CHAIN_ID, + targetContractAddress, + calldata, + getWatcherSigner() + ); +}; + +export const sendWatcherMultiCallWithNonce = async ( + targetContractAddress: string, + calldata: string +) => { + const addresses = getAddresses(mode); + const watcherContract = ( + await getInstance( + Contracts.Watcher, + addresses[EVMX_CHAIN_ID][Contracts.Watcher] + ) + ).connect(getWatcherSigner()); + const { nonce, signature } = await signWatcherMessage( + targetContractAddress, + calldata + ); + + const params: WatcherMultiCallParams = { + contractAddress: targetContractAddress, + data: calldata, + nonce, + signature, + }; + // Call watcherMultiCall function with single call data + return await watcherContract.watcherMultiCall([params], { + ...(await overrides(EVMX_CHAIN_ID as ChainSlug)), + }); +}; diff --git a/lib.tsconfig.json b/lib.tsconfig.json index ba2f6b86..e0ae1226 100644 --- a/lib.tsconfig.json +++ b/lib.tsconfig.json @@ -10,6 +10,6 @@ "moduleResolution": "node", "allowJs": true }, - "include": ["src/**/*.ts", "lib/**/*.ts", "deployments/"], + "include": ["src/**/*.ts"], "exclude": ["node_modules", "dist"] } diff --git a/package.json b/package.json index 2df9297e..b009f0a3 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "publishConfig": { "access": "public" }, - "version": "1.1.17", + "version": "1.1.19", "description": "socket protocol", "scripts": { "build": "yarn abi && tsc --project lib.tsconfig.json", @@ -48,9 +48,8 @@ "prompts": "^2.4.2", "ts-node": "^10.7.0", "typechain": "^8.0.0", - "typescript": "^4.6.4" - }, - "dependencies": { + "typescript": "^4.6.4", "hardhat-contract-sizer": "^2.10.0" - } + }, + "dependencies": {} } diff --git a/script/helpers/DepositCredit.s.sol b/script/helpers/DepositCredit.s.sol index 4088d142..767d5aac 100644 --- a/script/helpers/DepositCredit.s.sol +++ b/script/helpers/DepositCredit.s.sol @@ -6,24 +6,30 @@ import {console} from "forge-std/console.sol"; import {FeesPlug} from "../../contracts/evmx/plugs/FeesPlug.sol"; import {TestUSDC} from "../../contracts/evmx/mocks/TestUSDC.sol"; -// source .env && forge script script/helpers/DepositCredit.s.sol --broadcast --skip-simulation +// source .env && forge script script/helpers/DepositCreditAndNative.s.sol --broadcast --skip-simulation contract DepositCredit is Script { function run() external { + uint256 feesAmount = 100000000; // 100 USDC vm.createSelectFork(vm.envString("ARBITRUM_SEPOLIA_RPC")); uint256 privateKey = vm.envUint("PRIVATE_KEY"); vm.startBroadcast(privateKey); FeesPlug feesPlug = FeesPlug(payable(vm.envAddress("ARBITRUM_FEES_PLUG"))); - TestUSDC token = TestUSDC(vm.envAddress("USDC")); address appGateway = vm.envAddress("APP_GATEWAY"); + TestUSDC testUSDCContract = TestUSDC(vm.envAddress("ARBITRUM_TEST_USDC")); + + // mint test USDC to sender + testUSDCContract.mint(vm.addr(privateKey), feesAmount); + // approve fees plug to spend test USDC + testUSDCContract.approve(address(feesPlug), feesAmount); address sender = vm.addr(privateKey); console.log("Sender address:", sender); - uint256 balance = sender.balance; + uint256 balance = testUSDCContract.balanceOf(sender); console.log("Sender balance in wei:", balance); console.log("App Gateway:", appGateway); console.log("Fees Plug:", address(feesPlug)); - uint feesAmount = 0.001 ether; - feesPlug.depositCredit(address(token), appGateway, feesAmount); + console.log("Fees Amount:", feesAmount); + feesPlug.depositCredit(address(testUSDCContract), appGateway, feesAmount); } } diff --git a/script/helpers/DepositCreditAndNative.s.sol b/script/helpers/DepositCreditAndNative.s.sol index a9eb6c2f..629a3998 100644 --- a/script/helpers/DepositCreditAndNative.s.sol +++ b/script/helpers/DepositCreditAndNative.s.sol @@ -9,10 +9,10 @@ import {TestUSDC} from "../../contracts/evmx/mocks/TestUSDC.sol"; // source .env && forge script script/helpers/DepositCreditAndNative.s.sol --broadcast --skip-simulation contract DepositCreditAndNative is Script { function run() external { - uint256 feesAmount = 100000000; + uint256 feesAmount = 100000000; // 100 USDC vm.createSelectFork(vm.envString("ARBITRUM_SEPOLIA_RPC")); - uint256 privateKey = vm.envUint("SPONSOR_KEY"); + uint256 privateKey = vm.envUint("PRIVATE_KEY"); vm.startBroadcast(privateKey); FeesPlug feesPlug = FeesPlug(payable(vm.envAddress("ARBITRUM_FEES_PLUG"))); address appGateway = vm.envAddress("APP_GATEWAY"); diff --git a/setupInfraContracts.sh b/setupInfraContracts.sh index 9d916681..989eabaa 100644 --- a/setupInfraContracts.sh +++ b/setupInfraContracts.sh @@ -4,10 +4,13 @@ else time npx hardhat run hardhat-scripts/deploy/1.deploy.ts fi time npx hardhat run hardhat-scripts/deploy/2.roles.ts --no-compile -time npx hardhat run hardhat-scripts/deploy/3.upgradeManagers.ts --no-compile -time npx hardhat run hardhat-scripts/deploy/4.connect.ts --no-compile -time npx ts-node hardhat-scripts/deploy/5.upload.ts --resolveJsonModule -time npx hardhat run hardhat-scripts/deploy/6.setupEnv.ts --no-compile +time npx hardhat run hardhat-scripts/deploy/3.configureChains.ts --no-compile +time npx hardhat run hardhat-scripts/deploy/4.configureEVMx.ts --no-compile +time npx hardhat run hardhat-scripts/deploy/5.fundTransfers.ts --no-compile +time npx hardhat run hardhat-scripts/deploy/6.connect.ts --no-compile +time npx hardhat run hardhat-scripts/deploy/7.upload.ts --no-compile +time npx hardhat run hardhat-scripts/deploy/8.setupEnv.ts --no-compile +time npx hardhat run hardhat-scripts/deploy/9.setupTransmitter.ts --no-compile time npx hardhat run hardhat-scripts/misc-scripts/errorCodes.ts --no-compile time npx hardhat run hardhat-scripts/misc-scripts/eventTopics.ts --no-compile time npx hardhat run hardhat-scripts/misc-scripts/functionSigs.ts --no-compile diff --git a/src/enums.ts b/src/enums.ts index 68f4e796..a725f8ae 100644 --- a/src/enums.ts +++ b/src/enums.ts @@ -51,6 +51,8 @@ export enum Contracts { ContractFactoryPlug = "ContractFactoryPlug", FastSwitchboard = "FastSwitchboard", SocketBatcher = "SocketBatcher", + SocketFeeManager = "SocketFeeManager", + TestUSDC = "TestUSDC", AddressResolver = "AddressResolver", Watcher = "Watcher", @@ -62,6 +64,9 @@ export enum Contracts { WritePrecompile = "WritePrecompile", ReadPrecompile = "ReadPrecompile", SchedulePrecompile = "SchedulePrecompile", + FeesPool = "FeesPool", + AsyncDeployer = "AsyncDeployer", + DeployForwarder = "DeployForwarder", } export enum CallTypeNames { diff --git a/src/index.ts b/src/index.ts index 9e934473..39a65132 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,3 +4,4 @@ export * from "./events"; export * from "./finality"; export * from "./types"; export * from "./constants"; +export * from "./signer"; diff --git a/src/signer.ts b/src/signer.ts new file mode 100644 index 00000000..9ec27359 --- /dev/null +++ b/src/signer.ts @@ -0,0 +1,25 @@ +import { ethers } from "ethers"; + +export const signWatcherMultiCallMessage = async ( + watcherContractAddress: string, + evmxChainId: number, + targetContractAddress: string, + calldata: string, + signer: ethers.Signer +) => { + const signatureNonce = Date.now(); + const digest = ethers.utils.keccak256( + ethers.utils.defaultAbiCoder.encode( + ["address", "uint32", "uint256", "address", "bytes"], + [ + watcherContractAddress, + evmxChainId, + signatureNonce, + targetContractAddress, + calldata, + ] + ) + ); + const signature = await signer.signMessage(ethers.utils.arrayify(digest)); + return { nonce: signatureNonce, signature }; +}; diff --git a/src/types.ts b/src/types.ts index b22f3711..d63a03db 100644 --- a/src/types.ts +++ b/src/types.ts @@ -36,6 +36,7 @@ export type EVMxAddressesObj = { SchedulePrecompile: string; AuctionManager: string; FeesManager: string; + FeesPool: string; startBlock: number; }; diff --git a/test/Storage.t.sol b/test/Storage.t.sol index 65e6c1a8..2aa7bee2 100644 --- a/test/Storage.t.sol +++ b/test/Storage.t.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; - // contract StorageTest is DeliveryHelperTest { // DeliveryHelper public deliveryHelperImpl; From 4459a175d59906a3bad228263fa4f87c38f43f15 Mon Sep 17 00:00:00 2001 From: Akash Date: Fri, 30 May 2025 15:22:53 +0530 Subject: [PATCH 096/130] fix: deploy scripts --- Errors.md | 227 ++---- EventTopics.md | 350 ++++---- FunctionSignatures.md | 763 +++++++++--------- contracts/evmx/base/AppGatewayBase.sol | 3 +- hardhat-scripts/config/config.ts | 22 +- hardhat-scripts/constants/enums.ts | 21 - hardhat-scripts/constants/index.ts | 1 - hardhat-scripts/constants/roles.ts | 1 + hardhat-scripts/constants/types.ts | 7 + hardhat-scripts/deploy/1.deploy.ts | 379 +++------ hardhat-scripts/deploy/2.roles.ts | 29 +- hardhat-scripts/deploy/3.configureChains.ts | 182 +++++ hardhat-scripts/deploy/3.upgradeManagers.ts | 143 ---- hardhat-scripts/deploy/4.configureEVMx.ts | 162 ++++ hardhat-scripts/deploy/5.fundTransfers.ts | 47 ++ .../deploy/{4.connect.ts => 6.connect.ts} | 98 ++- .../deploy/{5.upload.ts => 7.upload.ts} | 0 .../deploy/{6.setupEnv.ts => 8.setupEnv.ts} | 20 +- hardhat-scripts/deploy/9.setupTransmitter.ts | 110 +++ hardhat-scripts/utils/deployUtils.ts | 44 +- hardhat-scripts/utils/overrides.ts | 2 +- hardhat-scripts/utils/sign.ts | 75 +- lib.tsconfig.json | 2 +- package.json | 9 +- script/helpers/DepositCredit.s.sol | 16 +- script/helpers/DepositCreditAndNative.s.sol | 4 +- setupInfraContracts.sh | 11 +- src/enums.ts | 5 + src/index.ts | 1 + src/signer.ts | 25 + src/types.ts | 1 + test/Storage.t.sol | 1 - 32 files changed, 1570 insertions(+), 1191 deletions(-) delete mode 100644 hardhat-scripts/constants/enums.ts create mode 100644 hardhat-scripts/deploy/3.configureChains.ts delete mode 100644 hardhat-scripts/deploy/3.upgradeManagers.ts create mode 100644 hardhat-scripts/deploy/4.configureEVMx.ts create mode 100644 hardhat-scripts/deploy/5.fundTransfers.ts rename hardhat-scripts/deploy/{4.connect.ts => 6.connect.ts} (77%) rename hardhat-scripts/deploy/{5.upload.ts => 7.upload.ts} (100%) rename hardhat-scripts/deploy/{6.setupEnv.ts => 8.setupEnv.ts} (68%) create mode 100644 hardhat-scripts/deploy/9.setupTransmitter.ts create mode 100644 src/signer.ts diff --git a/Errors.md b/Errors.md index e374a824..00d099e1 100644 --- a/Errors.md +++ b/Errors.md @@ -1,73 +1,29 @@ # Custom Error Codes -## base/PlugBase.sol - -| Error | Signature | -| ---------------------------- | ------------ | -| `SocketAlreadyInitialized()` | `0xc9500b00` | - -## interfaces/IWatcherPrecompile.sol - -| Error | Signature | -| ------------------------------------- | ------------ | -| `InvalidChainSlug()` | `0xbff6b106` | -| `InvalidConnection()` | `0x63228f29` | -| `InvalidTimeoutRequest()` | `0x600ca372` | -| `InvalidPayloadId()` | `0xfa0b8c86` | -| `InvalidCaller()` | `0x48f5c3ed` | -| `InvalidGateway()` | `0xfc9dfe85` | -| `InvalidSwitchboard()` | `0xf63c9e4d` | -| `RequestAlreadyCancelled()` | `0xc70f47d8` | -| `RequestCancelled()` | `0xe3cf2258` | -| `AlreadyStarted()` | `0x1fbde445` | -| `RequestNotProcessing()` | `0x07ba8aaa` | -| `InvalidLevelNumber()` | `0x5022f14b` | -| `DeadlineNotPassedForOnChainRevert()` | `0x7006aa10` | - -## protocol/AddressResolver.sol - -| Error | Signature | -| ---------------------------- | ------------ | -| `InvalidAppGateway(address)` | `0x0e66940d` | - -## protocol/AsyncPromise.sol +## evmx/fees/FeesPool.sol -| Error | Signature | -| ------------------------------- | ------------ | -| `PromiseAlreadyResolved()` | `0x56b63537` | -| `OnlyForwarderOrLocalInvoker()` | `0xa9fb0b28` | -| `PromiseAlreadySetUp()` | `0x927c53d5` | -| `PromiseRevertFailed()` | `0x0175b9de` | - -## protocol/payload-delivery/AuctionManager.sol +| Error | Signature | +| ------------------ | ------------ | +| `TransferFailed()` | `0x90b8ec18` | -| Error | Signature | -| ---------------------------- | ------------ | -| `InvalidBid()` | `0xc6388ef7` | -| `MaxReAuctionCountReached()` | `0xf2b4388c` | - -## protocol/payload-delivery/ContractFactoryPlug.sol +## evmx/helpers/AsyncPromise.sol | Error | Signature | | -------------------------- | ------------ | -| `DeploymentFailed()` | `0x30116425` | -| `ExecutionFailed()` | `0xacfdb444` | -| `information(bool,,bytes)` | `0x3a82a1f3` | +| `PromiseAlreadyResolved()` | `0x56b63537` | +| `OnlyInvoker()` | `0x74ed21f5` | +| `PromiseAlreadySetUp()` | `0x927c53d5` | +| `PromiseRevertFailed()` | `0x0175b9de` | -## protocol/payload-delivery/FeesManager.sol +## evmx/plugs/ContractFactoryPlug.sol | Error | Signature | | -------------------------------- | ------------ | -| `InsufficientCreditsAvailable()` | `0xe61dc0aa` | -| `NoFeesForTransmitter()` | `0x248bac55` | -| `NoCreditsBlocked()` | `0xada9eb4c` | -| `InvalidCaller()` | `0x48f5c3ed` | -| `InvalidUserSignature()` | `0xe3fb657c` | -| `AppGatewayNotWhitelisted()` | `0x84e5309f` | -| `InvalidAmount()` | `0x2c5211c6` | -| `InsufficientBalance()` | `0xf4d678b8` | +| `DeploymentFailed()` | `0x30116425` | +| `ExecutionFailed(bytes32,bytes)` | `0xd255d8a3` | +| `information(bool,,bytes)` | `0x3a82a1f3` | -## protocol/payload-delivery/FeesPlug.sol +## evmx/plugs/FeesPlug.sol | Error | Signature | | --------------------------------------------------- | ------------ | @@ -75,119 +31,110 @@ | `InvalidDepositAmount()` | `0xfe9ba5cd` | | `TokenNotWhitelisted(address)` | `0xea3bff2e` | -## protocol/payload-delivery/app-gateway/DeliveryUtils.sol - -| Error | Signature | -| ------------------------------------ | ------------ | -| `PayloadTooLarge()` | `0x492f620d` | -| `OnlyAppGateway()` | `0xfec944ea` | -| `WinningBidExists()` | `0xe8733654` | -| `InsufficientFees()` | `0x8d53e553` | -| `ReadOnlyRequests()` | `0x5f16b0e6` | -| `RequestPayloadCountLimitExceeded()` | `0xcbef144b` | -| `MaxMsgValueLimitExceeded()` | `0x97b4e8ce` | +## evmx/watcher/RequestHandler.sol -## protocol/payload-delivery/app-gateway/FeesHelpers.sol - -| Error | Signature | -| --------------------------------------------- | ------------ | -| `NewMaxFeesLowerThanCurrent(uint256,uint256)` | `0x1345dda1` | +| Error | Signature | +| ----------------------- | ------------ | +| `InsufficientMaxFees()` | `0x0e5bc492` | -## protocol/socket/Socket.sol +## protocol/Socket.sol | Error | Signature | | ----------------------------------------- | ------------ | | `PayloadAlreadyExecuted(ExecutionStatus)` | `0xf4c54edd` | | `VerificationFailed()` | `0x439cc0cd` | | `LowGasLimit()` | `0xd38edae0` | -| `InvalidSlug()` | `0x290a8315` | -| `DeadlinePassed()` | `0x70f65caa` | | `InsufficientMsgValue()` | `0x78f38f76` | -| `ReadOnlyCall()` | `0xcf8fd6f1` | -## protocol/socket/SocketConfig.sol +## protocol/SocketConfig.sol | Error | Signature | | ------------------------------- | ------------ | -| `InvalidConnection()` | `0x63228f29` | -| `InvalidSwitchboard()` | `0xf63c9e4d` | | `SwitchboardExists()` | `0x2dff8555` | | `SwitchboardExistsOrDisabled()` | `0x1c7d2487` | -## protocol/socket/SocketFeeManager.sol +## protocol/SocketFeeManager.sol | Error | Signature | | -------------------- | ------------ | | `InsufficientFees()` | `0x8d53e553` | | `FeeTooLow()` | `0x732f9413` | -## protocol/socket/switchboard/FastSwitchboard.sol +## protocol/SocketUtils.sol + +| Error | Signature | +| -------------------- | ------------ | +| `OnlyOffChain()` | `0x9cbfe066` | +| `SimulationFailed()` | `0x2fbab3ac` | + +## protocol/switchboard/FastSwitchboard.sol | Error | Signature | | ------------------- | ------------ | | `AlreadyAttested()` | `0x35d90805` | | `WatcherNotFound()` | `0xa278e4ad` | -## protocol/utils/AccessControl.sol +## utils/AccessControl.sol | Error | Signature | | ------------------- | ------------ | | `NoPermit(bytes32)` | `0x962f6333` | -## protocol/utils/AddressResolverUtil.sol +## utils/common/Errors.sol -| Error | Signature | -| ----------------------------------------- | ------------ | -| `OnlyPayloadDelivery()` | `0x7ccc3a43` | -| `OnlyWatcherPrecompile()` | `0x663a892a` | -| `OnlyWatcherPrecompileOrDeliveryHelper()` | `0xe93a2814` | - -## protocol/utils/common/Errors.sol - -| Error | Signature | -| ---------------------------- | ------------ | -| `NotSocket()` | `0xc59f8f7c` | -| `ZeroAddress()` | `0xd92e233d` | -| `TimeoutDelayTooLarge()` | `0xc10bfe64` | -| `TimeoutAlreadyResolved()` | `0x7dc8be06` | -| `ResolvingTimeoutTooEarly()` | `0x28fd4c50` | -| `LimitReached()` | `0x3dd19101` | -| `FeesAlreadyPaid()` | `0xd3b1ad69` | -| `NotAuctionManager()` | `0x87944c26` | -| `CallFailed()` | `0x3204506f` | -| `PlugNotFound()` | `0x5f1ac76a` | -| `InvalidAppGateway()` | `0x82ded261` | -| `AppGatewayAlreadyCalled()` | `0xb224683f` | -| `InvalidInboxCaller()` | `0x4f1aa61e` | -| `InvalidCallerTriggered()` | `0x3292d247` | -| `PromisesNotResolved()` | `0xb91dbe7d` | -| `InvalidPromise()` | `0x45f2d176` | -| `InvalidTransmitter()` | `0x58a70a0a` | -| `FeesNotSet()` | `0x2a831034` | -| `InvalidTokenAddress()` | `0x1eb00b06` | -| `InvalidWatcherSignature()` | `0x5029f14f` | -| `NonceUsed()` | `0x1f6d5aef` | -| `AuctionClosed()` | `0x36b6b46d` | -| `AuctionAlreadyStarted()` | `0x628e3883` | -| `BidExceedsMaxFees()` | `0x4c923f3c` | -| `LowerBidAlreadyExists()` | `0xaaa1f709` | -| `AsyncModifierNotUsed()` | `0xb9521e1a` | -| `InvalidIndex()` | `0x63df8171` | -| `RequestAlreadyExecuted()` | `0xd6f1f946` | -| `NoAsyncPromiseFound()` | `0xa2928f68` | -| `PromiseCallerMismatch()` | `0x2b87f115` | -| `RequestCountMismatch()` | `0x98bbcbff` | -| `DeliveryHelperNotSet()` | `0x07e6c946` | - -## protocol/watcherPrecompile/WatcherPrecompileConfig.sol - -| Error | Signature | -| ---------------------- | ------------ | -| `InvalidGateway()` | `0xfc9dfe85` | -| `InvalidSwitchboard()` | `0xf63c9e4d` | - -## protocol/watcherPrecompile/WatcherPrecompileLimits.sol - -| Error | Signature | -| ---------------------------- | ------------ | -| `WatcherFeesNotSet(bytes32)` | `0x1ce1de3f` | +| Error | Signature | +| --------------------------------------------- | ------------ | +| `ZeroAddress()` | `0xd92e233d` | +| `InvalidTransmitter()` | `0x58a70a0a` | +| `InvalidTokenAddress()` | `0x1eb00b06` | +| `InvalidSwitchboard()` | `0xf63c9e4d` | +| `SocketAlreadyInitialized()` | `0xc9500b00` | +| `NotSocket()` | `0xc59f8f7c` | +| `PlugNotFound()` | `0x5f1ac76a` | +| `ResolvingScheduleTooEarly()` | `0x207e8731` | +| `CallFailed()` | `0x3204506f` | +| `InvalidAppGateway()` | `0x82ded261` | +| `AppGatewayAlreadyCalled()` | `0xb224683f` | +| `InvalidCallerTriggered()` | `0x3292d247` | +| `InvalidPromise()` | `0x45f2d176` | +| `InvalidWatcherSignature()` | `0x5029f14f` | +| `NonceUsed()` | `0x1f6d5aef` | +| `AsyncModifierNotSet()` | `0xcae106f9` | +| `WatcherNotSet()` | `0x42d473a7` | +| `InvalidTarget()` | `0x82d5d76a` | +| `InvalidIndex()` | `0x63df8171` | +| `InvalidChainSlug()` | `0xbff6b106` | +| `InvalidPayloadSize()` | `0xfbdf7954` | +| `InvalidScheduleDelay()` | `0x9a993219` | +| `AuctionClosed()` | `0x36b6b46d` | +| `AuctionNotOpen()` | `0xf0460077` | +| `BidExceedsMaxFees()` | `0x4c923f3c` | +| `LowerBidAlreadyExists()` | `0xaaa1f709` | +| `RequestCountMismatch()` | `0x98bbcbff` | +| `InvalidAmount()` | `0x2c5211c6` | +| `InsufficientCreditsAvailable()` | `0xe61dc0aa` | +| `InsufficientBalance()` | `0xf4d678b8` | +| `InvalidCaller()` | `0x48f5c3ed` | +| `InvalidGateway()` | `0xfc9dfe85` | +| `RequestAlreadyCancelled()` | `0xc70f47d8` | +| `DeadlineNotPassedForOnChainRevert()` | `0x7006aa10` | +| `InvalidBid()` | `0xc6388ef7` | +| `MaxReAuctionCountReached()` | `0xf2b4388c` | +| `MaxMsgValueLimitExceeded()` | `0x97b4e8ce` | +| `OnlyWatcherAllowed()` | `0xdf7d227c` | +| `InvalidPrecompileData()` | `0x320062c0` | +| `InvalidCallType()` | `0x39d2eb55` | +| `NotRequestHandler()` | `0x8f8cba5b` | +| `NotInvoker()` | `0x8a6353d1` | +| `NotPromiseResolver()` | `0x86d876b2` | +| `RequestPayloadCountLimitExceeded()` | `0xcbef144b` | +| `InsufficientFees()` | `0x8d53e553` | +| `RequestAlreadySettled()` | `0x66fad465` | +| `NoWriteRequest()` | `0x9dcd3065` | +| `AlreadyAssigned()` | `0x9688dc51` | +| `OnlyAppGateway()` | `0xfec944ea` | +| `NewMaxFeesLowerThanCurrent(uint256,uint256)` | `0x1345dda1` | +| `InvalidContract()` | `0x6eefed20` | +| `InvalidData()` | `0x5cb045db` | +| `InvalidSignature()` | `0x8baa579f` | +| `DeadlinePassed()` | `0x70f65caa` | diff --git a/EventTopics.md b/EventTopics.md index cb976877..34f5e4bb 100644 --- a/EventTopics.md +++ b/EventTopics.md @@ -1,38 +1,114 @@ # Event Topics -## ProxyFactory +## AuctionManager -| Event | Arguments | Topic | -| -------------- | ----------------------------------------------------------- | -------------------------------------------------------------------- | -| `AdminChanged` | `(proxy: address, admin: address)` | `0x7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f` | -| `Deployed` | `(proxy: address, implementation: address, admin: address)` | `0xc95935a66d15e0da5e412aca0ad27ae891d20b2fb91cf3994b6a3bf2b8178082` | -| `Upgraded` | `(proxy: address, implementation: address)` | `0x5d611f318680d00598bb735d61bacf0c514c6b50e1e5ad30040a4df2b12791c7` | +| Event | Arguments | Topic | +| ---------------------------- | ------------------------------------------- | -------------------------------------------------------------------- | +| `AuctionEndDelaySecondsSet` | `(auctionEndDelaySeconds: uint256)` | `0xf38f0d9dc8459cf5426728c250d115196a4c065ebc1a6c29da24764a8c0da722` | +| `AuctionEnded` | `(requestCount: uint40, winningBid: tuple)` | `0xede4ec1efc469fac10dcb4930f70be4cd21f3700ed61c91967c19a7cd7c0d86e` | +| `AuctionRestarted` | `(requestCount: uint40)` | `0x071867b21946ec4655665f0d4515d3757a5a52f144c762ecfdfb11e1da542b82` | +| `AuctionStarted` | `(requestCount: uint40)` | `0xcd040613cf8ef0cfcaa3af0d711783e827a275fc647c116b74595bf17cb9364f` | +| `BidPlaced` | `(requestCount: uint40, bid: tuple)` | `0x7f79485e4c9aeea5d4899bc6f7c63b22ac1f4c01d2d28c801e94732fee657b5d` | +| `MaxReAuctionCountSet` | `(maxReAuctionCount: uint256)` | `0x2f6fadde7ab8ab83d21ab10c3bc09dde179f8696d47c4176581facf0c6f96bbf` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | +| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | -## TestUSDC +## Socket -| Event | Arguments | Topic | -| ---------- | ----------------------------------------------------- | -------------------------------------------------------------------- | -| `Approval` | `(owner: address, spender: address, amount: uint256)` | `0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925` | -| `Transfer` | `(from: address, to: address, amount: uint256)` | `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef` | +| Event | Arguments | Topic | +| ---------------------------- | -------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | +| `AppGatewayCallRequested` | `(triggerId: bytes32, appGatewayId: bytes32, switchboard: address, plug: address, overrides: bytes, payload: bytes)` | `0x5c88d65ab8ba22a57e582bd8ddfa9801cc0ca6be6cb3182baaedc705a612419e` | +| `ExecutionFailed` | `(payloadId: bytes32, exceededMaxCopy: bool, returnData: bytes)` | `0x385334bc68a32c4d164625189adc7633e6074eb1b837fb4d11d768245151e4ce` | +| `ExecutionSuccess` | `(payloadId: bytes32, exceededMaxCopy: bool, returnData: bytes)` | `0x324d63a433b21a12b90e79cd2ba736b2a5238be6165e03b750fa4a7d5193d5d9` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `PlugConnected` | `(plug: address, appGatewayId: bytes32, switchboard: address)` | `0x90c5924e27cfb6e3a688e729083681f30494ae2615ae14aac3bc807a0c436a88` | +| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | +| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | +| `SocketFeeManagerUpdated` | `(oldSocketFeeManager: address, newSocketFeeManager: address)` | `0xdcb02e10d5220346a4638aa2826eaab1897306623bc40a427049e4ebd12255b4` | +| `SwitchboardAdded` | `(switchboard: address)` | `0x1595852923edfbbf906f09fc8523e4cfb022a194773c4d1509446b614146ee88` | +| `SwitchboardDisabled` | `(switchboard: address)` | `0x1b4ee41596b4e754e5665f01ed6122b356f7b36ea0a02030804fac7fa0fdddfc` | +| `SwitchboardEnabled` | `(switchboard: address)` | `0x6909a9974e3eec619bc479ba882d30a5ef1219b72ab1ce6a354516e91be317b8` | + +## SocketBatcher + +| Event | Arguments | Topic | +| ---------------------------- | ---------------------------------------- | -------------------------------------------------------------------- | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | + +## SocketFeeManager + +| Event | Arguments | Topic | +| ---------------------------- | ---------------------------------------- | -------------------------------------------------------------------- | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | +| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | +| `SocketFeesUpdated` | `(oldFees: uint256, newFees: uint256)` | `0xcbd4d756fb6198bbcc2e4013cce929f504ad46e9d97c543ef9a8dfea3e407053` | + +## FeesManager + +| Event | Arguments | Topic | +| ----------------------------- | ------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | +| `CreditsBlocked` | `(requestCount: uint40, consumeFrom: address, amount: uint256)` | `0xf037c15aef41440aa823cf1fdeaea332105d8b23d52557f6670189b5d76f1eed` | +| `CreditsTransferred` | `(from: address, to: address, amount: uint256)` | `0xed198cadddd93e734cbf04cb1c3226d9bafaeb504cedbd8ee36b830b0cb9e7a5` | +| `CreditsUnblocked` | `(requestCount: uint40, consumeFrom: address)` | `0x45db29ef2701319155cac058aa2f56ce1f73e0e238161d3db9f8c9a47655210d` | +| `CreditsUnblockedAndAssigned` | `(requestCount: uint40, consumeFrom: address, transmitter: address, amount: uint256)` | `0x38fd327622576a468e1b2818b00f50c8854703633ef8e583e1f31662888ffac2` | +| `CreditsUnwrapped` | `(consumeFrom: address, amount: uint256)` | `0xdcc9473b722b4c953617ab373840b365298a520bc7f20ce94fa7314f4a857774` | +| `CreditsWrapped` | `(consumeFrom: address, amount: uint256)` | `0x40246503613721eb4acf4020c6c56b6a16e5d08713316db0bea5210e8819c592` | +| `Deposited` | `(chainSlug: uint32, token: address, depositTo: address, creditAmount: uint256, nativeAmount: uint256)` | `0x72aedd284699bbd7a987e6942b824cfd6c627e354cb5a0760ac5768acd473f4a` | +| `FeesPlugSet` | `(chainSlug: uint32, feesPlug: address)` | `0xa8c4be32b96cca895f1f0f4684e6b377b2c4513bc35eb57a13afb6b5efb2c0ce` | +| `FeesPoolSet` | `(feesPool: address)` | `0xd07af3fd70b48ab3c077a8d45c3a288498d905d0e3d1e65bc171f6c2e890d8ef` | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | + +## FeesPool + +| Event | Arguments | Topic | +| ---------------------------- | ----------------------------------------------- | -------------------------------------------------------------------- | +| `NativeDeposited` | `(from: address, amount: uint256)` | `0xb5d7700fb0cf415158b8db7cc7c39f0eab16a825c92e221404b4c8bb099b4bbb` | +| `NativeWithdrawn` | `(success: bool, to: address, amount: uint256)` | `0xa81f1c8490022ee829d2e1a231053f5dbecad46caee71f6ea38a9db663a3f12b` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | +| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | ## AddressResolver -| Event | Arguments | Topic | -| ------------------------------ | ----------------------------------------------------------- | -------------------------------------------------------------------- | -| `AddressSet` | `(name: bytes32, oldAddress: address, newAddress: address)` | `0x9ef0e8c8e52743bb38b83b17d9429141d494b8041ca6d616a6c77cebae9cd8b7` | -| `AsyncPromiseDeployed` | `(newAsyncPromise: address, salt: bytes32)` | `0xb6c5491cf83e09749b1a4dd6a9f07b0e925fcb0a915ac8c2b40e8ab28191c270` | -| `ContractsToGatewaysUpdated` | `(contractAddress_: address, appGateway_: address)` | `0xb870bb0c6b5ea24214ae6c653af6c2a8b6240d5838f82132703ee5c069b14b4c` | -| `DefaultAuctionManagerUpdated` | `(defaultAuctionManager_: address)` | `0x60f296739208a505ead7fb622df0f76b7791b824481b120a2300bdaf85e3e3d6` | -| `DeliveryHelperUpdated` | `(deliveryHelper_: address)` | `0xc792471d30bbabcf9dc9fdba5bfa74f8872ff3c28f6e65e122bdb82a71b83c1c` | -| `FeesManagerUpdated` | `(feesManager_: address)` | `0x94e67aa1341a65767dfde81e62fd265bfbade1f5744bfd3cd73f99a6eca0572a` | -| `ForwarderDeployed` | `(newForwarder: address, salt: bytes32)` | `0x4dbbecb9cf9c8b93da9743a2b48ea52efe68d69230ab1c1b711891d9d223b29f` | -| `ImplementationUpdated` | `(contractName: string, newImplementation: address)` | `0xa1e41aa2c2f3f20d9b63ac06b634d2788768d6034f3d9192cdf7d07374bb16f4` | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `PlugAdded` | `(appGateway: address, chainSlug: uint32, plug: address)` | `0x2cb8d865028f9abf3dc064724043264907615fadc8615a3699a85edb66472273` | -| `WatcherPrecompileUpdated` | `(watcherPrecompile_: address)` | `0xb00972c0b5c3d3d9ddc6d6a6db612abeb109653a3424d5d972510fa20bff4972` | +| Event | Arguments | Topic | +| ------------------------------ | --------------------------------------------------- | -------------------------------------------------------------------- | +| `AsyncDeployerUpdated` | `(asyncDeployer_: address)` | `0x4df9cdd01544e8f6b0326650bc0b55611f47ce5ba2faa522d21fb675e9fc1f73` | +| `ContractAddressUpdated` | `(contractId_: bytes32, contractAddress_: address)` | `0xdf5ec2c15e11ce657bb21bc09c0b5ba95e315b4dba9934c6e311f47559babf28` | +| `DefaultAuctionManagerUpdated` | `(defaultAuctionManager_: address)` | `0x60f296739208a505ead7fb622df0f76b7791b824481b120a2300bdaf85e3e3d6` | +| `DeployForwarderUpdated` | `(deployForwarder_: address)` | `0x237b9bc9fef7508a02ca9ccca81f6965e500064a58024cae1218035da865fd2b` | +| `FeesManagerUpdated` | `(feesManager_: address)` | `0x94e67aa1341a65767dfde81e62fd265bfbade1f5744bfd3cd73f99a6eca0572a` | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `WatcherUpdated` | `(watcher_: address)` | `0xc13081d38d92b454cdb6ca20bbc65c12fa43a7a14a1529204ced5b6350052bb0` | + +## AsyncDeployer + +| Event | Arguments | Topic | +| ---------------------------- | ---------------------------------------------------- | -------------------------------------------------------------------- | +| `AsyncPromiseDeployed` | `(newAsyncPromise: address, salt: bytes32)` | `0xb6c5491cf83e09749b1a4dd6a9f07b0e925fcb0a915ac8c2b40e8ab28191c270` | +| `ForwarderDeployed` | `(newForwarder: address, salt: bytes32)` | `0x4dbbecb9cf9c8b93da9743a2b48ea52efe68d69230ab1c1b711891d9d223b29f` | +| `ImplementationUpdated` | `(contractName: string, newImplementation: address)` | `0xa1e41aa2c2f3f20d9b63ac06b634d2788768d6034f3d9192cdf7d07374bb16f4` | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | ## AsyncPromise @@ -40,27 +116,31 @@ | ------------- | ------------------- | -------------------------------------------------------------------- | | `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +## DeployForwarder + +| Event | Arguments | Topic | +| ----- | --------- | ----- | + ## Forwarder | Event | Arguments | Topic | | ------------- | ------------------- | -------------------------------------------------------------------- | | `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -## AuctionManager +## ProxyFactory -| Event | Arguments | Topic | -| ---------------------------- | ------------------------------------------- | -------------------------------------------------------------------- | -| `AuctionEndDelaySecondsSet` | `(auctionEndDelaySeconds: uint256)` | `0xf38f0d9dc8459cf5426728c250d115196a4c065ebc1a6c29da24764a8c0da722` | -| `AuctionEnded` | `(requestCount: uint40, winningBid: tuple)` | `0xede4ec1efc469fac10dcb4930f70be4cd21f3700ed61c91967c19a7cd7c0d86e` | -| `AuctionRestarted` | `(requestCount: uint40)` | `0x071867b21946ec4655665f0d4515d3757a5a52f144c762ecfdfb11e1da542b82` | -| `AuctionStarted` | `(requestCount: uint40)` | `0xcd040613cf8ef0cfcaa3af0d711783e827a275fc647c116b74595bf17cb9364f` | -| `BidPlaced` | `(requestCount: uint40, bid: tuple)` | `0x7f79485e4c9aeea5d4899bc6f7c63b22ac1f4c01d2d28c801e94732fee657b5d` | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | -| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | +| Event | Arguments | Topic | +| -------------- | ----------------------------------------------------------- | -------------------------------------------------------------------- | +| `AdminChanged` | `(proxy: address, admin: address)` | `0x7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f` | +| `Deployed` | `(proxy: address, implementation: address, admin: address)` | `0xc95935a66d15e0da5e412aca0ad27ae891d20b2fb91cf3994b6a3bf2b8178082` | +| `Upgraded` | `(proxy: address, implementation: address)` | `0x5d611f318680d00598bb735d61bacf0c514c6b50e1e5ad30040a4df2b12791c7` | + +## TestUSDC + +| Event | Arguments | Topic | +| ---------- | ----------------------------------------------------- | -------------------------------------------------------------------- | +| `Approval` | `(owner: address, spender: address, amount: uint256)` | `0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925` | +| `Transfer` | `(from: address, to: address, amount: uint256)` | `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef` | ## ContractFactoryPlug @@ -74,24 +154,6 @@ | `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | | `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | -## FeesManager - -| Event | Arguments | Topic | -| ----------------------------------------------- | --------------------------------------------------------------------------- | -------------------------------------------------------------------- | -| `CreditsBlocked` | `(requestCount: uint40, consumeFrom: address, amount: uint256)` | `0xf037c15aef41440aa823cf1fdeaea332105d8b23d52557f6670189b5d76f1eed` | -| `CreditsDeposited` | `(chainSlug: uint32, appGateway: address, token: address, amount: uint256)` | `0x7254d040844de2dac4225a23f81bb54acb13d1eadb6e8b369dd251d36a9e8552` | -| `CreditsUnblocked` | `(requestCount: uint40, appGateway: address)` | `0x45db29ef2701319155cac058aa2f56ce1f73e0e238161d3db9f8c9a47655210d` | -| `CreditsUnblockedAndAssigned` | `(requestCount: uint40, transmitter: address, amount: uint256)` | `0x6f3d11270d1df9aff1aa04d1ea7797a3a572586a31437acc415ac853f625050c` | -| `CreditsUnwrapped` | `(consumeFrom: address, amount: uint256)` | `0xdcc9473b722b4c953617ab373840b365298a520bc7f20ce94fa7314f4a857774` | -| `CreditsWrapped` | `(consumeFrom: address, amount: uint256)` | `0x40246503613721eb4acf4020c6c56b6a16e5d08713316db0bea5210e8819c592` | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `InsufficientWatcherPrecompileCreditsAvailable` | `(chainSlug: uint32, token: address, consumeFrom: address)` | `0xd50bc02f94b9ef4a8aff7438da15a69e443956f56b6aa007cf2c584215e87493` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `TransmitterCreditsUpdated` | `(requestCount: uint40, transmitter: address, amount: uint256)` | `0x24790626bfbe84d1358ce3e8cb0ff6cfc9eb7ea16e597f43ab607107baf889e3` | -| `WatcherPrecompileCreditsAssigned` | `(amount: uint256, consumeFrom: address)` | `0x87eddb69736f41b812366535a59efc79b1997f2d237240d7176d210397012e1b` | - ## FeesPlug | Event | Arguments | Topic | @@ -107,85 +169,53 @@ | `TokenRemovedFromWhitelist` | `(token: address)` | `0xdd2e6d9f52cbe8f695939d018b7d4a216dc613a669876163ac548b916489d917` | | `TokenWhitelisted` | `(token: address)` | `0x6a65f90b1a644d2faac467a21e07e50e3f8fa5846e26231d30ae79a417d3d262` | -## Socket - -| Event | Arguments | Topic | -| ---------------------------- | -------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | -| `AppGatewayCallRequested` | `(triggerId: bytes32, appGatewayId: bytes32, switchboard: address, plug: address, overrides: bytes, payload: bytes)` | `0x5c88d65ab8ba22a57e582bd8ddfa9801cc0ca6be6cb3182baaedc705a612419e` | -| `ExecutionFailed` | `(payloadId: bytes32, exceededMaxCopy: bool, returnData: bytes)` | `0x385334bc68a32c4d164625189adc7633e6074eb1b837fb4d11d768245151e4ce` | -| `ExecutionSuccess` | `(payloadId: bytes32, exceededMaxCopy: bool, returnData: bytes)` | `0x324d63a433b21a12b90e79cd2ba736b2a5238be6165e03b750fa4a7d5193d5d9` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `PlugConnected` | `(plug: address, appGatewayId: bytes32, switchboard: address)` | `0x90c5924e27cfb6e3a688e729083681f30494ae2615ae14aac3bc807a0c436a88` | -| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | -| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | -| `SocketFeeManagerUpdated` | `(oldSocketFeeManager: address, newSocketFeeManager: address)` | `0xdcb02e10d5220346a4638aa2826eaab1897306623bc40a427049e4ebd12255b4` | -| `SwitchboardAdded` | `(switchboard: address)` | `0x1595852923edfbbf906f09fc8523e4cfb022a194773c4d1509446b614146ee88` | -| `SwitchboardDisabled` | `(switchboard: address)` | `0x1b4ee41596b4e754e5665f01ed6122b356f7b36ea0a02030804fac7fa0fdddfc` | -| `SwitchboardEnabled` | `(switchboard: address)` | `0x6909a9974e3eec619bc479ba882d30a5ef1219b72ab1ce6a354516e91be317b8` | - -## SocketBatcher +## Configurations + +| Event | Arguments | Topic | +| ---------------------------- | ------------------------------------------------------------------------ | -------------------------------------------------------------------- | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `IsValidPlugSet` | `(appGateway: address, chainSlug: uint32, plug: address, isValid: bool)` | `0x61cccc7387868fc741379c7acd9dd346e0ca2e5c067dc5b156fbbc55b1c2fcf5` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `PlugAdded` | `(appGatewayId: bytes32, chainSlug: uint32, plug: address)` | `0x7b3e14230a721c4737d275f9a63b92c44cb657bcfddbe6fe9b4d9cd9bd8d4a95` | +| `SocketSet` | `(chainSlug: uint32, socket: address)` | `0x5b13a5470e66a2ec5e9b32af5f9e23fe304864892918c60fffd22509ca73ac97` | +| `SwitchboardSet` | `(chainSlug: uint32, sbType: bytes32, switchboard: address)` | `0x6273f161f4a795e66ef3585d9b4442ef3796b32337157fdfb420b5281e4cf2e3` | + +## PromiseResolver + +| Event | Arguments | Topic | +| -------------------- | ------------------------------------------------ | -------------------------------------------------------------------- | +| `MarkedRevert` | `(payloadId: bytes32, isRevertingOnchain: bool)` | `0xcf1fd844cb4d32cbebb5ca6ce4ac834fe98da3ddac44deb77fffd22ad933824c` | +| `PromiseNotResolved` | `(payloadId: bytes32, asyncPromise: address)` | `0xbcf0d0c678940566e9e64f0c871439395bd5fb5c39bca3547b126fe6ee467937` | +| `PromiseResolved` | `(payloadId: bytes32, asyncPromise: address)` | `0x1b1b5810494fb3e17f7c46547e6e67cd6ad3e6001ea6fb7d12ea0241ba13c4ba` | + +## RequestHandler + +| Event | Arguments | Topic | +| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | +| `FeesIncreased` | `(requestCount: uint40, newMaxFees: uint256)` | `0xf258fca4e49b803ee2a4c2e33b6fcf18bc3982df21f111c00677025bf1ccbb6a` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `RequestCancelled` | `(requestCount: uint40)` | `0xff191657769be72fc08def44c645014c60d18cb24b9ca05c9a33406a28253245` | +| `RequestCompletedWithErrors` | `(requestCount: uint40)` | `0xd8d9915dc14b5a29b66cb263e1ea1e99e60418fc21d97f0fbf09cae1281291e2` | +| `RequestSettled` | `(requestCount: uint40, winner: address)` | `0x1234f98acbe1548b214f4528461a5377f1e2349569c04caa59325e488e7d2aa4` | +| `RequestSubmitted` | `(hasWrite: bool, requestCount: uint40, totalEstimatedWatcherFees: uint256, requestParams: tuple, payloadParamsArray: tuple[])` | `0x762bac43d5d7689b8911c5654a9d5550804373cead33bc98282067e6166e518f` | + +## Watcher | Event | Arguments | Topic | | ---------------------------- | ---------------------------------------- | -------------------------------------------------------------------- | +| `AppGatewayCallFailed` | `(triggerId: bytes32)` | `0xcaf8475fdade8465ea31672463949e6cf1797fdcdd11eeddbbaf857e1e5907b7` | +| `CalledAppGateway` | `(triggerId: bytes32)` | `0xf659ffb3875368f54fb4ab8f5412ac4518af79701a48076f7a58d4448e4bdd0b` | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | | `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | | `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | | `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | - -## SocketFeeManager - -| Event | Arguments | Topic | -| ---------------------------- | ---------------------------------------- | -------------------------------------------------------------------- | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | -| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | -| `SocketFeesUpdated` | `(oldFees: uint256, newFees: uint256)` | `0xcbd4d756fb6198bbcc2e4013cce929f504ad46e9d97c543ef9a8dfea3e407053` | - -## WatcherPrecompileConfig - -| Event | Arguments | Topic | -| ---------------------------- | --------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `IsValidPlugSet` | `(appGateway: address, chainSlug: uint32, plug: address, isValid: bool)` | `0x61cccc7387868fc741379c7acd9dd346e0ca2e5c067dc5b156fbbc55b1c2fcf5` | -| `OnChainContractSet` | `(chainSlug: uint32, socket: address, contractFactoryPlug: address, feesPlug: address)` | `0xd24cf816377e3c571e7bc798dd43d3d5fc78c32f7fc94b42898b0d37c5301a4e` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `PlugAdded` | `(appGatewayId: bytes32, chainSlug: uint32, plug: address)` | `0x7b3e14230a721c4737d275f9a63b92c44cb657bcfddbe6fe9b4d9cd9bd8d4a95` | -| `SwitchboardSet` | `(chainSlug: uint32, sbType: bytes32, switchboard: address)` | `0x6273f161f4a795e66ef3585d9b4442ef3796b32337157fdfb420b5281e4cf2e3` | - -## WatcherPrecompileLimits - -| Event | Arguments | Topic | -| --------------------------------- | ------------------------------------------------------------------ | -------------------------------------------------------------------- | -| `AppGatewayActivated` | `(appGateway: address, maxLimit: uint256, ratePerSecond: uint256)` | `0x44628d7d5628b9fbc2c84ea9bf3bd3987fa9cde8d2b28e2d5ceb451f916cb8b9` | -| `CallBackFeesSet` | `(callBackFees: uint256)` | `0x667c97afffb32265f3b4e026d31b81dc223275ff8bb9819e67012197f5799faf` | -| `DefaultLimitAndRatePerSecondSet` | `(defaultLimit: uint256, defaultRatePerSecond: uint256)` | `0x39def16be1ce80876ad0b0936cfdf88b8be7a1790b6c1da16ba8bdee53367e8e` | -| `FinalizeFeesSet` | `(finalizeFees: uint256)` | `0x0b710f92aabbdda2e8c347f802353f34ef27845d79db79efb4884e8790a0d5fb` | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `LimitParamsUpdated` | `(updates: tuple[])` | `0x81576b12f4d507fd0543afd25a86785573a595334c2c7eb8ca8ec1b0a56a55b3` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `QueryFeesSet` | `(queryFees: uint256)` | `0x19569faa0df733d4b0806372423e828b05a5257eb7652da812b90f662bed5cfb` | -| `TimeoutFeesSet` | `(timeoutFees: uint256)` | `0xe8a5b23529bc11019d6df86a1ee0d043571d464902a3fa98e7e3e67dbd5981ca` | - -## DeliveryHelper - -| Event | Arguments | Topic | -| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | -| `BidTimeoutUpdated` | `(newBidTimeout: uint256)` | `0xd4552e666d0e4e343fb2b13682972a8f0c7f1a86e252d6433b356f0c0e817c3d` | -| `ChainMaxMsgValueLimitsUpdated` | `(chainSlugs: uint32[], maxMsgValueLimits: uint256[])` | `0x17e47f6f0fa0e79831bee11b7c29adc45d9a7bd25acd70b91e4b2bad0f544352` | -| `FeesIncreased` | `(appGateway: address, requestCount: uint40, newMaxFees: uint256)` | `0x63ee9e9e84d216b804cb18f51b7f7511254b0c1f11304b7a3aa34d57511aa6dc` | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `PayloadSubmitted` | `(requestCount: uint40, appGateway: address, payloadSubmitParams: tuple[], fees: uint256, auctionManager: address, onlyReadRequests: bool)` | `0xc6455dba7c07a5e75c7189040ae9e3478162f333a96365b283b434fd0e32c6b3` | -| `RequestCancelled` | `(requestCount: uint40)` | `0xff191657769be72fc08def44c645014c60d18cb24b9ca05c9a33406a28253245` | +| `TriggerFailed` | `(triggerId: bytes32)` | `0x4386783bb0f7cad4ba12f033dbec03dc3441e7757a122f3097a7a4d945c98040` | +| `TriggerFeesSet` | `(triggerFees: uint256)` | `0x7df3967b7c8727af5ac0ee9825d88aafeb899d769bc428b91f8967fa0b623084` | +| `TriggerSucceeded` | `(triggerId: bytes32)` | `0x92d20fbcbf31370b8218e10ed00c5aad0e689022da30a08905ba5ced053219eb` | ## FastSwitchboard @@ -198,27 +228,35 @@ | `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | | `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | -## WatcherPrecompile - -| Event | Arguments | Topic | -| ----------------------------- | ----------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | -| `AppGatewayCallFailed` | `(triggerId: bytes32)` | `0xcaf8475fdade8465ea31672463949e6cf1797fdcdd11eeddbbaf857e1e5907b7` | -| `CalledAppGateway` | `(triggerId: bytes32)` | `0xf659ffb3875368f54fb4ab8f5412ac4518af79701a48076f7a58d4448e4bdd0b` | -| `ExpiryTimeSet` | `(expiryTime: uint256)` | `0x07e837e13ad9a34715a6bd45f49bbf12de19f06df79cb0be12b3a7d7f2397fa9` | -| `FinalizeRequested` | `(digest: bytes32, params: tuple)` | `0x5bc623895e2e50e307b4c3ba21df61ddfe68de0e084bb85eb1d42d4596532589` | -| `Finalized` | `(payloadId: bytes32, proof: bytes)` | `0x7e6e3e411317567fb9eabe3eb86768c3e33c46e38a50790726e916939b4918d6` | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `MarkedRevert` | `(payloadId: bytes32, isRevertingOnchain: bool)` | `0xcf1fd844cb4d32cbebb5ca6ce4ac834fe98da3ddac44deb77fffd22ad933824c` | -| `MaxTimeoutDelayInSecondsSet` | `(maxTimeoutDelayInSeconds: uint256)` | `0x3564638b089495c19e7359a040be083841e11da34c22a29ea8d602c8a9805fec` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `PromiseNotResolved` | `(payloadId: bytes32, asyncPromise: address)` | `0xbcf0d0c678940566e9e64f0c871439395bd5fb5c39bca3547b126fe6ee467937` | -| `PromiseResolved` | `(payloadId: bytes32, asyncPromise: address)` | `0x1b1b5810494fb3e17f7c46547e6e67cd6ad3e6001ea6fb7d12ea0241ba13c4ba` | -| `QueryRequested` | `(params: tuple)` | `0xca81bf0029a549d7e6e3a9c668a717472f4330a6a5ec4350304a9e79bf437345` | -| `RequestCancelledFromGateway` | `(requestCount: uint40)` | `0x333619ca4a2a9c4ee292aafa3c37215d88afe358afee4a575cfed21d743091c6` | -| `RequestSubmitted` | `(middleware: address, requestCount: uint40, payloadParamsArray: tuple[])` | `0xb856562fcff2119ba754f0486f47c06087ebc1842bff464faf1b2a1f8d273b1d` | -| `TimeoutRequested` | `(timeoutId: bytes32, target: address, payload: bytes, executeAt: uint256)` | `0xdf94fed77e41734b8a17815476bbbf88e2db15d762f42a30ddb9d7870f2fb858` | -| `TimeoutResolved` | `(timeoutId: bytes32, target: address, payload: bytes, executedAt: uint256, returnData: bytes)` | `0x61122416680ac7038ca053afc2c26983f2c524e5003b1f4d9dea095fbc8f6905` | -| `WatcherPrecompileConfigSet` | `(watcherPrecompileConfig: address)` | `0xdc19bca647582b3fbf69a6ffacabf56b4f7a4551d2d0944843712f2d0987a8e5` | -| `WatcherPrecompileLimitsSet` | `(watcherPrecompileLimits: address)` | `0xcec7ba89301793a37efb418279f17f8dd77e5959e9f3fbcbc54e40615a14bd8e` | +## ReadPrecompile + +| Event | Arguments | Topic | +| --------------- | ---------------------------------------------------------------------- | -------------------------------------------------------------------- | +| `ExpiryTimeSet` | `(expiryTime: uint256)` | `0x07e837e13ad9a34715a6bd45f49bbf12de19f06df79cb0be12b3a7d7f2397fa9` | +| `ReadFeesSet` | `(readFees: uint256)` | `0xc674cb6dde3a59f84dbf226832e606ffc54ac8a169e1568fc834c7813010f926` | +| `ReadRequested` | `(transaction: tuple, readAtBlockNumber: uint256, payloadId: bytes32)` | `0x42d9c65d4f6e45462ae6206adb3e388e046b7daa1dc8699d9380cac72ff5db0b` | + +## SchedulePrecompile + +| Event | Arguments | Topic | +| ------------------------------ | ---------------------------------------------------------------- | -------------------------------------------------------------------- | +| `ExpiryTimeSet` | `(expiryTime_: uint256)` | `0x07e837e13ad9a34715a6bd45f49bbf12de19f06df79cb0be12b3a7d7f2397fa9` | +| `MaxScheduleDelayInSecondsSet` | `(maxScheduleDelayInSeconds_: uint256)` | `0xfd5e4f0e96753ffb08a583390c2f151c51001d8e560625ab93b7fa7b4dac6d75` | +| `ScheduleCallbackFeesSet` | `(scheduleCallbackFees_: uint256)` | `0x82a2f41efc81ce7bfabc0affda7354dae42a3d09bd74a6196e8904b223138a52` | +| `ScheduleFeesPerSecondSet` | `(scheduleFeesPerSecond_: uint256)` | `0x7901a21229f6d2543d8676f53e21214d15f42513e7d46e0dcb510357222bdc7c` | +| `ScheduleRequested` | `(payloadId: bytes32, executeAfter: uint256, deadline: uint256)` | `0xd099d3e3d0f0e2c9c40e0066affeea125aab71d763b7ab0a279ccec3dff70b64` | +| `ScheduleResolved` | `(payloadId: bytes32)` | `0x925dc6c3ebffa07cac89d6e9675f1a5d04e045f2ed9a4fa442665935cb73e26b` | + +## WritePrecompile + +| Event | Arguments | Topic | +| ------------------------------- | ---------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | +| `ChainMaxMsgValueLimitsUpdated` | `(chainSlug: uint32, maxMsgValueLimit: uint256)` | `0x439087d094fe7dacbba3f0c67032041952d8bd58a891e15af10ced28fed0eb91` | +| `ContractFactoryPlugSet` | `(chainSlug: uint32, contractFactoryPlug: address)` | `0x85bfa413b9e5e225278f51af2ac872988e0a9374263b118d963c50945ea888bb` | +| `ExpiryTimeSet` | `(expiryTime: uint256)` | `0x07e837e13ad9a34715a6bd45f49bbf12de19f06df79cb0be12b3a7d7f2397fa9` | +| `FeesSet` | `(writeFees: uint256)` | `0x3346af6da1932164d501f2ec28f8c5d686db5828a36b77f2da4332d89184fe7b` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `WriteProofRequested` | `(transmitter: address, digest: bytes32, prevBatchDigestHash: bytes32, deadline: uint256, payloadParams: tuple)` | `0x3247df5b4e8df4ac60c2c1f803b404ee16bc9d84a6b7649865464a8a397b9acb` | +| `WriteProofUploaded` | `(payloadId: bytes32, proof: bytes)` | `0xd8fe3a99a88c9630360418877afdf14e3e79f0f25fee162aeb230633ea740156` | diff --git a/FunctionSignatures.md b/FunctionSignatures.md index e3ef596c..ab3f68b0 100644 --- a/FunctionSignatures.md +++ b/FunctionSignatures.md @@ -1,256 +1,65 @@ # Function Signatures -## ProxyFactory - -| Function | Signature | -| ----------------------------- | ------------ | -| `adminOf` | `0x2abbef15` | -| `changeAdmin` | `0x1acfd02a` | -| `deploy` | `0x545e7c61` | -| `deployAndCall` | `0x4314f120` | -| `deployDeterministic` | `0x3729f922` | -| `deployDeterministicAndCall` | `0xa97b90d5` | -| `initCodeHash` | `0xdb4c545e` | -| `predictDeterministicAddress` | `0x5414dff0` | -| `upgrade` | `0x99a88ec4` | -| `upgradeAndCall` | `0x9623609d` | - -## TestUSDC - -| Function | Signature | -| ------------------ | ------------ | -| `DOMAIN_SEPARATOR` | `0x3644e515` | -| `allowance` | `0xdd62ed3e` | -| `approve` | `0x095ea7b3` | -| `balanceOf` | `0x70a08231` | -| `decimals` | `0x313ce567` | -| `mint` | `0x40c10f19` | -| `name` | `0x06fdde03` | -| `nonces` | `0x7ecebe00` | -| `owner` | `0x8da5cb5b` | -| `permit` | `0xd505accf` | -| `symbol` | `0x95d89b41` | -| `totalSupply` | `0x18160ddd` | -| `transfer` | `0xa9059cbb` | -| `transferFrom` | `0x23b872dd` | - -## AddressResolver - -| Function | Signature | -| ------------------------------- | ------------ | -| `asyncPromiseBeacon` | `0xc0fbc0ef` | -| `asyncPromiseCounter` | `0x97cdbf4c` | -| `asyncPromiseImplementation` | `0x59531b8d` | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `clearPromises` | `0x96e03234` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `contractsToGateways` | `0x5bc03a67` | -| `defaultAuctionManager` | `0x8f27cdc6` | -| `deliveryHelper` | `0x71eaa36f` | -| `deployAsyncPromiseContract` | `0x00afbf9d` | -| `feesManager` | `0x05a9e073` | -| `forwarderBeacon` | `0x945709ae` | -| `forwarderImplementation` | `0xe38d60a1` | -| `getAsyncPromiseAddress` | `0xb6400df5` | -| `getForwarderAddress` | `0x48c0b3e0` | -| `getOrDeployForwarderContract` | `0xe8d616a8` | -| `getPromises` | `0xa01afb0d` | -| `initialize` | `0xc4d66de8` | -| `owner` | `0x8da5cb5b` | -| `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `renounceOwnership` | `0x715018a6` | -| `requestOwnershipHandover` | `0x25692962` | -| `setAsyncPromiseImplementation` | `0xeb506eab` | -| `setContractsToGateways` | `0xb08dd08b` | -| `setDefaultAuctionManager` | `0xede8b4b5` | -| `setDeliveryHelper` | `0x75523822` | -| `setFeesManager` | `0x1c89382a` | -| `setForwarderImplementation` | `0x83b1e974` | -| `setWatcherPrecompile` | `0x5ca44c9b` | -| `transferOwnership` | `0xf2fde38b` | -| `version` | `0x54fd4d50` | -| `watcherPrecompile__` | `0x1de360c3` | - -## AsyncPromise - -| Function | Signature | -| ------------------------- | ------------ | -| `addressResolver__` | `0x6a750469` | -| `callbackData` | `0xef44c272` | -| `callbackSelector` | `0x2764f92f` | -| `deliveryHelper__` | `0xc031dfb4` | -| `forwarder` | `0xf645d4f9` | -| `initialize` | `0xc0c53b8b` | -| `localInvoker` | `0x45eb87f4` | -| `markOnchainRevert` | `0x7734a84e` | -| `markResolved` | `0xdd94d9b2` | -| `resolved` | `0x3f6fa655` | -| `state` | `0xc19d93fb` | -| `then` | `0x0bf2ba15` | -| `watcherPrecompileConfig` | `0x8618a912` | -| `watcherPrecompileLimits` | `0xa71cd97d` | -| `watcherPrecompile__` | `0x1de360c3` | - -## Forwarder - -| Function | Signature | -| ------------------------- | ------------ | -| `addressResolver__` | `0x6a750469` | -| `chainSlug` | `0xb349ba65` | -| `deliveryHelper__` | `0xc031dfb4` | -| `getChainSlug` | `0x0b8c6568` | -| `getOnChainAddress` | `0x9da48789` | -| `initialize` | `0x647c576c` | -| `latestAsyncPromise` | `0xb8a8ba52` | -| `latestPromiseCaller` | `0xdfe580a8` | -| `latestRequestCount` | `0x198b9a47` | -| `onChainAddress` | `0x8bd0b363` | -| `then` | `0x0bf2ba15` | -| `watcherPrecompileConfig` | `0x8618a912` | -| `watcherPrecompileLimits` | `0xa71cd97d` | -| `watcherPrecompile__` | `0x1de360c3` | - ## AuctionManager -| Function | Signature | -| -------------------------------- | ------------ | -| `addressResolver__` | `0x6a750469` | -| `auctionClosed` | `0x6862ebb0` | -| `auctionEndDelaySeconds` | `0x9087dfdb` | -| `auctionStarted` | `0x7c9c5bb8` | -| `bid` | `0xfcdf49c2` | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `deliveryHelper__` | `0xc031dfb4` | -| `endAuction` | `0x1212e653` | -| `evmxSlug` | `0x8bae77c2` | -| `expireBid` | `0x1dd5022c` | -| `getTransmitterMaxFeesAvailable` | `0xa70f18ea` | -| `grantRole` | `0x2f2ff15d` | -| `hasRole` | `0x91d14854` | -| `initialize` | `0x5f24043b` | -| `maxReAuctionCount` | `0xc367b376` | -| `owner` | `0x8da5cb5b` | -| `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `reAuctionCount` | `0x9b4b22d3` | -| `renounceOwnership` | `0x715018a6` | -| `requestOwnershipHandover` | `0x25692962` | -| `revokeRole` | `0xd547741f` | -| `setAuctionEndDelaySeconds` | `0x88606b1a` | -| `transferOwnership` | `0xf2fde38b` | -| `watcherPrecompileConfig` | `0x8618a912` | -| `watcherPrecompileLimits` | `0xa71cd97d` | -| `watcherPrecompile__` | `0x1de360c3` | -| `winningBids` | `0x9133f232` | - -## ContractFactoryPlug - -| Function | Signature | -| ---------------------------- | ------------ | -| `appGatewayId` | `0x1c335f49` | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `connectSocket` | `0x258d19c8` | -| `deployContract` | `0xa0695389` | -| `getAddress` | `0x94ca2cb5` | -| `grantRole` | `0x2f2ff15d` | -| `hasRole` | `0x91d14854` | -| `initSocket` | `0xa07d8545` | -| `isSocketInitialized` | `0x9a7d9a9b` | -| `overrides` | `0x4a85f041` | -| `owner` | `0x8da5cb5b` | -| `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `renounceOwnership` | `0x715018a6` | -| `requestOwnershipHandover` | `0x25692962` | -| `rescueFunds` | `0x6ccae054` | -| `revokeRole` | `0xd547741f` | -| `socket__` | `0xc6a261d2` | -| `transferOwnership` | `0xf2fde38b` | - -## FeesManager - -| Function | Signature | -| ------------------------------------------------ | ------------ | -| `addressResolver__` | `0x6a750469` | -| `assignWatcherPrecompileCreditsFromAddress` | `0xd699b6c8` | -| `assignWatcherPrecompileCreditsFromRequestCount` | `0x7a483022` | -| `blockCredits` | `0x2d64fc91` | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `deliveryHelper__` | `0xc031dfb4` | -| `depositCredits` | `0x211998c8` | -| `evmxSlug` | `0x8bae77c2` | -| `feesCounter` | `0xb94f4778` | -| `getAvailableCredits` | `0xb065a8e5` | -| `getMaxCreditsAvailableForWithdraw` | `0x6ef9efe2` | -| `getWithdrawTransmitterCreditsPayloadParams` | `0x27be4536` | -| `initialize` | `0x6f6186bd` | -| `isAppGatewayWhitelisted` | `0x2a83b813` | -| `isNonceUsed` | `0x5d00bb12` | -| `isUserCreditsEnough` | `0x5bee3a67` | -| `onRequestComplete` | `0x5ed1f959` | -| `owner` | `0x8da5cb5b` | -| `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `renounceOwnership` | `0x715018a6` | -| `requestCountCredits` | `0x0c9b8a49` | -| `requestOwnershipHandover` | `0x25692962` | -| `sbType` | `0x745de344` | -| `tokenPoolBalances` | `0x2eda3bfd` | -| `transferOwnership` | `0xf2fde38b` | -| `unblockAndAssignCredits` | `0x01958181` | -| `unblockCredits` | `0xa0b32314` | -| `unwrap` | `0xde0e9a3e` | -| `userCredits` | `0x20babb92` | -| `userNonce` | `0x2e04b8e7` | -| `watcherPrecompileConfig` | `0x8618a912` | -| `watcherPrecompileCredits` | `0x052e1f6a` | -| `watcherPrecompileLimits` | `0xa71cd97d` | -| `watcherPrecompile__` | `0x1de360c3` | -| `whitelistAppGatewayWithSignature` | `0x28cbf83d` | -| `whitelistAppGateways` | `0x6c2499e3` | -| `withdrawCredits` | `0xc22f8cf3` | -| `wrap` | `0xd46eb119` | - -## FeesPlug - | Function | Signature | | ---------------------------- | ------------ | -| `appGatewayId` | `0x1c335f49` | +| `addressResolver__` | `0x6a750469` | +| `asyncDeployer__` | `0x2a39e801` | +| `auctionEndDelaySeconds` | `0x9087dfdb` | +| `auctionManager` | `0xb0192f9a` | +| `auctionStatus` | `0xd7d5fbf6` | +| `bid` | `0xfcdf49c2` | +| `bidTimeout` | `0x94090d0b` | | `cancelOwnershipHandover` | `0x54d1f13d` | | `completeOwnershipHandover` | `0xf04e283e` | -| `connectSocket` | `0x258d19c8` | -| `depositToFee` | `0xef0db49f` | -| `depositToFeeAndNative` | `0x5f952be8` | -| `depositToNative` | `0xe2665889` | +| `consumeFrom` | `0x40dd78be` | +| `creationCodeWithArgs` | `0xc126dcc4` | +| `deployForwarder__` | `0xd4e3b034` | +| `endAuction` | `0x1212e653` | +| `evmxSlug` | `0x8bae77c2` | +| `expireBid` | `0x1dd5022c` | +| `feesManager__` | `0x70568b58` | +| `forwarderAddresses` | `0x5390fdcb` | +| `getOnChainAddress` | `0xb6abffd7` | +| `getOverrideParams` | `0x54f0a866` | | `grantRole` | `0x2f2ff15d` | +| `handleRevert` | `0x44792f25` | | `hasRole` | `0x91d14854` | -| `initSocket` | `0xa07d8545` | -| `isSocketInitialized` | `0x9a7d9a9b` | -| `overrides` | `0x4a85f041` | +| `initialize` | `0x8d8965bd` | +| `isAsyncModifierSet` | `0xb69e0c4a` | +| `isValidPromise` | `0xb690b962` | +| `maxFees` | `0xe83e34b1` | +| `maxReAuctionCount` | `0xc367b376` | +| `onCompleteData` | `0xb52fa926` | +| `onRequestComplete` | `0x5ed1f959` | +| `overrideParams` | `0xec5490fe` | | `owner` | `0x8da5cb5b` | | `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `removeTokenFromWhitelist` | `0x306275be` | +| `reAuctionCount` | `0x9b4b22d3` | | `renounceOwnership` | `0x715018a6` | | `requestOwnershipHandover` | `0x25692962` | -| `rescueFunds` | `0x6ccae054` | | `revokeRole` | `0xd547741f` | -| `socket__` | `0xc6a261d2` | +| `sbType` | `0x745de344` | +| `setAddress` | `0x85bf312c` | +| `setAuctionEndDelaySeconds` | `0x88606b1a` | +| `setMaxReAuctionCount` | `0x64c71403` | | `transferOwnership` | `0xf2fde38b` | -| `whitelistToken` | `0x6247f6f2` | -| `whitelistedTokens` | `0xdaf9c210` | -| `withdrawFees` | `0xe55dc4e6` | +| `watcher__` | `0x300bb063` | +| `winningBids` | `0x9133f232` | ## Socket | Function | Signature | | ---------------------------- | ------------ | +| `OFF_CHAIN_CALLER` | `0xcb2cb4f6` | | `cancelOwnershipHandover` | `0x54d1f13d` | | `chainSlug` | `0xb349ba65` | | `completeOwnershipHandover` | `0xf04e283e` | | `connect` | `0xb3bde1aa` | | `disableSwitchboard` | `0xe545b261` | | `enableSwitchboard` | `0xf97a498a` | -| `execute` | `0x68ef086b` | +| `execute` | `0xafa8b480` | | `getPlugConfig` | `0xf9778ee0` | | `grantRole` | `0x2f2ff15d` | | `hasRole` | `0x91d14854` | @@ -267,6 +76,7 @@ | `revokeRole` | `0xd547741f` | | `setMaxCopyBytes` | `0x4fc7d6e9` | | `setSocketFeeManager` | `0x25bd97e5` | +| `simulate` | `0x91bf8275` | | `socketFeeManager` | `0xde5b8838` | | `transferOwnership` | `0xf2fde38b` | | `triggerCounter` | `0x8b0021de` | @@ -276,7 +86,7 @@ | Function | Signature | | ---------------------------- | ------------ | -| `attestAndExecute` | `0xa11d3bdc` | +| `attestAndExecute` | `0x66c7748a` | | `cancelOwnershipHandover` | `0x54d1f13d` | | `completeOwnershipHandover` | `0xf04e283e` | | `owner` | `0x8da5cb5b` | @@ -298,7 +108,7 @@ | `hasRole` | `0x91d14854` | | `owner` | `0x8da5cb5b` | | `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `payAndCheckFees` | `0xbaa56229` | +| `payAndCheckFees` | `0xd9d29ae3` | | `renounceOwnership` | `0x715018a6` | | `requestOwnershipHandover` | `0x25692962` | | `rescueFunds` | `0x6ccae054` | @@ -307,109 +117,335 @@ | `socketFees` | `0xab1b33a8` | | `transferOwnership` | `0xf2fde38b` | -## WatcherPrecompileConfig +## FeesManager + +| Function | Signature | +| -------------------------------- | ------------ | +| `addressResolver__` | `0x6a750469` | +| `approveAppGatewayWithSignature` | `0x94b649ec` | +| `approveAppGateways` | `0x86d23ab2` | +| `asyncDeployer__` | `0x2a39e801` | +| `blockCredits` | `0x9e434307` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `deployForwarder__` | `0xd4e3b034` | +| `deposit` | `0x5671d329` | +| `evmxSlug` | `0x8bae77c2` | +| `feesManager__` | `0x70568b58` | +| `feesPlugs` | `0x23f5ee8a` | +| `feesPool` | `0x6b259690` | +| `getAvailableCredits` | `0xb065a8e5` | +| `initialize` | `0xbf2c8539` | +| `isApproved` | `0xa389783e` | +| `isCreditSpendable` | `0x4f8990fd` | +| `isNonceUsed` | `0xcab7e8eb` | +| `onRequestComplete` | `0x5ed1f959` | +| `owner` | `0x8da5cb5b` | +| `ownershipHandoverExpiresAt` | `0xfee81cf4` | +| `renounceOwnership` | `0x715018a6` | +| `requestBlockedCredits` | `0xb62d25ac` | +| `requestOwnershipHandover` | `0x25692962` | +| `sbType` | `0x745de344` | +| `setFeesPlug` | `0xeab75f36` | +| `setFeesPool` | `0xd6684588` | +| `tokenOnChainBalances` | `0x3b27866d` | +| `transferCredits` | `0xf1686c89` | +| `transferOwnership` | `0xf2fde38b` | +| `unblockAndAssignCredits` | `0x01958181` | +| `unblockCredits` | `0xa0b32314` | +| `unwrap` | `0x7647691d` | +| `userCredits` | `0x20babb92` | +| `watcher__` | `0x300bb063` | +| `withdrawCredits` | `0xcfc6dbd9` | +| `wrap` | `0x023276f0` | + +## FeesPool + +| Function | Signature | +| ---------------------------- | ------------ | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `getBalance` | `0x12065fe0` | +| `grantRole` | `0x2f2ff15d` | +| `hasRole` | `0x91d14854` | +| `owner` | `0x8da5cb5b` | +| `ownershipHandoverExpiresAt` | `0xfee81cf4` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `revokeRole` | `0xd547741f` | +| `transferOwnership` | `0xf2fde38b` | +| `withdraw` | `0xf3fef3a3` | + +## AddressResolver + +| Function | Signature | +| ---------------------------- | ------------ | +| `asyncDeployer__` | `0x2a39e801` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `contractAddresses` | `0xf689e892` | +| `defaultAuctionManager` | `0x8f27cdc6` | +| `deployForwarder__` | `0xd4e3b034` | +| `feesManager__` | `0x70568b58` | +| `initialize` | `0xc4d66de8` | +| `owner` | `0x8da5cb5b` | +| `ownershipHandoverExpiresAt` | `0xfee81cf4` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `setAsyncDeployer` | `0xcb0ffff8` | +| `setContractAddress` | `0xe001f841` | +| `setDefaultAuctionManager` | `0xede8b4b5` | +| `setDeployForwarder` | `0xaeaee8a6` | +| `setFeesManager` | `0x1c89382a` | +| `setWatcher` | `0x24f48bc5` | +| `transferOwnership` | `0xf2fde38b` | +| `watcher__` | `0x300bb063` | + +## AsyncDeployer + +| Function | Signature | +| ------------------------------- | ------------ | +| `addressResolver__` | `0x6a750469` | +| `asyncDeployer__` | `0x2a39e801` | +| `asyncPromiseBeacon` | `0xc0fbc0ef` | +| `asyncPromiseCounter` | `0x97cdbf4c` | +| `asyncPromiseImplementation` | `0x59531b8d` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `deployAsyncPromiseContract` | `0x9851be0b` | +| `deployForwarder__` | `0xd4e3b034` | +| `feesManager__` | `0x70568b58` | +| `forwarderBeacon` | `0x945709ae` | +| `forwarderImplementation` | `0xe38d60a1` | +| `getAsyncPromiseAddress` | `0x104f39b4` | +| `getForwarderAddress` | `0x48c0b3e0` | +| `getOrDeployForwarderContract` | `0x0aa178de` | +| `initialize` | `0x485cc955` | +| `owner` | `0x8da5cb5b` | +| `ownershipHandoverExpiresAt` | `0xfee81cf4` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `setAsyncPromiseImplementation` | `0xeb506eab` | +| `setForwarderImplementation` | `0x83b1e974` | +| `transferOwnership` | `0xf2fde38b` | +| `watcher__` | `0x300bb063` | + +## AsyncPromise + +| Function | Signature | +| ------------------- | ------------ | +| `addressResolver__` | `0x6a750469` | +| `asyncDeployer__` | `0x2a39e801` | +| `callbackData` | `0xef44c272` | +| `callbackSelector` | `0x2764f92f` | +| `deployForwarder__` | `0xd4e3b034` | +| `exceededMaxCopy` | `0xaf598c7c` | +| `feesManager__` | `0x70568b58` | +| `initialize` | `0x0ece6089` | +| `localInvoker` | `0x45eb87f4` | +| `markOnchainRevert` | `0xd0e7af1b` | +| `markResolved` | `0x822d5d1f` | +| `requestCount` | `0x5badbe4c` | +| `returnData` | `0xebddbaf6` | +| `state` | `0xc19d93fb` | +| `then` | `0x0bf2ba15` | +| `watcher__` | `0x300bb063` | + +## DeployForwarder + +| Function | Signature | +| ------------------------- | ------------ | +| `addressResolver__` | `0x6a750469` | +| `asyncDeployer__` | `0x2a39e801` | +| `deploy` | `0x940f11af` | +| `deployForwarder__` | `0xd4e3b034` | +| `deployerSwitchboardType` | `0xaa381f9a` | +| `feesManager__` | `0x70568b58` | +| `saltCounter` | `0xa04c6809` | +| `watcher__` | `0x300bb063` | + +## Forwarder + +| Function | Signature | +| ------------------- | ------------ | +| `addressResolver__` | `0x6a750469` | +| `asyncDeployer__` | `0x2a39e801` | +| `chainSlug` | `0xb349ba65` | +| `deployForwarder__` | `0xd4e3b034` | +| `feesManager__` | `0x70568b58` | +| `getChainSlug` | `0x0b8c6568` | +| `getOnChainAddress` | `0x9da48789` | +| `initialize` | `0x647c576c` | +| `onChainAddress` | `0x8bd0b363` | +| `watcher__` | `0x300bb063` | + +## ProxyFactory + +| Function | Signature | +| ----------------------------- | ------------ | +| `adminOf` | `0x2abbef15` | +| `changeAdmin` | `0x1acfd02a` | +| `deploy` | `0x545e7c61` | +| `deployAndCall` | `0x4314f120` | +| `deployDeterministic` | `0x3729f922` | +| `deployDeterministicAndCall` | `0xa97b90d5` | +| `initCodeHash` | `0xdb4c545e` | +| `predictDeterministicAddress` | `0x5414dff0` | +| `upgrade` | `0x99a88ec4` | +| `upgradeAndCall` | `0x9623609d` | + +## TestUSDC + +| Function | Signature | +| ------------------ | ------------ | +| `DOMAIN_SEPARATOR` | `0x3644e515` | +| `allowance` | `0xdd62ed3e` | +| `approve` | `0x095ea7b3` | +| `balanceOf` | `0x70a08231` | +| `decimals` | `0x313ce567` | +| `mint` | `0x40c10f19` | +| `name` | `0x06fdde03` | +| `nonces` | `0x7ecebe00` | +| `owner` | `0x8da5cb5b` | +| `permit` | `0xd505accf` | +| `symbol` | `0x95d89b41` | +| `totalSupply` | `0x18160ddd` | +| `transfer` | `0xa9059cbb` | +| `transferFrom` | `0x23b872dd` | + +## ContractFactoryPlug + +| Function | Signature | +| ---------------------------- | ------------ | +| `appGatewayId` | `0x1c335f49` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `connectSocket` | `0x258d19c8` | +| `deployContract` | `0xa0695389` | +| `getAddress` | `0x94ca2cb5` | +| `grantRole` | `0x2f2ff15d` | +| `hasRole` | `0x91d14854` | +| `initSocket` | `0xa07d8545` | +| `isSocketInitialized` | `0x9a7d9a9b` | +| `overrides` | `0x4a85f041` | +| `owner` | `0x8da5cb5b` | +| `ownershipHandoverExpiresAt` | `0xfee81cf4` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | +| `revokeRole` | `0xd547741f` | +| `socket__` | `0xc6a261d2` | +| `transferOwnership` | `0xf2fde38b` | + +## Configurations | Function | Signature | | ---------------------------- | ------------ | -| `addressResolver__` | `0x6a750469` | | `cancelOwnershipHandover` | `0x54d1f13d` | | `completeOwnershipHandover` | `0xf04e283e` | -| `contractFactoryPlug` | `0xd8427483` | -| `deliveryHelper__` | `0xc031dfb4` | -| `evmxSlug` | `0x8bae77c2` | -| `feesPlug` | `0xd1ba159d` | | `getPlugConfigs` | `0x8a028c38` | -| `initialize` | `0x6ecf2b22` | -| `isNonceUsed` | `0x5d00bb12` | | `isValidPlug` | `0xec8aef74` | | `owner` | `0x8da5cb5b` | | `ownershipHandoverExpiresAt` | `0xfee81cf4` | | `renounceOwnership` | `0x715018a6` | | `requestOwnershipHandover` | `0x25692962` | -| `setAppGateways` | `0xdd8539d4` | -| `setIsValidPlug` | `0xb3a6bbcf` | -| `setOnChainContracts` | `0x33fa78c2` | +| `setAppGatewayConfigs` | `0xd137fcbb` | +| `setIsValidPlug` | `0xf41332b0` | +| `setSocket` | `0x075c40be` | | `setSwitchboard` | `0x61706f1e` | | `sockets` | `0xb44a23ab` | | `switchboards` | `0xaa539546` | | `transferOwnership` | `0xf2fde38b` | -| `verifyConnections` | `0xf269ab50` | -| `watcherPrecompileConfig` | `0x8618a912` | -| `watcherPrecompileLimits` | `0xa71cd97d` | -| `watcherPrecompile__` | `0x1de360c3` | - -## WatcherPrecompileLimits - -| Function | Signature | -| --------------------------------- | ------------ | -| `addressResolver__` | `0x6a750469` | -| `callBackFees` | `0xf9554ecc` | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `consumeLimit` | `0xc22f5a13` | -| `defaultLimit` | `0xe26b013b` | -| `defaultRatePerSecond` | `0x16d7acdf` | -| `deliveryHelper__` | `0xc031dfb4` | -| `finalizeFees` | `0x09207879` | -| `getCurrentLimit` | `0x1a065507` | -| `getLimitParams` | `0x2ff81ee0` | -| `getTotalFeesRequired` | `0x964500b5` | -| `initialize` | `0x1794bb3c` | -| `limitDecimals` | `0xee185533` | -| `owner` | `0x8da5cb5b` | -| `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `queryFees` | `0xcfcbafb6` | -| `renounceOwnership` | `0x715018a6` | -| `requestOwnershipHandover` | `0x25692962` | -| `setCallBackFees` | `0x622be814` | -| `setDefaultLimitAndRatePerSecond` | `0x7e434156` | -| `setFinalizeFees` | `0xbce0a88c` | -| `setQueryFees` | `0x877135d7` | -| `setTimeoutFees` | `0x571db4f9` | -| `timeoutFees` | `0xeab12f7e` | -| `transferOwnership` | `0xf2fde38b` | -| `updateLimitParams` | `0x01b2a5a0` | -| `watcherPrecompileConfig` | `0x8618a912` | -| `watcherPrecompileLimits` | `0xa71cd97d` | -| `watcherPrecompile__` | `0x1de360c3` | - -## DeliveryHelper +| `verifyConnections` | `0xa53b6fad` | +| `watcher__` | `0x300bb063` | + +## PromiseResolver + +| Function | Signature | +| ----------------- | ------------ | +| `markRevert` | `0x56501015` | +| `resolvePromises` | `0xbf8484b8` | +| `watcher__` | `0x300bb063` | + +## RequestHandler | Function | Signature | | ------------------------------ | ------------ | | `addressResolver__` | `0x6a750469` | -| `batch` | `0xd9307dd8` | -| `bidTimeout` | `0x94090d0b` | +| `assignTransmitter` | `0xae5e9c48` | +| `asyncDeployer__` | `0x2a39e801` | | `cancelOwnershipHandover` | `0x54d1f13d` | -| `cancelRequest` | `0x50ad0779` | -| `chainMaxMsgValueLimit` | `0x01d1e126` | -| `clearQueue` | `0xf22cb874` | +| `cancelRequest` | `0x3b5fd6fb` | +| `cancelRequestForReverts` | `0x82970278` | | `completeOwnershipHandover` | `0xf04e283e` | -| `deliveryHelper__` | `0xc031dfb4` | -| `finishRequest` | `0xeab148c0` | -| `getDeliveryHelperPlugAddress` | `0xb709bd9f` | -| `getFees` | `0xfbf4ec4b` | -| `getRequestMetadata` | `0x5f1dde51` | -| `handleRequestReverts` | `0x8fe9734f` | -| `increaseFees` | `0xe9b304da` | -| `initialize` | `0x7265580f` | +| `deployForwarder__` | `0xd4e3b034` | +| `feesManager__` | `0x70568b58` | +| `getBatchPayloadIds` | `0xfd83cd1f` | +| `getPayload` | `0xb48fd0fe` | +| `getPrecompileFees` | `0xabac263c` | +| `getRequest` | `0xcf39abf6` | +| `getRequestBatchIds` | `0xe138fadb` | +| `handleRevert` | `0xcc88d3f9` | +| `increaseFees` | `0x10205541` | +| `nextBatchCount` | `0x333a3963` | +| `nextRequestCount` | `0xfef72893` | | `owner` | `0x8da5cb5b` | | `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `queue` | `0x1b9396f5` | -| `queuePayloadParams` | `0x3c362159` | +| `payloadCounter` | `0x550ce1d5` | +| `precompiles` | `0x9932450b` | | `renounceOwnership` | `0x715018a6` | | `requestOwnershipHandover` | `0x25692962` | -| `requests` | `0xb71a5e58` | -| `saltCounter` | `0xa04c6809` | -| `startRequestProcessing` | `0x5ca2100f` | +| `setPrecompile` | `0x122e0042` | +| `submitRequest` | `0xbb299a2c` | | `transferOwnership` | `0xf2fde38b` | -| `updateBidTimeout` | `0xa29f83d1` | -| `updateChainMaxMsgValueLimits` | `0x0b32de76` | -| `watcherPrecompileConfig` | `0x8618a912` | -| `watcherPrecompileLimits` | `0xa71cd97d` | -| `watcherPrecompile__` | `0x1de360c3` | -| `withdrawTo` | `0x2ba9d5bb` | -| `withdrawTransmitterFees` | `0x38ff6dd2` | +| `updateRequestAndProcessBatch` | `0x46464471` | +| `watcher__` | `0x300bb063` | + +## Watcher + +| Function | Signature | +| ---------------------------- | ------------ | +| `addressResolver__` | `0x6a750469` | +| `appGatewayTemp` | `0x1394c029` | +| `asyncDeployer__` | `0x2a39e801` | +| `callAppGateways` | `0x0050bef1` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `cancelRequest` | `0x50ad0779` | +| `clearQueue` | `0xf22cb874` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `configurations__` | `0x52a3bbeb` | +| `deployForwarder__` | `0xd4e3b034` | +| `evmxSlug` | `0x8bae77c2` | +| `feesManager__` | `0x70568b58` | +| `getCurrentRequestCount` | `0x5715abbb` | +| `getPayloadParams` | `0xae5eeb77` | +| `getPrecompileFees` | `0xabac263c` | +| `getRequestParams` | `0x71263d0d` | +| `increaseFees` | `0xe9b304da` | +| `initialize` | `0xaaf7fc1a` | +| `isAppGatewayCalled` | `0xa79da6c7` | +| `isNonceUsed` | `0x5d00bb12` | +| `isWatcher` | `0x84785ecd` | +| `latestAsyncPromise` | `0xb8a8ba52` | +| `owner` | `0x8da5cb5b` | +| `ownershipHandoverExpiresAt` | `0xfee81cf4` | +| `payloadQueue` | `0x74f00ffb` | +| `promiseResolver__` | `0xdee152be` | +| `queue` | `0xf03ca7f7` | +| `queueAndSubmit` | `0xf0fb9665` | +| `renounceOwnership` | `0x715018a6` | +| `requestHandler__` | `0x55184561` | +| `requestOwnershipHandover` | `0x25692962` | +| `setCoreContracts` | `0xefa891c4` | +| `setIsValidPlug` | `0x7fc82ff6` | +| `setTriggerFees` | `0xaeb30511` | +| `submitRequest` | `0x4890b5ef` | +| `transferOwnership` | `0xf2fde38b` | +| `triggerFees` | `0x73f76aec` | +| `triggerFromChainSlug` | `0xd12b4f12` | +| `triggerFromPlug` | `0x3b847d12` | +| `watcherMultiCall` | `0x8021e82b` | +| `watcher__` | `0x300bb063` | ## FastSwitchboard @@ -433,61 +469,64 @@ | `socket__` | `0xc6a261d2` | | `transferOwnership` | `0xf2fde38b` | -## WatcherPrecompile +## ReadPrecompile -| Function | Signature | -| ----------------------------- | ------------ | -| `addressResolver__` | `0x6a750469` | -| `appGatewayCalled` | `0xc6767cf1` | -| `appGatewayCaller` | `0x712b193a` | -| `batchPayloadIds` | `0x02b74f98` | -| `callAppGateways` | `0x5c38ded5` | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `cancelRequest` | `0x50ad0779` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `deliveryHelper__` | `0xc031dfb4` | -| `evmxSlug` | `0x8bae77c2` | -| `expiryTime` | `0x99bc0aea` | -| `finalized` | `0x81c051de` | -| `getBatchPayloadIds` | `0xfd83cd1f` | -| `getBatches` | `0xcb95b7b3` | -| `getCurrentRequestCount` | `0x5715abbb` | -| `getDigest` | `0xa7993154` | -| `getPayloadParams` | `0xae5eeb77` | -| `getRequestParams` | `0x71263d0d` | -| `initialize` | `0xb7dc6b77` | -| `isNonceUsed` | `0x5d00bb12` | -| `isPromiseExecuted` | `0x17a2cdf0` | -| `markRevert` | `0x1c75dad5` | -| `maxTimeoutDelayInSeconds` | `0x46fbc9d7` | -| `nextBatchCount` | `0x333a3963` | -| `nextRequestCount` | `0xfef72893` | -| `owner` | `0x8da5cb5b` | -| `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `payloadCounter` | `0x550ce1d5` | -| `payloads` | `0x58722672` | -| `query` | `0x16ad71bc` | -| `renounceOwnership` | `0x715018a6` | -| `requestBatchIds` | `0xf865c4a7` | -| `requestMetadata` | `0x875b3f7e` | -| `requestOwnershipHandover` | `0x25692962` | -| `requestParams` | `0x5ce2d853` | -| `resolvePromises` | `0xccb1caff` | -| `resolveTimeout` | `0xa67c0781` | -| `setExpiryTime` | `0x30fc4cff` | -| `setMaxTimeoutDelayInSeconds` | `0x65d480fc` | -| `setTimeout` | `0x9c29ec74` | -| `setWatcherPrecompileConfig` | `0x794edeb4` | -| `setWatcherPrecompileLimits` | `0x712a6f07` | -| `startProcessingRequest` | `0x77290f24` | -| `submitRequest` | `0x16b47482` | -| `timeoutIdPrefix` | `0x96ec119f` | -| `timeoutRequests` | `0xcdf85751` | -| `transferOwnership` | `0xf2fde38b` | -| `updateTransmitter` | `0xb228a22c` | -| `watcherPrecompileConfig` | `0x8618a912` | -| `watcherPrecompileConfig__` | `0xa816cbd9` | -| `watcherPrecompileLimits` | `0xa71cd97d` | -| `watcherPrecompileLimits__` | `0xb2ad6c48` | -| `watcherPrecompile__` | `0x1de360c3` | -| `watcherProofs` | `0x3fa3166b` | +| Function | Signature | +| ------------------------------ | ------------ | +| `expiryTime` | `0x99bc0aea` | +| `getPrecompileFees` | `0xb7a3d04c` | +| `handlePayload` | `0x1d5e1d98` | +| `readFees` | `0xe06357a2` | +| `resolvePayload` | `0xea92e825` | +| `setExpiryTime` | `0x30fc4cff` | +| `setFees` | `0x3d18678e` | +| `validateAndGetPrecompileData` | `0xab172aab` | +| `watcher__` | `0x300bb063` | + +## SchedulePrecompile + +| Function | Signature | +| ------------------------------ | ------------ | +| `expiryTime` | `0x99bc0aea` | +| `getPrecompileFees` | `0xb7a3d04c` | +| `handlePayload` | `0x1d5e1d98` | +| `maxScheduleDelayInSeconds` | `0x3ef01cdb` | +| `resolvePayload` | `0xea92e825` | +| `scheduleCallbackFees` | `0x4c5b6007` | +| `scheduleFeesPerSecond` | `0x852a74c1` | +| `setExpiryTime` | `0x30fc4cff` | +| `setMaxScheduleDelayInSeconds` | `0x12953318` | +| `setScheduleCallbackFees` | `0xec8fd71e` | +| `setScheduleFeesPerSecond` | `0x28e59e57` | +| `validateAndGetPrecompileData` | `0xab172aab` | +| `watcher__` | `0x300bb063` | + +## WritePrecompile + +| Function | Signature | +| ------------------------------ | ------------ | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `chainMaxMsgValueLimit` | `0x01d1e126` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `contractFactoryPlugs` | `0x35426631` | +| `digestHashes` | `0xd1a862bf` | +| `expiryTime` | `0x99bc0aea` | +| `getDigest` | `0xdd4bf97b` | +| `getPrecompileFees` | `0xb7a3d04c` | +| `getPrevBatchDigestHash` | `0x82b35b69` | +| `handlePayload` | `0x1d5e1d98` | +| `owner` | `0x8da5cb5b` | +| `ownershipHandoverExpiresAt` | `0xfee81cf4` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `resolvePayload` | `0xea92e825` | +| `setContractFactoryPlugs` | `0xc067b6dd` | +| `setExpiryTime` | `0x30fc4cff` | +| `setFees` | `0x3d18678e` | +| `transferOwnership` | `0xf2fde38b` | +| `updateChainMaxMsgValueLimits` | `0x6a7aa6ac` | +| `uploadProof` | `0x81b48fcf` | +| `validateAndGetPrecompileData` | `0xab172aab` | +| `watcherProofs` | `0x3fa3166b` | +| `watcher__` | `0x300bb063` | +| `writeFees` | `0x5c664aeb` | diff --git a/contracts/evmx/base/AppGatewayBase.sol b/contracts/evmx/base/AppGatewayBase.sol index a8c6e7da..6451ae25 100644 --- a/contracts/evmx/base/AppGatewayBase.sol +++ b/contracts/evmx/base/AppGatewayBase.sol @@ -166,7 +166,8 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { return address(0); } - onChainAddress = IForwarder(forwarderAddresses[contractId_][chainSlug_]).getOnChainAddress(); + onChainAddress = IForwarder(forwarderAddresses[contractId_][chainSlug_]) + .getOnChainAddress(); } //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/hardhat-scripts/config/config.ts b/hardhat-scripts/config/config.ts index e0964075..022727f3 100644 --- a/hardhat-scripts/config/config.ts +++ b/hardhat-scripts/config/config.ts @@ -61,13 +61,13 @@ export const transmitter = "0x138e9840861C983DC0BB9b3e941FB7C0e9Ade320"; // Chain config export const EVMX_CHAIN_ID = EVM_CHAIN_ID_MAP[mode]; export const MAX_FEES = ethers.utils.parseEther("0.001"); +export const MAX_MSG_VALUE_LIMIT = ethers.utils.parseEther("0.001"); // Auction parameters -export const auctionEndDelaySeconds = 0; +export const AUCTION_END_DELAY_SECONDS = 0; export const BID_TIMEOUT = 600; // 10 minutes export const EXPIRY_TIME = 300; // 5 minutes export const MAX_RE_AUCTION_COUNT = 5; -export const AUCTION_MANAGER_FUNDING_AMOUNT = ethers.utils.parseEther("100"); // TestUSDC export const TEST_USDC_NAME = "testUSDC"; export const TEST_USDC_SYMBOL = "testUSDC"; @@ -76,12 +76,22 @@ export const TEST_USDC_INITIAL_SUPPLY = ethers.utils.parseEther( ); export const TEST_USDC_DECIMALS = 6; +// Fees Pool Funding Amount +export const FEES_POOL_FUNDING_AMOUNT_THRESHOLD = + ethers.utils.parseEther("10000"); + // Watcher Precompile Fees -export const QUERY_FEES = utils.parseEther("0.000001"); -export const FINALIZE_FEES = utils.parseEther("0.000001"); -export const TIMEOUT_FEES = utils.parseEther("0.000001"); -export const CALLBACK_FEES = utils.parseEther("0.000001"); +export const READ_FEES = utils.parseEther("0.000001"); +export const TRIGGER_FEES = utils.parseEther("0.000001"); +export const WRITE_FEES = utils.parseEther("0.000001"); +export const SCHEDULE_FEES_PER_SECOND = utils.parseEther("0.000001"); +export const SCHEDULE_CALLBACK_FEES = utils.parseEther("0.000001"); +export const MAX_SCHEDULE_DELAY_SECONDS = 60 * 60 * 24; // Other constants export const DEFAULT_MAX_LIMIT = 100; export const UPGRADE_VERSION = 1; + +// Transmitter constants +export const TRANSMITTER_CREDIT_THRESHOLD = ethers.utils.parseEther("100"); // 100 ETH threshold +export const TRANSMITTER_NATIVE_THRESHOLD = ethers.utils.parseEther("100"); // 100 ETH threshold diff --git a/hardhat-scripts/constants/enums.ts b/hardhat-scripts/constants/enums.ts deleted file mode 100644 index 9a349056..00000000 --- a/hardhat-scripts/constants/enums.ts +++ /dev/null @@ -1,21 +0,0 @@ -export enum CORE_CONTRACTS { - Socket = "Socket", - SocketBatcher = "SocketBatcher", - FastSwitchboard = "FastSwitchboard", - FeesPlug = "FeesPlug", - ContractFactoryPlug = "ContractFactoryPlug", - TestUSDC = "TestUSDC", - SocketFeeManager = "SocketFeeManager", -} - -export enum EVMxCoreContracts { - Watcher = "Watcher", - ReqestHandler = "ReqestHandler", - Configurations = "Configurations", - AuctionManager = "AuctionManager", - FeesManager = "FeesManager", - DeliveryHelper = "DeliveryHelper", - Forwarder = "Forwarder", - AsyncPromise = "AsyncPromise", - AddressResolver = "AddressResolver", -} diff --git a/hardhat-scripts/constants/index.ts b/hardhat-scripts/constants/index.ts index e42be831..e6869b19 100644 --- a/hardhat-scripts/constants/index.ts +++ b/hardhat-scripts/constants/index.ts @@ -1,3 +1,2 @@ export * from "./constants"; -export * from "./enums"; export * from "./types"; diff --git a/hardhat-scripts/constants/roles.ts b/hardhat-scripts/constants/roles.ts index ec875446..31a4493b 100644 --- a/hardhat-scripts/constants/roles.ts +++ b/hardhat-scripts/constants/roles.ts @@ -5,4 +5,5 @@ export enum ROLES { WATCHER_ROLE = "WATCHER_ROLE", TRANSMITTER_ROLE = "TRANSMITTER_ROLE", SWITCHBOARD_DISABLER_ROLE = "SWITCHBOARD_DISABLER_ROLE", + FEE_MANAGER_ROLE = "FEE_MANAGER_ROLE", } diff --git a/hardhat-scripts/constants/types.ts b/hardhat-scripts/constants/types.ts index 0cd19bef..afb44d41 100644 --- a/hardhat-scripts/constants/types.ts +++ b/hardhat-scripts/constants/types.ts @@ -3,3 +3,10 @@ import { ChainAddressesObj, ChainSlug } from "../../src"; export type DeploymentAddresses = { [chainSlug in ChainSlug]?: ChainAddressesObj; }; + +export interface WatcherMultiCallParams { + contractAddress: string; + data: string; + nonce: number; + signature: string; +} diff --git a/hardhat-scripts/deploy/1.deploy.ts b/hardhat-scripts/deploy/1.deploy.ts index 0f452059..c6e5a877 100644 --- a/hardhat-scripts/deploy/1.deploy.ts +++ b/hardhat-scripts/deploy/1.deploy.ts @@ -1,44 +1,40 @@ -import { ChainAddressesObj, ChainSlug } from "../../src"; import { config } from "dotenv"; -import { BigNumber, Contract, Signer, utils, Wallet } from "ethers"; +import { Contract, utils, Wallet } from "ethers"; import { formatEther } from "ethers/lib/utils"; import { ethers } from "hardhat"; +import { ChainAddressesObj, ChainSlug, Contracts } from "../../src"; import { - CORE_CONTRACTS, - DeploymentAddresses, - ETH_ADDRESS, - EVMxCoreContracts, - FAST_SWITCHBOARD_TYPE, - IMPLEMENTATION_SLOT, -} from "../constants"; -import { - DeployParams, - getAddresses, - getInstance, - getOrDeploy, - storeAddresses, -} from "../utils"; -import { getSocketSigner, getWatcherSigner } from "../utils/sign"; -import { - auctionEndDelaySeconds, + AUCTION_END_DELAY_SECONDS, BID_TIMEOUT, chains, EVMX_CHAIN_ID, EXPIRY_TIME, logConfig, - DEFAULT_MAX_LIMIT, MAX_RE_AUCTION_COUNT, + MAX_SCHEDULE_DELAY_SECONDS, mode, - TEST_USDC_INITIAL_SUPPLY, + READ_FEES, + SCHEDULE_CALLBACK_FEES, + SCHEDULE_FEES_PER_SECOND, TEST_USDC_DECIMALS, + TEST_USDC_INITIAL_SUPPLY, TEST_USDC_NAME, TEST_USDC_SYMBOL, - QUERY_FEES, - FINALIZE_FEES, - TIMEOUT_FEES, - CALLBACK_FEES, - AUCTION_MANAGER_FUNDING_AMOUNT, + TRIGGER_FEES, + WRITE_FEES, } from "../config/config"; +import { + DeploymentAddresses, + FAST_SWITCHBOARD_TYPE, + IMPLEMENTATION_SLOT, +} from "../constants"; +import { + DeployParams, + getAddresses, + getOrDeploy, + storeAddresses, +} from "../utils"; +import { getSocketSigner, getWatcherSigner } from "../utils/sign"; config(); let EVMxOwner: string; @@ -111,169 +107,152 @@ const deployEVMxContracts = async () => { ); deployUtils.addresses[contractName] = proxyFactory.address; - deployUtils = await deployContractWithProxy( - EVMxCoreContracts.AddressResolver, - `contracts/protocol/AddressResolver.sol`, + const feesPool = await getOrDeploy( + Contracts.FeesPool, + Contracts.FeesPool, + "contracts/evmx/fees/FeesPool.sol", [EVMxOwner], - proxyFactory, deployUtils ); - - const addressResolver = await ethers.getContractAt( - EVMxCoreContracts.AddressResolver, - deployUtils.addresses[EVMxCoreContracts.AddressResolver] - ); + deployUtils.addresses[Contracts.FeesPool] = feesPool.address; deployUtils = await deployContractWithProxy( - EVMxCoreContracts.ReqestHandler, - `contracts/protocol/watcherPrecompile/ReqestHandler.sol`, - [EVMxOwner, addressResolver.address, DEFAULT_MAX_LIMIT], + Contracts.AddressResolver, + `contracts/evmx/helpers/AddressResolver.sol`, + [EVMxOwner], proxyFactory, deployUtils ); - deployUtils = await deployContractWithProxy( - EVMxCoreContracts.Configurations, - `contracts/protocol/watcherPrecompile/Configurations.sol`, - [EVMxOwner, addressResolver.address, EVMX_CHAIN_ID], - proxyFactory, - deployUtils + const addressResolver = await ethers.getContractAt( + Contracts.AddressResolver, + deployUtils.addresses[Contracts.AddressResolver] ); deployUtils = await deployContractWithProxy( - EVMxCoreContracts.Watcher, - `contracts/protocol/watcherPrecompile/core/Watcher.sol`, + Contracts.FeesManager, + `contracts/evmx/fees/FeesManager.sol`, [ - EVMxOwner, - addressResolver.address, - EXPIRY_TIME, EVMX_CHAIN_ID, - deployUtils.addresses[EVMxCoreContracts.ReqestHandler], - deployUtils.addresses[EVMxCoreContracts.Configurations], + addressResolver.address, + feesPool.address, + EVMxOwner, + FAST_SWITCHBOARD_TYPE, ], proxyFactory, deployUtils ); deployUtils = await deployContractWithProxy( - EVMxCoreContracts.FeesManager, - `contracts/protocol/payload-delivery/FeesManager.sol`, - [ - addressResolver.address, - EVMxOwner, - EVMX_CHAIN_ID, - FAST_SWITCHBOARD_TYPE, - ], + Contracts.AsyncDeployer, + `contracts/evmx/helpers/AsyncDeployer.sol`, + [EVMxOwner, addressResolver.address], proxyFactory, deployUtils ); - const feesManagerAddress = - deployUtils.addresses[EVMxCoreContracts.FeesManager]; - - console.log("Deploying DeliveryHelper"); deployUtils = await deployContractWithProxy( - EVMxCoreContracts.DeliveryHelper, - `contracts/protocol/payload-delivery/app-gateway/DeliveryHelper.sol`, - [addressResolver.address, EVMxOwner, BID_TIMEOUT], + Contracts.Watcher, + `contracts/evmx/watcher/Watcher.sol`, + [EVMX_CHAIN_ID, TRIGGER_FEES, EVMxOwner, addressResolver.address], proxyFactory, deployUtils ); - deployUtils = await deployContractWithProxy( - EVMxCoreContracts.AuctionManager, - `contracts/protocol/payload-delivery/AuctionManager.sol`, + const auctionManager = await getOrDeploy( + Contracts.AuctionManager, + Contracts.AuctionManager, + "contracts/evmx/AuctionManager.sol", [ EVMX_CHAIN_ID, - auctionEndDelaySeconds, + BID_TIMEOUT, + MAX_RE_AUCTION_COUNT, + AUCTION_END_DELAY_SECONDS, addressResolver.address, EVMxOwner, - MAX_RE_AUCTION_COUNT, ], - proxyFactory, deployUtils ); + deployUtils.addresses[Contracts.AuctionManager] = auctionManager.address; - await updateContractSettings( - addressResolver, - "deliveryHelper", - "setDeliveryHelper", - deployUtils.addresses[EVMxCoreContracts.DeliveryHelper], - deployUtils.signer - ); - - await updateContractSettings( - addressResolver, - "feesManager", - "setFeesManager", - feesManagerAddress, - deployUtils.signer + const deployForwarder = await getOrDeploy( + Contracts.DeployForwarder, + Contracts.DeployForwarder, + "contracts/evmx/helpers/DeployForwarder.sol", + [addressResolver.address, FAST_SWITCHBOARD_TYPE], + deployUtils ); - - await updateContractSettings( - addressResolver, - "defaultAuctionManager", - "setDefaultAuctionManager", - deployUtils.addresses[EVMxCoreContracts.AuctionManager], - deployUtils.signer + deployUtils.addresses[Contracts.DeployForwarder] = + deployForwarder.address; + + const configurations = await getOrDeploy( + Contracts.Configurations, + Contracts.Configurations, + "contracts/evmx/watcher/Configurations.sol", + [deployUtils.addresses[Contracts.Watcher], EVMxOwner], + deployUtils ); + deployUtils.addresses[Contracts.Configurations] = configurations.address; - await updateContractSettings( - addressResolver, - "watcherPrecompile__", - "setWatcherPrecompile", - deployUtils.addresses[EVMxCoreContracts.Watcher], - deployUtils.signer + const requestHandler = await getOrDeploy( + Contracts.RequestHandler, + Contracts.RequestHandler, + "contracts/evmx/watcher/RequestHandler.sol", + [EVMxOwner, addressResolver.address], + deployUtils ); + deployUtils.addresses[Contracts.RequestHandler] = requestHandler.address; - let watcherPrecompileLimits = await getInstance( - EVMxCoreContracts.ReqestHandler, - deployUtils.addresses[EVMxCoreContracts.ReqestHandler] - ); - watcherPrecompileLimits = watcherPrecompileLimits.connect( - deployUtils.signer - ); - await updateContractSettings( - watcherPrecompileLimits, - "queryFees", - "setQueryFees", - QUERY_FEES, - deployUtils.signer + const promiseResolver = await getOrDeploy( + Contracts.PromiseResolver, + Contracts.PromiseResolver, + "contracts/evmx/watcher/PromiseResolver.sol", + [deployUtils.addresses[Contracts.Watcher]], + deployUtils ); + deployUtils.addresses[Contracts.PromiseResolver] = + promiseResolver.address; - await updateContractSettings( - watcherPrecompileLimits, - "finalizeFees", - "setFinalizeFees", - FINALIZE_FEES, - deployUtils.signer + const writePrecompile = await getOrDeploy( + Contracts.WritePrecompile, + Contracts.WritePrecompile, + "contracts/evmx/watcher/precompiles/WritePrecompile.sol", + [ + EVMxOwner, + deployUtils.addresses[Contracts.Watcher], + WRITE_FEES, + EXPIRY_TIME, + ], + deployUtils ); - - await updateContractSettings( - watcherPrecompileLimits, - "timeoutFees", - "setTimeoutFees", - TIMEOUT_FEES, - deployUtils.signer + deployUtils.addresses[Contracts.WritePrecompile] = + writePrecompile.address; + + const readPrecompile = await getOrDeploy( + Contracts.ReadPrecompile, + Contracts.ReadPrecompile, + "contracts/evmx/watcher/precompiles/ReadPrecompile.sol", + [deployUtils.addresses[Contracts.Watcher], READ_FEES, EXPIRY_TIME], + deployUtils ); + deployUtils.addresses[Contracts.ReadPrecompile] = readPrecompile.address; - await updateContractSettings( - watcherPrecompileLimits, - "callBackFees", - "setCallBackFees", - CALLBACK_FEES, - deployUtils.signer + const schedulePrecompile = await getOrDeploy( + Contracts.SchedulePrecompile, + Contracts.SchedulePrecompile, + "contracts/evmx/watcher/precompiles/SchedulePrecompile.sol", + [ + deployUtils.addresses[Contracts.Watcher], + MAX_SCHEDULE_DELAY_SECONDS, + SCHEDULE_FEES_PER_SECOND, + SCHEDULE_CALLBACK_FEES, + EXPIRY_TIME, + ], + deployUtils ); + deployUtils.addresses[Contracts.SchedulePrecompile] = + schedulePrecompile.address; - const feesManager = await getInstance( - EVMxCoreContracts.FeesManager, - deployUtils.addresses[EVMxCoreContracts.FeesManager] - ); - await fundAuctionManager( - feesManager.connect(deployUtils.signer), - deployUtils.addresses[EVMxCoreContracts.AuctionManager], - deployUtils.signer - ); deployUtils.addresses.startBlock = (deployUtils.addresses.startBlock ? deployUtils.addresses.startBlock @@ -289,56 +268,6 @@ const deployEVMxContracts = async () => { } }; -export const fundAuctionManager = async ( - feesManager: Contract, - auctionManagerAddress: string, - watcherSigner: Signer -) => { - const currentCredits = await feesManager.getAvailableCredits( - auctionManagerAddress - ); - console.log("Current credits:", currentCredits.toString()); - if (currentCredits.gte(BigNumber.from(AUCTION_MANAGER_FUNDING_AMOUNT))) { - console.log( - `Auction manager ${auctionManagerAddress} already has credits, skipping funding` - ); - return; - } - const signatureNonce = Date.now(); - const digest = ethers.utils.keccak256( - ethers.utils.defaultAbiCoder.encode( - ["address", "uint32", "address", "uint256", "address", "uint32"], - [ - auctionManagerAddress, - EVMX_CHAIN_ID, - ETH_ADDRESS, - AUCTION_MANAGER_FUNDING_AMOUNT, - feesManager.address, - EVMX_CHAIN_ID, - ] - ) - ); - const signature = await watcherSigner.signMessage( - ethers.utils.arrayify(digest) - ); - const tx = await feesManager - .connect(watcherSigner) - .depositCredits( - auctionManagerAddress, - EVMX_CHAIN_ID, - ETH_ADDRESS, - signatureNonce, - signature, - { - value: AUCTION_MANAGER_FUNDING_AMOUNT, - } - ); - console.log( - `Funding auction manager ${auctionManagerAddress} with ${AUCTION_MANAGER_FUNDING_AMOUNT} ETH, txHash: `, - tx.hash - ); - await tx.wait(); -}; const deploySocketContracts = async () => { try { let addresses: DeploymentAddresses; @@ -367,42 +296,42 @@ const deploySocketContracts = async () => { currentChainSlug: chain as ChainSlug, }; - let contractName = CORE_CONTRACTS.Socket; + let contractName = Contracts.Socket; const socket: Contract = await getOrDeploy( contractName, contractName, - `contracts/protocol/socket/${contractName}.sol`, + `contracts/protocol/${contractName}.sol`, [chain as ChainSlug, socketOwner, "EVMX"], deployUtils ); deployUtils.addresses[contractName] = socket.address; - contractName = CORE_CONTRACTS.SocketBatcher; + contractName = Contracts.SocketBatcher; const batcher: Contract = await getOrDeploy( contractName, contractName, - `contracts/protocol/socket/${contractName}.sol`, + `contracts/protocol/${contractName}.sol`, [socketOwner, socket.address], deployUtils ); deployUtils.addresses[contractName] = batcher.address; - contractName = CORE_CONTRACTS.FastSwitchboard; + contractName = Contracts.FastSwitchboard; const sb: Contract = await getOrDeploy( contractName, contractName, - `contracts/protocol/socket/switchboard/${contractName}.sol`, + `contracts/protocol/switchboard/${contractName}.sol`, [chain as ChainSlug, socket.address, socketOwner], deployUtils ); deployUtils.addresses[contractName] = sb.address; - contractName = CORE_CONTRACTS.TestUSDC; + contractName = Contracts.TestUSDC; const testUSDC: Contract = await getOrDeploy( contractName, contractName, - `contracts/helpers/${contractName}.sol`, + `contracts/evmx/mocks/${contractName}.sol`, [ TEST_USDC_NAME, TEST_USDC_SYMBOL, @@ -414,23 +343,21 @@ const deploySocketContracts = async () => { ); deployUtils.addresses[contractName] = testUSDC.address; - contractName = CORE_CONTRACTS.FeesPlug; + contractName = Contracts.FeesPlug; const feesPlug: Contract = await getOrDeploy( contractName, contractName, - `contracts/protocol/payload-delivery/${contractName}.sol`, + `contracts/evmx/plugs/${contractName}.sol`, [socket.address, socketOwner], deployUtils ); deployUtils.addresses[contractName] = feesPlug.address; - await whitelistToken(feesPlug, testUSDC.address, deployUtils.signer); - - contractName = CORE_CONTRACTS.ContractFactoryPlug; + contractName = Contracts.ContractFactoryPlug; const contractFactoryPlug: Contract = await getOrDeploy( contractName, contractName, - `contracts/protocol/payload-delivery/${contractName}.sol`, + `contracts/evmx/plugs/${contractName}.sol`, [socket.address, socketOwner], deployUtils ); @@ -456,50 +383,6 @@ const deploySocketContracts = async () => { } }; -async function whitelistToken( - feesPlug: Contract, - tokenAddress: string, - signer: Signer -) { - const isWhitelisted = await feesPlug - .connect(signer) - .whitelistedTokens(tokenAddress); - if (!isWhitelisted) { - const tx = await feesPlug.connect(signer).whitelistToken(tokenAddress); - console.log( - `Whitelisting token ${tokenAddress} for ${feesPlug.address}`, - tx.hash - ); - await tx.wait(); - } -} - -async function updateContractSettings( - contract: Contract, - getterMethod: string, - setterMethod: string, - requiredValue: string | BigNumber, - signer: Signer -) { - const currentValue = await contract.connect(signer)[getterMethod](); - - if ( - (typeof currentValue === "string" && - currentValue.toLowerCase() !== String(requiredValue).toLowerCase()) || - (BigNumber.isBigNumber(currentValue) && - currentValue.toString() !== requiredValue.toString()) - ) { - console.log({ - setterMethod, - current: currentValue, - required: requiredValue, - }); - const tx = await contract.connect(signer)[setterMethod](requiredValue); - console.log(`Setting ${getterMethod} for ${contract.address} to`, tx.hash); - await tx.wait(); - } -} - /** * @notice Deploys a contract implementation and its transparent proxy, then initializes it * @param contractName The name of the contract to deploy diff --git a/hardhat-scripts/deploy/2.roles.ts b/hardhat-scripts/deploy/2.roles.ts index d313e104..a13706c0 100644 --- a/hardhat-scripts/deploy/2.roles.ts +++ b/hardhat-scripts/deploy/2.roles.ts @@ -3,11 +3,7 @@ dotenvConfig(); import { Wallet } from "ethers"; import { chains, EVMX_CHAIN_ID, mode, watcher, transmitter } from "../config"; -import { - CORE_CONTRACTS, - DeploymentAddresses, - EVMxCoreContracts, -} from "../constants"; +import { DeploymentAddresses } from "../constants"; import { getAddresses, getInstance, @@ -15,7 +11,7 @@ import { getRoleHash, overrides, } from "../utils"; -import { ChainAddressesObj, ChainSlug } from "../../src"; +import { ChainAddressesObj, ChainSlug, Contracts } from "../../src"; import { ROLES } from "../constants/roles"; import { getWatcherSigner, getSocketSigner } from "../utils/sign"; export const REQUIRED_ROLES = { @@ -30,7 +26,7 @@ export const REQUIRED_ROLES = { }; async function setRoleForContract( - contractName: CORE_CONTRACTS | EVMxCoreContracts, + contractName: Contracts, contractAddress: string | number, targetAddress: string, roleName: string, @@ -86,13 +82,13 @@ async function setRolesForOnChain( for (const roleName of roles) { const targetAddress = - contractName === CORE_CONTRACTS.FastSwitchboard && + contractName === Contracts.FastSwitchboard && roleName === ROLES.WATCHER_ROLE ? watcher : signer.address; await setRoleForContract( - contractName as CORE_CONTRACTS, + contractName as Contracts, contractAddress, targetAddress, roleName, @@ -108,17 +104,26 @@ async function setRolesForEVMx(addresses: DeploymentAddresses) { {}) as ChainAddressesObj; const signer = await getSigner(EVMX_CHAIN_ID, true); - const contractAddress = chainAddresses[EVMxCoreContracts.Watcher]; + const contractAddress = chainAddresses[Contracts.Watcher]; if (!contractAddress) return; await setRoleForContract( - EVMxCoreContracts.AuctionManager, - chainAddresses[EVMxCoreContracts.AuctionManager], + Contracts.AuctionManager, + chainAddresses[Contracts.AuctionManager], transmitter, ROLES.TRANSMITTER_ROLE, signer, EVMX_CHAIN_ID ); + + await setRoleForContract( + Contracts.FeesPool, + chainAddresses[Contracts.FeesPool], + chainAddresses[Contracts.FeesManager], + ROLES.FEE_MANAGER_ROLE, + signer, + EVMX_CHAIN_ID + ); } export const main = async () => { diff --git a/hardhat-scripts/deploy/3.configureChains.ts b/hardhat-scripts/deploy/3.configureChains.ts new file mode 100644 index 00000000..7c090c45 --- /dev/null +++ b/hardhat-scripts/deploy/3.configureChains.ts @@ -0,0 +1,182 @@ +import { config as dotenvConfig } from "dotenv"; +dotenvConfig(); + +import { Contract, Signer, Wallet } from "ethers"; +import { ChainAddressesObj, ChainSlug, Contracts } from "../../src"; +import { chains, EVMX_CHAIN_ID, MAX_MSG_VALUE_LIMIT, mode } from "../config"; +import { DeploymentAddresses, FAST_SWITCHBOARD_TYPE } from "../constants"; +import { + getAddresses, + getInstance, + getSocketSigner, + getWatcherSigner, + updateContractSettings, +} from "../utils"; + +export const main = async () => { + let addresses: DeploymentAddresses; + try { + console.log("Configuring chain contracts"); + addresses = getAddresses(mode) as unknown as DeploymentAddresses; + await configureChains(addresses); + } catch (error) { + console.log("Error:", error); + } +}; + +export const configureChains = async (addresses: DeploymentAddresses) => { + for (const chain of chains) { + let chainAddresses: ChainAddressesObj = addresses[chain] + ? (addresses[chain] as ChainAddressesObj) + : ({} as ChainAddressesObj); + + const signer: Wallet = getSocketSigner(chain as ChainSlug); + + const socketContract = ( + await getInstance(Contracts.Socket, chainAddresses[Contracts.Socket]) + ).connect(signer); + + await registerSb( + chainAddresses[Contracts.FastSwitchboard], + signer, + socketContract + ); + + await whitelistToken( + chainAddresses[Contracts.FeesPlug], + chainAddresses[Contracts.TestUSDC], + signer + ); + await setMaxMsgValueLimit(chain); + + await setOnchainContracts(chain, addresses); + } +}; + +export const setMaxMsgValueLimit = async (chain: number) => { + console.log("Setting max msg value limit"); + const signer: Wallet = getWatcherSigner(); + await updateContractSettings( + EVMX_CHAIN_ID, + Contracts.WritePrecompile, + "chainMaxMsgValueLimit", + [chain], + MAX_MSG_VALUE_LIMIT, + "updateChainMaxMsgValueLimits", + [chain, MAX_MSG_VALUE_LIMIT], + signer + ); +}; + +async function setOnchainContracts( + chain: number, + addresses: DeploymentAddresses +) { + console.log("Setting onchain contracts"); + const signer: Wallet = getWatcherSigner(); + const chainAddresses = addresses[chain] as ChainAddressesObj; + + await updateContractSettings( + EVMX_CHAIN_ID, + Contracts.Configurations, + "switchboards", + [chain, FAST_SWITCHBOARD_TYPE], + chainAddresses[Contracts.FastSwitchboard], + "setSwitchboard", + [chain, FAST_SWITCHBOARD_TYPE, chainAddresses[Contracts.FastSwitchboard]], + signer + ); + await updateContractSettings( + EVMX_CHAIN_ID, + Contracts.Configurations, + "sockets", + [chain], + chainAddresses[Contracts.Socket], + "setSocket", + [chain, chainAddresses[Contracts.Socket]], + signer + ); + + await updateContractSettings( + EVMX_CHAIN_ID, + Contracts.FeesManager, + "feesPlugs", + [chain], + chainAddresses[Contracts.FeesPlug], + "setFeesPlug", + [chain, chainAddresses[Contracts.FeesPlug]], + signer + ); + + await updateContractSettings( + EVMX_CHAIN_ID, + Contracts.WritePrecompile, + "contractFactoryPlugs", + [chain], + chainAddresses[Contracts.ContractFactoryPlug], + "setContractFactoryPlugs", + [chain, chainAddresses[Contracts.ContractFactoryPlug]], + signer + ); +} + +const registerSb = async ( + sbAddress: string, + signer: Wallet, + socket: Contract +) => { + try { + console.log("Registering switchboard"); + // used fast switchboard here as all have same function signature + const switchboard = ( + await getInstance(Contracts.FastSwitchboard, sbAddress) + ).connect(signer); + + // send overrides while reading capacitor to avoid errors on mantle chain + // some chains give balance error if gas price is used with from address as zero + // therefore override from address as well + let sb = await socket.isValidSwitchboard(sbAddress, { + from: signer.address, + }); + + if (Number(sb) == 0) { + const registerTx = await switchboard.registerSwitchboard(); + console.log(`Registering Switchboard ${sbAddress}: ${registerTx.hash}`); + await registerTx.wait(); + } + } catch (error) { + throw error; + } +}; + +export const whitelistToken = async ( + feesPlugAddress: string, + tokenAddress: string, + signer: Signer +) => { + console.log("Whitelisting token"); + const feesPlugContract = await getInstance( + Contracts.FeesPlug, + feesPlugAddress + ); + const isWhitelisted = await feesPlugContract + .connect(signer) + .whitelistedTokens(tokenAddress); + if (!isWhitelisted) { + const tx = await feesPlugContract + .connect(signer) + .whitelistToken(tokenAddress); + console.log( + `Whitelisting token ${tokenAddress} for ${feesPlugContract.address}`, + tx.hash + ); + await tx.wait(); + } +}; + +main() + .then(() => process.exit(0)) + .catch((error: Error) => { + console.error(error); + process.exit(1); + }); diff --git a/hardhat-scripts/deploy/3.upgradeManagers.ts b/hardhat-scripts/deploy/3.upgradeManagers.ts deleted file mode 100644 index 92c24b1e..00000000 --- a/hardhat-scripts/deploy/3.upgradeManagers.ts +++ /dev/null @@ -1,143 +0,0 @@ -import { ChainAddressesObj, ChainSlug, EVMxAddressesObj } from "../../src"; - -import { config as dotenvConfig } from "dotenv"; -dotenvConfig(); - -import { Wallet } from "ethers"; -import { chains, EVMX_CHAIN_ID, mode } from "../config"; -import { - CORE_CONTRACTS, - DeploymentAddresses, - EVMxCoreContracts, - FAST_SWITCHBOARD_TYPE, -} from "../constants"; -import { - getAddresses, - getInstance, - getSocketSigner, - getWatcherSigner, - storeAddresses, -} from "../utils"; - -export const main = async () => { - let addresses: DeploymentAddresses; - try { - console.log("Upgrading Managers"); - addresses = getAddresses(mode) as unknown as DeploymentAddresses; - - for (const chain of chains) { - let chainAddresses: ChainAddressesObj = addresses[chain] - ? (addresses[chain] as ChainAddressesObj) - : ({} as ChainAddressesObj); - - const signer: Wallet = getSocketSigner(chain as ChainSlug); - - const socketContract = ( - await getInstance( - CORE_CONTRACTS.Socket, - chainAddresses[CORE_CONTRACTS.Socket] - ) - ).connect(signer); - - await registerSb( - chainAddresses[CORE_CONTRACTS.FastSwitchboard], - signer, - socketContract - ); - - await setOnchainContracts(chain, addresses); - - await storeAddresses(chainAddresses, chain, mode); - } - } catch (error) { - console.log("Error:", error); - } -}; - -async function setOnchainContracts(chain: number, addresses) { - const signer: Wallet = getWatcherSigner(); - const EVMxAddresses = addresses[EVMX_CHAIN_ID] as EVMxAddressesObj; - const chainAddresses = addresses[chain] as ChainAddressesObj; - const watcherPrecompileConfig = ( - await getInstance( - EVMxCoreContracts.Configurations, - EVMxAddresses[EVMxCoreContracts.Configurations] - ) - ).connect(signer); - - const sbAddress = chainAddresses[CORE_CONTRACTS.FastSwitchboard]; - const socketAddress = chainAddresses[CORE_CONTRACTS.Socket]; - const contractFactoryPlugAddress = - chainAddresses[CORE_CONTRACTS.ContractFactoryPlug]; - const feesPlugAddress = chainAddresses[CORE_CONTRACTS.FeesPlug]; - - const currentSbAddress = await watcherPrecompileConfig.switchboards( - chain, - FAST_SWITCHBOARD_TYPE - ); - const currentSocket = await watcherPrecompileConfig.sockets(chain); - const currentContractFactoryPlug = - await watcherPrecompileConfig.contractFactoryPlug(chain); - const currentFeesPlug = await watcherPrecompileConfig.feesPlug(chain); - - console.log("Setting onchain contracts for", chain); - if ( - currentSocket.toLowerCase() !== socketAddress.toLowerCase() || - currentContractFactoryPlug.toLowerCase() !== - contractFactoryPlugAddress.toLowerCase() || - currentFeesPlug.toLowerCase() !== feesPlugAddress.toLowerCase() - ) { - const tx = await watcherPrecompileConfig - .connect(signer) - .setOnChainContracts( - chain, - socketAddress, - contractFactoryPlugAddress, - feesPlugAddress - ); - - console.log(`Setting onchain contracts for ${chain}, txHash: `, tx.hash); - await tx.wait(); - } - - console.log("Setting switchboard for", chain); - if (currentSbAddress.toLowerCase() !== sbAddress.toLowerCase()) { - const tx = await watcherPrecompileConfig - .connect(signer) - .setSwitchboard(chain, FAST_SWITCHBOARD_TYPE, sbAddress); - - console.log(`Setting switchboard for ${chain}, txHash: `, tx.hash); - await tx.wait(); - } -} - -const registerSb = async (sbAddress, signer, socket) => { - try { - // used fast switchboard here as all have same function signature - const switchboard = ( - await getInstance(CORE_CONTRACTS.FastSwitchboard, sbAddress) - ).connect(signer); - - // send overrides while reading capacitor to avoid errors on mantle chain - // some chains give balance error if gas price is used with from address as zero - // therefore override from address as well - let sb = await socket.isValidSwitchboard(sbAddress, { - from: signer.address, - }); - - if (Number(sb) == 0) { - const registerTx = await switchboard.registerSwitchboard(); - console.log(`Registering Switchboard ${sbAddress}: ${registerTx.hash}`); - await registerTx.wait(); - } - } catch (error) { - throw error; - } -}; - -main() - .then(() => process.exit(0)) - .catch((error: Error) => { - console.error(error); - process.exit(1); - }); diff --git a/hardhat-scripts/deploy/4.configureEVMx.ts b/hardhat-scripts/deploy/4.configureEVMx.ts new file mode 100644 index 00000000..e12bd950 --- /dev/null +++ b/hardhat-scripts/deploy/4.configureEVMx.ts @@ -0,0 +1,162 @@ +import { config as dotenvConfig } from "dotenv"; +dotenvConfig(); + +import { + ChainAddressesObj, + ChainSlug, + Contracts, + EVMxAddressesObj, + READ, + SCHEDULE, + WRITE, +} from "../../src"; +import { Contract, Wallet } from "ethers"; +import { chains, EVMX_CHAIN_ID, mode } from "../config"; +import { DeploymentAddresses, FAST_SWITCHBOARD_TYPE } from "../constants"; +import { + getAddresses, + getInstance, + getSocketSigner, + getWatcherSigner, + updateContractSettings, +} from "../utils"; + +export const main = async () => { + let addresses: DeploymentAddresses; + try { + console.log("Configuring EVMx contracts"); + addresses = getAddresses(mode) as unknown as DeploymentAddresses; + const evmxAddresses = addresses[EVMX_CHAIN_ID] as EVMxAddressesObj; + + await configureEVMx(evmxAddresses); + } catch (error) { + console.log("Error:", error); + } +}; + +export const configureEVMx = async (evmxAddresses: EVMxAddressesObj) => { + const signer: Wallet = getWatcherSigner(); + + await updateContractSettings( + EVMX_CHAIN_ID, + Contracts.AddressResolver, + "asyncDeployer__", + [], + evmxAddresses[Contracts.AsyncDeployer], + "setAsyncDeployer", + [evmxAddresses[Contracts.AsyncDeployer]], + signer + ); + + await updateContractSettings( + EVMX_CHAIN_ID, + Contracts.AddressResolver, + "feesManager__", + [], + evmxAddresses[Contracts.FeesManager], + "setFeesManager", + [evmxAddresses[Contracts.FeesManager]], + signer + ); + + await updateContractSettings( + EVMX_CHAIN_ID, + Contracts.AddressResolver, + "defaultAuctionManager", + [], + evmxAddresses[Contracts.AuctionManager], + "setDefaultAuctionManager", + [evmxAddresses[Contracts.AuctionManager]], + signer + ); + + await updateContractSettings( + EVMX_CHAIN_ID, + Contracts.AddressResolver, + "watcher__", + [], + evmxAddresses[Contracts.Watcher], + "setWatcher", + [evmxAddresses[Contracts.Watcher]], + signer + ); + + await updateContractSettings( + EVMX_CHAIN_ID, + Contracts.AddressResolver, + "deployForwarder__", + [], + evmxAddresses[Contracts.DeployForwarder], + "setDeployForwarder", + [evmxAddresses[Contracts.DeployForwarder]], + signer + ); + + await updateContractSettings( + EVMX_CHAIN_ID, + Contracts.RequestHandler, + "precompiles", + [READ], + evmxAddresses[Contracts.ReadPrecompile], + "setPrecompile", + [READ, evmxAddresses[Contracts.ReadPrecompile]], + signer + ); + + await updateContractSettings( + EVMX_CHAIN_ID, + Contracts.RequestHandler, + "precompiles", + [WRITE], + evmxAddresses[Contracts.WritePrecompile], + "setPrecompile", + [WRITE, evmxAddresses[Contracts.WritePrecompile]], + signer + ); + + await updateContractSettings( + EVMX_CHAIN_ID, + Contracts.RequestHandler, + "precompiles", + [SCHEDULE], + evmxAddresses[Contracts.SchedulePrecompile], + "setPrecompile", + [SCHEDULE, evmxAddresses[Contracts.SchedulePrecompile]], + signer + ); + + await setWatcherCoreContracts(evmxAddresses); +}; + +export const setWatcherCoreContracts = async ( + evmxAddresses: EVMxAddressesObj +) => { + const watcherContract = ( + await getInstance(Contracts.Watcher, evmxAddresses[Contracts.Watcher]) + ).connect(getWatcherSigner()); + const requestHandlerSet = await watcherContract.requestHandler__(); + const PromiseResolverSet = await watcherContract.promiseResolver__(); + const ConfigurationsSet = await watcherContract.configurations__(); + + if ( + requestHandlerSet !== evmxAddresses[Contracts.RequestHandler] || + PromiseResolverSet !== evmxAddresses[Contracts.PromiseResolver] || + ConfigurationsSet !== evmxAddresses[Contracts.Configurations] + ) { + console.log("Setting watcher core contracts"); + const tx = await watcherContract.setCoreContracts( + evmxAddresses[Contracts.RequestHandler], + evmxAddresses[Contracts.Configurations], + evmxAddresses[Contracts.PromiseResolver] + ); + console.log("Watcher core contracts set tx: ", tx.hash); + await tx.wait(); + } +}; + +main() + .then(() => process.exit(0)) + .catch((error: Error) => { + console.error(error); + process.exit(1); + }); diff --git a/hardhat-scripts/deploy/5.fundTransfers.ts b/hardhat-scripts/deploy/5.fundTransfers.ts new file mode 100644 index 00000000..584e2ef2 --- /dev/null +++ b/hardhat-scripts/deploy/5.fundTransfers.ts @@ -0,0 +1,47 @@ +import { config } from "dotenv"; +import { Signer } from "ethers"; +import { Contracts } from "../../src"; +import { + EVMX_CHAIN_ID, + FEES_POOL_FUNDING_AMOUNT_THRESHOLD, + mode, +} from "../config/config"; +import { getAddresses, getWatcherSigner } from "../utils"; +config(); + +export const fundFeesPool = async (watcherSigner: Signer) => { + const addresses = getAddresses(mode); + const feesPoolAddress = addresses[EVMX_CHAIN_ID][Contracts.FeesPool]; + const feesPoolBalance = await watcherSigner.provider!.getBalance( + feesPoolAddress + ); + console.log({ + feesPoolAddress, + feesPoolBalance, + FEES_POOL_FUNDING_AMOUNT_THRESHOLD, + }); + if (feesPoolBalance.gte(FEES_POOL_FUNDING_AMOUNT_THRESHOLD)) { + console.log( + `Fees pool ${feesPoolAddress} already has sufficient balance, skipping funding` + ); + return; + } + + const tx = await watcherSigner.sendTransaction({ + to: feesPoolAddress, + value: FEES_POOL_FUNDING_AMOUNT_THRESHOLD, + }); + console.log( + `Funding fees pool ${feesPoolAddress} with ${FEES_POOL_FUNDING_AMOUNT_THRESHOLD} ETH, txHash: `, + tx.hash + ); + await tx.wait(); +}; + +const main = async () => { + console.log("Fund transfers"); + const watcherSigner = getWatcherSigner(); + await fundFeesPool(watcherSigner); +}; + +main(); diff --git a/hardhat-scripts/deploy/4.connect.ts b/hardhat-scripts/deploy/6.connect.ts similarity index 77% rename from hardhat-scripts/deploy/4.connect.ts rename to hardhat-scripts/deploy/6.connect.ts index 59efc2a6..8e96da51 100644 --- a/hardhat-scripts/deploy/4.connect.ts +++ b/hardhat-scripts/deploy/6.connect.ts @@ -1,25 +1,39 @@ import { constants, Contract, ethers, Wallet } from "ethers"; -import { ChainAddressesObj, ChainSlug } from "../../src"; +import { ChainAddressesObj, ChainSlug, Contracts } from "../../src"; import { chains, EVMX_CHAIN_ID, mode } from "../config"; -import { - CORE_CONTRACTS, - DeploymentAddresses, - EVMxCoreContracts, -} from "../constants"; +import { DeploymentAddresses } from "../constants"; import { getAddresses, getInstance, getSocketSigner, overrides, } from "../utils"; -import { getWatcherSigner, signWatcherMessage } from "../utils/sign"; -const plugs = [CORE_CONTRACTS.ContractFactoryPlug, CORE_CONTRACTS.FeesPlug]; +import { + getWatcherSigner, + sendWatcherMultiCallWithNonce, + signWatcherMessage, +} from "../utils/sign"; + +const plugs = [Contracts.ContractFactoryPlug, Contracts.FeesPlug]; export type AppGatewayConfig = { + plugConfig: { + appGatewayId: string; + switchboard: string; + }; plug: string; - appGatewayId: string; - switchboard: string; chainSlug: number; }; + +// Main function to connect plugs on all chains +export const main = async () => { + try { + await connectPlugsOnSocket(); + await updateConfigEVMx(); + } catch (error) { + console.log("Error while sending transaction", error); + } +}; + // Maps plug contracts to their corresponding app gateways export const getAppGatewayId = ( plug: string, @@ -27,12 +41,12 @@ export const getAppGatewayId = ( ) => { let address: string = ""; switch (plug) { - case CORE_CONTRACTS.ContractFactoryPlug: - address = addresses?.[EVMX_CHAIN_ID]?.[EVMxCoreContracts.DeliveryHelper]; - if (!address) throw new Error(`DeliveryHelper not found on EVMX`); + case Contracts.ContractFactoryPlug: + address = addresses?.[EVMX_CHAIN_ID]?.[Contracts.WritePrecompile]; + if (!address) throw new Error(`WritePrecompile not found on EVMX`); return ethers.utils.hexZeroPad(address, 32); - case CORE_CONTRACTS.FeesPlug: - address = addresses?.[EVMX_CHAIN_ID]?.[EVMxCoreContracts.FeesManager]; + case Contracts.FeesPlug: + address = addresses?.[EVMX_CHAIN_ID]?.[Contracts.FeesManager]; if (!address) throw new Error(`FeesManager not found on EVMX`); return ethers.utils.hexZeroPad(address, 32); default: @@ -95,11 +109,11 @@ async function connectPlug( socketSigner ); const socket = ( - await getInstance(CORE_CONTRACTS.Socket, addr[CORE_CONTRACTS.Socket]) + await getInstance(Contracts.Socket, addr[Contracts.Socket]) ).connect(socketSigner); // Get switchboard and app gateway addresses - const switchboard = addr[CORE_CONTRACTS.FastSwitchboard]; + const switchboard = addr[Contracts.FastSwitchboard]; checkIfAddressExists(switchboard, "Switchboard"); const appGatewayId = getAppGatewayId(plugContract, addresses); checkIfAppGatewayIdExists(appGatewayId, "AppGatewayId"); @@ -163,10 +177,10 @@ export const updateConfigEVMx = async () => { // Set up Watcher contract const signer = getWatcherSigner(); const EVMxAddresses = addresses[EVMX_CHAIN_ID]!; - const watcherPrecompileConfig = ( + const configurationsContract = ( await getInstance( - EVMxCoreContracts.Configurations, - EVMxAddresses[EVMxCoreContracts.Configurations] + Contracts.Configurations, + EVMxAddresses[Contracts.Configurations] ) ).connect(signer); @@ -178,13 +192,13 @@ export const updateConfigEVMx = async () => { for (const plugContract of plugs) { const appGatewayId = getAppGatewayId(plugContract, addresses); - const switchboard = addr[CORE_CONTRACTS.FastSwitchboard]; + const switchboard = addr[Contracts.FastSwitchboard]; checkIfAddressExists(switchboard, "Switchboard"); checkIfAppGatewayIdExists(appGatewayId, "AppGatewayId"); if ( await isConfigSetOnEVMx( - watcherPrecompileConfig, + configurationsContract, chain, addr[plugContract], appGatewayId, @@ -195,9 +209,11 @@ export const updateConfigEVMx = async () => { continue; } appConfigs.push({ + plugConfig: { + appGatewayId: appGatewayId, + switchboard: switchboard, + }, plug: addr[plugContract], - appGatewayId: appGatewayId, - switchboard: addr[CORE_CONTRACTS.FastSwitchboard], chainSlug: chain, }); } @@ -207,25 +223,13 @@ export const updateConfigEVMx = async () => { // Update configs if any changes needed if (appConfigs.length > 0) { console.log({ appConfigs }); - const encodedMessage = ethers.utils.defaultAbiCoder.encode( - [ - "bytes4", - "tuple(address plug,bytes32 appGatewayId,address switchboard,uint32 chainSlug)[]", - ], - [ - watcherPrecompileConfig.interface.getSighash("setAppGateways"), - appConfigs, - ] - ); - const { nonce, signature } = await signWatcherMessage( - encodedMessage, - watcherPrecompileConfig.address + const calldata = configurationsContract.interface.encodeFunctionData( + "setAppGatewayConfigs", + [appConfigs] ); - const tx = await watcherPrecompileConfig.setAppGateways( - appConfigs, - nonce, - signature, - { ...overrides(EVMX_CHAIN_ID) } + const tx = await sendWatcherMultiCallWithNonce( + configurationsContract.address, + calldata ); console.log(`Updating EVMx Config tx hash: ${tx.hash}`); await tx.wait(); @@ -235,16 +239,6 @@ export const updateConfigEVMx = async () => { } }; -// Main function to connect plugs on all chains -export const main = async () => { - try { - await connectPlugsOnSocket(); - await updateConfigEVMx(); - } catch (error) { - console.log("Error while sending transaction", error); - } -}; - main() .then(() => process.exit(0)) .catch((error: Error) => { diff --git a/hardhat-scripts/deploy/5.upload.ts b/hardhat-scripts/deploy/7.upload.ts similarity index 100% rename from hardhat-scripts/deploy/5.upload.ts rename to hardhat-scripts/deploy/7.upload.ts diff --git a/hardhat-scripts/deploy/6.setupEnv.ts b/hardhat-scripts/deploy/8.setupEnv.ts similarity index 68% rename from hardhat-scripts/deploy/6.setupEnv.ts rename to hardhat-scripts/deploy/8.setupEnv.ts index 02e27607..a47d36c0 100644 --- a/hardhat-scripts/deploy/6.setupEnv.ts +++ b/hardhat-scripts/deploy/8.setupEnv.ts @@ -1,4 +1,4 @@ -import { ChainSlug } from "../../src"; +import { ChainSlug, Contracts } from "../../src"; import fs from "fs"; import path from "path"; import { EVMX_CHAIN_ID, mode } from "../config/config"; @@ -20,28 +20,28 @@ const latestEVMxAddresses = latestAddresses[EVMX_CHAIN_ID]; // Create a new array to hold the updated lines const updatedLines = lines.map((line) => { if (line.startsWith("ADDRESS_RESOLVER=")) { - return `ADDRESS_RESOLVER=${latestEVMxAddresses["AddressResolver"]}`; - } else if (line.startsWith("WATCHER_PRECOMPILE=")) { - return `WATCHER_PRECOMPILE=${latestEVMxAddresses["Watcher"]}`; + return `ADDRESS_RESOLVER=${latestEVMxAddresses[Contracts.AddressResolver]}`; + } else if (line.startsWith("WATCHER=")) { + return `WATCHER=${latestEVMxAddresses[Contracts.Watcher]}`; } else if (line.startsWith("AUCTION_MANAGER=")) { - return `AUCTION_MANAGER=${latestEVMxAddresses["AuctionManager"]}`; + return `AUCTION_MANAGER=${latestEVMxAddresses[Contracts.AuctionManager]}`; } else if (line.startsWith("FEES_MANAGER=")) { - return `FEES_MANAGER=${latestEVMxAddresses["FeesManager"]}`; + return `FEES_MANAGER=${latestEVMxAddresses[Contracts.FeesManager]}`; } else if (line.startsWith("ARBITRUM_SOCKET=")) { return `ARBITRUM_SOCKET=${ - latestAddresses[ChainSlug.ARBITRUM_SEPOLIA]["Socket"] + latestAddresses[ChainSlug.ARBITRUM_SEPOLIA][Contracts.Socket] }`; } else if (line.startsWith("ARBITRUM_SWITCHBOARD=")) { return `ARBITRUM_SWITCHBOARD=${ - latestAddresses[ChainSlug.ARBITRUM_SEPOLIA]["FastSwitchboard"] + latestAddresses[ChainSlug.ARBITRUM_SEPOLIA][Contracts.FastSwitchboard] }`; } else if (line.startsWith("ARBITRUM_FEES_PLUG=")) { return `ARBITRUM_FEES_PLUG=${ - latestAddresses[ChainSlug.ARBITRUM_SEPOLIA]["FeesPlug"] + latestAddresses[ChainSlug.ARBITRUM_SEPOLIA][Contracts.FeesPlug] }`; } else if (line.startsWith("ARBITRUM_TEST_USDC=")) { return `ARBITRUM_TEST_USDC=${ - latestAddresses[ChainSlug.ARBITRUM_SEPOLIA]["TestUSDC"] + latestAddresses[ChainSlug.ARBITRUM_SEPOLIA][Contracts.TestUSDC] }`; } return line; // Return the line unchanged if it doesn't match any of the above diff --git a/hardhat-scripts/deploy/9.setupTransmitter.ts b/hardhat-scripts/deploy/9.setupTransmitter.ts new file mode 100644 index 00000000..279be8b1 --- /dev/null +++ b/hardhat-scripts/deploy/9.setupTransmitter.ts @@ -0,0 +1,110 @@ +import { Contract, Wallet } from "ethers"; +import { ChainSlug, Contracts, EVMxAddressesObj } from "../../src"; +import { + EVMX_CHAIN_ID, + mode, + TRANSMITTER_CREDIT_THRESHOLD, + TRANSMITTER_NATIVE_THRESHOLD, +} from "../config/config"; +import { getAddresses } from "../utils/address"; +import { getInstance } from "../utils/deployUtils"; +import { overrides } from "../utils/overrides"; +import { getTransmitterSigner, getWatcherSigner } from "../utils/sign"; +import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; + +let evmxAddresses: EVMxAddressesObj; +let feesManagerContract: Contract; +let transmitterSigner: SignerWithAddress | Wallet; +let transmitterAddress: string; + +export const main = async () => { + console.log("Setting up transmitter..."); + await init(); + await approveAuctionManager(); + await checkAndDepositCredits(); + + console.log("Transmitter setup complete!"); +}; + +export const init = async () => { + const addresses = getAddresses(mode); + evmxAddresses = addresses[EVMX_CHAIN_ID] as EVMxAddressesObj; + feesManagerContract = await getInstance( + Contracts.FeesManager, + evmxAddresses[Contracts.FeesManager] + ); + transmitterSigner = getTransmitterSigner(EVMX_CHAIN_ID as ChainSlug); + transmitterAddress = await transmitterSigner.getAddress(); +}; + +export const approveAuctionManager = async () => { + console.log("Approving auction manager"); + const auctionManagerAddress = evmxAddresses[Contracts.AuctionManager]; + const isAlreadyApproved = await feesManagerContract + .connect(transmitterSigner) + .isApproved(transmitterAddress, auctionManagerAddress); + + if (!isAlreadyApproved) { + console.log("Approving auction manager"); + const tx = await feesManagerContract + .connect(transmitterSigner) + .approveAppGateways( + [ + { + appGateway: auctionManagerAddress, + approval: true, + }, + ], + await overrides(EVMX_CHAIN_ID as ChainSlug) + ); + console.log("Auction manager approval tx hash:", tx.hash); + await tx.wait(); + console.log("Auction manager approved"); + } else { + console.log("Auction manager already approved"); + } +}; + +export const checkAndDepositCredits = async () => { + console.log("Checking and depositing credits"); + const credits = await feesManagerContract + .connect(transmitterSigner) + .getAvailableCredits(transmitterAddress); + + if (credits.lt(TRANSMITTER_CREDIT_THRESHOLD)) { + console.log("Depositing credits for transmitter..."); + const tx = await feesManagerContract + .connect(getWatcherSigner()) + .wrap(transmitterAddress, { + ...(await overrides(EVMX_CHAIN_ID as ChainSlug)), + value: TRANSMITTER_CREDIT_THRESHOLD, + }); + console.log("Credits wrap tx hash:", tx.hash); + await tx.wait(); + console.log("Credits wrapped"); + } +}; + +export const checkAndDepositNative = async () => { + console.log("Checking and depositing native"); + const nativeBalance = await transmitterSigner.provider!.getBalance( + transmitterAddress + ); + + if (nativeBalance.lt(TRANSMITTER_NATIVE_THRESHOLD)) { + console.log("Depositing native for transmitter..."); + const tx = await getWatcherSigner().sendTransaction({ + to: transmitterAddress, + value: TRANSMITTER_NATIVE_THRESHOLD, + ...(await overrides(EVMX_CHAIN_ID as ChainSlug)), + }); + console.log("Native deposit tx hash:", tx.hash); + await tx.wait(); + console.log("Native deposited"); + } +}; + +main().catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/hardhat-scripts/utils/deployUtils.ts b/hardhat-scripts/utils/deployUtils.ts index 62824dcf..0b6206a5 100644 --- a/hardhat-scripts/utils/deployUtils.ts +++ b/hardhat-scripts/utils/deployUtils.ts @@ -1,4 +1,4 @@ -import { Wallet, utils } from "ethers"; +import { BigNumber, Signer, Wallet, utils } from "ethers"; import { network, ethers, run } from "hardhat"; import { ContractFactory, Contract } from "ethers"; @@ -7,9 +7,10 @@ import path from "path"; import fs from "fs"; import { ChainAddressesObj, ChainSlug, DeploymentMode } from "../../src"; import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; -import { overrides } from "../utils"; +import { getAddresses, overrides } from "../utils"; import { VerifyArgs } from "../verify"; import { DeploymentAddresses } from "../constants"; +import { EVMX_CHAIN_ID, mode } from "../config"; export const deploymentsPath = path.join(__dirname, `/../../deployments/`); @@ -318,3 +319,42 @@ export function getChainSlugFromId(chainId: number) { // avoid conflict for now return parseInt(utils.id(chainId.toString()).substring(0, 10)); } + +export const updateContractSettings = async ( + chainSlug: number, + contractName: string, + getterMethod: string, + getterArgs: any[], + requiredValue: string | BigNumber, + setterMethod: string, + setterArgs: any[], + signer: SignerWithAddress | Wallet +) => { + const addresses = getAddresses(mode); + const contractAddress = addresses[chainSlug][contractName]; + const contractInstance = await getInstance(contractName, contractAddress); + const currentValue = await contractInstance + .connect(signer) + [getterMethod](...getterArgs); + + if ( + (typeof currentValue === "string" && + currentValue.toLowerCase() !== String(requiredValue).toLowerCase()) || + (BigNumber.isBigNumber(currentValue) && + currentValue.toString() !== requiredValue.toString()) + ) { + console.log({ + setterMethod, + current: currentValue, + required: requiredValue, + }); + const tx = await contractInstance + .connect(signer) + [setterMethod](...setterArgs); + console.log( + `Setting ${getterMethod} for ${contractInstance.address} to`, + tx.hash + ); + await tx.wait(); + } +}; diff --git a/hardhat-scripts/utils/overrides.ts b/hardhat-scripts/utils/overrides.ts index d4cfdafc..94a25c12 100644 --- a/hardhat-scripts/utils/overrides.ts +++ b/hardhat-scripts/utils/overrides.ts @@ -1,5 +1,5 @@ import { ChainSlug } from "../../src"; -import { BigNumber, BigNumberish, providers } from "ethers"; +import { BigNumber, BigNumberish, Contract, providers, Signer } from "ethers"; import { EVMX_CHAIN_ID } from "../config/config"; import { getProviderFromChainSlug } from "./networks"; diff --git a/hardhat-scripts/utils/sign.ts b/hardhat-scripts/utils/sign.ts index 5f7ed311..6f569ff0 100644 --- a/hardhat-scripts/utils/sign.ts +++ b/hardhat-scripts/utils/sign.ts @@ -1,23 +1,12 @@ import { ethers } from "ethers"; -import { ChainSlug } from "../../src"; -import { EVMX_CHAIN_ID } from "../config/config"; +import { ChainSlug, Contracts } from "../../src"; +import { EVMX_CHAIN_ID, mode } from "../config/config"; import { getProviderFromChainSlug } from "./networks"; - -export const signWatcherMessage = async ( - encodedMessage: string, - watcherContractAddress: string -) => { - const signatureNonce = Date.now(); - const signer = getWatcherSigner(); - const digest = ethers.utils.keccak256( - ethers.utils.defaultAbiCoder.encode( - ["address", "uint32", "uint256", "bytes"], - [watcherContractAddress, EVMX_CHAIN_ID, signatureNonce, encodedMessage] - ) - ); - const signature = await signer.signMessage(ethers.utils.arrayify(digest)); - return { nonce: signatureNonce, signature }; -}; +import { signWatcherMultiCallMessage } from "../../src/signer"; +import { getAddresses } from "./address"; +import { getOverrides, overrides } from "./overrides"; +import { getInstance } from "./deployUtils"; +import { WatcherMultiCallParams } from "../constants/types"; export const getWatcherSigner = () => { const provider = getProviderFromChainSlug(EVMX_CHAIN_ID as ChainSlug); @@ -28,3 +17,53 @@ export const getSocketSigner = (chainSlug: ChainSlug) => { const provider = getProviderFromChainSlug(chainSlug); return new ethers.Wallet(process.env.SOCKET_SIGNER_KEY as string, provider); }; + +export const getTransmitterSigner = (chainSlug: ChainSlug) => { + const provider = getProviderFromChainSlug(chainSlug); + return new ethers.Wallet( + process.env.TRANSMITTER_PRIVATE_KEY as string, + provider + ); +}; + +export const signWatcherMessage = async ( + targetContractAddress: string, + calldata: string +) => { + const addresses = getAddresses(mode); + return await signWatcherMultiCallMessage( + addresses[EVMX_CHAIN_ID][Contracts.Watcher], + EVMX_CHAIN_ID, + targetContractAddress, + calldata, + getWatcherSigner() + ); +}; + +export const sendWatcherMultiCallWithNonce = async ( + targetContractAddress: string, + calldata: string +) => { + const addresses = getAddresses(mode); + const watcherContract = ( + await getInstance( + Contracts.Watcher, + addresses[EVMX_CHAIN_ID][Contracts.Watcher] + ) + ).connect(getWatcherSigner()); + const { nonce, signature } = await signWatcherMessage( + targetContractAddress, + calldata + ); + + const params: WatcherMultiCallParams = { + contractAddress: targetContractAddress, + data: calldata, + nonce, + signature, + }; + // Call watcherMultiCall function with single call data + return await watcherContract.watcherMultiCall([params], { + ...(await overrides(EVMX_CHAIN_ID as ChainSlug)), + }); +}; diff --git a/lib.tsconfig.json b/lib.tsconfig.json index ba2f6b86..e0ae1226 100644 --- a/lib.tsconfig.json +++ b/lib.tsconfig.json @@ -10,6 +10,6 @@ "moduleResolution": "node", "allowJs": true }, - "include": ["src/**/*.ts", "lib/**/*.ts", "deployments/"], + "include": ["src/**/*.ts"], "exclude": ["node_modules", "dist"] } diff --git a/package.json b/package.json index 2df9297e..b009f0a3 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "publishConfig": { "access": "public" }, - "version": "1.1.17", + "version": "1.1.19", "description": "socket protocol", "scripts": { "build": "yarn abi && tsc --project lib.tsconfig.json", @@ -48,9 +48,8 @@ "prompts": "^2.4.2", "ts-node": "^10.7.0", "typechain": "^8.0.0", - "typescript": "^4.6.4" - }, - "dependencies": { + "typescript": "^4.6.4", "hardhat-contract-sizer": "^2.10.0" - } + }, + "dependencies": {} } diff --git a/script/helpers/DepositCredit.s.sol b/script/helpers/DepositCredit.s.sol index 4088d142..767d5aac 100644 --- a/script/helpers/DepositCredit.s.sol +++ b/script/helpers/DepositCredit.s.sol @@ -6,24 +6,30 @@ import {console} from "forge-std/console.sol"; import {FeesPlug} from "../../contracts/evmx/plugs/FeesPlug.sol"; import {TestUSDC} from "../../contracts/evmx/mocks/TestUSDC.sol"; -// source .env && forge script script/helpers/DepositCredit.s.sol --broadcast --skip-simulation +// source .env && forge script script/helpers/DepositCreditAndNative.s.sol --broadcast --skip-simulation contract DepositCredit is Script { function run() external { + uint256 feesAmount = 100000000; // 100 USDC vm.createSelectFork(vm.envString("ARBITRUM_SEPOLIA_RPC")); uint256 privateKey = vm.envUint("PRIVATE_KEY"); vm.startBroadcast(privateKey); FeesPlug feesPlug = FeesPlug(payable(vm.envAddress("ARBITRUM_FEES_PLUG"))); - TestUSDC token = TestUSDC(vm.envAddress("USDC")); address appGateway = vm.envAddress("APP_GATEWAY"); + TestUSDC testUSDCContract = TestUSDC(vm.envAddress("ARBITRUM_TEST_USDC")); + + // mint test USDC to sender + testUSDCContract.mint(vm.addr(privateKey), feesAmount); + // approve fees plug to spend test USDC + testUSDCContract.approve(address(feesPlug), feesAmount); address sender = vm.addr(privateKey); console.log("Sender address:", sender); - uint256 balance = sender.balance; + uint256 balance = testUSDCContract.balanceOf(sender); console.log("Sender balance in wei:", balance); console.log("App Gateway:", appGateway); console.log("Fees Plug:", address(feesPlug)); - uint feesAmount = 0.001 ether; - feesPlug.depositCredit(address(token), appGateway, feesAmount); + console.log("Fees Amount:", feesAmount); + feesPlug.depositCredit(address(testUSDCContract), appGateway, feesAmount); } } diff --git a/script/helpers/DepositCreditAndNative.s.sol b/script/helpers/DepositCreditAndNative.s.sol index a9eb6c2f..629a3998 100644 --- a/script/helpers/DepositCreditAndNative.s.sol +++ b/script/helpers/DepositCreditAndNative.s.sol @@ -9,10 +9,10 @@ import {TestUSDC} from "../../contracts/evmx/mocks/TestUSDC.sol"; // source .env && forge script script/helpers/DepositCreditAndNative.s.sol --broadcast --skip-simulation contract DepositCreditAndNative is Script { function run() external { - uint256 feesAmount = 100000000; + uint256 feesAmount = 100000000; // 100 USDC vm.createSelectFork(vm.envString("ARBITRUM_SEPOLIA_RPC")); - uint256 privateKey = vm.envUint("SPONSOR_KEY"); + uint256 privateKey = vm.envUint("PRIVATE_KEY"); vm.startBroadcast(privateKey); FeesPlug feesPlug = FeesPlug(payable(vm.envAddress("ARBITRUM_FEES_PLUG"))); address appGateway = vm.envAddress("APP_GATEWAY"); diff --git a/setupInfraContracts.sh b/setupInfraContracts.sh index 9d916681..989eabaa 100644 --- a/setupInfraContracts.sh +++ b/setupInfraContracts.sh @@ -4,10 +4,13 @@ else time npx hardhat run hardhat-scripts/deploy/1.deploy.ts fi time npx hardhat run hardhat-scripts/deploy/2.roles.ts --no-compile -time npx hardhat run hardhat-scripts/deploy/3.upgradeManagers.ts --no-compile -time npx hardhat run hardhat-scripts/deploy/4.connect.ts --no-compile -time npx ts-node hardhat-scripts/deploy/5.upload.ts --resolveJsonModule -time npx hardhat run hardhat-scripts/deploy/6.setupEnv.ts --no-compile +time npx hardhat run hardhat-scripts/deploy/3.configureChains.ts --no-compile +time npx hardhat run hardhat-scripts/deploy/4.configureEVMx.ts --no-compile +time npx hardhat run hardhat-scripts/deploy/5.fundTransfers.ts --no-compile +time npx hardhat run hardhat-scripts/deploy/6.connect.ts --no-compile +time npx hardhat run hardhat-scripts/deploy/7.upload.ts --no-compile +time npx hardhat run hardhat-scripts/deploy/8.setupEnv.ts --no-compile +time npx hardhat run hardhat-scripts/deploy/9.setupTransmitter.ts --no-compile time npx hardhat run hardhat-scripts/misc-scripts/errorCodes.ts --no-compile time npx hardhat run hardhat-scripts/misc-scripts/eventTopics.ts --no-compile time npx hardhat run hardhat-scripts/misc-scripts/functionSigs.ts --no-compile diff --git a/src/enums.ts b/src/enums.ts index 68f4e796..a725f8ae 100644 --- a/src/enums.ts +++ b/src/enums.ts @@ -51,6 +51,8 @@ export enum Contracts { ContractFactoryPlug = "ContractFactoryPlug", FastSwitchboard = "FastSwitchboard", SocketBatcher = "SocketBatcher", + SocketFeeManager = "SocketFeeManager", + TestUSDC = "TestUSDC", AddressResolver = "AddressResolver", Watcher = "Watcher", @@ -62,6 +64,9 @@ export enum Contracts { WritePrecompile = "WritePrecompile", ReadPrecompile = "ReadPrecompile", SchedulePrecompile = "SchedulePrecompile", + FeesPool = "FeesPool", + AsyncDeployer = "AsyncDeployer", + DeployForwarder = "DeployForwarder", } export enum CallTypeNames { diff --git a/src/index.ts b/src/index.ts index 9e934473..39a65132 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,3 +4,4 @@ export * from "./events"; export * from "./finality"; export * from "./types"; export * from "./constants"; +export * from "./signer"; diff --git a/src/signer.ts b/src/signer.ts new file mode 100644 index 00000000..9ec27359 --- /dev/null +++ b/src/signer.ts @@ -0,0 +1,25 @@ +import { ethers } from "ethers"; + +export const signWatcherMultiCallMessage = async ( + watcherContractAddress: string, + evmxChainId: number, + targetContractAddress: string, + calldata: string, + signer: ethers.Signer +) => { + const signatureNonce = Date.now(); + const digest = ethers.utils.keccak256( + ethers.utils.defaultAbiCoder.encode( + ["address", "uint32", "uint256", "address", "bytes"], + [ + watcherContractAddress, + evmxChainId, + signatureNonce, + targetContractAddress, + calldata, + ] + ) + ); + const signature = await signer.signMessage(ethers.utils.arrayify(digest)); + return { nonce: signatureNonce, signature }; +}; diff --git a/src/types.ts b/src/types.ts index b22f3711..d63a03db 100644 --- a/src/types.ts +++ b/src/types.ts @@ -36,6 +36,7 @@ export type EVMxAddressesObj = { SchedulePrecompile: string; AuctionManager: string; FeesManager: string; + FeesPool: string; startBlock: number; }; diff --git a/test/Storage.t.sol b/test/Storage.t.sol index 65e6c1a8..2aa7bee2 100644 --- a/test/Storage.t.sol +++ b/test/Storage.t.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; - // contract StorageTest is DeliveryHelperTest { // DeliveryHelper public deliveryHelperImpl; From c1b2aa4751051a7cd3c4c50432cab52342d7145e Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Fri, 30 May 2025 20:48:17 +0530 Subject: [PATCH 097/130] fix: rescue access --- contracts/evmx/AuctionManager.sol | 8 ++------ contracts/evmx/fees/Credit.sol | 1 - contracts/evmx/helpers/AsyncDeployer.sol | 12 +++--------- contracts/evmx/helpers/AsyncPromise.sol | 2 +- contracts/evmx/helpers/DeployForwarder.sol | 11 +++-------- contracts/evmx/helpers/Forwarder.sol | 2 +- contracts/evmx/watcher/RequestHandler.sol | 1 - contracts/evmx/watcher/Trigger.sol | 1 - 8 files changed, 10 insertions(+), 28 deletions(-) diff --git a/contracts/evmx/AuctionManager.sol b/contracts/evmx/AuctionManager.sol index 9e2c8db0..4faf54f5 100644 --- a/contracts/evmx/AuctionManager.sol +++ b/contracts/evmx/AuctionManager.sol @@ -11,7 +11,7 @@ import "../utils/RescueFundsLib.sol"; import {AuctionNotOpen, AuctionClosed, BidExceedsMaxFees, LowerBidAlreadyExists, InvalidTransmitter, MaxReAuctionCountReached, InvalidBid} from "../utils/common/Errors.sol"; import {SCHEDULE} from "../utils/common/Constants.sol"; -import {TRANSMITTER_ROLE, RESCUE_ROLE} from "../utils/common/AccessRoles.sol"; +import {TRANSMITTER_ROLE} from "../utils/common/AccessRoles.sol"; import {AppGatewayBase} from "./base/AppGatewayBase.sol"; /// @title AuctionManagerStorage @@ -293,11 +293,7 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AppGatewayBase, * @param rescueTo_ The address where rescued tokens need to be sent. * @param amount_ The amount of tokens to be rescued. */ - function rescueFunds( - address token_, - address rescueTo_, - uint256 amount_ - ) external onlyRole(RESCUE_ROLE) { + function rescueFunds(address token_, address rescueTo_, uint256 amount_) external onlyWatcher { RescueFundsLib._rescueFunds(token_, rescueTo_, amount_); } } diff --git a/contracts/evmx/fees/Credit.sol b/contracts/evmx/fees/Credit.sol index 1ad0f7a4..fb9dd643 100644 --- a/contracts/evmx/fees/Credit.sol +++ b/contracts/evmx/fees/Credit.sol @@ -63,7 +63,6 @@ abstract contract FeesManagerStorage is IFeesManager { uint256[50] _gap_after; // slots [108-157] 50 slots reserved for address resolver util - // slots [158-207] 50 slots reserved for access control } /// @title UserUtils diff --git a/contracts/evmx/helpers/AsyncDeployer.sol b/contracts/evmx/helpers/AsyncDeployer.sol index 3f204cf1..0f7decd4 100644 --- a/contracts/evmx/helpers/AsyncDeployer.sol +++ b/contracts/evmx/helpers/AsyncDeployer.sol @@ -4,13 +4,12 @@ pragma solidity ^0.8.21; import {LibClone} from "solady/utils/LibClone.sol"; import {UpgradeableBeacon} from "solady/utils/UpgradeableBeacon.sol"; import {Initializable} from "solady/utils/Initializable.sol"; +import "solady/auth/Ownable.sol"; import "../interfaces/IAsyncDeployer.sol"; import {Forwarder} from "./Forwarder.sol"; import {AsyncPromise} from "./AsyncPromise.sol"; import {AddressResolverUtil} from "./AddressResolverUtil.sol"; -import {RESCUE_ROLE} from "../../utils/common/AccessRoles.sol"; import "../../utils/RescueFundsLib.sol"; -import "../../utils/AccessControl.sol"; abstract contract AsyncDeployerStorage is IAsyncDeployer { // slots [0-49] reserved for gap @@ -35,13 +34,12 @@ abstract contract AsyncDeployerStorage is IAsyncDeployer { uint256[50] _gap_after; // slots [106-155] 50 slots reserved for address resolver util - // slots [156-205] 50 slots reserved for access control } /// @title AsyncDeployer Contract /// @notice This contract is responsible for deploying Forwarder and AsyncPromise contracts. /// @dev Inherits the AccessControl contract and implements the IAddressResolver interface. -contract AsyncDeployer is AsyncDeployerStorage, Initializable, AddressResolverUtil, AccessControl { +contract AsyncDeployer is AsyncDeployerStorage, Initializable, AddressResolverUtil, Ownable { constructor() { _disableInitializers(); // disable for implementation } @@ -219,11 +217,7 @@ contract AsyncDeployer is AsyncDeployerStorage, Initializable, AddressResolverUt * @param rescueTo_ The address where rescued tokens need to be sent. * @param amount_ The amount of tokens to be rescued. */ - function rescueFunds( - address token_, - address rescueTo_, - uint256 amount_ - ) external onlyRole(RESCUE_ROLE) { + function rescueFunds(address token_, address rescueTo_, uint256 amount_) external onlyWatcher { RescueFundsLib._rescueFunds(token_, rescueTo_, amount_); } } diff --git a/contracts/evmx/helpers/AsyncPromise.sol b/contracts/evmx/helpers/AsyncPromise.sol index dcf009da..f727947d 100644 --- a/contracts/evmx/helpers/AsyncPromise.sol +++ b/contracts/evmx/helpers/AsyncPromise.sol @@ -72,7 +72,7 @@ contract AsyncPromise is AsyncPromiseStorage, Initializable, AddressResolverUtil uint40 requestCount_, address invoker_, address addressResolver_ - ) public initializer { + ) public reinitializer(1) { localInvoker = invoker_; requestCount = requestCount_; _setAddressResolver(addressResolver_); diff --git a/contracts/evmx/helpers/DeployForwarder.sol b/contracts/evmx/helpers/DeployForwarder.sol index b26f5415..86a46f3e 100644 --- a/contracts/evmx/helpers/DeployForwarder.sol +++ b/contracts/evmx/helpers/DeployForwarder.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; +import "solady/auth/Ownable.sol"; import {Initializable} from "solady/utils/Initializable.sol"; import {IAppGateway} from "../interfaces/IAppGateway.sol"; import {IContractFactoryPlug} from "../interfaces/IContractFactoryPlug.sol"; @@ -9,14 +10,12 @@ import {AsyncModifierNotSet} from "../../utils/common/Errors.sol"; import {QueueParams, OverrideParams, Transaction} from "../../utils/common/Structs.sol"; import {WRITE} from "../../utils/common/Constants.sol"; import {encodeAppGatewayId} from "../../utils/common/IdUtils.sol"; -import {RESCUE_ROLE} from "../../utils/common/AccessRoles.sol"; import "../../utils/RescueFundsLib.sol"; -import "../../utils/AccessControl.sol"; import "./AddressResolverUtil.sol"; /// @title DeployForwarder /// @notice contract responsible for handling deployment requests -contract DeployForwarder is IDeployForwarder, Initializable, AddressResolverUtil, AccessControl { +contract DeployForwarder is IDeployForwarder, Initializable, AddressResolverUtil, Ownable { // slots [0-49] 50 slots reserved for address resolver util // slots [50-99] reserved for gap @@ -108,11 +107,7 @@ contract DeployForwarder is IDeployForwarder, Initializable, AddressResolverUtil * @param rescueTo_ The address where rescued tokens need to be sent. * @param amount_ The amount of tokens to be rescued. */ - function rescueFunds( - address token_, - address rescueTo_, - uint256 amount_ - ) external onlyRole(RESCUE_ROLE) { + function rescueFunds(address token_, address rescueTo_, uint256 amount_) external onlyWatcher { RescueFundsLib._rescueFunds(token_, rescueTo_, amount_); } } diff --git a/contracts/evmx/helpers/Forwarder.sol b/contracts/evmx/helpers/Forwarder.sol index aa227942..eba56336 100644 --- a/contracts/evmx/helpers/Forwarder.sol +++ b/contracts/evmx/helpers/Forwarder.sol @@ -43,7 +43,7 @@ contract Forwarder is ForwarderStorage, Initializable, AddressResolverUtil { uint32 chainSlug_, address onChainAddress_, address addressResolver_ - ) public initializer { + ) public reinitializer(1) { chainSlug = chainSlug_; onChainAddress = onChainAddress_; _setAddressResolver(addressResolver_); diff --git a/contracts/evmx/watcher/RequestHandler.sol b/contracts/evmx/watcher/RequestHandler.sol index 230e49d9..8b0e2686 100644 --- a/contracts/evmx/watcher/RequestHandler.sol +++ b/contracts/evmx/watcher/RequestHandler.sol @@ -56,7 +56,6 @@ abstract contract RequestHandlerStorage is IRequestHandler { /// @title RequestHandler /// @notice Contract that handles request processing and management, including request submission, batch processing, and request lifecycle management /// @dev Handles request submission, batch processing, transmitter assignment, request cancellation and settlement -/// @dev This contract interacts with the WatcherPrecompileStorage for storage access contract RequestHandler is RequestHandlerStorage, Initializable, Ownable, AddressResolverUtil { error InsufficientMaxFees(); diff --git a/contracts/evmx/watcher/Trigger.sol b/contracts/evmx/watcher/Trigger.sol index d27ff99d..c72ff27b 100644 --- a/contracts/evmx/watcher/Trigger.sol +++ b/contracts/evmx/watcher/Trigger.sol @@ -7,7 +7,6 @@ import {decodeAppGatewayId} from "../../utils/common/IdUtils.sol"; /// @title Trigger /// @notice Contract that handles trigger validation and execution logic -/// @dev This contract interacts with the WatcherPrecompileStorage for storage access abstract contract Trigger is WatcherStorage, AddressResolverUtil { using LibCall for address; From f8dc9b764742e6cca9d34939d925c8307d6cdac8 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Fri, 30 May 2025 23:11:55 +0530 Subject: [PATCH 098/130] feat: proxy migration and storage tests --- contracts/evmx/fees/Credit.sol | 2 +- contracts/evmx/helpers/AddressResolver.sol | 3 - contracts/evmx/helpers/AsyncDeployer.sol | 12 +- contracts/evmx/watcher/WatcherStorage.sol | 12 +- script/admin/mock/DeployEVMx.s.sol | 2 +- .../{Migration.t.sol => ProxyMigration.t.sol} | 147 +++++---- test/ProxyStorage.t.sol | 296 ++++++++++++++++++ test/SetupTest.t.sol | 28 +- test/Storage.t.sol | 77 ----- test/mock/MockWatcherPrecompile.sol | 126 ++++---- 10 files changed, 456 insertions(+), 249 deletions(-) rename test/{Migration.t.sol => ProxyMigration.t.sol} (67%) create mode 100644 test/ProxyStorage.t.sol delete mode 100644 test/Storage.t.sol diff --git a/contracts/evmx/fees/Credit.sol b/contracts/evmx/fees/Credit.sol index fb9dd643..d15e73a7 100644 --- a/contracts/evmx/fees/Credit.sol +++ b/contracts/evmx/fees/Credit.sol @@ -22,7 +22,7 @@ abstract contract FeesManagerStorage is IFeesManager { // slot 50 /// @notice evmx slug uint32 public evmxSlug; - + IFeesPool public feesPool; // slot 51 diff --git a/contracts/evmx/helpers/AddressResolver.sol b/contracts/evmx/helpers/AddressResolver.sol index 429b6d15..f11c1a10 100644 --- a/contracts/evmx/helpers/AddressResolver.sol +++ b/contracts/evmx/helpers/AddressResolver.sol @@ -28,9 +28,6 @@ abstract contract AddressResolverStorage is IAddressResolver { // slot 55 mapping(bytes32 => address) public override contractAddresses; - - // slots [56-105] reserved for gap - uint256[50] _gap_after; } /// @title AddressResolver Contract diff --git a/contracts/evmx/helpers/AsyncDeployer.sol b/contracts/evmx/helpers/AsyncDeployer.sol index 0f7decd4..8ac669a5 100644 --- a/contracts/evmx/helpers/AsyncDeployer.sol +++ b/contracts/evmx/helpers/AsyncDeployer.sol @@ -18,22 +18,22 @@ abstract contract AsyncDeployerStorage is IAsyncDeployer { // slot 50 UpgradeableBeacon public forwarderBeacon; - // slot 52 + // slot 51 UpgradeableBeacon public asyncPromiseBeacon; - // slot 53 + // slot 52 address public forwarderImplementation; - // slot 54 + // slot 53 address public asyncPromiseImplementation; - // slot 55 + // slot 54 uint256 public asyncPromiseCounter; - // slots [56-105] reserved for gap + // slots [55-104] reserved for gap uint256[50] _gap_after; - // slots [106-155] 50 slots reserved for address resolver util + // slots [105-154] 50 slots reserved for address resolver util } /// @title AsyncDeployer Contract diff --git a/contracts/evmx/watcher/WatcherStorage.sol b/contracts/evmx/watcher/WatcherStorage.sol index 4811d600..9c429a5e 100644 --- a/contracts/evmx/watcher/WatcherStorage.sol +++ b/contracts/evmx/watcher/WatcherStorage.sol @@ -48,17 +48,17 @@ abstract contract WatcherStorage is IWatcher, Initializable, Ownable { QueueParams[] public payloadQueue; // slot 58 - /// @notice Maps nonce to whether it has been used - /// @dev Used to prevent replay attacks with signature nonces - /// @dev signatureNonce => isValid - mapping(uint256 => bool) public isNonceUsed; - - // slot 59 /// @notice Mapping to store if appGateway has been called with trigger from on-chain Inbox /// @dev Maps call ID to boolean indicating if the appGateway has been called /// @dev callId => bool mapping(bytes32 => bool) public isAppGatewayCalled; + // slot 59 + /// @notice Maps nonce to whether it has been used + /// @dev Used to prevent replay attacks with signature nonces + /// @dev signatureNonce => isValid + mapping(uint256 => bool) public isNonceUsed; + // slots [60-109]: gap for future storage variables uint256[50] _gap_after; diff --git a/script/admin/mock/DeployEVMx.s.sol b/script/admin/mock/DeployEVMx.s.sol index c268e42c..294f2a99 100644 --- a/script/admin/mock/DeployEVMx.s.sol +++ b/script/admin/mock/DeployEVMx.s.sol @@ -11,7 +11,7 @@ contract DeployEVMx is Script { vm.createSelectFork(rpc); uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); vm.startBroadcast(deployerPrivateKey); - MockWatcherPrecompile watcher = new MockWatcherPrecompile(address(0), address(0)); + MockWatcherPrecompile watcher = new MockWatcherPrecompile(); console.log("MockWatcherPrecompile:", address(watcher)); } } diff --git a/test/Migration.t.sol b/test/ProxyMigration.t.sol similarity index 67% rename from test/Migration.t.sol rename to test/ProxyMigration.t.sol index 10e4acd5..ad35df2a 100644 --- a/test/Migration.t.sol +++ b/test/ProxyMigration.t.sol @@ -1,13 +1,10 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import "./SetupTest.t.sol"; -import "../contracts/evmx/helpers/AddressResolver.sol"; -import "../contracts/evmx/watcher/Watcher.sol"; -import "../contracts/evmx/helpers/Forwarder.sol"; -import "../contracts/evmx/helpers/AsyncPromise.sol"; +import "./ProxyStorage.t.sol"; +import "./mock/MockWatcherPrecompile.sol"; -contract MigrationTest is AppGatewayBaseSetup { +contract MigrationTest is ProxyStorageAssertions { // ERC1967Factory emits this event with both proxy and implementation addresses event Upgraded(address indexed proxy, address indexed implementation); event ImplementationUpdated(string contractName, address newImplementation); @@ -45,92 +42,92 @@ contract MigrationTest is AppGatewayBaseSetup { return address(uint160(uint256(value))); } - function testAddressResolverUpgrade() public { - // Deploy new implementation - AddressResolver newImpl = new AddressResolver(); + function upgradeAndCall(address proxy, address newImpl, bytes memory data) internal { + address oldImpl = getImplementation(proxy); - // Store old implementation address - address oldImpl = getImplementation(address(addressResolver)); - - // Upgrade proxy to new implementation - vm.startPrank(watcherEOA); + hoax(watcherEOA); vm.expectEmit(true, true, true, true, address(proxyFactory)); - emit Upgraded(address(addressResolver), address(newImpl)); - proxyFactory.upgradeAndCall(address(addressResolver), address(newImpl), ""); - vm.stopPrank(); + emit Upgraded(proxy, address(newImpl)); + proxyFactory.upgradeAndCall(proxy, address(newImpl), data); // Verify upgrade was successful - address newImplAddr = getImplementation(address(addressResolver)); + address newImplAddr = getImplementation(address(proxy)); assertNotEq(oldImpl, newImplAddr, "Implementation should have changed"); assertEq(newImplAddr, address(newImpl), "New implementation not set correctly"); + } - // Verify state is preserved - assertEq(addressResolver.owner(), watcherEOA, "Owner should be preserved after upgrade"); - assertEq( - address(addressResolver.watcher__()), - address(watcher), - "Watcher address should be preserved" - ); + function testFeesManagerUpgrade() public { + FeesManager newImpl = new FeesManager(); + upgradeAndCall(address(feesManager), address(newImpl), ""); + assertFeesManagerSlot(); + } + + function testAddressResolverUpgrade() public { + AddressResolver newImpl = new AddressResolver(); + upgradeAndCall(address(addressResolver), address(newImpl), ""); + assertAddressResolverSlot(); + } + + function testAsyncDeployerUpgrade() public { + AsyncDeployer newImpl = new AsyncDeployer(); + upgradeAndCall(address(asyncDeployer), address(newImpl), ""); + assertAsyncDeployerSlot(); } function testWatcherUpgrade() public { - // Deploy new implementation Watcher newImpl = new Watcher(); + upgradeAndCall(address(watcher), address(newImpl), ""); + assertWatcherSlot(); + } - // Store old implementation address - address oldImpl = getImplementation(address(watcher)); + function testAuctionManagerUpgrade() public { + AuctionManager newImpl = new AuctionManager(); + upgradeAndCall(address(auctionManager), address(newImpl), ""); + assertAuctionManagerSlot(); + } - // Upgrade proxy to new implementation - vm.startPrank(watcherEOA); - vm.expectEmit(true, true, true, true, address(proxyFactory)); - emit Upgraded(address(watcher), address(newImpl)); - proxyFactory.upgradeAndCall(address(watcher), address(newImpl), ""); - vm.stopPrank(); + function testDeployForwarderUpgrade() public { + DeployForwarder newImpl = new DeployForwarder(); + upgradeAndCall(address(deployForwarder), address(newImpl), ""); + assertDeployForwarderSlot(); + } - // Verify upgrade was successful - address newImplAddr = getImplementation(address(watcher)); - assertNotEq(oldImpl, newImplAddr, "Implementation should have changed"); - assertEq(newImplAddr, address(newImpl), "New implementation not set correctly"); + function testConfigurationsUpgrade() public { + Configurations newImpl = new Configurations(); + upgradeAndCall(address(configurations), address(newImpl), ""); + assertConfigurationsSlot(); + } - // Verify state is preserved - assertEq(watcher.owner(), watcherEOA, "Owner should be preserved after upgrade"); - assertEq( - address(watcher.configurations__()), - address(configurations), - "Configurations should be preserved" - ); - assertEq(watcher.evmxSlug(), evmxSlug, "EvmxSlug should be preserved"); + function testRequestHandlerUpgrade() public { + RequestHandler newImpl = new RequestHandler(); + upgradeAndCall(address(requestHandler), address(newImpl), ""); + assertRequestHandlerSlot(); + } + + function testWritePrecompileUpgrade() public { + WritePrecompile newImpl = new WritePrecompile(); + upgradeAndCall(address(writePrecompile), address(newImpl), ""); + assertWritePrecompileSlot(); } - // function testUpgradeWithInitializationData() public { - // // Deploy new implementation - // MockWatcherImpl newImpl = new MockWatcherImpl(); - - // // Store old implementation address for verification - // address oldImpl = getImplementation(address(watcher)); - - // // Prepare initialization data with new defaultLimit - // uint256 newDefaultLimit = 2000; - // bytes memory initData = abi.encodeWithSelector( - // MockWatcherImpl.mockReinitialize.selector, - // watcherEOA, - // address(addressResolver), - // newDefaultLimit - // ); - - // // Upgrade proxy with initialization data - // vm.startPrank(watcherEOA); - // vm.expectEmit(true, true, true, true, address(proxyFactory)); - // emit Upgraded(address(watcher), address(newImpl)); - // proxyFactory.upgradeAndCall(address(watcher), address(newImpl), initData); - // vm.stopPrank(); - - // // Verify upgrade and initialization was successful - // address newImplAddr = getImplementation(address(watcher)); - // assertNotEq(oldImpl, newImplAddr, "Implementation should have changed"); - // assertEq(newImplAddr, address(newImpl), "New implementation not set correctly"); - // assertEq(watcher.evmxSlug(), evmxSlug, "EvmxSlug should be preserved"); - // } + function testUpgradeWithInitializationData() public { + // Deploy new implementation + MockWatcherPrecompile newImpl = new MockWatcherPrecompile(); + + // Prepare initialization data with new defaultLimit + uint256 newValue = 2000; + bytes memory initData = abi.encodeWithSelector( + MockWatcherPrecompile.initialize.selector, + newValue + ); + + upgradeAndCall(address(watcher), address(newImpl), initData); + assertWatcherSlot(); + + // Verify new value is set + bytes32 slotValue = vm.load(address(watcher), bytes32(uint256(160))); + assertEq(uint256(slotValue), newValue, "newValue mismatch"); + } function testUnauthorizedUpgrade() public { // Deploy new implementation diff --git a/test/ProxyStorage.t.sol b/test/ProxyStorage.t.sol new file mode 100644 index 00000000..bc08b704 --- /dev/null +++ b/test/ProxyStorage.t.sol @@ -0,0 +1,296 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import "./SetupTest.t.sol"; + +contract ProxyStorageAssertions is AppGatewayBaseSetup { + uint256 public constant FIRST_SLOT = 50; + uint256 public constant ADDRESS_RESOLVER_SLOT = 59; + uint256 public constant WATCHER_SLOT = 52; + + function assertAddressResolverUtilSlot(uint256 slot_, address contract_) internal view { + bytes32 slotValue = vm.load(address(contract_), bytes32(uint256(slot_))); + assertEq( + address(uint160(uint256(slotValue))), + address(addressResolver), + "address resolver mismatch" + ); + } + + function assertAccessControlSlot(uint256 slot_, address contract_) internal { + bytes32 role = keccak256("ADMIN_ROLE"); + address account = address(0xBEEF); + bool value = true; + + // Compute the slot for _permits[role][account] + bytes32 outerSlot = keccak256(abi.encode(role, uint256(slot_))); + bytes32 mappingSlot = keccak256(abi.encode(account, outerSlot)); + + // Store the value + vm.store(address(contract_), mappingSlot, bytes32(uint256(value ? 1 : 0))); + + // Read back and assert + bytes32 slotValue = vm.load(address(contract_), mappingSlot); + assertEq(uint256(slotValue), value ? 1 : 0, "_permits mapping slot value mismatch"); + } + + function assertFeesManagerSlot() internal { + // first + bytes32 slotValue = vm.load(address(feesManager), bytes32(uint256(FIRST_SLOT))); + assertEq(uint32(uint256(slotValue)), evmxSlug, "evmxSlug mismatch"); + + // last + hoax(watcherEOA); + feesManager.setFeesPlug(evmxSlug, address(addressResolver)); + bytes32 mappingSlot = keccak256(abi.encode(uint256(evmxSlug), uint256(57))); + slotValue = vm.load(address(feesManager), mappingSlot); + assertEq( + address(uint160(uint256(slotValue))), + address(addressResolver), + "fees plug mismatch" + ); + + // address resolver util slot + assertAddressResolverUtilSlot(108, address(feesManager)); + } + + function assertAddressResolverSlot() internal { + // first + bytes32 slotValue = vm.load(address(addressResolver), bytes32(uint256(FIRST_SLOT))); + assertEq(address(uint160(uint256(slotValue))), address(watcher), "watcher mismatch"); + + // last + hoax(watcherEOA); + addressResolver.setContractAddress(keccak256("auctionManager"), address(auctionManager)); + bytes32 mappingSlot = keccak256(abi.encode(keccak256("auctionManager"), uint256(55))); + slotValue = vm.load(address(addressResolver), mappingSlot); + assertEq( + address(uint160(uint256(slotValue))), + address(auctionManager), + "auctionManager mismatch" + ); + } + + function assertAsyncDeployerSlot() internal { + // first + bytes32 slotValue = vm.load(address(asyncDeployer), bytes32(uint256(FIRST_SLOT))); + assertEq( + address(uint160(uint256(slotValue))), + address(asyncDeployer.forwarderBeacon()), + "forwarderBeacon mismatch" + ); + + // last + hoax(address(watcher)); + asyncDeployer.deployAsyncPromiseContract(address(this), 1); + slotValue = vm.load(address(asyncDeployer), bytes32(uint256(54))); + assertEq(uint256(slotValue), 1, "asyncPromiseCounter mismatch"); + + // address resolver util slot + assertAddressResolverUtilSlot(105, address(asyncDeployer)); + } + + function assertWatcherSlot() internal { + // first + bytes32 slotValue = vm.load(address(watcher), bytes32(uint256(FIRST_SLOT))); + assertEq(uint32(uint256(slotValue)), evmxSlug, "evmxSlug mismatch"); + + // last + uint256 nonce = watcherNonce; + watcherMultiCall( + address(writePrecompile), + abi.encodeWithSelector(WritePrecompile.uploadProof.selector, bytes32(0), bytes32(0)) + ); + bytes32 mappingSlot = keccak256(abi.encode(uint256(nonce), uint256(59))); + slotValue = vm.load(address(watcher), mappingSlot); + assertEq(uint256(slotValue), 1, "isNonceUsed mismatch"); + + // address resolver util slot + assertAddressResolverUtilSlot(110, address(watcher)); + } + + function assertAuctionManagerSlot() internal { + // first + bytes32 slotValue = vm.load(address(auctionManager), bytes32(uint256(FIRST_SLOT))); + assertEq(uint32(uint256(slotValue)), evmxSlug, "evmxSlug mismatch"); + + // last + uint40 requestCount = 1; + uint256 reAuctionCount = 100; + bytes32 mappingSlot = keccak256(abi.encode(uint256(requestCount), uint256(54))); + vm.store(address(auctionManager), mappingSlot, bytes32(uint256(reAuctionCount))); + slotValue = vm.load(address(auctionManager), mappingSlot); + assertEq(uint256(slotValue), reAuctionCount, "reAuctionCount mismatch"); + + // address resolver util slot + assertAddressResolverUtilSlot(106, address(auctionManager)); + + // access control slot + assertAccessControlSlot(165, address(auctionManager)); + } + + function assertDeployForwarderSlot() internal view { + // address resolver util slot + assertAddressResolverUtilSlot(0, address(deployForwarder)); + + // first + bytes32 slotValue = vm.load(address(deployForwarder), bytes32(uint256(100))); + assertEq(uint32(uint256(slotValue)), 0, "saltCounter mismatch"); + + slotValue = vm.load(address(deployForwarder), bytes32(uint256(101))); + assertEq(bytes32(slotValue), FAST, "deployerSwitchboardType mismatch"); + } + + function assertConfigurationsSlot() internal { + // first + uint32 chainSlug = 123; + address plug = address(0xBEEF); + uint256 testValue = 42; + // Compute the slot for _plugConfigs[chainSlug][plug] + bytes32 outerSlot = keccak256(abi.encode(uint256(chainSlug), uint256(50))); + bytes32 mappingSlot = keccak256(abi.encode(plug, outerSlot)); + vm.store(address(configurations), mappingSlot, bytes32(testValue)); + bytes32 slotValue = vm.load(address(configurations), mappingSlot); + assertEq(uint256(slotValue), testValue, "_plugConfigs mapping slot value mismatch"); + + // last + address appGateway = address(0xCAFE); + bool value = true; + // Compute the slot for isValidPlug[appGateway][chainSlug][plug] + bytes32 outerSlot1 = keccak256(abi.encode(appGateway, uint256(53))); + bytes32 outerSlot2 = keccak256(abi.encode(uint256(chainSlug), outerSlot1)); + mappingSlot = keccak256(abi.encode(plug, outerSlot2)); + vm.store(address(configurations), mappingSlot, bytes32(uint256(value ? 1 : 0))); + slotValue = vm.load(address(configurations), mappingSlot); + assertEq(uint256(slotValue), value ? 1 : 0, "isValidPlug mapping slot value mismatch"); + + // watcher base slot + slotValue = vm.load(address(configurations), bytes32(uint256(104))); + assertEq(address(uint160(uint256(slotValue))), address(watcher), "watcher mismatch"); + } + + function assertRequestHandlerSlot() internal { + // first + bytes32 slotValue = vm.load(address(requestHandler), bytes32(uint256(FIRST_SLOT))); + assertEq( + uint40(uint256(slotValue)), + requestHandler.nextRequestCount(), + "nextRequestCount mismatch" + ); + + // last + uint40 requestCount = 1; + uint256 testValue = 42; + // Compute the slot for _requests[requestCount] + bytes32 mappingSlot = keccak256(abi.encode(uint256(requestCount), uint256(55))); + vm.store(address(requestHandler), mappingSlot, bytes32(testValue)); + slotValue = vm.load(address(requestHandler), mappingSlot); + assertEq(uint256(slotValue), testValue, "_requests mapping slot value mismatch"); + + // address resolver util slot + assertAddressResolverUtilSlot(106, address(requestHandler)); + } + + function assertWritePrecompileSlot() internal view { + // first + bytes32 slotValue = vm.load(address(writePrecompile), bytes32(uint256(FIRST_SLOT))); + assertEq(uint256(slotValue), writeFees, "writeFees mismatch"); + + // last + bytes32 mappingSlot = keccak256(abi.encode(uint256(arbChainSlug), uint256(55))); + slotValue = vm.load(address(writePrecompile), mappingSlot); + assertEq( + address(uint160(uint256(slotValue))), + address(arbConfig.contractFactoryPlug), + "contractFactoryPlugs mismatch" + ); + + // watcher base slot + slotValue = vm.load(address(writePrecompile), bytes32(uint256(106))); + assertEq(address(uint160(uint256(slotValue))), address(watcher), "watcher mismatch"); + } + + function assertForwarderSlot() internal { + address forwarder = asyncDeployer.getOrDeployForwarderContract(address(this), evmxSlug); + + // first + bytes32 slotValue = vm.load(address(forwarder), bytes32(uint256(FIRST_SLOT))); + assertEq(uint32(uint256(slotValue)), evmxSlug); + + assertAddressResolverUtilSlot(101, address(forwarder)); + } + + function assertAsyncPromiseSlot() internal { + hoax(address(watcher)); + address asyncPromise = asyncDeployer.deployAsyncPromiseContract(address(this), 100); + + // first + bytes32 slotValue = vm.load(address(asyncPromise), bytes32(uint256(FIRST_SLOT))); + assertEq( + bytes4(bytes32(slotValue)), + bytes4(AsyncPromise(asyncPromise).callbackSelector()), + "callbackSelector mismatch" + ); + + // last + slotValue = vm.load(address(asyncPromise), bytes32(uint256(52))); + assertEq( + bytes32(slotValue), + bytes32(AsyncPromise(asyncPromise).callbackData()), + "callbackData mismatch" + ); + + // address resolver util slot + assertAddressResolverUtilSlot(103, address(asyncPromise)); + } +} + +contract ProxyTest is ProxyStorageAssertions { + function setUp() public { + deploy(); + } + + function testFeesManagerSlot() public { + assertFeesManagerSlot(); + } + + function testAddressResolverSlot() public { + assertAddressResolverSlot(); + } + + function testAsyncDeployerSlot() public { + assertAsyncDeployerSlot(); + } + + function testWatcherSlot() public { + assertWatcherSlot(); + } + + function testAuctionManagerSlot() public { + assertAuctionManagerSlot(); + } + + function testDeployForwarderSlot() public view { + assertDeployForwarderSlot(); + } + + function testConfigurationsSlot() public { + assertConfigurationsSlot(); + } + + function testRequestHandlerSlot() public { + assertRequestHandlerSlot(); + } + + function testWritePrecompileSlot() public view { + assertWritePrecompileSlot(); + } + + function testForwarderSlot() public { + assertForwarderSlot(); + } + + function testAsyncPromiseSlot() public { + assertAsyncPromiseSlot(); + } +} diff --git a/test/SetupTest.t.sol b/test/SetupTest.t.sol index 204f69eb..c818e2ec 100644 --- a/test/SetupTest.t.sol +++ b/test/SetupTest.t.sol @@ -81,6 +81,16 @@ contract SetupStore is Test { SocketContracts public arbConfig; SocketContracts public optConfig; + FeesManager feesManagerImpl; + AddressResolver addressResolverImpl; + AsyncDeployer asyncDeployerImpl; + Watcher watcherImpl; + AuctionManager auctionManagerImpl; + DeployForwarder deployForwarderImpl; + Configurations configurationsImpl; + RequestHandler requestHandlerImpl; + WritePrecompile writePrecompileImpl; + ERC1967Factory public proxyFactory; FeesManager feesManager; FeesPool feesPool; @@ -262,15 +272,15 @@ contract DeploySetup is SetupStore { feesPool = new FeesPool(watcherEOA); // Deploy implementations for upgradeable contracts - FeesManager feesManagerImpl = new FeesManager(); - AddressResolver addressResolverImpl = new AddressResolver(); - AsyncDeployer asyncDeployerImpl = new AsyncDeployer(); - Watcher watcherImpl = new Watcher(); - AuctionManager auctionManagerImpl = new AuctionManager(); - DeployForwarder deployForwarderImpl = new DeployForwarder(); - Configurations configurationsImpl = new Configurations(); - RequestHandler requestHandlerImpl = new RequestHandler(); - WritePrecompile writePrecompileImpl = new WritePrecompile(); + feesManagerImpl = new FeesManager(); + addressResolverImpl = new AddressResolver(); + asyncDeployerImpl = new AsyncDeployer(); + watcherImpl = new Watcher(); + auctionManagerImpl = new AuctionManager(); + deployForwarderImpl = new DeployForwarder(); + configurationsImpl = new Configurations(); + requestHandlerImpl = new RequestHandler(); + writePrecompileImpl = new WritePrecompile(); // Deploy and initialize proxies address addressResolverProxy = _deployAndVerifyProxy( diff --git a/test/Storage.t.sol b/test/Storage.t.sol deleted file mode 100644 index 2aa7bee2..00000000 --- a/test/Storage.t.sol +++ /dev/null @@ -1,77 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -pragma solidity ^0.8.21; - -// contract StorageTest is DeliveryHelperTest { -// DeliveryHelper public deliveryHelperImpl; - -// function setUp() public { -// setUpDeliveryHelper(); -// } - -// function testAddressResolverSlot() public view { -// // Test AddressResolver version at slot 59 -// bytes32 versionSlot = vm.load(address(addressResolver), bytes32(uint256(59))); -// assertEq(uint64(uint256(versionSlot)), 1); - -// // Test auction manager address at slot 61 in AddressResolver -// bytes32 slotValue = vm.load(address(addressResolver), bytes32(uint256(61))); -// assertEq(address(uint160(uint256(slotValue))), address(auctionManager)); -// } - -// function testWatcherPrecompileSlot() public view { -// // Test AddressResolver address at slot 109 in WatcherPrecompile -// bytes32 slotValue = vm.load(address(watcherPrecompile), bytes32(uint256(52))); -// assertEq(uint256(slotValue), evmxSlug); - -// slotValue = vm.load(address(watcherPrecompile), bytes32(uint256(220))); -// assertEq(address(uint160(uint256(slotValue))), address(addressResolver)); -// } - -// function testFeesManagerSlot() public view { -// bytes32 slotValue = vm.load(address(feesManager), bytes32(uint256(51))); -// assertEq(uint32(uint256(slotValue)), evmxSlug); - -// slotValue = vm.load(address(feesManager), bytes32(uint256(106))); -// assertEq(address(uint160(uint256(slotValue))), address(addressResolver)); -// } - -// function testAuctionManagerSlot() public view { -// bytes32 slotValue = vm.load(address(auctionManager), bytes32(uint256(50))); -// assertEq(uint32(uint256(slotValue)), evmxSlug); - -// slotValue = vm.load(address(auctionManager), bytes32(uint256(105))); -// assertEq(address(uint160(uint256(slotValue))), address(addressResolver)); -// } - -// function testForwarderSlot() public { -// address forwarder = addressResolver.getOrDeployForwarderContract( -// address(this), -// address(this), -// evmxSlug -// ); - -// bytes32 slotValue = vm.load(address(forwarder), bytes32(uint256(50))); -// assertEq(uint32(uint256(slotValue)), evmxSlug); - -// slotValue = vm.load(address(forwarder), bytes32(uint256(53))); -// assertEq(address(uint160(uint256(slotValue))), address(0)); -// } - -// function testAsyncPromiseSlot() public { -// address asyncPromise = addressResolver.deployAsyncPromiseContract(address(this)); - -// bytes32 slotValue = vm.load(address(asyncPromise), bytes32(uint256(51))); -// assertEq(address(uint160(uint256(slotValue))), address(this)); - -// slotValue = vm.load(address(asyncPromise), bytes32(uint256(103))); -// assertEq(address(uint160(uint256(slotValue))), address(addressResolver)); -// } - -// function testDeliveryHelperSlot() public view { -// bytes32 slotValue = vm.load(address(deliveryHelper), bytes32(uint256(50))); -// assertEq(uint256(uint256(slotValue)), 0); - -// slotValue = vm.load(address(deliveryHelper), bytes32(uint256(109))); -// assertEq(address(uint160(uint256(slotValue))), address(addressResolver)); -// } -// } diff --git a/test/mock/MockWatcherPrecompile.sol b/test/mock/MockWatcherPrecompile.sol index 3ef3a50a..7ee24975 100644 --- a/test/mock/MockWatcherPrecompile.sol +++ b/test/mock/MockWatcherPrecompile.sol @@ -1,84 +1,68 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import "../../contracts/evmx/interfaces/IAppGateway.sol"; -import "../../contracts/evmx/interfaces/IWatcher.sol"; -import "../../contracts/evmx/interfaces/IPromise.sol"; - -import "../../contracts/utils/common/Structs.sol"; -import "../../contracts/utils/common/Constants.sol"; -import "../../contracts/utils/common/Errors.sol"; -import "solady/utils/ERC1967Factory.sol"; +import "../../contracts/evmx/watcher/Trigger.sol"; /// @title WatcherPrecompile /// @notice Contract that handles payload verification, execution and app configurations -contract MockWatcherPrecompile { - /// @notice Counter for tracking payload execution requests - uint256 public payloadCounter; - - mapping(uint32 => mapping(address => PlugConfig)) internal _plugConfigs; - - event CalledAppGateway(bytes32 triggerId); - - /// @notice Emitted when a new read is requested - /// @param chainSlug The identifier of the destination chain - /// @param targetAddress The address of the target contract - /// @param payloadId The unique identifier for the read - /// @param payload The read data - event ReadRequested(uint32 chainSlug, address targetAddress, bytes32 payloadId, bytes payload); - - /// @notice Emitted when a write proof is requested - event WriteProofRequested(bytes32 digest, PayloadParams params); - - /// @notice Emitted when a request proof is uploaded - /// @param payloadId The unique identifier for the request - /// @param proof The proof from the watcher - event WriteProofUploaded(bytes32 indexed payloadId, bytes proof); - - /// @notice Emitted when a promise is resolved - /// @param payloadId The unique identifier for the resolved promise - event PromiseResolved(bytes32 indexed payloadId); - - /// @notice Emitted when a Schedule is resolved - /// @param scheduleId The unique identifier for the Schedule - /// @param target The target address for the Schedule - /// @param payload The payload data - /// @param executedAt The epoch time when the task was executed - event ScheduleResolved(bytes32 scheduleId, address target, bytes payload, uint256 executedAt); - - /// @notice Contract constructor - /// @param _owner Address of the contract owner - constructor(address _owner, address addressResolver_) {} - - /// @notice Resolves multiple promises with their return data - /// @param promiseReturnData_ Array of resolved promises and their return data - /// @dev Only callable by the contract owner - function resolvePromises(PromiseReturnData[] calldata promiseReturnData_) external { - for (uint256 i = 0; i < promiseReturnData_.length; i++) { - emit PromiseResolved(promiseReturnData_[i].payloadId); - } +contract MockWatcherPrecompile is Trigger { + uint256 public newValue; + + function initialize(uint256 newValue_) external reinitializer(2) { + newValue = newValue_; } - // ================== On-Chain Trigger ================== + function getRequestParams( + uint40 requestCount_ + ) external view override returns (RequestParams memory) {} - function callAppGateways(TriggerParams[] calldata params_) external { - for (uint256 i = 0; i < params_.length; i++) { - emit CalledAppGateway(params_[i].triggerId); - } - } + function getPayloadParams( + bytes32 payloadId_ + ) external view override returns (PayloadParams memory) {} + + function getCurrentRequestCount() external view override returns (uint40) {} + + function queue( + QueueParams calldata queueParams_, + address appGateway_ + ) external override returns (address, uint40) {} + + function clearQueue() external override {} + + function submitRequest( + uint256 maxFees, + address auctionManager, + address consumeFrom, + bytes calldata onCompleteData + ) external override returns (uint40 requestCount, address[] memory promises) {} - /// @notice Retrieves the configuration for a specific plug on a network - /// @param chainSlug_ The identifier of the network - /// @param plug_ The address of the plug - /// @return The app gateway address and switchboard address for the plug - /// @dev Returns zero addresses if configuration doesn't exist - function getPlugConfigs( + function queueAndSubmit( + QueueParams memory queue_, + uint256 maxFees, + address auctionManager, + address consumeFrom, + bytes calldata onCompleteData + ) external override returns (uint40 requestCount, address[] memory promises) {} + + function getPrecompileFees( + bytes4 precompile_, + bytes memory precompileData_ + ) external view override returns (uint256) {} + + function cancelRequest(uint40 requestCount_) external override {} + + function increaseFees(uint40 requestCount_, uint256 newFees_) external override {} + + function setIsValidPlug( + bool isValid_, uint32 chainSlug_, - address plug_ - ) public view returns (bytes32, address) { - return ( - _plugConfigs[chainSlug_][plug_].appGatewayId, - _plugConfigs[chainSlug_][plug_].switchboard - ); + address onchainAddress_ + ) external override {} + + function isWatcher(address account_) external view override returns (bool) {} + + function watcherMultiCall(WatcherMultiCallParams[] memory params_) external payable { + if (isNonceUsed[params_[0].nonce]) revert NonceUsed(); + isNonceUsed[params_[0].nonce] = true; } } From 4b8041818474de90c5899dd3fde3b95be2e7505a Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Fri, 30 May 2025 23:19:48 +0530 Subject: [PATCH 099/130] fix: promise slot test --- test/ProxyStorage.t.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/ProxyStorage.t.sol b/test/ProxyStorage.t.sol index bc08b704..284b84cc 100644 --- a/test/ProxyStorage.t.sol +++ b/test/ProxyStorage.t.sol @@ -138,7 +138,7 @@ contract ProxyStorageAssertions is AppGatewayBaseSetup { assertEq(uint32(uint256(slotValue)), 0, "saltCounter mismatch"); slotValue = vm.load(address(deployForwarder), bytes32(uint256(101))); - assertEq(bytes32(slotValue), FAST, "deployerSwitchboardType mismatch"); + assertEq(bytes32(uint256(slotValue)), FAST, "deployerSwitchboardType mismatch"); } function assertConfigurationsSlot() internal { @@ -227,7 +227,7 @@ contract ProxyStorageAssertions is AppGatewayBaseSetup { // first bytes32 slotValue = vm.load(address(asyncPromise), bytes32(uint256(FIRST_SLOT))); assertEq( - bytes4(bytes32(slotValue)), + bytes4(uint32(uint256(slotValue))), bytes4(AsyncPromise(asyncPromise).callbackSelector()), "callbackSelector mismatch" ); @@ -235,7 +235,7 @@ contract ProxyStorageAssertions is AppGatewayBaseSetup { // last slotValue = vm.load(address(asyncPromise), bytes32(uint256(52))); assertEq( - bytes32(slotValue), + bytes32(uint256(slotValue)), bytes32(AsyncPromise(asyncPromise).callbackData()), "callbackData mismatch" ); From ec8fb1d40cd98914f2c21adbdce170601d448fef Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Fri, 30 May 2025 23:24:34 +0530 Subject: [PATCH 100/130] rm: old tests --- test/Storage.t.sol | 77 ---------------------------------------------- 1 file changed, 77 deletions(-) delete mode 100644 test/Storage.t.sol diff --git a/test/Storage.t.sol b/test/Storage.t.sol deleted file mode 100644 index 2aa7bee2..00000000 --- a/test/Storage.t.sol +++ /dev/null @@ -1,77 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -pragma solidity ^0.8.21; - -// contract StorageTest is DeliveryHelperTest { -// DeliveryHelper public deliveryHelperImpl; - -// function setUp() public { -// setUpDeliveryHelper(); -// } - -// function testAddressResolverSlot() public view { -// // Test AddressResolver version at slot 59 -// bytes32 versionSlot = vm.load(address(addressResolver), bytes32(uint256(59))); -// assertEq(uint64(uint256(versionSlot)), 1); - -// // Test auction manager address at slot 61 in AddressResolver -// bytes32 slotValue = vm.load(address(addressResolver), bytes32(uint256(61))); -// assertEq(address(uint160(uint256(slotValue))), address(auctionManager)); -// } - -// function testWatcherPrecompileSlot() public view { -// // Test AddressResolver address at slot 109 in WatcherPrecompile -// bytes32 slotValue = vm.load(address(watcherPrecompile), bytes32(uint256(52))); -// assertEq(uint256(slotValue), evmxSlug); - -// slotValue = vm.load(address(watcherPrecompile), bytes32(uint256(220))); -// assertEq(address(uint160(uint256(slotValue))), address(addressResolver)); -// } - -// function testFeesManagerSlot() public view { -// bytes32 slotValue = vm.load(address(feesManager), bytes32(uint256(51))); -// assertEq(uint32(uint256(slotValue)), evmxSlug); - -// slotValue = vm.load(address(feesManager), bytes32(uint256(106))); -// assertEq(address(uint160(uint256(slotValue))), address(addressResolver)); -// } - -// function testAuctionManagerSlot() public view { -// bytes32 slotValue = vm.load(address(auctionManager), bytes32(uint256(50))); -// assertEq(uint32(uint256(slotValue)), evmxSlug); - -// slotValue = vm.load(address(auctionManager), bytes32(uint256(105))); -// assertEq(address(uint160(uint256(slotValue))), address(addressResolver)); -// } - -// function testForwarderSlot() public { -// address forwarder = addressResolver.getOrDeployForwarderContract( -// address(this), -// address(this), -// evmxSlug -// ); - -// bytes32 slotValue = vm.load(address(forwarder), bytes32(uint256(50))); -// assertEq(uint32(uint256(slotValue)), evmxSlug); - -// slotValue = vm.load(address(forwarder), bytes32(uint256(53))); -// assertEq(address(uint160(uint256(slotValue))), address(0)); -// } - -// function testAsyncPromiseSlot() public { -// address asyncPromise = addressResolver.deployAsyncPromiseContract(address(this)); - -// bytes32 slotValue = vm.load(address(asyncPromise), bytes32(uint256(51))); -// assertEq(address(uint160(uint256(slotValue))), address(this)); - -// slotValue = vm.load(address(asyncPromise), bytes32(uint256(103))); -// assertEq(address(uint160(uint256(slotValue))), address(addressResolver)); -// } - -// function testDeliveryHelperSlot() public view { -// bytes32 slotValue = vm.load(address(deliveryHelper), bytes32(uint256(50))); -// assertEq(uint256(uint256(slotValue)), 0); - -// slotValue = vm.load(address(deliveryHelper), bytes32(uint256(109))); -// assertEq(address(uint160(uint256(slotValue))), address(addressResolver)); -// } -// } From a83dce96aad425bc5fd00cf749d58f59012c753a Mon Sep 17 00:00:00 2001 From: arthcp Date: Fri, 30 May 2025 21:59:44 +0400 Subject: [PATCH 101/130] feat: proxy deployment for new contracts --- hardhat-scripts/deploy/1.deploy.ts | 39 ++++++++++++------------------ 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/hardhat-scripts/deploy/1.deploy.ts b/hardhat-scripts/deploy/1.deploy.ts index c6e5a877..963ca12a 100644 --- a/hardhat-scripts/deploy/1.deploy.ts +++ b/hardhat-scripts/deploy/1.deploy.ts @@ -159,10 +159,9 @@ const deployEVMxContracts = async () => { deployUtils ); - const auctionManager = await getOrDeploy( - Contracts.AuctionManager, + deployUtils = await deployContractWithProxy( Contracts.AuctionManager, - "contracts/evmx/AuctionManager.sol", + `contracts/evmx/AuctionManager.sol`, [ EVMX_CHAIN_ID, BID_TIMEOUT, @@ -171,37 +170,33 @@ const deployEVMxContracts = async () => { addressResolver.address, EVMxOwner, ], + proxyFactory, deployUtils ); - deployUtils.addresses[Contracts.AuctionManager] = auctionManager.address; - const deployForwarder = await getOrDeploy( - Contracts.DeployForwarder, + deployUtils = await deployContractWithProxy( Contracts.DeployForwarder, - "contracts/evmx/helpers/DeployForwarder.sol", - [addressResolver.address, FAST_SWITCHBOARD_TYPE], + `contracts/evmx/helpers/DeployForwarder.sol`, + [EVMxOwner, addressResolver.address, FAST_SWITCHBOARD_TYPE], + proxyFactory, deployUtils ); - deployUtils.addresses[Contracts.DeployForwarder] = - deployForwarder.address; - const configurations = await getOrDeploy( - Contracts.Configurations, + deployUtils = await deployContractWithProxy( Contracts.Configurations, - "contracts/evmx/watcher/Configurations.sol", + `contracts/evmx/watcher/Configurations.sol`, [deployUtils.addresses[Contracts.Watcher], EVMxOwner], + proxyFactory, deployUtils ); - deployUtils.addresses[Contracts.Configurations] = configurations.address; - const requestHandler = await getOrDeploy( - Contracts.RequestHandler, + deployUtils = await deployContractWithProxy( Contracts.RequestHandler, - "contracts/evmx/watcher/RequestHandler.sol", + `contracts/evmx/watcher/RequestHandler.sol`, [EVMxOwner, addressResolver.address], + proxyFactory, deployUtils ); - deployUtils.addresses[Contracts.RequestHandler] = requestHandler.address; const promiseResolver = await getOrDeploy( Contracts.PromiseResolver, @@ -213,20 +208,18 @@ const deployEVMxContracts = async () => { deployUtils.addresses[Contracts.PromiseResolver] = promiseResolver.address; - const writePrecompile = await getOrDeploy( - Contracts.WritePrecompile, + deployUtils = await deployContractWithProxy( Contracts.WritePrecompile, - "contracts/evmx/watcher/precompiles/WritePrecompile.sol", + `contracts/evmx/watcher/precompiles/WritePrecompile.sol`, [ EVMxOwner, deployUtils.addresses[Contracts.Watcher], WRITE_FEES, EXPIRY_TIME, ], + proxyFactory, deployUtils ); - deployUtils.addresses[Contracts.WritePrecompile] = - writePrecompile.address; const readPrecompile = await getOrDeploy( Contracts.ReadPrecompile, From a098c26414e4f721193641decdd54be6be39a553 Mon Sep 17 00:00:00 2001 From: arthcp Date: Fri, 30 May 2025 22:00:17 +0400 Subject: [PATCH 102/130] fix: initialize conflict --- .gitignore | 3 ++- contracts/evmx/base/AppGatewayBase.sol | 4 ++-- contracts/evmx/interfaces/IAppGateway.sol | 2 +- test/apps/app-gateways/counter/CounterAppGateway.sol | 2 +- test/apps/app-gateways/super-token/SuperTokenAppGateway.sol | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index f72715cd..99e108e6 100644 --- a/.gitignore +++ b/.gitignore @@ -29,4 +29,5 @@ broadcast/ deployments/local_addresses.json deployments/local_verification.json -testScript.sh \ No newline at end of file +testScript.sh +CLAUDE.md diff --git a/contracts/evmx/base/AppGatewayBase.sol b/contracts/evmx/base/AppGatewayBase.sol index 6451ae25..70c3835e 100644 --- a/contracts/evmx/base/AppGatewayBase.sol +++ b/contracts/evmx/base/AppGatewayBase.sol @@ -369,14 +369,14 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { if (onCompleteData_.length == 0) return; (uint32 chainSlug, bool isDeploy) = abi.decode(onCompleteData_, (uint32, bool)); if (isDeploy) { - initialize(chainSlug); + initializeOnChain(chainSlug); } } /// @notice Initializes the contract after deployment /// @dev can be overridden by the app gateway to add custom logic /// @param chainSlug_ The chain slug - function initialize(uint32 chainSlug_) public virtual {} + function initializeOnChain(uint32 chainSlug_) public virtual {} /// @notice hook to handle the revert in callbacks or onchain executions /// @dev can be overridden by the app gateway to add custom logic diff --git a/contracts/evmx/interfaces/IAppGateway.sol b/contracts/evmx/interfaces/IAppGateway.sol index 6af9b399..132e8c96 100644 --- a/contracts/evmx/interfaces/IAppGateway.sol +++ b/contracts/evmx/interfaces/IAppGateway.sol @@ -26,7 +26,7 @@ interface IAppGateway { /// @notice initialize the contracts on chain /// @param chainSlug_ The chain slug - function initialize(uint32 chainSlug_) external; + function initializeOnChain(uint32 chainSlug_) external; /// @notice get the on-chain address of a contract /// @param contractId_ The contract id diff --git a/test/apps/app-gateways/counter/CounterAppGateway.sol b/test/apps/app-gateways/counter/CounterAppGateway.sol index 1e46eeb2..f48807d9 100644 --- a/test/apps/app-gateways/counter/CounterAppGateway.sol +++ b/test/apps/app-gateways/counter/CounterAppGateway.sol @@ -50,7 +50,7 @@ contract CounterAppGateway is AppGatewayBase, Ownable { _setOverrides(Parallel.OFF); } - function initialize(uint32) public pure override { + function initializeOnChain(uint32) public pure override { return; } diff --git a/test/apps/app-gateways/super-token/SuperTokenAppGateway.sol b/test/apps/app-gateways/super-token/SuperTokenAppGateway.sol index b793aeb2..0e835b7e 100644 --- a/test/apps/app-gateways/super-token/SuperTokenAppGateway.sol +++ b/test/apps/app-gateways/super-token/SuperTokenAppGateway.sol @@ -57,7 +57,7 @@ contract SuperTokenAppGateway is AppGatewayBase, Ownable { // no need to call this directly, will be called automatically after all contracts are deployed. // check AppGatewayBase._deploy and AppGatewayBase.onRequestComplete - function initialize(uint32) public pure override { + function initializeOnChain(uint32) public pure override { return; } From 2389f35404aa119c81f656fbc7a2d7cc6390d1f8 Mon Sep 17 00:00:00 2001 From: Akash Date: Mon, 2 Jun 2025 12:21:03 +0530 Subject: [PATCH 103/130] fix: prevDigestHash rename --- contracts/evmx/watcher/precompiles/WritePrecompile.sol | 10 +++++----- contracts/protocol/SocketUtils.sol | 2 +- contracts/utils/common/Structs.sol | 4 ++-- package.json | 6 +++--- test/SetupTest.t.sol | 6 +++--- test/SocketFeeManager.t.sol | 2 +- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/contracts/evmx/watcher/precompiles/WritePrecompile.sol b/contracts/evmx/watcher/precompiles/WritePrecompile.sol index 6bda9002..d9cc56cb 100644 --- a/contracts/evmx/watcher/precompiles/WritePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/WritePrecompile.sol @@ -187,13 +187,13 @@ contract WritePrecompile is IPrecompile, WatcherBase, Ownable { uint40 prevBatchCount = batchCount_ - 1; bytes32[] memory payloadIds = requestHandler__().getBatchPayloadIds(prevBatchCount); - bytes32 prevDigestsHash = bytes32(0); + bytes32 prevBatchDigestHash = bytes32(0); for (uint40 i = 0; i < payloadIds.length; i++) { - prevDigestsHash = keccak256( - abi.encodePacked(prevDigestsHash, digestHashes[payloadIds[i]]) + prevBatchDigestHash = keccak256( + abi.encodePacked(prevBatchDigestHash, digestHashes[payloadIds[i]]) ); } - return prevDigestsHash; + return prevBatchDigestHash; } /// @notice Calculates the digest hash of payload parameters @@ -214,7 +214,7 @@ contract WritePrecompile is IPrecompile, WatcherBase, Ownable { params_.payload, params_.target, params_.appGatewayId, - params_.prevDigestsHash, + params_.prevBatchDigestHash, params_.extraData ) ); diff --git a/contracts/protocol/SocketUtils.sol b/contracts/protocol/SocketUtils.sol index c873d698..4f96ec81 100644 --- a/contracts/protocol/SocketUtils.sol +++ b/contracts/protocol/SocketUtils.sol @@ -84,7 +84,7 @@ abstract contract SocketUtils is SocketConfig { executeParams_.payload, executeParams_.target, appGatewayId_, - executeParams_.prevDigestsHash, + executeParams_.prevBatchDigestHash, executeParams_.extraData ) ); diff --git a/contracts/utils/common/Structs.sol b/contracts/utils/common/Structs.sol index 13cad4a0..80943216 100644 --- a/contracts/utils/common/Structs.sol +++ b/contracts/utils/common/Structs.sol @@ -84,7 +84,7 @@ struct ExecuteParams { uint256 deadline; uint256 gasLimit; uint256 value; - bytes32 prevDigestsHash; + bytes32 prevBatchDigestHash; address target; bytes payload; bytes extraData; @@ -134,7 +134,7 @@ struct DigestParams { bytes payload; address target; bytes32 appGatewayId; - bytes32 prevDigestsHash; + bytes32 prevBatchDigestHash; bytes extraData; } diff --git a/package.json b/package.json index b009f0a3..534293f9 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "publishConfig": { "access": "public" }, - "version": "1.1.19", + "version": "1.1.20", "description": "socket protocol", "scripts": { "build": "yarn abi && tsc --project lib.tsconfig.json", @@ -38,6 +38,7 @@ "hardhat": "2.12.2", "hardhat-abi-exporter": "2.10.1", "hardhat-change-network": "^0.0.7", + "hardhat-contract-sizer": "^2.10.0", "hardhat-deploy": "0.11.20", "hardhat-preprocessor": "0.1.4", "http-server": "^14.1.1", @@ -48,8 +49,7 @@ "prompts": "^2.4.2", "ts-node": "^10.7.0", "typechain": "^8.0.0", - "typescript": "^4.6.4", - "hardhat-contract-sizer": "^2.10.0" + "typescript": "^4.6.4" }, "dependencies": {} } diff --git a/test/SetupTest.t.sol b/test/SetupTest.t.sol index 0cb38ec8..638e152d 100644 --- a/test/SetupTest.t.sol +++ b/test/SetupTest.t.sol @@ -776,7 +776,7 @@ contract WatcherSetup is AuctionSetup { chainSlug = transaction.chainSlug; switchboard = switchboard_; - bytes32 prevDigestsHash = writePrecompile.getPrevBatchDigestHash(payloadParams.batchCount); + bytes32 prevBatchDigestHash = writePrecompile.getPrevBatchDigestHash(payloadParams.batchCount); digestParams = DigestParams( address(getSocketConfig(transaction.chainSlug).socket), transmitterEOA, @@ -788,7 +788,7 @@ contract WatcherSetup is AuctionSetup { transaction.payload, transaction.target, encodeAppGatewayId(appGateway), - prevDigestsHash, + prevBatchDigestHash, bytes("") ); @@ -822,7 +822,7 @@ contract WatcherSetup is AuctionSetup { requestCount: payloadParams.requestCount, batchCount: payloadParams.batchCount, payloadCount: payloadParams.payloadCount, - prevDigestsHash: digestParams.prevDigestsHash, + prevBatchDigestHash: digestParams.prevBatchDigestHash, extraData: digestParams.extraData }), switchboard, diff --git a/test/SocketFeeManager.t.sol b/test/SocketFeeManager.t.sol index 1d7d7810..8809d11e 100644 --- a/test/SocketFeeManager.t.sol +++ b/test/SocketFeeManager.t.sol @@ -137,7 +137,7 @@ contract SocketFeeManagerTest is AppGatewayBaseSetup { requestCount: 0, batchCount: 0, payloadCount: 0, - prevDigestsHash: bytes32(0), + prevBatchDigestHash: bytes32(0), extraData: bytes("") }); From 2a50676c18e02a0c8eabc1539bca1330b2d89b55 Mon Sep 17 00:00:00 2001 From: Akash Date: Mon, 2 Jun 2025 14:15:52 +0530 Subject: [PATCH 104/130] chore: added testnet, mainnet chains to s3 --- Errors.md | 1 + EventTopics.md | 11 +- FunctionSignatures.md | 48 +++- contracts/evmx/fees/Credit.sol | 2 +- contracts/evmx/watcher/Configurations.sol | 6 +- deployments/dev_addresses.json | 68 +++--- deployments/dev_verification.json | 270 ++++++++-------------- hardhat-scripts/config/config.ts | 15 +- hardhat-scripts/deploy/1.deploy.ts | 21 -- hardhat-scripts/s3Config/buildConfig.ts | 10 +- src/types.ts | 2 + test/SetupTest.t.sol | 4 +- 12 files changed, 207 insertions(+), 251 deletions(-) diff --git a/Errors.md b/Errors.md index 00d099e1..c9ef6e7e 100644 --- a/Errors.md +++ b/Errors.md @@ -14,6 +14,7 @@ | `OnlyInvoker()` | `0x74ed21f5` | | `PromiseAlreadySetUp()` | `0x927c53d5` | | `PromiseRevertFailed()` | `0x0175b9de` | +| `NotLatestPromise()` | `0x39ca95d3` | ## evmx/plugs/ContractFactoryPlug.sol diff --git a/EventTopics.md b/EventTopics.md index 34f5e4bb..36cadb7d 100644 --- a/EventTopics.md +++ b/EventTopics.md @@ -9,6 +9,7 @@ | `AuctionRestarted` | `(requestCount: uint40)` | `0x071867b21946ec4655665f0d4515d3757a5a52f144c762ecfdfb11e1da542b82` | | `AuctionStarted` | `(requestCount: uint40)` | `0xcd040613cf8ef0cfcaa3af0d711783e827a275fc647c116b74595bf17cb9364f` | | `BidPlaced` | `(requestCount: uint40, bid: tuple)` | `0x7f79485e4c9aeea5d4899bc6f7c63b22ac1f4c01d2d28c801e94732fee657b5d` | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | | `MaxReAuctionCountSet` | `(maxReAuctionCount: uint256)` | `0x2f6fadde7ab8ab83d21ab10c3bc09dde179f8696d47c4176581facf0c6f96bbf` | | `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | | `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | @@ -118,8 +119,12 @@ ## DeployForwarder -| Event | Arguments | Topic | -| ----- | --------- | ----- | +| Event | Arguments | Topic | +| ---------------------------- | ---------------------------------------- | -------------------------------------------------------------------- | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | ## Forwarder @@ -195,6 +200,7 @@ | Event | Arguments | Topic | | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | | `FeesIncreased` | `(requestCount: uint40, newMaxFees: uint256)` | `0xf258fca4e49b803ee2a4c2e33b6fcf18bc3982df21f111c00677025bf1ccbb6a` | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | | `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | | `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | | `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | @@ -255,6 +261,7 @@ | `ContractFactoryPlugSet` | `(chainSlug: uint32, contractFactoryPlug: address)` | `0x85bfa413b9e5e225278f51af2ac872988e0a9374263b118d963c50945ea888bb` | | `ExpiryTimeSet` | `(expiryTime: uint256)` | `0x07e837e13ad9a34715a6bd45f49bbf12de19f06df79cb0be12b3a7d7f2397fa9` | | `FeesSet` | `(writeFees: uint256)` | `0x3346af6da1932164d501f2ec28f8c5d686db5828a36b77f2da4332d89184fe7b` | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | | `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | | `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | | `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | diff --git a/FunctionSignatures.md b/FunctionSignatures.md index ab3f68b0..126336f5 100644 --- a/FunctionSignatures.md +++ b/FunctionSignatures.md @@ -26,7 +26,8 @@ | `grantRole` | `0x2f2ff15d` | | `handleRevert` | `0x44792f25` | | `hasRole` | `0x91d14854` | -| `initialize` | `0x8d8965bd` | +| `initialize` | `0x86891c9b` | +| `initializeOnChain` | `0x86f01739` | | `isAsyncModifierSet` | `0xb69e0c4a` | | `isValidPromise` | `0xb690b962` | | `maxFees` | `0xe83e34b1` | @@ -39,6 +40,7 @@ | `reAuctionCount` | `0x9b4b22d3` | | `renounceOwnership` | `0x715018a6` | | `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | | `revokeRole` | `0xd547741f` | | `sbType` | `0x745de344` | | `setAddress` | `0x85bf312c` | @@ -145,6 +147,7 @@ | `renounceOwnership` | `0x715018a6` | | `requestBlockedCredits` | `0xb62d25ac` | | `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | | `sbType` | `0x745de344` | | `setFeesPlug` | `0xeab75f36` | | `setFeesPool` | `0xd6684588` | @@ -192,6 +195,7 @@ | `ownershipHandoverExpiresAt` | `0xfee81cf4` | | `renounceOwnership` | `0x715018a6` | | `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | | `setAsyncDeployer` | `0xcb0ffff8` | | `setContractAddress` | `0xe001f841` | | `setDefaultAuctionManager` | `0xede8b4b5` | @@ -225,6 +229,7 @@ | `ownershipHandoverExpiresAt` | `0xfee81cf4` | | `renounceOwnership` | `0x715018a6` | | `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | | `setAsyncPromiseImplementation` | `0xeb506eab` | | `setForwarderImplementation` | `0x83b1e974` | | `transferOwnership` | `0xf2fde38b` | @@ -246,6 +251,7 @@ | `markOnchainRevert` | `0xd0e7af1b` | | `markResolved` | `0x822d5d1f` | | `requestCount` | `0x5badbe4c` | +| `rescueFunds` | `0x6ccae054` | | `returnData` | `0xebddbaf6` | | `state` | `0xc19d93fb` | | `then` | `0x0bf2ba15` | @@ -253,16 +259,25 @@ ## DeployForwarder -| Function | Signature | -| ------------------------- | ------------ | -| `addressResolver__` | `0x6a750469` | -| `asyncDeployer__` | `0x2a39e801` | -| `deploy` | `0x940f11af` | -| `deployForwarder__` | `0xd4e3b034` | -| `deployerSwitchboardType` | `0xaa381f9a` | -| `feesManager__` | `0x70568b58` | -| `saltCounter` | `0xa04c6809` | -| `watcher__` | `0x300bb063` | +| Function | Signature | +| ---------------------------- | ------------ | +| `addressResolver__` | `0x6a750469` | +| `asyncDeployer__` | `0x2a39e801` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `deploy` | `0x940f11af` | +| `deployForwarder__` | `0xd4e3b034` | +| `deployerSwitchboardType` | `0xaa381f9a` | +| `feesManager__` | `0x70568b58` | +| `initialize` | `0x6133f985` | +| `owner` | `0x8da5cb5b` | +| `ownershipHandoverExpiresAt` | `0xfee81cf4` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | +| `saltCounter` | `0xa04c6809` | +| `transferOwnership` | `0xf2fde38b` | +| `watcher__` | `0x300bb063` | ## Forwarder @@ -277,6 +292,7 @@ | `getOnChainAddress` | `0x9da48789` | | `initialize` | `0x647c576c` | | `onChainAddress` | `0x8bd0b363` | +| `rescueFunds` | `0x6ccae054` | | `watcher__` | `0x300bb063` | ## ProxyFactory @@ -344,11 +360,13 @@ | `cancelOwnershipHandover` | `0x54d1f13d` | | `completeOwnershipHandover` | `0xf04e283e` | | `getPlugConfigs` | `0x8a028c38` | +| `initialize` | `0x485cc955` | | `isValidPlug` | `0xec8aef74` | | `owner` | `0x8da5cb5b` | | `ownershipHandoverExpiresAt` | `0xfee81cf4` | | `renounceOwnership` | `0x715018a6` | | `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | | `setAppGatewayConfigs` | `0xd137fcbb` | | `setIsValidPlug` | `0xf41332b0` | | `setSocket` | `0x075c40be` | @@ -364,6 +382,7 @@ | Function | Signature | | ----------------- | ------------ | | `markRevert` | `0x56501015` | +| `rescueFunds` | `0x6ccae054` | | `resolvePromises` | `0xbf8484b8` | | `watcher__` | `0x300bb063` | @@ -387,6 +406,7 @@ | `getRequestBatchIds` | `0xe138fadb` | | `handleRevert` | `0xcc88d3f9` | | `increaseFees` | `0x10205541` | +| `initialize` | `0x485cc955` | | `nextBatchCount` | `0x333a3963` | | `nextRequestCount` | `0xfef72893` | | `owner` | `0x8da5cb5b` | @@ -395,6 +415,7 @@ | `precompiles` | `0x9932450b` | | `renounceOwnership` | `0x715018a6` | | `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | | `setPrecompile` | `0x122e0042` | | `submitRequest` | `0xbb299a2c` | | `transferOwnership` | `0xf2fde38b` | @@ -436,6 +457,7 @@ | `renounceOwnership` | `0x715018a6` | | `requestHandler__` | `0x55184561` | | `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0xa58c6fc5` | | `setCoreContracts` | `0xefa891c4` | | `setIsValidPlug` | `0x7fc82ff6` | | `setTriggerFees` | `0xaeb30511` | @@ -477,6 +499,7 @@ | `getPrecompileFees` | `0xb7a3d04c` | | `handlePayload` | `0x1d5e1d98` | | `readFees` | `0xe06357a2` | +| `rescueFunds` | `0x6ccae054` | | `resolvePayload` | `0xea92e825` | | `setExpiryTime` | `0x30fc4cff` | | `setFees` | `0x3d18678e` | @@ -491,6 +514,7 @@ | `getPrecompileFees` | `0xb7a3d04c` | | `handlePayload` | `0x1d5e1d98` | | `maxScheduleDelayInSeconds` | `0x3ef01cdb` | +| `rescueFunds` | `0x6ccae054` | | `resolvePayload` | `0xea92e825` | | `scheduleCallbackFees` | `0x4c5b6007` | | `scheduleFeesPerSecond` | `0x852a74c1` | @@ -515,10 +539,12 @@ | `getPrecompileFees` | `0xb7a3d04c` | | `getPrevBatchDigestHash` | `0x82b35b69` | | `handlePayload` | `0x1d5e1d98` | +| `initialize` | `0xeb990c59` | | `owner` | `0x8da5cb5b` | | `ownershipHandoverExpiresAt` | `0xfee81cf4` | | `renounceOwnership` | `0x715018a6` | | `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | | `resolvePayload` | `0xea92e825` | | `setContractFactoryPlugs` | `0xc067b6dd` | | `setExpiryTime` | `0x30fc4cff` | diff --git a/contracts/evmx/fees/Credit.sol b/contracts/evmx/fees/Credit.sol index d15e73a7..fb9dd643 100644 --- a/contracts/evmx/fees/Credit.sol +++ b/contracts/evmx/fees/Credit.sol @@ -22,7 +22,7 @@ abstract contract FeesManagerStorage is IFeesManager { // slot 50 /// @notice evmx slug uint32 public evmxSlug; - + IFeesPool public feesPool; // slot 51 diff --git a/contracts/evmx/watcher/Configurations.sol b/contracts/evmx/watcher/Configurations.sol index 21c2b4ea..2674f7fb 100644 --- a/contracts/evmx/watcher/Configurations.sol +++ b/contracts/evmx/watcher/Configurations.sol @@ -170,11 +170,7 @@ contract Configurations is ConfigurationsStorage, Initializable, Ownable, Watche * @param rescueTo_ The address where rescued tokens need to be sent. * @param amount_ The amount of tokens to be rescued. */ - function rescueFunds( - address token_, - address rescueTo_, - uint256 amount_ - ) external onlyWatcher { + function rescueFunds(address token_, address rescueTo_, uint256 amount_) external onlyWatcher { RescueFundsLib._rescueFunds(token_, rescueTo_, amount_); } } diff --git a/deployments/dev_addresses.json b/deployments/dev_addresses.json index 72af1b71..22993cb6 100644 --- a/deployments/dev_addresses.json +++ b/deployments/dev_addresses.json @@ -1,38 +1,46 @@ { "421614": { - "ContractFactoryPlug": "0x9dEa956E863a44a24c1CE068460E6190EA438602", - "FastSwitchboard": "0xb4C5A231614639801F421Ca386388f65576F3c81", - "FeesPlug": "0x2fc70A464588b3f692D5C500Bfe3A2F2165911aD", - "Socket": "0xBd0436A6E0dee11e9359767142Ed6bD7B48ba258", - "SocketBatcher": "0x1683c3AB4954852f71f400AbDeF98112a066ee44", - "startBlock": 148461456, - "TestUSDC": "0x3f134B047620590a0b7a2f98d5F9B07D32d4D927" + "ContractFactoryPlug": "0xaCd26f991E548F353f285942509d90200064Cf14", + "FastSwitchboard": "0xbcc1CE144cA85C0d121f08634547a61E93627ce4", + "FeesPlug": "0xb0cbd56A86568BB4cBBE59B0EcA029A4F2D7f235", + "Socket": "0xEb907f52eAF6e81439F8807AE2F143Bd3482e6b6", + "SocketBatcher": "0xc498A63eE84143A15A7D3080E1E51af700f35e41", + "startBlock": 159285686, + "TestUSDC": "0x2321BF7AdFaf49b1338F1Cd474859dBc0D8dfA96" }, "7625382": { - "AddressResolver": "0x9EAa5b231c1DF8c5660dDC5fE7cD06a9D86e26f0", - "AddressResolverImpl": "0x4b067469E7865d9959E0E658BA77ec4b0F28FB15", - "AuctionManager": "0x2b1F13479D9D2E53E1487169b9C9073958710170", - "AuctionManagerImpl": "0x23364acdd298EBB3Dfd3c1835C5ACd7f77E3E2bD", - "DeliveryHelper": "0xe557Ba90Dd94Aa0Dd49DD6467f1e7d196C6Bd179", - "DeliveryHelperImpl": "0x915eA695e03265998cd455B4df2A1EAeb1b61e74", - "ERC1967Factory": "0xb30eBbA571721923175751AE7aF5aC90cfb1E892", - "FeesManager": "0xBf9529b5aA4a6a047Ff65CfAE9613A274C479143", - "FeesManagerImpl": "0xB577c29F7Cbb1bBB314dD8E74059Aa5BF72838b0", - "startBlock": 5537530, - "WatcherPrecompile": "0xB0CC4C4a6706E265306daCa279Ce60D1052b2782", - "WatcherPrecompileConfig": "0xD0F77272a5F0208f20c836bB4eeddbCE1e4aef9d", - "WatcherPrecompileConfigImpl": "0x060b4a50EcCC9Cf329005c94406dd2886676F759", - "WatcherPrecompileImpl": "0xe1CA4da421C52161B4EecCE6F5Cb2937554e2958", - "WatcherPrecompileLimits": "0x4A645F050166FaBdA7ce44BE90B0A61073C19696", - "WatcherPrecompileLimitsImpl": "0x4Fd04B0D4903e630F169BB228be52750E6B5331a" + "AddressResolver": "0xF7efc3886b225A571d35C2DF736eD515F132911F", + "AddressResolverImpl": "0x865A24Cf706027639124489e0dA2A28766efB96A", + "AsyncDeployer": "0xC1A87C08d86bE83323F071362Cf4f48C946b9d00", + "AsyncDeployerImpl": "0xF4f5606189Bc091528680b2ca1c82167641d3cAf", + "AuctionManager": "0xEdf413851964c6Ac5154FA768F3e54e9BeB777dB", + "AuctionManagerImpl": "0x1C40B5d5f6E9be1Ca4557d92cb7dba35e721a322", + "Configurations": "0x5A6c10F1c7bEf419022be7c2F716CC4628cBa3Cf", + "ConfigurationsImpl": "0x8d41aBDbE6Bbd208D68Dd4E671c4B72474525C7B", + "DeployForwarder": "0xD0d5BAF888afE7F857B5AeF74A63bE7416B742eE", + "DeployForwarderImpl": "0xD9CF47342c8a256fcD8B51aaABA810cd5D05F726", + "ERC1967Factory": "0x1b0F1aA38F8BBbe779A6C1fCe7e3Ff00380fa9CE", + "FeesManager": "0x07653B23F84aB397649378BB512bd82D19D9D6F1", + "FeesManagerImpl": "0x255fBaD02F8f2Aae0Faf7074249a8701371890D2", + "FeesPool": "0xc20Be67ef742202dc93A78aa741E7C3715eA1DFd", + "PromiseResolver": "0xF24B41A8C9F814d70FAD9E617CE32C74EcCB1A25", + "ReadPrecompile": "0xddeEDDD5F156123fDbf77B86A66A043568AEfcda", + "RequestHandler": "0x52968Eb279aad2287aF4C9a4638C146F91787958", + "RequestHandlerImpl": "0x1fa5D12C7dC1F3615c28B842A6053f5f151230F8", + "SchedulePrecompile": "0xDa60303321dc6aA8AeF32557bDe914008a3196eC", + "startBlock": 8263673, + "Watcher": "0x60005b459Dc46D9a63bcb61D01Ad002130644a4F", + "WatcherImpl": "0x812EcdF5366036B045e41Fe2dD95B72ecc26d8f3", + "WritePrecompile": "0xF221bAA9AEA24c366258309ab09C2C7ce80610Fc", + "WritePrecompileImpl": "0xb64D07B0dDb23cc54eE5EDe294E0cD15f08CC971" }, "11155420": { - "ContractFactoryPlug": "0x95Be4D8500e3e5C970802c64b0755027d4Fc5C9F", - "FastSwitchboard": "0xe7858f1dc202f5E9C9B3ee6db052F45164a88534", - "FeesPlug": "0x29b77ecEf2D163528d1F4A235c0795daDD2DA1Bf", - "Socket": "0xE09CC429e77EE5DBeF68f3796b2A33BBDF39C03C", - "SocketBatcher": "0x9175d90706a2b17f0aE025ce5A6C76e64850c2f5", - "startBlock": 27158986, - "TestUSDC": "0x3D7515519beab77B541497626CFB7E764F6887CD" + "ContractFactoryPlug": "0xf134E3a725DdbBebf9e0f66D6767B44468cdBB48", + "FastSwitchboard": "0xa2E9eC2B0e035650744B6F489e8dDd471B502b2b", + "FeesPlug": "0x64b7157Fe0878880b180d9BD2a0bd0D1794Cf44A", + "Socket": "0xd8C787c27Cc6F4BF143855Bb50c880FB2DE38267", + "SocketBatcher": "0xc6Fe653dAfeDd76d50e3F971dDA650917824f948", + "startBlock": 28522517, + "TestUSDC": "0x15dbE4B96306Cc9Eba15D834d6c1a895cF4e1697" } } diff --git a/deployments/dev_verification.json b/deployments/dev_verification.json index cb1975f3..2e26ac90 100644 --- a/deployments/dev_verification.json +++ b/deployments/dev_verification.json @@ -1,254 +1,168 @@ { - "84532": [ - [ - "0xFEFdbD9CB5bdC58Aa8B6B455923454275392838c", - "ContractFactoryPlug", - "contracts/protocol/payload-delivery/ContractFactoryPlug.sol", - [ - "0x89e66357C5F101C56b4F9F97cf378Cc32A21438a", - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" - ] - ], - [ - "0xBBff19fBEAd971f39F1B298De985D7ADfb57b784", - "FeesPlug", - "contracts/protocol/payload-delivery/FeesPlug.sol", - [ - "0x89e66357C5F101C56b4F9F97cf378Cc32A21438a", - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" - ] - ], - [ - "0xCc9f995DAE2D3Cf3C0763e353986E97ab78801b4", - "FastSwitchboard", - "contracts/protocol/socket/switchboard/FastSwitchboard.sol", - [ - 84532, - "0x89e66357C5F101C56b4F9F97cf378Cc32A21438a", - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" - ] - ], - [ - "0x3bABE35428D9E2B87d678289f837F805dAB0db3A", - "SocketBatcher", - "contracts/protocol/socket/SocketBatcher.sol", - [ - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", - "0x89e66357C5F101C56b4F9F97cf378Cc32A21438a" - ] - ], - [ - "0x89e66357C5F101C56b4F9F97cf378Cc32A21438a", - "Socket", - "contracts/protocol/socket/Socket.sol", - [84532, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] - ] - ], - "421614": [ + "421614": [], + "7625382": [ [ - "0x092194e4Cd90d950ED91bD216472A18cCA7cd8F7", - "FeesPlug", - "contracts/protocol/payload-delivery/FeesPlug.sol", + "0xDa60303321dc6aA8AeF32557bDe914008a3196eC", + "SchedulePrecompile", + "contracts/evmx/watcher/precompiles/SchedulePrecompile.sol", [ - "0xBd0436A6E0dee11e9359767142Ed6bD7B48ba258", - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + "0x60005b459Dc46D9a63bcb61D01Ad002130644a4F", + 86400, + { + "type": "BigNumber", + "hex": "0xe8d4a51000" + }, + { + "type": "BigNumber", + "hex": "0xe8d4a51000" + }, + 300 ] ], [ - "0x44f182553Ccdd82f95b592a935Bd7Dd90FF7F292", - "FeesPlug", - "contracts/protocol/payload-delivery/FeesPlug.sol", + "0xddeEDDD5F156123fDbf77B86A66A043568AEfcda", + "ReadPrecompile", + "contracts/evmx/watcher/precompiles/ReadPrecompile.sol", [ - "0xBd0436A6E0dee11e9359767142Ed6bD7B48ba258", - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + "0x60005b459Dc46D9a63bcb61D01Ad002130644a4F", + { + "type": "BigNumber", + "hex": "0xe8d4a51000" + }, + 300 ] - ] - ], - "7625382": [ - [ - "0xe1CA4da421C52161B4EecCE6F5Cb2937554e2958", - "WatcherPrecompile", - "contracts/protocol/watcherPrecompile/core/WatcherPrecompile.sol", - [] ], [ - "0x23364acdd298EBB3Dfd3c1835C5ACd7f77E3E2bD", - "AuctionManager", - "contracts/protocol/payload-delivery/AuctionManager.sol", + "0xb64D07B0dDb23cc54eE5EDe294E0cD15f08CC971", + "WritePrecompile", + "contracts/evmx/watcher/precompiles/WritePrecompile.sol", [] ], [ - "0x915eA695e03265998cd455B4df2A1EAeb1b61e74", - "DeliveryHelper", - "contracts/protocol/payload-delivery/app-gateway/DeliveryHelper.sol", - [] + "0xF24B41A8C9F814d70FAD9E617CE32C74EcCB1A25", + "PromiseResolver", + "contracts/evmx/watcher/PromiseResolver.sol", + ["0x60005b459Dc46D9a63bcb61D01Ad002130644a4F"] ], [ - "0xB577c29F7Cbb1bBB314dD8E74059Aa5BF72838b0", - "FeesManager", - "contracts/protocol/payload-delivery/FeesManager.sol", + "0x1fa5D12C7dC1F3615c28B842A6053f5f151230F8", + "RequestHandler", + "contracts/evmx/watcher/RequestHandler.sol", [] ], [ - "0x1BCe40d84499Db8E7Bc65277A32f0abd56588CC7", - "WatcherPrecompile", - "contracts/protocol/watcherPrecompile/core/WatcherPrecompile.sol", + "0x8d41aBDbE6Bbd208D68Dd4E671c4B72474525C7B", + "Configurations", + "contracts/evmx/watcher/Configurations.sol", [] ], [ - "0x060b4a50EcCC9Cf329005c94406dd2886676F759", - "WatcherPrecompileConfig", - "contracts/protocol/watcherPrecompile/WatcherPrecompileConfig.sol", + "0xD9CF47342c8a256fcD8B51aaABA810cd5D05F726", + "DeployForwarder", + "contracts/evmx/helpers/DeployForwarder.sol", [] ], [ - "0x4Fd04B0D4903e630F169BB228be52750E6B5331a", - "WatcherPrecompileLimits", - "contracts/protocol/watcherPrecompile/WatcherPrecompileLimits.sol", - [] - ], - [ - "0x4b067469E7865d9959E0E658BA77ec4b0F28FB15", - "AddressResolver", - "contracts/protocol/AddressResolver.sol", - [] - ], - [ - "0xb30eBbA571721923175751AE7aF5aC90cfb1E892", - "ERC1967Factory", - "lib/solady/src/utils/ERC1967Factory.sol", - [] - ], - [ - "0x2c50B6e519e0705A396E5c8652E5D447F37f9796", - "FeesManager", - "contracts/protocol/payload-delivery/FeesManager.sol", - [] - ], - [ - "0x233539d6BBf231660652AF00B5d6E850E892946a", - "WatcherPrecompile", - "contracts/protocol/watcherPrecompile/WatcherPrecompile.sol", - [] - ], - [ - "0x4D0FA91403b4902B56Ad650aF2BA9D4fcA46aB0B", - "WatcherPrecompile", - "contracts/protocol/watcherPrecompile/WatcherPrecompile.sol", - [] - ], - [ - "0xaE4624b006D7730f22De1F7df5b1C0b960262AE3", + "0x1C40B5d5f6E9be1Ca4557d92cb7dba35e721a322", "AuctionManager", - "contracts/protocol/payload-delivery/AuctionManager.sol", + "contracts/evmx/AuctionManager.sol", [] ], [ - "0xE693bEc40e39223749AC351156E713b7256541B0", - "DeliveryHelper", - "contracts/protocol/payload-delivery/app-gateway/DeliveryHelper.sol", + "0x812EcdF5366036B045e41Fe2dD95B72ecc26d8f3", + "Watcher", + "contracts/evmx/watcher/Watcher.sol", [] ], [ - "0xc2Ca571f4d4C2008Da4Bd750BaD3d50A5705ffF8", - "FeesManager", - "contracts/protocol/payload-delivery/FeesManager.sol", + "0xF4f5606189Bc091528680b2ca1c82167641d3cAf", + "AsyncDeployer", + "contracts/evmx/helpers/AsyncDeployer.sol", [] ], [ - "0x4894D35BF607BB47099172d42133ffe411a1d4B8", - "WatcherPrecompile", - "contracts/protocol/watcherPrecompile/WatcherPrecompile.sol", + "0x255fBaD02F8f2Aae0Faf7074249a8701371890D2", + "FeesManager", + "contracts/evmx/fees/FeesManager.sol", [] ], [ - "0xE4a2eBcE3Bdcaa1861c01ddc6465b90311B749e4", - "WatcherPrecompileConfig", - "contracts/protocol/watcherPrecompile/WatcherPrecompileConfig.sol", + "0x865A24Cf706027639124489e0dA2A28766efB96A", + "AddressResolver", + "contracts/evmx/helpers/AddressResolver.sol", [] ], [ - "0xdfeA8cb793b84b3f046d2426259e0eC237Ec9bF3", - "WatcherPrecompileLimits", - "contracts/protocol/watcherPrecompile/WatcherPrecompileLimits.sol", - [] + "0xc20Be67ef742202dc93A78aa741E7C3715eA1DFd", + "FeesPool", + "contracts/evmx/fees/FeesPool.sol", + ["0xb62505feacC486e809392c65614Ce4d7b051923b"] ], [ - "0x2736Fc0AA0fa5Ca595Ae5F27Ec807B912A5b1D0f", - "AddressResolver", - "contracts/protocol/AddressResolver.sol", - [] - ], - [ - "0x122beAFCfc2E99D825322a78EAFD8a11fa2d9E0b", + "0x1b0F1aA38F8BBbe779A6C1fCe7e3Ff00380fa9CE", "ERC1967Factory", "lib/solady/src/utils/ERC1967Factory.sol", [] ] ], - "11155111": [ + "11155420": [ [ - "0xdd7b56968a3505D1A10181F2880cAA65a89E4750", + "0xf134E3a725DdbBebf9e0f66D6767B44468cdBB48", "ContractFactoryPlug", - "contracts/protocol/payload-delivery/ContractFactoryPlug.sol", + "contracts/evmx/plugs/ContractFactoryPlug.sol", [ - "0xF86B89B5c689c170BfD2734254228D6d2db5a672", + "0xd8C787c27Cc6F4BF143855Bb50c880FB2DE38267", "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" ] ], [ - "0xfBa932AaE9Ae2777aEC77832FC0C2D9059C8E905", + "0x64b7157Fe0878880b180d9BD2a0bd0D1794Cf44A", "FeesPlug", - "contracts/protocol/payload-delivery/FeesPlug.sol", + "contracts/evmx/plugs/FeesPlug.sol", [ - "0xF86B89B5c689c170BfD2734254228D6d2db5a672", + "0xd8C787c27Cc6F4BF143855Bb50c880FB2DE38267", "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" ] ], [ - "0xb34DB19C7FAeECf14B3D0336C6E34f7dc1336968", + "0x15dbE4B96306Cc9Eba15D834d6c1a895cF4e1697", + "TestUSDC", + "contracts/evmx/mocks/TestUSDC.sol", + [ + "testUSDC", + "testUSDC", + 6, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + { + "type": "BigNumber", + "hex": "0x0b7abc627050305adf14a3d9e40000000000" + } + ] + ], + [ + "0xa2E9eC2B0e035650744B6F489e8dDd471B502b2b", "FastSwitchboard", - "contracts/protocol/socket/switchboard/FastSwitchboard.sol", + "contracts/protocol/switchboard/FastSwitchboard.sol", [ - 11155111, - "0xF86B89B5c689c170BfD2734254228D6d2db5a672", + 11155420, + "0xd8C787c27Cc6F4BF143855Bb50c880FB2DE38267", "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" ] ], [ - "0x466b51bcc1799A4cb8F629C46640ab3aA2608F75", + "0xc6Fe653dAfeDd76d50e3F971dDA650917824f948", "SocketBatcher", - "contracts/protocol/socket/SocketBatcher.sol", + "contracts/protocol/SocketBatcher.sol", [ "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", - "0xF86B89B5c689c170BfD2734254228D6d2db5a672" + "0xd8C787c27Cc6F4BF143855Bb50c880FB2DE38267" ] ], [ - "0xF86B89B5c689c170BfD2734254228D6d2db5a672", + "0xd8C787c27Cc6F4BF143855Bb50c880FB2DE38267", "Socket", - "contracts/protocol/socket/Socket.sol", - [11155111, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] - ] - ], - "11155420": [ - [ - "0x78775DCd56fBdb903e4d83AE51924797a74AD49d", - "FeesPlug", - "contracts/protocol/payload-delivery/FeesPlug.sol", - [ - "0xE09CC429e77EE5DBeF68f3796b2A33BBDF39C03C", - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" - ] - ], - [ - "0x8eD0cebe57236Bf85b0a74951CeE74357B1d381D", - "FeesPlug", - "contracts/protocol/payload-delivery/FeesPlug.sol", - [ - "0xE09CC429e77EE5DBeF68f3796b2A33BBDF39C03C", - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" - ] + "contracts/protocol/Socket.sol", + [11155420, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] ] ] } diff --git a/hardhat-scripts/config/config.ts b/hardhat-scripts/config/config.ts index 022727f3..bb7303eb 100644 --- a/hardhat-scripts/config/config.ts +++ b/hardhat-scripts/config/config.ts @@ -34,6 +34,9 @@ export const getChains = () => { ChainSlug.OPTIMISM_SEPOLIA, ChainSlug.ARBITRUM_SEPOLIA, ChainSlug.BASE_SEPOLIA, + ChainSlug.BASE, + ChainSlug.ARBITRUM, + ChainSlug.OPTIMISM, ]; case DeploymentMode.PROD: return [ @@ -46,6 +49,16 @@ export const getChains = () => { throw new Error(`Invalid deployment mode: ${mode}`); } }; +export const testnetChains: Array = [ + ChainSlug.OPTIMISM_SEPOLIA, + ChainSlug.ARBITRUM_SEPOLIA, + ChainSlug.BASE_SEPOLIA, +]; +export const mainnetChains: Array = [ + ChainSlug.OPTIMISM, + ChainSlug.ARBITRUM, + ChainSlug.BASE, +]; export const chains: Array = getChains(); export const EVM_CHAIN_ID_MAP: Record = { @@ -78,7 +91,7 @@ export const TEST_USDC_DECIMALS = 6; // Fees Pool Funding Amount export const FEES_POOL_FUNDING_AMOUNT_THRESHOLD = - ethers.utils.parseEther("10000"); + ethers.utils.parseEther("1000"); // Watcher Precompile Fees export const READ_FEES = utils.parseEther("0.000001"); diff --git a/hardhat-scripts/deploy/1.deploy.ts b/hardhat-scripts/deploy/1.deploy.ts index 963ca12a..effbbcad 100644 --- a/hardhat-scripts/deploy/1.deploy.ts +++ b/hardhat-scripts/deploy/1.deploy.ts @@ -16,10 +16,6 @@ import { READ_FEES, SCHEDULE_CALLBACK_FEES, SCHEDULE_FEES_PER_SECOND, - TEST_USDC_DECIMALS, - TEST_USDC_INITIAL_SUPPLY, - TEST_USDC_NAME, - TEST_USDC_SYMBOL, TRIGGER_FEES, WRITE_FEES, } from "../config/config"; @@ -319,23 +315,6 @@ const deploySocketContracts = async () => { ); deployUtils.addresses[contractName] = sb.address; - contractName = Contracts.TestUSDC; - - const testUSDC: Contract = await getOrDeploy( - contractName, - contractName, - `contracts/evmx/mocks/${contractName}.sol`, - [ - TEST_USDC_NAME, - TEST_USDC_SYMBOL, - TEST_USDC_DECIMALS, - socketOwner, - TEST_USDC_INITIAL_SUPPLY, - ], - deployUtils - ); - deployUtils.addresses[contractName] = testUSDC.address; - contractName = Contracts.FeesPlug; const feesPlug: Contract = await getOrDeploy( contractName, diff --git a/hardhat-scripts/s3Config/buildConfig.ts b/hardhat-scripts/s3Config/buildConfig.ts index 7d51681b..73bac889 100644 --- a/hardhat-scripts/s3Config/buildConfig.ts +++ b/hardhat-scripts/s3Config/buildConfig.ts @@ -1,6 +1,12 @@ import { config as dotenvConfig } from "dotenv"; import { ChainConfig, ChainSlug, S3Config, getFinalityBlocks } from "../../src"; -import { EVMX_CHAIN_ID, chains, mode } from "../config/config"; +import { + EVMX_CHAIN_ID, + chains, + mainnetChains, + mode, + testnetChains, +} from "../config/config"; import { getAddresses } from "../utils/address"; import { getChainName, rpcKeys, wssRpcKeys } from "../utils/networks"; import { getChainType } from "./utils"; @@ -15,6 +21,8 @@ export const getS3Config = () => { supportedChainSlugs, version: version[mode], chains: {}, + testnetChainSlugs: testnetChains, + mainnetChainSlugs: mainnetChains, }; supportedChainSlugs.forEach((chainSlug) => { config.chains[chainSlug] = getChainConfig(chainSlug); diff --git a/src/types.ts b/src/types.ts index d63a03db..4cf64f1e 100644 --- a/src/types.ts +++ b/src/types.ts @@ -44,6 +44,8 @@ export type S3Config = { version: string; chains: { [chainSlug: number]: ChainConfig }; supportedChainSlugs: number[]; + testnetChainSlugs: number[]; + mainnetChainSlugs: number[]; }; export type ChainConfig = { diff --git a/test/SetupTest.t.sol b/test/SetupTest.t.sol index 71dc61b3..f511ba68 100644 --- a/test/SetupTest.t.sol +++ b/test/SetupTest.t.sol @@ -837,7 +837,9 @@ contract WatcherSetup is AuctionSetup { chainSlug = transaction.chainSlug; switchboard = switchboard_; - bytes32 prevBatchDigestHash = writePrecompile.getPrevBatchDigestHash(payloadParams.batchCount); + bytes32 prevBatchDigestHash = writePrecompile.getPrevBatchDigestHash( + payloadParams.batchCount + ); digestParams = DigestParams( address(getSocketConfig(transaction.chainSlug).socket), transmitterEOA, From 4c68063c5efbe46d4827319ed0b9b589e41623f3 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Mon, 2 Jun 2025 15:20:49 +0530 Subject: [PATCH 105/130] fix: use base maxfees --- contracts/evmx/base/AppGatewayBase.sol | 6 ++---- script/counter/WithdrawFeesArbitrumFeesPlug.s.sol | 1 - test/apps/app-gateways/counter/CounterAppGateway.sol | 3 +-- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/contracts/evmx/base/AppGatewayBase.sol b/contracts/evmx/base/AppGatewayBase.sol index 70c3835e..ca0d1cfb 100644 --- a/contracts/evmx/base/AppGatewayBase.sol +++ b/contracts/evmx/base/AppGatewayBase.sol @@ -166,8 +166,7 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { return address(0); } - onChainAddress = IForwarder(forwarderAddresses[contractId_][chainSlug_]) - .getOnChainAddress(); + onChainAddress = IForwarder(forwarderAddresses[contractId_][chainSlug_]).getOnChainAddress(); } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -234,10 +233,9 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { uint32 chainSlug_, address token_, uint256 amount_, - uint256 maxFees_, address receiver_ ) internal { - feesManager__().withdrawCredits(chainSlug_, token_, amount_, maxFees_, receiver_); + feesManager__().withdrawCredits(chainSlug_, token_, amount_, maxFees, receiver_); } //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/script/counter/WithdrawFeesArbitrumFeesPlug.s.sol b/script/counter/WithdrawFeesArbitrumFeesPlug.s.sol index dc8834ed..38eb6b8b 100644 --- a/script/counter/WithdrawFeesArbitrumFeesPlug.s.sol +++ b/script/counter/WithdrawFeesArbitrumFeesPlug.s.sol @@ -49,7 +49,6 @@ contract WithdrawFees is Script { 421614, token, amountToWithdraw, - estimatedGasCost, sender ); vm.stopBroadcast(); diff --git a/test/apps/app-gateways/counter/CounterAppGateway.sol b/test/apps/app-gateways/counter/CounterAppGateway.sol index f48807d9..ae175171 100644 --- a/test/apps/app-gateways/counter/CounterAppGateway.sol +++ b/test/apps/app-gateways/counter/CounterAppGateway.sol @@ -125,10 +125,9 @@ contract CounterAppGateway is AppGatewayBase, Ownable { uint32 chainSlug_, address token_, uint256 amount_, - uint256 maxFees_, address receiver_ ) external { - _withdrawCredits(chainSlug_, token_, amount_, maxFees_, receiver_); + _withdrawCredits(chainSlug_, token_, amount_, receiver_); } function testOnChainRevert(uint32 chainSlug) public async { From e9614082fd445769932c4d56ff9442543a7cd3e4 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Mon, 2 Jun 2025 15:23:59 +0530 Subject: [PATCH 106/130] feat: check for 0 onchain addr --- contracts/evmx/helpers/Forwarder.sol | 3 ++- contracts/utils/common/Errors.sol | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/contracts/evmx/helpers/Forwarder.sol b/contracts/evmx/helpers/Forwarder.sol index eba56336..8b778061 100644 --- a/contracts/evmx/helpers/Forwarder.sol +++ b/contracts/evmx/helpers/Forwarder.sol @@ -7,7 +7,7 @@ import "../interfaces/IAddressResolver.sol"; import "../interfaces/IAppGateway.sol"; import "../interfaces/IForwarder.sol"; import {QueueParams, OverrideParams, Transaction} from "../../utils/common/Structs.sol"; -import {AsyncModifierNotSet, WatcherNotSet} from "../../utils/common/Errors.sol"; +import {AsyncModifierNotSet, WatcherNotSet, InvalidOnChainAddress} from "../../utils/common/Errors.sol"; import "../../utils/RescueFundsLib.sol"; /// @title Forwarder Storage @@ -44,6 +44,7 @@ contract Forwarder is ForwarderStorage, Initializable, AddressResolverUtil { address onChainAddress_, address addressResolver_ ) public reinitializer(1) { + if (onChainAddress_ == address(0)) revert InvalidOnChainAddress(); chainSlug = chainSlug_; onChainAddress = onChainAddress_; _setAddressResolver(addressResolver_); diff --git a/contracts/utils/common/Errors.sol b/contracts/utils/common/Errors.sol index 83a002ef..40cfcf80 100644 --- a/contracts/utils/common/Errors.sol +++ b/contracts/utils/common/Errors.sol @@ -26,6 +26,7 @@ error InvalidTarget(); error InvalidIndex(); error InvalidChainSlug(); error InvalidPayloadSize(); +error InvalidOnChainAddress(); error InvalidScheduleDelay(); /// @notice Error thrown when trying to start or bid a closed auction error AuctionClosed(); From efa3f9f666cf044d60dc88b262925a7cc194b04f Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Mon, 2 Jun 2025 15:34:03 +0530 Subject: [PATCH 107/130] feat: fees token and pool constants --- hardhat-scripts/constants/feeConstants.ts | 26 +++++++++++++++++++++++ hardhat-scripts/constants/index.ts | 1 + hardhat-scripts/constants/types.ts | 2 ++ 3 files changed, 29 insertions(+) create mode 100644 hardhat-scripts/constants/feeConstants.ts diff --git a/hardhat-scripts/constants/feeConstants.ts b/hardhat-scripts/constants/feeConstants.ts new file mode 100644 index 00000000..4bfd41bf --- /dev/null +++ b/hardhat-scripts/constants/feeConstants.ts @@ -0,0 +1,26 @@ +import { DeploymentMode } from "../../src"; +import { TokenMap } from "./types"; + +const tokens: TokenMap = { + [DeploymentMode.DEV]: { + 421614: ["0x2321BF7AdFaf49b1338F1Cd474859dBc0D8dfA96"], + 11155420: ["0x15dbE4B96306Cc9Eba15D834d6c1a895cF4e1697"] + }, + [DeploymentMode.STAGE]: {} +}; + +const feePools: { [key: string]: string } = { + [DeploymentMode.DEV]: "0xc20Be67ef742202dc93A78aa741E7C3715eA1DFd", + [DeploymentMode.STAGE]: "0x15dbE4B96306Cc9Eba15D834d6c1a895cF4e1697" +}; + + +export const getFeeTokens = (mode: DeploymentMode, chainSlug: number): string[] => { + return tokens[mode][chainSlug] || []; +}; + +export const getFeePool = (mode: DeploymentMode): string => { + return feePools[mode]; +}; + + diff --git a/hardhat-scripts/constants/index.ts b/hardhat-scripts/constants/index.ts index e6869b19..fb57bb11 100644 --- a/hardhat-scripts/constants/index.ts +++ b/hardhat-scripts/constants/index.ts @@ -1,2 +1,3 @@ export * from "./constants"; +export * from "./feeConstants"; export * from "./types"; diff --git a/hardhat-scripts/constants/types.ts b/hardhat-scripts/constants/types.ts index afb44d41..e01cd81f 100644 --- a/hardhat-scripts/constants/types.ts +++ b/hardhat-scripts/constants/types.ts @@ -4,6 +4,8 @@ export type DeploymentAddresses = { [chainSlug in ChainSlug]?: ChainAddressesObj; }; +export type TokenMap = { [key: string]: { [chainSlug: number]: string[] } }; + export interface WatcherMultiCallParams { contractAddress: string; data: string; From 4abdd7c42cc7cd03bae7e038691b4c3ff2e5666e Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Mon, 2 Jun 2025 16:10:25 +0530 Subject: [PATCH 108/130] fix: deploy and roles --- contracts/evmx/helpers/AsyncDeployer.sol | 1 - hardhat-scripts/constants/feeConstants.ts | 10 ++++-- hardhat-scripts/deploy/1.deploy.ts | 24 ++++++++------ hardhat-scripts/deploy/2.roles.ts | 38 +++++++++++------------ test/SetupTest.t.sol | 6 +++- 5 files changed, 46 insertions(+), 33 deletions(-) diff --git a/contracts/evmx/helpers/AsyncDeployer.sol b/contracts/evmx/helpers/AsyncDeployer.sol index 8ac669a5..735d3241 100644 --- a/contracts/evmx/helpers/AsyncDeployer.sol +++ b/contracts/evmx/helpers/AsyncDeployer.sol @@ -38,7 +38,6 @@ abstract contract AsyncDeployerStorage is IAsyncDeployer { /// @title AsyncDeployer Contract /// @notice This contract is responsible for deploying Forwarder and AsyncPromise contracts. -/// @dev Inherits the AccessControl contract and implements the IAddressResolver interface. contract AsyncDeployer is AsyncDeployerStorage, Initializable, AddressResolverUtil, Ownable { constructor() { _disableInitializers(); // disable for implementation diff --git a/hardhat-scripts/constants/feeConstants.ts b/hardhat-scripts/constants/feeConstants.ts index 4bfd41bf..a13acacc 100644 --- a/hardhat-scripts/constants/feeConstants.ts +++ b/hardhat-scripts/constants/feeConstants.ts @@ -6,15 +6,19 @@ const tokens: TokenMap = { 421614: ["0x2321BF7AdFaf49b1338F1Cd474859dBc0D8dfA96"], 11155420: ["0x15dbE4B96306Cc9Eba15D834d6c1a895cF4e1697"] }, - [DeploymentMode.STAGE]: {} + [DeploymentMode.STAGE]: { + 84532: ["0xfD51918C0572512901fFA79F822c99A475d22BB4"], + 421614: ["0xa03Cbf13f331aF7c0fD7F2E28E6Cbc13F879E3F3"], + 11155420: ["0xa0E1738a9Fc0698789866e09d7A335d30128C5C5"], + 11155111: ["0xbcaDE56f86a819994d0F66b98e921C484bE6FE4e"] + } }; const feePools: { [key: string]: string } = { [DeploymentMode.DEV]: "0xc20Be67ef742202dc93A78aa741E7C3715eA1DFd", - [DeploymentMode.STAGE]: "0x15dbE4B96306Cc9Eba15D834d6c1a895cF4e1697" + [DeploymentMode.STAGE]: "" }; - export const getFeeTokens = (mode: DeploymentMode, chainSlug: number): string[] => { return tokens[mode][chainSlug] || []; }; diff --git a/hardhat-scripts/deploy/1.deploy.ts b/hardhat-scripts/deploy/1.deploy.ts index effbbcad..5750ed5c 100644 --- a/hardhat-scripts/deploy/1.deploy.ts +++ b/hardhat-scripts/deploy/1.deploy.ts @@ -22,6 +22,7 @@ import { import { DeploymentAddresses, FAST_SWITCHBOARD_TYPE, + getFeePool, IMPLEMENTATION_SLOT, } from "../constants"; import { @@ -103,14 +104,19 @@ const deployEVMxContracts = async () => { ); deployUtils.addresses[contractName] = proxyFactory.address; - const feesPool = await getOrDeploy( - Contracts.FeesPool, - Contracts.FeesPool, - "contracts/evmx/fees/FeesPool.sol", - [EVMxOwner], - deployUtils - ); - deployUtils.addresses[Contracts.FeesPool] = feesPool.address; + const feePool = getFeePool(mode); + if (feePool == "") { + const feesPool = await getOrDeploy( + Contracts.FeesPool, + Contracts.FeesPool, + "contracts/evmx/fees/FeesPool.sol", + [EVMxOwner], + deployUtils + ); + deployUtils.addresses[Contracts.FeesPool] = feesPool.address; + } else { + deployUtils.addresses[Contracts.FeesPool] = feePool; + } deployUtils = await deployContractWithProxy( Contracts.AddressResolver, @@ -131,7 +137,7 @@ const deployEVMxContracts = async () => { [ EVMX_CHAIN_ID, addressResolver.address, - feesPool.address, + deployUtils.addresses[Contracts.FeesPool], EVMxOwner, FAST_SWITCHBOARD_TYPE, ], diff --git a/hardhat-scripts/deploy/2.roles.ts b/hardhat-scripts/deploy/2.roles.ts index a13706c0..e6a04340 100644 --- a/hardhat-scripts/deploy/2.roles.ts +++ b/hardhat-scripts/deploy/2.roles.ts @@ -7,22 +7,28 @@ import { DeploymentAddresses } from "../constants"; import { getAddresses, getInstance, - getProviderFromChainSlug, getRoleHash, overrides, } from "../utils"; import { ChainAddressesObj, ChainSlug, Contracts } from "../../src"; import { ROLES } from "../constants/roles"; import { getWatcherSigner, getSocketSigner } from "../utils/sign"; + export const REQUIRED_ROLES = { - FastSwitchboard: [ROLES.WATCHER_ROLE, ROLES.RESCUE_ROLE], - Socket: [ - ROLES.GOVERNANCE_ROLE, - ROLES.RESCUE_ROLE, - ROLES.SWITCHBOARD_DISABLER_ROLE, - ], - FeesPlug: [ROLES.RESCUE_ROLE], - ContractFactoryPlug: [ROLES.RESCUE_ROLE], + EVMx: { + AuctionManager: [ROLES.TRANSMITTER_ROLE], + FeesPool: [ROLES.FEE_MANAGER_ROLE], + }, + Chain: { + FastSwitchboard: [ROLES.WATCHER_ROLE, ROLES.RESCUE_ROLE], + Socket: [ + ROLES.GOVERNANCE_ROLE, + ROLES.RESCUE_ROLE, + ROLES.SWITCHBOARD_DISABLER_ROLE, + ], + FeesPlug: [ROLES.RESCUE_ROLE], + ContractFactoryPlug: [ROLES.RESCUE_ROLE], + } }; async function setRoleForContract( @@ -67,15 +73,12 @@ async function getSigner(chain: number, isWatcher: boolean = false) { return signer; } -async function setRolesForOnChain( - chain: number, - addresses: DeploymentAddresses -) { +async function setRolesOnChain(chain: number, addresses: DeploymentAddresses) { const chainAddresses: ChainAddressesObj = (addresses[chain] ?? {}) as ChainAddressesObj; const signer = await getSigner(chain); - for (const [contractName, roles] of Object.entries(REQUIRED_ROLES)) { + for (const [contractName, roles] of Object.entries(REQUIRED_ROLES["Chain"])) { const contractAddress = chainAddresses[contractName as keyof ChainAddressesObj]; if (!contractAddress) continue; @@ -83,7 +86,7 @@ async function setRolesForOnChain( for (const roleName of roles) { const targetAddress = contractName === Contracts.FastSwitchboard && - roleName === ROLES.WATCHER_ROLE + roleName === ROLES.WATCHER_ROLE ? watcher : signer.address; @@ -104,9 +107,6 @@ async function setRolesForEVMx(addresses: DeploymentAddresses) { {}) as ChainAddressesObj; const signer = await getSigner(EVMX_CHAIN_ID, true); - const contractAddress = chainAddresses[Contracts.Watcher]; - if (!contractAddress) return; - await setRoleForContract( Contracts.AuctionManager, chainAddresses[Contracts.AuctionManager], @@ -132,7 +132,7 @@ export const main = async () => { const addresses = getAddresses(mode) as unknown as DeploymentAddresses; console.log("Setting Roles for On Chain"); for (const chain of chains) { - await setRolesForOnChain(chain, addresses); + await setRolesOnChain(chain, addresses); } await setRolesForEVMx(addresses); } catch (error) { diff --git a/test/SetupTest.t.sol b/test/SetupTest.t.sol index f511ba68..7c48365d 100644 --- a/test/SetupTest.t.sol +++ b/test/SetupTest.t.sol @@ -232,19 +232,23 @@ contract DeploySetup is SetupStore { vm.startPrank(socketOwner); // socket socket.grantRole(GOVERNANCE_ROLE, address(socketOwner)); + socket.grantRole(RESCUE_ROLE, address(socketOwner)); + socket.grantRole(SWITCHBOARD_DISABLER_ROLE, address(socketOwner)); // switchboard switchboard.registerSwitchboard(); switchboard.grantRole(WATCHER_ROLE, watcherEOA); + switchboard.grantRole(RESCUE_ROLE, address(socketOwner)); + feesPlug.grantRole(RESCUE_ROLE, address(socketOwner)); feesPlug.whitelistToken(address(socketConfig.testUSDC)); - feesPlug.connectSocket( encodeAppGatewayId(address(feesManager)), address(socket), address(switchboard) ); + contractFactoryPlug.grantRole(RESCUE_ROLE, address(socketOwner)); contractFactoryPlug.connectSocket( encodeAppGatewayId(address(writePrecompile)), address(socket), From ad7a9864a1756587d6a7c41db4e063759d845086 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Mon, 2 Jun 2025 16:22:08 +0530 Subject: [PATCH 109/130] feat: custom fee token whitelist --- hardhat-scripts/deploy/3.configureChains.ts | 47 ++++++++++++--------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/hardhat-scripts/deploy/3.configureChains.ts b/hardhat-scripts/deploy/3.configureChains.ts index 7c090c45..7039f43f 100644 --- a/hardhat-scripts/deploy/3.configureChains.ts +++ b/hardhat-scripts/deploy/3.configureChains.ts @@ -4,7 +4,7 @@ dotenvConfig(); import { Contract, Signer, Wallet } from "ethers"; import { ChainAddressesObj, ChainSlug, Contracts } from "../../src"; import { chains, EVMX_CHAIN_ID, MAX_MSG_VALUE_LIMIT, mode } from "../config"; -import { DeploymentAddresses, FAST_SWITCHBOARD_TYPE } from "../constants"; +import { DeploymentAddresses, FAST_SWITCHBOARD_TYPE, getFeeTokens } from "../constants"; import { getAddresses, getInstance, @@ -43,9 +43,8 @@ export const configureChains = async (addresses: DeploymentAddresses) => { ); await whitelistToken( - chainAddresses[Contracts.FeesPlug], - chainAddresses[Contracts.TestUSDC], - signer + chain, + chainAddresses[Contracts.FeesPlug], signer ); await setMaxMsgValueLimit(chain); @@ -150,27 +149,33 @@ const registerSb = async ( }; export const whitelistToken = async ( + chain: number, feesPlugAddress: string, - tokenAddress: string, signer: Signer ) => { console.log("Whitelisting token"); - const feesPlugContract = await getInstance( - Contracts.FeesPlug, - feesPlugAddress - ); - const isWhitelisted = await feesPlugContract - .connect(signer) - .whitelistedTokens(tokenAddress); - if (!isWhitelisted) { - const tx = await feesPlugContract - .connect(signer) - .whitelistToken(tokenAddress); - console.log( - `Whitelisting token ${tokenAddress} for ${feesPlugContract.address}`, - tx.hash - ); - await tx.wait(); + + const feesPlugContract = ( + await getInstance(Contracts.FeesPlug, feesPlugAddress) + ).connect(signer); + + const tokens = getFeeTokens(mode, chain); + if (tokens.length == 0) return; + + for (const token of tokens) { + const isWhitelisted = await feesPlugContract + .whitelistedTokens(token); + + if (!isWhitelisted) { + const tx = await feesPlugContract.whitelistToken(token); + console.log( + `Whitelisting token ${token} for ${feesPlugContract.address}`, + tx.hash + ); + await tx.wait(); + } else { + console.log(`Token ${token} is already whitelisted`); + } } }; From 45ff21f7b7fed5d326c70e9e312a4b09d6a7c4ab Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Mon, 2 Jun 2025 16:30:59 +0530 Subject: [PATCH 110/130] feat: custom fees plug chains --- hardhat-scripts/config/config.ts | 17 +++++++++++ hardhat-scripts/deploy/1.deploy.ts | 21 +++++++------ hardhat-scripts/deploy/3.configureChains.ts | 33 ++++++++++++--------- hardhat-scripts/deploy/6.connect.ts | 11 +++++-- hardhat-scripts/deploy/8.setupEnv.ts | 24 +++++++-------- src/types.ts | 3 +- 6 files changed, 68 insertions(+), 41 deletions(-) diff --git a/hardhat-scripts/config/config.ts b/hardhat-scripts/config/config.ts index bb7303eb..58c3f663 100644 --- a/hardhat-scripts/config/config.ts +++ b/hardhat-scripts/config/config.ts @@ -49,6 +49,23 @@ export const getChains = () => { throw new Error(`Invalid deployment mode: ${mode}`); } }; + + +export const getFeesPlugChains = (): Array => { + switch (mode) { + case DeploymentMode.LOCAL: + return getChains(); + case DeploymentMode.DEV: + return getChains(); + case DeploymentMode.STAGE: + return getChains(); + case DeploymentMode.PROD: + return getChains(); + default: + throw new Error(`Invalid deployment mode: ${mode}`); + } +}; + export const testnetChains: Array = [ ChainSlug.OPTIMISM_SEPOLIA, ChainSlug.ARBITRUM_SEPOLIA, diff --git a/hardhat-scripts/deploy/1.deploy.ts b/hardhat-scripts/deploy/1.deploy.ts index 5750ed5c..23721037 100644 --- a/hardhat-scripts/deploy/1.deploy.ts +++ b/hardhat-scripts/deploy/1.deploy.ts @@ -9,6 +9,7 @@ import { chains, EVMX_CHAIN_ID, EXPIRY_TIME, + getFeesPlugChains, logConfig, MAX_RE_AUCTION_COUNT, MAX_SCHEDULE_DELAY_SECONDS, @@ -321,15 +322,17 @@ const deploySocketContracts = async () => { ); deployUtils.addresses[contractName] = sb.address; - contractName = Contracts.FeesPlug; - const feesPlug: Contract = await getOrDeploy( - contractName, - contractName, - `contracts/evmx/plugs/${contractName}.sol`, - [socket.address, socketOwner], - deployUtils - ); - deployUtils.addresses[contractName] = feesPlug.address; + if (getFeesPlugChains().includes(chain as ChainSlug)) { + contractName = Contracts.FeesPlug; + const feesPlug: Contract = await getOrDeploy( + contractName, + contractName, + `contracts/evmx/plugs/${contractName}.sol`, + [socket.address, socketOwner], + deployUtils + ); + deployUtils.addresses[contractName] = feesPlug.address; + } contractName = Contracts.ContractFactoryPlug; const contractFactoryPlug: Contract = await getOrDeploy( diff --git a/hardhat-scripts/deploy/3.configureChains.ts b/hardhat-scripts/deploy/3.configureChains.ts index 7039f43f..0ad02d7f 100644 --- a/hardhat-scripts/deploy/3.configureChains.ts +++ b/hardhat-scripts/deploy/3.configureChains.ts @@ -42,10 +42,14 @@ export const configureChains = async (addresses: DeploymentAddresses) => { socketContract ); - await whitelistToken( - chain, - chainAddresses[Contracts.FeesPlug], signer - ); + if (chainAddresses[Contracts.FeesPlug]) { + await whitelistToken( + chain, + chainAddresses[Contracts.FeesPlug], + signer + ); + } + await setMaxMsgValueLimit(chain); await setOnchainContracts(chain, addresses); @@ -96,16 +100,17 @@ async function setOnchainContracts( signer ); - await updateContractSettings( - EVMX_CHAIN_ID, - Contracts.FeesManager, - "feesPlugs", - [chain], - chainAddresses[Contracts.FeesPlug], - "setFeesPlug", - [chain, chainAddresses[Contracts.FeesPlug]], - signer - ); + if (chainAddresses[Contracts.FeesPlug]) + await updateContractSettings( + EVMX_CHAIN_ID, + Contracts.FeesManager, + "feesPlugs", + [chain], + chainAddresses[Contracts.FeesPlug], + "setFeesPlug", + [chain, chainAddresses[Contracts.FeesPlug]], + signer + ); await updateContractSettings( EVMX_CHAIN_ID, diff --git a/hardhat-scripts/deploy/6.connect.ts b/hardhat-scripts/deploy/6.connect.ts index 8e96da51..0995bebe 100644 --- a/hardhat-scripts/deploy/6.connect.ts +++ b/hardhat-scripts/deploy/6.connect.ts @@ -89,7 +89,7 @@ export const isConfigSetOnSocket = async ( const plugConfigRegistered = await socket.getPlugConfig(plug.address); return ( plugConfigRegistered.appGatewayId.toLowerCase() === - appGatewayId.toLowerCase() && + appGatewayId.toLowerCase() && plugConfigRegistered.switchboard.toLowerCase() === switchboard.toLowerCase() ); }; @@ -147,7 +147,9 @@ export const connectPlugsOnSocket = async () => { const addr = addresses[chain]!; // Connect each plug contract for (const plugContract of plugs) { - await connectPlug(chain, plugContract, socketSigner, addresses, addr); + if (addr[plugContract]) { + await connectPlug(chain, plugContract, socketSigner, addresses, addr); + } } }) ); @@ -196,6 +198,11 @@ export const updateConfigEVMx = async () => { checkIfAddressExists(switchboard, "Switchboard"); checkIfAppGatewayIdExists(appGatewayId, "AppGatewayId"); + if (!addr[plugContract]) { + console.log(`${plugContract} not found on ${chain}`); + continue; + } + if ( await isConfigSetOnEVMx( configurationsContract, diff --git a/hardhat-scripts/deploy/8.setupEnv.ts b/hardhat-scripts/deploy/8.setupEnv.ts index a47d36c0..9a48f4c2 100644 --- a/hardhat-scripts/deploy/8.setupEnv.ts +++ b/hardhat-scripts/deploy/8.setupEnv.ts @@ -3,6 +3,7 @@ import fs from "fs"; import path from "path"; import { EVMX_CHAIN_ID, mode } from "../config/config"; import { getAddresses } from "../utils"; +import { getFeeTokens } from "../constants"; const envFilePath = path.join(__dirname, "../../.env"); const encoding = "utf8"; @@ -28,21 +29,16 @@ const updatedLines = lines.map((line) => { } else if (line.startsWith("FEES_MANAGER=")) { return `FEES_MANAGER=${latestEVMxAddresses[Contracts.FeesManager]}`; } else if (line.startsWith("ARBITRUM_SOCKET=")) { - return `ARBITRUM_SOCKET=${ - latestAddresses[ChainSlug.ARBITRUM_SEPOLIA][Contracts.Socket] - }`; + return `ARBITRUM_SOCKET=${latestAddresses[ChainSlug.ARBITRUM_SEPOLIA][Contracts.Socket] + }`; } else if (line.startsWith("ARBITRUM_SWITCHBOARD=")) { - return `ARBITRUM_SWITCHBOARD=${ - latestAddresses[ChainSlug.ARBITRUM_SEPOLIA][Contracts.FastSwitchboard] - }`; - } else if (line.startsWith("ARBITRUM_FEES_PLUG=")) { - return `ARBITRUM_FEES_PLUG=${ - latestAddresses[ChainSlug.ARBITRUM_SEPOLIA][Contracts.FeesPlug] - }`; - } else if (line.startsWith("ARBITRUM_TEST_USDC=")) { - return `ARBITRUM_TEST_USDC=${ - latestAddresses[ChainSlug.ARBITRUM_SEPOLIA][Contracts.TestUSDC] - }`; + return `ARBITRUM_SWITCHBOARD=${latestAddresses[ChainSlug.ARBITRUM_SEPOLIA][Contracts.FastSwitchboard] + }`; + } else if (line.startsWith("ARBITRUM_FEES_PLUG=") && latestAddresses[ChainSlug.ARBITRUM_SEPOLIA][Contracts.FeesPlug]) { + return `ARBITRUM_FEES_PLUG=${latestAddresses[ChainSlug.ARBITRUM_SEPOLIA][Contracts.FeesPlug] + }`; + } else if (line.startsWith("ARBITRUM_TEST_USDC=") && getFeeTokens(mode, ChainSlug.ARBITRUM_SEPOLIA).length > 0) { + return `ARBITRUM_TEST_USDC=${getFeeTokens(mode, ChainSlug.ARBITRUM_SEPOLIA)[0]}`; } return line; // Return the line unchanged if it doesn't match any of the above }); diff --git a/src/types.ts b/src/types.ts index 4cf64f1e..420d5dd3 100644 --- a/src/types.ts +++ b/src/types.ts @@ -19,9 +19,8 @@ export type ChainAddressesObj = { Socket: string; SocketBatcher: string; FastSwitchboard: string; - FeesPlug: string; ContractFactoryPlug: string; - TestUSDC: string; + FeesPlug?: string; startBlock: number; }; From a051f85cf3c269cb5ab3e19a7074ce4a5387575d Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Mon, 2 Jun 2025 16:32:25 +0530 Subject: [PATCH 111/130] fix: lint --- contracts/evmx/base/AppGatewayBase.sol | 3 +- hardhat-scripts/config/config.ts | 1 - hardhat-scripts/constants/feeConstants.ts | 35 ++++++++++--------- hardhat-scripts/deploy/2.roles.ts | 11 ++---- hardhat-scripts/deploy/3.configureChains.ts | 15 ++++---- hardhat-scripts/deploy/6.connect.ts | 2 +- hardhat-scripts/deploy/8.setupEnv.ts | 29 ++++++++++----- .../WithdrawFeesArbitrumFeesPlug.s.sol | 7 +--- 8 files changed, 52 insertions(+), 51 deletions(-) diff --git a/contracts/evmx/base/AppGatewayBase.sol b/contracts/evmx/base/AppGatewayBase.sol index ca0d1cfb..bbcb2f50 100644 --- a/contracts/evmx/base/AppGatewayBase.sol +++ b/contracts/evmx/base/AppGatewayBase.sol @@ -166,7 +166,8 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { return address(0); } - onChainAddress = IForwarder(forwarderAddresses[contractId_][chainSlug_]).getOnChainAddress(); + onChainAddress = IForwarder(forwarderAddresses[contractId_][chainSlug_]) + .getOnChainAddress(); } //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/hardhat-scripts/config/config.ts b/hardhat-scripts/config/config.ts index 58c3f663..8eb7dfcd 100644 --- a/hardhat-scripts/config/config.ts +++ b/hardhat-scripts/config/config.ts @@ -50,7 +50,6 @@ export const getChains = () => { } }; - export const getFeesPlugChains = (): Array => { switch (mode) { case DeploymentMode.LOCAL: diff --git a/hardhat-scripts/constants/feeConstants.ts b/hardhat-scripts/constants/feeConstants.ts index a13acacc..1f85aaec 100644 --- a/hardhat-scripts/constants/feeConstants.ts +++ b/hardhat-scripts/constants/feeConstants.ts @@ -2,29 +2,30 @@ import { DeploymentMode } from "../../src"; import { TokenMap } from "./types"; const tokens: TokenMap = { - [DeploymentMode.DEV]: { - 421614: ["0x2321BF7AdFaf49b1338F1Cd474859dBc0D8dfA96"], - 11155420: ["0x15dbE4B96306Cc9Eba15D834d6c1a895cF4e1697"] - }, - [DeploymentMode.STAGE]: { - 84532: ["0xfD51918C0572512901fFA79F822c99A475d22BB4"], - 421614: ["0xa03Cbf13f331aF7c0fD7F2E28E6Cbc13F879E3F3"], - 11155420: ["0xa0E1738a9Fc0698789866e09d7A335d30128C5C5"], - 11155111: ["0xbcaDE56f86a819994d0F66b98e921C484bE6FE4e"] - } + [DeploymentMode.DEV]: { + 421614: ["0x2321BF7AdFaf49b1338F1Cd474859dBc0D8dfA96"], + 11155420: ["0x15dbE4B96306Cc9Eba15D834d6c1a895cF4e1697"], + }, + [DeploymentMode.STAGE]: { + 84532: ["0xfD51918C0572512901fFA79F822c99A475d22BB4"], + 421614: ["0xa03Cbf13f331aF7c0fD7F2E28E6Cbc13F879E3F3"], + 11155420: ["0xa0E1738a9Fc0698789866e09d7A335d30128C5C5"], + 11155111: ["0xbcaDE56f86a819994d0F66b98e921C484bE6FE4e"], + }, }; const feePools: { [key: string]: string } = { - [DeploymentMode.DEV]: "0xc20Be67ef742202dc93A78aa741E7C3715eA1DFd", - [DeploymentMode.STAGE]: "" + [DeploymentMode.DEV]: "0xc20Be67ef742202dc93A78aa741E7C3715eA1DFd", + [DeploymentMode.STAGE]: "", }; -export const getFeeTokens = (mode: DeploymentMode, chainSlug: number): string[] => { - return tokens[mode][chainSlug] || []; +export const getFeeTokens = ( + mode: DeploymentMode, + chainSlug: number +): string[] => { + return tokens[mode][chainSlug] || []; }; export const getFeePool = (mode: DeploymentMode): string => { - return feePools[mode]; + return feePools[mode]; }; - - diff --git a/hardhat-scripts/deploy/2.roles.ts b/hardhat-scripts/deploy/2.roles.ts index e6a04340..53ece239 100644 --- a/hardhat-scripts/deploy/2.roles.ts +++ b/hardhat-scripts/deploy/2.roles.ts @@ -4,12 +4,7 @@ dotenvConfig(); import { Wallet } from "ethers"; import { chains, EVMX_CHAIN_ID, mode, watcher, transmitter } from "../config"; import { DeploymentAddresses } from "../constants"; -import { - getAddresses, - getInstance, - getRoleHash, - overrides, -} from "../utils"; +import { getAddresses, getInstance, getRoleHash, overrides } from "../utils"; import { ChainAddressesObj, ChainSlug, Contracts } from "../../src"; import { ROLES } from "../constants/roles"; import { getWatcherSigner, getSocketSigner } from "../utils/sign"; @@ -28,7 +23,7 @@ export const REQUIRED_ROLES = { ], FeesPlug: [ROLES.RESCUE_ROLE], ContractFactoryPlug: [ROLES.RESCUE_ROLE], - } + }, }; async function setRoleForContract( @@ -86,7 +81,7 @@ async function setRolesOnChain(chain: number, addresses: DeploymentAddresses) { for (const roleName of roles) { const targetAddress = contractName === Contracts.FastSwitchboard && - roleName === ROLES.WATCHER_ROLE + roleName === ROLES.WATCHER_ROLE ? watcher : signer.address; diff --git a/hardhat-scripts/deploy/3.configureChains.ts b/hardhat-scripts/deploy/3.configureChains.ts index 0ad02d7f..6bda0941 100644 --- a/hardhat-scripts/deploy/3.configureChains.ts +++ b/hardhat-scripts/deploy/3.configureChains.ts @@ -4,7 +4,11 @@ dotenvConfig(); import { Contract, Signer, Wallet } from "ethers"; import { ChainAddressesObj, ChainSlug, Contracts } from "../../src"; import { chains, EVMX_CHAIN_ID, MAX_MSG_VALUE_LIMIT, mode } from "../config"; -import { DeploymentAddresses, FAST_SWITCHBOARD_TYPE, getFeeTokens } from "../constants"; +import { + DeploymentAddresses, + FAST_SWITCHBOARD_TYPE, + getFeeTokens, +} from "../constants"; import { getAddresses, getInstance, @@ -43,11 +47,7 @@ export const configureChains = async (addresses: DeploymentAddresses) => { ); if (chainAddresses[Contracts.FeesPlug]) { - await whitelistToken( - chain, - chainAddresses[Contracts.FeesPlug], - signer - ); + await whitelistToken(chain, chainAddresses[Contracts.FeesPlug], signer); } await setMaxMsgValueLimit(chain); @@ -168,8 +168,7 @@ export const whitelistToken = async ( if (tokens.length == 0) return; for (const token of tokens) { - const isWhitelisted = await feesPlugContract - .whitelistedTokens(token); + const isWhitelisted = await feesPlugContract.whitelistedTokens(token); if (!isWhitelisted) { const tx = await feesPlugContract.whitelistToken(token); diff --git a/hardhat-scripts/deploy/6.connect.ts b/hardhat-scripts/deploy/6.connect.ts index 0995bebe..83882441 100644 --- a/hardhat-scripts/deploy/6.connect.ts +++ b/hardhat-scripts/deploy/6.connect.ts @@ -89,7 +89,7 @@ export const isConfigSetOnSocket = async ( const plugConfigRegistered = await socket.getPlugConfig(plug.address); return ( plugConfigRegistered.appGatewayId.toLowerCase() === - appGatewayId.toLowerCase() && + appGatewayId.toLowerCase() && plugConfigRegistered.switchboard.toLowerCase() === switchboard.toLowerCase() ); }; diff --git a/hardhat-scripts/deploy/8.setupEnv.ts b/hardhat-scripts/deploy/8.setupEnv.ts index 9a48f4c2..66899cef 100644 --- a/hardhat-scripts/deploy/8.setupEnv.ts +++ b/hardhat-scripts/deploy/8.setupEnv.ts @@ -29,16 +29,27 @@ const updatedLines = lines.map((line) => { } else if (line.startsWith("FEES_MANAGER=")) { return `FEES_MANAGER=${latestEVMxAddresses[Contracts.FeesManager]}`; } else if (line.startsWith("ARBITRUM_SOCKET=")) { - return `ARBITRUM_SOCKET=${latestAddresses[ChainSlug.ARBITRUM_SEPOLIA][Contracts.Socket] - }`; + return `ARBITRUM_SOCKET=${ + latestAddresses[ChainSlug.ARBITRUM_SEPOLIA][Contracts.Socket] + }`; } else if (line.startsWith("ARBITRUM_SWITCHBOARD=")) { - return `ARBITRUM_SWITCHBOARD=${latestAddresses[ChainSlug.ARBITRUM_SEPOLIA][Contracts.FastSwitchboard] - }`; - } else if (line.startsWith("ARBITRUM_FEES_PLUG=") && latestAddresses[ChainSlug.ARBITRUM_SEPOLIA][Contracts.FeesPlug]) { - return `ARBITRUM_FEES_PLUG=${latestAddresses[ChainSlug.ARBITRUM_SEPOLIA][Contracts.FeesPlug] - }`; - } else if (line.startsWith("ARBITRUM_TEST_USDC=") && getFeeTokens(mode, ChainSlug.ARBITRUM_SEPOLIA).length > 0) { - return `ARBITRUM_TEST_USDC=${getFeeTokens(mode, ChainSlug.ARBITRUM_SEPOLIA)[0]}`; + return `ARBITRUM_SWITCHBOARD=${ + latestAddresses[ChainSlug.ARBITRUM_SEPOLIA][Contracts.FastSwitchboard] + }`; + } else if ( + line.startsWith("ARBITRUM_FEES_PLUG=") && + latestAddresses[ChainSlug.ARBITRUM_SEPOLIA][Contracts.FeesPlug] + ) { + return `ARBITRUM_FEES_PLUG=${ + latestAddresses[ChainSlug.ARBITRUM_SEPOLIA][Contracts.FeesPlug] + }`; + } else if ( + line.startsWith("ARBITRUM_TEST_USDC=") && + getFeeTokens(mode, ChainSlug.ARBITRUM_SEPOLIA).length > 0 + ) { + return `ARBITRUM_TEST_USDC=${ + getFeeTokens(mode, ChainSlug.ARBITRUM_SEPOLIA)[0] + }`; } return line; // Return the line unchanged if it doesn't match any of the above }); diff --git a/script/counter/WithdrawFeesArbitrumFeesPlug.s.sol b/script/counter/WithdrawFeesArbitrumFeesPlug.s.sol index 38eb6b8b..2d329a2f 100644 --- a/script/counter/WithdrawFeesArbitrumFeesPlug.s.sol +++ b/script/counter/WithdrawFeesArbitrumFeesPlug.s.sol @@ -45,12 +45,7 @@ contract WithdrawFees is Script { vm.createSelectFork(vm.envString("EVMX_RPC")); vm.startBroadcast(privateKey); console.log("Withdrawing amount:", amountToWithdraw); - appGateway.withdrawCredits( - 421614, - token, - amountToWithdraw, - sender - ); + appGateway.withdrawCredits(421614, token, amountToWithdraw, sender); vm.stopBroadcast(); // Switch back to Arbitrum Sepolia to check final balance From 716ccddc108a94ea07b082c02e742a3169ec1be1 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Mon, 2 Jun 2025 16:37:21 +0530 Subject: [PATCH 112/130] fix: env setup --- hardhat-scripts/deploy/1.deploy.ts | 2 +- hardhat-scripts/deploy/8.setupEnv.ts | 29 ++++++++++++++-------------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/hardhat-scripts/deploy/1.deploy.ts b/hardhat-scripts/deploy/1.deploy.ts index 23721037..672ceffd 100644 --- a/hardhat-scripts/deploy/1.deploy.ts +++ b/hardhat-scripts/deploy/1.deploy.ts @@ -106,7 +106,7 @@ const deployEVMxContracts = async () => { deployUtils.addresses[contractName] = proxyFactory.address; const feePool = getFeePool(mode); - if (feePool == "") { + if (feePool.length == 0) { const feesPool = await getOrDeploy( Contracts.FeesPool, Contracts.FeesPool, diff --git a/hardhat-scripts/deploy/8.setupEnv.ts b/hardhat-scripts/deploy/8.setupEnv.ts index 66899cef..d8bc7ead 100644 --- a/hardhat-scripts/deploy/8.setupEnv.ts +++ b/hardhat-scripts/deploy/8.setupEnv.ts @@ -36,20 +36,21 @@ const updatedLines = lines.map((line) => { return `ARBITRUM_SWITCHBOARD=${ latestAddresses[ChainSlug.ARBITRUM_SEPOLIA][Contracts.FastSwitchboard] }`; - } else if ( - line.startsWith("ARBITRUM_FEES_PLUG=") && - latestAddresses[ChainSlug.ARBITRUM_SEPOLIA][Contracts.FeesPlug] - ) { - return `ARBITRUM_FEES_PLUG=${ - latestAddresses[ChainSlug.ARBITRUM_SEPOLIA][Contracts.FeesPlug] - }`; - } else if ( - line.startsWith("ARBITRUM_TEST_USDC=") && - getFeeTokens(mode, ChainSlug.ARBITRUM_SEPOLIA).length > 0 - ) { - return `ARBITRUM_TEST_USDC=${ - getFeeTokens(mode, ChainSlug.ARBITRUM_SEPOLIA)[0] - }`; + } else if (line.startsWith("ARBITRUM_FEES_PLUG=")) { + const feesPlug = + latestAddresses[ChainSlug.ARBITRUM_SEPOLIA][Contracts.FeesPlug]; + if (feesPlug) { + return `ARBITRUM_FEES_PLUG=${feesPlug}`; + } else { + return line; + } + } else if (line.startsWith("ARBITRUM_TEST_USDC=")) { + const testUSDC = getFeeTokens(mode, ChainSlug.ARBITRUM_SEPOLIA)[0]; + if (testUSDC) { + return `ARBITRUM_TEST_USDC=${testUSDC}`; + } else { + return line; + } } return line; // Return the line unchanged if it doesn't match any of the above }); From b89a5ccc08da1d33abd197132a90f120522cd47f Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Mon, 2 Jun 2025 17:06:08 +0530 Subject: [PATCH 113/130] socket-protocol@1.1.21 --- deployments/dev_addresses.json | 6 ++---- deployments/stage_addresses.json | 12 ++++-------- package.json | 2 +- src/enums.ts | 2 -- 4 files changed, 7 insertions(+), 15 deletions(-) diff --git a/deployments/dev_addresses.json b/deployments/dev_addresses.json index 22993cb6..92206359 100644 --- a/deployments/dev_addresses.json +++ b/deployments/dev_addresses.json @@ -5,8 +5,7 @@ "FeesPlug": "0xb0cbd56A86568BB4cBBE59B0EcA029A4F2D7f235", "Socket": "0xEb907f52eAF6e81439F8807AE2F143Bd3482e6b6", "SocketBatcher": "0xc498A63eE84143A15A7D3080E1E51af700f35e41", - "startBlock": 159285686, - "TestUSDC": "0x2321BF7AdFaf49b1338F1Cd474859dBc0D8dfA96" + "startBlock": 159285686 }, "7625382": { "AddressResolver": "0xF7efc3886b225A571d35C2DF736eD515F132911F", @@ -40,7 +39,6 @@ "FeesPlug": "0x64b7157Fe0878880b180d9BD2a0bd0D1794Cf44A", "Socket": "0xd8C787c27Cc6F4BF143855Bb50c880FB2DE38267", "SocketBatcher": "0xc6Fe653dAfeDd76d50e3F971dDA650917824f948", - "startBlock": 28522517, - "TestUSDC": "0x15dbE4B96306Cc9Eba15D834d6c1a895cF4e1697" + "startBlock": 28522517 } } diff --git a/deployments/stage_addresses.json b/deployments/stage_addresses.json index d950e823..4987a330 100644 --- a/deployments/stage_addresses.json +++ b/deployments/stage_addresses.json @@ -23,8 +23,7 @@ "FeesPlug": "0x9161a99deD597fe519E03D319053CA1669118dDA", "Socket": "0x36Ae239a92faee6aFF4df9749d592dA7c00717Be", "SocketBatcher": "0x8fa361816874a11a66D02EC84b28E1A931B4035e", - "startBlock": 25218634, - "TestUSDC": "0xfD51918C0572512901fFA79F822c99A475d22BB4" + "startBlock": 25218634 }, "421614": { "ContractFactoryPlug": "0x65C066BE05CB4622393fADc1Bf3dE8eEdEcB3817", @@ -32,15 +31,13 @@ "FeesPlug": "0xDfE94B9b14de382Ed13C8A7F387884808D0f7E0b", "Socket": "0xDAB25fB82cc1b1611Fb9016FB50222dBFcD1BCf5", "SocketBatcher": "0x4e7163Ce9F7F335138fB32827d6f99f174060897", - "startBlock": 148801970, - "TestUSDC": "0xa03Cbf13f331aF7c0fD7F2E28E6Cbc13F879E3F3" + "startBlock": 148801970 }, "11155111": { "FastSwitchboard": "0x1eFD3AF2317B9E6E7492718878f69De747C9e7c3", "FeesPlug": "0xfE555AD869ac24305471F0755976c556425E8D23", "Socket": "0xae59BA0Bd0D92232B3B6304185448C9Fe5445f4d", - "SocketBatcher": "0xdaE4538FbbEf41B2Feb5c79DD2fFC9720AF13d7b", - "TestUSDC": "0xbcaDE56f86a819994d0F66b98e921C484bE6FE4e" + "SocketBatcher": "0xdaE4538FbbEf41B2Feb5c79DD2fFC9720AF13d7b" }, "11155420": { "ContractFactoryPlug": "0x469B536c5Df15948c8759FEEE5DB1c17790d4152", @@ -48,7 +45,6 @@ "FeesPlug": "0x6734a30B8f2d210faefa5aeD4E11b674C59641F1", "Socket": "0x11fbd3a7031b28607973fc44d4d24B26DEfac886", "SocketBatcher": "0x2c2060f5586751676fC2Af96cc8bE9BF0c7A8770", - "startBlock": 27201458, - "TestUSDC": "0xa0E1738a9Fc0698789866e09d7A335d30128C5C5" + "startBlock": 27201458 } } diff --git a/package.json b/package.json index 534293f9..a30b0517 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "publishConfig": { "access": "public" }, - "version": "1.1.20", + "version": "1.1.21", "description": "socket protocol", "scripts": { "build": "yarn abi && tsc --project lib.tsconfig.json", diff --git a/src/enums.ts b/src/enums.ts index a725f8ae..cb7af5e4 100644 --- a/src/enums.ts +++ b/src/enums.ts @@ -52,8 +52,6 @@ export enum Contracts { FastSwitchboard = "FastSwitchboard", SocketBatcher = "SocketBatcher", SocketFeeManager = "SocketFeeManager", - TestUSDC = "TestUSDC", - AddressResolver = "AddressResolver", Watcher = "Watcher", RequestHandler = "RequestHandler", From dafecb81475a2a48147fc27f4b485734c83e5635 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Mon, 2 Jun 2025 18:05:07 +0530 Subject: [PATCH 114/130] feat: disconnect fees plug script --- hardhat-scripts/admin/disconnect.ts | 177 +++++++++++++++++++++++++ hardhat-scripts/constants/constants.ts | 8 +- hardhat-scripts/constants/types.ts | 9 ++ hardhat-scripts/deploy/6.connect.ts | 68 +--------- hardhat-scripts/utils/address.ts | 12 ++ hardhat-scripts/utils/gatewayId.ts | 38 ++++++ hardhat-scripts/utils/index.ts | 1 + 7 files changed, 250 insertions(+), 63 deletions(-) create mode 100644 hardhat-scripts/admin/disconnect.ts create mode 100644 hardhat-scripts/utils/gatewayId.ts diff --git a/hardhat-scripts/admin/disconnect.ts b/hardhat-scripts/admin/disconnect.ts new file mode 100644 index 00000000..b5fb69d9 --- /dev/null +++ b/hardhat-scripts/admin/disconnect.ts @@ -0,0 +1,177 @@ +import { constants, Wallet } from "ethers"; +import { ChainAddressesObj, ChainSlug, Contracts } from "../../src"; +import { chains, EVMX_CHAIN_ID, getFeesPlugChains, mode } from "../config"; +import { + AppGatewayConfig, + DeploymentAddresses, + ZERO_APP_GATEWAY_ID, +} from "../constants"; +import { + checkIfAddressExists, + getAddresses, + getInstance, + getSocketSigner, +} from "../utils"; +import { getWatcherSigner, sendWatcherMultiCallWithNonce } from "../utils/sign"; +import { isConfigSetOnEVMx, isConfigSetOnSocket } from "../deploy/6.connect"; + +// update this map to disconnect plugs from chains not in this list +const feesPlugChains = getFeesPlugChains(); + +export const main = async () => { + try { + await disconnectPlugsOnSocket(); + await updateConfigEVMx(); + } catch (error) { + console.log("Error while sending transaction", error); + } +}; + +// Connect a single plug contract to its app gateway and switchboard +async function disconnectPlug( + chain: number, + plugContract: string, + socketSigner: Wallet, + addr: ChainAddressesObj +) { + console.log(`Disconnecting ${plugContract} on ${chain}`); + + // Get contract instances + const plug = (await getInstance(plugContract, addr[plugContract])).connect( + socketSigner + ); + const socket = ( + await getInstance(Contracts.Socket, addr[Contracts.Socket]) + ).connect(socketSigner); + + // Get switchboard and app gateway addresses + const switchboard = addr[Contracts.FastSwitchboard]; + checkIfAddressExists(switchboard, "Switchboard"); + + // Check if config is already set + if ( + await isConfigSetOnSocket(plug, socket, ZERO_APP_GATEWAY_ID, switchboard) + ) { + console.log(`${plugContract} Socket Config on ${chain} already set!`); + return; + } + + // Connect the plug + const tx = await plug.functions["connectSocket"]( + ZERO_APP_GATEWAY_ID, + socket.address, + switchboard + ); + console.log( + `Connecting ${plugContract} on ${chain} to ${ZERO_APP_GATEWAY_ID} tx hash: ${tx.hash}` + ); + await tx.wait(); +} + +export const disconnectPlugsOnSocket = async () => { + console.log("Disconnecting plugs"); + const addresses = getAddresses(mode) as unknown as DeploymentAddresses; + // Disconnect plugs on each chain + await Promise.all( + chains.map(async (chain) => { + // skip if chain is in feesPlugChains or not in addresses + if (feesPlugChains.includes(chain) || !addresses[chain]) return; + + const socketSigner = getSocketSigner(chain as ChainSlug); + const addr = addresses[chain]!; + if (addr[Contracts.FeesPlug]) { + await disconnectPlug(chain, Contracts.FeesPlug, socketSigner, addr); + } + }) + ); +}; + +// Configure plugs on the Watcher VM +export const updateConfigEVMx = async () => { + try { + console.log("Disconnecting plugs on EVMx"); + const addresses = getAddresses(mode) as unknown as DeploymentAddresses; + const appConfigs: AppGatewayConfig[] = []; + + // Set up Watcher contract + const signer = getWatcherSigner(); + const EVMxAddresses = addresses[EVMX_CHAIN_ID]!; + const configurationsContract = ( + await getInstance( + Contracts.Configurations, + EVMxAddresses[Contracts.Configurations] + ) + ).connect(signer); + + // Collect configs for each chain and plug + await Promise.all( + chains.map(async (chain) => { + // skip if chain is in feesPlugChains or not in addresses + if (feesPlugChains.includes(chain) || !addresses[chain]) return; + const addr = addresses[chain]!; + + const appGatewayId = ZERO_APP_GATEWAY_ID; + const switchboard = constants.AddressZero; + const plugContract = Contracts.FeesPlug; + + if (!addr[plugContract]) return; + + if ( + await isConfigSetOnEVMx( + configurationsContract, + chain, + addr[plugContract], + appGatewayId, + switchboard + ) + ) { + console.log(`Config already set on ${chain} for ${plugContract}`); + return; + } + appConfigs.push({ + plugConfig: { + appGatewayId: appGatewayId, + switchboard: switchboard, + }, + plug: addr[plugContract], + chainSlug: chain, + }); + + // update fees manager + const feesManager = ( + await getInstance(Contracts.FeesManager, addr[Contracts.FeesManager]) + ).connect(signer); + + const tx = await feesManager.functions["setFeesPlug"]( + chain, + constants.AddressZero + ); + console.log(`Updating Fees Manager tx hash: ${tx.hash}`); + }) + ); + + // Update configs if any changes needed + if (appConfigs.length > 0) { + console.log({ appConfigs }); + const calldata = configurationsContract.interface.encodeFunctionData( + "setAppGatewayConfigs", + [appConfigs] + ); + const tx = await sendWatcherMultiCallWithNonce( + configurationsContract.address, + calldata + ); + console.log(`Updating EVMx Config tx hash: ${tx.hash}`); + await tx.wait(); + } + } catch (error) { + console.log("Error while sending transaction", error); + } +}; + +main() + .then(() => process.exit(0)) + .catch((error: Error) => { + console.error(error); + process.exit(1); + }); diff --git a/hardhat-scripts/constants/constants.ts b/hardhat-scripts/constants/constants.ts index bd93d8d3..71aa09e1 100644 --- a/hardhat-scripts/constants/constants.ts +++ b/hardhat-scripts/constants/constants.ts @@ -1,4 +1,5 @@ -import { keccak256, id } from "ethers/lib/utils"; +import { constants, ethers } from "ethers"; +import { id } from "ethers/lib/utils"; export const ETH_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"; @@ -6,3 +7,8 @@ export const IMPLEMENTATION_SLOT = "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc"; export const FAST_SWITCHBOARD_TYPE = id("FAST"); + +export const ZERO_APP_GATEWAY_ID = ethers.utils.hexZeroPad( + constants.AddressZero, + 32 +); diff --git a/hardhat-scripts/constants/types.ts b/hardhat-scripts/constants/types.ts index e01cd81f..3e41d235 100644 --- a/hardhat-scripts/constants/types.ts +++ b/hardhat-scripts/constants/types.ts @@ -12,3 +12,12 @@ export interface WatcherMultiCallParams { nonce: number; signature: string; } + +export type AppGatewayConfig = { + plugConfig: { + appGatewayId: string; + switchboard: string; + }; + plug: string; + chainSlug: number; +}; diff --git a/hardhat-scripts/deploy/6.connect.ts b/hardhat-scripts/deploy/6.connect.ts index 83882441..82d54e8f 100644 --- a/hardhat-scripts/deploy/6.connect.ts +++ b/hardhat-scripts/deploy/6.connect.ts @@ -1,28 +1,18 @@ -import { constants, Contract, ethers, Wallet } from "ethers"; +import { Contract, Wallet } from "ethers"; import { ChainAddressesObj, ChainSlug, Contracts } from "../../src"; import { chains, EVMX_CHAIN_ID, mode } from "../config"; -import { DeploymentAddresses } from "../constants"; +import { AppGatewayConfig, DeploymentAddresses } from "../constants"; import { + checkIfAddressExists, + checkIfAppGatewayIdExists, getAddresses, + getAppGatewayId, getInstance, getSocketSigner, - overrides, } from "../utils"; -import { - getWatcherSigner, - sendWatcherMultiCallWithNonce, - signWatcherMessage, -} from "../utils/sign"; +import { getWatcherSigner, sendWatcherMultiCallWithNonce } from "../utils/sign"; const plugs = [Contracts.ContractFactoryPlug, Contracts.FeesPlug]; -export type AppGatewayConfig = { - plugConfig: { - appGatewayId: string; - switchboard: string; - }; - plug: string; - chainSlug: number; -}; // Main function to connect plugs on all chains export const main = async () => { @@ -34,52 +24,6 @@ export const main = async () => { } }; -// Maps plug contracts to their corresponding app gateways -export const getAppGatewayId = ( - plug: string, - addresses: DeploymentAddresses -) => { - let address: string = ""; - switch (plug) { - case Contracts.ContractFactoryPlug: - address = addresses?.[EVMX_CHAIN_ID]?.[Contracts.WritePrecompile]; - if (!address) throw new Error(`WritePrecompile not found on EVMX`); - return ethers.utils.hexZeroPad(address, 32); - case Contracts.FeesPlug: - address = addresses?.[EVMX_CHAIN_ID]?.[Contracts.FeesManager]; - if (!address) throw new Error(`FeesManager not found on EVMX`); - return ethers.utils.hexZeroPad(address, 32); - default: - throw new Error(`Unknown plug: ${plug}`); - } -}; - -export const checkIfAddressExists = (address: string, name: string) => { - if ( - address == "0x0000000000000000000000000000000000000000" || - !address || - address == "0x" || - address.length != 42 - ) { - throw Error(`${name} not found : ${address}`); - } - return address; -}; -export const checkIfAppGatewayIdExists = ( - appGatewayId: string, - name: string -) => { - if ( - appGatewayId == constants.HashZero || - !appGatewayId || - appGatewayId == "0x" || - appGatewayId.length != 66 - ) { - throw Error(`${name} not found : ${appGatewayId}`); - } - return appGatewayId; -}; - export const isConfigSetOnSocket = async ( plug: Contract, socket: Contract, diff --git a/hardhat-scripts/utils/address.ts b/hardhat-scripts/utils/address.ts index 6caf8c3f..f1476c41 100644 --- a/hardhat-scripts/utils/address.ts +++ b/hardhat-scripts/utils/address.ts @@ -20,3 +20,15 @@ export const getAddresses = ( throw new Error(`Invalid deployment mode: ${mode}`); } }; + +export const checkIfAddressExists = (address: string, name: string) => { + if ( + address == "0x0000000000000000000000000000000000000000" || + !address || + address == "0x" || + address.length != 42 + ) { + throw Error(`${name} not found : ${address}`); + } + return address; +}; diff --git a/hardhat-scripts/utils/gatewayId.ts b/hardhat-scripts/utils/gatewayId.ts new file mode 100644 index 00000000..a24fc02d --- /dev/null +++ b/hardhat-scripts/utils/gatewayId.ts @@ -0,0 +1,38 @@ +import { constants, ethers } from "ethers"; +import { Contracts } from "../../src"; +import { EVMX_CHAIN_ID } from "../config"; +import { DeploymentAddresses } from "../constants"; + +export const getAppGatewayId = ( + plug: string, + addresses: DeploymentAddresses +) => { + let address: string = ""; + switch (plug) { + case Contracts.ContractFactoryPlug: + address = addresses?.[EVMX_CHAIN_ID]?.[Contracts.WritePrecompile]; + if (!address) throw new Error(`WritePrecompile not found on EVMX`); + return ethers.utils.hexZeroPad(address, 32); + case Contracts.FeesPlug: + address = addresses?.[EVMX_CHAIN_ID]?.[Contracts.FeesManager]; + if (!address) throw new Error(`FeesManager not found on EVMX`); + return ethers.utils.hexZeroPad(address, 32); + default: + throw new Error(`Unknown plug: ${plug}`); + } +}; + +export const checkIfAppGatewayIdExists = ( + appGatewayId: string, + name: string +) => { + if ( + appGatewayId == constants.HashZero || + !appGatewayId || + appGatewayId == "0x" || + appGatewayId.length != 66 + ) { + throw Error(`${name} not found : ${appGatewayId}`); + } + return appGatewayId; +}; diff --git a/hardhat-scripts/utils/index.ts b/hardhat-scripts/utils/index.ts index e11a036e..b53a8577 100644 --- a/hardhat-scripts/utils/index.ts +++ b/hardhat-scripts/utils/index.ts @@ -4,3 +4,4 @@ export * from "./overrides"; export * from "./accounts"; export * from "./deployUtils"; export * from "./sign"; +export * from "./gatewayId"; From 59f2e31f05c274e3443b3bb09e345ae46cc6a614 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Mon, 2 Jun 2025 18:59:51 +0530 Subject: [PATCH 115/130] feat: req payload count setter --- contracts/evmx/watcher/RequestHandler.sol | 12 ++++++++++-- contracts/utils/common/Constants.sol | 1 - 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/contracts/evmx/watcher/RequestHandler.sol b/contracts/evmx/watcher/RequestHandler.sol index 8b0e2686..d53c363b 100644 --- a/contracts/evmx/watcher/RequestHandler.sol +++ b/contracts/evmx/watcher/RequestHandler.sol @@ -16,7 +16,7 @@ abstract contract RequestHandlerStorage is IRequestHandler { // slots [0-49] reserved for gap uint256[50] _gap_before; - // slot 50 (40 + 40 + 40) + // slot 50 (40 + 40 + 40 + 128) /// @notice Counter for tracking request counts uint40 public nextRequestCount = 1; @@ -26,6 +26,9 @@ abstract contract RequestHandlerStorage is IRequestHandler { /// @notice Counter for tracking batch counts uint40 public nextBatchCount; + /// @notice max number of payloads in single request + uint128 requestPayloadCountLimit; + // slot 51 /// @notice Mapping to store the precompiles for each call type mapping(bytes4 => IPrecompile) public precompiles; @@ -88,6 +91,7 @@ contract RequestHandler is RequestHandlerStorage, Initializable, Ownable, Addres } function initialize(address owner_, address addressResolver_) external reinitializer(1) { + requestPayloadCountLimit = 100; _initializeOwner(owner_); _setAddressResolver(addressResolver_); } @@ -96,6 +100,10 @@ contract RequestHandler is RequestHandlerStorage, Initializable, Ownable, Addres precompiles[callType_] = precompile_; } + function setRequestPayloadCountLimit(uint128 requestPayloadCountLimit_) external onlyOwner { + requestPayloadCountLimit = requestPayloadCountLimit_; + } + function getPrecompileFees( bytes4 callType_, bytes memory precompileData_ @@ -128,7 +136,7 @@ contract RequestHandler is RequestHandlerStorage, Initializable, Ownable, Addres bytes memory onCompleteData_ ) external onlyWatcher returns (uint40 requestCount, address[] memory promiseList) { if (queueParams_.length == 0) return (0, new address[](0)); - if (queueParams_.length > REQUEST_PAYLOAD_COUNT_LIMIT) + if (queueParams_.length > requestPayloadCountLimit) revert RequestPayloadCountLimitExceeded(); if (!feesManager__().isCreditSpendable(consumeFrom_, appGateway_, maxFees_)) diff --git a/contracts/utils/common/Constants.sol b/contracts/utils/common/Constants.sol index 921173b9..2afa6479 100644 --- a/contracts/utils/common/Constants.sol +++ b/contracts/utils/common/Constants.sol @@ -14,6 +14,5 @@ bytes4 constant SCHEDULE = bytes4(keccak256("SCHEDULE")); bytes32 constant CALLBACK = keccak256("CALLBACK"); bytes32 constant FAST = keccak256("FAST"); -uint256 constant REQUEST_PAYLOAD_COUNT_LIMIT = 10; uint256 constant PAYLOAD_SIZE_LIMIT = 24_500; uint16 constant MAX_COPY_BYTES = 2048; // 2KB From 01f612202862a62bb2f31aff9ef8d43897858aab Mon Sep 17 00:00:00 2001 From: Akash Date: Mon, 2 Jun 2025 22:28:48 +0530 Subject: [PATCH 116/130] fix: batchCount bug --- FunctionSignatures.md | 2 +- contracts/evmx/watcher/RequestHandler.sol | 4 +- .../watcher/precompiles/WritePrecompile.sol | 12 +++- deployments/dev_addresses.json | 2 +- deployments/dev_verification.json | 67 ++----------------- hardhat-scripts/deploy/1.deploy.ts | 13 ++-- test/SetupTest.t.sol | 1 + 7 files changed, 30 insertions(+), 71 deletions(-) diff --git a/FunctionSignatures.md b/FunctionSignatures.md index 126336f5..d2412f5f 100644 --- a/FunctionSignatures.md +++ b/FunctionSignatures.md @@ -537,7 +537,7 @@ | `expiryTime` | `0x99bc0aea` | | `getDigest` | `0xdd4bf97b` | | `getPrecompileFees` | `0xb7a3d04c` | -| `getPrevBatchDigestHash` | `0x82b35b69` | +| `getPrevBatchDigestHash` | `0x372863a1` | | `handlePayload` | `0x1d5e1d98` | | `initialize` | `0xeb990c59` | | `owner` | `0x8da5cb5b` | diff --git a/contracts/evmx/watcher/RequestHandler.sol b/contracts/evmx/watcher/RequestHandler.sol index 8b0e2686..bd3889b0 100644 --- a/contracts/evmx/watcher/RequestHandler.sol +++ b/contracts/evmx/watcher/RequestHandler.sol @@ -103,8 +103,8 @@ contract RequestHandler is RequestHandlerStorage, Initializable, Ownable, Addres return precompiles[callType_].getPrecompileFees(precompileData_); } - function getRequestBatchIds(uint40 batchCount_) external view returns (uint40[] memory) { - return _requestBatchIds[batchCount_]; + function getRequestBatchIds(uint40 requestCount_) external view returns (uint40[] memory) { + return _requestBatchIds[requestCount_]; } function getBatchPayloadIds(uint40 batchCount_) external view returns (bytes32[] memory) { diff --git a/contracts/evmx/watcher/precompiles/WritePrecompile.sol b/contracts/evmx/watcher/precompiles/WritePrecompile.sol index a5ad893b..a36eaf4e 100644 --- a/contracts/evmx/watcher/precompiles/WritePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/WritePrecompile.sol @@ -170,7 +170,10 @@ contract WritePrecompile is WritePrecompileStorage, Initializable, Ownable, Watc deadline = block.timestamp + expiryTime; fees = getPrecompileFees(payloadParams.precompileData); - bytes32 prevBatchDigestHash = getPrevBatchDigestHash(payloadParams.batchCount); + bytes32 prevBatchDigestHash = getPrevBatchDigestHash( + payloadParams.requestCount, + payloadParams.batchCount + ); // create digest DigestParams memory digestParams_ = DigestParams( @@ -201,11 +204,14 @@ contract WritePrecompile is WritePrecompileStorage, Initializable, Ownable, Watc ); } - function getPrevBatchDigestHash(uint40 batchCount_) public view returns (bytes32) { + function getPrevBatchDigestHash( + uint40 requestCount_, + uint40 batchCount_ + ) public view returns (bytes32) { if (batchCount_ == 0) return bytes32(0); // if first batch, return bytes32(0) - uint40[] memory requestBatchIds = requestHandler__().getRequestBatchIds(batchCount_); + uint40[] memory requestBatchIds = requestHandler__().getRequestBatchIds(requestCount_); if (requestBatchIds[0] == batchCount_) return bytes32(0); uint40 prevBatchCount = batchCount_ - 1; diff --git a/deployments/dev_addresses.json b/deployments/dev_addresses.json index 22993cb6..80c0774b 100644 --- a/deployments/dev_addresses.json +++ b/deployments/dev_addresses.json @@ -32,7 +32,7 @@ "Watcher": "0x60005b459Dc46D9a63bcb61D01Ad002130644a4F", "WatcherImpl": "0x812EcdF5366036B045e41Fe2dD95B72ecc26d8f3", "WritePrecompile": "0xF221bAA9AEA24c366258309ab09C2C7ce80610Fc", - "WritePrecompileImpl": "0xb64D07B0dDb23cc54eE5EDe294E0cD15f08CC971" + "WritePrecompileImpl": "0x09A1A0A7BB8266171855871c4c0Af200a30922BE" }, "11155420": { "ContractFactoryPlug": "0xf134E3a725DdbBebf9e0f66D6767B44468cdBB48", diff --git a/deployments/dev_verification.json b/deployments/dev_verification.json index 2e26ac90..b1a2b712 100644 --- a/deployments/dev_verification.json +++ b/deployments/dev_verification.json @@ -1,6 +1,12 @@ { "421614": [], "7625382": [ + [ + "0x09A1A0A7BB8266171855871c4c0Af200a30922BE", + "WritePrecompile", + "contracts/evmx/watcher/precompiles/WritePrecompile.sol", + [] + ], [ "0xDa60303321dc6aA8AeF32557bDe914008a3196eC", "SchedulePrecompile", @@ -105,64 +111,5 @@ [] ] ], - "11155420": [ - [ - "0xf134E3a725DdbBebf9e0f66D6767B44468cdBB48", - "ContractFactoryPlug", - "contracts/evmx/plugs/ContractFactoryPlug.sol", - [ - "0xd8C787c27Cc6F4BF143855Bb50c880FB2DE38267", - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" - ] - ], - [ - "0x64b7157Fe0878880b180d9BD2a0bd0D1794Cf44A", - "FeesPlug", - "contracts/evmx/plugs/FeesPlug.sol", - [ - "0xd8C787c27Cc6F4BF143855Bb50c880FB2DE38267", - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" - ] - ], - [ - "0x15dbE4B96306Cc9Eba15D834d6c1a895cF4e1697", - "TestUSDC", - "contracts/evmx/mocks/TestUSDC.sol", - [ - "testUSDC", - "testUSDC", - 6, - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", - { - "type": "BigNumber", - "hex": "0x0b7abc627050305adf14a3d9e40000000000" - } - ] - ], - [ - "0xa2E9eC2B0e035650744B6F489e8dDd471B502b2b", - "FastSwitchboard", - "contracts/protocol/switchboard/FastSwitchboard.sol", - [ - 11155420, - "0xd8C787c27Cc6F4BF143855Bb50c880FB2DE38267", - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" - ] - ], - [ - "0xc6Fe653dAfeDd76d50e3F971dDA650917824f948", - "SocketBatcher", - "contracts/protocol/SocketBatcher.sol", - [ - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", - "0xd8C787c27Cc6F4BF143855Bb50c880FB2DE38267" - ] - ], - [ - "0xd8C787c27Cc6F4BF143855Bb50c880FB2DE38267", - "Socket", - "contracts/protocol/Socket.sol", - [11155420, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] - ] - ] + "11155420": [] } diff --git a/hardhat-scripts/deploy/1.deploy.ts b/hardhat-scripts/deploy/1.deploy.ts index effbbcad..1ba63595 100644 --- a/hardhat-scripts/deploy/1.deploy.ts +++ b/hardhat-scripts/deploy/1.deploy.ts @@ -387,19 +387,24 @@ const deployContractWithProxy = async ( ); const newImplementation = implementation.address; - console.log("Current implementation:", currentImplAddress); - console.log("New implementation:", newImplementation); + console.log( + "Current implementation for", + contractName, + ":", + currentImplAddress + ); + console.log("New implementation for", contractName, ":", newImplementation); if (currentImplAddress.toLowerCase() === newImplementation.toLowerCase()) return deployUtils; - console.log("Upgrading contract"); + console.log("Upgrading contract: ", contractName); const tx = await proxyFactory .connect(deployUtils.signer) .upgrade(deployUtils.addresses[contractName], newImplementation); - console.log("Upgraded contract", tx.hash); + console.log("Upgraded contract", contractName, tx.hash); await tx.wait(); diff --git a/test/SetupTest.t.sol b/test/SetupTest.t.sol index f511ba68..0128cd53 100644 --- a/test/SetupTest.t.sol +++ b/test/SetupTest.t.sol @@ -838,6 +838,7 @@ contract WatcherSetup is AuctionSetup { switchboard = switchboard_; bytes32 prevBatchDigestHash = writePrecompile.getPrevBatchDigestHash( + payloadParams.requestCount, payloadParams.batchCount ); digestParams = DigestParams( From 16b92b44029c0d82fb6d83cf1f2b4778b62aef0d Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 3 Jun 2025 12:38:09 +0530 Subject: [PATCH 117/130] fix: counter gateway --- test/apps/app-gateways/counter/CounterAppGateway.sol | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/apps/app-gateways/counter/CounterAppGateway.sol b/test/apps/app-gateways/counter/CounterAppGateway.sol index ae175171..8933d99c 100644 --- a/test/apps/app-gateways/counter/CounterAppGateway.sol +++ b/test/apps/app-gateways/counter/CounterAppGateway.sol @@ -2,8 +2,6 @@ pragma solidity ^0.8.21; import "../../../../contracts/evmx/base/AppGatewayBase.sol"; -import "../../../../contracts/evmx/interfaces/IForwarder.sol"; -import "../../../../contracts/evmx/interfaces/IPromise.sol"; import "./Counter.sol"; import "./ICounter.sol"; @@ -84,7 +82,7 @@ contract CounterAppGateway is AppGatewayBase, Ownable { uint32 chainSlug = IForwarder(instance_).getChainSlug(); _setOverrides(Read.ON, Parallel.ON, blockNumber_); ICounter(instance_).getCounter(); - IPromise(instance_).then(this.setCounterValues.selector, abi.encode(chainSlug)); + then(this.setCounterValues.selector, abi.encode(chainSlug)); } function setCounterValues(bytes memory data, bytes memory returnData) external onlyPromises { @@ -141,11 +139,13 @@ contract CounterAppGateway is AppGatewayBase, Ownable { address instance = forwarderAddresses[counter][chainSlug]; ICounter(instance).getCounter(); // wrong function call in callback so it reverts - IPromise(instance).then(this.withdrawCredits.selector, abi.encode(chainSlug)); + then(this.withdrawCredits.selector, abi.encode(chainSlug)); _setOverrides(Read.OFF, Parallel.OFF); } function increaseFees(uint40 requestCount_, uint256 newMaxFees_) public { _increaseFees(requestCount_, newMaxFees_); } + + function initialize(uint32 chainSlug_) external override {} } From f4d05f6d1581c9caeac11d54023ce5abecddb191 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 3 Jun 2025 13:47:26 +0530 Subject: [PATCH 118/130] feat: rescue for onchain contracts --- hardhat-scripts/admin/rescue.ts | 165 ++++++++++++++++++++++++++++++++ src/types.ts | 16 ++-- 2 files changed, 175 insertions(+), 6 deletions(-) create mode 100644 hardhat-scripts/admin/rescue.ts diff --git a/hardhat-scripts/admin/rescue.ts b/hardhat-scripts/admin/rescue.ts new file mode 100644 index 00000000..66e5bb17 --- /dev/null +++ b/hardhat-scripts/admin/rescue.ts @@ -0,0 +1,165 @@ +import { config as dotenvConfig } from "dotenv"; + +dotenvConfig(); + +import { formatEther } from "ethers/lib/utils"; +import { Contract, ethers } from "ethers"; +import { mainnetChains, mode, testnetChains } from "../config"; +import { getAddresses, getSocketSigner, overrides } from "../utils"; +import { DeploymentAddresses } from "../constants"; +import { ChainAddressesObj, ChainSlug } from "../../src"; + +/** + * Usable flags + * --sendtx Send rescue tx along with checking balance. + * Default is only check balance. + * Eg. npx --sendtx ts-node scripts/admin/rescueFunds.ts + * + * --amount Specify amount to rescue, can be used only with --sendtx + * If this much is not available then less is rescued. + * Full amount is rescued if not mentioned. + * Eg. npx --chains=2999 --sendtx --amount=0.2 ts-node scripts/admin/rescueFunds.ts + * + * --chains Run only for specified chains. + * Default is all chains. + * Eg. npx --chains=10,2999 ts-node scripts/admin/rescueFunds.ts + * + * --testnets Run for testnets. + * Default is false. + */ + +const addresses: DeploymentAddresses = getAddresses( + mode +) as unknown as DeploymentAddresses; + +const testnets = process.env.npm_config_testnets == "true"; +let activeChainSlugs: string[]; +if (testnets) + activeChainSlugs = Object.keys(addresses).filter((c) => + testnetChains.includes(parseInt(c) as ChainSlug) + ); +else + activeChainSlugs = Object.keys(addresses).filter((c) => + mainnetChains.includes(parseInt(c) as ChainSlug) + ); + +const sendTx = process.env.npm_config_sendtx == "true"; +const filterChains = process.env.npm_config_chains + ? process.env.npm_config_chains.split(",") + : activeChainSlugs; +const maxRescueAmount = ethers.utils.parseEther( + process.env.npm_config_amount || "0" +); + +const ETH_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"; +const rescueFundsABI = [ + { + inputs: [ + { + internalType: "address", + name: "token_", + type: "address", + }, + { + internalType: "address", + name: "rescueTo_", + type: "address", + }, + { + internalType: "uint256", + name: "amount_", + type: "uint256", + }, + ], + name: "rescueFunds", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, +]; + +const createContractAddrArray = (chainSlug: number): string[] => { + let chainAddresses = addresses[chainSlug] as unknown as ChainAddressesObj; + if (!chainAddresses) { + console.log("addresses not found for ", chainSlug, chainAddresses); + return []; + } + + let addressArray: string[] = []; + if (chainAddresses.SocketFeesManager) + addressArray.push(chainAddresses.SocketFeesManager); + if (chainAddresses.FeesPlug) addressArray.push(chainAddresses.FeesPlug); + addressArray.push(chainAddresses.Socket); + addressArray.push(chainAddresses.SocketBatcher); + addressArray.push(chainAddresses.FastSwitchboard); + addressArray.push(chainAddresses.ContractFactoryPlug); + return addressArray; +}; + +export const main = async () => { + // parallelize chains + await Promise.all( + activeChainSlugs + .filter((c) => filterChains.includes(c)) + .map(async (chainSlug) => { + const signer = await getSocketSigner(parseInt(chainSlug)); + const contractAddr = createContractAddrArray(parseInt(chainSlug)); + + for (let index = 0; index < contractAddr.length; index++) { + const rescueableAmount = await signer.provider.getBalance( + contractAddr[index] + ); + const fundingAmount = await signer.provider.getBalance( + "0x0240c3151FE3e5bdBB1894F59C5Ed9fE71ba0a5E" + ); + console.log( + `rescueableAmount on ${chainSlug} : ${formatEther( + rescueableAmount + )}` + ); + console.log( + `fundingAmount on ${chainSlug}: ${formatEther(fundingAmount)}` + ); + + const rescueAmount = + maxRescueAmount.eq(0) || rescueableAmount.lt(maxRescueAmount) + ? rescueableAmount + : maxRescueAmount; + if (rescueAmount.toString() === "0") continue; + + const contractInstance: Contract = new ethers.Contract( + contractAddr[index], + rescueFundsABI, + signer + ); + + if (sendTx) { + try { + const tx = await contractInstance.rescueFunds( + ETH_ADDRESS, + signer.address, + rescueAmount, + { ...(await overrides(parseInt(chainSlug))) } + ); + console.log( + `Rescuing ${rescueAmount} from ${contractAddr[index]} on ${chainSlug}: ${tx.hash}` + ); + + await tx.wait(); + } catch (e) { + console.log( + `Error while rescuing ${rescueAmount} from ${contractAddr[index]} on ${chainSlug}` + ); + } + } + } + }) + ); +}; + +main() + .then(() => process.exit(0)) + .catch((error: Error) => { + console.error(error); + process.exit(1); + }); diff --git a/src/types.ts b/src/types.ts index 420d5dd3..1a047bcc 100644 --- a/src/types.ts +++ b/src/types.ts @@ -20,22 +20,26 @@ export type ChainAddressesObj = { SocketBatcher: string; FastSwitchboard: string; ContractFactoryPlug: string; + SocketFeesManager?: string; FeesPlug?: string; startBlock: number; }; export type EVMxAddressesObj = { AddressResolver: string; - Watcher: string; - RequestHandler: string; + AsyncDeployer: string; + AuctionManager: string; Configurations: string; + DeployForwarder: string; + FeesManager: string; + FeesPool: string; PromiseResolver: string; - WritePrecompile: string; ReadPrecompile: string; + RequestHandler: string; SchedulePrecompile: string; - AuctionManager: string; - FeesManager: string; - FeesPool: string; + Watcher: string; + WritePrecompile: string; + ERC1967Factory: string; startBlock: number; }; From d61c54593bdd6de116e02e072e4f199e0a66efc3 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 3 Jun 2025 14:22:32 +0530 Subject: [PATCH 119/130] feat: dev deployment --- Errors.md | 184 ++--- EventTopics.md | 391 ++++----- FunctionSignatures.md | 928 +++++++++++----------- deployments/dev_addresses.json | 70 +- deployments/dev_verification.json | 189 ++++- hardhat-scripts/deploy/4.configureEVMx.ts | 29 +- hardhat-scripts/utils/deployUtils.ts | 6 +- 7 files changed, 993 insertions(+), 804 deletions(-) diff --git a/Errors.md b/Errors.md index c9ef6e7e..d40a6613 100644 --- a/Errors.md +++ b/Errors.md @@ -1,141 +1,143 @@ # Custom Error Codes + ## evmx/fees/FeesPool.sol -| Error | Signature | -| ------------------ | ------------ | +| Error | Signature | +|-------|-----------| | `TransferFailed()` | `0x90b8ec18` | ## evmx/helpers/AsyncPromise.sol -| Error | Signature | -| -------------------------- | ------------ | +| Error | Signature | +|-------|-----------| | `PromiseAlreadyResolved()` | `0x56b63537` | -| `OnlyInvoker()` | `0x74ed21f5` | -| `PromiseAlreadySetUp()` | `0x927c53d5` | -| `PromiseRevertFailed()` | `0x0175b9de` | -| `NotLatestPromise()` | `0x39ca95d3` | +| `OnlyInvoker()` | `0x74ed21f5` | +| `PromiseAlreadySetUp()` | `0x927c53d5` | +| `PromiseRevertFailed()` | `0x0175b9de` | +| `NotLatestPromise()` | `0x39ca95d3` | ## evmx/plugs/ContractFactoryPlug.sol -| Error | Signature | -| -------------------------------- | ------------ | -| `DeploymentFailed()` | `0x30116425` | +| Error | Signature | +|-------|-----------| +| `DeploymentFailed()` | `0x30116425` | | `ExecutionFailed(bytes32,bytes)` | `0xd255d8a3` | -| `information(bool,,bytes)` | `0x3a82a1f3` | +| `information(bool,,bytes)` | `0x3a82a1f3` | ## evmx/plugs/FeesPlug.sol -| Error | Signature | -| --------------------------------------------------- | ------------ | +| Error | Signature | +|-------|-----------| | `InsufficientTokenBalance(address,uint256,uint256)` | `0xebd6ced9` | -| `InvalidDepositAmount()` | `0xfe9ba5cd` | -| `TokenNotWhitelisted(address)` | `0xea3bff2e` | +| `InvalidDepositAmount()` | `0xfe9ba5cd` | +| `TokenNotWhitelisted(address)` | `0xea3bff2e` | ## evmx/watcher/RequestHandler.sol -| Error | Signature | -| ----------------------- | ------------ | +| Error | Signature | +|-------|-----------| | `InsufficientMaxFees()` | `0x0e5bc492` | ## protocol/Socket.sol -| Error | Signature | -| ----------------------------------------- | ------------ | +| Error | Signature | +|-------|-----------| | `PayloadAlreadyExecuted(ExecutionStatus)` | `0xf4c54edd` | -| `VerificationFailed()` | `0x439cc0cd` | -| `LowGasLimit()` | `0xd38edae0` | -| `InsufficientMsgValue()` | `0x78f38f76` | +| `VerificationFailed()` | `0x439cc0cd` | +| `LowGasLimit()` | `0xd38edae0` | +| `InsufficientMsgValue()` | `0x78f38f76` | ## protocol/SocketConfig.sol -| Error | Signature | -| ------------------------------- | ------------ | -| `SwitchboardExists()` | `0x2dff8555` | +| Error | Signature | +|-------|-----------| +| `SwitchboardExists()` | `0x2dff8555` | | `SwitchboardExistsOrDisabled()` | `0x1c7d2487` | ## protocol/SocketFeeManager.sol -| Error | Signature | -| -------------------- | ------------ | +| Error | Signature | +|-------|-----------| | `InsufficientFees()` | `0x8d53e553` | -| `FeeTooLow()` | `0x732f9413` | +| `FeeTooLow()` | `0x732f9413` | ## protocol/SocketUtils.sol -| Error | Signature | -| -------------------- | ------------ | -| `OnlyOffChain()` | `0x9cbfe066` | +| Error | Signature | +|-------|-----------| +| `OnlyOffChain()` | `0x9cbfe066` | | `SimulationFailed()` | `0x2fbab3ac` | ## protocol/switchboard/FastSwitchboard.sol -| Error | Signature | -| ------------------- | ------------ | +| Error | Signature | +|-------|-----------| | `AlreadyAttested()` | `0x35d90805` | | `WatcherNotFound()` | `0xa278e4ad` | ## utils/AccessControl.sol -| Error | Signature | -| ------------------- | ------------ | +| Error | Signature | +|-------|-----------| | `NoPermit(bytes32)` | `0x962f6333` | ## utils/common/Errors.sol -| Error | Signature | -| --------------------------------------------- | ------------ | -| `ZeroAddress()` | `0xd92e233d` | -| `InvalidTransmitter()` | `0x58a70a0a` | -| `InvalidTokenAddress()` | `0x1eb00b06` | -| `InvalidSwitchboard()` | `0xf63c9e4d` | -| `SocketAlreadyInitialized()` | `0xc9500b00` | -| `NotSocket()` | `0xc59f8f7c` | -| `PlugNotFound()` | `0x5f1ac76a` | -| `ResolvingScheduleTooEarly()` | `0x207e8731` | -| `CallFailed()` | `0x3204506f` | -| `InvalidAppGateway()` | `0x82ded261` | -| `AppGatewayAlreadyCalled()` | `0xb224683f` | -| `InvalidCallerTriggered()` | `0x3292d247` | -| `InvalidPromise()` | `0x45f2d176` | -| `InvalidWatcherSignature()` | `0x5029f14f` | -| `NonceUsed()` | `0x1f6d5aef` | -| `AsyncModifierNotSet()` | `0xcae106f9` | -| `WatcherNotSet()` | `0x42d473a7` | -| `InvalidTarget()` | `0x82d5d76a` | -| `InvalidIndex()` | `0x63df8171` | -| `InvalidChainSlug()` | `0xbff6b106` | -| `InvalidPayloadSize()` | `0xfbdf7954` | -| `InvalidScheduleDelay()` | `0x9a993219` | -| `AuctionClosed()` | `0x36b6b46d` | -| `AuctionNotOpen()` | `0xf0460077` | -| `BidExceedsMaxFees()` | `0x4c923f3c` | -| `LowerBidAlreadyExists()` | `0xaaa1f709` | -| `RequestCountMismatch()` | `0x98bbcbff` | -| `InvalidAmount()` | `0x2c5211c6` | -| `InsufficientCreditsAvailable()` | `0xe61dc0aa` | -| `InsufficientBalance()` | `0xf4d678b8` | -| `InvalidCaller()` | `0x48f5c3ed` | -| `InvalidGateway()` | `0xfc9dfe85` | -| `RequestAlreadyCancelled()` | `0xc70f47d8` | -| `DeadlineNotPassedForOnChainRevert()` | `0x7006aa10` | -| `InvalidBid()` | `0xc6388ef7` | -| `MaxReAuctionCountReached()` | `0xf2b4388c` | -| `MaxMsgValueLimitExceeded()` | `0x97b4e8ce` | -| `OnlyWatcherAllowed()` | `0xdf7d227c` | -| `InvalidPrecompileData()` | `0x320062c0` | -| `InvalidCallType()` | `0x39d2eb55` | -| `NotRequestHandler()` | `0x8f8cba5b` | -| `NotInvoker()` | `0x8a6353d1` | -| `NotPromiseResolver()` | `0x86d876b2` | -| `RequestPayloadCountLimitExceeded()` | `0xcbef144b` | -| `InsufficientFees()` | `0x8d53e553` | -| `RequestAlreadySettled()` | `0x66fad465` | -| `NoWriteRequest()` | `0x9dcd3065` | -| `AlreadyAssigned()` | `0x9688dc51` | -| `OnlyAppGateway()` | `0xfec944ea` | +| Error | Signature | +|-------|-----------| +| `ZeroAddress()` | `0xd92e233d` | +| `InvalidTransmitter()` | `0x58a70a0a` | +| `InvalidTokenAddress()` | `0x1eb00b06` | +| `InvalidSwitchboard()` | `0xf63c9e4d` | +| `SocketAlreadyInitialized()` | `0xc9500b00` | +| `NotSocket()` | `0xc59f8f7c` | +| `PlugNotFound()` | `0x5f1ac76a` | +| `ResolvingScheduleTooEarly()` | `0x207e8731` | +| `CallFailed()` | `0x3204506f` | +| `InvalidAppGateway()` | `0x82ded261` | +| `AppGatewayAlreadyCalled()` | `0xb224683f` | +| `InvalidCallerTriggered()` | `0x3292d247` | +| `InvalidPromise()` | `0x45f2d176` | +| `InvalidWatcherSignature()` | `0x5029f14f` | +| `NonceUsed()` | `0x1f6d5aef` | +| `AsyncModifierNotSet()` | `0xcae106f9` | +| `WatcherNotSet()` | `0x42d473a7` | +| `InvalidTarget()` | `0x82d5d76a` | +| `InvalidIndex()` | `0x63df8171` | +| `InvalidChainSlug()` | `0xbff6b106` | +| `InvalidPayloadSize()` | `0xfbdf7954` | +| `InvalidOnChainAddress()` | `0xb758c606` | +| `InvalidScheduleDelay()` | `0x9a993219` | +| `AuctionClosed()` | `0x36b6b46d` | +| `AuctionNotOpen()` | `0xf0460077` | +| `BidExceedsMaxFees()` | `0x4c923f3c` | +| `LowerBidAlreadyExists()` | `0xaaa1f709` | +| `RequestCountMismatch()` | `0x98bbcbff` | +| `InvalidAmount()` | `0x2c5211c6` | +| `InsufficientCreditsAvailable()` | `0xe61dc0aa` | +| `InsufficientBalance()` | `0xf4d678b8` | +| `InvalidCaller()` | `0x48f5c3ed` | +| `InvalidGateway()` | `0xfc9dfe85` | +| `RequestAlreadyCancelled()` | `0xc70f47d8` | +| `DeadlineNotPassedForOnChainRevert()` | `0x7006aa10` | +| `InvalidBid()` | `0xc6388ef7` | +| `MaxReAuctionCountReached()` | `0xf2b4388c` | +| `MaxMsgValueLimitExceeded()` | `0x97b4e8ce` | +| `OnlyWatcherAllowed()` | `0xdf7d227c` | +| `InvalidPrecompileData()` | `0x320062c0` | +| `InvalidCallType()` | `0x39d2eb55` | +| `NotRequestHandler()` | `0x8f8cba5b` | +| `NotInvoker()` | `0x8a6353d1` | +| `NotPromiseResolver()` | `0x86d876b2` | +| `RequestPayloadCountLimitExceeded()` | `0xcbef144b` | +| `InsufficientFees()` | `0x8d53e553` | +| `RequestAlreadySettled()` | `0x66fad465` | +| `NoWriteRequest()` | `0x9dcd3065` | +| `AlreadyAssigned()` | `0x9688dc51` | +| `OnlyAppGateway()` | `0xfec944ea` | | `NewMaxFeesLowerThanCurrent(uint256,uint256)` | `0x1345dda1` | -| `InvalidContract()` | `0x6eefed20` | -| `InvalidData()` | `0x5cb045db` | -| `InvalidSignature()` | `0x8baa579f` | -| `DeadlinePassed()` | `0x70f65caa` | +| `InvalidContract()` | `0x6eefed20` | +| `InvalidData()` | `0x5cb045db` | +| `InvalidSignature()` | `0x8baa579f` | +| `DeadlinePassed()` | `0x70f65caa` | diff --git a/EventTopics.md b/EventTopics.md index 36cadb7d..b4fb85c7 100644 --- a/EventTopics.md +++ b/EventTopics.md @@ -2,268 +2,269 @@ ## AuctionManager -| Event | Arguments | Topic | -| ---------------------------- | ------------------------------------------- | -------------------------------------------------------------------- | -| `AuctionEndDelaySecondsSet` | `(auctionEndDelaySeconds: uint256)` | `0xf38f0d9dc8459cf5426728c250d115196a4c065ebc1a6c29da24764a8c0da722` | -| `AuctionEnded` | `(requestCount: uint40, winningBid: tuple)` | `0xede4ec1efc469fac10dcb4930f70be4cd21f3700ed61c91967c19a7cd7c0d86e` | -| `AuctionRestarted` | `(requestCount: uint40)` | `0x071867b21946ec4655665f0d4515d3757a5a52f144c762ecfdfb11e1da542b82` | -| `AuctionStarted` | `(requestCount: uint40)` | `0xcd040613cf8ef0cfcaa3af0d711783e827a275fc647c116b74595bf17cb9364f` | -| `BidPlaced` | `(requestCount: uint40, bid: tuple)` | `0x7f79485e4c9aeea5d4899bc6f7c63b22ac1f4c01d2d28c801e94732fee657b5d` | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `MaxReAuctionCountSet` | `(maxReAuctionCount: uint256)` | `0x2f6fadde7ab8ab83d21ab10c3bc09dde179f8696d47c4176581facf0c6f96bbf` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | -| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | +| Event | Arguments | Topic | +| ----- | --------- | ----- | +| `AuctionEndDelaySecondsSet` | `(auctionEndDelaySeconds: uint256)` | `0xf38f0d9dc8459cf5426728c250d115196a4c065ebc1a6c29da24764a8c0da722` | +| `AuctionEnded` | `(requestCount: uint40, winningBid: tuple)` | `0xede4ec1efc469fac10dcb4930f70be4cd21f3700ed61c91967c19a7cd7c0d86e` | +| `AuctionRestarted` | `(requestCount: uint40)` | `0x071867b21946ec4655665f0d4515d3757a5a52f144c762ecfdfb11e1da542b82` | +| `AuctionStarted` | `(requestCount: uint40)` | `0xcd040613cf8ef0cfcaa3af0d711783e827a275fc647c116b74595bf17cb9364f` | +| `BidPlaced` | `(requestCount: uint40, bid: tuple)` | `0x7f79485e4c9aeea5d4899bc6f7c63b22ac1f4c01d2d28c801e94732fee657b5d` | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `MaxReAuctionCountSet` | `(maxReAuctionCount: uint256)` | `0x2f6fadde7ab8ab83d21ab10c3bc09dde179f8696d47c4176581facf0c6f96bbf` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | +| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | ## Socket -| Event | Arguments | Topic | -| ---------------------------- | -------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | -| `AppGatewayCallRequested` | `(triggerId: bytes32, appGatewayId: bytes32, switchboard: address, plug: address, overrides: bytes, payload: bytes)` | `0x5c88d65ab8ba22a57e582bd8ddfa9801cc0ca6be6cb3182baaedc705a612419e` | -| `ExecutionFailed` | `(payloadId: bytes32, exceededMaxCopy: bool, returnData: bytes)` | `0x385334bc68a32c4d164625189adc7633e6074eb1b837fb4d11d768245151e4ce` | -| `ExecutionSuccess` | `(payloadId: bytes32, exceededMaxCopy: bool, returnData: bytes)` | `0x324d63a433b21a12b90e79cd2ba736b2a5238be6165e03b750fa4a7d5193d5d9` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `PlugConnected` | `(plug: address, appGatewayId: bytes32, switchboard: address)` | `0x90c5924e27cfb6e3a688e729083681f30494ae2615ae14aac3bc807a0c436a88` | -| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | -| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | -| `SocketFeeManagerUpdated` | `(oldSocketFeeManager: address, newSocketFeeManager: address)` | `0xdcb02e10d5220346a4638aa2826eaab1897306623bc40a427049e4ebd12255b4` | -| `SwitchboardAdded` | `(switchboard: address)` | `0x1595852923edfbbf906f09fc8523e4cfb022a194773c4d1509446b614146ee88` | -| `SwitchboardDisabled` | `(switchboard: address)` | `0x1b4ee41596b4e754e5665f01ed6122b356f7b36ea0a02030804fac7fa0fdddfc` | -| `SwitchboardEnabled` | `(switchboard: address)` | `0x6909a9974e3eec619bc479ba882d30a5ef1219b72ab1ce6a354516e91be317b8` | +| Event | Arguments | Topic | +| ----- | --------- | ----- | +| `AppGatewayCallRequested` | `(triggerId: bytes32, appGatewayId: bytes32, switchboard: address, plug: address, overrides: bytes, payload: bytes)` | `0x5c88d65ab8ba22a57e582bd8ddfa9801cc0ca6be6cb3182baaedc705a612419e` | +| `ExecutionFailed` | `(payloadId: bytes32, exceededMaxCopy: bool, returnData: bytes)` | `0x385334bc68a32c4d164625189adc7633e6074eb1b837fb4d11d768245151e4ce` | +| `ExecutionSuccess` | `(payloadId: bytes32, exceededMaxCopy: bool, returnData: bytes)` | `0x324d63a433b21a12b90e79cd2ba736b2a5238be6165e03b750fa4a7d5193d5d9` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `PlugConnected` | `(plug: address, appGatewayId: bytes32, switchboard: address)` | `0x90c5924e27cfb6e3a688e729083681f30494ae2615ae14aac3bc807a0c436a88` | +| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | +| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | +| `SocketFeeManagerUpdated` | `(oldSocketFeeManager: address, newSocketFeeManager: address)` | `0xdcb02e10d5220346a4638aa2826eaab1897306623bc40a427049e4ebd12255b4` | +| `SwitchboardAdded` | `(switchboard: address)` | `0x1595852923edfbbf906f09fc8523e4cfb022a194773c4d1509446b614146ee88` | +| `SwitchboardDisabled` | `(switchboard: address)` | `0x1b4ee41596b4e754e5665f01ed6122b356f7b36ea0a02030804fac7fa0fdddfc` | +| `SwitchboardEnabled` | `(switchboard: address)` | `0x6909a9974e3eec619bc479ba882d30a5ef1219b72ab1ce6a354516e91be317b8` | ## SocketBatcher -| Event | Arguments | Topic | -| ---------------------------- | ---------------------------------------- | -------------------------------------------------------------------- | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| Event | Arguments | Topic | +| ----- | --------- | ----- | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | ## SocketFeeManager -| Event | Arguments | Topic | -| ---------------------------- | ---------------------------------------- | -------------------------------------------------------------------- | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | -| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | -| `SocketFeesUpdated` | `(oldFees: uint256, newFees: uint256)` | `0xcbd4d756fb6198bbcc2e4013cce929f504ad46e9d97c543ef9a8dfea3e407053` | +| Event | Arguments | Topic | +| ----- | --------- | ----- | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | +| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | +| `SocketFeesUpdated` | `(oldFees: uint256, newFees: uint256)` | `0xcbd4d756fb6198bbcc2e4013cce929f504ad46e9d97c543ef9a8dfea3e407053` | ## FeesManager -| Event | Arguments | Topic | -| ----------------------------- | ------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | -| `CreditsBlocked` | `(requestCount: uint40, consumeFrom: address, amount: uint256)` | `0xf037c15aef41440aa823cf1fdeaea332105d8b23d52557f6670189b5d76f1eed` | -| `CreditsTransferred` | `(from: address, to: address, amount: uint256)` | `0xed198cadddd93e734cbf04cb1c3226d9bafaeb504cedbd8ee36b830b0cb9e7a5` | -| `CreditsUnblocked` | `(requestCount: uint40, consumeFrom: address)` | `0x45db29ef2701319155cac058aa2f56ce1f73e0e238161d3db9f8c9a47655210d` | -| `CreditsUnblockedAndAssigned` | `(requestCount: uint40, consumeFrom: address, transmitter: address, amount: uint256)` | `0x38fd327622576a468e1b2818b00f50c8854703633ef8e583e1f31662888ffac2` | -| `CreditsUnwrapped` | `(consumeFrom: address, amount: uint256)` | `0xdcc9473b722b4c953617ab373840b365298a520bc7f20ce94fa7314f4a857774` | -| `CreditsWrapped` | `(consumeFrom: address, amount: uint256)` | `0x40246503613721eb4acf4020c6c56b6a16e5d08713316db0bea5210e8819c592` | -| `Deposited` | `(chainSlug: uint32, token: address, depositTo: address, creditAmount: uint256, nativeAmount: uint256)` | `0x72aedd284699bbd7a987e6942b824cfd6c627e354cb5a0760ac5768acd473f4a` | -| `FeesPlugSet` | `(chainSlug: uint32, feesPlug: address)` | `0xa8c4be32b96cca895f1f0f4684e6b377b2c4513bc35eb57a13afb6b5efb2c0ce` | -| `FeesPoolSet` | `(feesPool: address)` | `0xd07af3fd70b48ab3c077a8d45c3a288498d905d0e3d1e65bc171f6c2e890d8ef` | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| Event | Arguments | Topic | +| ----- | --------- | ----- | +| `CreditsBlocked` | `(requestCount: uint40, consumeFrom: address, amount: uint256)` | `0xf037c15aef41440aa823cf1fdeaea332105d8b23d52557f6670189b5d76f1eed` | +| `CreditsTransferred` | `(from: address, to: address, amount: uint256)` | `0xed198cadddd93e734cbf04cb1c3226d9bafaeb504cedbd8ee36b830b0cb9e7a5` | +| `CreditsUnblocked` | `(requestCount: uint40, consumeFrom: address)` | `0x45db29ef2701319155cac058aa2f56ce1f73e0e238161d3db9f8c9a47655210d` | +| `CreditsUnblockedAndAssigned` | `(requestCount: uint40, consumeFrom: address, transmitter: address, amount: uint256)` | `0x38fd327622576a468e1b2818b00f50c8854703633ef8e583e1f31662888ffac2` | +| `CreditsUnwrapped` | `(consumeFrom: address, amount: uint256)` | `0xdcc9473b722b4c953617ab373840b365298a520bc7f20ce94fa7314f4a857774` | +| `CreditsWrapped` | `(consumeFrom: address, amount: uint256)` | `0x40246503613721eb4acf4020c6c56b6a16e5d08713316db0bea5210e8819c592` | +| `Deposited` | `(chainSlug: uint32, token: address, depositTo: address, creditAmount: uint256, nativeAmount: uint256)` | `0x72aedd284699bbd7a987e6942b824cfd6c627e354cb5a0760ac5768acd473f4a` | +| `FeesPlugSet` | `(chainSlug: uint32, feesPlug: address)` | `0xa8c4be32b96cca895f1f0f4684e6b377b2c4513bc35eb57a13afb6b5efb2c0ce` | +| `FeesPoolSet` | `(feesPool: address)` | `0xd07af3fd70b48ab3c077a8d45c3a288498d905d0e3d1e65bc171f6c2e890d8ef` | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | ## FeesPool -| Event | Arguments | Topic | -| ---------------------------- | ----------------------------------------------- | -------------------------------------------------------------------- | -| `NativeDeposited` | `(from: address, amount: uint256)` | `0xb5d7700fb0cf415158b8db7cc7c39f0eab16a825c92e221404b4c8bb099b4bbb` | -| `NativeWithdrawn` | `(success: bool, to: address, amount: uint256)` | `0xa81f1c8490022ee829d2e1a231053f5dbecad46caee71f6ea38a9db663a3f12b` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | -| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | +| Event | Arguments | Topic | +| ----- | --------- | ----- | +| `NativeDeposited` | `(from: address, amount: uint256)` | `0xb5d7700fb0cf415158b8db7cc7c39f0eab16a825c92e221404b4c8bb099b4bbb` | +| `NativeWithdrawn` | `(success: bool, to: address, amount: uint256)` | `0xa81f1c8490022ee829d2e1a231053f5dbecad46caee71f6ea38a9db663a3f12b` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | +| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | ## AddressResolver -| Event | Arguments | Topic | -| ------------------------------ | --------------------------------------------------- | -------------------------------------------------------------------- | -| `AsyncDeployerUpdated` | `(asyncDeployer_: address)` | `0x4df9cdd01544e8f6b0326650bc0b55611f47ce5ba2faa522d21fb675e9fc1f73` | -| `ContractAddressUpdated` | `(contractId_: bytes32, contractAddress_: address)` | `0xdf5ec2c15e11ce657bb21bc09c0b5ba95e315b4dba9934c6e311f47559babf28` | -| `DefaultAuctionManagerUpdated` | `(defaultAuctionManager_: address)` | `0x60f296739208a505ead7fb622df0f76b7791b824481b120a2300bdaf85e3e3d6` | -| `DeployForwarderUpdated` | `(deployForwarder_: address)` | `0x237b9bc9fef7508a02ca9ccca81f6965e500064a58024cae1218035da865fd2b` | -| `FeesManagerUpdated` | `(feesManager_: address)` | `0x94e67aa1341a65767dfde81e62fd265bfbade1f5744bfd3cd73f99a6eca0572a` | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `WatcherUpdated` | `(watcher_: address)` | `0xc13081d38d92b454cdb6ca20bbc65c12fa43a7a14a1529204ced5b6350052bb0` | +| Event | Arguments | Topic | +| ----- | --------- | ----- | +| `AsyncDeployerUpdated` | `(asyncDeployer_: address)` | `0x4df9cdd01544e8f6b0326650bc0b55611f47ce5ba2faa522d21fb675e9fc1f73` | +| `ContractAddressUpdated` | `(contractId_: bytes32, contractAddress_: address)` | `0xdf5ec2c15e11ce657bb21bc09c0b5ba95e315b4dba9934c6e311f47559babf28` | +| `DefaultAuctionManagerUpdated` | `(defaultAuctionManager_: address)` | `0x60f296739208a505ead7fb622df0f76b7791b824481b120a2300bdaf85e3e3d6` | +| `DeployForwarderUpdated` | `(deployForwarder_: address)` | `0x237b9bc9fef7508a02ca9ccca81f6965e500064a58024cae1218035da865fd2b` | +| `FeesManagerUpdated` | `(feesManager_: address)` | `0x94e67aa1341a65767dfde81e62fd265bfbade1f5744bfd3cd73f99a6eca0572a` | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `WatcherUpdated` | `(watcher_: address)` | `0xc13081d38d92b454cdb6ca20bbc65c12fa43a7a14a1529204ced5b6350052bb0` | ## AsyncDeployer -| Event | Arguments | Topic | -| ---------------------------- | ---------------------------------------------------- | -------------------------------------------------------------------- | -| `AsyncPromiseDeployed` | `(newAsyncPromise: address, salt: bytes32)` | `0xb6c5491cf83e09749b1a4dd6a9f07b0e925fcb0a915ac8c2b40e8ab28191c270` | -| `ForwarderDeployed` | `(newForwarder: address, salt: bytes32)` | `0x4dbbecb9cf9c8b93da9743a2b48ea52efe68d69230ab1c1b711891d9d223b29f` | -| `ImplementationUpdated` | `(contractName: string, newImplementation: address)` | `0xa1e41aa2c2f3f20d9b63ac06b634d2788768d6034f3d9192cdf7d07374bb16f4` | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| Event | Arguments | Topic | +| ----- | --------- | ----- | +| `AsyncPromiseDeployed` | `(newAsyncPromise: address, salt: bytes32)` | `0xb6c5491cf83e09749b1a4dd6a9f07b0e925fcb0a915ac8c2b40e8ab28191c270` | +| `ForwarderDeployed` | `(newForwarder: address, salt: bytes32)` | `0x4dbbecb9cf9c8b93da9743a2b48ea52efe68d69230ab1c1b711891d9d223b29f` | +| `ImplementationUpdated` | `(contractName: string, newImplementation: address)` | `0xa1e41aa2c2f3f20d9b63ac06b634d2788768d6034f3d9192cdf7d07374bb16f4` | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | ## AsyncPromise -| Event | Arguments | Topic | -| ------------- | ------------------- | -------------------------------------------------------------------- | +| Event | Arguments | Topic | +| ----- | --------- | ----- | | `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | ## DeployForwarder -| Event | Arguments | Topic | -| ---------------------------- | ---------------------------------------- | -------------------------------------------------------------------- | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| Event | Arguments | Topic | +| ----- | --------- | ----- | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | ## Forwarder -| Event | Arguments | Topic | -| ------------- | ------------------- | -------------------------------------------------------------------- | +| Event | Arguments | Topic | +| ----- | --------- | ----- | | `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | ## ProxyFactory -| Event | Arguments | Topic | -| -------------- | ----------------------------------------------------------- | -------------------------------------------------------------------- | -| `AdminChanged` | `(proxy: address, admin: address)` | `0x7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f` | -| `Deployed` | `(proxy: address, implementation: address, admin: address)` | `0xc95935a66d15e0da5e412aca0ad27ae891d20b2fb91cf3994b6a3bf2b8178082` | -| `Upgraded` | `(proxy: address, implementation: address)` | `0x5d611f318680d00598bb735d61bacf0c514c6b50e1e5ad30040a4df2b12791c7` | +| Event | Arguments | Topic | +| ----- | --------- | ----- | +| `AdminChanged` | `(proxy: address, admin: address)` | `0x7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f` | +| `Deployed` | `(proxy: address, implementation: address, admin: address)` | `0xc95935a66d15e0da5e412aca0ad27ae891d20b2fb91cf3994b6a3bf2b8178082` | +| `Upgraded` | `(proxy: address, implementation: address)` | `0x5d611f318680d00598bb735d61bacf0c514c6b50e1e5ad30040a4df2b12791c7` | ## TestUSDC -| Event | Arguments | Topic | -| ---------- | ----------------------------------------------------- | -------------------------------------------------------------------- | +| Event | Arguments | Topic | +| ----- | --------- | ----- | | `Approval` | `(owner: address, spender: address, amount: uint256)` | `0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925` | -| `Transfer` | `(from: address, to: address, amount: uint256)` | `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef` | +| `Transfer` | `(from: address, to: address, amount: uint256)` | `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef` | ## ContractFactoryPlug -| Event | Arguments | Topic | -| ---------------------------- | --------------------------------------------------- | -------------------------------------------------------------------- | -| `ConnectorPlugDisconnected` | `()` | `0xc2af098c82dba3c4b00be8bda596d62d13b98a87b42626fefa67e0bb0e198fdd` | -| `Deployed` | `(addr: address, salt: bytes32, returnData: bytes)` | `0x1246c6f8fd9f4abc542c7c8c8f793cfcde6b67aed1976a38aa134fc24af2dfe3` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | -| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | +| Event | Arguments | Topic | +| ----- | --------- | ----- | +| `ConnectorPlugDisconnected` | `()` | `0xc2af098c82dba3c4b00be8bda596d62d13b98a87b42626fefa67e0bb0e198fdd` | +| `Deployed` | `(addr: address, salt: bytes32, returnData: bytes)` | `0x1246c6f8fd9f4abc542c7c8c8f793cfcde6b67aed1976a38aa134fc24af2dfe3` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | +| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | ## FeesPlug -| Event | Arguments | Topic | -| ---------------------------- | ----------------------------------------------------------------------------------- | -------------------------------------------------------------------- | -| `ConnectorPlugDisconnected` | `()` | `0xc2af098c82dba3c4b00be8bda596d62d13b98a87b42626fefa67e0bb0e198fdd` | -| `FeesDeposited` | `(token: address, receiver: address, creditAmount: uint256, nativeAmount: uint256)` | `0xeb4e1b24b7fe377de69f80f7380bda5ba4b43176c6a4d300a3be9009c49f4228` | -| `FeesWithdrawn` | `(token: address, receiver: address, amount: uint256)` | `0x5e110f8bc8a20b65dcc87f224bdf1cc039346e267118bae2739847f07321ffa8` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | -| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | -| `TokenRemovedFromWhitelist` | `(token: address)` | `0xdd2e6d9f52cbe8f695939d018b7d4a216dc613a669876163ac548b916489d917` | -| `TokenWhitelisted` | `(token: address)` | `0x6a65f90b1a644d2faac467a21e07e50e3f8fa5846e26231d30ae79a417d3d262` | +| Event | Arguments | Topic | +| ----- | --------- | ----- | +| `ConnectorPlugDisconnected` | `()` | `0xc2af098c82dba3c4b00be8bda596d62d13b98a87b42626fefa67e0bb0e198fdd` | +| `FeesDeposited` | `(token: address, receiver: address, creditAmount: uint256, nativeAmount: uint256)` | `0xeb4e1b24b7fe377de69f80f7380bda5ba4b43176c6a4d300a3be9009c49f4228` | +| `FeesWithdrawn` | `(token: address, receiver: address, amount: uint256)` | `0x5e110f8bc8a20b65dcc87f224bdf1cc039346e267118bae2739847f07321ffa8` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | +| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | +| `TokenRemovedFromWhitelist` | `(token: address)` | `0xdd2e6d9f52cbe8f695939d018b7d4a216dc613a669876163ac548b916489d917` | +| `TokenWhitelisted` | `(token: address)` | `0x6a65f90b1a644d2faac467a21e07e50e3f8fa5846e26231d30ae79a417d3d262` | ## Configurations -| Event | Arguments | Topic | -| ---------------------------- | ------------------------------------------------------------------------ | -------------------------------------------------------------------- | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `IsValidPlugSet` | `(appGateway: address, chainSlug: uint32, plug: address, isValid: bool)` | `0x61cccc7387868fc741379c7acd9dd346e0ca2e5c067dc5b156fbbc55b1c2fcf5` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `PlugAdded` | `(appGatewayId: bytes32, chainSlug: uint32, plug: address)` | `0x7b3e14230a721c4737d275f9a63b92c44cb657bcfddbe6fe9b4d9cd9bd8d4a95` | -| `SocketSet` | `(chainSlug: uint32, socket: address)` | `0x5b13a5470e66a2ec5e9b32af5f9e23fe304864892918c60fffd22509ca73ac97` | -| `SwitchboardSet` | `(chainSlug: uint32, sbType: bytes32, switchboard: address)` | `0x6273f161f4a795e66ef3585d9b4442ef3796b32337157fdfb420b5281e4cf2e3` | +| Event | Arguments | Topic | +| ----- | --------- | ----- | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `IsValidPlugSet` | `(appGateway: address, chainSlug: uint32, plug: address, isValid: bool)` | `0x61cccc7387868fc741379c7acd9dd346e0ca2e5c067dc5b156fbbc55b1c2fcf5` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `PlugAdded` | `(appGatewayId: bytes32, chainSlug: uint32, plug: address)` | `0x7b3e14230a721c4737d275f9a63b92c44cb657bcfddbe6fe9b4d9cd9bd8d4a95` | +| `SocketSet` | `(chainSlug: uint32, socket: address)` | `0x5b13a5470e66a2ec5e9b32af5f9e23fe304864892918c60fffd22509ca73ac97` | +| `SwitchboardSet` | `(chainSlug: uint32, sbType: bytes32, switchboard: address)` | `0x6273f161f4a795e66ef3585d9b4442ef3796b32337157fdfb420b5281e4cf2e3` | ## PromiseResolver -| Event | Arguments | Topic | -| -------------------- | ------------------------------------------------ | -------------------------------------------------------------------- | -| `MarkedRevert` | `(payloadId: bytes32, isRevertingOnchain: bool)` | `0xcf1fd844cb4d32cbebb5ca6ce4ac834fe98da3ddac44deb77fffd22ad933824c` | -| `PromiseNotResolved` | `(payloadId: bytes32, asyncPromise: address)` | `0xbcf0d0c678940566e9e64f0c871439395bd5fb5c39bca3547b126fe6ee467937` | -| `PromiseResolved` | `(payloadId: bytes32, asyncPromise: address)` | `0x1b1b5810494fb3e17f7c46547e6e67cd6ad3e6001ea6fb7d12ea0241ba13c4ba` | +| Event | Arguments | Topic | +| ----- | --------- | ----- | +| `MarkedRevert` | `(payloadId: bytes32, isRevertingOnchain: bool)` | `0xcf1fd844cb4d32cbebb5ca6ce4ac834fe98da3ddac44deb77fffd22ad933824c` | +| `PromiseNotResolved` | `(payloadId: bytes32, asyncPromise: address)` | `0xbcf0d0c678940566e9e64f0c871439395bd5fb5c39bca3547b126fe6ee467937` | +| `PromiseResolved` | `(payloadId: bytes32, asyncPromise: address)` | `0x1b1b5810494fb3e17f7c46547e6e67cd6ad3e6001ea6fb7d12ea0241ba13c4ba` | ## RequestHandler -| Event | Arguments | Topic | -| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | -| `FeesIncreased` | `(requestCount: uint40, newMaxFees: uint256)` | `0xf258fca4e49b803ee2a4c2e33b6fcf18bc3982df21f111c00677025bf1ccbb6a` | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `RequestCancelled` | `(requestCount: uint40)` | `0xff191657769be72fc08def44c645014c60d18cb24b9ca05c9a33406a28253245` | -| `RequestCompletedWithErrors` | `(requestCount: uint40)` | `0xd8d9915dc14b5a29b66cb263e1ea1e99e60418fc21d97f0fbf09cae1281291e2` | -| `RequestSettled` | `(requestCount: uint40, winner: address)` | `0x1234f98acbe1548b214f4528461a5377f1e2349569c04caa59325e488e7d2aa4` | -| `RequestSubmitted` | `(hasWrite: bool, requestCount: uint40, totalEstimatedWatcherFees: uint256, requestParams: tuple, payloadParamsArray: tuple[])` | `0x762bac43d5d7689b8911c5654a9d5550804373cead33bc98282067e6166e518f` | +| Event | Arguments | Topic | +| ----- | --------- | ----- | +| `FeesIncreased` | `(requestCount: uint40, newMaxFees: uint256)` | `0xf258fca4e49b803ee2a4c2e33b6fcf18bc3982df21f111c00677025bf1ccbb6a` | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `RequestCancelled` | `(requestCount: uint40)` | `0xff191657769be72fc08def44c645014c60d18cb24b9ca05c9a33406a28253245` | +| `RequestCompletedWithErrors` | `(requestCount: uint40)` | `0xd8d9915dc14b5a29b66cb263e1ea1e99e60418fc21d97f0fbf09cae1281291e2` | +| `RequestSettled` | `(requestCount: uint40, winner: address)` | `0x1234f98acbe1548b214f4528461a5377f1e2349569c04caa59325e488e7d2aa4` | +| `RequestSubmitted` | `(hasWrite: bool, requestCount: uint40, totalEstimatedWatcherFees: uint256, requestParams: tuple, payloadParamsArray: tuple[])` | `0x762bac43d5d7689b8911c5654a9d5550804373cead33bc98282067e6166e518f` | ## Watcher -| Event | Arguments | Topic | -| ---------------------------- | ---------------------------------------- | -------------------------------------------------------------------- | -| `AppGatewayCallFailed` | `(triggerId: bytes32)` | `0xcaf8475fdade8465ea31672463949e6cf1797fdcdd11eeddbbaf857e1e5907b7` | -| `CalledAppGateway` | `(triggerId: bytes32)` | `0xf659ffb3875368f54fb4ab8f5412ac4518af79701a48076f7a58d4448e4bdd0b` | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `TriggerFailed` | `(triggerId: bytes32)` | `0x4386783bb0f7cad4ba12f033dbec03dc3441e7757a122f3097a7a4d945c98040` | -| `TriggerFeesSet` | `(triggerFees: uint256)` | `0x7df3967b7c8727af5ac0ee9825d88aafeb899d769bc428b91f8967fa0b623084` | -| `TriggerSucceeded` | `(triggerId: bytes32)` | `0x92d20fbcbf31370b8218e10ed00c5aad0e689022da30a08905ba5ced053219eb` | +| Event | Arguments | Topic | +| ----- | --------- | ----- | +| `AppGatewayCallFailed` | `(triggerId: bytes32)` | `0xcaf8475fdade8465ea31672463949e6cf1797fdcdd11eeddbbaf857e1e5907b7` | +| `CalledAppGateway` | `(triggerId: bytes32)` | `0xf659ffb3875368f54fb4ab8f5412ac4518af79701a48076f7a58d4448e4bdd0b` | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `TriggerFailed` | `(triggerId: bytes32)` | `0x4386783bb0f7cad4ba12f033dbec03dc3441e7757a122f3097a7a4d945c98040` | +| `TriggerFeesSet` | `(triggerFees: uint256)` | `0x7df3967b7c8727af5ac0ee9825d88aafeb899d769bc428b91f8967fa0b623084` | +| `TriggerSucceeded` | `(triggerId: bytes32)` | `0x92d20fbcbf31370b8218e10ed00c5aad0e689022da30a08905ba5ced053219eb` | ## FastSwitchboard -| Event | Arguments | Topic | -| ---------------------------- | ----------------------------------------- | -------------------------------------------------------------------- | -| `Attested` | `(payloadId_: bytes32, watcher: address)` | `0x3d83c7bc55c269e0bc853ddc0d7b9fca30216ecc43779acb4e36b7e0ad1c71e4` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | -| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | +| Event | Arguments | Topic | +| ----- | --------- | ----- | +| `Attested` | `(payloadId_: bytes32, watcher: address)` | `0x3d83c7bc55c269e0bc853ddc0d7b9fca30216ecc43779acb4e36b7e0ad1c71e4` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | +| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | ## ReadPrecompile -| Event | Arguments | Topic | -| --------------- | ---------------------------------------------------------------------- | -------------------------------------------------------------------- | -| `ExpiryTimeSet` | `(expiryTime: uint256)` | `0x07e837e13ad9a34715a6bd45f49bbf12de19f06df79cb0be12b3a7d7f2397fa9` | -| `ReadFeesSet` | `(readFees: uint256)` | `0xc674cb6dde3a59f84dbf226832e606ffc54ac8a169e1568fc834c7813010f926` | +| Event | Arguments | Topic | +| ----- | --------- | ----- | +| `ExpiryTimeSet` | `(expiryTime: uint256)` | `0x07e837e13ad9a34715a6bd45f49bbf12de19f06df79cb0be12b3a7d7f2397fa9` | +| `ReadFeesSet` | `(readFees: uint256)` | `0xc674cb6dde3a59f84dbf226832e606ffc54ac8a169e1568fc834c7813010f926` | | `ReadRequested` | `(transaction: tuple, readAtBlockNumber: uint256, payloadId: bytes32)` | `0x42d9c65d4f6e45462ae6206adb3e388e046b7daa1dc8699d9380cac72ff5db0b` | ## SchedulePrecompile -| Event | Arguments | Topic | -| ------------------------------ | ---------------------------------------------------------------- | -------------------------------------------------------------------- | -| `ExpiryTimeSet` | `(expiryTime_: uint256)` | `0x07e837e13ad9a34715a6bd45f49bbf12de19f06df79cb0be12b3a7d7f2397fa9` | -| `MaxScheduleDelayInSecondsSet` | `(maxScheduleDelayInSeconds_: uint256)` | `0xfd5e4f0e96753ffb08a583390c2f151c51001d8e560625ab93b7fa7b4dac6d75` | -| `ScheduleCallbackFeesSet` | `(scheduleCallbackFees_: uint256)` | `0x82a2f41efc81ce7bfabc0affda7354dae42a3d09bd74a6196e8904b223138a52` | -| `ScheduleFeesPerSecondSet` | `(scheduleFeesPerSecond_: uint256)` | `0x7901a21229f6d2543d8676f53e21214d15f42513e7d46e0dcb510357222bdc7c` | -| `ScheduleRequested` | `(payloadId: bytes32, executeAfter: uint256, deadline: uint256)` | `0xd099d3e3d0f0e2c9c40e0066affeea125aab71d763b7ab0a279ccec3dff70b64` | -| `ScheduleResolved` | `(payloadId: bytes32)` | `0x925dc6c3ebffa07cac89d6e9675f1a5d04e045f2ed9a4fa442665935cb73e26b` | +| Event | Arguments | Topic | +| ----- | --------- | ----- | +| `ExpiryTimeSet` | `(expiryTime_: uint256)` | `0x07e837e13ad9a34715a6bd45f49bbf12de19f06df79cb0be12b3a7d7f2397fa9` | +| `MaxScheduleDelayInSecondsSet` | `(maxScheduleDelayInSeconds_: uint256)` | `0xfd5e4f0e96753ffb08a583390c2f151c51001d8e560625ab93b7fa7b4dac6d75` | +| `ScheduleCallbackFeesSet` | `(scheduleCallbackFees_: uint256)` | `0x82a2f41efc81ce7bfabc0affda7354dae42a3d09bd74a6196e8904b223138a52` | +| `ScheduleFeesPerSecondSet` | `(scheduleFeesPerSecond_: uint256)` | `0x7901a21229f6d2543d8676f53e21214d15f42513e7d46e0dcb510357222bdc7c` | +| `ScheduleRequested` | `(payloadId: bytes32, executeAfter: uint256, deadline: uint256)` | `0xd099d3e3d0f0e2c9c40e0066affeea125aab71d763b7ab0a279ccec3dff70b64` | +| `ScheduleResolved` | `(payloadId: bytes32)` | `0x925dc6c3ebffa07cac89d6e9675f1a5d04e045f2ed9a4fa442665935cb73e26b` | ## WritePrecompile -| Event | Arguments | Topic | -| ------------------------------- | ---------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | -| `ChainMaxMsgValueLimitsUpdated` | `(chainSlug: uint32, maxMsgValueLimit: uint256)` | `0x439087d094fe7dacbba3f0c67032041952d8bd58a891e15af10ced28fed0eb91` | -| `ContractFactoryPlugSet` | `(chainSlug: uint32, contractFactoryPlug: address)` | `0x85bfa413b9e5e225278f51af2ac872988e0a9374263b118d963c50945ea888bb` | -| `ExpiryTimeSet` | `(expiryTime: uint256)` | `0x07e837e13ad9a34715a6bd45f49bbf12de19f06df79cb0be12b3a7d7f2397fa9` | -| `FeesSet` | `(writeFees: uint256)` | `0x3346af6da1932164d501f2ec28f8c5d686db5828a36b77f2da4332d89184fe7b` | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `WriteProofRequested` | `(transmitter: address, digest: bytes32, prevBatchDigestHash: bytes32, deadline: uint256, payloadParams: tuple)` | `0x3247df5b4e8df4ac60c2c1f803b404ee16bc9d84a6b7649865464a8a397b9acb` | -| `WriteProofUploaded` | `(payloadId: bytes32, proof: bytes)` | `0xd8fe3a99a88c9630360418877afdf14e3e79f0f25fee162aeb230633ea740156` | +| Event | Arguments | Topic | +| ----- | --------- | ----- | +| `ChainMaxMsgValueLimitsUpdated` | `(chainSlug: uint32, maxMsgValueLimit: uint256)` | `0x439087d094fe7dacbba3f0c67032041952d8bd58a891e15af10ced28fed0eb91` | +| `ContractFactoryPlugSet` | `(chainSlug: uint32, contractFactoryPlug: address)` | `0x85bfa413b9e5e225278f51af2ac872988e0a9374263b118d963c50945ea888bb` | +| `ExpiryTimeSet` | `(expiryTime: uint256)` | `0x07e837e13ad9a34715a6bd45f49bbf12de19f06df79cb0be12b3a7d7f2397fa9` | +| `FeesSet` | `(writeFees: uint256)` | `0x3346af6da1932164d501f2ec28f8c5d686db5828a36b77f2da4332d89184fe7b` | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `WriteProofRequested` | `(transmitter: address, digest: bytes32, prevBatchDigestHash: bytes32, deadline: uint256, payloadParams: tuple)` | `0x3247df5b4e8df4ac60c2c1f803b404ee16bc9d84a6b7649865464a8a397b9acb` | +| `WriteProofUploaded` | `(payloadId: bytes32, proof: bytes)` | `0xd8fe3a99a88c9630360418877afdf14e3e79f0f25fee162aeb230633ea740156` | + diff --git a/FunctionSignatures.md b/FunctionSignatures.md index d2412f5f..7837a5d6 100644 --- a/FunctionSignatures.md +++ b/FunctionSignatures.md @@ -2,557 +2,559 @@ ## AuctionManager -| Function | Signature | -| ---------------------------- | ------------ | -| `addressResolver__` | `0x6a750469` | -| `asyncDeployer__` | `0x2a39e801` | -| `auctionEndDelaySeconds` | `0x9087dfdb` | -| `auctionManager` | `0xb0192f9a` | -| `auctionStatus` | `0xd7d5fbf6` | -| `bid` | `0xfcdf49c2` | -| `bidTimeout` | `0x94090d0b` | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `consumeFrom` | `0x40dd78be` | -| `creationCodeWithArgs` | `0xc126dcc4` | -| `deployForwarder__` | `0xd4e3b034` | -| `endAuction` | `0x1212e653` | -| `evmxSlug` | `0x8bae77c2` | -| `expireBid` | `0x1dd5022c` | -| `feesManager__` | `0x70568b58` | -| `forwarderAddresses` | `0x5390fdcb` | -| `getOnChainAddress` | `0xb6abffd7` | -| `getOverrideParams` | `0x54f0a866` | -| `grantRole` | `0x2f2ff15d` | -| `handleRevert` | `0x44792f25` | -| `hasRole` | `0x91d14854` | -| `initialize` | `0x86891c9b` | -| `initializeOnChain` | `0x86f01739` | -| `isAsyncModifierSet` | `0xb69e0c4a` | -| `isValidPromise` | `0xb690b962` | -| `maxFees` | `0xe83e34b1` | -| `maxReAuctionCount` | `0xc367b376` | -| `onCompleteData` | `0xb52fa926` | -| `onRequestComplete` | `0x5ed1f959` | -| `overrideParams` | `0xec5490fe` | -| `owner` | `0x8da5cb5b` | +| Function | Signature | +| -------- | --------- | +| `addressResolver__` | `0x6a750469` | +| `asyncDeployer__` | `0x2a39e801` | +| `auctionEndDelaySeconds` | `0x9087dfdb` | +| `auctionManager` | `0xb0192f9a` | +| `auctionStatus` | `0xd7d5fbf6` | +| `bid` | `0xfcdf49c2` | +| `bidTimeout` | `0x94090d0b` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `consumeFrom` | `0x40dd78be` | +| `creationCodeWithArgs` | `0xc126dcc4` | +| `deployForwarder__` | `0xd4e3b034` | +| `endAuction` | `0x1212e653` | +| `evmxSlug` | `0x8bae77c2` | +| `expireBid` | `0x1dd5022c` | +| `feesManager__` | `0x70568b58` | +| `forwarderAddresses` | `0x5390fdcb` | +| `getOnChainAddress` | `0xb6abffd7` | +| `getOverrideParams` | `0x54f0a866` | +| `grantRole` | `0x2f2ff15d` | +| `handleRevert` | `0x44792f25` | +| `hasRole` | `0x91d14854` | +| `initialize` | `0x86891c9b` | +| `initializeOnChain` | `0x86f01739` | +| `isAsyncModifierSet` | `0xb69e0c4a` | +| `isValidPromise` | `0xb690b962` | +| `maxFees` | `0xe83e34b1` | +| `maxReAuctionCount` | `0xc367b376` | +| `onCompleteData` | `0xb52fa926` | +| `onRequestComplete` | `0x5ed1f959` | +| `overrideParams` | `0xec5490fe` | +| `owner` | `0x8da5cb5b` | | `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `reAuctionCount` | `0x9b4b22d3` | -| `renounceOwnership` | `0x715018a6` | -| `requestOwnershipHandover` | `0x25692962` | -| `rescueFunds` | `0x6ccae054` | -| `revokeRole` | `0xd547741f` | -| `sbType` | `0x745de344` | -| `setAddress` | `0x85bf312c` | -| `setAuctionEndDelaySeconds` | `0x88606b1a` | -| `setMaxReAuctionCount` | `0x64c71403` | -| `transferOwnership` | `0xf2fde38b` | -| `watcher__` | `0x300bb063` | -| `winningBids` | `0x9133f232` | +| `reAuctionCount` | `0x9b4b22d3` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | +| `revokeRole` | `0xd547741f` | +| `sbType` | `0x745de344` | +| `setAddress` | `0x85bf312c` | +| `setAuctionEndDelaySeconds` | `0x88606b1a` | +| `setMaxReAuctionCount` | `0x64c71403` | +| `transferOwnership` | `0xf2fde38b` | +| `watcher__` | `0x300bb063` | +| `winningBids` | `0x9133f232` | ## Socket -| Function | Signature | -| ---------------------------- | ------------ | -| `OFF_CHAIN_CALLER` | `0xcb2cb4f6` | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `chainSlug` | `0xb349ba65` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `connect` | `0xb3bde1aa` | -| `disableSwitchboard` | `0xe545b261` | -| `enableSwitchboard` | `0xf97a498a` | -| `execute` | `0xafa8b480` | -| `getPlugConfig` | `0xf9778ee0` | -| `grantRole` | `0x2f2ff15d` | -| `hasRole` | `0x91d14854` | -| `isValidSwitchboard` | `0xb2d67675` | -| `maxCopyBytes` | `0x212249d4` | -| `owner` | `0x8da5cb5b` | +| Function | Signature | +| -------- | --------- | +| `OFF_CHAIN_CALLER` | `0xcb2cb4f6` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `chainSlug` | `0xb349ba65` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `connect` | `0xb3bde1aa` | +| `disableSwitchboard` | `0xe545b261` | +| `enableSwitchboard` | `0xf97a498a` | +| `execute` | `0xafa8b480` | +| `getPlugConfig` | `0xf9778ee0` | +| `grantRole` | `0x2f2ff15d` | +| `hasRole` | `0x91d14854` | +| `isValidSwitchboard` | `0xb2d67675` | +| `maxCopyBytes` | `0x212249d4` | +| `owner` | `0x8da5cb5b` | | `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `payloadExecuted` | `0x3eaeac3d` | -| `payloadIdToDigest` | `0x7c8552b2` | -| `registerSwitchboard` | `0x74f5b1fc` | -| `renounceOwnership` | `0x715018a6` | -| `requestOwnershipHandover` | `0x25692962` | -| `rescueFunds` | `0x6ccae054` | -| `revokeRole` | `0xd547741f` | -| `setMaxCopyBytes` | `0x4fc7d6e9` | -| `setSocketFeeManager` | `0x25bd97e5` | -| `simulate` | `0x91bf8275` | -| `socketFeeManager` | `0xde5b8838` | -| `transferOwnership` | `0xf2fde38b` | -| `triggerCounter` | `0x8b0021de` | -| `version` | `0x54fd4d50` | +| `payloadExecuted` | `0x3eaeac3d` | +| `payloadIdToDigest` | `0x7c8552b2` | +| `registerSwitchboard` | `0x74f5b1fc` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | +| `revokeRole` | `0xd547741f` | +| `setMaxCopyBytes` | `0x4fc7d6e9` | +| `setSocketFeeManager` | `0x25bd97e5` | +| `simulate` | `0x91bf8275` | +| `socketFeeManager` | `0xde5b8838` | +| `transferOwnership` | `0xf2fde38b` | +| `triggerCounter` | `0x8b0021de` | +| `version` | `0x54fd4d50` | ## SocketBatcher -| Function | Signature | -| ---------------------------- | ------------ | -| `attestAndExecute` | `0x66c7748a` | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `owner` | `0x8da5cb5b` | +| Function | Signature | +| -------- | --------- | +| `attestAndExecute` | `0x66c7748a` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `owner` | `0x8da5cb5b` | | `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `renounceOwnership` | `0x715018a6` | -| `requestOwnershipHandover` | `0x25692962` | -| `rescueFunds` | `0x6ccae054` | -| `socket__` | `0xc6a261d2` | -| `transferOwnership` | `0xf2fde38b` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | +| `socket__` | `0xc6a261d2` | +| `transferOwnership` | `0xf2fde38b` | ## SocketFeeManager -| Function | Signature | -| ---------------------------- | ------------ | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `getMinSocketFees` | `0xd383b688` | -| `grantRole` | `0x2f2ff15d` | -| `hasRole` | `0x91d14854` | -| `owner` | `0x8da5cb5b` | +| Function | Signature | +| -------- | --------- | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `getMinSocketFees` | `0xd383b688` | +| `grantRole` | `0x2f2ff15d` | +| `hasRole` | `0x91d14854` | +| `owner` | `0x8da5cb5b` | | `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `payAndCheckFees` | `0xd9d29ae3` | -| `renounceOwnership` | `0x715018a6` | -| `requestOwnershipHandover` | `0x25692962` | -| `rescueFunds` | `0x6ccae054` | -| `revokeRole` | `0xd547741f` | -| `setSocketFees` | `0x47a406f6` | -| `socketFees` | `0xab1b33a8` | -| `transferOwnership` | `0xf2fde38b` | +| `payAndCheckFees` | `0xd9d29ae3` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | +| `revokeRole` | `0xd547741f` | +| `setSocketFees` | `0x47a406f6` | +| `socketFees` | `0xab1b33a8` | +| `transferOwnership` | `0xf2fde38b` | ## FeesManager -| Function | Signature | -| -------------------------------- | ------------ | -| `addressResolver__` | `0x6a750469` | +| Function | Signature | +| -------- | --------- | +| `addressResolver__` | `0x6a750469` | | `approveAppGatewayWithSignature` | `0x94b649ec` | -| `approveAppGateways` | `0x86d23ab2` | -| `asyncDeployer__` | `0x2a39e801` | -| `blockCredits` | `0x9e434307` | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `deployForwarder__` | `0xd4e3b034` | -| `deposit` | `0x5671d329` | -| `evmxSlug` | `0x8bae77c2` | -| `feesManager__` | `0x70568b58` | -| `feesPlugs` | `0x23f5ee8a` | -| `feesPool` | `0x6b259690` | -| `getAvailableCredits` | `0xb065a8e5` | -| `initialize` | `0xbf2c8539` | -| `isApproved` | `0xa389783e` | -| `isCreditSpendable` | `0x4f8990fd` | -| `isNonceUsed` | `0xcab7e8eb` | -| `onRequestComplete` | `0x5ed1f959` | -| `owner` | `0x8da5cb5b` | -| `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `renounceOwnership` | `0x715018a6` | -| `requestBlockedCredits` | `0xb62d25ac` | -| `requestOwnershipHandover` | `0x25692962` | -| `rescueFunds` | `0x6ccae054` | -| `sbType` | `0x745de344` | -| `setFeesPlug` | `0xeab75f36` | -| `setFeesPool` | `0xd6684588` | -| `tokenOnChainBalances` | `0x3b27866d` | -| `transferCredits` | `0xf1686c89` | -| `transferOwnership` | `0xf2fde38b` | -| `unblockAndAssignCredits` | `0x01958181` | -| `unblockCredits` | `0xa0b32314` | -| `unwrap` | `0x7647691d` | -| `userCredits` | `0x20babb92` | -| `watcher__` | `0x300bb063` | -| `withdrawCredits` | `0xcfc6dbd9` | -| `wrap` | `0x023276f0` | +| `approveAppGateways` | `0x86d23ab2` | +| `asyncDeployer__` | `0x2a39e801` | +| `blockCredits` | `0x9e434307` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `deployForwarder__` | `0xd4e3b034` | +| `deposit` | `0x5671d329` | +| `evmxSlug` | `0x8bae77c2` | +| `feesManager__` | `0x70568b58` | +| `feesPlugs` | `0x23f5ee8a` | +| `feesPool` | `0x6b259690` | +| `getAvailableCredits` | `0xb065a8e5` | +| `initialize` | `0xbf2c8539` | +| `isApproved` | `0xa389783e` | +| `isCreditSpendable` | `0x4f8990fd` | +| `isNonceUsed` | `0xcab7e8eb` | +| `onRequestComplete` | `0x5ed1f959` | +| `owner` | `0x8da5cb5b` | +| `ownershipHandoverExpiresAt` | `0xfee81cf4` | +| `renounceOwnership` | `0x715018a6` | +| `requestBlockedCredits` | `0xb62d25ac` | +| `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | +| `sbType` | `0x745de344` | +| `setFeesPlug` | `0xeab75f36` | +| `setFeesPool` | `0xd6684588` | +| `tokenOnChainBalances` | `0x3b27866d` | +| `transferCredits` | `0xf1686c89` | +| `transferOwnership` | `0xf2fde38b` | +| `unblockAndAssignCredits` | `0x01958181` | +| `unblockCredits` | `0xa0b32314` | +| `unwrap` | `0x7647691d` | +| `userCredits` | `0x20babb92` | +| `watcher__` | `0x300bb063` | +| `withdrawCredits` | `0xcfc6dbd9` | +| `wrap` | `0x023276f0` | ## FeesPool -| Function | Signature | -| ---------------------------- | ------------ | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `getBalance` | `0x12065fe0` | -| `grantRole` | `0x2f2ff15d` | -| `hasRole` | `0x91d14854` | -| `owner` | `0x8da5cb5b` | +| Function | Signature | +| -------- | --------- | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `getBalance` | `0x12065fe0` | +| `grantRole` | `0x2f2ff15d` | +| `hasRole` | `0x91d14854` | +| `owner` | `0x8da5cb5b` | | `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `renounceOwnership` | `0x715018a6` | -| `requestOwnershipHandover` | `0x25692962` | -| `revokeRole` | `0xd547741f` | -| `transferOwnership` | `0xf2fde38b` | -| `withdraw` | `0xf3fef3a3` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `revokeRole` | `0xd547741f` | +| `transferOwnership` | `0xf2fde38b` | +| `withdraw` | `0xf3fef3a3` | ## AddressResolver -| Function | Signature | -| ---------------------------- | ------------ | -| `asyncDeployer__` | `0x2a39e801` | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `contractAddresses` | `0xf689e892` | -| `defaultAuctionManager` | `0x8f27cdc6` | -| `deployForwarder__` | `0xd4e3b034` | -| `feesManager__` | `0x70568b58` | -| `initialize` | `0xc4d66de8` | -| `owner` | `0x8da5cb5b` | +| Function | Signature | +| -------- | --------- | +| `asyncDeployer__` | `0x2a39e801` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `contractAddresses` | `0xf689e892` | +| `defaultAuctionManager` | `0x8f27cdc6` | +| `deployForwarder__` | `0xd4e3b034` | +| `feesManager__` | `0x70568b58` | +| `initialize` | `0xc4d66de8` | +| `owner` | `0x8da5cb5b` | | `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `renounceOwnership` | `0x715018a6` | -| `requestOwnershipHandover` | `0x25692962` | -| `rescueFunds` | `0x6ccae054` | -| `setAsyncDeployer` | `0xcb0ffff8` | -| `setContractAddress` | `0xe001f841` | -| `setDefaultAuctionManager` | `0xede8b4b5` | -| `setDeployForwarder` | `0xaeaee8a6` | -| `setFeesManager` | `0x1c89382a` | -| `setWatcher` | `0x24f48bc5` | -| `transferOwnership` | `0xf2fde38b` | -| `watcher__` | `0x300bb063` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | +| `setAsyncDeployer` | `0xcb0ffff8` | +| `setContractAddress` | `0xe001f841` | +| `setDefaultAuctionManager` | `0xede8b4b5` | +| `setDeployForwarder` | `0xaeaee8a6` | +| `setFeesManager` | `0x1c89382a` | +| `setWatcher` | `0x24f48bc5` | +| `transferOwnership` | `0xf2fde38b` | +| `watcher__` | `0x300bb063` | ## AsyncDeployer -| Function | Signature | -| ------------------------------- | ------------ | -| `addressResolver__` | `0x6a750469` | -| `asyncDeployer__` | `0x2a39e801` | -| `asyncPromiseBeacon` | `0xc0fbc0ef` | -| `asyncPromiseCounter` | `0x97cdbf4c` | -| `asyncPromiseImplementation` | `0x59531b8d` | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `deployAsyncPromiseContract` | `0x9851be0b` | -| `deployForwarder__` | `0xd4e3b034` | -| `feesManager__` | `0x70568b58` | -| `forwarderBeacon` | `0x945709ae` | -| `forwarderImplementation` | `0xe38d60a1` | -| `getAsyncPromiseAddress` | `0x104f39b4` | -| `getForwarderAddress` | `0x48c0b3e0` | -| `getOrDeployForwarderContract` | `0x0aa178de` | -| `initialize` | `0x485cc955` | -| `owner` | `0x8da5cb5b` | -| `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `renounceOwnership` | `0x715018a6` | -| `requestOwnershipHandover` | `0x25692962` | -| `rescueFunds` | `0x6ccae054` | +| Function | Signature | +| -------- | --------- | +| `addressResolver__` | `0x6a750469` | +| `asyncDeployer__` | `0x2a39e801` | +| `asyncPromiseBeacon` | `0xc0fbc0ef` | +| `asyncPromiseCounter` | `0x97cdbf4c` | +| `asyncPromiseImplementation` | `0x59531b8d` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `deployAsyncPromiseContract` | `0x9851be0b` | +| `deployForwarder__` | `0xd4e3b034` | +| `feesManager__` | `0x70568b58` | +| `forwarderBeacon` | `0x945709ae` | +| `forwarderImplementation` | `0xe38d60a1` | +| `getAsyncPromiseAddress` | `0x104f39b4` | +| `getForwarderAddress` | `0x48c0b3e0` | +| `getOrDeployForwarderContract` | `0x0aa178de` | +| `initialize` | `0x485cc955` | +| `owner` | `0x8da5cb5b` | +| `ownershipHandoverExpiresAt` | `0xfee81cf4` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | | `setAsyncPromiseImplementation` | `0xeb506eab` | -| `setForwarderImplementation` | `0x83b1e974` | -| `transferOwnership` | `0xf2fde38b` | -| `watcher__` | `0x300bb063` | +| `setForwarderImplementation` | `0x83b1e974` | +| `transferOwnership` | `0xf2fde38b` | +| `watcher__` | `0x300bb063` | ## AsyncPromise -| Function | Signature | -| ------------------- | ------------ | +| Function | Signature | +| -------- | --------- | | `addressResolver__` | `0x6a750469` | -| `asyncDeployer__` | `0x2a39e801` | -| `callbackData` | `0xef44c272` | -| `callbackSelector` | `0x2764f92f` | +| `asyncDeployer__` | `0x2a39e801` | +| `callbackData` | `0xef44c272` | +| `callbackSelector` | `0x2764f92f` | | `deployForwarder__` | `0xd4e3b034` | -| `exceededMaxCopy` | `0xaf598c7c` | -| `feesManager__` | `0x70568b58` | -| `initialize` | `0x0ece6089` | -| `localInvoker` | `0x45eb87f4` | +| `exceededMaxCopy` | `0xaf598c7c` | +| `feesManager__` | `0x70568b58` | +| `initialize` | `0x0ece6089` | +| `localInvoker` | `0x45eb87f4` | | `markOnchainRevert` | `0xd0e7af1b` | -| `markResolved` | `0x822d5d1f` | -| `requestCount` | `0x5badbe4c` | -| `rescueFunds` | `0x6ccae054` | -| `returnData` | `0xebddbaf6` | -| `state` | `0xc19d93fb` | -| `then` | `0x0bf2ba15` | -| `watcher__` | `0x300bb063` | +| `markResolved` | `0x822d5d1f` | +| `requestCount` | `0x5badbe4c` | +| `rescueFunds` | `0x6ccae054` | +| `returnData` | `0xebddbaf6` | +| `state` | `0xc19d93fb` | +| `then` | `0x0bf2ba15` | +| `watcher__` | `0x300bb063` | ## DeployForwarder -| Function | Signature | -| ---------------------------- | ------------ | -| `addressResolver__` | `0x6a750469` | -| `asyncDeployer__` | `0x2a39e801` | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `deploy` | `0x940f11af` | -| `deployForwarder__` | `0xd4e3b034` | -| `deployerSwitchboardType` | `0xaa381f9a` | -| `feesManager__` | `0x70568b58` | -| `initialize` | `0x6133f985` | -| `owner` | `0x8da5cb5b` | +| Function | Signature | +| -------- | --------- | +| `addressResolver__` | `0x6a750469` | +| `asyncDeployer__` | `0x2a39e801` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `deploy` | `0x940f11af` | +| `deployForwarder__` | `0xd4e3b034` | +| `deployerSwitchboardType` | `0xaa381f9a` | +| `feesManager__` | `0x70568b58` | +| `initialize` | `0x6133f985` | +| `owner` | `0x8da5cb5b` | | `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `renounceOwnership` | `0x715018a6` | -| `requestOwnershipHandover` | `0x25692962` | -| `rescueFunds` | `0x6ccae054` | -| `saltCounter` | `0xa04c6809` | -| `transferOwnership` | `0xf2fde38b` | -| `watcher__` | `0x300bb063` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | +| `saltCounter` | `0xa04c6809` | +| `transferOwnership` | `0xf2fde38b` | +| `watcher__` | `0x300bb063` | ## Forwarder -| Function | Signature | -| ------------------- | ------------ | +| Function | Signature | +| -------- | --------- | | `addressResolver__` | `0x6a750469` | -| `asyncDeployer__` | `0x2a39e801` | -| `chainSlug` | `0xb349ba65` | +| `asyncDeployer__` | `0x2a39e801` | +| `chainSlug` | `0xb349ba65` | | `deployForwarder__` | `0xd4e3b034` | -| `feesManager__` | `0x70568b58` | -| `getChainSlug` | `0x0b8c6568` | +| `feesManager__` | `0x70568b58` | +| `getChainSlug` | `0x0b8c6568` | | `getOnChainAddress` | `0x9da48789` | -| `initialize` | `0x647c576c` | -| `onChainAddress` | `0x8bd0b363` | -| `rescueFunds` | `0x6ccae054` | -| `watcher__` | `0x300bb063` | +| `initialize` | `0x647c576c` | +| `onChainAddress` | `0x8bd0b363` | +| `rescueFunds` | `0x6ccae054` | +| `watcher__` | `0x300bb063` | ## ProxyFactory -| Function | Signature | -| ----------------------------- | ------------ | -| `adminOf` | `0x2abbef15` | -| `changeAdmin` | `0x1acfd02a` | -| `deploy` | `0x545e7c61` | -| `deployAndCall` | `0x4314f120` | -| `deployDeterministic` | `0x3729f922` | -| `deployDeterministicAndCall` | `0xa97b90d5` | -| `initCodeHash` | `0xdb4c545e` | +| Function | Signature | +| -------- | --------- | +| `adminOf` | `0x2abbef15` | +| `changeAdmin` | `0x1acfd02a` | +| `deploy` | `0x545e7c61` | +| `deployAndCall` | `0x4314f120` | +| `deployDeterministic` | `0x3729f922` | +| `deployDeterministicAndCall` | `0xa97b90d5` | +| `initCodeHash` | `0xdb4c545e` | | `predictDeterministicAddress` | `0x5414dff0` | -| `upgrade` | `0x99a88ec4` | -| `upgradeAndCall` | `0x9623609d` | +| `upgrade` | `0x99a88ec4` | +| `upgradeAndCall` | `0x9623609d` | ## TestUSDC -| Function | Signature | -| ------------------ | ------------ | +| Function | Signature | +| -------- | --------- | | `DOMAIN_SEPARATOR` | `0x3644e515` | -| `allowance` | `0xdd62ed3e` | -| `approve` | `0x095ea7b3` | -| `balanceOf` | `0x70a08231` | -| `decimals` | `0x313ce567` | -| `mint` | `0x40c10f19` | -| `name` | `0x06fdde03` | -| `nonces` | `0x7ecebe00` | -| `owner` | `0x8da5cb5b` | -| `permit` | `0xd505accf` | -| `symbol` | `0x95d89b41` | -| `totalSupply` | `0x18160ddd` | -| `transfer` | `0xa9059cbb` | -| `transferFrom` | `0x23b872dd` | +| `allowance` | `0xdd62ed3e` | +| `approve` | `0x095ea7b3` | +| `balanceOf` | `0x70a08231` | +| `decimals` | `0x313ce567` | +| `mint` | `0x40c10f19` | +| `name` | `0x06fdde03` | +| `nonces` | `0x7ecebe00` | +| `owner` | `0x8da5cb5b` | +| `permit` | `0xd505accf` | +| `symbol` | `0x95d89b41` | +| `totalSupply` | `0x18160ddd` | +| `transfer` | `0xa9059cbb` | +| `transferFrom` | `0x23b872dd` | ## ContractFactoryPlug -| Function | Signature | -| ---------------------------- | ------------ | -| `appGatewayId` | `0x1c335f49` | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `connectSocket` | `0x258d19c8` | -| `deployContract` | `0xa0695389` | -| `getAddress` | `0x94ca2cb5` | -| `grantRole` | `0x2f2ff15d` | -| `hasRole` | `0x91d14854` | -| `initSocket` | `0xa07d8545` | -| `isSocketInitialized` | `0x9a7d9a9b` | -| `overrides` | `0x4a85f041` | -| `owner` | `0x8da5cb5b` | +| Function | Signature | +| -------- | --------- | +| `appGatewayId` | `0x1c335f49` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `connectSocket` | `0x258d19c8` | +| `deployContract` | `0xa0695389` | +| `getAddress` | `0x94ca2cb5` | +| `grantRole` | `0x2f2ff15d` | +| `hasRole` | `0x91d14854` | +| `initSocket` | `0xa07d8545` | +| `isSocketInitialized` | `0x9a7d9a9b` | +| `overrides` | `0x4a85f041` | +| `owner` | `0x8da5cb5b` | | `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `renounceOwnership` | `0x715018a6` | -| `requestOwnershipHandover` | `0x25692962` | -| `rescueFunds` | `0x6ccae054` | -| `revokeRole` | `0xd547741f` | -| `socket__` | `0xc6a261d2` | -| `transferOwnership` | `0xf2fde38b` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | +| `revokeRole` | `0xd547741f` | +| `socket__` | `0xc6a261d2` | +| `transferOwnership` | `0xf2fde38b` | ## Configurations -| Function | Signature | -| ---------------------------- | ------------ | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `getPlugConfigs` | `0x8a028c38` | -| `initialize` | `0x485cc955` | -| `isValidPlug` | `0xec8aef74` | -| `owner` | `0x8da5cb5b` | +| Function | Signature | +| -------- | --------- | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `getPlugConfigs` | `0x8a028c38` | +| `initialize` | `0x485cc955` | +| `isValidPlug` | `0xec8aef74` | +| `owner` | `0x8da5cb5b` | | `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `renounceOwnership` | `0x715018a6` | -| `requestOwnershipHandover` | `0x25692962` | -| `rescueFunds` | `0x6ccae054` | -| `setAppGatewayConfigs` | `0xd137fcbb` | -| `setIsValidPlug` | `0xf41332b0` | -| `setSocket` | `0x075c40be` | -| `setSwitchboard` | `0x61706f1e` | -| `sockets` | `0xb44a23ab` | -| `switchboards` | `0xaa539546` | -| `transferOwnership` | `0xf2fde38b` | -| `verifyConnections` | `0xa53b6fad` | -| `watcher__` | `0x300bb063` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | +| `setAppGatewayConfigs` | `0xd137fcbb` | +| `setIsValidPlug` | `0xf41332b0` | +| `setSocket` | `0x075c40be` | +| `setSwitchboard` | `0x61706f1e` | +| `sockets` | `0xb44a23ab` | +| `switchboards` | `0xaa539546` | +| `transferOwnership` | `0xf2fde38b` | +| `verifyConnections` | `0xa53b6fad` | +| `watcher__` | `0x300bb063` | ## PromiseResolver -| Function | Signature | -| ----------------- | ------------ | -| `markRevert` | `0x56501015` | -| `rescueFunds` | `0x6ccae054` | +| Function | Signature | +| -------- | --------- | +| `markRevert` | `0x56501015` | +| `rescueFunds` | `0x6ccae054` | | `resolvePromises` | `0xbf8484b8` | -| `watcher__` | `0x300bb063` | +| `watcher__` | `0x300bb063` | ## RequestHandler -| Function | Signature | -| ------------------------------ | ------------ | -| `addressResolver__` | `0x6a750469` | -| `assignTransmitter` | `0xae5e9c48` | -| `asyncDeployer__` | `0x2a39e801` | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `cancelRequest` | `0x3b5fd6fb` | -| `cancelRequestForReverts` | `0x82970278` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `deployForwarder__` | `0xd4e3b034` | -| `feesManager__` | `0x70568b58` | -| `getBatchPayloadIds` | `0xfd83cd1f` | -| `getPayload` | `0xb48fd0fe` | -| `getPrecompileFees` | `0xabac263c` | -| `getRequest` | `0xcf39abf6` | -| `getRequestBatchIds` | `0xe138fadb` | -| `handleRevert` | `0xcc88d3f9` | -| `increaseFees` | `0x10205541` | -| `initialize` | `0x485cc955` | -| `nextBatchCount` | `0x333a3963` | -| `nextRequestCount` | `0xfef72893` | -| `owner` | `0x8da5cb5b` | -| `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `payloadCounter` | `0x550ce1d5` | -| `precompiles` | `0x9932450b` | -| `renounceOwnership` | `0x715018a6` | -| `requestOwnershipHandover` | `0x25692962` | -| `rescueFunds` | `0x6ccae054` | -| `setPrecompile` | `0x122e0042` | -| `submitRequest` | `0xbb299a2c` | -| `transferOwnership` | `0xf2fde38b` | +| Function | Signature | +| -------- | --------- | +| `addressResolver__` | `0x6a750469` | +| `assignTransmitter` | `0xae5e9c48` | +| `asyncDeployer__` | `0x2a39e801` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `cancelRequest` | `0x3b5fd6fb` | +| `cancelRequestForReverts` | `0x82970278` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `deployForwarder__` | `0xd4e3b034` | +| `feesManager__` | `0x70568b58` | +| `getBatchPayloadIds` | `0xfd83cd1f` | +| `getPayload` | `0xb48fd0fe` | +| `getPrecompileFees` | `0xabac263c` | +| `getRequest` | `0xcf39abf6` | +| `getRequestBatchIds` | `0xe138fadb` | +| `handleRevert` | `0xcc88d3f9` | +| `increaseFees` | `0x10205541` | +| `initialize` | `0x485cc955` | +| `nextBatchCount` | `0x333a3963` | +| `nextRequestCount` | `0xfef72893` | +| `owner` | `0x8da5cb5b` | +| `ownershipHandoverExpiresAt` | `0xfee81cf4` | +| `payloadCounter` | `0x550ce1d5` | +| `precompiles` | `0x9932450b` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | +| `setPrecompile` | `0x122e0042` | +| `setRequestPayloadCountLimit` | `0x8526582b` | +| `submitRequest` | `0xbb299a2c` | +| `transferOwnership` | `0xf2fde38b` | | `updateRequestAndProcessBatch` | `0x46464471` | -| `watcher__` | `0x300bb063` | +| `watcher__` | `0x300bb063` | ## Watcher -| Function | Signature | -| ---------------------------- | ------------ | -| `addressResolver__` | `0x6a750469` | -| `appGatewayTemp` | `0x1394c029` | -| `asyncDeployer__` | `0x2a39e801` | -| `callAppGateways` | `0x0050bef1` | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `cancelRequest` | `0x50ad0779` | -| `clearQueue` | `0xf22cb874` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `configurations__` | `0x52a3bbeb` | -| `deployForwarder__` | `0xd4e3b034` | -| `evmxSlug` | `0x8bae77c2` | -| `feesManager__` | `0x70568b58` | -| `getCurrentRequestCount` | `0x5715abbb` | -| `getPayloadParams` | `0xae5eeb77` | -| `getPrecompileFees` | `0xabac263c` | -| `getRequestParams` | `0x71263d0d` | -| `increaseFees` | `0xe9b304da` | -| `initialize` | `0xaaf7fc1a` | -| `isAppGatewayCalled` | `0xa79da6c7` | -| `isNonceUsed` | `0x5d00bb12` | -| `isWatcher` | `0x84785ecd` | -| `latestAsyncPromise` | `0xb8a8ba52` | -| `owner` | `0x8da5cb5b` | +| Function | Signature | +| -------- | --------- | +| `addressResolver__` | `0x6a750469` | +| `appGatewayTemp` | `0x1394c029` | +| `asyncDeployer__` | `0x2a39e801` | +| `callAppGateways` | `0x0050bef1` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `cancelRequest` | `0x50ad0779` | +| `clearQueue` | `0xf22cb874` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `configurations__` | `0x52a3bbeb` | +| `deployForwarder__` | `0xd4e3b034` | +| `evmxSlug` | `0x8bae77c2` | +| `feesManager__` | `0x70568b58` | +| `getCurrentRequestCount` | `0x5715abbb` | +| `getPayloadParams` | `0xae5eeb77` | +| `getPrecompileFees` | `0xabac263c` | +| `getRequestParams` | `0x71263d0d` | +| `increaseFees` | `0xe9b304da` | +| `initialize` | `0xaaf7fc1a` | +| `isAppGatewayCalled` | `0xa79da6c7` | +| `isNonceUsed` | `0x5d00bb12` | +| `isWatcher` | `0x84785ecd` | +| `latestAsyncPromise` | `0xb8a8ba52` | +| `owner` | `0x8da5cb5b` | | `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `payloadQueue` | `0x74f00ffb` | -| `promiseResolver__` | `0xdee152be` | -| `queue` | `0xf03ca7f7` | -| `queueAndSubmit` | `0xf0fb9665` | -| `renounceOwnership` | `0x715018a6` | -| `requestHandler__` | `0x55184561` | -| `requestOwnershipHandover` | `0x25692962` | -| `rescueFunds` | `0xa58c6fc5` | -| `setCoreContracts` | `0xefa891c4` | -| `setIsValidPlug` | `0x7fc82ff6` | -| `setTriggerFees` | `0xaeb30511` | -| `submitRequest` | `0x4890b5ef` | -| `transferOwnership` | `0xf2fde38b` | -| `triggerFees` | `0x73f76aec` | -| `triggerFromChainSlug` | `0xd12b4f12` | -| `triggerFromPlug` | `0x3b847d12` | -| `watcherMultiCall` | `0x8021e82b` | -| `watcher__` | `0x300bb063` | +| `payloadQueue` | `0x74f00ffb` | +| `promiseResolver__` | `0xdee152be` | +| `queue` | `0xf03ca7f7` | +| `queueAndSubmit` | `0xf0fb9665` | +| `renounceOwnership` | `0x715018a6` | +| `requestHandler__` | `0x55184561` | +| `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0xa58c6fc5` | +| `setCoreContracts` | `0xefa891c4` | +| `setIsValidPlug` | `0x7fc82ff6` | +| `setTriggerFees` | `0xaeb30511` | +| `submitRequest` | `0x4890b5ef` | +| `transferOwnership` | `0xf2fde38b` | +| `triggerFees` | `0x73f76aec` | +| `triggerFromChainSlug` | `0xd12b4f12` | +| `triggerFromPlug` | `0x3b847d12` | +| `watcherMultiCall` | `0x8021e82b` | +| `watcher__` | `0x300bb063` | ## FastSwitchboard -| Function | Signature | -| ---------------------------- | ------------ | -| `allowPayload` | `0x31c23f66` | -| `attest` | `0x63671b60` | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `chainSlug` | `0xb349ba65` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `grantRole` | `0x2f2ff15d` | -| `hasRole` | `0x91d14854` | -| `isAttested` | `0xc13c2396` | -| `owner` | `0x8da5cb5b` | +| Function | Signature | +| -------- | --------- | +| `allowPayload` | `0x31c23f66` | +| `attest` | `0x63671b60` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `chainSlug` | `0xb349ba65` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `grantRole` | `0x2f2ff15d` | +| `hasRole` | `0x91d14854` | +| `isAttested` | `0xc13c2396` | +| `owner` | `0x8da5cb5b` | | `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `registerSwitchboard` | `0x74f5b1fc` | -| `renounceOwnership` | `0x715018a6` | -| `requestOwnershipHandover` | `0x25692962` | -| `rescueFunds` | `0x6ccae054` | -| `revokeRole` | `0xd547741f` | -| `socket__` | `0xc6a261d2` | -| `transferOwnership` | `0xf2fde38b` | +| `registerSwitchboard` | `0x74f5b1fc` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | +| `revokeRole` | `0xd547741f` | +| `socket__` | `0xc6a261d2` | +| `transferOwnership` | `0xf2fde38b` | ## ReadPrecompile -| Function | Signature | -| ------------------------------ | ------------ | -| `expiryTime` | `0x99bc0aea` | -| `getPrecompileFees` | `0xb7a3d04c` | -| `handlePayload` | `0x1d5e1d98` | -| `readFees` | `0xe06357a2` | -| `rescueFunds` | `0x6ccae054` | -| `resolvePayload` | `0xea92e825` | -| `setExpiryTime` | `0x30fc4cff` | -| `setFees` | `0x3d18678e` | +| Function | Signature | +| -------- | --------- | +| `expiryTime` | `0x99bc0aea` | +| `getPrecompileFees` | `0xb7a3d04c` | +| `handlePayload` | `0x1d5e1d98` | +| `readFees` | `0xe06357a2` | +| `rescueFunds` | `0x6ccae054` | +| `resolvePayload` | `0xea92e825` | +| `setExpiryTime` | `0x30fc4cff` | +| `setFees` | `0x3d18678e` | | `validateAndGetPrecompileData` | `0xab172aab` | -| `watcher__` | `0x300bb063` | +| `watcher__` | `0x300bb063` | ## SchedulePrecompile -| Function | Signature | -| ------------------------------ | ------------ | -| `expiryTime` | `0x99bc0aea` | -| `getPrecompileFees` | `0xb7a3d04c` | -| `handlePayload` | `0x1d5e1d98` | -| `maxScheduleDelayInSeconds` | `0x3ef01cdb` | -| `rescueFunds` | `0x6ccae054` | -| `resolvePayload` | `0xea92e825` | -| `scheduleCallbackFees` | `0x4c5b6007` | -| `scheduleFeesPerSecond` | `0x852a74c1` | -| `setExpiryTime` | `0x30fc4cff` | +| Function | Signature | +| -------- | --------- | +| `expiryTime` | `0x99bc0aea` | +| `getPrecompileFees` | `0xb7a3d04c` | +| `handlePayload` | `0x1d5e1d98` | +| `maxScheduleDelayInSeconds` | `0x3ef01cdb` | +| `rescueFunds` | `0x6ccae054` | +| `resolvePayload` | `0xea92e825` | +| `scheduleCallbackFees` | `0x4c5b6007` | +| `scheduleFeesPerSecond` | `0x852a74c1` | +| `setExpiryTime` | `0x30fc4cff` | | `setMaxScheduleDelayInSeconds` | `0x12953318` | -| `setScheduleCallbackFees` | `0xec8fd71e` | -| `setScheduleFeesPerSecond` | `0x28e59e57` | +| `setScheduleCallbackFees` | `0xec8fd71e` | +| `setScheduleFeesPerSecond` | `0x28e59e57` | | `validateAndGetPrecompileData` | `0xab172aab` | -| `watcher__` | `0x300bb063` | +| `watcher__` | `0x300bb063` | ## WritePrecompile -| Function | Signature | -| ------------------------------ | ------------ | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `chainMaxMsgValueLimit` | `0x01d1e126` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `contractFactoryPlugs` | `0x35426631` | -| `digestHashes` | `0xd1a862bf` | -| `expiryTime` | `0x99bc0aea` | -| `getDigest` | `0xdd4bf97b` | -| `getPrecompileFees` | `0xb7a3d04c` | -| `getPrevBatchDigestHash` | `0x372863a1` | -| `handlePayload` | `0x1d5e1d98` | -| `initialize` | `0xeb990c59` | -| `owner` | `0x8da5cb5b` | -| `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `renounceOwnership` | `0x715018a6` | -| `requestOwnershipHandover` | `0x25692962` | -| `rescueFunds` | `0x6ccae054` | -| `resolvePayload` | `0xea92e825` | -| `setContractFactoryPlugs` | `0xc067b6dd` | -| `setExpiryTime` | `0x30fc4cff` | -| `setFees` | `0x3d18678e` | -| `transferOwnership` | `0xf2fde38b` | +| Function | Signature | +| -------- | --------- | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `chainMaxMsgValueLimit` | `0x01d1e126` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `contractFactoryPlugs` | `0x35426631` | +| `digestHashes` | `0xd1a862bf` | +| `expiryTime` | `0x99bc0aea` | +| `getDigest` | `0xdd4bf97b` | +| `getPrecompileFees` | `0xb7a3d04c` | +| `getPrevBatchDigestHash` | `0x372863a1` | +| `handlePayload` | `0x1d5e1d98` | +| `initialize` | `0xeb990c59` | +| `owner` | `0x8da5cb5b` | +| `ownershipHandoverExpiresAt` | `0xfee81cf4` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | +| `resolvePayload` | `0xea92e825` | +| `setContractFactoryPlugs` | `0xc067b6dd` | +| `setExpiryTime` | `0x30fc4cff` | +| `setFees` | `0x3d18678e` | +| `transferOwnership` | `0xf2fde38b` | | `updateChainMaxMsgValueLimits` | `0x6a7aa6ac` | -| `uploadProof` | `0x81b48fcf` | +| `uploadProof` | `0x81b48fcf` | | `validateAndGetPrecompileData` | `0xab172aab` | -| `watcherProofs` | `0x3fa3166b` | -| `watcher__` | `0x300bb063` | -| `writeFees` | `0x5c664aeb` | +| `watcherProofs` | `0x3fa3166b` | +| `watcher__` | `0x300bb063` | +| `writeFees` | `0x5c664aeb` | + diff --git a/deployments/dev_addresses.json b/deployments/dev_addresses.json index 49a3be67..ffda3474 100644 --- a/deployments/dev_addresses.json +++ b/deployments/dev_addresses.json @@ -1,44 +1,44 @@ { "421614": { - "ContractFactoryPlug": "0xaCd26f991E548F353f285942509d90200064Cf14", - "FastSwitchboard": "0xbcc1CE144cA85C0d121f08634547a61E93627ce4", - "FeesPlug": "0xb0cbd56A86568BB4cBBE59B0EcA029A4F2D7f235", - "Socket": "0xEb907f52eAF6e81439F8807AE2F143Bd3482e6b6", - "SocketBatcher": "0xc498A63eE84143A15A7D3080E1E51af700f35e41", - "startBlock": 159285686 + "ContractFactoryPlug": "0x7b9928b01272b915050aDfcba7e0a11b22271BAd", + "FastSwitchboard": "0x2974E94c0d1323D3A24f7B4F924fbdB325Be1aa3", + "FeesPlug": "0x6FdF04Cbcbd40414BF12e0b4Ce0e331e4657EB03", + "Socket": "0xb7378ae43b135988C8a83dfD1AcD71Ff39381396", + "SocketBatcher": "0x60541d31Fda60163480CAb486be3762b5793B650", + "startBlock": 159641867 }, "7625382": { - "AddressResolver": "0xF7efc3886b225A571d35C2DF736eD515F132911F", - "AddressResolverImpl": "0x865A24Cf706027639124489e0dA2A28766efB96A", - "AsyncDeployer": "0xC1A87C08d86bE83323F071362Cf4f48C946b9d00", - "AsyncDeployerImpl": "0xF4f5606189Bc091528680b2ca1c82167641d3cAf", - "AuctionManager": "0xEdf413851964c6Ac5154FA768F3e54e9BeB777dB", - "AuctionManagerImpl": "0x1C40B5d5f6E9be1Ca4557d92cb7dba35e721a322", - "Configurations": "0x5A6c10F1c7bEf419022be7c2F716CC4628cBa3Cf", - "ConfigurationsImpl": "0x8d41aBDbE6Bbd208D68Dd4E671c4B72474525C7B", - "DeployForwarder": "0xD0d5BAF888afE7F857B5AeF74A63bE7416B742eE", - "DeployForwarderImpl": "0xD9CF47342c8a256fcD8B51aaABA810cd5D05F726", - "ERC1967Factory": "0x1b0F1aA38F8BBbe779A6C1fCe7e3Ff00380fa9CE", - "FeesManager": "0x07653B23F84aB397649378BB512bd82D19D9D6F1", - "FeesManagerImpl": "0x255fBaD02F8f2Aae0Faf7074249a8701371890D2", + "AddressResolver": "0x8161cDBa2d2fCE66307254AAC1d42966D4F5353E", + "AddressResolverImpl": "0x91e548d87768313C03da8405D01171b83912c430", + "AsyncDeployer": "0x025b308371dC1C5e337527f96BE46Ba6A12c774A", + "AsyncDeployerImpl": "0x80CFbD3B6134Fb2D2B7d21FC132a9F7c115e7B72", + "AuctionManager": "0xA40aFA1632328D84226084a4539B3869D2B68e28", + "AuctionManagerImpl": "0x42109F6212765ABeb589f9b2c14Bee4b8DB3e638", + "Configurations": "0x60185198097df249B504D5A164323eBF42B3764d", + "ConfigurationsImpl": "0x0d2646fC08af29A7799Af435c5ABBA1b020C4dC7", + "DeployForwarder": "0xdC51D652B8c3cCB3cAAB9C1E2704fD4D62E76433", + "DeployForwarderImpl": "0xCe95fca954a0BF43c299c79d5152f2c164C02b7A", + "ERC1967Factory": "0xb0364Fd8f158071831ac87E7EE2C792Ab509a524", + "FeesManager": "0x09F824Eae77f71279d73Ae24FEb2163FCe88B25D", + "FeesManagerImpl": "0x6975302A1B7aF61d89F85a13855B66D15221Cf8D", "FeesPool": "0xc20Be67ef742202dc93A78aa741E7C3715eA1DFd", - "PromiseResolver": "0xF24B41A8C9F814d70FAD9E617CE32C74EcCB1A25", - "ReadPrecompile": "0xddeEDDD5F156123fDbf77B86A66A043568AEfcda", - "RequestHandler": "0x52968Eb279aad2287aF4C9a4638C146F91787958", - "RequestHandlerImpl": "0x1fa5D12C7dC1F3615c28B842A6053f5f151230F8", - "SchedulePrecompile": "0xDa60303321dc6aA8AeF32557bDe914008a3196eC", - "startBlock": 8263673, - "Watcher": "0x60005b459Dc46D9a63bcb61D01Ad002130644a4F", - "WatcherImpl": "0x812EcdF5366036B045e41Fe2dD95B72ecc26d8f3", - "WritePrecompile": "0xF221bAA9AEA24c366258309ab09C2C7ce80610Fc", - "WritePrecompileImpl": "0x09A1A0A7BB8266171855871c4c0Af200a30922BE" + "PromiseResolver": "0xcfFda1dF8668266E6A77809EcA9CCA8A632ecaF3", + "ReadPrecompile": "0x254Dc9e0623426A79F02D2001E367cd32B50aaaA", + "RequestHandler": "0x1FE7527a8620374B3Fdb101bA1D56eC46EC9a24A", + "RequestHandlerImpl": "0x3d9578B252ed1F5A66348Cc40E482dacc32Ae790", + "SchedulePrecompile": "0x7D6F2A4aDf7e5Cfcf9627CC7FCA1d39fD19C07fc", + "startBlock": 8355289, + "Watcher": "0xD5b30DC89D96ee7303Dc2726491996B46089F693", + "WatcherImpl": "0xFa9B9271A4153eEABa76ae10bfc4F128651c25D7", + "WritePrecompile": "0x10eaDbd1a2787ebbF4Abe9b6D79e669C0c8E8B26", + "WritePrecompileImpl": "0xD3aEb53da0a72788C16eAf5a23a5aBae6708C073" }, "11155420": { - "ContractFactoryPlug": "0xf134E3a725DdbBebf9e0f66D6767B44468cdBB48", - "FastSwitchboard": "0xa2E9eC2B0e035650744B6F489e8dDd471B502b2b", - "FeesPlug": "0x64b7157Fe0878880b180d9BD2a0bd0D1794Cf44A", - "Socket": "0xd8C787c27Cc6F4BF143855Bb50c880FB2DE38267", - "SocketBatcher": "0xc6Fe653dAfeDd76d50e3F971dDA650917824f948", - "startBlock": 28522517 + "ContractFactoryPlug": "0x0279A18d5FC235A92fB4ABd5F7e9258e78E27948", + "FastSwitchboard": "0x6b4EF1452265193798bfa3ef6D29421da9e7E222", + "FeesPlug": "0x99f7441292EB7f0b127Db204ba269Abd9F912d4C", + "Socket": "0xB260A4DD0952e9A5b5F6652019469F05Fb137dC5", + "SocketBatcher": "0xc320FC7b06D4491A9E7e6fa55a3305b12548519e", + "startBlock": 28568337 } } diff --git a/deployments/dev_verification.json b/deployments/dev_verification.json index b1a2b712..a2c3199e 100644 --- a/deployments/dev_verification.json +++ b/deployments/dev_verification.json @@ -1,6 +1,147 @@ { - "421614": [], + "421614": [ + [ + "0x7b9928b01272b915050aDfcba7e0a11b22271BAd", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0xb7378ae43b135988C8a83dfD1AcD71Ff39381396", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x6FdF04Cbcbd40414BF12e0b4Ce0e331e4657EB03", + "FeesPlug", + "contracts/evmx/plugs/FeesPlug.sol", + [ + "0xb7378ae43b135988C8a83dfD1AcD71Ff39381396", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x2974E94c0d1323D3A24f7B4F924fbdB325Be1aa3", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", + [ + 421614, + "0xb7378ae43b135988C8a83dfD1AcD71Ff39381396", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x60541d31Fda60163480CAb486be3762b5793B650", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0xb7378ae43b135988C8a83dfD1AcD71Ff39381396" + ] + ], + [ + "0xb7378ae43b135988C8a83dfD1AcD71Ff39381396", + "Socket", + "contracts/protocol/Socket.sol", + [421614, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] + ] + ], "7625382": [ + [ + "0x7D6F2A4aDf7e5Cfcf9627CC7FCA1d39fD19C07fc", + "SchedulePrecompile", + "contracts/evmx/watcher/precompiles/SchedulePrecompile.sol", + [ + "0xD5b30DC89D96ee7303Dc2726491996B46089F693", + 86400, + { + "type": "BigNumber", + "hex": "0xe8d4a51000" + }, + { + "type": "BigNumber", + "hex": "0xe8d4a51000" + }, + 300 + ] + ], + [ + "0x254Dc9e0623426A79F02D2001E367cd32B50aaaA", + "ReadPrecompile", + "contracts/evmx/watcher/precompiles/ReadPrecompile.sol", + [ + "0xD5b30DC89D96ee7303Dc2726491996B46089F693", + { + "type": "BigNumber", + "hex": "0xe8d4a51000" + }, + 300 + ] + ], + [ + "0xD3aEb53da0a72788C16eAf5a23a5aBae6708C073", + "WritePrecompile", + "contracts/evmx/watcher/precompiles/WritePrecompile.sol", + [] + ], + [ + "0xcfFda1dF8668266E6A77809EcA9CCA8A632ecaF3", + "PromiseResolver", + "contracts/evmx/watcher/PromiseResolver.sol", + ["0xD5b30DC89D96ee7303Dc2726491996B46089F693"] + ], + [ + "0x3d9578B252ed1F5A66348Cc40E482dacc32Ae790", + "RequestHandler", + "contracts/evmx/watcher/RequestHandler.sol", + [] + ], + [ + "0x0d2646fC08af29A7799Af435c5ABBA1b020C4dC7", + "Configurations", + "contracts/evmx/watcher/Configurations.sol", + [] + ], + [ + "0xCe95fca954a0BF43c299c79d5152f2c164C02b7A", + "DeployForwarder", + "contracts/evmx/helpers/DeployForwarder.sol", + [] + ], + [ + "0x42109F6212765ABeb589f9b2c14Bee4b8DB3e638", + "AuctionManager", + "contracts/evmx/AuctionManager.sol", + [] + ], + [ + "0xFa9B9271A4153eEABa76ae10bfc4F128651c25D7", + "Watcher", + "contracts/evmx/watcher/Watcher.sol", + [] + ], + [ + "0x80CFbD3B6134Fb2D2B7d21FC132a9F7c115e7B72", + "AsyncDeployer", + "contracts/evmx/helpers/AsyncDeployer.sol", + [] + ], + [ + "0x6975302A1B7aF61d89F85a13855B66D15221Cf8D", + "FeesManager", + "contracts/evmx/fees/FeesManager.sol", + [] + ], + [ + "0x91e548d87768313C03da8405D01171b83912c430", + "AddressResolver", + "contracts/evmx/helpers/AddressResolver.sol", + [] + ], + [ + "0xb0364Fd8f158071831ac87E7EE2C792Ab509a524", + "ERC1967Factory", + "lib/solady/src/utils/ERC1967Factory.sol", + [] + ], [ "0x09A1A0A7BB8266171855871c4c0Af200a30922BE", "WritePrecompile", @@ -111,5 +252,49 @@ [] ] ], - "11155420": [] + "11155420": [ + [ + "0x0279A18d5FC235A92fB4ABd5F7e9258e78E27948", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0xB260A4DD0952e9A5b5F6652019469F05Fb137dC5", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x99f7441292EB7f0b127Db204ba269Abd9F912d4C", + "FeesPlug", + "contracts/evmx/plugs/FeesPlug.sol", + [ + "0xB260A4DD0952e9A5b5F6652019469F05Fb137dC5", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x6b4EF1452265193798bfa3ef6D29421da9e7E222", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", + [ + 11155420, + "0xB260A4DD0952e9A5b5F6652019469F05Fb137dC5", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xc320FC7b06D4491A9E7e6fa55a3305b12548519e", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0xB260A4DD0952e9A5b5F6652019469F05Fb137dC5" + ] + ], + [ + "0xB260A4DD0952e9A5b5F6652019469F05Fb137dC5", + "Socket", + "contracts/protocol/Socket.sol", + [11155420, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] + ] + ] } diff --git a/hardhat-scripts/deploy/4.configureEVMx.ts b/hardhat-scripts/deploy/4.configureEVMx.ts index e12bd950..bac01a52 100644 --- a/hardhat-scripts/deploy/4.configureEVMx.ts +++ b/hardhat-scripts/deploy/4.configureEVMx.ts @@ -1,22 +1,13 @@ import { config as dotenvConfig } from "dotenv"; dotenvConfig(); -import { - ChainAddressesObj, - ChainSlug, - Contracts, - EVMxAddressesObj, - READ, - SCHEDULE, - WRITE, -} from "../../src"; -import { Contract, Wallet } from "ethers"; -import { chains, EVMX_CHAIN_ID, mode } from "../config"; -import { DeploymentAddresses, FAST_SWITCHBOARD_TYPE } from "../constants"; +import { Contracts, EVMxAddressesObj, READ, SCHEDULE, WRITE } from "../../src"; +import { Wallet } from "ethers"; +import { EVMX_CHAIN_ID, mode } from "../config"; +import { DeploymentAddresses } from "../constants"; import { getAddresses, getInstance, - getSocketSigner, getWatcherSigner, updateContractSettings, } from "../utils"; @@ -134,14 +125,18 @@ export const setWatcherCoreContracts = async ( const watcherContract = ( await getInstance(Contracts.Watcher, evmxAddresses[Contracts.Watcher]) ).connect(getWatcherSigner()); + const requestHandlerSet = await watcherContract.requestHandler__(); const PromiseResolverSet = await watcherContract.promiseResolver__(); const ConfigurationsSet = await watcherContract.configurations__(); if ( - requestHandlerSet !== evmxAddresses[Contracts.RequestHandler] || - PromiseResolverSet !== evmxAddresses[Contracts.PromiseResolver] || - ConfigurationsSet !== evmxAddresses[Contracts.Configurations] + requestHandlerSet.toLowerCase() !== + evmxAddresses[Contracts.RequestHandler].toLowerCase() || + PromiseResolverSet.toLowerCase() !== + evmxAddresses[Contracts.PromiseResolver].toLowerCase() || + ConfigurationsSet.toLowerCase() !== + evmxAddresses[Contracts.Configurations].toLowerCase() ) { console.log("Setting watcher core contracts"); const tx = await watcherContract.setCoreContracts( @@ -151,6 +146,8 @@ export const setWatcherCoreContracts = async ( ); console.log("Watcher core contracts set tx: ", tx.hash); await tx.wait(); + } else { + console.log("Watcher core contracts are already set"); } }; diff --git a/hardhat-scripts/utils/deployUtils.ts b/hardhat-scripts/utils/deployUtils.ts index 0b6206a5..f034e5de 100644 --- a/hardhat-scripts/utils/deployUtils.ts +++ b/hardhat-scripts/utils/deployUtils.ts @@ -335,7 +335,7 @@ export const updateContractSettings = async ( const contractInstance = await getInstance(contractName, contractAddress); const currentValue = await contractInstance .connect(signer) - [getterMethod](...getterArgs); + [getterMethod](...getterArgs); if ( (typeof currentValue === "string" && @@ -350,11 +350,13 @@ export const updateContractSettings = async ( }); const tx = await contractInstance .connect(signer) - [setterMethod](...setterArgs); + [setterMethod](...setterArgs); console.log( `Setting ${getterMethod} for ${contractInstance.address} to`, tx.hash ); await tx.wait(); + } else { + console.log(`${getterMethod} is already set to ${requiredValue}`); } }; From 85ea8cf7684fd68e4f3997189b00463c2666a978 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 3 Jun 2025 14:23:12 +0530 Subject: [PATCH 120/130] fix: lint --- Errors.md | 185 +++-- EventTopics.md | 391 +++++---- FunctionSignatures.md | 929 +++++++++++----------- hardhat-scripts/deploy/4.configureEVMx.ts | 6 +- hardhat-scripts/utils/deployUtils.ts | 4 +- 5 files changed, 756 insertions(+), 759 deletions(-) diff --git a/Errors.md b/Errors.md index d40a6613..77179268 100644 --- a/Errors.md +++ b/Errors.md @@ -1,143 +1,142 @@ # Custom Error Codes - ## evmx/fees/FeesPool.sol -| Error | Signature | -|-------|-----------| +| Error | Signature | +| ------------------ | ------------ | | `TransferFailed()` | `0x90b8ec18` | ## evmx/helpers/AsyncPromise.sol -| Error | Signature | -|-------|-----------| +| Error | Signature | +| -------------------------- | ------------ | | `PromiseAlreadyResolved()` | `0x56b63537` | -| `OnlyInvoker()` | `0x74ed21f5` | -| `PromiseAlreadySetUp()` | `0x927c53d5` | -| `PromiseRevertFailed()` | `0x0175b9de` | -| `NotLatestPromise()` | `0x39ca95d3` | +| `OnlyInvoker()` | `0x74ed21f5` | +| `PromiseAlreadySetUp()` | `0x927c53d5` | +| `PromiseRevertFailed()` | `0x0175b9de` | +| `NotLatestPromise()` | `0x39ca95d3` | ## evmx/plugs/ContractFactoryPlug.sol -| Error | Signature | -|-------|-----------| -| `DeploymentFailed()` | `0x30116425` | +| Error | Signature | +| -------------------------------- | ------------ | +| `DeploymentFailed()` | `0x30116425` | | `ExecutionFailed(bytes32,bytes)` | `0xd255d8a3` | -| `information(bool,,bytes)` | `0x3a82a1f3` | +| `information(bool,,bytes)` | `0x3a82a1f3` | ## evmx/plugs/FeesPlug.sol -| Error | Signature | -|-------|-----------| +| Error | Signature | +| --------------------------------------------------- | ------------ | | `InsufficientTokenBalance(address,uint256,uint256)` | `0xebd6ced9` | -| `InvalidDepositAmount()` | `0xfe9ba5cd` | -| `TokenNotWhitelisted(address)` | `0xea3bff2e` | +| `InvalidDepositAmount()` | `0xfe9ba5cd` | +| `TokenNotWhitelisted(address)` | `0xea3bff2e` | ## evmx/watcher/RequestHandler.sol -| Error | Signature | -|-------|-----------| +| Error | Signature | +| ----------------------- | ------------ | | `InsufficientMaxFees()` | `0x0e5bc492` | ## protocol/Socket.sol -| Error | Signature | -|-------|-----------| +| Error | Signature | +| ----------------------------------------- | ------------ | | `PayloadAlreadyExecuted(ExecutionStatus)` | `0xf4c54edd` | -| `VerificationFailed()` | `0x439cc0cd` | -| `LowGasLimit()` | `0xd38edae0` | -| `InsufficientMsgValue()` | `0x78f38f76` | +| `VerificationFailed()` | `0x439cc0cd` | +| `LowGasLimit()` | `0xd38edae0` | +| `InsufficientMsgValue()` | `0x78f38f76` | ## protocol/SocketConfig.sol -| Error | Signature | -|-------|-----------| -| `SwitchboardExists()` | `0x2dff8555` | +| Error | Signature | +| ------------------------------- | ------------ | +| `SwitchboardExists()` | `0x2dff8555` | | `SwitchboardExistsOrDisabled()` | `0x1c7d2487` | ## protocol/SocketFeeManager.sol -| Error | Signature | -|-------|-----------| +| Error | Signature | +| -------------------- | ------------ | | `InsufficientFees()` | `0x8d53e553` | -| `FeeTooLow()` | `0x732f9413` | +| `FeeTooLow()` | `0x732f9413` | ## protocol/SocketUtils.sol -| Error | Signature | -|-------|-----------| -| `OnlyOffChain()` | `0x9cbfe066` | +| Error | Signature | +| -------------------- | ------------ | +| `OnlyOffChain()` | `0x9cbfe066` | | `SimulationFailed()` | `0x2fbab3ac` | ## protocol/switchboard/FastSwitchboard.sol -| Error | Signature | -|-------|-----------| +| Error | Signature | +| ------------------- | ------------ | | `AlreadyAttested()` | `0x35d90805` | | `WatcherNotFound()` | `0xa278e4ad` | ## utils/AccessControl.sol -| Error | Signature | -|-------|-----------| +| Error | Signature | +| ------------------- | ------------ | | `NoPermit(bytes32)` | `0x962f6333` | ## utils/common/Errors.sol -| Error | Signature | -|-------|-----------| -| `ZeroAddress()` | `0xd92e233d` | -| `InvalidTransmitter()` | `0x58a70a0a` | -| `InvalidTokenAddress()` | `0x1eb00b06` | -| `InvalidSwitchboard()` | `0xf63c9e4d` | -| `SocketAlreadyInitialized()` | `0xc9500b00` | -| `NotSocket()` | `0xc59f8f7c` | -| `PlugNotFound()` | `0x5f1ac76a` | -| `ResolvingScheduleTooEarly()` | `0x207e8731` | -| `CallFailed()` | `0x3204506f` | -| `InvalidAppGateway()` | `0x82ded261` | -| `AppGatewayAlreadyCalled()` | `0xb224683f` | -| `InvalidCallerTriggered()` | `0x3292d247` | -| `InvalidPromise()` | `0x45f2d176` | -| `InvalidWatcherSignature()` | `0x5029f14f` | -| `NonceUsed()` | `0x1f6d5aef` | -| `AsyncModifierNotSet()` | `0xcae106f9` | -| `WatcherNotSet()` | `0x42d473a7` | -| `InvalidTarget()` | `0x82d5d76a` | -| `InvalidIndex()` | `0x63df8171` | -| `InvalidChainSlug()` | `0xbff6b106` | -| `InvalidPayloadSize()` | `0xfbdf7954` | -| `InvalidOnChainAddress()` | `0xb758c606` | -| `InvalidScheduleDelay()` | `0x9a993219` | -| `AuctionClosed()` | `0x36b6b46d` | -| `AuctionNotOpen()` | `0xf0460077` | -| `BidExceedsMaxFees()` | `0x4c923f3c` | -| `LowerBidAlreadyExists()` | `0xaaa1f709` | -| `RequestCountMismatch()` | `0x98bbcbff` | -| `InvalidAmount()` | `0x2c5211c6` | -| `InsufficientCreditsAvailable()` | `0xe61dc0aa` | -| `InsufficientBalance()` | `0xf4d678b8` | -| `InvalidCaller()` | `0x48f5c3ed` | -| `InvalidGateway()` | `0xfc9dfe85` | -| `RequestAlreadyCancelled()` | `0xc70f47d8` | -| `DeadlineNotPassedForOnChainRevert()` | `0x7006aa10` | -| `InvalidBid()` | `0xc6388ef7` | -| `MaxReAuctionCountReached()` | `0xf2b4388c` | -| `MaxMsgValueLimitExceeded()` | `0x97b4e8ce` | -| `OnlyWatcherAllowed()` | `0xdf7d227c` | -| `InvalidPrecompileData()` | `0x320062c0` | -| `InvalidCallType()` | `0x39d2eb55` | -| `NotRequestHandler()` | `0x8f8cba5b` | -| `NotInvoker()` | `0x8a6353d1` | -| `NotPromiseResolver()` | `0x86d876b2` | -| `RequestPayloadCountLimitExceeded()` | `0xcbef144b` | -| `InsufficientFees()` | `0x8d53e553` | -| `RequestAlreadySettled()` | `0x66fad465` | -| `NoWriteRequest()` | `0x9dcd3065` | -| `AlreadyAssigned()` | `0x9688dc51` | -| `OnlyAppGateway()` | `0xfec944ea` | +| Error | Signature | +| --------------------------------------------- | ------------ | +| `ZeroAddress()` | `0xd92e233d` | +| `InvalidTransmitter()` | `0x58a70a0a` | +| `InvalidTokenAddress()` | `0x1eb00b06` | +| `InvalidSwitchboard()` | `0xf63c9e4d` | +| `SocketAlreadyInitialized()` | `0xc9500b00` | +| `NotSocket()` | `0xc59f8f7c` | +| `PlugNotFound()` | `0x5f1ac76a` | +| `ResolvingScheduleTooEarly()` | `0x207e8731` | +| `CallFailed()` | `0x3204506f` | +| `InvalidAppGateway()` | `0x82ded261` | +| `AppGatewayAlreadyCalled()` | `0xb224683f` | +| `InvalidCallerTriggered()` | `0x3292d247` | +| `InvalidPromise()` | `0x45f2d176` | +| `InvalidWatcherSignature()` | `0x5029f14f` | +| `NonceUsed()` | `0x1f6d5aef` | +| `AsyncModifierNotSet()` | `0xcae106f9` | +| `WatcherNotSet()` | `0x42d473a7` | +| `InvalidTarget()` | `0x82d5d76a` | +| `InvalidIndex()` | `0x63df8171` | +| `InvalidChainSlug()` | `0xbff6b106` | +| `InvalidPayloadSize()` | `0xfbdf7954` | +| `InvalidOnChainAddress()` | `0xb758c606` | +| `InvalidScheduleDelay()` | `0x9a993219` | +| `AuctionClosed()` | `0x36b6b46d` | +| `AuctionNotOpen()` | `0xf0460077` | +| `BidExceedsMaxFees()` | `0x4c923f3c` | +| `LowerBidAlreadyExists()` | `0xaaa1f709` | +| `RequestCountMismatch()` | `0x98bbcbff` | +| `InvalidAmount()` | `0x2c5211c6` | +| `InsufficientCreditsAvailable()` | `0xe61dc0aa` | +| `InsufficientBalance()` | `0xf4d678b8` | +| `InvalidCaller()` | `0x48f5c3ed` | +| `InvalidGateway()` | `0xfc9dfe85` | +| `RequestAlreadyCancelled()` | `0xc70f47d8` | +| `DeadlineNotPassedForOnChainRevert()` | `0x7006aa10` | +| `InvalidBid()` | `0xc6388ef7` | +| `MaxReAuctionCountReached()` | `0xf2b4388c` | +| `MaxMsgValueLimitExceeded()` | `0x97b4e8ce` | +| `OnlyWatcherAllowed()` | `0xdf7d227c` | +| `InvalidPrecompileData()` | `0x320062c0` | +| `InvalidCallType()` | `0x39d2eb55` | +| `NotRequestHandler()` | `0x8f8cba5b` | +| `NotInvoker()` | `0x8a6353d1` | +| `NotPromiseResolver()` | `0x86d876b2` | +| `RequestPayloadCountLimitExceeded()` | `0xcbef144b` | +| `InsufficientFees()` | `0x8d53e553` | +| `RequestAlreadySettled()` | `0x66fad465` | +| `NoWriteRequest()` | `0x9dcd3065` | +| `AlreadyAssigned()` | `0x9688dc51` | +| `OnlyAppGateway()` | `0xfec944ea` | | `NewMaxFeesLowerThanCurrent(uint256,uint256)` | `0x1345dda1` | -| `InvalidContract()` | `0x6eefed20` | -| `InvalidData()` | `0x5cb045db` | -| `InvalidSignature()` | `0x8baa579f` | -| `DeadlinePassed()` | `0x70f65caa` | +| `InvalidContract()` | `0x6eefed20` | +| `InvalidData()` | `0x5cb045db` | +| `InvalidSignature()` | `0x8baa579f` | +| `DeadlinePassed()` | `0x70f65caa` | diff --git a/EventTopics.md b/EventTopics.md index b4fb85c7..36cadb7d 100644 --- a/EventTopics.md +++ b/EventTopics.md @@ -2,269 +2,268 @@ ## AuctionManager -| Event | Arguments | Topic | -| ----- | --------- | ----- | -| `AuctionEndDelaySecondsSet` | `(auctionEndDelaySeconds: uint256)` | `0xf38f0d9dc8459cf5426728c250d115196a4c065ebc1a6c29da24764a8c0da722` | -| `AuctionEnded` | `(requestCount: uint40, winningBid: tuple)` | `0xede4ec1efc469fac10dcb4930f70be4cd21f3700ed61c91967c19a7cd7c0d86e` | -| `AuctionRestarted` | `(requestCount: uint40)` | `0x071867b21946ec4655665f0d4515d3757a5a52f144c762ecfdfb11e1da542b82` | -| `AuctionStarted` | `(requestCount: uint40)` | `0xcd040613cf8ef0cfcaa3af0d711783e827a275fc647c116b74595bf17cb9364f` | -| `BidPlaced` | `(requestCount: uint40, bid: tuple)` | `0x7f79485e4c9aeea5d4899bc6f7c63b22ac1f4c01d2d28c801e94732fee657b5d` | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `MaxReAuctionCountSet` | `(maxReAuctionCount: uint256)` | `0x2f6fadde7ab8ab83d21ab10c3bc09dde179f8696d47c4176581facf0c6f96bbf` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | -| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | +| Event | Arguments | Topic | +| ---------------------------- | ------------------------------------------- | -------------------------------------------------------------------- | +| `AuctionEndDelaySecondsSet` | `(auctionEndDelaySeconds: uint256)` | `0xf38f0d9dc8459cf5426728c250d115196a4c065ebc1a6c29da24764a8c0da722` | +| `AuctionEnded` | `(requestCount: uint40, winningBid: tuple)` | `0xede4ec1efc469fac10dcb4930f70be4cd21f3700ed61c91967c19a7cd7c0d86e` | +| `AuctionRestarted` | `(requestCount: uint40)` | `0x071867b21946ec4655665f0d4515d3757a5a52f144c762ecfdfb11e1da542b82` | +| `AuctionStarted` | `(requestCount: uint40)` | `0xcd040613cf8ef0cfcaa3af0d711783e827a275fc647c116b74595bf17cb9364f` | +| `BidPlaced` | `(requestCount: uint40, bid: tuple)` | `0x7f79485e4c9aeea5d4899bc6f7c63b22ac1f4c01d2d28c801e94732fee657b5d` | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `MaxReAuctionCountSet` | `(maxReAuctionCount: uint256)` | `0x2f6fadde7ab8ab83d21ab10c3bc09dde179f8696d47c4176581facf0c6f96bbf` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | +| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | ## Socket -| Event | Arguments | Topic | -| ----- | --------- | ----- | -| `AppGatewayCallRequested` | `(triggerId: bytes32, appGatewayId: bytes32, switchboard: address, plug: address, overrides: bytes, payload: bytes)` | `0x5c88d65ab8ba22a57e582bd8ddfa9801cc0ca6be6cb3182baaedc705a612419e` | -| `ExecutionFailed` | `(payloadId: bytes32, exceededMaxCopy: bool, returnData: bytes)` | `0x385334bc68a32c4d164625189adc7633e6074eb1b837fb4d11d768245151e4ce` | -| `ExecutionSuccess` | `(payloadId: bytes32, exceededMaxCopy: bool, returnData: bytes)` | `0x324d63a433b21a12b90e79cd2ba736b2a5238be6165e03b750fa4a7d5193d5d9` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `PlugConnected` | `(plug: address, appGatewayId: bytes32, switchboard: address)` | `0x90c5924e27cfb6e3a688e729083681f30494ae2615ae14aac3bc807a0c436a88` | -| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | -| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | -| `SocketFeeManagerUpdated` | `(oldSocketFeeManager: address, newSocketFeeManager: address)` | `0xdcb02e10d5220346a4638aa2826eaab1897306623bc40a427049e4ebd12255b4` | -| `SwitchboardAdded` | `(switchboard: address)` | `0x1595852923edfbbf906f09fc8523e4cfb022a194773c4d1509446b614146ee88` | -| `SwitchboardDisabled` | `(switchboard: address)` | `0x1b4ee41596b4e754e5665f01ed6122b356f7b36ea0a02030804fac7fa0fdddfc` | -| `SwitchboardEnabled` | `(switchboard: address)` | `0x6909a9974e3eec619bc479ba882d30a5ef1219b72ab1ce6a354516e91be317b8` | +| Event | Arguments | Topic | +| ---------------------------- | -------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | +| `AppGatewayCallRequested` | `(triggerId: bytes32, appGatewayId: bytes32, switchboard: address, plug: address, overrides: bytes, payload: bytes)` | `0x5c88d65ab8ba22a57e582bd8ddfa9801cc0ca6be6cb3182baaedc705a612419e` | +| `ExecutionFailed` | `(payloadId: bytes32, exceededMaxCopy: bool, returnData: bytes)` | `0x385334bc68a32c4d164625189adc7633e6074eb1b837fb4d11d768245151e4ce` | +| `ExecutionSuccess` | `(payloadId: bytes32, exceededMaxCopy: bool, returnData: bytes)` | `0x324d63a433b21a12b90e79cd2ba736b2a5238be6165e03b750fa4a7d5193d5d9` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `PlugConnected` | `(plug: address, appGatewayId: bytes32, switchboard: address)` | `0x90c5924e27cfb6e3a688e729083681f30494ae2615ae14aac3bc807a0c436a88` | +| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | +| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | +| `SocketFeeManagerUpdated` | `(oldSocketFeeManager: address, newSocketFeeManager: address)` | `0xdcb02e10d5220346a4638aa2826eaab1897306623bc40a427049e4ebd12255b4` | +| `SwitchboardAdded` | `(switchboard: address)` | `0x1595852923edfbbf906f09fc8523e4cfb022a194773c4d1509446b614146ee88` | +| `SwitchboardDisabled` | `(switchboard: address)` | `0x1b4ee41596b4e754e5665f01ed6122b356f7b36ea0a02030804fac7fa0fdddfc` | +| `SwitchboardEnabled` | `(switchboard: address)` | `0x6909a9974e3eec619bc479ba882d30a5ef1219b72ab1ce6a354516e91be317b8` | ## SocketBatcher -| Event | Arguments | Topic | -| ----- | --------- | ----- | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| Event | Arguments | Topic | +| ---------------------------- | ---------------------------------------- | -------------------------------------------------------------------- | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | ## SocketFeeManager -| Event | Arguments | Topic | -| ----- | --------- | ----- | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | -| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | -| `SocketFeesUpdated` | `(oldFees: uint256, newFees: uint256)` | `0xcbd4d756fb6198bbcc2e4013cce929f504ad46e9d97c543ef9a8dfea3e407053` | +| Event | Arguments | Topic | +| ---------------------------- | ---------------------------------------- | -------------------------------------------------------------------- | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | +| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | +| `SocketFeesUpdated` | `(oldFees: uint256, newFees: uint256)` | `0xcbd4d756fb6198bbcc2e4013cce929f504ad46e9d97c543ef9a8dfea3e407053` | ## FeesManager -| Event | Arguments | Topic | -| ----- | --------- | ----- | -| `CreditsBlocked` | `(requestCount: uint40, consumeFrom: address, amount: uint256)` | `0xf037c15aef41440aa823cf1fdeaea332105d8b23d52557f6670189b5d76f1eed` | -| `CreditsTransferred` | `(from: address, to: address, amount: uint256)` | `0xed198cadddd93e734cbf04cb1c3226d9bafaeb504cedbd8ee36b830b0cb9e7a5` | -| `CreditsUnblocked` | `(requestCount: uint40, consumeFrom: address)` | `0x45db29ef2701319155cac058aa2f56ce1f73e0e238161d3db9f8c9a47655210d` | -| `CreditsUnblockedAndAssigned` | `(requestCount: uint40, consumeFrom: address, transmitter: address, amount: uint256)` | `0x38fd327622576a468e1b2818b00f50c8854703633ef8e583e1f31662888ffac2` | -| `CreditsUnwrapped` | `(consumeFrom: address, amount: uint256)` | `0xdcc9473b722b4c953617ab373840b365298a520bc7f20ce94fa7314f4a857774` | -| `CreditsWrapped` | `(consumeFrom: address, amount: uint256)` | `0x40246503613721eb4acf4020c6c56b6a16e5d08713316db0bea5210e8819c592` | -| `Deposited` | `(chainSlug: uint32, token: address, depositTo: address, creditAmount: uint256, nativeAmount: uint256)` | `0x72aedd284699bbd7a987e6942b824cfd6c627e354cb5a0760ac5768acd473f4a` | -| `FeesPlugSet` | `(chainSlug: uint32, feesPlug: address)` | `0xa8c4be32b96cca895f1f0f4684e6b377b2c4513bc35eb57a13afb6b5efb2c0ce` | -| `FeesPoolSet` | `(feesPool: address)` | `0xd07af3fd70b48ab3c077a8d45c3a288498d905d0e3d1e65bc171f6c2e890d8ef` | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| Event | Arguments | Topic | +| ----------------------------- | ------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | +| `CreditsBlocked` | `(requestCount: uint40, consumeFrom: address, amount: uint256)` | `0xf037c15aef41440aa823cf1fdeaea332105d8b23d52557f6670189b5d76f1eed` | +| `CreditsTransferred` | `(from: address, to: address, amount: uint256)` | `0xed198cadddd93e734cbf04cb1c3226d9bafaeb504cedbd8ee36b830b0cb9e7a5` | +| `CreditsUnblocked` | `(requestCount: uint40, consumeFrom: address)` | `0x45db29ef2701319155cac058aa2f56ce1f73e0e238161d3db9f8c9a47655210d` | +| `CreditsUnblockedAndAssigned` | `(requestCount: uint40, consumeFrom: address, transmitter: address, amount: uint256)` | `0x38fd327622576a468e1b2818b00f50c8854703633ef8e583e1f31662888ffac2` | +| `CreditsUnwrapped` | `(consumeFrom: address, amount: uint256)` | `0xdcc9473b722b4c953617ab373840b365298a520bc7f20ce94fa7314f4a857774` | +| `CreditsWrapped` | `(consumeFrom: address, amount: uint256)` | `0x40246503613721eb4acf4020c6c56b6a16e5d08713316db0bea5210e8819c592` | +| `Deposited` | `(chainSlug: uint32, token: address, depositTo: address, creditAmount: uint256, nativeAmount: uint256)` | `0x72aedd284699bbd7a987e6942b824cfd6c627e354cb5a0760ac5768acd473f4a` | +| `FeesPlugSet` | `(chainSlug: uint32, feesPlug: address)` | `0xa8c4be32b96cca895f1f0f4684e6b377b2c4513bc35eb57a13afb6b5efb2c0ce` | +| `FeesPoolSet` | `(feesPool: address)` | `0xd07af3fd70b48ab3c077a8d45c3a288498d905d0e3d1e65bc171f6c2e890d8ef` | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | ## FeesPool -| Event | Arguments | Topic | -| ----- | --------- | ----- | -| `NativeDeposited` | `(from: address, amount: uint256)` | `0xb5d7700fb0cf415158b8db7cc7c39f0eab16a825c92e221404b4c8bb099b4bbb` | -| `NativeWithdrawn` | `(success: bool, to: address, amount: uint256)` | `0xa81f1c8490022ee829d2e1a231053f5dbecad46caee71f6ea38a9db663a3f12b` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | -| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | +| Event | Arguments | Topic | +| ---------------------------- | ----------------------------------------------- | -------------------------------------------------------------------- | +| `NativeDeposited` | `(from: address, amount: uint256)` | `0xb5d7700fb0cf415158b8db7cc7c39f0eab16a825c92e221404b4c8bb099b4bbb` | +| `NativeWithdrawn` | `(success: bool, to: address, amount: uint256)` | `0xa81f1c8490022ee829d2e1a231053f5dbecad46caee71f6ea38a9db663a3f12b` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | +| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | ## AddressResolver -| Event | Arguments | Topic | -| ----- | --------- | ----- | -| `AsyncDeployerUpdated` | `(asyncDeployer_: address)` | `0x4df9cdd01544e8f6b0326650bc0b55611f47ce5ba2faa522d21fb675e9fc1f73` | -| `ContractAddressUpdated` | `(contractId_: bytes32, contractAddress_: address)` | `0xdf5ec2c15e11ce657bb21bc09c0b5ba95e315b4dba9934c6e311f47559babf28` | -| `DefaultAuctionManagerUpdated` | `(defaultAuctionManager_: address)` | `0x60f296739208a505ead7fb622df0f76b7791b824481b120a2300bdaf85e3e3d6` | -| `DeployForwarderUpdated` | `(deployForwarder_: address)` | `0x237b9bc9fef7508a02ca9ccca81f6965e500064a58024cae1218035da865fd2b` | -| `FeesManagerUpdated` | `(feesManager_: address)` | `0x94e67aa1341a65767dfde81e62fd265bfbade1f5744bfd3cd73f99a6eca0572a` | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `WatcherUpdated` | `(watcher_: address)` | `0xc13081d38d92b454cdb6ca20bbc65c12fa43a7a14a1529204ced5b6350052bb0` | +| Event | Arguments | Topic | +| ------------------------------ | --------------------------------------------------- | -------------------------------------------------------------------- | +| `AsyncDeployerUpdated` | `(asyncDeployer_: address)` | `0x4df9cdd01544e8f6b0326650bc0b55611f47ce5ba2faa522d21fb675e9fc1f73` | +| `ContractAddressUpdated` | `(contractId_: bytes32, contractAddress_: address)` | `0xdf5ec2c15e11ce657bb21bc09c0b5ba95e315b4dba9934c6e311f47559babf28` | +| `DefaultAuctionManagerUpdated` | `(defaultAuctionManager_: address)` | `0x60f296739208a505ead7fb622df0f76b7791b824481b120a2300bdaf85e3e3d6` | +| `DeployForwarderUpdated` | `(deployForwarder_: address)` | `0x237b9bc9fef7508a02ca9ccca81f6965e500064a58024cae1218035da865fd2b` | +| `FeesManagerUpdated` | `(feesManager_: address)` | `0x94e67aa1341a65767dfde81e62fd265bfbade1f5744bfd3cd73f99a6eca0572a` | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `WatcherUpdated` | `(watcher_: address)` | `0xc13081d38d92b454cdb6ca20bbc65c12fa43a7a14a1529204ced5b6350052bb0` | ## AsyncDeployer -| Event | Arguments | Topic | -| ----- | --------- | ----- | -| `AsyncPromiseDeployed` | `(newAsyncPromise: address, salt: bytes32)` | `0xb6c5491cf83e09749b1a4dd6a9f07b0e925fcb0a915ac8c2b40e8ab28191c270` | -| `ForwarderDeployed` | `(newForwarder: address, salt: bytes32)` | `0x4dbbecb9cf9c8b93da9743a2b48ea52efe68d69230ab1c1b711891d9d223b29f` | -| `ImplementationUpdated` | `(contractName: string, newImplementation: address)` | `0xa1e41aa2c2f3f20d9b63ac06b634d2788768d6034f3d9192cdf7d07374bb16f4` | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| Event | Arguments | Topic | +| ---------------------------- | ---------------------------------------------------- | -------------------------------------------------------------------- | +| `AsyncPromiseDeployed` | `(newAsyncPromise: address, salt: bytes32)` | `0xb6c5491cf83e09749b1a4dd6a9f07b0e925fcb0a915ac8c2b40e8ab28191c270` | +| `ForwarderDeployed` | `(newForwarder: address, salt: bytes32)` | `0x4dbbecb9cf9c8b93da9743a2b48ea52efe68d69230ab1c1b711891d9d223b29f` | +| `ImplementationUpdated` | `(contractName: string, newImplementation: address)` | `0xa1e41aa2c2f3f20d9b63ac06b634d2788768d6034f3d9192cdf7d07374bb16f4` | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | ## AsyncPromise -| Event | Arguments | Topic | -| ----- | --------- | ----- | +| Event | Arguments | Topic | +| ------------- | ------------------- | -------------------------------------------------------------------- | | `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | ## DeployForwarder -| Event | Arguments | Topic | -| ----- | --------- | ----- | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| Event | Arguments | Topic | +| ---------------------------- | ---------------------------------------- | -------------------------------------------------------------------- | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | ## Forwarder -| Event | Arguments | Topic | -| ----- | --------- | ----- | +| Event | Arguments | Topic | +| ------------- | ------------------- | -------------------------------------------------------------------- | | `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | ## ProxyFactory -| Event | Arguments | Topic | -| ----- | --------- | ----- | -| `AdminChanged` | `(proxy: address, admin: address)` | `0x7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f` | -| `Deployed` | `(proxy: address, implementation: address, admin: address)` | `0xc95935a66d15e0da5e412aca0ad27ae891d20b2fb91cf3994b6a3bf2b8178082` | -| `Upgraded` | `(proxy: address, implementation: address)` | `0x5d611f318680d00598bb735d61bacf0c514c6b50e1e5ad30040a4df2b12791c7` | +| Event | Arguments | Topic | +| -------------- | ----------------------------------------------------------- | -------------------------------------------------------------------- | +| `AdminChanged` | `(proxy: address, admin: address)` | `0x7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f` | +| `Deployed` | `(proxy: address, implementation: address, admin: address)` | `0xc95935a66d15e0da5e412aca0ad27ae891d20b2fb91cf3994b6a3bf2b8178082` | +| `Upgraded` | `(proxy: address, implementation: address)` | `0x5d611f318680d00598bb735d61bacf0c514c6b50e1e5ad30040a4df2b12791c7` | ## TestUSDC -| Event | Arguments | Topic | -| ----- | --------- | ----- | +| Event | Arguments | Topic | +| ---------- | ----------------------------------------------------- | -------------------------------------------------------------------- | | `Approval` | `(owner: address, spender: address, amount: uint256)` | `0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925` | -| `Transfer` | `(from: address, to: address, amount: uint256)` | `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef` | +| `Transfer` | `(from: address, to: address, amount: uint256)` | `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef` | ## ContractFactoryPlug -| Event | Arguments | Topic | -| ----- | --------- | ----- | -| `ConnectorPlugDisconnected` | `()` | `0xc2af098c82dba3c4b00be8bda596d62d13b98a87b42626fefa67e0bb0e198fdd` | -| `Deployed` | `(addr: address, salt: bytes32, returnData: bytes)` | `0x1246c6f8fd9f4abc542c7c8c8f793cfcde6b67aed1976a38aa134fc24af2dfe3` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | -| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | +| Event | Arguments | Topic | +| ---------------------------- | --------------------------------------------------- | -------------------------------------------------------------------- | +| `ConnectorPlugDisconnected` | `()` | `0xc2af098c82dba3c4b00be8bda596d62d13b98a87b42626fefa67e0bb0e198fdd` | +| `Deployed` | `(addr: address, salt: bytes32, returnData: bytes)` | `0x1246c6f8fd9f4abc542c7c8c8f793cfcde6b67aed1976a38aa134fc24af2dfe3` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | +| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | ## FeesPlug -| Event | Arguments | Topic | -| ----- | --------- | ----- | -| `ConnectorPlugDisconnected` | `()` | `0xc2af098c82dba3c4b00be8bda596d62d13b98a87b42626fefa67e0bb0e198fdd` | -| `FeesDeposited` | `(token: address, receiver: address, creditAmount: uint256, nativeAmount: uint256)` | `0xeb4e1b24b7fe377de69f80f7380bda5ba4b43176c6a4d300a3be9009c49f4228` | -| `FeesWithdrawn` | `(token: address, receiver: address, amount: uint256)` | `0x5e110f8bc8a20b65dcc87f224bdf1cc039346e267118bae2739847f07321ffa8` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | -| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | -| `TokenRemovedFromWhitelist` | `(token: address)` | `0xdd2e6d9f52cbe8f695939d018b7d4a216dc613a669876163ac548b916489d917` | -| `TokenWhitelisted` | `(token: address)` | `0x6a65f90b1a644d2faac467a21e07e50e3f8fa5846e26231d30ae79a417d3d262` | +| Event | Arguments | Topic | +| ---------------------------- | ----------------------------------------------------------------------------------- | -------------------------------------------------------------------- | +| `ConnectorPlugDisconnected` | `()` | `0xc2af098c82dba3c4b00be8bda596d62d13b98a87b42626fefa67e0bb0e198fdd` | +| `FeesDeposited` | `(token: address, receiver: address, creditAmount: uint256, nativeAmount: uint256)` | `0xeb4e1b24b7fe377de69f80f7380bda5ba4b43176c6a4d300a3be9009c49f4228` | +| `FeesWithdrawn` | `(token: address, receiver: address, amount: uint256)` | `0x5e110f8bc8a20b65dcc87f224bdf1cc039346e267118bae2739847f07321ffa8` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | +| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | +| `TokenRemovedFromWhitelist` | `(token: address)` | `0xdd2e6d9f52cbe8f695939d018b7d4a216dc613a669876163ac548b916489d917` | +| `TokenWhitelisted` | `(token: address)` | `0x6a65f90b1a644d2faac467a21e07e50e3f8fa5846e26231d30ae79a417d3d262` | ## Configurations -| Event | Arguments | Topic | -| ----- | --------- | ----- | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `IsValidPlugSet` | `(appGateway: address, chainSlug: uint32, plug: address, isValid: bool)` | `0x61cccc7387868fc741379c7acd9dd346e0ca2e5c067dc5b156fbbc55b1c2fcf5` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `PlugAdded` | `(appGatewayId: bytes32, chainSlug: uint32, plug: address)` | `0x7b3e14230a721c4737d275f9a63b92c44cb657bcfddbe6fe9b4d9cd9bd8d4a95` | -| `SocketSet` | `(chainSlug: uint32, socket: address)` | `0x5b13a5470e66a2ec5e9b32af5f9e23fe304864892918c60fffd22509ca73ac97` | -| `SwitchboardSet` | `(chainSlug: uint32, sbType: bytes32, switchboard: address)` | `0x6273f161f4a795e66ef3585d9b4442ef3796b32337157fdfb420b5281e4cf2e3` | +| Event | Arguments | Topic | +| ---------------------------- | ------------------------------------------------------------------------ | -------------------------------------------------------------------- | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `IsValidPlugSet` | `(appGateway: address, chainSlug: uint32, plug: address, isValid: bool)` | `0x61cccc7387868fc741379c7acd9dd346e0ca2e5c067dc5b156fbbc55b1c2fcf5` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `PlugAdded` | `(appGatewayId: bytes32, chainSlug: uint32, plug: address)` | `0x7b3e14230a721c4737d275f9a63b92c44cb657bcfddbe6fe9b4d9cd9bd8d4a95` | +| `SocketSet` | `(chainSlug: uint32, socket: address)` | `0x5b13a5470e66a2ec5e9b32af5f9e23fe304864892918c60fffd22509ca73ac97` | +| `SwitchboardSet` | `(chainSlug: uint32, sbType: bytes32, switchboard: address)` | `0x6273f161f4a795e66ef3585d9b4442ef3796b32337157fdfb420b5281e4cf2e3` | ## PromiseResolver -| Event | Arguments | Topic | -| ----- | --------- | ----- | -| `MarkedRevert` | `(payloadId: bytes32, isRevertingOnchain: bool)` | `0xcf1fd844cb4d32cbebb5ca6ce4ac834fe98da3ddac44deb77fffd22ad933824c` | -| `PromiseNotResolved` | `(payloadId: bytes32, asyncPromise: address)` | `0xbcf0d0c678940566e9e64f0c871439395bd5fb5c39bca3547b126fe6ee467937` | -| `PromiseResolved` | `(payloadId: bytes32, asyncPromise: address)` | `0x1b1b5810494fb3e17f7c46547e6e67cd6ad3e6001ea6fb7d12ea0241ba13c4ba` | +| Event | Arguments | Topic | +| -------------------- | ------------------------------------------------ | -------------------------------------------------------------------- | +| `MarkedRevert` | `(payloadId: bytes32, isRevertingOnchain: bool)` | `0xcf1fd844cb4d32cbebb5ca6ce4ac834fe98da3ddac44deb77fffd22ad933824c` | +| `PromiseNotResolved` | `(payloadId: bytes32, asyncPromise: address)` | `0xbcf0d0c678940566e9e64f0c871439395bd5fb5c39bca3547b126fe6ee467937` | +| `PromiseResolved` | `(payloadId: bytes32, asyncPromise: address)` | `0x1b1b5810494fb3e17f7c46547e6e67cd6ad3e6001ea6fb7d12ea0241ba13c4ba` | ## RequestHandler -| Event | Arguments | Topic | -| ----- | --------- | ----- | -| `FeesIncreased` | `(requestCount: uint40, newMaxFees: uint256)` | `0xf258fca4e49b803ee2a4c2e33b6fcf18bc3982df21f111c00677025bf1ccbb6a` | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `RequestCancelled` | `(requestCount: uint40)` | `0xff191657769be72fc08def44c645014c60d18cb24b9ca05c9a33406a28253245` | -| `RequestCompletedWithErrors` | `(requestCount: uint40)` | `0xd8d9915dc14b5a29b66cb263e1ea1e99e60418fc21d97f0fbf09cae1281291e2` | -| `RequestSettled` | `(requestCount: uint40, winner: address)` | `0x1234f98acbe1548b214f4528461a5377f1e2349569c04caa59325e488e7d2aa4` | -| `RequestSubmitted` | `(hasWrite: bool, requestCount: uint40, totalEstimatedWatcherFees: uint256, requestParams: tuple, payloadParamsArray: tuple[])` | `0x762bac43d5d7689b8911c5654a9d5550804373cead33bc98282067e6166e518f` | +| Event | Arguments | Topic | +| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | +| `FeesIncreased` | `(requestCount: uint40, newMaxFees: uint256)` | `0xf258fca4e49b803ee2a4c2e33b6fcf18bc3982df21f111c00677025bf1ccbb6a` | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `RequestCancelled` | `(requestCount: uint40)` | `0xff191657769be72fc08def44c645014c60d18cb24b9ca05c9a33406a28253245` | +| `RequestCompletedWithErrors` | `(requestCount: uint40)` | `0xd8d9915dc14b5a29b66cb263e1ea1e99e60418fc21d97f0fbf09cae1281291e2` | +| `RequestSettled` | `(requestCount: uint40, winner: address)` | `0x1234f98acbe1548b214f4528461a5377f1e2349569c04caa59325e488e7d2aa4` | +| `RequestSubmitted` | `(hasWrite: bool, requestCount: uint40, totalEstimatedWatcherFees: uint256, requestParams: tuple, payloadParamsArray: tuple[])` | `0x762bac43d5d7689b8911c5654a9d5550804373cead33bc98282067e6166e518f` | ## Watcher -| Event | Arguments | Topic | -| ----- | --------- | ----- | -| `AppGatewayCallFailed` | `(triggerId: bytes32)` | `0xcaf8475fdade8465ea31672463949e6cf1797fdcdd11eeddbbaf857e1e5907b7` | -| `CalledAppGateway` | `(triggerId: bytes32)` | `0xf659ffb3875368f54fb4ab8f5412ac4518af79701a48076f7a58d4448e4bdd0b` | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `TriggerFailed` | `(triggerId: bytes32)` | `0x4386783bb0f7cad4ba12f033dbec03dc3441e7757a122f3097a7a4d945c98040` | -| `TriggerFeesSet` | `(triggerFees: uint256)` | `0x7df3967b7c8727af5ac0ee9825d88aafeb899d769bc428b91f8967fa0b623084` | -| `TriggerSucceeded` | `(triggerId: bytes32)` | `0x92d20fbcbf31370b8218e10ed00c5aad0e689022da30a08905ba5ced053219eb` | +| Event | Arguments | Topic | +| ---------------------------- | ---------------------------------------- | -------------------------------------------------------------------- | +| `AppGatewayCallFailed` | `(triggerId: bytes32)` | `0xcaf8475fdade8465ea31672463949e6cf1797fdcdd11eeddbbaf857e1e5907b7` | +| `CalledAppGateway` | `(triggerId: bytes32)` | `0xf659ffb3875368f54fb4ab8f5412ac4518af79701a48076f7a58d4448e4bdd0b` | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `TriggerFailed` | `(triggerId: bytes32)` | `0x4386783bb0f7cad4ba12f033dbec03dc3441e7757a122f3097a7a4d945c98040` | +| `TriggerFeesSet` | `(triggerFees: uint256)` | `0x7df3967b7c8727af5ac0ee9825d88aafeb899d769bc428b91f8967fa0b623084` | +| `TriggerSucceeded` | `(triggerId: bytes32)` | `0x92d20fbcbf31370b8218e10ed00c5aad0e689022da30a08905ba5ced053219eb` | ## FastSwitchboard -| Event | Arguments | Topic | -| ----- | --------- | ----- | -| `Attested` | `(payloadId_: bytes32, watcher: address)` | `0x3d83c7bc55c269e0bc853ddc0d7b9fca30216ecc43779acb4e36b7e0ad1c71e4` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | -| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | +| Event | Arguments | Topic | +| ---------------------------- | ----------------------------------------- | -------------------------------------------------------------------- | +| `Attested` | `(payloadId_: bytes32, watcher: address)` | `0x3d83c7bc55c269e0bc853ddc0d7b9fca30216ecc43779acb4e36b7e0ad1c71e4` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `RoleGranted` | `(role: bytes32, grantee: address)` | `0x2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f3` | +| `RoleRevoked` | `(role: bytes32, revokee: address)` | `0x155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a52` | ## ReadPrecompile -| Event | Arguments | Topic | -| ----- | --------- | ----- | -| `ExpiryTimeSet` | `(expiryTime: uint256)` | `0x07e837e13ad9a34715a6bd45f49bbf12de19f06df79cb0be12b3a7d7f2397fa9` | -| `ReadFeesSet` | `(readFees: uint256)` | `0xc674cb6dde3a59f84dbf226832e606ffc54ac8a169e1568fc834c7813010f926` | +| Event | Arguments | Topic | +| --------------- | ---------------------------------------------------------------------- | -------------------------------------------------------------------- | +| `ExpiryTimeSet` | `(expiryTime: uint256)` | `0x07e837e13ad9a34715a6bd45f49bbf12de19f06df79cb0be12b3a7d7f2397fa9` | +| `ReadFeesSet` | `(readFees: uint256)` | `0xc674cb6dde3a59f84dbf226832e606ffc54ac8a169e1568fc834c7813010f926` | | `ReadRequested` | `(transaction: tuple, readAtBlockNumber: uint256, payloadId: bytes32)` | `0x42d9c65d4f6e45462ae6206adb3e388e046b7daa1dc8699d9380cac72ff5db0b` | ## SchedulePrecompile -| Event | Arguments | Topic | -| ----- | --------- | ----- | -| `ExpiryTimeSet` | `(expiryTime_: uint256)` | `0x07e837e13ad9a34715a6bd45f49bbf12de19f06df79cb0be12b3a7d7f2397fa9` | -| `MaxScheduleDelayInSecondsSet` | `(maxScheduleDelayInSeconds_: uint256)` | `0xfd5e4f0e96753ffb08a583390c2f151c51001d8e560625ab93b7fa7b4dac6d75` | -| `ScheduleCallbackFeesSet` | `(scheduleCallbackFees_: uint256)` | `0x82a2f41efc81ce7bfabc0affda7354dae42a3d09bd74a6196e8904b223138a52` | -| `ScheduleFeesPerSecondSet` | `(scheduleFeesPerSecond_: uint256)` | `0x7901a21229f6d2543d8676f53e21214d15f42513e7d46e0dcb510357222bdc7c` | -| `ScheduleRequested` | `(payloadId: bytes32, executeAfter: uint256, deadline: uint256)` | `0xd099d3e3d0f0e2c9c40e0066affeea125aab71d763b7ab0a279ccec3dff70b64` | -| `ScheduleResolved` | `(payloadId: bytes32)` | `0x925dc6c3ebffa07cac89d6e9675f1a5d04e045f2ed9a4fa442665935cb73e26b` | +| Event | Arguments | Topic | +| ------------------------------ | ---------------------------------------------------------------- | -------------------------------------------------------------------- | +| `ExpiryTimeSet` | `(expiryTime_: uint256)` | `0x07e837e13ad9a34715a6bd45f49bbf12de19f06df79cb0be12b3a7d7f2397fa9` | +| `MaxScheduleDelayInSecondsSet` | `(maxScheduleDelayInSeconds_: uint256)` | `0xfd5e4f0e96753ffb08a583390c2f151c51001d8e560625ab93b7fa7b4dac6d75` | +| `ScheduleCallbackFeesSet` | `(scheduleCallbackFees_: uint256)` | `0x82a2f41efc81ce7bfabc0affda7354dae42a3d09bd74a6196e8904b223138a52` | +| `ScheduleFeesPerSecondSet` | `(scheduleFeesPerSecond_: uint256)` | `0x7901a21229f6d2543d8676f53e21214d15f42513e7d46e0dcb510357222bdc7c` | +| `ScheduleRequested` | `(payloadId: bytes32, executeAfter: uint256, deadline: uint256)` | `0xd099d3e3d0f0e2c9c40e0066affeea125aab71d763b7ab0a279ccec3dff70b64` | +| `ScheduleResolved` | `(payloadId: bytes32)` | `0x925dc6c3ebffa07cac89d6e9675f1a5d04e045f2ed9a4fa442665935cb73e26b` | ## WritePrecompile -| Event | Arguments | Topic | -| ----- | --------- | ----- | -| `ChainMaxMsgValueLimitsUpdated` | `(chainSlug: uint32, maxMsgValueLimit: uint256)` | `0x439087d094fe7dacbba3f0c67032041952d8bd58a891e15af10ced28fed0eb91` | -| `ContractFactoryPlugSet` | `(chainSlug: uint32, contractFactoryPlug: address)` | `0x85bfa413b9e5e225278f51af2ac872988e0a9374263b118d963c50945ea888bb` | -| `ExpiryTimeSet` | `(expiryTime: uint256)` | `0x07e837e13ad9a34715a6bd45f49bbf12de19f06df79cb0be12b3a7d7f2397fa9` | -| `FeesSet` | `(writeFees: uint256)` | `0x3346af6da1932164d501f2ec28f8c5d686db5828a36b77f2da4332d89184fe7b` | -| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | -| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | -| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | -| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | -| `WriteProofRequested` | `(transmitter: address, digest: bytes32, prevBatchDigestHash: bytes32, deadline: uint256, payloadParams: tuple)` | `0x3247df5b4e8df4ac60c2c1f803b404ee16bc9d84a6b7649865464a8a397b9acb` | -| `WriteProofUploaded` | `(payloadId: bytes32, proof: bytes)` | `0xd8fe3a99a88c9630360418877afdf14e3e79f0f25fee162aeb230633ea740156` | - +| Event | Arguments | Topic | +| ------------------------------- | ---------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | +| `ChainMaxMsgValueLimitsUpdated` | `(chainSlug: uint32, maxMsgValueLimit: uint256)` | `0x439087d094fe7dacbba3f0c67032041952d8bd58a891e15af10ced28fed0eb91` | +| `ContractFactoryPlugSet` | `(chainSlug: uint32, contractFactoryPlug: address)` | `0x85bfa413b9e5e225278f51af2ac872988e0a9374263b118d963c50945ea888bb` | +| `ExpiryTimeSet` | `(expiryTime: uint256)` | `0x07e837e13ad9a34715a6bd45f49bbf12de19f06df79cb0be12b3a7d7f2397fa9` | +| `FeesSet` | `(writeFees: uint256)` | `0x3346af6da1932164d501f2ec28f8c5d686db5828a36b77f2da4332d89184fe7b` | +| `Initialized` | `(version: uint64)` | `0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2` | +| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | +| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | +| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `WriteProofRequested` | `(transmitter: address, digest: bytes32, prevBatchDigestHash: bytes32, deadline: uint256, payloadParams: tuple)` | `0x3247df5b4e8df4ac60c2c1f803b404ee16bc9d84a6b7649865464a8a397b9acb` | +| `WriteProofUploaded` | `(payloadId: bytes32, proof: bytes)` | `0xd8fe3a99a88c9630360418877afdf14e3e79f0f25fee162aeb230633ea740156` | diff --git a/FunctionSignatures.md b/FunctionSignatures.md index 7837a5d6..be1d1ac8 100644 --- a/FunctionSignatures.md +++ b/FunctionSignatures.md @@ -2,559 +2,558 @@ ## AuctionManager -| Function | Signature | -| -------- | --------- | -| `addressResolver__` | `0x6a750469` | -| `asyncDeployer__` | `0x2a39e801` | -| `auctionEndDelaySeconds` | `0x9087dfdb` | -| `auctionManager` | `0xb0192f9a` | -| `auctionStatus` | `0xd7d5fbf6` | -| `bid` | `0xfcdf49c2` | -| `bidTimeout` | `0x94090d0b` | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `consumeFrom` | `0x40dd78be` | -| `creationCodeWithArgs` | `0xc126dcc4` | -| `deployForwarder__` | `0xd4e3b034` | -| `endAuction` | `0x1212e653` | -| `evmxSlug` | `0x8bae77c2` | -| `expireBid` | `0x1dd5022c` | -| `feesManager__` | `0x70568b58` | -| `forwarderAddresses` | `0x5390fdcb` | -| `getOnChainAddress` | `0xb6abffd7` | -| `getOverrideParams` | `0x54f0a866` | -| `grantRole` | `0x2f2ff15d` | -| `handleRevert` | `0x44792f25` | -| `hasRole` | `0x91d14854` | -| `initialize` | `0x86891c9b` | -| `initializeOnChain` | `0x86f01739` | -| `isAsyncModifierSet` | `0xb69e0c4a` | -| `isValidPromise` | `0xb690b962` | -| `maxFees` | `0xe83e34b1` | -| `maxReAuctionCount` | `0xc367b376` | -| `onCompleteData` | `0xb52fa926` | -| `onRequestComplete` | `0x5ed1f959` | -| `overrideParams` | `0xec5490fe` | -| `owner` | `0x8da5cb5b` | +| Function | Signature | +| ---------------------------- | ------------ | +| `addressResolver__` | `0x6a750469` | +| `asyncDeployer__` | `0x2a39e801` | +| `auctionEndDelaySeconds` | `0x9087dfdb` | +| `auctionManager` | `0xb0192f9a` | +| `auctionStatus` | `0xd7d5fbf6` | +| `bid` | `0xfcdf49c2` | +| `bidTimeout` | `0x94090d0b` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `consumeFrom` | `0x40dd78be` | +| `creationCodeWithArgs` | `0xc126dcc4` | +| `deployForwarder__` | `0xd4e3b034` | +| `endAuction` | `0x1212e653` | +| `evmxSlug` | `0x8bae77c2` | +| `expireBid` | `0x1dd5022c` | +| `feesManager__` | `0x70568b58` | +| `forwarderAddresses` | `0x5390fdcb` | +| `getOnChainAddress` | `0xb6abffd7` | +| `getOverrideParams` | `0x54f0a866` | +| `grantRole` | `0x2f2ff15d` | +| `handleRevert` | `0x44792f25` | +| `hasRole` | `0x91d14854` | +| `initialize` | `0x86891c9b` | +| `initializeOnChain` | `0x86f01739` | +| `isAsyncModifierSet` | `0xb69e0c4a` | +| `isValidPromise` | `0xb690b962` | +| `maxFees` | `0xe83e34b1` | +| `maxReAuctionCount` | `0xc367b376` | +| `onCompleteData` | `0xb52fa926` | +| `onRequestComplete` | `0x5ed1f959` | +| `overrideParams` | `0xec5490fe` | +| `owner` | `0x8da5cb5b` | | `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `reAuctionCount` | `0x9b4b22d3` | -| `renounceOwnership` | `0x715018a6` | -| `requestOwnershipHandover` | `0x25692962` | -| `rescueFunds` | `0x6ccae054` | -| `revokeRole` | `0xd547741f` | -| `sbType` | `0x745de344` | -| `setAddress` | `0x85bf312c` | -| `setAuctionEndDelaySeconds` | `0x88606b1a` | -| `setMaxReAuctionCount` | `0x64c71403` | -| `transferOwnership` | `0xf2fde38b` | -| `watcher__` | `0x300bb063` | -| `winningBids` | `0x9133f232` | +| `reAuctionCount` | `0x9b4b22d3` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | +| `revokeRole` | `0xd547741f` | +| `sbType` | `0x745de344` | +| `setAddress` | `0x85bf312c` | +| `setAuctionEndDelaySeconds` | `0x88606b1a` | +| `setMaxReAuctionCount` | `0x64c71403` | +| `transferOwnership` | `0xf2fde38b` | +| `watcher__` | `0x300bb063` | +| `winningBids` | `0x9133f232` | ## Socket -| Function | Signature | -| -------- | --------- | -| `OFF_CHAIN_CALLER` | `0xcb2cb4f6` | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `chainSlug` | `0xb349ba65` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `connect` | `0xb3bde1aa` | -| `disableSwitchboard` | `0xe545b261` | -| `enableSwitchboard` | `0xf97a498a` | -| `execute` | `0xafa8b480` | -| `getPlugConfig` | `0xf9778ee0` | -| `grantRole` | `0x2f2ff15d` | -| `hasRole` | `0x91d14854` | -| `isValidSwitchboard` | `0xb2d67675` | -| `maxCopyBytes` | `0x212249d4` | -| `owner` | `0x8da5cb5b` | +| Function | Signature | +| ---------------------------- | ------------ | +| `OFF_CHAIN_CALLER` | `0xcb2cb4f6` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `chainSlug` | `0xb349ba65` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `connect` | `0xb3bde1aa` | +| `disableSwitchboard` | `0xe545b261` | +| `enableSwitchboard` | `0xf97a498a` | +| `execute` | `0xafa8b480` | +| `getPlugConfig` | `0xf9778ee0` | +| `grantRole` | `0x2f2ff15d` | +| `hasRole` | `0x91d14854` | +| `isValidSwitchboard` | `0xb2d67675` | +| `maxCopyBytes` | `0x212249d4` | +| `owner` | `0x8da5cb5b` | | `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `payloadExecuted` | `0x3eaeac3d` | -| `payloadIdToDigest` | `0x7c8552b2` | -| `registerSwitchboard` | `0x74f5b1fc` | -| `renounceOwnership` | `0x715018a6` | -| `requestOwnershipHandover` | `0x25692962` | -| `rescueFunds` | `0x6ccae054` | -| `revokeRole` | `0xd547741f` | -| `setMaxCopyBytes` | `0x4fc7d6e9` | -| `setSocketFeeManager` | `0x25bd97e5` | -| `simulate` | `0x91bf8275` | -| `socketFeeManager` | `0xde5b8838` | -| `transferOwnership` | `0xf2fde38b` | -| `triggerCounter` | `0x8b0021de` | -| `version` | `0x54fd4d50` | +| `payloadExecuted` | `0x3eaeac3d` | +| `payloadIdToDigest` | `0x7c8552b2` | +| `registerSwitchboard` | `0x74f5b1fc` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | +| `revokeRole` | `0xd547741f` | +| `setMaxCopyBytes` | `0x4fc7d6e9` | +| `setSocketFeeManager` | `0x25bd97e5` | +| `simulate` | `0x91bf8275` | +| `socketFeeManager` | `0xde5b8838` | +| `transferOwnership` | `0xf2fde38b` | +| `triggerCounter` | `0x8b0021de` | +| `version` | `0x54fd4d50` | ## SocketBatcher -| Function | Signature | -| -------- | --------- | -| `attestAndExecute` | `0x66c7748a` | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `owner` | `0x8da5cb5b` | +| Function | Signature | +| ---------------------------- | ------------ | +| `attestAndExecute` | `0x66c7748a` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `owner` | `0x8da5cb5b` | | `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `renounceOwnership` | `0x715018a6` | -| `requestOwnershipHandover` | `0x25692962` | -| `rescueFunds` | `0x6ccae054` | -| `socket__` | `0xc6a261d2` | -| `transferOwnership` | `0xf2fde38b` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | +| `socket__` | `0xc6a261d2` | +| `transferOwnership` | `0xf2fde38b` | ## SocketFeeManager -| Function | Signature | -| -------- | --------- | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `getMinSocketFees` | `0xd383b688` | -| `grantRole` | `0x2f2ff15d` | -| `hasRole` | `0x91d14854` | -| `owner` | `0x8da5cb5b` | +| Function | Signature | +| ---------------------------- | ------------ | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `getMinSocketFees` | `0xd383b688` | +| `grantRole` | `0x2f2ff15d` | +| `hasRole` | `0x91d14854` | +| `owner` | `0x8da5cb5b` | | `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `payAndCheckFees` | `0xd9d29ae3` | -| `renounceOwnership` | `0x715018a6` | -| `requestOwnershipHandover` | `0x25692962` | -| `rescueFunds` | `0x6ccae054` | -| `revokeRole` | `0xd547741f` | -| `setSocketFees` | `0x47a406f6` | -| `socketFees` | `0xab1b33a8` | -| `transferOwnership` | `0xf2fde38b` | +| `payAndCheckFees` | `0xd9d29ae3` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | +| `revokeRole` | `0xd547741f` | +| `setSocketFees` | `0x47a406f6` | +| `socketFees` | `0xab1b33a8` | +| `transferOwnership` | `0xf2fde38b` | ## FeesManager -| Function | Signature | -| -------- | --------- | -| `addressResolver__` | `0x6a750469` | +| Function | Signature | +| -------------------------------- | ------------ | +| `addressResolver__` | `0x6a750469` | | `approveAppGatewayWithSignature` | `0x94b649ec` | -| `approveAppGateways` | `0x86d23ab2` | -| `asyncDeployer__` | `0x2a39e801` | -| `blockCredits` | `0x9e434307` | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `deployForwarder__` | `0xd4e3b034` | -| `deposit` | `0x5671d329` | -| `evmxSlug` | `0x8bae77c2` | -| `feesManager__` | `0x70568b58` | -| `feesPlugs` | `0x23f5ee8a` | -| `feesPool` | `0x6b259690` | -| `getAvailableCredits` | `0xb065a8e5` | -| `initialize` | `0xbf2c8539` | -| `isApproved` | `0xa389783e` | -| `isCreditSpendable` | `0x4f8990fd` | -| `isNonceUsed` | `0xcab7e8eb` | -| `onRequestComplete` | `0x5ed1f959` | -| `owner` | `0x8da5cb5b` | -| `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `renounceOwnership` | `0x715018a6` | -| `requestBlockedCredits` | `0xb62d25ac` | -| `requestOwnershipHandover` | `0x25692962` | -| `rescueFunds` | `0x6ccae054` | -| `sbType` | `0x745de344` | -| `setFeesPlug` | `0xeab75f36` | -| `setFeesPool` | `0xd6684588` | -| `tokenOnChainBalances` | `0x3b27866d` | -| `transferCredits` | `0xf1686c89` | -| `transferOwnership` | `0xf2fde38b` | -| `unblockAndAssignCredits` | `0x01958181` | -| `unblockCredits` | `0xa0b32314` | -| `unwrap` | `0x7647691d` | -| `userCredits` | `0x20babb92` | -| `watcher__` | `0x300bb063` | -| `withdrawCredits` | `0xcfc6dbd9` | -| `wrap` | `0x023276f0` | +| `approveAppGateways` | `0x86d23ab2` | +| `asyncDeployer__` | `0x2a39e801` | +| `blockCredits` | `0x9e434307` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `deployForwarder__` | `0xd4e3b034` | +| `deposit` | `0x5671d329` | +| `evmxSlug` | `0x8bae77c2` | +| `feesManager__` | `0x70568b58` | +| `feesPlugs` | `0x23f5ee8a` | +| `feesPool` | `0x6b259690` | +| `getAvailableCredits` | `0xb065a8e5` | +| `initialize` | `0xbf2c8539` | +| `isApproved` | `0xa389783e` | +| `isCreditSpendable` | `0x4f8990fd` | +| `isNonceUsed` | `0xcab7e8eb` | +| `onRequestComplete` | `0x5ed1f959` | +| `owner` | `0x8da5cb5b` | +| `ownershipHandoverExpiresAt` | `0xfee81cf4` | +| `renounceOwnership` | `0x715018a6` | +| `requestBlockedCredits` | `0xb62d25ac` | +| `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | +| `sbType` | `0x745de344` | +| `setFeesPlug` | `0xeab75f36` | +| `setFeesPool` | `0xd6684588` | +| `tokenOnChainBalances` | `0x3b27866d` | +| `transferCredits` | `0xf1686c89` | +| `transferOwnership` | `0xf2fde38b` | +| `unblockAndAssignCredits` | `0x01958181` | +| `unblockCredits` | `0xa0b32314` | +| `unwrap` | `0x7647691d` | +| `userCredits` | `0x20babb92` | +| `watcher__` | `0x300bb063` | +| `withdrawCredits` | `0xcfc6dbd9` | +| `wrap` | `0x023276f0` | ## FeesPool -| Function | Signature | -| -------- | --------- | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `getBalance` | `0x12065fe0` | -| `grantRole` | `0x2f2ff15d` | -| `hasRole` | `0x91d14854` | -| `owner` | `0x8da5cb5b` | +| Function | Signature | +| ---------------------------- | ------------ | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `getBalance` | `0x12065fe0` | +| `grantRole` | `0x2f2ff15d` | +| `hasRole` | `0x91d14854` | +| `owner` | `0x8da5cb5b` | | `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `renounceOwnership` | `0x715018a6` | -| `requestOwnershipHandover` | `0x25692962` | -| `revokeRole` | `0xd547741f` | -| `transferOwnership` | `0xf2fde38b` | -| `withdraw` | `0xf3fef3a3` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `revokeRole` | `0xd547741f` | +| `transferOwnership` | `0xf2fde38b` | +| `withdraw` | `0xf3fef3a3` | ## AddressResolver -| Function | Signature | -| -------- | --------- | -| `asyncDeployer__` | `0x2a39e801` | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `contractAddresses` | `0xf689e892` | -| `defaultAuctionManager` | `0x8f27cdc6` | -| `deployForwarder__` | `0xd4e3b034` | -| `feesManager__` | `0x70568b58` | -| `initialize` | `0xc4d66de8` | -| `owner` | `0x8da5cb5b` | +| Function | Signature | +| ---------------------------- | ------------ | +| `asyncDeployer__` | `0x2a39e801` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `contractAddresses` | `0xf689e892` | +| `defaultAuctionManager` | `0x8f27cdc6` | +| `deployForwarder__` | `0xd4e3b034` | +| `feesManager__` | `0x70568b58` | +| `initialize` | `0xc4d66de8` | +| `owner` | `0x8da5cb5b` | | `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `renounceOwnership` | `0x715018a6` | -| `requestOwnershipHandover` | `0x25692962` | -| `rescueFunds` | `0x6ccae054` | -| `setAsyncDeployer` | `0xcb0ffff8` | -| `setContractAddress` | `0xe001f841` | -| `setDefaultAuctionManager` | `0xede8b4b5` | -| `setDeployForwarder` | `0xaeaee8a6` | -| `setFeesManager` | `0x1c89382a` | -| `setWatcher` | `0x24f48bc5` | -| `transferOwnership` | `0xf2fde38b` | -| `watcher__` | `0x300bb063` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | +| `setAsyncDeployer` | `0xcb0ffff8` | +| `setContractAddress` | `0xe001f841` | +| `setDefaultAuctionManager` | `0xede8b4b5` | +| `setDeployForwarder` | `0xaeaee8a6` | +| `setFeesManager` | `0x1c89382a` | +| `setWatcher` | `0x24f48bc5` | +| `transferOwnership` | `0xf2fde38b` | +| `watcher__` | `0x300bb063` | ## AsyncDeployer -| Function | Signature | -| -------- | --------- | -| `addressResolver__` | `0x6a750469` | -| `asyncDeployer__` | `0x2a39e801` | -| `asyncPromiseBeacon` | `0xc0fbc0ef` | -| `asyncPromiseCounter` | `0x97cdbf4c` | -| `asyncPromiseImplementation` | `0x59531b8d` | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `deployAsyncPromiseContract` | `0x9851be0b` | -| `deployForwarder__` | `0xd4e3b034` | -| `feesManager__` | `0x70568b58` | -| `forwarderBeacon` | `0x945709ae` | -| `forwarderImplementation` | `0xe38d60a1` | -| `getAsyncPromiseAddress` | `0x104f39b4` | -| `getForwarderAddress` | `0x48c0b3e0` | -| `getOrDeployForwarderContract` | `0x0aa178de` | -| `initialize` | `0x485cc955` | -| `owner` | `0x8da5cb5b` | -| `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `renounceOwnership` | `0x715018a6` | -| `requestOwnershipHandover` | `0x25692962` | -| `rescueFunds` | `0x6ccae054` | +| Function | Signature | +| ------------------------------- | ------------ | +| `addressResolver__` | `0x6a750469` | +| `asyncDeployer__` | `0x2a39e801` | +| `asyncPromiseBeacon` | `0xc0fbc0ef` | +| `asyncPromiseCounter` | `0x97cdbf4c` | +| `asyncPromiseImplementation` | `0x59531b8d` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `deployAsyncPromiseContract` | `0x9851be0b` | +| `deployForwarder__` | `0xd4e3b034` | +| `feesManager__` | `0x70568b58` | +| `forwarderBeacon` | `0x945709ae` | +| `forwarderImplementation` | `0xe38d60a1` | +| `getAsyncPromiseAddress` | `0x104f39b4` | +| `getForwarderAddress` | `0x48c0b3e0` | +| `getOrDeployForwarderContract` | `0x0aa178de` | +| `initialize` | `0x485cc955` | +| `owner` | `0x8da5cb5b` | +| `ownershipHandoverExpiresAt` | `0xfee81cf4` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | | `setAsyncPromiseImplementation` | `0xeb506eab` | -| `setForwarderImplementation` | `0x83b1e974` | -| `transferOwnership` | `0xf2fde38b` | -| `watcher__` | `0x300bb063` | +| `setForwarderImplementation` | `0x83b1e974` | +| `transferOwnership` | `0xf2fde38b` | +| `watcher__` | `0x300bb063` | ## AsyncPromise -| Function | Signature | -| -------- | --------- | +| Function | Signature | +| ------------------- | ------------ | | `addressResolver__` | `0x6a750469` | -| `asyncDeployer__` | `0x2a39e801` | -| `callbackData` | `0xef44c272` | -| `callbackSelector` | `0x2764f92f` | +| `asyncDeployer__` | `0x2a39e801` | +| `callbackData` | `0xef44c272` | +| `callbackSelector` | `0x2764f92f` | | `deployForwarder__` | `0xd4e3b034` | -| `exceededMaxCopy` | `0xaf598c7c` | -| `feesManager__` | `0x70568b58` | -| `initialize` | `0x0ece6089` | -| `localInvoker` | `0x45eb87f4` | +| `exceededMaxCopy` | `0xaf598c7c` | +| `feesManager__` | `0x70568b58` | +| `initialize` | `0x0ece6089` | +| `localInvoker` | `0x45eb87f4` | | `markOnchainRevert` | `0xd0e7af1b` | -| `markResolved` | `0x822d5d1f` | -| `requestCount` | `0x5badbe4c` | -| `rescueFunds` | `0x6ccae054` | -| `returnData` | `0xebddbaf6` | -| `state` | `0xc19d93fb` | -| `then` | `0x0bf2ba15` | -| `watcher__` | `0x300bb063` | +| `markResolved` | `0x822d5d1f` | +| `requestCount` | `0x5badbe4c` | +| `rescueFunds` | `0x6ccae054` | +| `returnData` | `0xebddbaf6` | +| `state` | `0xc19d93fb` | +| `then` | `0x0bf2ba15` | +| `watcher__` | `0x300bb063` | ## DeployForwarder -| Function | Signature | -| -------- | --------- | -| `addressResolver__` | `0x6a750469` | -| `asyncDeployer__` | `0x2a39e801` | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `deploy` | `0x940f11af` | -| `deployForwarder__` | `0xd4e3b034` | -| `deployerSwitchboardType` | `0xaa381f9a` | -| `feesManager__` | `0x70568b58` | -| `initialize` | `0x6133f985` | -| `owner` | `0x8da5cb5b` | +| Function | Signature | +| ---------------------------- | ------------ | +| `addressResolver__` | `0x6a750469` | +| `asyncDeployer__` | `0x2a39e801` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `deploy` | `0x940f11af` | +| `deployForwarder__` | `0xd4e3b034` | +| `deployerSwitchboardType` | `0xaa381f9a` | +| `feesManager__` | `0x70568b58` | +| `initialize` | `0x6133f985` | +| `owner` | `0x8da5cb5b` | | `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `renounceOwnership` | `0x715018a6` | -| `requestOwnershipHandover` | `0x25692962` | -| `rescueFunds` | `0x6ccae054` | -| `saltCounter` | `0xa04c6809` | -| `transferOwnership` | `0xf2fde38b` | -| `watcher__` | `0x300bb063` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | +| `saltCounter` | `0xa04c6809` | +| `transferOwnership` | `0xf2fde38b` | +| `watcher__` | `0x300bb063` | ## Forwarder -| Function | Signature | -| -------- | --------- | +| Function | Signature | +| ------------------- | ------------ | | `addressResolver__` | `0x6a750469` | -| `asyncDeployer__` | `0x2a39e801` | -| `chainSlug` | `0xb349ba65` | +| `asyncDeployer__` | `0x2a39e801` | +| `chainSlug` | `0xb349ba65` | | `deployForwarder__` | `0xd4e3b034` | -| `feesManager__` | `0x70568b58` | -| `getChainSlug` | `0x0b8c6568` | +| `feesManager__` | `0x70568b58` | +| `getChainSlug` | `0x0b8c6568` | | `getOnChainAddress` | `0x9da48789` | -| `initialize` | `0x647c576c` | -| `onChainAddress` | `0x8bd0b363` | -| `rescueFunds` | `0x6ccae054` | -| `watcher__` | `0x300bb063` | +| `initialize` | `0x647c576c` | +| `onChainAddress` | `0x8bd0b363` | +| `rescueFunds` | `0x6ccae054` | +| `watcher__` | `0x300bb063` | ## ProxyFactory -| Function | Signature | -| -------- | --------- | -| `adminOf` | `0x2abbef15` | -| `changeAdmin` | `0x1acfd02a` | -| `deploy` | `0x545e7c61` | -| `deployAndCall` | `0x4314f120` | -| `deployDeterministic` | `0x3729f922` | -| `deployDeterministicAndCall` | `0xa97b90d5` | -| `initCodeHash` | `0xdb4c545e` | +| Function | Signature | +| ----------------------------- | ------------ | +| `adminOf` | `0x2abbef15` | +| `changeAdmin` | `0x1acfd02a` | +| `deploy` | `0x545e7c61` | +| `deployAndCall` | `0x4314f120` | +| `deployDeterministic` | `0x3729f922` | +| `deployDeterministicAndCall` | `0xa97b90d5` | +| `initCodeHash` | `0xdb4c545e` | | `predictDeterministicAddress` | `0x5414dff0` | -| `upgrade` | `0x99a88ec4` | -| `upgradeAndCall` | `0x9623609d` | +| `upgrade` | `0x99a88ec4` | +| `upgradeAndCall` | `0x9623609d` | ## TestUSDC -| Function | Signature | -| -------- | --------- | +| Function | Signature | +| ------------------ | ------------ | | `DOMAIN_SEPARATOR` | `0x3644e515` | -| `allowance` | `0xdd62ed3e` | -| `approve` | `0x095ea7b3` | -| `balanceOf` | `0x70a08231` | -| `decimals` | `0x313ce567` | -| `mint` | `0x40c10f19` | -| `name` | `0x06fdde03` | -| `nonces` | `0x7ecebe00` | -| `owner` | `0x8da5cb5b` | -| `permit` | `0xd505accf` | -| `symbol` | `0x95d89b41` | -| `totalSupply` | `0x18160ddd` | -| `transfer` | `0xa9059cbb` | -| `transferFrom` | `0x23b872dd` | +| `allowance` | `0xdd62ed3e` | +| `approve` | `0x095ea7b3` | +| `balanceOf` | `0x70a08231` | +| `decimals` | `0x313ce567` | +| `mint` | `0x40c10f19` | +| `name` | `0x06fdde03` | +| `nonces` | `0x7ecebe00` | +| `owner` | `0x8da5cb5b` | +| `permit` | `0xd505accf` | +| `symbol` | `0x95d89b41` | +| `totalSupply` | `0x18160ddd` | +| `transfer` | `0xa9059cbb` | +| `transferFrom` | `0x23b872dd` | ## ContractFactoryPlug -| Function | Signature | -| -------- | --------- | -| `appGatewayId` | `0x1c335f49` | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `connectSocket` | `0x258d19c8` | -| `deployContract` | `0xa0695389` | -| `getAddress` | `0x94ca2cb5` | -| `grantRole` | `0x2f2ff15d` | -| `hasRole` | `0x91d14854` | -| `initSocket` | `0xa07d8545` | -| `isSocketInitialized` | `0x9a7d9a9b` | -| `overrides` | `0x4a85f041` | -| `owner` | `0x8da5cb5b` | +| Function | Signature | +| ---------------------------- | ------------ | +| `appGatewayId` | `0x1c335f49` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `connectSocket` | `0x258d19c8` | +| `deployContract` | `0xa0695389` | +| `getAddress` | `0x94ca2cb5` | +| `grantRole` | `0x2f2ff15d` | +| `hasRole` | `0x91d14854` | +| `initSocket` | `0xa07d8545` | +| `isSocketInitialized` | `0x9a7d9a9b` | +| `overrides` | `0x4a85f041` | +| `owner` | `0x8da5cb5b` | | `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `renounceOwnership` | `0x715018a6` | -| `requestOwnershipHandover` | `0x25692962` | -| `rescueFunds` | `0x6ccae054` | -| `revokeRole` | `0xd547741f` | -| `socket__` | `0xc6a261d2` | -| `transferOwnership` | `0xf2fde38b` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | +| `revokeRole` | `0xd547741f` | +| `socket__` | `0xc6a261d2` | +| `transferOwnership` | `0xf2fde38b` | ## Configurations -| Function | Signature | -| -------- | --------- | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `getPlugConfigs` | `0x8a028c38` | -| `initialize` | `0x485cc955` | -| `isValidPlug` | `0xec8aef74` | -| `owner` | `0x8da5cb5b` | +| Function | Signature | +| ---------------------------- | ------------ | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `getPlugConfigs` | `0x8a028c38` | +| `initialize` | `0x485cc955` | +| `isValidPlug` | `0xec8aef74` | +| `owner` | `0x8da5cb5b` | | `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `renounceOwnership` | `0x715018a6` | -| `requestOwnershipHandover` | `0x25692962` | -| `rescueFunds` | `0x6ccae054` | -| `setAppGatewayConfigs` | `0xd137fcbb` | -| `setIsValidPlug` | `0xf41332b0` | -| `setSocket` | `0x075c40be` | -| `setSwitchboard` | `0x61706f1e` | -| `sockets` | `0xb44a23ab` | -| `switchboards` | `0xaa539546` | -| `transferOwnership` | `0xf2fde38b` | -| `verifyConnections` | `0xa53b6fad` | -| `watcher__` | `0x300bb063` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | +| `setAppGatewayConfigs` | `0xd137fcbb` | +| `setIsValidPlug` | `0xf41332b0` | +| `setSocket` | `0x075c40be` | +| `setSwitchboard` | `0x61706f1e` | +| `sockets` | `0xb44a23ab` | +| `switchboards` | `0xaa539546` | +| `transferOwnership` | `0xf2fde38b` | +| `verifyConnections` | `0xa53b6fad` | +| `watcher__` | `0x300bb063` | ## PromiseResolver -| Function | Signature | -| -------- | --------- | -| `markRevert` | `0x56501015` | -| `rescueFunds` | `0x6ccae054` | +| Function | Signature | +| ----------------- | ------------ | +| `markRevert` | `0x56501015` | +| `rescueFunds` | `0x6ccae054` | | `resolvePromises` | `0xbf8484b8` | -| `watcher__` | `0x300bb063` | +| `watcher__` | `0x300bb063` | ## RequestHandler -| Function | Signature | -| -------- | --------- | -| `addressResolver__` | `0x6a750469` | -| `assignTransmitter` | `0xae5e9c48` | -| `asyncDeployer__` | `0x2a39e801` | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `cancelRequest` | `0x3b5fd6fb` | -| `cancelRequestForReverts` | `0x82970278` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `deployForwarder__` | `0xd4e3b034` | -| `feesManager__` | `0x70568b58` | -| `getBatchPayloadIds` | `0xfd83cd1f` | -| `getPayload` | `0xb48fd0fe` | -| `getPrecompileFees` | `0xabac263c` | -| `getRequest` | `0xcf39abf6` | -| `getRequestBatchIds` | `0xe138fadb` | -| `handleRevert` | `0xcc88d3f9` | -| `increaseFees` | `0x10205541` | -| `initialize` | `0x485cc955` | -| `nextBatchCount` | `0x333a3963` | -| `nextRequestCount` | `0xfef72893` | -| `owner` | `0x8da5cb5b` | -| `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `payloadCounter` | `0x550ce1d5` | -| `precompiles` | `0x9932450b` | -| `renounceOwnership` | `0x715018a6` | -| `requestOwnershipHandover` | `0x25692962` | -| `rescueFunds` | `0x6ccae054` | -| `setPrecompile` | `0x122e0042` | -| `setRequestPayloadCountLimit` | `0x8526582b` | -| `submitRequest` | `0xbb299a2c` | -| `transferOwnership` | `0xf2fde38b` | +| Function | Signature | +| ------------------------------ | ------------ | +| `addressResolver__` | `0x6a750469` | +| `assignTransmitter` | `0xae5e9c48` | +| `asyncDeployer__` | `0x2a39e801` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `cancelRequest` | `0x3b5fd6fb` | +| `cancelRequestForReverts` | `0x82970278` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `deployForwarder__` | `0xd4e3b034` | +| `feesManager__` | `0x70568b58` | +| `getBatchPayloadIds` | `0xfd83cd1f` | +| `getPayload` | `0xb48fd0fe` | +| `getPrecompileFees` | `0xabac263c` | +| `getRequest` | `0xcf39abf6` | +| `getRequestBatchIds` | `0xe138fadb` | +| `handleRevert` | `0xcc88d3f9` | +| `increaseFees` | `0x10205541` | +| `initialize` | `0x485cc955` | +| `nextBatchCount` | `0x333a3963` | +| `nextRequestCount` | `0xfef72893` | +| `owner` | `0x8da5cb5b` | +| `ownershipHandoverExpiresAt` | `0xfee81cf4` | +| `payloadCounter` | `0x550ce1d5` | +| `precompiles` | `0x9932450b` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | +| `setPrecompile` | `0x122e0042` | +| `setRequestPayloadCountLimit` | `0x8526582b` | +| `submitRequest` | `0xbb299a2c` | +| `transferOwnership` | `0xf2fde38b` | | `updateRequestAndProcessBatch` | `0x46464471` | -| `watcher__` | `0x300bb063` | +| `watcher__` | `0x300bb063` | ## Watcher -| Function | Signature | -| -------- | --------- | -| `addressResolver__` | `0x6a750469` | -| `appGatewayTemp` | `0x1394c029` | -| `asyncDeployer__` | `0x2a39e801` | -| `callAppGateways` | `0x0050bef1` | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `cancelRequest` | `0x50ad0779` | -| `clearQueue` | `0xf22cb874` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `configurations__` | `0x52a3bbeb` | -| `deployForwarder__` | `0xd4e3b034` | -| `evmxSlug` | `0x8bae77c2` | -| `feesManager__` | `0x70568b58` | -| `getCurrentRequestCount` | `0x5715abbb` | -| `getPayloadParams` | `0xae5eeb77` | -| `getPrecompileFees` | `0xabac263c` | -| `getRequestParams` | `0x71263d0d` | -| `increaseFees` | `0xe9b304da` | -| `initialize` | `0xaaf7fc1a` | -| `isAppGatewayCalled` | `0xa79da6c7` | -| `isNonceUsed` | `0x5d00bb12` | -| `isWatcher` | `0x84785ecd` | -| `latestAsyncPromise` | `0xb8a8ba52` | -| `owner` | `0x8da5cb5b` | +| Function | Signature | +| ---------------------------- | ------------ | +| `addressResolver__` | `0x6a750469` | +| `appGatewayTemp` | `0x1394c029` | +| `asyncDeployer__` | `0x2a39e801` | +| `callAppGateways` | `0x0050bef1` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `cancelRequest` | `0x50ad0779` | +| `clearQueue` | `0xf22cb874` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `configurations__` | `0x52a3bbeb` | +| `deployForwarder__` | `0xd4e3b034` | +| `evmxSlug` | `0x8bae77c2` | +| `feesManager__` | `0x70568b58` | +| `getCurrentRequestCount` | `0x5715abbb` | +| `getPayloadParams` | `0xae5eeb77` | +| `getPrecompileFees` | `0xabac263c` | +| `getRequestParams` | `0x71263d0d` | +| `increaseFees` | `0xe9b304da` | +| `initialize` | `0xaaf7fc1a` | +| `isAppGatewayCalled` | `0xa79da6c7` | +| `isNonceUsed` | `0x5d00bb12` | +| `isWatcher` | `0x84785ecd` | +| `latestAsyncPromise` | `0xb8a8ba52` | +| `owner` | `0x8da5cb5b` | | `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `payloadQueue` | `0x74f00ffb` | -| `promiseResolver__` | `0xdee152be` | -| `queue` | `0xf03ca7f7` | -| `queueAndSubmit` | `0xf0fb9665` | -| `renounceOwnership` | `0x715018a6` | -| `requestHandler__` | `0x55184561` | -| `requestOwnershipHandover` | `0x25692962` | -| `rescueFunds` | `0xa58c6fc5` | -| `setCoreContracts` | `0xefa891c4` | -| `setIsValidPlug` | `0x7fc82ff6` | -| `setTriggerFees` | `0xaeb30511` | -| `submitRequest` | `0x4890b5ef` | -| `transferOwnership` | `0xf2fde38b` | -| `triggerFees` | `0x73f76aec` | -| `triggerFromChainSlug` | `0xd12b4f12` | -| `triggerFromPlug` | `0x3b847d12` | -| `watcherMultiCall` | `0x8021e82b` | -| `watcher__` | `0x300bb063` | +| `payloadQueue` | `0x74f00ffb` | +| `promiseResolver__` | `0xdee152be` | +| `queue` | `0xf03ca7f7` | +| `queueAndSubmit` | `0xf0fb9665` | +| `renounceOwnership` | `0x715018a6` | +| `requestHandler__` | `0x55184561` | +| `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0xa58c6fc5` | +| `setCoreContracts` | `0xefa891c4` | +| `setIsValidPlug` | `0x7fc82ff6` | +| `setTriggerFees` | `0xaeb30511` | +| `submitRequest` | `0x4890b5ef` | +| `transferOwnership` | `0xf2fde38b` | +| `triggerFees` | `0x73f76aec` | +| `triggerFromChainSlug` | `0xd12b4f12` | +| `triggerFromPlug` | `0x3b847d12` | +| `watcherMultiCall` | `0x8021e82b` | +| `watcher__` | `0x300bb063` | ## FastSwitchboard -| Function | Signature | -| -------- | --------- | -| `allowPayload` | `0x31c23f66` | -| `attest` | `0x63671b60` | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `chainSlug` | `0xb349ba65` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `grantRole` | `0x2f2ff15d` | -| `hasRole` | `0x91d14854` | -| `isAttested` | `0xc13c2396` | -| `owner` | `0x8da5cb5b` | +| Function | Signature | +| ---------------------------- | ------------ | +| `allowPayload` | `0x31c23f66` | +| `attest` | `0x63671b60` | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `chainSlug` | `0xb349ba65` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `grantRole` | `0x2f2ff15d` | +| `hasRole` | `0x91d14854` | +| `isAttested` | `0xc13c2396` | +| `owner` | `0x8da5cb5b` | | `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `registerSwitchboard` | `0x74f5b1fc` | -| `renounceOwnership` | `0x715018a6` | -| `requestOwnershipHandover` | `0x25692962` | -| `rescueFunds` | `0x6ccae054` | -| `revokeRole` | `0xd547741f` | -| `socket__` | `0xc6a261d2` | -| `transferOwnership` | `0xf2fde38b` | +| `registerSwitchboard` | `0x74f5b1fc` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | +| `revokeRole` | `0xd547741f` | +| `socket__` | `0xc6a261d2` | +| `transferOwnership` | `0xf2fde38b` | ## ReadPrecompile -| Function | Signature | -| -------- | --------- | -| `expiryTime` | `0x99bc0aea` | -| `getPrecompileFees` | `0xb7a3d04c` | -| `handlePayload` | `0x1d5e1d98` | -| `readFees` | `0xe06357a2` | -| `rescueFunds` | `0x6ccae054` | -| `resolvePayload` | `0xea92e825` | -| `setExpiryTime` | `0x30fc4cff` | -| `setFees` | `0x3d18678e` | +| Function | Signature | +| ------------------------------ | ------------ | +| `expiryTime` | `0x99bc0aea` | +| `getPrecompileFees` | `0xb7a3d04c` | +| `handlePayload` | `0x1d5e1d98` | +| `readFees` | `0xe06357a2` | +| `rescueFunds` | `0x6ccae054` | +| `resolvePayload` | `0xea92e825` | +| `setExpiryTime` | `0x30fc4cff` | +| `setFees` | `0x3d18678e` | | `validateAndGetPrecompileData` | `0xab172aab` | -| `watcher__` | `0x300bb063` | +| `watcher__` | `0x300bb063` | ## SchedulePrecompile -| Function | Signature | -| -------- | --------- | -| `expiryTime` | `0x99bc0aea` | -| `getPrecompileFees` | `0xb7a3d04c` | -| `handlePayload` | `0x1d5e1d98` | -| `maxScheduleDelayInSeconds` | `0x3ef01cdb` | -| `rescueFunds` | `0x6ccae054` | -| `resolvePayload` | `0xea92e825` | -| `scheduleCallbackFees` | `0x4c5b6007` | -| `scheduleFeesPerSecond` | `0x852a74c1` | -| `setExpiryTime` | `0x30fc4cff` | +| Function | Signature | +| ------------------------------ | ------------ | +| `expiryTime` | `0x99bc0aea` | +| `getPrecompileFees` | `0xb7a3d04c` | +| `handlePayload` | `0x1d5e1d98` | +| `maxScheduleDelayInSeconds` | `0x3ef01cdb` | +| `rescueFunds` | `0x6ccae054` | +| `resolvePayload` | `0xea92e825` | +| `scheduleCallbackFees` | `0x4c5b6007` | +| `scheduleFeesPerSecond` | `0x852a74c1` | +| `setExpiryTime` | `0x30fc4cff` | | `setMaxScheduleDelayInSeconds` | `0x12953318` | -| `setScheduleCallbackFees` | `0xec8fd71e` | -| `setScheduleFeesPerSecond` | `0x28e59e57` | +| `setScheduleCallbackFees` | `0xec8fd71e` | +| `setScheduleFeesPerSecond` | `0x28e59e57` | | `validateAndGetPrecompileData` | `0xab172aab` | -| `watcher__` | `0x300bb063` | +| `watcher__` | `0x300bb063` | ## WritePrecompile -| Function | Signature | -| -------- | --------- | -| `cancelOwnershipHandover` | `0x54d1f13d` | -| `chainMaxMsgValueLimit` | `0x01d1e126` | -| `completeOwnershipHandover` | `0xf04e283e` | -| `contractFactoryPlugs` | `0x35426631` | -| `digestHashes` | `0xd1a862bf` | -| `expiryTime` | `0x99bc0aea` | -| `getDigest` | `0xdd4bf97b` | -| `getPrecompileFees` | `0xb7a3d04c` | -| `getPrevBatchDigestHash` | `0x372863a1` | -| `handlePayload` | `0x1d5e1d98` | -| `initialize` | `0xeb990c59` | -| `owner` | `0x8da5cb5b` | -| `ownershipHandoverExpiresAt` | `0xfee81cf4` | -| `renounceOwnership` | `0x715018a6` | -| `requestOwnershipHandover` | `0x25692962` | -| `rescueFunds` | `0x6ccae054` | -| `resolvePayload` | `0xea92e825` | -| `setContractFactoryPlugs` | `0xc067b6dd` | -| `setExpiryTime` | `0x30fc4cff` | -| `setFees` | `0x3d18678e` | -| `transferOwnership` | `0xf2fde38b` | +| Function | Signature | +| ------------------------------ | ------------ | +| `cancelOwnershipHandover` | `0x54d1f13d` | +| `chainMaxMsgValueLimit` | `0x01d1e126` | +| `completeOwnershipHandover` | `0xf04e283e` | +| `contractFactoryPlugs` | `0x35426631` | +| `digestHashes` | `0xd1a862bf` | +| `expiryTime` | `0x99bc0aea` | +| `getDigest` | `0xdd4bf97b` | +| `getPrecompileFees` | `0xb7a3d04c` | +| `getPrevBatchDigestHash` | `0x372863a1` | +| `handlePayload` | `0x1d5e1d98` | +| `initialize` | `0xeb990c59` | +| `owner` | `0x8da5cb5b` | +| `ownershipHandoverExpiresAt` | `0xfee81cf4` | +| `renounceOwnership` | `0x715018a6` | +| `requestOwnershipHandover` | `0x25692962` | +| `rescueFunds` | `0x6ccae054` | +| `resolvePayload` | `0xea92e825` | +| `setContractFactoryPlugs` | `0xc067b6dd` | +| `setExpiryTime` | `0x30fc4cff` | +| `setFees` | `0x3d18678e` | +| `transferOwnership` | `0xf2fde38b` | | `updateChainMaxMsgValueLimits` | `0x6a7aa6ac` | -| `uploadProof` | `0x81b48fcf` | +| `uploadProof` | `0x81b48fcf` | | `validateAndGetPrecompileData` | `0xab172aab` | -| `watcherProofs` | `0x3fa3166b` | -| `watcher__` | `0x300bb063` | -| `writeFees` | `0x5c664aeb` | - +| `watcherProofs` | `0x3fa3166b` | +| `watcher__` | `0x300bb063` | +| `writeFees` | `0x5c664aeb` | diff --git a/hardhat-scripts/deploy/4.configureEVMx.ts b/hardhat-scripts/deploy/4.configureEVMx.ts index bac01a52..d4ee1f57 100644 --- a/hardhat-scripts/deploy/4.configureEVMx.ts +++ b/hardhat-scripts/deploy/4.configureEVMx.ts @@ -132,11 +132,11 @@ export const setWatcherCoreContracts = async ( if ( requestHandlerSet.toLowerCase() !== - evmxAddresses[Contracts.RequestHandler].toLowerCase() || + evmxAddresses[Contracts.RequestHandler].toLowerCase() || PromiseResolverSet.toLowerCase() !== - evmxAddresses[Contracts.PromiseResolver].toLowerCase() || + evmxAddresses[Contracts.PromiseResolver].toLowerCase() || ConfigurationsSet.toLowerCase() !== - evmxAddresses[Contracts.Configurations].toLowerCase() + evmxAddresses[Contracts.Configurations].toLowerCase() ) { console.log("Setting watcher core contracts"); const tx = await watcherContract.setCoreContracts( diff --git a/hardhat-scripts/utils/deployUtils.ts b/hardhat-scripts/utils/deployUtils.ts index f034e5de..dd71525e 100644 --- a/hardhat-scripts/utils/deployUtils.ts +++ b/hardhat-scripts/utils/deployUtils.ts @@ -335,7 +335,7 @@ export const updateContractSettings = async ( const contractInstance = await getInstance(contractName, contractAddress); const currentValue = await contractInstance .connect(signer) - [getterMethod](...getterArgs); + [getterMethod](...getterArgs); if ( (typeof currentValue === "string" && @@ -350,7 +350,7 @@ export const updateContractSettings = async ( }); const tx = await contractInstance .connect(signer) - [setterMethod](...setterArgs); + [setterMethod](...setterArgs); console.log( `Setting ${getterMethod} for ${contractInstance.address} to`, tx.hash From cc782dcd420ca97e59773ca8b9d4e7ba5c3cc85a Mon Sep 17 00:00:00 2001 From: Rookmate <14072042+rookmate@users.noreply.github.com> Date: Tue, 3 Jun 2025 14:42:30 +0100 Subject: [PATCH 121/130] fix: add FeesManager approval when withdrawing credits --- contracts/evmx/base/AppGatewayBase.sol | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contracts/evmx/base/AppGatewayBase.sol b/contracts/evmx/base/AppGatewayBase.sol index 70c3835e..faae8e50 100644 --- a/contracts/evmx/base/AppGatewayBase.sol +++ b/contracts/evmx/base/AppGatewayBase.sol @@ -237,6 +237,9 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { uint256 maxFees_, address receiver_ ) internal { + AppGatewayApprovals[] memory approvals = new AppGatewayApprovals[](1); + approvals[0] = AppGatewayApprovals({appGateway: address(feesManager__()), approval: true}); + feesManager__().approveAppGateways(approvals); feesManager__().withdrawCredits(chainSlug_, token_, amount_, maxFees_, receiver_); } From a220354215c561d65f7d7012810958a9c12f4144 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 3 Jun 2025 21:09:28 +0530 Subject: [PATCH 122/130] fix: return on 0 queue length --- contracts/evmx/base/AppGatewayBase.sol | 5 ++--- contracts/evmx/watcher/Watcher.sol | 1 + test/apps/app-gateways/counter/CounterAppGateway.sol | 2 -- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/contracts/evmx/base/AppGatewayBase.sol b/contracts/evmx/base/AppGatewayBase.sol index 5545e878..a9702d5c 100644 --- a/contracts/evmx/base/AppGatewayBase.sol +++ b/contracts/evmx/base/AppGatewayBase.sol @@ -166,8 +166,7 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { return address(0); } - onChainAddress = IForwarder(forwarderAddresses[contractId_][chainSlug_]) - .getOnChainAddress(); + onChainAddress = IForwarder(forwarderAddresses[contractId_][chainSlug_]).getOnChainAddress(); } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -239,7 +238,7 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { AppGatewayApprovals[] memory approvals = new AppGatewayApprovals[](1); approvals[0] = AppGatewayApprovals({appGateway: address(feesManager__()), approval: true}); feesManager__().approveAppGateways(approvals); - feesManager__().withdrawCredits(chainSlug_, token_, amount_, maxFees_, receiver_); + feesManager__().withdrawCredits(chainSlug_, token_, amount_, maxFees, receiver_); } //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/contracts/evmx/watcher/Watcher.sol b/contracts/evmx/watcher/Watcher.sol index 05586c90..7dbaa28b 100644 --- a/contracts/evmx/watcher/Watcher.sol +++ b/contracts/evmx/watcher/Watcher.sol @@ -98,6 +98,7 @@ contract Watcher is Trigger { address consumeFrom, bytes memory onCompleteData ) internal returns (uint40 requestCount, address[] memory promiseList) { + if (payloadQueue.length == 0) return (0, new address[](0)); address appGateway = msg.sender; // this check is to verify that msg.sender (app gateway base) belongs to correct app gateway diff --git a/test/apps/app-gateways/counter/CounterAppGateway.sol b/test/apps/app-gateways/counter/CounterAppGateway.sol index 8933d99c..41666c9b 100644 --- a/test/apps/app-gateways/counter/CounterAppGateway.sol +++ b/test/apps/app-gateways/counter/CounterAppGateway.sol @@ -146,6 +146,4 @@ contract CounterAppGateway is AppGatewayBase, Ownable { function increaseFees(uint40 requestCount_, uint256 newMaxFees_) public { _increaseFees(requestCount_, newMaxFees_); } - - function initialize(uint32 chainSlug_) external override {} } From dc173aea1bfcec23d39c16b9e1ec43333f7fba72 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 3 Jun 2025 21:19:13 +0530 Subject: [PATCH 123/130] feat: contract upgrades --- deployments/dev_addresses.json | 2 +- deployments/dev_verification.json | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/deployments/dev_addresses.json b/deployments/dev_addresses.json index ffda3474..df55a5d3 100644 --- a/deployments/dev_addresses.json +++ b/deployments/dev_addresses.json @@ -29,7 +29,7 @@ "SchedulePrecompile": "0x7D6F2A4aDf7e5Cfcf9627CC7FCA1d39fD19C07fc", "startBlock": 8355289, "Watcher": "0xD5b30DC89D96ee7303Dc2726491996B46089F693", - "WatcherImpl": "0xFa9B9271A4153eEABa76ae10bfc4F128651c25D7", + "WatcherImpl": "0x872bb254118a2210e3C491918133F2ab4D7Bc362", "WritePrecompile": "0x10eaDbd1a2787ebbF4Abe9b6D79e669C0c8E8B26", "WritePrecompileImpl": "0xD3aEb53da0a72788C16eAf5a23a5aBae6708C073" }, diff --git a/deployments/dev_verification.json b/deployments/dev_verification.json index a2c3199e..7726efac 100644 --- a/deployments/dev_verification.json +++ b/deployments/dev_verification.json @@ -45,6 +45,12 @@ ] ], "7625382": [ + [ + "0x872bb254118a2210e3C491918133F2ab4D7Bc362", + "Watcher", + "contracts/evmx/watcher/Watcher.sol", + [] + ], [ "0x7D6F2A4aDf7e5Cfcf9627CC7FCA1d39fD19C07fc", "SchedulePrecompile", From dd7158af19b091fb0bb81ef6ec9d461a0e3b996c Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 3 Jun 2025 21:34:55 +0530 Subject: [PATCH 124/130] fix: stage constants --- hardhat-scripts/config/config.ts | 15 ++++++--------- hardhat-scripts/constants/feeConstants.ts | 7 +++---- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/hardhat-scripts/config/config.ts b/hardhat-scripts/config/config.ts index 8eb7dfcd..a768c61a 100644 --- a/hardhat-scripts/config/config.ts +++ b/hardhat-scripts/config/config.ts @@ -57,7 +57,11 @@ export const getFeesPlugChains = (): Array => { case DeploymentMode.DEV: return getChains(); case DeploymentMode.STAGE: - return getChains(); + return [ + ChainSlug.OPTIMISM_SEPOLIA, + ChainSlug.ARBITRUM_SEPOLIA, + ChainSlug.BASE_SEPOLIA + ]; case DeploymentMode.PROD: return getChains(); default: @@ -83,6 +87,7 @@ export const EVM_CHAIN_ID_MAP: Record = { [DeploymentMode.STAGE]: 43, [DeploymentMode.PROD]: 3605, }; + // Addresses export const watcher = "0xb62505feacC486e809392c65614Ce4d7b051923b"; export const transmitter = "0x138e9840861C983DC0BB9b3e941FB7C0e9Ade320"; @@ -97,13 +102,6 @@ export const AUCTION_END_DELAY_SECONDS = 0; export const BID_TIMEOUT = 600; // 10 minutes export const EXPIRY_TIME = 300; // 5 minutes export const MAX_RE_AUCTION_COUNT = 5; -// TestUSDC -export const TEST_USDC_NAME = "testUSDC"; -export const TEST_USDC_SYMBOL = "testUSDC"; -export const TEST_USDC_INITIAL_SUPPLY = ethers.utils.parseEther( - "1000000000000000000000000" -); -export const TEST_USDC_DECIMALS = 6; // Fees Pool Funding Amount export const FEES_POOL_FUNDING_AMOUNT_THRESHOLD = @@ -118,7 +116,6 @@ export const SCHEDULE_CALLBACK_FEES = utils.parseEther("0.000001"); export const MAX_SCHEDULE_DELAY_SECONDS = 60 * 60 * 24; // Other constants -export const DEFAULT_MAX_LIMIT = 100; export const UPGRADE_VERSION = 1; // Transmitter constants diff --git a/hardhat-scripts/constants/feeConstants.ts b/hardhat-scripts/constants/feeConstants.ts index 1f85aaec..15a49275 100644 --- a/hardhat-scripts/constants/feeConstants.ts +++ b/hardhat-scripts/constants/feeConstants.ts @@ -7,10 +7,9 @@ const tokens: TokenMap = { 11155420: ["0x15dbE4B96306Cc9Eba15D834d6c1a895cF4e1697"], }, [DeploymentMode.STAGE]: { - 84532: ["0xfD51918C0572512901fFA79F822c99A475d22BB4"], - 421614: ["0xa03Cbf13f331aF7c0fD7F2E28E6Cbc13F879E3F3"], - 11155420: ["0xa0E1738a9Fc0698789866e09d7A335d30128C5C5"], - 11155111: ["0xbcaDE56f86a819994d0F66b98e921C484bE6FE4e"], + 8453: ["0x833589fcd6edb6e08f4c7c32d4f71b54bda02913"], + 42161: ["0xaf88d065e77c8cc2239327c5edb3a432268e5831"], + 10: ["0x0b2c639c533813f4aa9d7837caf62653d097ff85"], }, }; From 2a55276737db278b3396c6e551b1322ece0b9215 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 3 Jun 2025 21:44:42 +0530 Subject: [PATCH 125/130] fix: schedule fees --- hardhat-scripts/config/config.ts | 3 +-- hardhat-scripts/utils/sign.ts | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/hardhat-scripts/config/config.ts b/hardhat-scripts/config/config.ts index a768c61a..6418a2e6 100644 --- a/hardhat-scripts/config/config.ts +++ b/hardhat-scripts/config/config.ts @@ -94,7 +94,6 @@ export const transmitter = "0x138e9840861C983DC0BB9b3e941FB7C0e9Ade320"; // Chain config export const EVMX_CHAIN_ID = EVM_CHAIN_ID_MAP[mode]; -export const MAX_FEES = ethers.utils.parseEther("0.001"); export const MAX_MSG_VALUE_LIMIT = ethers.utils.parseEther("0.001"); // Auction parameters @@ -111,7 +110,7 @@ export const FEES_POOL_FUNDING_AMOUNT_THRESHOLD = export const READ_FEES = utils.parseEther("0.000001"); export const TRIGGER_FEES = utils.parseEther("0.000001"); export const WRITE_FEES = utils.parseEther("0.000001"); -export const SCHEDULE_FEES_PER_SECOND = utils.parseEther("0.000001"); +export const SCHEDULE_FEES_PER_SECOND = utils.parseEther("0.00000001"); export const SCHEDULE_CALLBACK_FEES = utils.parseEther("0.000001"); export const MAX_SCHEDULE_DELAY_SECONDS = 60 * 60 * 24; diff --git a/hardhat-scripts/utils/sign.ts b/hardhat-scripts/utils/sign.ts index 6f569ff0..00afdcb4 100644 --- a/hardhat-scripts/utils/sign.ts +++ b/hardhat-scripts/utils/sign.ts @@ -4,7 +4,7 @@ import { EVMX_CHAIN_ID, mode } from "../config/config"; import { getProviderFromChainSlug } from "./networks"; import { signWatcherMultiCallMessage } from "../../src/signer"; import { getAddresses } from "./address"; -import { getOverrides, overrides } from "./overrides"; +import { overrides } from "./overrides"; import { getInstance } from "./deployUtils"; import { WatcherMultiCallParams } from "../constants/types"; From 61d2dcfdd9bb81d778236a8609c07cb59cdbdeac Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 3 Jun 2025 22:16:44 +0530 Subject: [PATCH 126/130] feat: stage deployments --- deployments/stage_addresses.json | 103 +++--- deployments/stage_verification.json | 490 +++++++++++++++++++++++++++- hardhat-scripts/config/config.ts | 6 +- 3 files changed, 552 insertions(+), 47 deletions(-) diff --git a/deployments/stage_addresses.json b/deployments/stage_addresses.json index 4987a330..10006872 100644 --- a/deployments/stage_addresses.json +++ b/deployments/stage_addresses.json @@ -1,50 +1,73 @@ { + "10": { + "ContractFactoryPlug": "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "FastSwitchboard": "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "FeesPlug": "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "Socket": "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "SocketBatcher": "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "startBlock": 136685079 + }, "43": { - "AddressResolver": "0x21a9AFDfbEb0399D4a12f3AA1324042Be2B57F8e", - "AddressResolverImpl": "0x794b92C2Ade7D33Fb34d138B13014C63aB27CBC0", - "AuctionManager": "0x87E15a6f9Cbe482f67683Ec3f7294f12d221C8bA", - "AuctionManagerImpl": "0xfddb38811a0774E66ABD5F3Ae960bFB7E7415029", - "DeliveryHelper": "0xb399b60C22A32512a24F01C4401f43BfF979A49F", - "DeliveryHelperImpl": "0xa07e38cAB46eAA358C3653C63219f1009e8F7789", - "ERC1967Factory": "0x98ea7A5601f203DE56d86BDCA69fC3019377D6B1", - "FeesManager": "0x30e07016eB24570629Bc8765CA307394Af90B27C", - "FeesManagerImpl": "0x9F10A0c71178dbD4d049f2C04fD0e34966134b9e", - "startBlock": 5480301, - "WatcherPrecompile": "0x426509517074E0fBf15F8aAB2472711FB456C58C", - "WatcherPrecompileConfig": "0x49094ECAF26d8295BcBD73b0Ff17215348E7b253", - "WatcherPrecompileConfigImpl": "0xd69E17Ce715f49Cd2B16C64cf75201A56Ce0E90d", - "WatcherPrecompileImpl": "0xB423eE3bffc3604F96B59cF419C48AE05b8E9d0b", - "WatcherPrecompileLimits": "0x54B315eC6c7059b19164BC0e5335643d5bBAad4f", - "WatcherPrecompileLimitsImpl": "0x0e26C8CFCABC04c642696A625664553e2C183bbe" + "AddressResolver": "0x935b06902cA5C8bb4C76e18738561c294D377A93", + "AddressResolverImpl": "0xD1586EaaA0d473E6655c11A927cE4FbED648F3BF", + "AsyncDeployer": "0xECa623A443F21B705714D4A0f810d0A5D135FF6F", + "AsyncDeployerImpl": "0x1B0ea1b79B526dD3d5889Bb33Dbd24f790C23102", + "AuctionManager": "0xD044f27A9c5EE4f92EF0e38685276adFDF13E90E", + "AuctionManagerImpl": "0xC72BE9e639DA23570fa1eF2fF2cb7901a081916F", + "Configurations": "0x72f4C225B4B4f0F9608a50aEe17dA9e11dcb94b2", + "ConfigurationsImpl": "0x351De7e4275dA7f49F75363e4E7ea86Dfe050501", + "DeployForwarder": "0x5E9d1072B60D6c752B1593F5937393413372E5eF", + "DeployForwarderImpl": "0x1b7752F0039E80Aa38f7CF8b5d18798dD2ac1597", + "ERC1967Factory": "0x526796AC60e45CBB9b17c654C9447Baf160C084d", + "FeesManager": "0xA07208F9e7aE243F922317ab6604DC9F86822406", + "FeesManagerImpl": "0xbD22EDD6559B28614f44D1c768EC26491CDE1cDD", + "FeesPool": "0xe2054B575664dfDBD7a7FbAf2B12420ae88DE0FF", + "PromiseResolver": "0x38e24A2F157817b830F36A35b862F24B1494d1aD", + "ReadPrecompile": "0x39b5D3FBBa1BC28438e25955aaB412C7576eCd61", + "RequestHandler": "0x2E928C000bdC1f90716B05cE2D7182C9FA081d31", + "RequestHandlerImpl": "0xD38ae1a6C410c7681ac464bd60009198406035Ed", + "SchedulePrecompile": "0xb14a7763f09eCbd47bC5230D6170547a22834a82", + "startBlock": 8240883, + "Watcher": "0x4C846eCa55ad8cF19B9D5d906225da7b565174C1", + "WatcherImpl": "0x2920F4FB50343EF2b33096650cE234E8aF9E8556", + "WritePrecompile": "0x393007B660a00970b25E34FEd6506CE96120f8e2", + "WritePrecompileImpl": "0x0026c4736E57fE2817b53f6df1E0808c3a61984d" + }, + "8453": { + "ContractFactoryPlug": "0x3aac37DC85C522c09A3DDdA44D181E6aCCD2f9F0", + "FastSwitchboard": "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", + "FeesPlug": "0xfE34ACE07836F7F05f485EAc7122D0CD58BAC047", + "Socket": "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "SocketBatcher": "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "startBlock": 31089766 + }, + "42161": { + "ContractFactoryPlug": "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "FastSwitchboard": "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "FeesPlug": "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "Socket": "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "SocketBatcher": "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "startBlock": 343531414 }, "84532": { - "ContractFactoryPlug": "0x8e51D99Bf353Ebba50080D0452546fd2EBAd86A4", - "FastSwitchboard": "0x4C114115755c39dB81a06fBfEb4b08302Abe7beE", - "FeesPlug": "0x9161a99deD597fe519E03D319053CA1669118dDA", - "Socket": "0x36Ae239a92faee6aFF4df9749d592dA7c00717Be", - "SocketBatcher": "0x8fa361816874a11a66D02EC84b28E1A931B4035e", - "startBlock": 25218634 + "ContractFactoryPlug": "0x87cC19AedD434ebD3B74FfdC073CAeC7dC1E92EA", + "FastSwitchboard": "0x5aA84ffE5eCCB5263d1AE6aEd5682EAb39Bc7036", + "Socket": "0xa09217Cfc47F399C382E982778f6128685e13aD4", + "SocketBatcher": "0x80568677f2B092bd974657FE47Fc8531bfE5DBDC", + "startBlock": 26600215 }, "421614": { - "ContractFactoryPlug": "0x65C066BE05CB4622393fADc1Bf3dE8eEdEcB3817", - "FastSwitchboard": "0xF121f4B97F7C902eeD4b188B08052Da9A1FD5aBe", - "FeesPlug": "0xDfE94B9b14de382Ed13C8A7F387884808D0f7E0b", - "Socket": "0xDAB25fB82cc1b1611Fb9016FB50222dBFcD1BCf5", - "SocketBatcher": "0x4e7163Ce9F7F335138fB32827d6f99f174060897", - "startBlock": 148801970 - }, - "11155111": { - "FastSwitchboard": "0x1eFD3AF2317B9E6E7492718878f69De747C9e7c3", - "FeesPlug": "0xfE555AD869ac24305471F0755976c556425E8D23", - "Socket": "0xae59BA0Bd0D92232B3B6304185448C9Fe5445f4d", - "SocketBatcher": "0xdaE4538FbbEf41B2Feb5c79DD2fFC9720AF13d7b" + "ContractFactoryPlug": "0xe2904171afCeC319236cc051c81202677F7Aac1B", + "FastSwitchboard": "0x82833e5ac997F8f9c426949595d49702E3b08414", + "Socket": "0x468cA4bB968FD86eD752A7bD453c6869E27204f0", + "SocketBatcher": "0x977B8aB88A7159130457adA4b7078208Ab4fB111", + "startBlock": 159757112 }, "11155420": { - "ContractFactoryPlug": "0x469B536c5Df15948c8759FEEE5DB1c17790d4152", - "FastSwitchboard": "0xd8bCd4b4Bc4b0f5cb279B6FAdCEd733614f34F51", - "FeesPlug": "0x6734a30B8f2d210faefa5aeD4E11b674C59641F1", - "Socket": "0x11fbd3a7031b28607973fc44d4d24B26DEfac886", - "SocketBatcher": "0x2c2060f5586751676fC2Af96cc8bE9BF0c7A8770", - "startBlock": 27201458 + "ContractFactoryPlug": "0x705A4DD80D7203BF78AcAf3BA1851D1A80fA3d89", + "FastSwitchboard": "0x74388051BcCfA2D28690a98242A259aD94f2B1f3", + "Socket": "0x790E894C59d6275503e2Ff4ba95A42E38c071195", + "SocketBatcher": "0xa13B9b5e797e13316B23EfC01E506c8c0c2BFeF2", + "startBlock": 28583052 } } diff --git a/deployments/stage_verification.json b/deployments/stage_verification.json index 88f93e4b..fad6247d 100644 --- a/deployments/stage_verification.json +++ b/deployments/stage_verification.json @@ -1,5 +1,244 @@ { + "10": [ + [ + "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "FeesPlug", + "contracts/evmx/plugs/FeesPlug.sol", + [ + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", + [ + 10, + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a" + ] + ], + [ + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "Socket", + "contracts/protocol/Socket.sol", + [ + 10, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "EVMX" + ] + ] + ], "43": [ + [ + "0xb14a7763f09eCbd47bC5230D6170547a22834a82", + "SchedulePrecompile", + "contracts/evmx/watcher/precompiles/SchedulePrecompile.sol", + [ + "0x4C846eCa55ad8cF19B9D5d906225da7b565174C1", + 86400, + { + "type": "BigNumber", + "hex": "0x02540be400" + }, + { + "type": "BigNumber", + "hex": "0xe8d4a51000" + }, + 300 + ] + ], + [ + "0x39b5D3FBBa1BC28438e25955aaB412C7576eCd61", + "ReadPrecompile", + "contracts/evmx/watcher/precompiles/ReadPrecompile.sol", + [ + "0x4C846eCa55ad8cF19B9D5d906225da7b565174C1", + { + "type": "BigNumber", + "hex": "0xe8d4a51000" + }, + 300 + ] + ], + [ + "0x0026c4736E57fE2817b53f6df1E0808c3a61984d", + "WritePrecompile", + "contracts/evmx/watcher/precompiles/WritePrecompile.sol", + [] + ], + [ + "0x38e24A2F157817b830F36A35b862F24B1494d1aD", + "PromiseResolver", + "contracts/evmx/watcher/PromiseResolver.sol", + [ + "0x4C846eCa55ad8cF19B9D5d906225da7b565174C1" + ] + ], + [ + "0xD38ae1a6C410c7681ac464bd60009198406035Ed", + "RequestHandler", + "contracts/evmx/watcher/RequestHandler.sol", + [] + ], + [ + "0x351De7e4275dA7f49F75363e4E7ea86Dfe050501", + "Configurations", + "contracts/evmx/watcher/Configurations.sol", + [] + ], + [ + "0x1b7752F0039E80Aa38f7CF8b5d18798dD2ac1597", + "DeployForwarder", + "contracts/evmx/helpers/DeployForwarder.sol", + [] + ], + [ + "0xC72BE9e639DA23570fa1eF2fF2cb7901a081916F", + "AuctionManager", + "contracts/evmx/AuctionManager.sol", + [] + ], + [ + "0x2920F4FB50343EF2b33096650cE234E8aF9E8556", + "Watcher", + "contracts/evmx/watcher/Watcher.sol", + [] + ], + [ + "0x1B0ea1b79B526dD3d5889Bb33Dbd24f790C23102", + "AsyncDeployer", + "contracts/evmx/helpers/AsyncDeployer.sol", + [] + ], + [ + "0xbD22EDD6559B28614f44D1c768EC26491CDE1cDD", + "FeesManager", + "contracts/evmx/fees/FeesManager.sol", + [] + ], + [ + "0xD1586EaaA0d473E6655c11A927cE4FbED648F3BF", + "AddressResolver", + "contracts/evmx/helpers/AddressResolver.sol", + [] + ], + [ + "0xe2054B575664dfDBD7a7FbAf2B12420ae88DE0FF", + "FeesPool", + "contracts/evmx/fees/FeesPool.sol", + [ + "0xb62505feacC486e809392c65614Ce4d7b051923b" + ] + ], + [ + "0x526796AC60e45CBB9b17c654C9447Baf160C084d", + "ERC1967Factory", + "lib/solady/src/utils/ERC1967Factory.sol", + [] + ], + [ + "0xFaa00117ED72CAE3399669a1E3FEedaF93020853", + "SchedulePrecompile", + "contracts/evmx/watcher/precompiles/SchedulePrecompile.sol", + [ + "0x03Aa399188E2741f89cc4265493DC5b544C52134", + 86400, + { + "type": "BigNumber", + "hex": "0x02540be400" + }, + { + "type": "BigNumber", + "hex": "0xe8d4a51000" + }, + 300 + ] + ], + [ + "0xD38d0Dfd8e7d61B45Cce6Ec58E1Ec4c514c00e7F", + "ReadPrecompile", + "contracts/evmx/watcher/precompiles/ReadPrecompile.sol", + [ + "0x03Aa399188E2741f89cc4265493DC5b544C52134", + { + "type": "BigNumber", + "hex": "0xe8d4a51000" + }, + 300 + ] + ], + [ + "0x702EfE1DfABc3963114E2356aFaF36c8b67CA961", + "WritePrecompile", + "contracts/evmx/watcher/precompiles/WritePrecompile.sol", + [] + ], + [ + "0xd0bd7837E66eEd7Be04C88354e75F5bA3cd19959", + "PromiseResolver", + "contracts/evmx/watcher/PromiseResolver.sol", + [ + "0x03Aa399188E2741f89cc4265493DC5b544C52134" + ] + ], + [ + "0x446C6B4086d1888cB15cF62735Bf57A4647E31A4", + "RequestHandler", + "contracts/evmx/watcher/RequestHandler.sol", + [] + ], + [ + "0x2dc671B87d1A9dc7C1cf06C74C2db06673b31FFf", + "Configurations", + "contracts/evmx/watcher/Configurations.sol", + [] + ], + [ + "0x4ab75b62c0E2A09E428Ce73043C36d54c78C8CFd", + "DeployForwarder", + "contracts/evmx/helpers/DeployForwarder.sol", + [] + ], + [ + "0xed8255097DFB0BB2135870bb342335dCC0C30e21", + "Watcher", + "contracts/evmx/watcher/Watcher.sol", + [] + ], + [ + "0xF946503b3bF14b39468AEce46E7Ce1A08404D109", + "AsyncDeployer", + "contracts/evmx/helpers/AsyncDeployer.sol", + [] + ], + [ + "0x69DD00B8a250e0A1bFF1b59db2EA99792faAbC66", + "FeesPool", + "contracts/evmx/fees/FeesPool.sol", + [ + "0xb62505feacC486e809392c65614Ce4d7b051923b" + ] + ], [ "0xfddb38811a0774E66ABD5F3Ae960bFB7E7415029", "AuctionManager", @@ -49,8 +288,251 @@ [] ] ], - "84532": [], - "421614": [], - "11155111": [], - "11155420": [] + "8453": [ + [ + "0x3aac37DC85C522c09A3DDdA44D181E6aCCD2f9F0", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xfE34ACE07836F7F05f485EAc7122D0CD58BAC047", + "FeesPlug", + "contracts/evmx/plugs/FeesPlug.sol", + [ + "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", + [ + 8453, + "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d" + ] + ], + [ + "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "Socket", + "contracts/protocol/Socket.sol", + [ + 8453, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "EVMX" + ] + ], + [ + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", + [ + 8453, + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a" + ] + ], + [ + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "Socket", + "contracts/protocol/Socket.sol", + [ + 8453, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "EVMX" + ] + ] + ], + "42161": [ + [ + "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "FeesPlug", + "contracts/evmx/plugs/FeesPlug.sol", + [ + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", + [ + 42161, + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a" + ] + ], + [ + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "Socket", + "contracts/protocol/Socket.sol", + [ + 42161, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "EVMX" + ] + ] + ], + "84532": [ + [ + "0x87cC19AedD434ebD3B74FfdC073CAeC7dC1E92EA", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0xa09217Cfc47F399C382E982778f6128685e13aD4", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x5aA84ffE5eCCB5263d1AE6aEd5682EAb39Bc7036", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", + [ + 84532, + "0xa09217Cfc47F399C382E982778f6128685e13aD4", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x80568677f2B092bd974657FE47Fc8531bfE5DBDC", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0xa09217Cfc47F399C382E982778f6128685e13aD4" + ] + ], + [ + "0xa09217Cfc47F399C382E982778f6128685e13aD4", + "Socket", + "contracts/protocol/Socket.sol", + [ + 84532, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "EVMX" + ] + ] + ], + "421614": [ + [ + "0xe2904171afCeC319236cc051c81202677F7Aac1B", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0x468cA4bB968FD86eD752A7bD453c6869E27204f0", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x82833e5ac997F8f9c426949595d49702E3b08414", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", + [ + 421614, + "0x468cA4bB968FD86eD752A7bD453c6869E27204f0", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x977B8aB88A7159130457adA4b7078208Ab4fB111", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x468cA4bB968FD86eD752A7bD453c6869E27204f0" + ] + ], + [ + "0x468cA4bB968FD86eD752A7bD453c6869E27204f0", + "Socket", + "contracts/protocol/Socket.sol", + [ + 421614, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "EVMX" + ] + ] + ], + "11155420": [ + [ + "0x705A4DD80D7203BF78AcAf3BA1851D1A80fA3d89", + "ContractFactoryPlug", + "contracts/evmx/plugs/ContractFactoryPlug.sol", + [ + "0x790E894C59d6275503e2Ff4ba95A42E38c071195", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x74388051BcCfA2D28690a98242A259aD94f2B1f3", + "FastSwitchboard", + "contracts/protocol/switchboard/FastSwitchboard.sol", + [ + 11155420, + "0x790E894C59d6275503e2Ff4ba95A42E38c071195", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xa13B9b5e797e13316B23EfC01E506c8c0c2BFeF2", + "SocketBatcher", + "contracts/protocol/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x790E894C59d6275503e2Ff4ba95A42E38c071195" + ] + ], + [ + "0x790E894C59d6275503e2Ff4ba95A42E38c071195", + "Socket", + "contracts/protocol/Socket.sol", + [ + 11155420, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "EVMX" + ] + ] + ] } diff --git a/hardhat-scripts/config/config.ts b/hardhat-scripts/config/config.ts index 6418a2e6..5073c273 100644 --- a/hardhat-scripts/config/config.ts +++ b/hardhat-scripts/config/config.ts @@ -58,9 +58,9 @@ export const getFeesPlugChains = (): Array => { return getChains(); case DeploymentMode.STAGE: return [ - ChainSlug.OPTIMISM_SEPOLIA, - ChainSlug.ARBITRUM_SEPOLIA, - ChainSlug.BASE_SEPOLIA + ChainSlug.OPTIMISM, + ChainSlug.ARBITRUM, + ChainSlug.BASE, ]; case DeploymentMode.PROD: return getChains(); From b5cfed6c92a9e1edbda377ea9259a4771e7ab745 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 3 Jun 2025 22:39:00 +0530 Subject: [PATCH 127/130] fix: role overrides --- hardhat-scripts/deploy/2.roles.ts | 4 ++-- hardhat-scripts/utils/overrides.ts | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/hardhat-scripts/deploy/2.roles.ts b/hardhat-scripts/deploy/2.roles.ts index 53ece239..44fad7f2 100644 --- a/hardhat-scripts/deploy/2.roles.ts +++ b/hardhat-scripts/deploy/2.roles.ts @@ -49,7 +49,7 @@ async function setRoleForContract( if (!hasRole) { let tx = await contract.grantRole(roleHash, targetAddress, { - ...overrides(chain), + ...await overrides(chain as ChainSlug), }); console.log( `granting ${roleName} role to ${targetAddress} for ${contractName}`, @@ -81,7 +81,7 @@ async function setRolesOnChain(chain: number, addresses: DeploymentAddresses) { for (const roleName of roles) { const targetAddress = contractName === Contracts.FastSwitchboard && - roleName === ROLES.WATCHER_ROLE + roleName === ROLES.WATCHER_ROLE ? watcher : signer.address; diff --git a/hardhat-scripts/utils/overrides.ts b/hardhat-scripts/utils/overrides.ts index 94a25c12..6ffd630b 100644 --- a/hardhat-scripts/utils/overrides.ts +++ b/hardhat-scripts/utils/overrides.ts @@ -27,6 +27,9 @@ export const chainOverrides: { // gasLimit: 1_000_000, // gasPrice: 212_000_000_000, }, + [ChainSlug.BASE]: { + gasLimit: 2_000_000, + }, [EVMX_CHAIN_ID as ChainSlug]: { type: 0, // gasLimit: 1_000_000_000, @@ -41,7 +44,7 @@ export const overrides = async ( gasLimit?: BigNumberish | undefined; gasPrice?: BigNumberish | undefined; }> => { - return await getOverrides(chain, getProviderFromChainSlug(chain)); + return await getOverrides(chain as ChainSlug, getProviderFromChainSlug(chain)); }; export const getOverrides = async ( From cd759e6629a85e52d502e4a466e3c3fd0edd79be Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 3 Jun 2025 22:49:41 +0530 Subject: [PATCH 128/130] feat: add overrides --- hardhat-scripts/deploy/2.roles.ts | 4 ++-- hardhat-scripts/deploy/3.configureChains.ts | 11 +++++++++-- hardhat-scripts/deploy/4.configureEVMx.ts | 4 +++- hardhat-scripts/deploy/6.connect.ts | 4 +++- hardhat-scripts/utils/overrides.ts | 5 ++++- 5 files changed, 21 insertions(+), 7 deletions(-) diff --git a/hardhat-scripts/deploy/2.roles.ts b/hardhat-scripts/deploy/2.roles.ts index 44fad7f2..79723cec 100644 --- a/hardhat-scripts/deploy/2.roles.ts +++ b/hardhat-scripts/deploy/2.roles.ts @@ -49,7 +49,7 @@ async function setRoleForContract( if (!hasRole) { let tx = await contract.grantRole(roleHash, targetAddress, { - ...await overrides(chain as ChainSlug), + ...(await overrides(chain as ChainSlug)), }); console.log( `granting ${roleName} role to ${targetAddress} for ${contractName}`, @@ -81,7 +81,7 @@ async function setRolesOnChain(chain: number, addresses: DeploymentAddresses) { for (const roleName of roles) { const targetAddress = contractName === Contracts.FastSwitchboard && - roleName === ROLES.WATCHER_ROLE + roleName === ROLES.WATCHER_ROLE ? watcher : signer.address; diff --git a/hardhat-scripts/deploy/3.configureChains.ts b/hardhat-scripts/deploy/3.configureChains.ts index 6bda0941..54a3cb11 100644 --- a/hardhat-scripts/deploy/3.configureChains.ts +++ b/hardhat-scripts/deploy/3.configureChains.ts @@ -14,6 +14,7 @@ import { getInstance, getSocketSigner, getWatcherSigner, + overrides, updateContractSettings, } from "../utils"; @@ -41,6 +42,7 @@ export const configureChains = async (addresses: DeploymentAddresses) => { ).connect(signer); await registerSb( + chain, chainAddresses[Contracts.FastSwitchboard], signer, socketContract @@ -125,6 +127,7 @@ async function setOnchainContracts( } const registerSb = async ( + chain: number, sbAddress: string, signer: Wallet, socket: Contract @@ -144,7 +147,9 @@ const registerSb = async ( }); if (Number(sb) == 0) { - const registerTx = await switchboard.registerSwitchboard(); + const registerTx = await switchboard.registerSwitchboard({ + ...(await overrides(chain)), + }); console.log(`Registering Switchboard ${sbAddress}: ${registerTx.hash}`); await registerTx.wait(); } @@ -171,7 +176,9 @@ export const whitelistToken = async ( const isWhitelisted = await feesPlugContract.whitelistedTokens(token); if (!isWhitelisted) { - const tx = await feesPlugContract.whitelistToken(token); + const tx = await feesPlugContract.whitelistToken(token, { + ...(await overrides(chain)), + }); console.log( `Whitelisting token ${token} for ${feesPlugContract.address}`, tx.hash diff --git a/hardhat-scripts/deploy/4.configureEVMx.ts b/hardhat-scripts/deploy/4.configureEVMx.ts index d4ee1f57..1b05f542 100644 --- a/hardhat-scripts/deploy/4.configureEVMx.ts +++ b/hardhat-scripts/deploy/4.configureEVMx.ts @@ -9,6 +9,7 @@ import { getAddresses, getInstance, getWatcherSigner, + overrides, updateContractSettings, } from "../utils"; @@ -142,7 +143,8 @@ export const setWatcherCoreContracts = async ( const tx = await watcherContract.setCoreContracts( evmxAddresses[Contracts.RequestHandler], evmxAddresses[Contracts.Configurations], - evmxAddresses[Contracts.PromiseResolver] + evmxAddresses[Contracts.PromiseResolver], + { ...(await overrides(EVMX_CHAIN_ID)) } ); console.log("Watcher core contracts set tx: ", tx.hash); await tx.wait(); diff --git a/hardhat-scripts/deploy/6.connect.ts b/hardhat-scripts/deploy/6.connect.ts index 82d54e8f..cd9fcf62 100644 --- a/hardhat-scripts/deploy/6.connect.ts +++ b/hardhat-scripts/deploy/6.connect.ts @@ -9,6 +9,7 @@ import { getAppGatewayId, getInstance, getSocketSigner, + overrides, } from "../utils"; import { getWatcherSigner, sendWatcherMultiCallWithNonce } from "../utils/sign"; @@ -71,7 +72,8 @@ async function connectPlug( const tx = await plug.functions["connectSocket"]( appGatewayId, socket.address, - switchboard + switchboard, + { ...(await overrides(chain)) } ); console.log( `Connecting ${plugContract} on ${chain} to ${appGatewayId} tx hash: ${tx.hash}` diff --git a/hardhat-scripts/utils/overrides.ts b/hardhat-scripts/utils/overrides.ts index 6ffd630b..b81f365b 100644 --- a/hardhat-scripts/utils/overrides.ts +++ b/hardhat-scripts/utils/overrides.ts @@ -44,7 +44,10 @@ export const overrides = async ( gasLimit?: BigNumberish | undefined; gasPrice?: BigNumberish | undefined; }> => { - return await getOverrides(chain as ChainSlug, getProviderFromChainSlug(chain)); + return await getOverrides( + chain as ChainSlug, + getProviderFromChainSlug(chain) + ); }; export const getOverrides = async ( From 1ce423066e1c4515724ccb92010ed2dddb3ddb77 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 3 Jun 2025 22:59:10 +0530 Subject: [PATCH 129/130] fix: config --- contracts/evmx/base/AppGatewayBase.sol | 3 +- deployments/stage_verification.json | 58 +++++------------------ hardhat-scripts/config/config.ts | 12 ++--- hardhat-scripts/constants/feeConstants.ts | 2 +- hardhat.config.ts | 11 +++++ 5 files changed, 29 insertions(+), 57 deletions(-) diff --git a/contracts/evmx/base/AppGatewayBase.sol b/contracts/evmx/base/AppGatewayBase.sol index a9702d5c..3e60dce0 100644 --- a/contracts/evmx/base/AppGatewayBase.sol +++ b/contracts/evmx/base/AppGatewayBase.sol @@ -166,7 +166,8 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { return address(0); } - onChainAddress = IForwarder(forwarderAddresses[contractId_][chainSlug_]).getOnChainAddress(); + onChainAddress = IForwarder(forwarderAddresses[contractId_][chainSlug_]) + .getOnChainAddress(); } //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/deployments/stage_verification.json b/deployments/stage_verification.json index fad6247d..6ebbf455 100644 --- a/deployments/stage_verification.json +++ b/deployments/stage_verification.json @@ -41,11 +41,7 @@ "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", "Socket", "contracts/protocol/Socket.sol", - [ - 10, - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", - "EVMX" - ] + [10, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] ] ], "43": [ @@ -90,9 +86,7 @@ "0x38e24A2F157817b830F36A35b862F24B1494d1aD", "PromiseResolver", "contracts/evmx/watcher/PromiseResolver.sol", - [ - "0x4C846eCa55ad8cF19B9D5d906225da7b565174C1" - ] + ["0x4C846eCa55ad8cF19B9D5d906225da7b565174C1"] ], [ "0xD38ae1a6C410c7681ac464bd60009198406035Ed", @@ -146,9 +140,7 @@ "0xe2054B575664dfDBD7a7FbAf2B12420ae88DE0FF", "FeesPool", "contracts/evmx/fees/FeesPool.sol", - [ - "0xb62505feacC486e809392c65614Ce4d7b051923b" - ] + ["0xb62505feacC486e809392c65614Ce4d7b051923b"] ], [ "0x526796AC60e45CBB9b17c654C9447Baf160C084d", @@ -197,9 +189,7 @@ "0xd0bd7837E66eEd7Be04C88354e75F5bA3cd19959", "PromiseResolver", "contracts/evmx/watcher/PromiseResolver.sol", - [ - "0x03Aa399188E2741f89cc4265493DC5b544C52134" - ] + ["0x03Aa399188E2741f89cc4265493DC5b544C52134"] ], [ "0x446C6B4086d1888cB15cF62735Bf57A4647E31A4", @@ -235,9 +225,7 @@ "0x69DD00B8a250e0A1bFF1b59db2EA99792faAbC66", "FeesPool", "contracts/evmx/fees/FeesPool.sol", - [ - "0xb62505feacC486e809392c65614Ce4d7b051923b" - ] + ["0xb62505feacC486e809392c65614Ce4d7b051923b"] ], [ "0xfddb38811a0774E66ABD5F3Ae960bFB7E7415029", @@ -330,11 +318,7 @@ "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", "Socket", "contracts/protocol/Socket.sol", - [ - 8453, - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", - "EVMX" - ] + [8453, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] ], [ "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", @@ -359,11 +343,7 @@ "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", "Socket", "contracts/protocol/Socket.sol", - [ - 8453, - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", - "EVMX" - ] + [8453, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] ] ], "42161": [ @@ -408,11 +388,7 @@ "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", "Socket", "contracts/protocol/Socket.sol", - [ - 42161, - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", - "EVMX" - ] + [42161, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] ] ], "84532": [ @@ -448,11 +424,7 @@ "0xa09217Cfc47F399C382E982778f6128685e13aD4", "Socket", "contracts/protocol/Socket.sol", - [ - 84532, - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", - "EVMX" - ] + [84532, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] ] ], "421614": [ @@ -488,11 +460,7 @@ "0x468cA4bB968FD86eD752A7bD453c6869E27204f0", "Socket", "contracts/protocol/Socket.sol", - [ - 421614, - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", - "EVMX" - ] + [421614, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] ] ], "11155420": [ @@ -528,11 +496,7 @@ "0x790E894C59d6275503e2Ff4ba95A42E38c071195", "Socket", "contracts/protocol/Socket.sol", - [ - 11155420, - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", - "EVMX" - ] + [11155420, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] ] ] } diff --git a/hardhat-scripts/config/config.ts b/hardhat-scripts/config/config.ts index 5073c273..7ba92e79 100644 --- a/hardhat-scripts/config/config.ts +++ b/hardhat-scripts/config/config.ts @@ -31,12 +31,12 @@ export const getChains = () => { return [ChainSlug.ARBITRUM_SEPOLIA, ChainSlug.OPTIMISM_SEPOLIA]; case DeploymentMode.STAGE: return [ - ChainSlug.OPTIMISM_SEPOLIA, - ChainSlug.ARBITRUM_SEPOLIA, - ChainSlug.BASE_SEPOLIA, ChainSlug.BASE, ChainSlug.ARBITRUM, ChainSlug.OPTIMISM, + ChainSlug.OPTIMISM_SEPOLIA, + ChainSlug.ARBITRUM_SEPOLIA, + ChainSlug.BASE_SEPOLIA, ]; case DeploymentMode.PROD: return [ @@ -57,11 +57,7 @@ export const getFeesPlugChains = (): Array => { case DeploymentMode.DEV: return getChains(); case DeploymentMode.STAGE: - return [ - ChainSlug.OPTIMISM, - ChainSlug.ARBITRUM, - ChainSlug.BASE, - ]; + return [ChainSlug.OPTIMISM, ChainSlug.ARBITRUM, ChainSlug.BASE]; case DeploymentMode.PROD: return getChains(); default: diff --git a/hardhat-scripts/constants/feeConstants.ts b/hardhat-scripts/constants/feeConstants.ts index 15a49275..0c610e3e 100644 --- a/hardhat-scripts/constants/feeConstants.ts +++ b/hardhat-scripts/constants/feeConstants.ts @@ -15,7 +15,7 @@ const tokens: TokenMap = { const feePools: { [key: string]: string } = { [DeploymentMode.DEV]: "0xc20Be67ef742202dc93A78aa741E7C3715eA1DFd", - [DeploymentMode.STAGE]: "", + [DeploymentMode.STAGE]: "0xe2054B575664dfDBD7a7FbAf2B12420ae88DE0FF", }; export const getFeeTokens = ( diff --git a/hardhat.config.ts b/hardhat.config.ts index ada0e153..fe491c5d 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -61,6 +61,9 @@ let liveNetworks = { ), [HardhatChainName.SEPOLIA]: getChainConfig(ChainSlug.SEPOLIA), [HardhatChainName.BASE_SEPOLIA]: getChainConfig(ChainSlug.BASE_SEPOLIA), + [HardhatChainName.BASE]: getChainConfig(ChainSlug.BASE), + [HardhatChainName.ARBITRUM]: getChainConfig(ChainSlug.ARBITRUM), + [HardhatChainName.OPTIMISM]: getChainConfig(ChainSlug.OPTIMISM), EVMX: { accounts: [`0x${privateKey}`], chainId: EVMX_CHAIN_ID, @@ -124,6 +127,14 @@ const config: HardhatUserConfig = { browserURL: "https://sepolia.basescan.org/", }, }, + { + network: "base", + chainId: ChainId.BASE, + urls: { + apiURL: "https://api.basescan.org/api", + browserURL: "https://basescan.org/", + }, + }, { network: "evmx", chainId: EVMX_CHAIN_ID, From 8334d597bbc9cf1fcef402bf6f772515c7a6de66 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 3 Jun 2025 23:30:01 +0530 Subject: [PATCH 130/130] feat: verify stage contracts --- deployments/stage_verification.json | 321 ++-------------------------- hardhat-scripts/verify/verify.ts | 3 +- hardhat.config.ts | 10 +- 3 files changed, 22 insertions(+), 312 deletions(-) diff --git a/deployments/stage_verification.json b/deployments/stage_verification.json index 6ebbf455..2b0fd6f8 100644 --- a/deployments/stage_verification.json +++ b/deployments/stage_verification.json @@ -1,81 +1,6 @@ { - "10": [ - [ - "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", - "ContractFactoryPlug", - "contracts/evmx/plugs/ContractFactoryPlug.sol", - [ - "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" - ] - ], - [ - "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", - "FeesPlug", - "contracts/evmx/plugs/FeesPlug.sol", - [ - "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" - ] - ], - [ - "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", - "FastSwitchboard", - "contracts/protocol/switchboard/FastSwitchboard.sol", - [ - 10, - "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" - ] - ], - [ - "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", - "SocketBatcher", - "contracts/protocol/SocketBatcher.sol", - [ - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", - "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a" - ] - ], - [ - "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", - "Socket", - "contracts/protocol/Socket.sol", - [10, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] - ] - ], + "10": [], "43": [ - [ - "0xb14a7763f09eCbd47bC5230D6170547a22834a82", - "SchedulePrecompile", - "contracts/evmx/watcher/precompiles/SchedulePrecompile.sol", - [ - "0x4C846eCa55ad8cF19B9D5d906225da7b565174C1", - 86400, - { - "type": "BigNumber", - "hex": "0x02540be400" - }, - { - "type": "BigNumber", - "hex": "0xe8d4a51000" - }, - 300 - ] - ], - [ - "0x39b5D3FBBa1BC28438e25955aaB412C7576eCd61", - "ReadPrecompile", - "contracts/evmx/watcher/precompiles/ReadPrecompile.sol", - [ - "0x4C846eCa55ad8cF19B9D5d906225da7b565174C1", - { - "type": "BigNumber", - "hex": "0xe8d4a51000" - }, - 300 - ] - ], [ "0x0026c4736E57fE2817b53f6df1E0808c3a61984d", "WritePrecompile", @@ -86,7 +11,9 @@ "0x38e24A2F157817b830F36A35b862F24B1494d1aD", "PromiseResolver", "contracts/evmx/watcher/PromiseResolver.sol", - ["0x4C846eCa55ad8cF19B9D5d906225da7b565174C1"] + [ + "0x4C846eCa55ad8cF19B9D5d906225da7b565174C1" + ] ], [ "0xD38ae1a6C410c7681ac464bd60009198406035Ed", @@ -140,7 +67,9 @@ "0xe2054B575664dfDBD7a7FbAf2B12420ae88DE0FF", "FeesPool", "contracts/evmx/fees/FeesPool.sol", - ["0xb62505feacC486e809392c65614Ce4d7b051923b"] + [ + "0xb62505feacC486e809392c65614Ce4d7b051923b" + ] ], [ "0x526796AC60e45CBB9b17c654C9447Baf160C084d", @@ -189,7 +118,9 @@ "0xd0bd7837E66eEd7Be04C88354e75F5bA3cd19959", "PromiseResolver", "contracts/evmx/watcher/PromiseResolver.sol", - ["0x03Aa399188E2741f89cc4265493DC5b544C52134"] + [ + "0x03Aa399188E2741f89cc4265493DC5b544C52134" + ] ], [ "0x446C6B4086d1888cB15cF62735Bf57A4647E31A4", @@ -225,7 +156,9 @@ "0x69DD00B8a250e0A1bFF1b59db2EA99792faAbC66", "FeesPool", "contracts/evmx/fees/FeesPool.sol", - ["0xb62505feacC486e809392c65614Ce4d7b051923b"] + [ + "0xb62505feacC486e809392c65614Ce4d7b051923b" + ] ], [ "0xfddb38811a0774E66ABD5F3Ae960bFB7E7415029", @@ -276,227 +209,9 @@ [] ] ], - "8453": [ - [ - "0x3aac37DC85C522c09A3DDdA44D181E6aCCD2f9F0", - "ContractFactoryPlug", - "contracts/evmx/plugs/ContractFactoryPlug.sol", - [ - "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" - ] - ], - [ - "0xfE34ACE07836F7F05f485EAc7122D0CD58BAC047", - "FeesPlug", - "contracts/evmx/plugs/FeesPlug.sol", - [ - "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" - ] - ], - [ - "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", - "FastSwitchboard", - "contracts/protocol/switchboard/FastSwitchboard.sol", - [ - 8453, - "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" - ] - ], - [ - "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", - "SocketBatcher", - "contracts/protocol/SocketBatcher.sol", - [ - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", - "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d" - ] - ], - [ - "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", - "Socket", - "contracts/protocol/Socket.sol", - [8453, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] - ], - [ - "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", - "FastSwitchboard", - "contracts/protocol/switchboard/FastSwitchboard.sol", - [ - 8453, - "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" - ] - ], - [ - "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", - "SocketBatcher", - "contracts/protocol/SocketBatcher.sol", - [ - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", - "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a" - ] - ], - [ - "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", - "Socket", - "contracts/protocol/Socket.sol", - [8453, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] - ] - ], - "42161": [ - [ - "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", - "FeesPlug", - "contracts/evmx/plugs/FeesPlug.sol", - [ - "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" - ] - ], - [ - "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", - "ContractFactoryPlug", - "contracts/evmx/plugs/ContractFactoryPlug.sol", - [ - "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" - ] - ], - [ - "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", - "FastSwitchboard", - "contracts/protocol/switchboard/FastSwitchboard.sol", - [ - 42161, - "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" - ] - ], - [ - "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", - "SocketBatcher", - "contracts/protocol/SocketBatcher.sol", - [ - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", - "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a" - ] - ], - [ - "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", - "Socket", - "contracts/protocol/Socket.sol", - [42161, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] - ] - ], - "84532": [ - [ - "0x87cC19AedD434ebD3B74FfdC073CAeC7dC1E92EA", - "ContractFactoryPlug", - "contracts/evmx/plugs/ContractFactoryPlug.sol", - [ - "0xa09217Cfc47F399C382E982778f6128685e13aD4", - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" - ] - ], - [ - "0x5aA84ffE5eCCB5263d1AE6aEd5682EAb39Bc7036", - "FastSwitchboard", - "contracts/protocol/switchboard/FastSwitchboard.sol", - [ - 84532, - "0xa09217Cfc47F399C382E982778f6128685e13aD4", - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" - ] - ], - [ - "0x80568677f2B092bd974657FE47Fc8531bfE5DBDC", - "SocketBatcher", - "contracts/protocol/SocketBatcher.sol", - [ - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", - "0xa09217Cfc47F399C382E982778f6128685e13aD4" - ] - ], - [ - "0xa09217Cfc47F399C382E982778f6128685e13aD4", - "Socket", - "contracts/protocol/Socket.sol", - [84532, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] - ] - ], - "421614": [ - [ - "0xe2904171afCeC319236cc051c81202677F7Aac1B", - "ContractFactoryPlug", - "contracts/evmx/plugs/ContractFactoryPlug.sol", - [ - "0x468cA4bB968FD86eD752A7bD453c6869E27204f0", - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" - ] - ], - [ - "0x82833e5ac997F8f9c426949595d49702E3b08414", - "FastSwitchboard", - "contracts/protocol/switchboard/FastSwitchboard.sol", - [ - 421614, - "0x468cA4bB968FD86eD752A7bD453c6869E27204f0", - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" - ] - ], - [ - "0x977B8aB88A7159130457adA4b7078208Ab4fB111", - "SocketBatcher", - "contracts/protocol/SocketBatcher.sol", - [ - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", - "0x468cA4bB968FD86eD752A7bD453c6869E27204f0" - ] - ], - [ - "0x468cA4bB968FD86eD752A7bD453c6869E27204f0", - "Socket", - "contracts/protocol/Socket.sol", - [421614, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] - ] - ], - "11155420": [ - [ - "0x705A4DD80D7203BF78AcAf3BA1851D1A80fA3d89", - "ContractFactoryPlug", - "contracts/evmx/plugs/ContractFactoryPlug.sol", - [ - "0x790E894C59d6275503e2Ff4ba95A42E38c071195", - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" - ] - ], - [ - "0x74388051BcCfA2D28690a98242A259aD94f2B1f3", - "FastSwitchboard", - "contracts/protocol/switchboard/FastSwitchboard.sol", - [ - 11155420, - "0x790E894C59d6275503e2Ff4ba95A42E38c071195", - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" - ] - ], - [ - "0xa13B9b5e797e13316B23EfC01E506c8c0c2BFeF2", - "SocketBatcher", - "contracts/protocol/SocketBatcher.sol", - [ - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", - "0x790E894C59d6275503e2Ff4ba95A42E38c071195" - ] - ], - [ - "0x790E894C59d6275503e2Ff4ba95A42E38c071195", - "Socket", - "contracts/protocol/Socket.sol", - [11155420, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] - ] - ] + "8453": [], + "42161": [], + "84532": [], + "421614": [], + "11155420": [] } diff --git a/hardhat-scripts/verify/verify.ts b/hardhat-scripts/verify/verify.ts index 2835a150..38140e02 100644 --- a/hardhat-scripts/verify/verify.ts +++ b/hardhat-scripts/verify/verify.ts @@ -43,7 +43,6 @@ export const main = async () => { for (let chainIndex = 0; chainIndex < chains.length; chainIndex++) { const chain = parseInt(chains[chainIndex]) as ChainSlug; let chainName: string; - console.log({ chain }); if (chain == (EVMX_CHAIN_ID as ChainSlug)) { chainName = "EVMX"; } else { @@ -51,10 +50,10 @@ export const main = async () => { } console.log({ chainName }); hre.changeNetwork(chainName); - console.log(chainName); const chainParams: VerifyArgs[] = verificationParams[chain]; const unverifiedChainParams: VerifyArgs[] = []; + if (chainParams.length) { const len = chainParams.length; for (let index = 0; index < len!; index++) { diff --git a/hardhat.config.ts b/hardhat.config.ts index fe491c5d..74627321 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -93,6 +93,7 @@ const config: HardhatUserConfig = { arbitrumOne: process.env.ARBISCAN_API_KEY || "", arbitrumTestnet: process.env.ARBISCAN_API_KEY || "", baseTestnet: process.env.BASESCAN_API_KEY || "", + base: process.env.BASESCAN_API_KEY || "", bsc: process.env.BSCSCAN_API_KEY || "", bscTestnet: process.env.BSCSCAN_API_KEY || "", goerli: process.env.ETHERSCAN_API_KEY || "", @@ -100,7 +101,7 @@ const config: HardhatUserConfig = { sepolia: process.env.ETHERSCAN_API_KEY || "", optimisticEthereum: process.env.OPTIMISM_API_KEY || "", optimisticTestnet: process.env.OPTIMISM_API_KEY || "", - evmx: "none", + EVMX: "none", }, customChains: [ { @@ -136,7 +137,7 @@ const config: HardhatUserConfig = { }, }, { - network: "evmx", + network: "EVMX", chainId: EVMX_CHAIN_ID, urls: { apiURL: "https://evmx.cloud.blockscout.com/api", @@ -145,11 +146,6 @@ const config: HardhatUserConfig = { }, ], }, - sourcify: { - // Disabled by default - // Doesn't need an API key - enabled: true, - }, // This fully resolves paths for imports in the ./lib directory for Hardhat preprocess: { eachLine: (hre) => ({