diff --git a/Errors.md b/Errors.md index c9ef6e7e..77179268 100644 --- a/Errors.md +++ b/Errors.md @@ -106,6 +106,7 @@ | `InvalidIndex()` | `0x63df8171` | | `InvalidChainSlug()` | `0xbff6b106` | | `InvalidPayloadSize()` | `0xfbdf7954` | +| `InvalidOnChainAddress()` | `0xb758c606` | | `InvalidScheduleDelay()` | `0x9a993219` | | `AuctionClosed()` | `0x36b6b46d` | | `AuctionNotOpen()` | `0xf0460077` | diff --git a/FunctionSignatures.md b/FunctionSignatures.md index d2412f5f..be1d1ac8 100644 --- a/FunctionSignatures.md +++ b/FunctionSignatures.md @@ -417,6 +417,7 @@ | `requestOwnershipHandover` | `0x25692962` | | `rescueFunds` | `0x6ccae054` | | `setPrecompile` | `0x122e0042` | +| `setRequestPayloadCountLimit` | `0x8526582b` | | `submitRequest` | `0xbb299a2c` | | `transferOwnership` | `0xf2fde38b` | | `updateRequestAndProcessBatch` | `0x46464471` | diff --git a/contracts/evmx/base/AppGatewayBase.sol b/contracts/evmx/base/AppGatewayBase.sol index faae8e50..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(); } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -234,13 +233,12 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { uint32 chainSlug_, address token_, uint256 amount_, - 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_); + feesManager__().withdrawCredits(chainSlug_, token_, amount_, maxFees, receiver_); } //////////////////////////////////////////////////////////////////////////////////////////////// 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/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/evmx/watcher/RequestHandler.sol b/contracts/evmx/watcher/RequestHandler.sol index bd3889b0..f11ca0bf 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/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/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 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(); diff --git a/deployments/dev_addresses.json b/deployments/dev_addresses.json index 80c0774b..ffda3474 100644 --- a/deployments/dev_addresses.json +++ b/deployments/dev_addresses.json @@ -1,46 +1,44 @@ { "421614": { - "ContractFactoryPlug": "0xaCd26f991E548F353f285942509d90200064Cf14", - "FastSwitchboard": "0xbcc1CE144cA85C0d121f08634547a61E93627ce4", - "FeesPlug": "0xb0cbd56A86568BB4cBBE59B0EcA029A4F2D7f235", - "Socket": "0xEb907f52eAF6e81439F8807AE2F143Bd3482e6b6", - "SocketBatcher": "0xc498A63eE84143A15A7D3080E1E51af700f35e41", - "startBlock": 159285686, - "TestUSDC": "0x2321BF7AdFaf49b1338F1Cd474859dBc0D8dfA96" + "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, - "TestUSDC": "0x15dbE4B96306Cc9Eba15D834d6c1a895cF4e1697" + "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/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/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/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/hardhat-scripts/config/config.ts b/hardhat-scripts/config/config.ts index bb7303eb..8eb7dfcd 100644 --- a/hardhat-scripts/config/config.ts +++ b/hardhat-scripts/config/config.ts @@ -49,6 +49,22 @@ 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/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/feeConstants.ts b/hardhat-scripts/constants/feeConstants.ts new file mode 100644 index 00000000..1f85aaec --- /dev/null +++ b/hardhat-scripts/constants/feeConstants.ts @@ -0,0 +1,31 @@ +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"], + }, +}; + +const feePools: { [key: string]: string } = { + [DeploymentMode.DEV]: "0xc20Be67ef742202dc93A78aa741E7C3715eA1DFd", + [DeploymentMode.STAGE]: "", +}; + +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..3e41d235 100644 --- a/hardhat-scripts/constants/types.ts +++ b/hardhat-scripts/constants/types.ts @@ -4,9 +4,20 @@ export type DeploymentAddresses = { [chainSlug in ChainSlug]?: ChainAddressesObj; }; +export type TokenMap = { [key: string]: { [chainSlug: number]: string[] } }; + export interface WatcherMultiCallParams { contractAddress: string; data: string; nonce: number; signature: string; } + +export type AppGatewayConfig = { + plugConfig: { + appGatewayId: string; + switchboard: string; + }; + plug: string; + chainSlug: number; +}; diff --git a/hardhat-scripts/deploy/1.deploy.ts b/hardhat-scripts/deploy/1.deploy.ts index 1ba63595..60581ec7 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, @@ -22,6 +23,7 @@ import { import { DeploymentAddresses, FAST_SWITCHBOARD_TYPE, + getFeePool, IMPLEMENTATION_SLOT, } from "../constants"; import { @@ -103,14 +105,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.length == 0) { + 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 +138,7 @@ const deployEVMxContracts = async () => { [ EVMX_CHAIN_ID, addressResolver.address, - feesPool.address, + deployUtils.addresses[Contracts.FeesPool], EVMxOwner, FAST_SWITCHBOARD_TYPE, ], @@ -315,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/2.roles.ts b/hardhat-scripts/deploy/2.roles.ts index a13706c0..53ece239 100644 --- a/hardhat-scripts/deploy/2.roles.ts +++ b/hardhat-scripts/deploy/2.roles.ts @@ -4,25 +4,26 @@ dotenvConfig(); import { Wallet } from "ethers"; import { chains, EVMX_CHAIN_ID, mode, watcher, transmitter } from "../config"; import { DeploymentAddresses } from "../constants"; -import { - getAddresses, - getInstance, - getProviderFromChainSlug, - 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"; + 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 +68,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; @@ -104,9 +102,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 +127,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/hardhat-scripts/deploy/3.configureChains.ts b/hardhat-scripts/deploy/3.configureChains.ts index 7c090c45..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 } from "../constants"; +import { + DeploymentAddresses, + FAST_SWITCHBOARD_TYPE, + getFeeTokens, +} from "../constants"; import { getAddresses, getInstance, @@ -42,11 +46,10 @@ export const configureChains = async (addresses: DeploymentAddresses) => { socketContract ); - await whitelistToken( - chainAddresses[Contracts.FeesPlug], - chainAddresses[Contracts.TestUSDC], - signer - ); + if (chainAddresses[Contracts.FeesPlug]) { + await whitelistToken(chain, chainAddresses[Contracts.FeesPlug], signer); + } + await setMaxMsgValueLimit(chain); await setOnchainContracts(chain, addresses); @@ -97,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, @@ -150,27 +154,32 @@ 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`); + } } }; diff --git a/hardhat-scripts/deploy/4.configureEVMx.ts b/hardhat-scripts/deploy/4.configureEVMx.ts index e12bd950..d4ee1f57 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/deploy/6.connect.ts b/hardhat-scripts/deploy/6.connect.ts index 8e96da51..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, @@ -147,7 +91,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 +142,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..d8bc7ead 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"; @@ -36,13 +37,20 @@ const updatedLines = lines.map((line) => { latestAddresses[ChainSlug.ARBITRUM_SEPOLIA][Contracts.FastSwitchboard] }`; } else if (line.startsWith("ARBITRUM_FEES_PLUG=")) { - return `ARBITRUM_FEES_PLUG=${ - latestAddresses[ChainSlug.ARBITRUM_SEPOLIA][Contracts.FeesPlug] - }`; + 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=")) { - return `ARBITRUM_TEST_USDC=${ - latestAddresses[ChainSlug.ARBITRUM_SEPOLIA][Contracts.TestUSDC] - }`; + 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 }); 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/deployUtils.ts b/hardhat-scripts/utils/deployUtils.ts index 0b6206a5..dd71525e 100644 --- a/hardhat-scripts/utils/deployUtils.ts +++ b/hardhat-scripts/utils/deployUtils.ts @@ -356,5 +356,7 @@ export const updateContractSettings = async ( tx.hash ); await tx.wait(); + } else { + console.log(`${getterMethod} is already set to ${requiredValue}`); } }; 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"; 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/script/counter/WithdrawFeesArbitrumFeesPlug.s.sol b/script/counter/WithdrawFeesArbitrumFeesPlug.s.sol index dc8834ed..2d329a2f 100644 --- a/script/counter/WithdrawFeesArbitrumFeesPlug.s.sol +++ b/script/counter/WithdrawFeesArbitrumFeesPlug.s.sol @@ -45,13 +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, - estimatedGasCost, - sender - ); + appGateway.withdrawCredits(421614, token, amountToWithdraw, sender); vm.stopBroadcast(); // Switch back to Arbitrum Sepolia to check final balance 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", diff --git a/src/types.ts b/src/types.ts index 4cf64f1e..1a047bcc 100644 --- a/src/types.ts +++ b/src/types.ts @@ -19,24 +19,27 @@ export type ChainAddressesObj = { Socket: string; SocketBatcher: string; FastSwitchboard: string; - FeesPlug: string; ContractFactoryPlug: string; - TestUSDC: 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; }; diff --git a/test/SetupTest.t.sol b/test/SetupTest.t.sol index 0128cd53..03ed46b2 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), diff --git a/test/apps/app-gateways/counter/CounterAppGateway.sol b/test/apps/app-gateways/counter/CounterAppGateway.sol index f48807d9..41666c9b 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 { @@ -125,10 +123,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 { @@ -142,7 +139,7 @@ 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); }