Replace composition for inheritance in Bounty

pull/48/head
Federico Bond 8 years ago
parent 056320ed94
commit 278f060c56
  1. 28
      README.md
  2. 18
      contracts/Bounty.sol
  3. 6
      contracts/test-helpers/InsecureTargetBounty.sol
  4. 6
      contracts/test-helpers/SecureTargetBounty.sol
  5. 6
      migrations/2_deploy_contracts.js
  6. 45
      test/Bounty.js

@ -33,11 +33,18 @@ contract MetaCoin is Rejector {
## Add your own bounty contract ## Add your own bounty contract
So far you inherit Zeppelin contracts into your own contract through inheritance. To create a bounty for your contract, inherit from the base Bounty contract and provide an implementation for `deployContract()` returning the new contract address.
A bounty contract, however, is a special contract that is deployed on its own.
Each researcher creates a separate copy of your contract, and can claims bounty by breaking invariants logic on the copy of your contract without hacking your original contract.
To use the bounty contract, please follow the below instruction. ```
import "./zeppelin/Bounty.sol";
import "./YourContract.sol";
contract YourBounty is Bounty {
function deployContract() internal returns(address) {
return new YourContract()
}
}
```
### Implement invariant logic into your smart contract ### Implement invariant logic into your smart contract
@ -49,25 +56,16 @@ contract YourContract {
// Implement your logic to make sure that none of the state is broken. // Implement your logic to make sure that none of the state is broken.
} }
} }
contract YourContractFactory {
function deployContract() returns (address) {
// This contract allows researchers to create a copy of your contract
return new YourContract();
}
}
``` ```
### Add the bounty contracts as well as your contracts into migrations ### Deploy your bounty contract as usual
At `migrations/2_deploy_contracts.js` At `migrations/2_deploy_contracts.js`
``` ```
module.exports = function(deployer) { module.exports = function(deployer) {
deployer.deploy(YourContract); deployer.deploy(YourContract);
deployer.deploy(YourContractFactory).then(function() { deployer.deploy(YourBounty);
return deployer.deploy(Bounty, YourContractFactory.address);
});
}; };
``` ```

@ -8,10 +8,6 @@ import './Killable.sol';
* the contract you bet reward against. * the contract you bet reward against.
*/ */
contract Factory {
function deployContract() returns (address);
}
contract Target { contract Target {
function checkInvariant() returns(bool); function checkInvariant() returns(bool);
} }
@ -19,7 +15,6 @@ contract Target {
contract Bounty is PullPayment, Killable { contract Bounty is PullPayment, Killable {
Target target; Target target;
bool public claimed; bool public claimed;
address public factoryAddress;
mapping(address => address) public researchers; mapping(address => address) public researchers;
event TargetCreated(address createdAddress); event TargetCreated(address createdAddress);
@ -28,22 +23,15 @@ contract Bounty is PullPayment, Killable {
if (claimed) throw; if (claimed) throw;
} }
modifier withAddress(address _address) {
if(_address == 0) throw;
_;
}
function Bounty(address _factoryAddress) withAddress(_factoryAddress){
factoryAddress = _factoryAddress;
}
function createTarget() returns(Target) { function createTarget() returns(Target) {
target = Target(Factory(factoryAddress).deployContract()); target = Target(deployContract());
researchers[target] = msg.sender; researchers[target] = msg.sender;
TargetCreated(target); TargetCreated(target);
return target; return target;
} }
function deployContract() internal returns(address);
function checkInvariant() returns(bool){ function checkInvariant() returns(bool){
return target.checkInvariant(); return target.checkInvariant();
} }

@ -1,13 +1,15 @@
pragma solidity ^0.4.4; pragma solidity ^0.4.4;
import "../Bounty.sol";
contract InsecureTargetMock { contract InsecureTargetMock {
function checkInvariant() returns(bool){ function checkInvariant() returns(bool){
return false; return false;
} }
} }
contract InsecureTargetFactory { contract InsecureTargetBounty is Bounty {
function deployContract() returns (address) { function deployContract() internal returns (address) {
return new InsecureTargetMock(); return new InsecureTargetMock();
} }
} }

@ -1,13 +1,15 @@
pragma solidity ^0.4.4; pragma solidity ^0.4.4;
import "../Bounty.sol";
contract SecureTargetMock { contract SecureTargetMock {
function checkInvariant() returns(bool){ function checkInvariant() returns(bool){
return true; return true;
} }
} }
contract SecureTargetFactory { contract SecureTargetBounty is Bounty {
function deployContract() returns (address) { function deployContract() internal returns (address) {
return new SecureTargetMock(); return new SecureTargetMock();
} }
} }

@ -5,9 +5,7 @@ module.exports = function(deployer) {
deployer.deploy(Ownable); deployer.deploy(Ownable);
deployer.deploy(LimitFunds); deployer.deploy(LimitFunds);
if(deployer.network == 'test'){ if(deployer.network == 'test'){
deployer.deploy(SecureTargetMock); deployer.deploy(SecureTargetBounty);
deployer.deploy(SecureTargetFactory); deployer.deploy(InsecureTargetBounty);
deployer.deploy(InsecureTargetMock);
deployer.deploy(InsecureTargetFactory);
}; };
}; };

@ -7,25 +7,12 @@ var sendReward = function(sender, receiver, value){
} }
contract('Bounty', function(accounts) { contract('Bounty', function(accounts) {
it("creates bounty contract with factory address", function(done){
var target = SecureTargetMock.deployed();
Bounty.new(target.address).
then(function(bounty){
return bounty.factoryAddress.call()
}).
then(function(address){
assert.equal(address, target.address)
}).
then(done);
})
it("sets reward", function(done){ it("sets reward", function(done){
var target = SecureTargetMock.deployed();
var owner = accounts[0]; var owner = accounts[0];
var reward = web3.toWei(1, "ether"); var reward = web3.toWei(1, "ether");
Bounty.new(target.address). SecureTargetBounty.new().
then(function(bounty){ then(function(bounty){
sendReward(owner, bounty.address, reward); sendReward(owner, bounty.address, reward);
assert.equal(reward, web3.eth.getBalance(bounty.address).toNumber()) assert.equal(reward, web3.eth.getBalance(bounty.address).toNumber())
@ -33,24 +20,12 @@ contract('Bounty', function(accounts) {
then(done); then(done);
}) })
it("cannot create bounty without address", function(done){
var target = SecureTargetMock.deployed();
Bounty.new().
then(function(bounty){
throw {name : "NoThrowError", message : "should not come here"};
}).
catch(function(error){
assert.notEqual(error.name, "NoThrowError");
}).
then(done);
})
it("empties itself when killed", function(done){ it("empties itself when killed", function(done){
var target = SecureTargetMock.deployed();
var owner = accounts[0]; var owner = accounts[0];
var reward = web3.toWei(1, "ether"); var reward = web3.toWei(1, "ether");
var bounty; var bounty;
Bounty.new(target.address).
SecureTargetBounty.new().
then(function(_bounty){ then(function(_bounty){
bounty = _bounty; bounty = _bounty;
sendReward(owner, bounty.address, reward); sendReward(owner, bounty.address, reward);
@ -65,9 +40,9 @@ contract('Bounty', function(accounts) {
describe("Against secure contract", function(){ describe("Against secure contract", function(){
it("checkInvariant returns true", function(done){ it("checkInvariant returns true", function(done){
var targetFactory = SecureTargetFactory.deployed();
var bounty; var bounty;
Bounty.new(targetFactory.address).
SecureTargetBounty.new().
then(function(_bounty) { then(function(_bounty) {
bounty = _bounty; bounty = _bounty;
return bounty.createTarget(); return bounty.createTarget();
@ -82,12 +57,11 @@ contract('Bounty', function(accounts) {
}) })
it("cannot claim reward", function(done){ it("cannot claim reward", function(done){
var targetFactory = SecureTargetFactory.deployed();
var owner = accounts[0]; var owner = accounts[0];
var researcher = accounts[1]; var researcher = accounts[1];
var reward = web3.toWei(1, "ether"); var reward = web3.toWei(1, "ether");
Bounty.new(targetFactory.address). SecureTargetBounty.new().
then(function(bounty) { then(function(bounty) {
var event = bounty.TargetCreated({}); var event = bounty.TargetCreated({});
event.watch(function(err, result) { event.watch(function(err, result) {
@ -118,9 +92,9 @@ contract('Bounty', function(accounts) {
describe("Against broken contract", function(){ describe("Against broken contract", function(){
it("checkInvariant returns false", function(done){ it("checkInvariant returns false", function(done){
var targetFactory = InsecureTargetFactory.deployed();
var bounty; var bounty;
Bounty.new(targetFactory.address).
InsecureTargetBounty.new().
then(function(_bounty) { then(function(_bounty) {
bounty = _bounty; bounty = _bounty;
return bounty.createTarget(); return bounty.createTarget();
@ -135,12 +109,11 @@ contract('Bounty', function(accounts) {
}) })
it("claims reward", function(done){ it("claims reward", function(done){
var targetFactory = InsecureTargetFactory.deployed();
var owner = accounts[0]; var owner = accounts[0];
var researcher = accounts[1]; var researcher = accounts[1];
var reward = web3.toWei(1, "ether"); var reward = web3.toWei(1, "ether");
Bounty.new(targetFactory.address). InsecureTargetBounty.new().
then(function(bounty) { then(function(bounty) {
var event = bounty.TargetCreated({}); var event = bounty.TargetCreated({});
event.watch(function(err, result) { event.watch(function(err, result) {

Loading…
Cancel
Save