diff --git a/contracts/core/src/solve/Inbox.sol b/contracts/core/src/solve/Inbox.sol index eef633fc7..1f3e64f30 100644 --- a/contracts/core/src/solve/Inbox.sol +++ b/contracts/core/src/solve/Inbox.sol @@ -4,11 +4,10 @@ pragma solidity =0.8.24; import { OwnableRoles } from "solady/src/auth/OwnableRoles.sol"; import { ReentrancyGuard } from "solady/src/utils/ReentrancyGuard.sol"; import { Initializable } from "solady/src/utils/Initializable.sol"; -import { XAppBase } from "../pkg/XAppBase.sol"; -import { IInbox } from "./interfaces/IInbox.sol"; - import { SafeTransferLib } from "solady/src/utils/SafeTransferLib.sol"; -import { IConversionRateOracle } from "../interfaces/IConversionRateOracle.sol"; +import { IConversionRateOracle } from "src/interfaces/IConversionRateOracle.sol"; +import { XAppBase } from "src/pkg/XAppBase.sol"; +import { IInbox } from "./interfaces/IInbox.sol"; import { Solve } from "./Solve.sol"; /** @@ -25,50 +24,6 @@ contract Inbox is OwnableRoles, ReentrancyGuard, Initializable, XAppBase, IInbox error TransferFailed(); error RequestStateInvalid(); - /** - * @notice Emitted when a request is created. - * @param id ID of the request. - * @param from Address of the user who created the request. - * @param call Details of the call to be executed on another chain. - * @param deposits Array of deposits backing the request. - */ - event Requested(bytes32 indexed id, address indexed from, Solve.Call call, Solve.Deposit[] deposits); - - /** - * @notice Emitted when a request is accepted. - * @param id ID of the request. - * @param by Address of the solver who accepted the request. - */ - event Accepted(bytes32 indexed id, address indexed by); - - /** - * @notice Emitted when a request is rejected. - * @param id ID of the request. - * @param by Address of the solver who rejected the request. - * @param reason Reason for rejecting the request. - */ - event Rejected(bytes32 indexed id, address indexed by, Solve.RejectReason indexed reason); - - /** - * @notice Emitted when a request is cancelled. - * @param id ID of the request. - */ - event Reverted(bytes32 indexed id); - - /** - * @notice Emitted when a request is fulfilled. - * @param id ID of the request. - * @param callHash Hash of the call executed on another chain. - * @param creditedTo Address of the recipient credited the funds by the solver. - */ - event Fulfilled(bytes32 indexed id, bytes32 indexed callHash, address indexed creditedTo); - - /** - * @notice Emitted when a request is claimed. - * @param id ID of the request. - */ - event Claimed(bytes32 indexed id); - /** * @notice Role for solvers. * @dev _ROLE_0 evaluates to '1'. @@ -114,28 +69,6 @@ contract Inbox is OwnableRoles, ReentrancyGuard, Initializable, XAppBase, IInbox return _requests[id]; } - /** - * @notice Suggest the amount of native currency to send with a request. - * @param call Details of the call to be executed on another chain. - * @param gasLimit Maximum gas limit for the call. - * @param gasPrice Destination chain gas price in wei. - * @param fulfillFee Fee for the fulfill call, retrieved from the destination outbox. - */ - function suggestNativePayment(Solve.Call calldata call, uint64 gasLimit, uint64 gasPrice, uint256 fulfillFee) - external - view - returns (uint256) - { - IConversionRateOracle oracle = IConversionRateOracle(omni.feeOracle()); - - uint256 nativeValue = call.value * oracle.toNativeRate(call.destChainId) / oracle.CONVERSION_RATE_DENOM(); - uint256 executionFee = omni.feeFor(call.destChainId, call.data, gasLimit); - uint256 acceptFee = 55_000 * gasPrice; - uint256 solveFee = 100_000 gwei; // TODO: determine solve fee - - return nativeValue + executionFee + acceptFee + solveFee + fulfillFee; - } - /** * @notice Open a request to execute a call on another chain, backed by deposits. * Token deposits are transferred from msg.sender to this inbox. @@ -249,6 +182,28 @@ contract Inbox is OwnableRoles, ReentrancyGuard, Initializable, XAppBase, IInbox emit Claimed(id); } + /** + * @notice Suggest the amount of native currency to send with a request. + * @param call Details of the call to be executed on another chain. + * @param gasLimit Maximum gas limit for the call. + * @param gasPrice Destination chain gas price in wei. + * @param fulfillFee Fee for the fulfill call, retrieved from the destination outbox. + */ + function suggestNativePayment(Solve.Call calldata call, uint64 gasLimit, uint64 gasPrice, uint256 fulfillFee) + external + view + returns (uint256) + { + IConversionRateOracle oracle = IConversionRateOracle(omni.feeOracle()); + + uint256 nativeValue = call.value * oracle.toNativeRate(call.destChainId) / oracle.CONVERSION_RATE_DENOM(); + uint256 executionFee = omni.feeFor(call.destChainId, call.data, gasLimit); + uint256 acceptFee = 55_000 * gasPrice; + uint256 solveFee = 100_000 gwei; // TODO: determine solve fee + + return nativeValue + executionFee + acceptFee + solveFee + fulfillFee; + } + /** * @dev Transfer deposits to recipient. Used regardless of refund or claim. */ diff --git a/contracts/core/src/solve/interfaces/IInbox.sol b/contracts/core/src/solve/interfaces/IInbox.sol index c7acc07c8..7b76af1aa 100644 --- a/contracts/core/src/solve/interfaces/IInbox.sol +++ b/contracts/core/src/solve/interfaces/IInbox.sol @@ -1,6 +1,112 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity =0.8.24; +import { Solve } from "../Solve.sol"; + interface IInbox { + /** + * @notice Emitted when a request is created. + * @param id ID of the request. + * @param from Address of the user who created the request. + * @param call Details of the call to be executed on another chain. + * @param deposits Array of deposits backing the request. + */ + event Requested(bytes32 indexed id, address indexed from, Solve.Call call, Solve.Deposit[] deposits); + + /** + * @notice Emitted when a request is accepted. + * @param id ID of the request. + * @param by Address of the solver who accepted the request. + */ + event Accepted(bytes32 indexed id, address indexed by); + + /** + * @notice Emitted when a request is rejected. + * @param id ID of the request. + * @param by Address of the solver who rejected the request. + * @param reason Reason for rejecting the request. + */ + event Rejected(bytes32 indexed id, address indexed by, Solve.RejectReason indexed reason); + + /** + * @notice Emitted when a request is cancelled. + * @param id ID of the request. + */ + event Reverted(bytes32 indexed id); + + /** + * @notice Emitted when a request is fulfilled. + * @param id ID of the request. + * @param callHash Hash of the call executed on another chain. + * @param creditedTo Address of the recipient credited the funds by the solver. + */ + event Fulfilled(bytes32 indexed id, bytes32 indexed callHash, address indexed creditedTo); + + /** + * @notice Emitted when a request is claimed. + * @param id ID of the request. + */ + event Claimed(bytes32 indexed id); + + /** + * /** + * @notice Returns the request with the given ID. + */ + function getRequest(bytes32 id) external view returns (Solve.Request memory); + + /** + * @notice Suggest the amount of native currency to send with a request. + * @param call Details of the call to be executed on another chain. + * @param gasLimit Maximum gas limit for the call. + * @param gasPrice Destination chain gas price in wei. + * @param fulfillFee Fee for the fulfill call, retrieved from the destination outbox. + */ + function suggestNativePayment(Solve.Call calldata call, uint64 gasLimit, uint64 gasPrice, uint256 fulfillFee) + external + view + returns (uint256); + + /** + * @notice Open a request to execute a call on another chain, backed by deposits. + * Token deposits are transferred from msg.sender to this inbox. + * @param call Details of the call to be executed on another chain. + * @param deposits Array of deposits backing the request. + */ + function request(Solve.Call calldata call, Solve.TokenDeposit[] calldata deposits) + external + payable + returns (bytes32 id); + + /** + * @notice Accept an open request. + * @dev Only a whitelisted solver can accept. + * @param id ID of the request. + */ + function accept(bytes32 id) external; + + /** + * @notice Reject an open request. + * @dev Only a whitelisted solver can reject. + * @param id ID of the request. + */ + function reject(bytes32 id, Solve.RejectReason reason) external; + + /** + * @notice Cancel an open or rejected request and refund deposits. + * @dev Only request initiator can cancel. + * @param id ID of the request. + */ + function cancel(bytes32 id) external; + + /** + * @notice Fulfill a request. + * @dev Only callable by the outbox. + */ function markFulfilled(bytes32 id, bytes32 callHash, address creditTo) external; + + /** + * @notice Claim a fulfilled request. + * @param id ID of the request. + */ + function claim(bytes32 id) external; } diff --git a/contracts/core/test/solve/Outbox_fulfill.t.sol b/contracts/core/test/solve/Outbox_fulfill.t.sol index 5306b51ea..5de1a2357 100644 --- a/contracts/core/test/solve/Outbox_fulfill.t.sol +++ b/contracts/core/test/solve/Outbox_fulfill.t.sol @@ -5,7 +5,7 @@ import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/trans import { MockToken } from "test/utils/MockToken.sol"; import { MockVault } from "test/utils/MockVault.sol"; import { Outbox } from "src/solve/Outbox.sol"; -import { Inbox } from "src/solve/Inbox.sol"; +import { Inbox, IInbox } from "src/solve/Inbox.sol"; import { Solve } from "src/solve/Solve.sol"; import "test/xchain/common/Base.sol"; @@ -261,7 +261,7 @@ contract Outbox_fulfill_Test is Base { vm.prank(relayer); expectCalls(xsub.msgs); vm.expectEmit(true, true, true, true, address(inbox)); - emit Inbox.Fulfilled(bytes32(uint256(1)), callHash, solver); + emit IInbox.Fulfilled(bytes32(uint256(1)), callHash, solver); vm.expectEmit(true, true, true, false, address(portal)); emit IOmniPortal.XReceipt(chainAId, ConfLevel.Finalized, uint64(1), 0, relayer, true, bytes("")); portal.xsubmit(xsub);