From 9be0f100c48e4726bee73829fbb10f7d85b6ef54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Tue, 16 Oct 2018 17:21:24 -0300 Subject: [PATCH] Removed BreakInvariantBounty. (#1424) --- contracts/bounties/BreakInvariantBounty.sol | 93 ------------- contracts/mocks/BreakInvariantBountyMock.sol | 28 ---- test/BreakInvariantBounty.test.js | 131 ------------------- 3 files changed, 252 deletions(-) delete mode 100644 contracts/bounties/BreakInvariantBounty.sol delete mode 100644 contracts/mocks/BreakInvariantBountyMock.sol delete mode 100644 test/BreakInvariantBounty.test.js diff --git a/contracts/bounties/BreakInvariantBounty.sol b/contracts/bounties/BreakInvariantBounty.sol deleted file mode 100644 index 6dec45a3b..000000000 --- a/contracts/bounties/BreakInvariantBounty.sol +++ /dev/null @@ -1,93 +0,0 @@ -pragma solidity ^0.4.24; - -import "../payment/PullPayment.sol"; -import "../ownership/Ownable.sol"; - -/** - * @title BreakInvariantBounty - * @dev This bounty will pay out to a researcher if they break invariant logic of the contract. - */ -contract BreakInvariantBounty is PullPayment, Ownable { - bool private _claimable; - mapping(address => address) private _researchers; - - event TargetCreated(address createdAddress); - event BountyCanceled(); - - constructor() public { - _claimable = true; - } - - /** - * @dev Fallback function allowing the contract to receive funds, if they haven't already been claimed. - */ - function() external payable { - require(_claimable); - } - - /** - * @dev Determine if the bounty is claimable. - * @return false if the bounty was claimed, true otherwise. - */ - function claimable() public view returns(bool) { - return _claimable; - } - - /** - * @dev Create and deploy the target contract (extension of Target contract), and sets the - * msg.sender as a researcher - * @return A target contract - */ - function createTarget() public returns(Target) { - Target target = Target(_deployContract()); - _researchers[target] = msg.sender; - emit TargetCreated(target); - return target; - } - - /** - * @dev Transfers the contract funds to the researcher that proved the contract is broken. - * @param target contract - */ - function claim(Target target) public { - require(_claimable); - address researcher = _researchers[target]; - require(researcher != address(0)); - // Check Target contract invariants - require(!target.checkInvariant()); - _asyncTransfer(researcher, address(this).balance); - _claimable = false; - } - - /** - * @dev Cancels the bounty and transfers all funds to the owner - */ - function cancelBounty() public onlyOwner{ - require(_claimable); - _asyncTransfer(owner(), address(this).balance); - _claimable = false; - emit BountyCanceled(); - } - - /** - * @dev Internal function to deploy the target contract. - * @return A target contract address - */ - function _deployContract() internal returns(address); - -} - -/** - * @title Target - * @dev Your main contract should inherit from this class and implement the checkInvariant method. - */ -contract Target { - - /** - * @dev Checks all values a contract assumes to be true all the time. If this function returns - * false, the contract is broken in some way and is in an inconsistent state. - * In order to win the bounty, security researchers will try to cause this broken state. - * @return True if all invariant values are correct, false otherwise. - */ - function checkInvariant() public returns(bool); -} diff --git a/contracts/mocks/BreakInvariantBountyMock.sol b/contracts/mocks/BreakInvariantBountyMock.sol deleted file mode 100644 index 9343ef012..000000000 --- a/contracts/mocks/BreakInvariantBountyMock.sol +++ /dev/null @@ -1,28 +0,0 @@ -pragma solidity ^0.4.24; - -// When this line is split, truffle parsing fails. -// See: https://github.com/ethereum/solidity/issues/4871 -// solium-disable-next-line max-len -import {BreakInvariantBounty, Target} from "../bounties/BreakInvariantBounty.sol"; - -contract TargetMock is Target { - bool private exploited; - - function exploitVulnerability() public { - exploited = true; - } - - function checkInvariant() public returns (bool) { - if (exploited) { - return false; - } - - return true; - } -} - -contract BreakInvariantBountyMock is BreakInvariantBounty { - function _deployContract() internal returns (address) { - return new TargetMock(); - } -} diff --git a/test/BreakInvariantBounty.test.js b/test/BreakInvariantBounty.test.js deleted file mode 100644 index 77f11bb2b..000000000 --- a/test/BreakInvariantBounty.test.js +++ /dev/null @@ -1,131 +0,0 @@ -const { ethGetBalance, ethSendTransaction } = require('./helpers/web3'); -const { ether } = require('./helpers/ether'); -const { sendEther } = require('./helpers/sendTransaction'); -const { balanceDifference } = require('./helpers/balanceDiff'); -const expectEvent = require('./helpers/expectEvent'); -const shouldFail = require('./helpers/shouldFail'); - -const BreakInvariantBountyMock = artifacts.require('BreakInvariantBountyMock'); -const TargetMock = artifacts.require('TargetMock'); - -require('chai') - .use(require('chai-bignumber')(web3.BigNumber)) - .should(); - -const reward = ether(1); - -contract('BreakInvariantBounty', function ([_, owner, researcher, anyone, nonTarget]) { - beforeEach(async function () { - this.bounty = await BreakInvariantBountyMock.new({ from: owner }); - }); - - it('can set reward', async function () { - await sendEther(owner, this.bounty.address, reward); - (await ethGetBalance(this.bounty.address)).should.be.bignumber.equal(reward); - }); - - context('with reward', function () { - beforeEach(async function () { - await sendEther(owner, this.bounty.address, reward); - }); - - describe('claim', function () { - it('is initially claimable', async function () { - (await this.bounty.claimable()).should.equal(true); - }); - - it('can create claimable target', async function () { - const { logs } = await this.bounty.createTarget({ from: researcher }); - expectEvent.inLogs(logs, 'TargetCreated'); - }); - - context('with target', async function () { - beforeEach(async function () { - const { logs } = await this.bounty.createTarget({ from: researcher }); - const event = expectEvent.inLogs(logs, 'TargetCreated'); - this.target = TargetMock.at(event.args.createdAddress); - }); - - context('before exploiting vulnerability', async function () { - it('reverts when claiming reward', async function () { - await shouldFail.reverting(this.bounty.claim(this.target.address, { from: researcher })); - }); - }); - - context('after exploiting vulnerability', async function () { - beforeEach(async function () { - await this.target.exploitVulnerability({ from: researcher }); - }); - - it('sends the reward to the researcher', async function () { - await this.bounty.claim(this.target.address, { from: anyone }); - (await balanceDifference(researcher, () => this.bounty.withdrawPayments(researcher))) - .should.be.bignumber.equal(reward); - (await ethGetBalance(this.bounty.address)).should.be.bignumber.equal(0); - }); - - context('after claiming', async function () { - beforeEach(async function () { - await this.bounty.claim(this.target.address, { from: researcher }); - }); - - it('is not claimable', async function () { - (await this.bounty.claimable()).should.equal(false); - }); - - it('no longer accepts rewards', async function () { - await shouldFail.reverting(ethSendTransaction({ from: owner, to: this.bounty.address, value: reward })); - }); - - it('reverts when reclaimed', async function () { - await shouldFail.reverting(this.bounty.claim(this.target.address, { from: researcher })); - }); - }); - }); - }); - - context('with non-target', function () { - it('reverts when claiming reward', async function () { - await shouldFail.reverting(this.bounty.claim(nonTarget, { from: researcher })); - }); - }); - }); - - describe('cancelBounty', function () { - context('before canceling', function () { - it('is claimable', async function () { - (await this.bounty.claimable()).should.equal(true); - }); - - it('can be canceled by the owner', async function () { - const { logs } = await this.bounty.cancelBounty({ from: owner }); - expectEvent.inLogs(logs, 'BountyCanceled'); - (await balanceDifference(owner, () => this.bounty.withdrawPayments(owner))) - .should.be.bignumber.equal(reward); - }); - - it('reverts when canceled by anyone', async function () { - await shouldFail.reverting(this.bounty.cancelBounty({ from: anyone })); - }); - }); - - context('after canceling', async function () { - beforeEach(async function () { - await this.bounty.cancelBounty({ from: owner }); - }); - - it('is not claimable', async function () { - (await this.bounty.claimable()).should.equal(false); - }); - - it('no longer accepts rewards', async function () { - await shouldFail.reverting(ethSendTransaction({ from: owner, to: this.bounty.address, value: reward })); - }); - - it('reverts when recanceled', async function () { - await shouldFail.reverting(this.bounty.cancelBounty({ from: owner })); - }); - }); - }); - }); -});