Merge pull request #170 from Recmo/feature/no-owner
Prevent contracts from owning Ether, Tokens and other contracts.
This commit is contained in:
35
test/HasNoContracts.js
Normal file
35
test/HasNoContracts.js
Normal file
@ -0,0 +1,35 @@
|
||||
'use strict';
|
||||
import expectThrow from './helpers/expectThrow';
|
||||
import toPromise from './helpers/toPromise';
|
||||
const Ownable = artifacts.require('../contracts/ownership/Ownable.sol');
|
||||
const HasNoContracts = artifacts.require(
|
||||
'../contracts/ownership/HasNoContracts.sol',
|
||||
);
|
||||
|
||||
contract('HasNoContracts', function(accounts) {
|
||||
let hasNoContracts = null;
|
||||
let ownable = null;
|
||||
|
||||
beforeEach(async () => {
|
||||
// Create contract and token
|
||||
hasNoContracts = await HasNoContracts.new();
|
||||
ownable = await Ownable.new();
|
||||
|
||||
// Force ownership into contract
|
||||
await ownable.transferOwnership(hasNoContracts.address);
|
||||
const owner = await ownable.owner();
|
||||
assert.equal(owner, hasNoContracts.address);
|
||||
});
|
||||
|
||||
it('should allow owner to reclaim contracts', async function() {
|
||||
await hasNoContracts.reclaimContract(ownable.address);
|
||||
const owner = await ownable.owner();
|
||||
assert.equal(owner, accounts[0]);
|
||||
});
|
||||
|
||||
it('should allow only owner to reclaim contracts', async function() {
|
||||
await expectThrow(
|
||||
hasNoContracts.reclaimContract(ownable.address, {from: accounts[1]}),
|
||||
);
|
||||
});
|
||||
});
|
||||
63
test/HasNoEther.js
Normal file
63
test/HasNoEther.js
Normal file
@ -0,0 +1,63 @@
|
||||
'use strict';
|
||||
import expectThrow from './helpers/expectThrow';
|
||||
import toPromise from './helpers/toPromise';
|
||||
const HasNoEther = artifacts.require('../contracts/lifecycle/HasNoEther.sol');
|
||||
const HasNoEtherTest = artifacts.require('../helpers/HasNoEtherTest.sol');
|
||||
const ForceEther = artifacts.require('../helpers/ForceEther.sol');
|
||||
|
||||
contract('HasNoEther', function(accounts) {
|
||||
const amount = web3.toWei('1', 'ether');
|
||||
|
||||
it('should be constructorable', async function() {
|
||||
let hasNoEther = await HasNoEtherTest.new();
|
||||
});
|
||||
|
||||
it('should not accept ether in constructor', async function() {
|
||||
await expectThrow(HasNoEtherTest.new({value: amount}));
|
||||
});
|
||||
|
||||
it('should not accept ether', async function() {
|
||||
let hasNoEther = await HasNoEtherTest.new();
|
||||
|
||||
await expectThrow(
|
||||
toPromise(web3.eth.sendTransaction)({
|
||||
from: accounts[1],
|
||||
to: hasNoEther.address,
|
||||
value: amount,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should allow owner to reclaim ether', async function() {
|
||||
// Create contract
|
||||
let hasNoEther = await HasNoEtherTest.new();
|
||||
const startBalance = await web3.eth.getBalance(hasNoEther.address);
|
||||
assert.equal(startBalance, 0);
|
||||
|
||||
// Force ether into it
|
||||
await ForceEther.new(hasNoEther.address, {value: amount});
|
||||
const forcedBalance = await web3.eth.getBalance(hasNoEther.address);
|
||||
assert.equal(forcedBalance, amount);
|
||||
|
||||
// Reclaim
|
||||
const ownerStartBalance = await web3.eth.getBalance(accounts[0]);
|
||||
await hasNoEther.reclaimEther();
|
||||
const ownerFinalBalance = await web3.eth.getBalance(accounts[0]);
|
||||
const finalBalance = await web3.eth.getBalance(hasNoEther.address);
|
||||
assert.equal(finalBalance, 0);
|
||||
assert.isAbove(ownerFinalBalance, ownerStartBalance);
|
||||
});
|
||||
|
||||
it('should allow only owner to reclaim ether', async function() {
|
||||
// Create contract
|
||||
let hasNoEther = await HasNoEtherTest.new({from: accounts[0]});
|
||||
|
||||
// Force ether into it
|
||||
await ForceEther.new(hasNoEther.address, {value: amount});
|
||||
const forcedBalance = await web3.eth.getBalance(hasNoEther.address);
|
||||
assert.equal(forcedBalance, amount);
|
||||
|
||||
// Reclaim
|
||||
await expectThrow(hasNoEther.reclaimEther({from: accounts[1]}));
|
||||
});
|
||||
});
|
||||
40
test/HasNoTokens.js
Normal file
40
test/HasNoTokens.js
Normal file
@ -0,0 +1,40 @@
|
||||
'use strict';
|
||||
import expectThrow from './helpers/expectThrow';
|
||||
import toPromise from './helpers/toPromise';
|
||||
const HasNoTokens = artifacts.require('../contracts/lifecycle/HasNoTokens.sol');
|
||||
const ERC23TokenMock = artifacts.require('./helpers/ERC23TokenMock.sol');
|
||||
|
||||
contract('HasNoTokens', function(accounts) {
|
||||
let hasNoTokens = null;
|
||||
let token = null;
|
||||
|
||||
beforeEach(async () => {
|
||||
// Create contract and token
|
||||
hasNoTokens = await HasNoTokens.new();
|
||||
token = await ERC23TokenMock.new(accounts[0], 100);
|
||||
|
||||
// Force token into contract
|
||||
await token.transfer(hasNoTokens.address, 10);
|
||||
const startBalance = await token.balanceOf(hasNoTokens.address);
|
||||
assert.equal(startBalance, 10);
|
||||
});
|
||||
|
||||
it('should not accept ERC23 tokens', async function() {
|
||||
await expectThrow(token.transferERC23(hasNoTokens.address, 10, ''));
|
||||
});
|
||||
|
||||
it('should allow owner to reclaim tokens', async function() {
|
||||
const ownerStartBalance = await token.balanceOf(accounts[0]);
|
||||
await hasNoTokens.reclaimToken(token.address);
|
||||
const ownerFinalBalance = await token.balanceOf(accounts[0]);
|
||||
const finalBalance = await token.balanceOf(hasNoTokens.address);
|
||||
assert.equal(finalBalance, 0);
|
||||
assert.equal(ownerFinalBalance - ownerStartBalance, 10);
|
||||
});
|
||||
|
||||
it('should allow only owner to reclaim tokens', async function() {
|
||||
await expectThrow(
|
||||
hasNoTokens.reclaimToken(token.address, {from: accounts[1]}),
|
||||
);
|
||||
});
|
||||
});
|
||||
33
test/helpers/ERC23TokenMock.sol
Normal file
33
test/helpers/ERC23TokenMock.sol
Normal file
@ -0,0 +1,33 @@
|
||||
pragma solidity ^0.4.8;
|
||||
|
||||
|
||||
import '../../contracts/token/BasicToken.sol';
|
||||
|
||||
|
||||
contract ERC23ContractInterface {
|
||||
function tokenFallback(address _from, uint _value, bytes _data) external;
|
||||
}
|
||||
|
||||
contract ERC23TokenMock is BasicToken {
|
||||
|
||||
function ERC23TokenMock(address initialAccount, uint initialBalance) {
|
||||
balances[initialAccount] = initialBalance;
|
||||
totalSupply = initialBalance;
|
||||
}
|
||||
|
||||
// ERC23 compatible transfer function (except the name)
|
||||
function transferERC23(address _to, uint _value, bytes _data)
|
||||
returns (bool success)
|
||||
{
|
||||
transfer(_to, _value);
|
||||
bool is_contract = false;
|
||||
assembly {
|
||||
is_contract := not(iszero(extcodesize(_to)))
|
||||
}
|
||||
if(is_contract) {
|
||||
ERC23ContractInterface receiver = ERC23ContractInterface(_to);
|
||||
receiver.tokenFallback(msg.sender, _value, _data);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
13
test/helpers/ForceEther.sol
Normal file
13
test/helpers/ForceEther.sol
Normal file
@ -0,0 +1,13 @@
|
||||
pragma solidity ^0.4.8;
|
||||
|
||||
// @title Force Ether into a contract.
|
||||
// @notice even
|
||||
// if the contract is not payable.
|
||||
// @notice To use, construct the contract with the target as argument.
|
||||
// @author Remco Bloemen <remco@neufund.org>
|
||||
contract ForceEther {
|
||||
function ForceEther(address target) payable {
|
||||
// Selfdestruct transfers all Ether to the arget address
|
||||
selfdestruct(target);
|
||||
}
|
||||
}
|
||||
11
test/helpers/HasNoEtherTest.sol
Normal file
11
test/helpers/HasNoEtherTest.sol
Normal file
@ -0,0 +1,11 @@
|
||||
pragma solidity ^0.4.8;
|
||||
|
||||
import "../../contracts/ownership/HasNoEther.sol";
|
||||
|
||||
contract HasNoEtherTest is HasNoEther {
|
||||
|
||||
// Constructor with explicit payable — should still fail
|
||||
function HasNoEtherTest() payable {
|
||||
}
|
||||
|
||||
}
|
||||
4
test/helpers/toPromise.js
Normal file
4
test/helpers/toPromise.js
Normal file
@ -0,0 +1,4 @@
|
||||
export default func =>
|
||||
(...args) =>
|
||||
new Promise((accept, reject) =>
|
||||
func(...args, (error, data) => error ? reject(error) : accept(data)));
|
||||
Reference in New Issue
Block a user