diff --git a/EventTopics.md b/EventTopics.md index 36cadb7d..be6695ea 100644 --- a/EventTopics.md +++ b/EventTopics.md @@ -71,6 +71,7 @@ | `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` | | `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` | | `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` | +| `WithdrawFailed` | `(payloadId: bytes32)` | `0xea147eb2109f71b4bda9e57528ba08b84821087a31cb43a7851dc6ff743d9be7` | ## FeesPool diff --git a/FunctionSignatures.md b/FunctionSignatures.md index be1d1ac8..c5445dae 100644 --- a/FunctionSignatures.md +++ b/FunctionSignatures.md @@ -124,6 +124,7 @@ | Function | Signature | | -------------------------------- | ------------ | | `addressResolver__` | `0x6a750469` | +| `approveAppGateway` | `0xa3b53d8b` | | `approveAppGatewayWithSignature` | `0x94b649ec` | | `approveAppGateways` | `0x86d23ab2` | | `asyncDeployer__` | `0x2a39e801` | @@ -137,6 +138,7 @@ | `feesPlugs` | `0x23f5ee8a` | | `feesPool` | `0x6b259690` | | `getAvailableCredits` | `0xb065a8e5` | +| `handleRevert` | `0x44792f25` | | `initialize` | `0xbf2c8539` | | `isApproved` | `0xa389783e` | | `isCreditSpendable` | `0x4f8990fd` | diff --git a/contracts/evmx/base/AppGatewayBase.sol b/contracts/evmx/base/AppGatewayBase.sol index 3e60dce0..5bcdb2db 100644 --- a/contracts/evmx/base/AppGatewayBase.sol +++ b/contracts/evmx/base/AppGatewayBase.sol @@ -236,9 +236,7 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { uint256 amount_, address receiver_ ) internal { - AppGatewayApprovals[] memory approvals = new AppGatewayApprovals[](1); - approvals[0] = AppGatewayApprovals({appGateway: address(feesManager__()), approval: true}); - feesManager__().approveAppGateways(approvals); + feesManager__().approveAppGateway(address(feesManager__()), true); feesManager__().withdrawCredits(chainSlug_, token_, amount_, maxFees, receiver_); } diff --git a/contracts/evmx/fees/Credit.sol b/contracts/evmx/fees/Credit.sol index fb9dd643..4468d12f 100644 --- a/contracts/evmx/fees/Credit.sol +++ b/contracts/evmx/fees/Credit.sol @@ -97,6 +97,9 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressR /// @notice Emitted when fees pool is set event FeesPoolSet(address indexed feesPool); + /// @notice Emitted when withdraw fails + event WithdrawFailed(bytes32 indexed payloadId); + function setFeesPlug(uint32 chainSlug_, address feesPlug_) external onlyOwner { feesPlugs[chainSlug_] = feesPlug_; emit FeesPlugSet(chainSlug_, feesPlug_); @@ -196,6 +199,13 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressR emit CreditsTransferred(from_, to_, amount_); } + /// @notice Approves app gateway for the caller + /// @param appGateway_ app gateway address + /// @param approval_ approval + function approveAppGateway(address appGateway_, bool approval_) external override { + isApproved[msg.sender][appGateway_] = approval_; + } + /// @notice Approves multiple app gateways for the caller /// @param params_ Array of app gateway addresses to approve function approveAppGateways(AppGatewayApprovals[] calldata params_) external override { @@ -305,4 +315,11 @@ abstract contract Credit is FeesManagerStorage, Initializable, Ownable, AddressR /// @notice hook called by watcher precompile when request is finished function onRequestComplete(uint40, bytes memory) external {} + + /// @notice hook to handle the revert while withdrawing credits + /// @param payloadId_ The payload ID + function handleRevert(bytes32 payloadId_) external { + if (watcher__().getPayloadParams(payloadId_).asyncPromise != msg.sender) return; + emit WithdrawFailed(payloadId_); + } } diff --git a/contracts/evmx/interfaces/IFeesManager.sol b/contracts/evmx/interfaces/IFeesManager.sol index 8e4a495b..ea81aad6 100644 --- a/contracts/evmx/interfaces/IFeesManager.sol +++ b/contracts/evmx/interfaces/IFeesManager.sol @@ -25,6 +25,8 @@ interface IFeesManager { function transferCredits(address from_, address to_, uint256 amount_) external; + function approveAppGateway(address appGateway_, bool approval_) external; + function approveAppGateways(AppGatewayApprovals[] calldata params_) external; function approveAppGatewayWithSignature( diff --git a/contracts/evmx/plugs/ContractFactoryPlug.sol b/contracts/evmx/plugs/ContractFactoryPlug.sol index 29c8fd64..a83e098e 100644 --- a/contracts/evmx/plugs/ContractFactoryPlug.sol +++ b/contracts/evmx/plugs/ContractFactoryPlug.sol @@ -27,6 +27,8 @@ contract ContractFactoryPlug is PlugBase, AccessControl, IContractFactoryPlug { constructor(address socket_, address owner_) { _initializeOwner(owner_); _setSocket(socket_); + + isSocketInitialized = 1; } /// @notice Deploys a contract diff --git a/contracts/evmx/plugs/FeesPlug.sol b/contracts/evmx/plugs/FeesPlug.sol index cc8bde5e..3e035125 100644 --- a/contracts/evmx/plugs/FeesPlug.sol +++ b/contracts/evmx/plugs/FeesPlug.sol @@ -11,6 +11,8 @@ import {InvalidTokenAddress} from "../../utils/common/Errors.sol"; interface IERC20 { function balanceOf(address account) external view returns (uint256); + + function decimals() external view returns (uint8); } /// @title FeesPlug @@ -36,6 +38,8 @@ contract FeesPlug is IFeesPlug, PlugBase, AccessControl { constructor(address socket_, address owner_) { _setSocket(socket_); _initializeOwner(owner_); + + isSocketInitialized = 1; } /////////////////////// DEPOSIT AND WITHDRAWAL /////////////////////// @@ -82,6 +86,13 @@ contract FeesPlug is IFeesPlug, PlugBase, AccessControl { uint256 amount_ ) external override onlySocket { uint256 balance = IERC20(token_).balanceOf(address(this)); + uint8 decimals = IERC20(token_).decimals(); + + if (decimals < 18) { + amount_ = amount_ / 10 ** (18 - decimals); + } else if (decimals > 18) { + amount_ = amount_ * 10 ** (decimals - 18); + } if (balance < amount_) revert InsufficientTokenBalance(token_, balance, amount_); token_.safeTransfer(receiver_, amount_); diff --git a/deployments/dev_addresses.json b/deployments/dev_addresses.json index df55a5d3..6e0444a6 100644 --- a/deployments/dev_addresses.json +++ b/deployments/dev_addresses.json @@ -2,7 +2,7 @@ "421614": { "ContractFactoryPlug": "0x7b9928b01272b915050aDfcba7e0a11b22271BAd", "FastSwitchboard": "0x2974E94c0d1323D3A24f7B4F924fbdB325Be1aa3", - "FeesPlug": "0x6FdF04Cbcbd40414BF12e0b4Ce0e331e4657EB03", + "FeesPlug": "0xaFD76cADB518E7e5131991Fe4403e00297916957", "Socket": "0xb7378ae43b135988C8a83dfD1AcD71Ff39381396", "SocketBatcher": "0x60541d31Fda60163480CAb486be3762b5793B650", "startBlock": 159641867 @@ -20,7 +20,7 @@ "DeployForwarderImpl": "0xCe95fca954a0BF43c299c79d5152f2c164C02b7A", "ERC1967Factory": "0xb0364Fd8f158071831ac87E7EE2C792Ab509a524", "FeesManager": "0x09F824Eae77f71279d73Ae24FEb2163FCe88B25D", - "FeesManagerImpl": "0x6975302A1B7aF61d89F85a13855B66D15221Cf8D", + "FeesManagerImpl": "0x5b460B29750648f6D569Ed57139967BE589174F8", "FeesPool": "0xc20Be67ef742202dc93A78aa741E7C3715eA1DFd", "PromiseResolver": "0xcfFda1dF8668266E6A77809EcA9CCA8A632ecaF3", "ReadPrecompile": "0x254Dc9e0623426A79F02D2001E367cd32B50aaaA", @@ -36,7 +36,7 @@ "11155420": { "ContractFactoryPlug": "0x0279A18d5FC235A92fB4ABd5F7e9258e78E27948", "FastSwitchboard": "0x6b4EF1452265193798bfa3ef6D29421da9e7E222", - "FeesPlug": "0x99f7441292EB7f0b127Db204ba269Abd9F912d4C", + "FeesPlug": "0x5E175fD699E066D6536054198d57AF0De88C7c4E", "Socket": "0xB260A4DD0952e9A5b5F6652019469F05Fb137dC5", "SocketBatcher": "0xc320FC7b06D4491A9E7e6fa55a3305b12548519e", "startBlock": 28568337 diff --git a/deployments/dev_verification.json b/deployments/dev_verification.json index 7726efac..d491459d 100644 --- a/deployments/dev_verification.json +++ b/deployments/dev_verification.json @@ -1,50 +1,12 @@ { - "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" - ] - ], + "421614": [], + "7625382": [ [ - "0x60541d31Fda60163480CAb486be3762b5793B650", - "SocketBatcher", - "contracts/protocol/SocketBatcher.sol", - [ - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", - "0xb7378ae43b135988C8a83dfD1AcD71Ff39381396" - ] + "0x5b460B29750648f6D569Ed57139967BE589174F8", + "FeesManager", + "contracts/evmx/fees/FeesManager.sol", + [] ], - [ - "0xb7378ae43b135988C8a83dfD1AcD71Ff39381396", - "Socket", - "contracts/protocol/Socket.sol", - [421614, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] - ] - ], - "7625382": [ [ "0x872bb254118a2210e3C491918133F2ab4D7Bc362", "Watcher", @@ -258,49 +220,5 @@ [] ] ], - "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"] - ] - ] + "11155420": [] } diff --git a/deployments/stage_addresses.json b/deployments/stage_addresses.json index 10006872..8ba36507 100644 --- a/deployments/stage_addresses.json +++ b/deployments/stage_addresses.json @@ -2,7 +2,7 @@ "10": { "ContractFactoryPlug": "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", "FastSwitchboard": "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", - "FeesPlug": "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "FeesPlug": "0x501bdF8C7163ddD32172575C2836c5A7F556cbE7", "Socket": "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", "SocketBatcher": "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", "startBlock": 136685079 @@ -20,7 +20,7 @@ "DeployForwarderImpl": "0x1b7752F0039E80Aa38f7CF8b5d18798dD2ac1597", "ERC1967Factory": "0x526796AC60e45CBB9b17c654C9447Baf160C084d", "FeesManager": "0xA07208F9e7aE243F922317ab6604DC9F86822406", - "FeesManagerImpl": "0xbD22EDD6559B28614f44D1c768EC26491CDE1cDD", + "FeesManagerImpl": "0xC7A525A5D78610A9B7154315F3eC39Aa62594d1f", "FeesPool": "0xe2054B575664dfDBD7a7FbAf2B12420ae88DE0FF", "PromiseResolver": "0x38e24A2F157817b830F36A35b862F24B1494d1aD", "ReadPrecompile": "0x39b5D3FBBa1BC28438e25955aaB412C7576eCd61", @@ -36,7 +36,7 @@ "8453": { "ContractFactoryPlug": "0x3aac37DC85C522c09A3DDdA44D181E6aCCD2f9F0", "FastSwitchboard": "0xa33ACE59E4b0d9a45Cd4a3F0DBAB86D87BDd67e2", - "FeesPlug": "0xfE34ACE07836F7F05f485EAc7122D0CD58BAC047", + "FeesPlug": "0x79EB309890F4A797816478dB7D9d57A1e63CeeC2", "Socket": "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", "SocketBatcher": "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", "startBlock": 31089766 @@ -44,7 +44,7 @@ "42161": { "ContractFactoryPlug": "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", "FastSwitchboard": "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", - "FeesPlug": "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "FeesPlug": "0x501bdF8C7163ddD32172575C2836c5A7F556cbE7", "Socket": "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", "SocketBatcher": "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", "startBlock": 343531414 diff --git a/deployments/stage_verification.json b/deployments/stage_verification.json index 2b0fd6f8..28d06e20 100644 --- a/deployments/stage_verification.json +++ b/deployments/stage_verification.json @@ -1,6 +1,12 @@ { "10": [], "43": [ + [ + "0xC7A525A5D78610A9B7154315F3eC39Aa62594d1f", + "FeesManager", + "contracts/evmx/fees/FeesManager.sol", + [] + ], [ "0x0026c4736E57fE2817b53f6df1E0808c3a61984d", "WritePrecompile", @@ -11,9 +17,7 @@ "0x38e24A2F157817b830F36A35b862F24B1494d1aD", "PromiseResolver", "contracts/evmx/watcher/PromiseResolver.sol", - [ - "0x4C846eCa55ad8cF19B9D5d906225da7b565174C1" - ] + ["0x4C846eCa55ad8cF19B9D5d906225da7b565174C1"] ], [ "0xD38ae1a6C410c7681ac464bd60009198406035Ed", @@ -67,9 +71,7 @@ "0xe2054B575664dfDBD7a7FbAf2B12420ae88DE0FF", "FeesPool", "contracts/evmx/fees/FeesPool.sol", - [ - "0xb62505feacC486e809392c65614Ce4d7b051923b" - ] + ["0xb62505feacC486e809392c65614Ce4d7b051923b"] ], [ "0x526796AC60e45CBB9b17c654C9447Baf160C084d", @@ -118,9 +120,7 @@ "0xd0bd7837E66eEd7Be04C88354e75F5bA3cd19959", "PromiseResolver", "contracts/evmx/watcher/PromiseResolver.sol", - [ - "0x03Aa399188E2741f89cc4265493DC5b544C52134" - ] + ["0x03Aa399188E2741f89cc4265493DC5b544C52134"] ], [ "0x446C6B4086d1888cB15cF62735Bf57A4647E31A4", @@ -156,9 +156,7 @@ "0x69DD00B8a250e0A1bFF1b59db2EA99792faAbC66", "FeesPool", "contracts/evmx/fees/FeesPool.sol", - [ - "0xb62505feacC486e809392c65614Ce4d7b051923b" - ] + ["0xb62505feacC486e809392c65614Ce4d7b051923b"] ], [ "0xfddb38811a0774E66ABD5F3Ae960bFB7E7415029", diff --git a/hardhat-scripts/admin/disconnect.ts b/hardhat-scripts/admin/disconnect.ts index b5fb69d9..e5931ca5 100644 --- a/hardhat-scripts/admin/disconnect.ts +++ b/hardhat-scripts/admin/disconnect.ts @@ -11,9 +11,10 @@ import { getAddresses, getInstance, getSocketSigner, + overrides, } from "../utils"; import { getWatcherSigner, sendWatcherMultiCallWithNonce } from "../utils/sign"; -import { isConfigSetOnEVMx, isConfigSetOnSocket } from "../deploy/6.connect"; +import { isConfigSetOnEVMx, isConfigSetOnSocket } from "../utils"; // update this map to disconnect plugs from chains not in this list const feesPlugChains = getFeesPlugChains(); @@ -60,7 +61,8 @@ async function disconnectPlug( const tx = await plug.functions["connectSocket"]( ZERO_APP_GATEWAY_ID, socket.address, - switchboard + switchboard, + { ...(await overrides(chain as ChainSlug)) } ); console.log( `Connecting ${plugContract} on ${chain} to ${ZERO_APP_GATEWAY_ID} tx hash: ${tx.hash}` @@ -96,6 +98,13 @@ export const updateConfigEVMx = async () => { // Set up Watcher contract const signer = getWatcherSigner(); const EVMxAddresses = addresses[EVMX_CHAIN_ID]!; + const feesManagerContract = ( + await getInstance( + Contracts.FeesManager, + EVMxAddresses[Contracts.FeesManager] + ) + ).connect(signer); + const configurationsContract = ( await getInstance( Contracts.Configurations, @@ -126,27 +135,32 @@ export const updateConfigEVMx = async () => { ) ) { console.log(`Config already set on ${chain} for ${plugContract}`); - return; + } else { + appConfigs.push({ + plugConfig: { + appGatewayId: appGatewayId, + switchboard: switchboard, + }, + plug: addr[plugContract], + chainSlug: chain, + }); } - 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 + const currentFeesPlug = await feesManagerContract.feesPlugs(chain); + if (currentFeesPlug === constants.AddressZero) { + console.log(`Fees plug already set on ${chain}`); + return; + } + + const tx = await feesManagerContract.functions["setFeesPlug"]( + Number(chain), + constants.AddressZero, + { ...(await overrides(EVMX_CHAIN_ID as ChainSlug)) } ); console.log(`Updating Fees Manager tx hash: ${tx.hash}`); + await tx.wait(); }) ); diff --git a/hardhat-scripts/deploy/6.connect.ts b/hardhat-scripts/deploy/6.connect.ts index cd9fcf62..e13d781c 100644 --- a/hardhat-scripts/deploy/6.connect.ts +++ b/hardhat-scripts/deploy/6.connect.ts @@ -1,4 +1,4 @@ -import { Contract, Wallet } from "ethers"; +import { Wallet } from "ethers"; import { ChainAddressesObj, ChainSlug, Contracts } from "../../src"; import { chains, EVMX_CHAIN_ID, mode } from "../config"; import { AppGatewayConfig, DeploymentAddresses } from "../constants"; @@ -12,6 +12,7 @@ import { overrides, } from "../utils"; import { getWatcherSigner, sendWatcherMultiCallWithNonce } from "../utils/sign"; +import { isConfigSetOnEVMx, isConfigSetOnSocket } from "../utils"; const plugs = [Contracts.ContractFactoryPlug, Contracts.FeesPlug]; @@ -25,20 +26,6 @@ export const main = async () => { } }; -export const isConfigSetOnSocket = async ( - plug: Contract, - socket: Contract, - appGatewayId: string, - switchboard: string -) => { - const plugConfigRegistered = await socket.getPlugConfig(plug.address); - return ( - plugConfigRegistered.appGatewayId.toLowerCase() === - appGatewayId.toLowerCase() && - plugConfigRegistered.switchboard.toLowerCase() === switchboard.toLowerCase() - ); -}; - // Connect a single plug contract to its app gateway and switchboard async function connectPlug( chain: number, @@ -101,20 +88,6 @@ export const connectPlugsOnSocket = async () => { ); }; -export const isConfigSetOnEVMx = async ( - watcher: Contract, - chain: number, - plug: string, - appGatewayId: string, - switchboard: string -) => { - const plugConfigRegistered = await watcher.getPlugConfigs(chain, plug); - return ( - plugConfigRegistered[0].toLowerCase() === appGatewayId?.toLowerCase() && - plugConfigRegistered[1].toLowerCase() === switchboard.toLowerCase() - ); -}; - // Configure plugs on the Watcher VM export const updateConfigEVMx = async () => { try { diff --git a/hardhat-scripts/utils/appConfig.ts b/hardhat-scripts/utils/appConfig.ts new file mode 100644 index 00000000..40387b76 --- /dev/null +++ b/hardhat-scripts/utils/appConfig.ts @@ -0,0 +1,29 @@ +import { Contract } from "ethers"; + +export const isConfigSetOnSocket = async ( + plug: Contract, + socket: Contract, + appGatewayId: string, + switchboard: string +) => { + const plugConfigRegistered = await socket.getPlugConfig(plug.address); + return ( + plugConfigRegistered.appGatewayId.toLowerCase() === + appGatewayId.toLowerCase() && + plugConfigRegistered.switchboard.toLowerCase() === switchboard.toLowerCase() + ); +}; + +export const isConfigSetOnEVMx = async ( + watcher: Contract, + chain: number, + plug: string, + appGatewayId: string, + switchboard: string +) => { + const plugConfigRegistered = await watcher.getPlugConfigs(chain, plug); + return ( + plugConfigRegistered[0].toLowerCase() === appGatewayId?.toLowerCase() && + plugConfigRegistered[1].toLowerCase() === switchboard.toLowerCase() + ); +}; diff --git a/hardhat-scripts/utils/index.ts b/hardhat-scripts/utils/index.ts index b53a8577..e0b53879 100644 --- a/hardhat-scripts/utils/index.ts +++ b/hardhat-scripts/utils/index.ts @@ -1,4 +1,5 @@ export * from "./address"; +export * from "./appConfig"; export * from "./networks"; export * from "./overrides"; export * from "./accounts"; diff --git a/hardhat-scripts/utils/overrides.ts b/hardhat-scripts/utils/overrides.ts index b81f365b..5d49ab6e 100644 --- a/hardhat-scripts/utils/overrides.ts +++ b/hardhat-scripts/utils/overrides.ts @@ -30,6 +30,9 @@ export const chainOverrides: { [ChainSlug.BASE]: { gasLimit: 2_000_000, }, + [ChainSlug.ARBITRUM]: { + gasPrice: 100_629_157, + }, [EVMX_CHAIN_ID as ChainSlug]: { type: 0, // gasLimit: 1_000_000_000, diff --git a/test/FeesTest.t.sol b/test/FeesTest.t.sol index 73016fdc..c60bd554 100644 --- a/test/FeesTest.t.sol +++ b/test/FeesTest.t.sol @@ -15,6 +15,8 @@ contract FeesTest is AppGatewayBaseSetup { SocketContracts feesConfig; CounterAppGateway counterGateway; + event WithdrawFailed(bytes32 indexed payloadId); + function setUp() public { deploy(); @@ -32,6 +34,7 @@ contract FeesTest is AppGatewayBaseSetup { function withdrawCredits(address from, uint256 withdrawAmount) public { approveAppGateway(address(feesManager), from); + hoax(from); feesManager.withdrawCredits( feesChainSlug, @@ -49,8 +52,9 @@ contract FeesTest is AppGatewayBaseSetup { withdrawAmount = withdrawAmount - feesAmount; withdrawCredits(transmitterEOA, withdrawAmount); + uint256 withdrawAmountInTokens = withdrawAmount / 10 ** (18 - 6); assertEq( - transmitterReceiverBalanceBefore + withdrawAmount, + transmitterReceiverBalanceBefore + withdrawAmountInTokens, feesConfig.testUSDC.balanceOf(receiver), "Transmitter Balance should be correct" ); @@ -62,8 +66,9 @@ contract FeesTest is AppGatewayBaseSetup { withdrawCredits(address(counterGateway), withdrawAmount); + uint256 withdrawAmountInTokens = withdrawAmount / 10 ** (18 - 6); assertEq( - receiverBalanceBefore + withdrawAmount, + receiverBalanceBefore + withdrawAmountInTokens, feesConfig.testUSDC.balanceOf(receiver), "Receiver Balance should be correct" ); @@ -76,10 +81,126 @@ contract FeesTest is AppGatewayBaseSetup { uint256 withdrawAmount = 0.5 ether; withdrawCredits(user, withdrawAmount); + uint256 withdrawAmountInTokens = withdrawAmount / 10 ** (18 - 6); assertEq( - receiverBalanceBefore + withdrawAmount, + receiverBalanceBefore + withdrawAmountInTokens, feesConfig.testUSDC.balanceOf(receiver), "Receiver Balance should be correct" ); } + + function testDisconnectFeesPlug() public { + hoax(socketOwner); + + // disconnect old fees plug + arbConfig.feesPlug.connectSocket( + bytes32(0), + address(arbConfig.socket), + address(arbConfig.switchboard) + ); + + hoax(watcherEOA); + feesManager.setFeesPlug(arbChainSlug, address(0)); + + AppGatewayConfig[] memory configs = new AppGatewayConfig[](1); + configs[0] = AppGatewayConfig({ + chainSlug: arbChainSlug, + plug: address(arbConfig.feesPlug), + plugConfig: PlugConfig({ + appGatewayId: encodeAppGatewayId(address(0)), + switchboard: address(0) + }) + }); + watcherMultiCall( + address(configurations), + abi.encodeWithSelector(Configurations.setAppGatewayConfigs.selector, configs) + ); + + approveAppGateway(address(feesManager), address(counterGateway)); + uint256 withdrawAmount = 0.5 ether; + + vm.expectRevert(abi.encodeWithSelector(InvalidChainSlug.selector)); + hoax(address(counterGateway)); + feesManager.withdrawCredits( + arbChainSlug, + address(arbConfig.testUSDC), + withdrawAmount, + feesAmount, + address(receiver) + ); + } + + function testMigrateFeesPlug() public { + FeesPlug oldFeesPlug = arbConfig.feesPlug; + + // disconnect old fees plug + hoax(socketOwner); + oldFeesPlug.connectSocket( + bytes32(0), + address(arbConfig.socket), + address(arbConfig.switchboard) + ); + + // deploy new fees plug + arbConfig.feesPlug = new FeesPlug(address(arbConfig.socket), address(socketOwner)); + + // configure + vm.startPrank(socketOwner); + arbConfig.feesPlug.grantRole(RESCUE_ROLE, address(socketOwner)); + arbConfig.feesPlug.whitelistToken(address(arbConfig.testUSDC)); + arbConfig.feesPlug.connectSocket( + encodeAppGatewayId(address(feesManager)), + address(arbConfig.socket), + address(arbConfig.switchboard) + ); + vm.stopPrank(); + + hoax(watcherEOA); + feesManager.setFeesPlug(arbChainSlug, address(arbConfig.feesPlug)); + + AppGatewayConfig[] memory configs = new AppGatewayConfig[](1); + configs[0] = AppGatewayConfig({ + chainSlug: arbChainSlug, + plug: address(arbConfig.feesPlug), + plugConfig: PlugConfig({ + appGatewayId: encodeAppGatewayId(address(feesManager)), + switchboard: address(arbConfig.switchboard) + }) + }); + watcherMultiCall( + address(configurations), + abi.encodeWithSelector(Configurations.setAppGatewayConfigs.selector, configs) + ); + + uint256 withdrawAmount = 0.5 ether; + uint256 withdrawAmountInTokens = withdrawAmount / 10 ** (18 - 6); + approveAppGateway(address(feesManager), address(counterGateway)); + + uint256 receiverBalanceBefore = arbConfig.testUSDC.balanceOf(receiver); + + hoax(address(counterGateway)); + feesManager.withdrawCredits( + arbChainSlug, + address(arbConfig.testUSDC), + withdrawAmount, + feesAmount, + address(receiver) + ); + executeRequest(); + + assertEq( + arbConfig.testUSDC.balanceOf(receiver), + receiverBalanceBefore, + "Receiver balance should be same" + ); + + arbConfig.testUSDC.mint(address(arbConfig.feesPlug), withdrawAmount); + withdrawCredits(address(counterGateway), withdrawAmount); + + assertEq( + arbConfig.testUSDC.balanceOf(receiver), + receiverBalanceBefore + withdrawAmountInTokens, + "Receiver balance should increase" + ); + } } diff --git a/test/SetupTest.t.sol b/test/SetupTest.t.sol index 03ed46b2..377e2c4b 100644 --- a/test/SetupTest.t.sol +++ b/test/SetupTest.t.sol @@ -147,7 +147,10 @@ contract DeploySetup is SetupStore { vm.stopPrank(); _connectCorePlugs(); + _setupTransmitter(); + } + function _setupTransmitter() internal { vm.startPrank(transmitterEOA); arbConfig.testUSDC.mint(address(transmitterEOA), 100 ether); arbConfig.testUSDC.approve(address(arbConfig.feesPlug), 100 ether); @@ -158,9 +161,7 @@ contract DeploySetup is SetupStore { 100 ether ); - AppGatewayApprovals[] memory approvals = new AppGatewayApprovals[](1); - approvals[0] = AppGatewayApprovals({appGateway: address(auctionManager), approval: true}); - feesManager.approveAppGateways(approvals); + feesManager.approveAppGateway(address(auctionManager), true); vm.stopPrank(); } @@ -716,12 +717,17 @@ 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]); + bool isRequestExecuted; + for (uint i = 0; i < batches.length; i++) { + isRequestExecuted = _processBatch(batches[i]); + if (!isRequestExecuted) break; + } + requestParams = requestHandler.getRequest(requestCount); - assertEq(requestParams.requestTrackingParams.isRequestExecuted, true); + assertEq(requestParams.requestTrackingParams.isRequestExecuted, isRequestExecuted); } - function _processBatch(uint40 batchCount_) internal { + function _processBatch(uint40 batchCount_) internal returns (bool) { bytes32[] memory payloadIds = requestHandler.getBatchPayloadIds(batchCount_); PromiseReturnData[] memory promiseReturnData = new PromiseReturnData[](1); @@ -748,8 +754,11 @@ contract WatcherSetup is AuctionSetup { } else { vm.warp(payloadParams.deadline); _markRevert(promiseReturnData[0], true); + return false; } } + + return true; } function _processRead( diff --git a/test/Watcher.t.sol b/test/Watcher.t.sol index bc8eb07b..4a0b9395 100644 --- a/test/Watcher.t.sol +++ b/test/Watcher.t.sol @@ -4,6 +4,10 @@ pragma solidity ^0.8.21; import "./SetupTest.t.sol"; contract WatcherTest is AppGatewayBaseSetup { + function setUp() public { + deploy(); + } + function testWatcherDeployment() public { deploy(); @@ -13,4 +17,14 @@ contract WatcherTest is AppGatewayBaseSetup { vm.assertEq(address(arbConfig.contractFactoryPlug.socket__()), address(arbConfig.socket)); vm.assertEq(address(optConfig.contractFactoryPlug.socket__()), address(optConfig.socket)); } + + function testRevertInitSocketPlug() public { + address hackerEOA = address(0x123); + vm.expectRevert(abi.encodeWithSelector(SocketAlreadyInitialized.selector)); + arbConfig.feesPlug.initSocket( + bytes32(0), + address(hackerEOA), + address(arbConfig.switchboard) + ); + } }