Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(contracts/core): add additional actions to inbox #2360

Merged
merged 6 commits into from
Nov 4, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 25 additions & 7 deletions contracts/core/.gas-snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Admin_Test:test_pause_unpause_bridge() (gas: 21501844)
Admin_Test:test_pause_unpause_xcall() (gas: 26426087)
Admin_Test:test_pause_unpause_xsubmit() (gas: 26425838)
Admin_Test:test_upgrade() (gas: 30507332)
AllocPredeploys_Test:test_num_allocs() (gas: 1181198035)
AllocPredeploys_Test:test_num_allocs() (gas: 1181152549)
AllocPredeploys_Test:test_predeploys() (gas: 1181134337)
AllocPredeploys_Test:test_preinstalls() (gas: 1181850775)
AllocPredeploys_Test:test_proxies() (gas: 1408777576)
Expand All @@ -22,12 +22,30 @@ FeeOracleV2_Test:test_setExecGasPrice() (gas: 44247)
FeeOracleV2_Test:test_setManager() (gas: 45775)
FeeOracleV2_Test:test_setProtocolFee() (gas: 32226)
FeeOracleV2_Test:test_setToNativeRate() (gas: 43640)
Inbox_request_Test:test_request_multiToken() (gas: 547583)
Inbox_request_Test:test_request_nativeMultiToken() (gas: 605757)
Inbox_request_Test:test_request_reverts() (gas: 891165)
Inbox_request_Test:test_request_singleNative() (gas: 364015)
Inbox_request_Test:test_request_singleToken() (gas: 426691)
Inbox_request_Test:test_request_two() (gas: 671465)
Inbox_request_Test:test_accept_one_request() (gas: 399801)
Inbox_request_Test:test_accept_reverts() (gas: 801467)
Inbox_request_Test:test_accept_skip_first() (gas: 717578)
Inbox_request_Test:test_accept_two_requests() (gas: 740791)
Inbox_request_Test:test_cancel_multiToken() (gas: 534734)
Inbox_request_Test:test_cancel_nativeMultiToken() (gas: 605436)
Inbox_request_Test:test_cancel_oldest_request() (gas: 560631)
Inbox_request_Test:test_cancel_one_request() (gas: 314120)
Inbox_request_Test:test_cancel_rejected_nativeMultiToken_request() (gas: 611928)
Inbox_request_Test:test_cancel_rejected_nativeToken_request() (gas: 320258)
Inbox_request_Test:test_cancel_reverts() (gas: 825676)
Inbox_request_Test:test_cancel_singleToken() (gas: 389059)
Inbox_request_Test:test_cancel_two_requests() (gas: 566788)
Inbox_request_Test:test_reject_nativeMultiToken() (gas: 614992)
Inbox_request_Test:test_reject_oldest_request() (gas: 681251)
Inbox_request_Test:test_reject_one_request() (gas: 372690)
Inbox_request_Test:test_reject_reverts() (gas: 565842)
Inbox_request_Test:test_reject_two_requests() (gas: 684264)
Inbox_request_Test:test_request_multiToken() (gas: 548172)
Inbox_request_Test:test_request_nativeMultiToken() (gas: 606437)
Inbox_request_Test:test_request_reverts() (gas: 891638)
Inbox_request_Test:test_request_singleNative() (gas: 364446)
Inbox_request_Test:test_request_singleToken() (gas: 427141)
Inbox_request_Test:test_request_two() (gas: 672268)
InitializableHelper_Test:test_disableInitalizers() (gas: 181686)
InitializableHelper_Test:test_getInitialized() (gas: 178023)
OmniBridgeL1_Test:test_bridge() (gas: 233678)
Expand Down
1 change: 1 addition & 0 deletions contracts/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"@openzeppelin/contracts-upgradeable": "^5.0.2",
"eigenlayer-contracts": "github:Layr-Labs/eigenlayer-contracts",
"eigenlayer-middleware": "github:Layr-Labs/eigenlayer-middleware",
"solady": "^0.0.261",
"solmate": "^6.2.0"
}
}
9 changes: 9 additions & 0 deletions contracts/core/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

111 changes: 106 additions & 5 deletions contracts/core/src/solve/Inbox.sol
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity =0.8.24;

import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
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 { SafeERC20, IERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { Solve } from "./Solve.sol";

/**
* @title Inbox
* @notice Entrypoint and alt-mempoool for user solve requests.
*/
contract Inbox is ReentrancyGuardUpgradeable {
contract Inbox is OwnableRoles, ReentrancyGuard, Initializable {
using SafeERC20 for IERC20;

error NoDeposits();
error InvalidCall();
error InvalidDeposit();
error ZeroDeposit();
error RequestNotOpen();
error TransferFailed();
error RequestNotCancelable();

/**
* @notice Emitted when a request is created.
Expand All @@ -26,6 +30,32 @@ contract Inbox is ReentrancyGuardUpgradeable {
*/
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.
*/
event Rejected(bytes32 indexed id, address indexed by);

/**
* @notice Emitted when a request is cancelled.
* @param id ID of the request.
*/
event Cancelled(bytes32 indexed id);

/**
* @notice Role for solvers.
* @dev _ROLE_0 evaluates to '1'.
*/
uint256 internal constant SOLVER = _ROLE_0;

/**
* @dev uint repr of last assigned request ID.
*/
Expand All @@ -36,8 +66,15 @@ contract Inbox is ReentrancyGuardUpgradeable {
*/
mapping(bytes32 id => Solve.Request) internal _requests;

function initialize() public initializer {
__ReentrancyGuard_init();
/**
* @notice Initialize the contract's owner and solver.
* @dev Used instead of constructor as we want to use the transparent upgradeable proxy pattern.
* @param owner_ Address of the owner.
* @param solver_ Address of the solver.
*/
function initialize(address owner_, address solver_) external initializer {
_initializeOwner(owner_);
_grantRoles(solver_, SOLVER);
}

/**
Expand Down Expand Up @@ -71,6 +108,52 @@ contract Inbox is ReentrancyGuardUpgradeable {
return req.id;
}

/**
* @notice Accept an open request.
* @dev Only a whitelisted solver can accept.
* @param id ID of the request.
*/
function accept(bytes32 id) external onlyRoles(SOLVER) {
Solve.Request storage req = _requests[id];
if (req.status != Solve.Status.Open) revert RequestNotOpen();

req.updatedAt = uint40(block.timestamp);
req.status = Solve.Status.Accepted;
req.acceptedBy = msg.sender;

emit Accepted(id, msg.sender);
}

/**
* @notice Reject an open request.
* @dev Only a whitelisted solver can reject.
* @param id ID of the request.
*/
function reject(bytes32 id) external onlyRoles(SOLVER) {
Solve.Request storage req = _requests[id];
if (req.status != Solve.Status.Open) revert RequestNotOpen();

req.updatedAt = uint40(block.timestamp);
req.status = Solve.Status.Rejected;

emit Rejected(id, msg.sender);
}

/**
* @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 {
Zodomo marked this conversation as resolved.
Show resolved Hide resolved
Solve.Request storage req = _requests[id];
if (req.status != Solve.Status.Open && req.status != Solve.Status.Rejected) revert RequestNotCancelable();
if (req.from != msg.sender) revert Unauthorized();

_cancelRequest(req);

emit Cancelled(id);
}

/**
* @dev Open a new request in storage at `id`.
* Transfer token deposits from msg.sender to this inbox.
Expand All @@ -85,6 +168,7 @@ contract Inbox is ReentrancyGuardUpgradeable {
req = _requests[id];
req.id = id;
req.updatedAt = uint40(block.timestamp);
req.status = Solve.Status.Open;
req.from = from;
req.call = call;

Expand All @@ -104,6 +188,23 @@ contract Inbox is ReentrancyGuardUpgradeable {
}
}

function _cancelRequest(Solve.Request storage req) internal {
// Refund deposits
uint256 length = req.deposits.length;
for (uint256 i = 0; i < length; i++) {
Solve.Deposit memory deposit = req.deposits[i];
if (deposit.isNative) {
(bool success,) = payable(msg.sender).call{ value: deposit.amount }("");
if (!success) revert TransferFailed();
} else {
IERC20(deposit.token).safeTransfer(msg.sender, deposit.amount);
}
}

// Delete request
delete _requests[req.id];
Zodomo marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* @dev Increment and return _lastId.
*/
Expand Down
9 changes: 4 additions & 5 deletions contracts/core/src/solve/Solve.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,19 @@ pragma solidity =0.8.24;

library Solve {
enum Status {
Invalid,
Zodomo marked this conversation as resolved.
Show resolved Hide resolved
Open,
Accepted,
Cancelled,
Rejected,
Fulfilled,
Paid
Fulfilled
}

/**
* @notice A request to execute a call on another chain, backed by a deposit.
* @param id ID for the request, globally unique per inbox.
* @param updatedAt Timestamp request status was last updated.
* @param from Address of the user who created the request.
* @param fulfilledBy Address of the solver that fulfilled the request.
* @param acceptedBy Address of the solver that accepted the request.
* @param status Request status (open, accepted, cancelled, rejected, fulfilled, paid).
* @param call Details of the call to be executed on another chain.
* @param deposits Array of deposits backing the request.
Expand All @@ -26,7 +25,7 @@ library Solve {
uint40 updatedAt;
Status status;
address from;
address fulfilledBy;
address acceptedBy;
Call call;
Deposit[] deposits;
}
Expand Down
Loading
Loading