Skip to content

Commit

Permalink
perf: reduce the cost of creating a request
Browse files Browse the repository at this point in the history
  • Loading branch information
gas1cent committed Oct 23, 2023
1 parent a5f05d5 commit c8a341c
Show file tree
Hide file tree
Showing 28 changed files with 3,507 additions and 2,018 deletions.
71 changes: 42 additions & 29 deletions solidity/contracts/Oracle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ contract Oracle is IOracle {
using EnumerableSet for EnumerableSet.Bytes32Set;
using EnumerableSet for EnumerableSet.AddressSet;

mapping(bytes32 _requestId => bytes32 _requestHash) internal _requestHashes;
mapping(bytes32 _requestId => HashedRequest _hashedRequest) internal _hashedRequests;

/// @inheritdoc IOracle
mapping(bytes32 _responseId => bytes32 _disputeId) public disputeOf;

Expand Down Expand Up @@ -156,23 +159,28 @@ contract Oracle is IOracle {
}

/// @inheritdoc IOracle
function proposeResponse(bytes32 _requestId, bytes calldata _responseData) external returns (bytes32 _responseId) {
function proposeResponse(
bytes32 _requestId,
bytes calldata _responseData,
bytes calldata _moduleData
) external returns (bytes32 _responseId) {
Request memory _request = _requests[_requestId];
if (_request.createdAt == 0) revert Oracle_InvalidRequestId(_requestId);
_responseId = _proposeResponse(msg.sender, _requestId, _request, _responseData);
_responseId = _proposeResponse(msg.sender, _requestId, _request, _responseData, _moduleData);

Check failure on line 169 in solidity/contracts/Oracle.sol

View workflow job for this annotation

GitHub Actions / Run Linters (16.x)

Missing named parameters. Max unnamed parameters value is 4
}

/// @inheritdoc IOracle
function proposeResponse(
address _proposer,
bytes32 _requestId,
bytes calldata _responseData
bytes calldata _responseData,
bytes calldata _moduleData
) external returns (bytes32 _responseId) {
Request memory _request = _requests[_requestId];
if (msg.sender != address(_request.disputeModule)) {
revert Oracle_NotDisputeModule(msg.sender);
}
_responseId = _proposeResponse(_proposer, _requestId, _request, _responseData);
_responseId = _proposeResponse(_proposer, _requestId, _request, _responseData, _moduleData);

Check failure on line 183 in solidity/contracts/Oracle.sol

View workflow job for this annotation

GitHub Actions / Run Linters (16.x)

Missing named parameters. Max unnamed parameters value is 4
}

/**
Expand All @@ -187,15 +195,17 @@ contract Oracle is IOracle {
address _proposer,
bytes32 _requestId,
Request memory _request,
bytes calldata _responseData
bytes calldata _responseData,
bytes calldata _moduleData
) internal returns (bytes32 _responseId) {
if (_request.finalizedAt != 0) {
revert Oracle_AlreadyFinalized(_requestId);
}

_responseId = keccak256(abi.encodePacked(_proposer, address(this), _requestId, _responseNonce++));
_participants[_requestId].add(_proposer);
_responses[_responseId] = _request.responseModule.propose(_requestId, _proposer, _responseData, msg.sender);
_responses[_responseId] =
_request.responseModule.propose(_requestId, _proposer, _responseData, _moduleData, msg.sender);

Check failure on line 208 in solidity/contracts/Oracle.sol

View workflow job for this annotation

GitHub Actions / Run Linters (16.x)

Missing named parameters. Max unnamed parameters value is 4
_responseIds[_requestId].add(_responseId);

if (_responses[_responseId].proposer != _proposer) {
Expand Down Expand Up @@ -226,7 +236,11 @@ contract Oracle is IOracle {
}

/// @inheritdoc IOracle
function disputeResponse(bytes32 _requestId, bytes32 _responseId) external returns (bytes32 _disputeId) {
function disputeResponse(
bytes32 _requestId,
bytes32 _responseId,
bytes calldata _moduleData
) external returns (bytes32 _disputeId) {
Request memory _request = _requests[_requestId];
if (_request.finalizedAt != 0) {
revert Oracle_AlreadyFinalized(_requestId);
Expand All @@ -244,7 +258,7 @@ contract Oracle is IOracle {
_participants[_requestId].add(msg.sender);

Dispute memory _dispute =
_request.disputeModule.disputeResponse(_requestId, _responseId, msg.sender, _response.proposer);
_request.disputeModule.disputeResponse(_requestId, _responseId, msg.sender, _response.proposer, _moduleData);

Check failure on line 261 in solidity/contracts/Oracle.sol

View workflow job for this annotation

GitHub Actions / Run Linters (16.x)

Missing named parameters. Max unnamed parameters value is 4
_disputes[_disputeId] = _dispute;
disputeOf[_responseId] = _disputeId;
_response.disputeId = _disputeId;
Expand All @@ -256,12 +270,12 @@ contract Oracle is IOracle {
emit ResponseDisputed(msg.sender, _responseId, _disputeId);

if (_dispute.status != DisputeStatus.Active) {
_request.disputeModule.onDisputeStatusChange(_disputeId, _dispute);
_request.disputeModule.onDisputeStatusChange(_disputeId, _dispute, _moduleData);
}
}

/// @inheritdoc IOracle
function escalateDispute(bytes32 _disputeId) external {
function escalateDispute(bytes32 _disputeId, bytes calldata _moduleData) external {
Dispute storage _dispute = _disputes[_disputeId];

if (_dispute.createdAt == 0) revert Oracle_InvalidDisputeId(_disputeId);
Expand All @@ -275,18 +289,18 @@ contract Oracle is IOracle {
Request memory _request = _requests[_dispute.requestId];

// Notify the dispute module about the escalation
_request.disputeModule.disputeEscalated(_disputeId);
_request.disputeModule.disputeEscalated(_disputeId, _moduleData);

emit DisputeEscalated(msg.sender, _disputeId);

if (address(_request.resolutionModule) != address(0)) {
// Initiate the resolution
_request.resolutionModule.startResolution(_disputeId);
_request.resolutionModule.startResolution(_disputeId, _moduleData);
}
}

/// @inheritdoc IOracle
function resolveDispute(bytes32 _disputeId) external {
function resolveDispute(bytes32 _disputeId, bytes calldata _moduleData) external {
Dispute memory _dispute = _disputes[_disputeId];

if (_dispute.createdAt == 0) revert Oracle_InvalidDisputeId(_disputeId);
Expand All @@ -300,20 +314,20 @@ contract Oracle is IOracle {
revert Oracle_NoResolutionModule(_disputeId);
}

_request.resolutionModule.resolveDispute(_disputeId);
_request.resolutionModule.resolveDispute(_disputeId, _moduleData);

emit DisputeResolved(msg.sender, _disputeId);
}

/// @inheritdoc IOracle
function updateDisputeStatus(bytes32 _disputeId, DisputeStatus _status) external {
function updateDisputeStatus(bytes32 _disputeId, DisputeStatus _status, bytes calldata _moduleData) external {
Dispute storage _dispute = _disputes[_disputeId];
Request memory _request = _requests[_dispute.requestId];
if (msg.sender != address(_request.disputeModule) && msg.sender != address(_request.resolutionModule)) {
revert Oracle_NotDisputeOrResolutionModule(msg.sender);
}
_dispute.status = _status;
_request.disputeModule.onDisputeStatusChange(_disputeId, _dispute);
_request.disputeModule.onDisputeStatusChange(_disputeId, _dispute, _moduleData);

emit DisputeStatusUpdated(_disputeId, _status);
}
Expand Down Expand Up @@ -419,8 +433,19 @@ contract Oracle is IOracle {
*/
function _createRequest(NewRequest memory _request) internal returns (bytes32 _requestId) {
uint256 _requestNonce = totalRequestCount++;
bytes32 _requestHash = keccak256(
abi.encodePacked(

Check failure on line 437 in solidity/contracts/Oracle.sol

View workflow job for this annotation

GitHub Actions / Run Linters (16.x)

Missing named parameters. Max unnamed parameters value is 4
_requestNonce,
_request.requestModule,
_request.responseModule,
_request.disputeModule,
_request.resolutionModule,
_request.finalityModule
)
);
_requestId = keccak256(abi.encodePacked(msg.sender, address(this), _requestNonce));
_requestIds[_requestNonce] = _requestId;
_requestHashes[_requestId] = _requestHash;

Request memory _storedRequest = Request({
ipfsHash: _request.ipfsHash,
Expand All @@ -438,19 +463,7 @@ contract Oracle is IOracle {
_requests[_requestId] = _storedRequest;
_participants[_requestId].add(msg.sender);

_request.requestModule.setupRequest(_requestId, _request.requestModuleData);
_request.responseModule.setupRequest(_requestId, _request.responseModuleData);
_request.disputeModule.setupRequest(_requestId, _request.disputeModuleData);

if (address(_request.resolutionModule) != address(0)) {
_request.resolutionModule.setupRequest(_requestId, _request.resolutionModuleData);
}

if (address(_request.finalityModule) != address(0)) {
_request.finalityModule.setupRequest(_requestId, _request.finalityModuleData);
}

emit RequestCreated(_requestId, msg.sender);
emit RequestCreated(_requestId, _requestHash, msg.sender, block.timestamp);
}

/**
Expand Down
163 changes: 163 additions & 0 deletions solidity/contracts/extensions/AccountingExtension.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
import {EnumerableSet} from '@openzeppelin/contracts/utils/structs/EnumerableSet.sol';
import {IOracle} from '../../interfaces/IOracle.sol';

import {IAccountingExtension} from '../../interfaces/extensions/IAccountingExtension.sol';

contract AccountingExtension is IAccountingExtension {
using SafeERC20 for IERC20;
using EnumerableSet for EnumerableSet.AddressSet;

/// @inheritdoc IAccountingExtension
IOracle public immutable ORACLE;

/// @inheritdoc IAccountingExtension
mapping(address _bonder => mapping(IERC20 _token => uint256 _balance)) public balanceOf;

/// @inheritdoc IAccountingExtension
mapping(address _bonder => mapping(IERC20 _token => mapping(bytes32 _requestId => uint256 _amount))) public
bondedAmountOf;

/**
* @notice Storing which modules have the users approved to bond their tokens.
*/
mapping(address _bonder => EnumerableSet.AddressSet _modules) internal _approvals;

constructor(IOracle _oracle) {
ORACLE = _oracle;
}

/**
* @notice Checks that the caller is an allowed module used in the request.
*/
modifier onlyAllowedModule(bytes32 _requestId) {
if (!ORACLE.allowedModule(_requestId, msg.sender)) revert AccountingExtension_UnauthorizedModule();
_;
}

modifier onlyParticipant(bytes32 _requestId, address _user) {
if (!ORACLE.isParticipant(_requestId, _user)) revert AccountingExtension_UnauthorizedUser();
_;
}

/// @inheritdoc IAccountingExtension
function deposit(IERC20 _token, uint256 _amount) external {
_token.safeTransferFrom(msg.sender, address(this), _amount);
balanceOf[msg.sender][_token] += _amount;
emit Deposited(msg.sender, _token, _amount);
}

/// @inheritdoc IAccountingExtension
function withdraw(IERC20 _token, uint256 _amount) external {
uint256 _balance = balanceOf[msg.sender][_token];

if (_balance < _amount) revert AccountingExtension_InsufficientFunds();

unchecked {
balanceOf[msg.sender][_token] -= _amount;
}

_token.safeTransfer(msg.sender, _amount);

emit Withdrew(msg.sender, _token, _amount);
}

/// @inheritdoc IAccountingExtension
function pay(
bytes32 _requestId,
address _payer,
address _receiver,
IERC20 _token,
uint256 _amount
) external onlyAllowedModule(_requestId) onlyParticipant(_requestId, _payer) onlyParticipant(_requestId, _receiver) {
if (bondedAmountOf[_payer][_token][_requestId] < _amount) {
revert AccountingExtension_InsufficientFunds();
}

balanceOf[_receiver][_token] += _amount;

unchecked {
bondedAmountOf[_payer][_token][_requestId] -= _amount;
}

emit Paid({_requestId: _requestId, _beneficiary: _receiver, _payer: _payer, _token: _token, _amount: _amount});
}

/// @inheritdoc IAccountingExtension
function bond(
address _bonder,
bytes32 _requestId,
IERC20 _token,
uint256 _amount
) external onlyAllowedModule(_requestId) onlyParticipant(_requestId, _bonder) {
if (!_approvals[_bonder].contains(msg.sender)) revert AccountingExtension_InsufficientAllowance();
if (balanceOf[_bonder][_token] < _amount) revert AccountingExtension_InsufficientFunds();

bondedAmountOf[_bonder][_token][_requestId] += _amount;

unchecked {
balanceOf[_bonder][_token] -= _amount;
}

emit Bonded(_requestId, _bonder, _token, _amount);
}

/// @inheritdoc IAccountingExtension
function bond(
address _bonder,
bytes32 _requestId,
IERC20 _token,
uint256 _amount,
address _sender
) external onlyAllowedModule(_requestId) onlyParticipant(_requestId, _bonder) {
if (!(_approvals[_bonder].contains(msg.sender) || _approvals[_bonder].contains(_sender))) {
revert AccountingExtension_InsufficientAllowance();
}
if (balanceOf[_bonder][_token] < _amount) revert AccountingExtension_InsufficientFunds();

bondedAmountOf[_bonder][_token][_requestId] += _amount;

unchecked {
balanceOf[_bonder][_token] -= _amount;
}

emit Bonded(_requestId, _bonder, _token, _amount);
}

/// @inheritdoc IAccountingExtension
function release(
address _bonder,
bytes32 _requestId,
IERC20 _token,
uint256 _amount
) external onlyAllowedModule(_requestId) onlyParticipant(_requestId, _bonder) {
if (bondedAmountOf[_bonder][_token][_requestId] < _amount) revert AccountingExtension_InsufficientFunds();

balanceOf[_bonder][_token] += _amount;

unchecked {
bondedAmountOf[_bonder][_token][_requestId] -= _amount;
}

emit Released(_requestId, _bonder, _token, _amount);
}

/// @inheritdoc IAccountingExtension
function approveModule(address _module) external {
_approvals[msg.sender].add(_module);
}

/// @inheritdoc IAccountingExtension
function revokeModule(address _module) external {
_approvals[msg.sender].remove(_module);
}

/// @inheritdoc IAccountingExtension
function approvedModules(address _user) external view returns (address[] memory _approvedModules) {
_approvedModules = _approvals[_user].values();
}
}
Loading

0 comments on commit c8a341c

Please sign in to comment.