Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
30 changes: 24 additions & 6 deletions contracts/src/0.8/RealitioForeignProxyOptimism.sol
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ contract RealitioForeignProxyOptimism is IForeignArbitrationProxy, IDisputeResol
Requested,
Created,
Ruled,
Relayed,
Failed
}

Expand Down Expand Up @@ -237,8 +238,9 @@ contract RealitioForeignProxyOptimism is IForeignArbitrationProxy, IDisputeResol

uint256 deposit = arbitration.deposit;

delete arbitrationRequests[arbitrationID][_requester];

// Note that we don't nullify the status to allow the function to be called
// multiple times to avoid intentional blocking.
arbitration.deposit = 0;
payable(_requester).safeSend(deposit, wNative);

messenger.sendMessage(homeProxy, data, MIN_GAS_LIMIT);
Expand Down Expand Up @@ -412,14 +414,30 @@ contract RealitioForeignProxyOptimism is IForeignArbitrationProxy, IDisputeResol
arbitration.answer = finalRuling;
arbitration.status = Status.Ruled;

emit Ruling(arbitrator, _disputeID, finalRuling);
}

/**
* @notice Relays the ruling to home proxy.
* @param _questionID The ID of the question.
* @param _requester The address of the arbitration requester.
*/
function relayRule(bytes32 _questionID, address _requester) external {
uint256 arbitrationID = uint256(_questionID);
ArbitrationRequest storage arbitration = arbitrationRequests[arbitrationID][_requester];
// Note that we allow to relay multiple times to prevent intentional blocking.
require(arbitration.status == Status.Ruled || arbitration.status == Status.Relayed, "Dispute not resolved");

// Realitio ruling is shifted by 1 compared to Kleros.
uint256 realitioRuling = finalRuling != 0 ? finalRuling - 1 : REFUSE_TO_ARBITRATE_REALITIO;
uint256 realitioRuling = arbitration.answer != 0 ? arbitration.answer - 1 : REFUSE_TO_ARBITRATE_REALITIO;

bytes4 methodSelector = IHomeArbitrationProxy.receiveArbitrationAnswer.selector;
bytes memory data = abi.encodeWithSelector(methodSelector, bytes32(arbitrationID), bytes32(realitioRuling));
messenger.sendMessage(homeProxy, data, MIN_GAS_LIMIT);
bytes memory data = abi.encodeWithSelector(methodSelector, _questionID, bytes32(realitioRuling));

emit Ruling(arbitrator, _disputeID, finalRuling);
arbitration.status = Status.Relayed;

messenger.sendMessage(homeProxy, data, MIN_GAS_LIMIT);
emit RulingRelayed(_questionID, bytes32(realitioRuling));
}

// ********************************* //
Expand Down
27 changes: 21 additions & 6 deletions contracts/test/foreign-proxy-optimism.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ describe("Cross-chain arbitration with appeals", () => {
.withArgs(questionID, await requester.getAddress());

let arbitration = await foreignProxy.arbitrationRequests(arbitrationID, await requester.getAddress());
expect(arbitration[0]).to.equal(4, "Status should be Failed");
expect(arbitration[0]).to.equal(5, "Status should be Failed");

const oldBalance = await getBalance(requester);
await expect(foreignProxy.connect(other).handleFailedDisputeCreation(questionID, await requester.getAddress()))
Expand All @@ -290,12 +290,16 @@ describe("Cross-chain arbitration with appeals", () => {
expect(newBalance).to.equal(oldBalance + toBigInt(arbitrationCost), "Requester was not reimbursed correctly");

arbitration = await foreignProxy.arbitrationRequests(0, await requester.getAddress());
expect(arbitration[0]).to.equal(0, "Status should be empty");
expect(arbitration[0]).to.equal(5, "Status should not change");
expect(arbitration[1]).to.equal(0, "Deposit should be empty");
expect(arbitration[2]).to.equal(0, "Dispute id should be empty");

const request = await homeProxy.requests(questionID, await requester.getAddress());
expect(request[0]).to.equal(0, "Status should be nullified in home proxy");

await expect(
foreignProxy.connect(other).handleFailedDisputeCreation(questionID, await requester.getAddress())
).to.be.revertedWith("Failed TxToL1");
});

it("Should handle the ruling correctly", async () => {
Expand All @@ -311,14 +315,21 @@ describe("Cross-chain arbitration with appeals", () => {

await expect(arbitrator.giveRuling(2, 8))
.to.emit(foreignProxy, "Ruling")
.withArgs(arbitrator.target, 2, 8)
.to.emit(homeProxy, "ArbitratorAnswered")
.withArgs(questionID, arbAnswer);
.withArgs(arbitrator.target, 2, 8);

const arbitration = await foreignProxy.arbitrationRequests(arbitrationID, await requester.getAddress());
let arbitration = await foreignProxy.arbitrationRequests(arbitrationID, await requester.getAddress());
expect(arbitration[0]).to.equal(3, "Status should be Ruled");
expect(arbitration[3]).to.equal(8, "Stored answer is incorrect");

await expect(foreignProxy.connect(other).relayRule(questionID, await requester.getAddress()))
.to.emit(foreignProxy, "RulingRelayed")
.withArgs(questionID, arbAnswer)
.to.emit(homeProxy, "ArbitratorAnswered")
.withArgs(questionID, arbAnswer);

arbitration = await foreignProxy.arbitrationRequests(arbitrationID, await requester.getAddress());
expect(arbitration[0]).to.equal(4, "Status should be Relayed");

let request = await homeProxy.requests(questionID, await requester.getAddress());
expect(request[0]).to.equal(4, "Status should be Ruled");
expect(request[1]).to.equal(arbAnswer, "Incorrect answer stored");
Expand All @@ -331,6 +342,10 @@ describe("Cross-chain arbitration with appeals", () => {

request = await homeProxy.requests(questionID, await requester.getAddress());
expect(request[0]).to.equal(5, "Status should be Finished");

await expect(foreignProxy.connect(other).relayRule(questionID, await requester.getAddress())).to.be.revertedWith(
"Failed TxToL1"
);
});

it("Should correctly fund an appeal and fire the events", async () => {
Expand Down