diff --git a/contracts/dapp/Application.sol b/contracts/dapp/Application.sol index d74b3510..41cc1a6e 100644 --- a/contracts/dapp/Application.sol +++ b/contracts/dapp/Application.sol @@ -168,7 +168,14 @@ contract Application is (address, uint256, bytes) ); - destination.safeCall(value, payload); + bool enoughFunds; + uint256 balance; + + (enoughFunds, balance) = destination.safeCall(value, payload); + + if (!enoughFunds) { + revert InsufficientFunds(value, balance); + } } /// @notice Executes a delegatecall voucher diff --git a/contracts/dapp/IApplication.sol b/contracts/dapp/IApplication.sol index c0d0bb9b..fa95aba1 100644 --- a/contracts/dapp/IApplication.sol +++ b/contracts/dapp/IApplication.sol @@ -47,6 +47,11 @@ interface IApplication is IOwnable { /// @param output The output error OutputNotReexecutable(bytes output); + /// @notice Could not execute an output, because the application contract doesn't have enough Ether. + /// @param value The amount of Wei necessary for the execution of the output + /// @param balance The current application contract balance + error InsufficientFunds(uint256 value, uint256 balance); + /// @notice Raised when the output hashes siblings array has an invalid size. /// @dev Please consult `CanonicalMachine` for the maximum number of outputs. error InvalidOutputHashesSiblingsArrayLength(); diff --git a/contracts/library/LibAddress.sol b/contracts/library/LibAddress.sol index 7583494b..5872ca7e 100644 --- a/contracts/library/LibAddress.sol +++ b/contracts/library/LibAddress.sol @@ -8,29 +8,23 @@ import {LibError} from "../library/LibError.sol"; library LibAddress { using LibError for bytes; - /// @notice Caller does not have enough Ether to make call - /// @param caller The address of the contract making the call - /// @param value The value being transmitted through the call - /// @param balance The current contract balance - error InsufficientFunds(address caller, uint256 value, uint256 balance); - /// @notice Perform a low level call and raise error if failed /// @param destination The address that will be called /// @param value The amount of Wei to be transferred through the call /// @param payload The payload, which—in the case of Solidity /// contracts—encodes a function call - /// @dev Raises an `InsufficientFunds` error - /// if the caller has less than `value` Wei + /// @return Whether the caller had enough Ether to make the call, + /// and the balance before the call function safeCall( address destination, uint256 value, bytes memory payload - ) internal { + ) internal returns (bool, uint256) { address caller = address(this); uint256 balance = caller.balance; if (value > balance) { - revert InsufficientFunds(caller, value, balance); + return (false, balance); } bool success; @@ -41,6 +35,8 @@ library LibAddress { if (!success) { returndata.raise(); } + + return (true, balance); } /// @notice Perform a delegate call and raise error if failed diff --git a/test/dapp/Application.t.sol b/test/dapp/Application.t.sol index d0ddfe3b..cf961ef3 100644 --- a/test/dapp/Application.t.sol +++ b/test/dapp/Application.t.sol @@ -562,8 +562,7 @@ contract ApplicationTest is TestBase, OwnableTest { vm.expectRevert( abi.encodeWithSelector( - LibAddress.InsufficientFunds.selector, - address(_appContract), + IApplication.InsufficientFunds.selector, _transferAmount, 0 )