Browse Source

Removed selfdestruct from BreakInvariantBounty (#1385)

* signing prefix added

* Minor improvement

* Tests changed

* Successfully tested

* Minor improvements

* Minor improvements

* Revert "Dangling commas are now required. (#1359)"

This reverts commit a6889776f46adca374b6ebf014aa7b0038112a9d.

* updates

* fixes #1384

* introduced claimable and cancelBounty

* cancelBounty tests

* Update BreakInvariantBounty.test.js
Aniket 7 years ago
parent
commit
41f84f8b40
2 changed files with 58 additions and 31 deletions
  1. 15 11
      contracts/bounties/BreakInvariantBounty.sol
  2. 43 20
      test/BreakInvariantBounty.test.js

+ 15 - 11
contracts/bounties/BreakInvariantBounty.sol

@@ -8,24 +8,25 @@ import "../ownership/Ownable.sol";
  * @dev This bounty will pay out to a researcher if they break invariant logic of the contract.
  * @dev This bounty will pay out to a researcher if they break invariant logic of the contract.
  */
  */
 contract BreakInvariantBounty is PullPayment, Ownable {
 contract BreakInvariantBounty is PullPayment, Ownable {
-  bool private _claimed;
+  bool private _claimable = true;
   mapping(address => address) private _researchers;
   mapping(address => address) private _researchers;
 
 
   event TargetCreated(address createdAddress);
   event TargetCreated(address createdAddress);
+  event BountyCanceled();
 
 
   /**
   /**
    * @dev Fallback function allowing the contract to receive funds, if they haven't already been claimed.
    * @dev Fallback function allowing the contract to receive funds, if they haven't already been claimed.
    */
    */
   function() external payable {
   function() external payable {
-    require(!_claimed);
+    require(_claimable);
   }
   }
 
 
   /**
   /**
-   * @dev Determine if the bounty was claimed.
-   * @return true if the bounty was claimed, false otherwise.
+   * @dev Determine if the bounty is claimable.
+   * @return false if the bounty was claimed, true otherwise.
    */
    */
-  function claimed() public view returns(bool) {
-    return _claimed;
+  function claimable() public view returns(bool) {
+    return _claimable;
   }
   }
 
 
   /**
   /**
@@ -45,20 +46,23 @@ contract BreakInvariantBounty is PullPayment, Ownable {
    * @param target contract
    * @param target contract
    */
    */
   function claim(Target target) public {
   function claim(Target target) public {
-    require(!_claimed);
+    require(_claimable);
     address researcher = _researchers[target];
     address researcher = _researchers[target];
     require(researcher != address(0));
     require(researcher != address(0));
     // Check Target contract invariants
     // Check Target contract invariants
     require(!target.checkInvariant());
     require(!target.checkInvariant());
     _asyncTransfer(researcher, address(this).balance);
     _asyncTransfer(researcher, address(this).balance);
-    _claimed = true;
+    _claimable = false;
   }
   }
 
 
   /**
   /**
-   * @dev Transfers the current balance to the owner and terminates the contract.
+   * @dev Cancels the bounty and transfers all funds to the owner
    */
    */
-  function destroy() public onlyOwner {
-    selfdestruct(owner());
+  function cancelBounty() public onlyOwner{
+    require(_claimable);
+    _asyncTransfer(owner(), address(this).balance);
+    _claimable = false;
+    emit BountyCanceled();
   }
   }
 
 
   /**
   /**

+ 43 - 20
test/BreakInvariantBounty.test.js

@@ -1,4 +1,5 @@
 const { ethGetBalance, ethSendTransaction } = require('./helpers/web3');
 const { ethGetBalance, ethSendTransaction } = require('./helpers/web3');
+const { ether } = require('./helpers/ether');
 const { sendEther } = require('./helpers/sendTransaction');
 const { sendEther } = require('./helpers/sendTransaction');
 const { balanceDifference } = require('./helpers/balanceDiff');
 const { balanceDifference } = require('./helpers/balanceDiff');
 const expectEvent = require('./helpers/expectEvent');
 const expectEvent = require('./helpers/expectEvent');
@@ -11,7 +12,7 @@ require('chai')
   .use(require('chai-bignumber')(web3.BigNumber))
   .use(require('chai-bignumber')(web3.BigNumber))
   .should();
   .should();
 
 
-const reward = new web3.BigNumber(web3.toWei(1, 'ether'));
+const reward = ether(1);
 
 
 contract('BreakInvariantBounty', function ([_, owner, researcher, anyone, nonTarget]) {
 contract('BreakInvariantBounty', function ([_, owner, researcher, anyone, nonTarget]) {
   beforeEach(async function () {
   beforeEach(async function () {
@@ -28,24 +29,9 @@ contract('BreakInvariantBounty', function ([_, owner, researcher, anyone, nonTar
       await sendEther(owner, this.bounty.address, reward);
       await sendEther(owner, this.bounty.address, reward);
     });
     });
 
 
-    describe('destroy', function () {
-      it('returns all balance to the owner', async function () {
-        const ownerPreBalance = await ethGetBalance(owner);
-        await this.bounty.destroy({ from: owner, gasPrice: 0 });
-        const ownerPostBalance = await ethGetBalance(owner);
-
-        (await ethGetBalance(this.bounty.address)).should.be.bignumber.equal(0);
-        ownerPostBalance.sub(ownerPreBalance).should.be.bignumber.equal(reward);
-      });
-
-      it('reverts when called by anyone', async function () {
-        await assertRevert(this.bounty.destroy({ from: anyone }));
-      });
-    });
-
     describe('claim', function () {
     describe('claim', function () {
-      it('is initially unclaimed', async function () {
-        (await this.bounty.claimed()).should.equal(false);
+      it('is initially claimable', async function () {
+        (await this.bounty.claimable()).should.equal(true);
       });
       });
 
 
       it('can create claimable target', async function () {
       it('can create claimable target', async function () {
@@ -83,8 +69,8 @@ contract('BreakInvariantBounty', function ([_, owner, researcher, anyone, nonTar
               await this.bounty.claim(this.target.address, { from: researcher });
               await this.bounty.claim(this.target.address, { from: researcher });
             });
             });
 
 
-            it('is claimed', async function () {
-              (await this.bounty.claimed()).should.equal(true);
+            it('is not claimable', async function () {
+              (await this.bounty.claimable()).should.equal(false);
             });
             });
 
 
             it('no longer accepts rewards', async function () {
             it('no longer accepts rewards', async function () {
@@ -104,5 +90,42 @@ contract('BreakInvariantBounty', function ([_, owner, researcher, anyone, nonTar
         });
         });
       });
       });
     });
     });
+
+    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 assertRevert(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 assertRevert(ethSendTransaction({ from: owner, to: this.bounty.address, value: reward }));
+        });
+
+        it('reverts when recanceled', async function () {
+          await assertRevert(this.bounty.cancelBounty({ from: owner }));
+        });
+      });
+    });
   });
   });
 });
 });