Remove HasNoEther, HasNoTokens, HasNoContracts, and NoOwner (#1254)
* remove HasNoEther, HasNoTokens, HasNoContracts, and NoOwner * remove unused ERC223TokenMock * remove Contactable * remove TokenDestructible * remove DeprecatedERC721 * inline Destructible#destroy in Bounty * remove Destructible
This commit is contained in:
committed by
GitHub
parent
2441fd7d17
commit
bd994a88de
@ -2,14 +2,13 @@ pragma solidity ^0.4.24;
|
|||||||
|
|
||||||
|
|
||||||
import "../payment/PullPayment.sol";
|
import "../payment/PullPayment.sol";
|
||||||
import "../lifecycle/Destructible.sol";
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @title BreakInvariantBounty
|
* @title BreakInvariantBounty
|
||||||
* @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, Destructible {
|
contract BreakInvariantBounty is PullPayment, Ownable {
|
||||||
bool public claimed;
|
bool public claimed;
|
||||||
mapping(address => address) public researchers;
|
mapping(address => address) public researchers;
|
||||||
|
|
||||||
@ -47,6 +46,13 @@ contract BreakInvariantBounty is PullPayment, Destructible {
|
|||||||
claimed = true;
|
claimed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Transfers the current balance to the owner and terminates the contract.
|
||||||
|
*/
|
||||||
|
function destroy() public onlyOwner {
|
||||||
|
selfdestruct(owner);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Internal function to deploy the target contract.
|
* @dev Internal function to deploy the target contract.
|
||||||
* @return A target contract address
|
* @return A target contract address
|
||||||
|
|||||||
@ -1,22 +0,0 @@
|
|||||||
pragma solidity ^0.4.24;
|
|
||||||
|
|
||||||
|
|
||||||
import "../ownership/Ownable.sol";
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @title Destructible
|
|
||||||
* @dev Base contract that can be destroyed by owner. All funds in contract will be sent to the owner.
|
|
||||||
*/
|
|
||||||
contract Destructible is Ownable {
|
|
||||||
/**
|
|
||||||
* @dev Transfers the current balance to the owner and terminates the contract.
|
|
||||||
*/
|
|
||||||
function destroy() public onlyOwner {
|
|
||||||
selfdestruct(owner);
|
|
||||||
}
|
|
||||||
|
|
||||||
function destroyAndSend(address _recipient) public onlyOwner {
|
|
||||||
selfdestruct(_recipient);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,36 +0,0 @@
|
|||||||
pragma solidity ^0.4.24;
|
|
||||||
|
|
||||||
import "../ownership/Ownable.sol";
|
|
||||||
import "../token/ERC20/IERC20.sol";
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @title TokenDestructible:
|
|
||||||
* @author Remco Bloemen <remco@2π.com>
|
|
||||||
* @dev Base contract that can be destroyed by owner. All funds in contract including
|
|
||||||
* listed tokens will be sent to the owner.
|
|
||||||
*/
|
|
||||||
contract TokenDestructible is Ownable {
|
|
||||||
|
|
||||||
constructor() public payable { }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @notice Terminate contract and refund to owner
|
|
||||||
* @param _tokens List of addresses of ERC20 token contracts to
|
|
||||||
refund.
|
|
||||||
* @notice The called token contracts could try to re-enter this contract. Only
|
|
||||||
supply token contracts you trust.
|
|
||||||
*/
|
|
||||||
function destroy(address[] _tokens) public onlyOwner {
|
|
||||||
|
|
||||||
// Transfer tokens to owner
|
|
||||||
for (uint256 i = 0; i < _tokens.length; i++) {
|
|
||||||
IERC20 token = IERC20(_tokens[i]);
|
|
||||||
uint256 balance = token.balanceOf(this);
|
|
||||||
token.transfer(owner, balance);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transfer Eth to owner and terminate contract
|
|
||||||
selfdestruct(owner);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
pragma solidity ^0.4.24;
|
|
||||||
|
|
||||||
import "../lifecycle/Destructible.sol";
|
|
||||||
|
|
||||||
|
|
||||||
contract DestructibleMock is Destructible {
|
|
||||||
function() public payable {}
|
|
||||||
}
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
pragma solidity ^0.4.24;
|
|
||||||
|
|
||||||
import "../token/ERC20/ERC20.sol";
|
|
||||||
|
|
||||||
|
|
||||||
contract ERC223ContractInterface {
|
|
||||||
function tokenFallback(address _from, uint256 _value, bytes _data) external;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
contract ERC223TokenMock is ERC20 {
|
|
||||||
|
|
||||||
constructor(address _initialAccount, uint256 _initialBalance) public {
|
|
||||||
_mint(_initialAccount, _initialBalance);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ERC223 compatible transfer function (except the name)
|
|
||||||
function transferERC223(address _to, uint256 _value, bytes _data) public
|
|
||||||
returns (bool success)
|
|
||||||
{
|
|
||||||
transfer(_to, _value);
|
|
||||||
bool isContract = false;
|
|
||||||
// solium-disable-next-line security/no-inline-assembly
|
|
||||||
assembly {
|
|
||||||
isContract := not(iszero(extcodesize(_to)))
|
|
||||||
}
|
|
||||||
if (isContract) {
|
|
||||||
ERC223ContractInterface receiver = ERC223ContractInterface(_to);
|
|
||||||
receiver.tokenFallback(msg.sender, _value, _data);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
pragma solidity ^0.4.24;
|
|
||||||
|
|
||||||
import "../../contracts/ownership/HasNoEther.sol";
|
|
||||||
|
|
||||||
|
|
||||||
contract HasNoEtherTest is HasNoEther {
|
|
||||||
|
|
||||||
// Constructor with explicit payable — should still fail
|
|
||||||
constructor() public payable {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
pragma solidity ^0.4.24;
|
|
||||||
|
|
||||||
import "./Ownable.sol";
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @title Contactable token
|
|
||||||
* @dev Basic version of a contactable contract, allowing the owner to provide a string with their
|
|
||||||
* contact information.
|
|
||||||
*/
|
|
||||||
contract Contactable is Ownable {
|
|
||||||
|
|
||||||
string public contactInformation;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @dev Allows the owner to set a string with their contact information.
|
|
||||||
* @param _info The contact information to attach to the contract.
|
|
||||||
*/
|
|
||||||
function setContactInformation(string _info) public onlyOwner {
|
|
||||||
contactInformation = _info;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
pragma solidity ^0.4.24;
|
|
||||||
|
|
||||||
import "./Ownable.sol";
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @title Contracts that should not own Contracts
|
|
||||||
* @author Remco Bloemen <remco@2π.com>
|
|
||||||
* @dev Should contracts (anything Ownable) end up being owned by this contract, it allows the owner
|
|
||||||
* of this contract to reclaim ownership of the contracts.
|
|
||||||
*/
|
|
||||||
contract HasNoContracts is Ownable {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @dev Reclaim ownership of Ownable contracts
|
|
||||||
* @param _contractAddr The address of the Ownable to be reclaimed.
|
|
||||||
*/
|
|
||||||
function reclaimContract(address _contractAddr) external onlyOwner {
|
|
||||||
Ownable contractInst = Ownable(_contractAddr);
|
|
||||||
contractInst.transferOwnership(owner);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,41 +0,0 @@
|
|||||||
pragma solidity ^0.4.24;
|
|
||||||
|
|
||||||
import "./Ownable.sol";
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @title Contracts that should not own Ether
|
|
||||||
* @author Remco Bloemen <remco@2π.com>
|
|
||||||
* @dev This tries to block incoming ether to prevent accidental loss of Ether. Should Ether end up
|
|
||||||
* in the contract, it will allow the owner to reclaim this Ether.
|
|
||||||
* @notice Ether can still be sent to this contract by:
|
|
||||||
* calling functions labeled `payable`
|
|
||||||
* `selfdestruct(contract_address)`
|
|
||||||
* mining directly to the contract address
|
|
||||||
*/
|
|
||||||
contract HasNoEther is Ownable {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @dev Constructor that rejects incoming Ether
|
|
||||||
* The `payable` flag is added so we can access `msg.value` without compiler warning. If we
|
|
||||||
* leave out payable, then Solidity will allow inheriting contracts to implement a payable
|
|
||||||
* constructor. By doing it this way we prevent a payable constructor from working. Alternatively
|
|
||||||
* we could use assembly to access msg.value.
|
|
||||||
*/
|
|
||||||
constructor() public payable {
|
|
||||||
require(msg.value == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @dev Disallows direct send by setting a default function without the `payable` flag.
|
|
||||||
*/
|
|
||||||
function() external {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @dev Transfer all Ether held by the contract to the owner.
|
|
||||||
*/
|
|
||||||
function reclaimEther() external onlyOwner {
|
|
||||||
owner.transfer(address(this).balance);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
pragma solidity ^0.4.24;
|
|
||||||
|
|
||||||
import "./CanReclaimToken.sol";
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @title Contracts that should not own Tokens
|
|
||||||
* @author Remco Bloemen <remco@2π.com>
|
|
||||||
* @dev This blocks incoming ERC223 tokens to prevent accidental loss of tokens.
|
|
||||||
* Should tokens (any ERC20 compatible) end up in the contract, it allows the
|
|
||||||
* owner to reclaim the tokens.
|
|
||||||
*/
|
|
||||||
contract HasNoTokens is CanReclaimToken {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @dev Reject all ERC223 compatible tokens
|
|
||||||
* @param _from address The address that is transferring the tokens
|
|
||||||
* @param _value uint256 the amount of the specified token
|
|
||||||
* @param _data Bytes The data passed from the caller.
|
|
||||||
*/
|
|
||||||
function tokenFallback(
|
|
||||||
address _from,
|
|
||||||
uint256 _value,
|
|
||||||
bytes _data
|
|
||||||
)
|
|
||||||
external
|
|
||||||
pure
|
|
||||||
{
|
|
||||||
_from;
|
|
||||||
_value;
|
|
||||||
_data;
|
|
||||||
revert();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
pragma solidity ^0.4.24;
|
|
||||||
|
|
||||||
import "./HasNoEther.sol";
|
|
||||||
import "./HasNoTokens.sol";
|
|
||||||
import "./HasNoContracts.sol";
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @title Base contract for contracts that should not own things.
|
|
||||||
* @author Remco Bloemen <remco@2π.com>
|
|
||||||
* @dev Solves a class of errors where a contract accidentally becomes owner of Ether, Tokens or
|
|
||||||
* Owned contracts. See respective base contracts for details.
|
|
||||||
*/
|
|
||||||
contract NoOwner is HasNoEther, HasNoTokens, HasNoContracts {
|
|
||||||
}
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
pragma solidity ^0.4.24;
|
|
||||||
|
|
||||||
import "./IERC721.sol";
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @title ERC-721 methods shipped in OpenZeppelin v1.7.0, removed in the latest version of the standard
|
|
||||||
* @dev Only use this interface for compatibility with previously deployed contracts
|
|
||||||
* Use ERC721 for interacting with new contracts which are standard-compliant
|
|
||||||
*/
|
|
||||||
contract IDeprecatedERC721 is IERC721 {
|
|
||||||
function takeOwnership(uint256 _tokenId) public;
|
|
||||||
function transfer(address _to, uint256 _tokenId) public;
|
|
||||||
function tokensOf(address _owner) public view returns (uint256[]);
|
|
||||||
}
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
const DestructibleMock = artifacts.require('DestructibleMock');
|
|
||||||
const { ethGetBalance } = require('../helpers/web3');
|
|
||||||
|
|
||||||
const BigNumber = web3.BigNumber;
|
|
||||||
|
|
||||||
require('chai')
|
|
||||||
.use(require('chai-bignumber')(BigNumber))
|
|
||||||
.should();
|
|
||||||
|
|
||||||
contract('Destructible', function ([_, owner, recipient]) {
|
|
||||||
beforeEach(async function () {
|
|
||||||
this.destructible = await DestructibleMock.new({ from: owner });
|
|
||||||
await web3.eth.sendTransaction({
|
|
||||||
from: owner,
|
|
||||||
to: this.destructible.address,
|
|
||||||
value: web3.toWei('10', 'ether'),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should send balance to owner after destruction', async function () {
|
|
||||||
const initBalance = await ethGetBalance(owner);
|
|
||||||
await this.destructible.destroy({ from: owner });
|
|
||||||
const newBalance = await ethGetBalance(owner);
|
|
||||||
newBalance.should.be.bignumber.gt(initBalance);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should send balance to recepient after destruction', async function () {
|
|
||||||
const initBalance = await ethGetBalance(recipient);
|
|
||||||
await this.destructible.destroyAndSend(recipient, { from: owner });
|
|
||||||
const newBalance = await ethGetBalance(recipient);
|
|
||||||
newBalance.should.be.bignumber.gt(initBalance);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,39 +0,0 @@
|
|||||||
const { ethGetBalance } = require('../helpers/web3');
|
|
||||||
|
|
||||||
const TokenDestructible = artifacts.require('TokenDestructible');
|
|
||||||
const ERC20Mock = artifacts.require('ERC20Mock');
|
|
||||||
|
|
||||||
const BigNumber = web3.BigNumber;
|
|
||||||
|
|
||||||
require('chai')
|
|
||||||
.use(require('chai-bignumber')(BigNumber))
|
|
||||||
.should();
|
|
||||||
|
|
||||||
contract('TokenDestructible', function ([_, owner]) {
|
|
||||||
let tokenDestructible;
|
|
||||||
|
|
||||||
beforeEach(async function () {
|
|
||||||
tokenDestructible = await TokenDestructible.new({
|
|
||||||
from: owner,
|
|
||||||
value: web3.toWei('10', 'ether'),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should send balance to owner after destruction', async function () {
|
|
||||||
const initBalance = await ethGetBalance(owner);
|
|
||||||
await tokenDestructible.destroy([], { from: owner });
|
|
||||||
|
|
||||||
const newBalance = await ethGetBalance(owner);
|
|
||||||
newBalance.should.be.bignumber.gt(initBalance);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should send tokens to owner after destruction', async function () {
|
|
||||||
const token = await ERC20Mock.new(tokenDestructible.address, 100);
|
|
||||||
(await token.balanceOf(tokenDestructible.address)).should.be.bignumber.equal(100);
|
|
||||||
(await token.balanceOf(owner)).should.be.bignumber.equal(0);
|
|
||||||
|
|
||||||
await tokenDestructible.destroy([token.address], { from: owner });
|
|
||||||
(await token.balanceOf(tokenDestructible.address)).should.be.bignumber.equal(0);
|
|
||||||
(await token.balanceOf(owner)).should.be.bignumber.equal(100);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
const Contactable = artifacts.require('Contactable');
|
|
||||||
|
|
||||||
contract('Contactable', function () {
|
|
||||||
let contactable;
|
|
||||||
|
|
||||||
beforeEach(async function () {
|
|
||||||
contactable = await Contactable.new();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should have an empty contact info', async function () {
|
|
||||||
(await contactable.contactInformation()).should.equal('');
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('after setting the contact information', function () {
|
|
||||||
const contactInfo = 'contact information';
|
|
||||||
|
|
||||||
beforeEach(async function () {
|
|
||||||
await contactable.setContactInformation(contactInfo);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return the setted contact information', async function () {
|
|
||||||
(await contactable.contactInformation()).should.equal(contactInfo);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,29 +0,0 @@
|
|||||||
const { expectThrow } = require('../helpers/expectThrow');
|
|
||||||
|
|
||||||
const Ownable = artifacts.require('Ownable');
|
|
||||||
const HasNoContracts = artifacts.require('HasNoContracts');
|
|
||||||
|
|
||||||
contract('HasNoContracts', function ([_, owner, anyone]) {
|
|
||||||
let hasNoContracts = null;
|
|
||||||
let ownable = null;
|
|
||||||
|
|
||||||
beforeEach(async function () {
|
|
||||||
// Create contract and token
|
|
||||||
hasNoContracts = await HasNoContracts.new({ from: owner });
|
|
||||||
ownable = await Ownable.new({ from: owner });
|
|
||||||
|
|
||||||
// Force ownership into contract
|
|
||||||
await ownable.transferOwnership(hasNoContracts.address, { from: owner });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow owner to reclaim contracts', async function () {
|
|
||||||
await hasNoContracts.reclaimContract(ownable.address, { from: owner });
|
|
||||||
(await ownable.owner()).should.equal(owner);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow only owner to reclaim contracts', async function () {
|
|
||||||
await expectThrow(
|
|
||||||
hasNoContracts.reclaimContract(ownable.address, { from: anyone })
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,61 +0,0 @@
|
|||||||
const { expectThrow } = require('../helpers/expectThrow');
|
|
||||||
const { ethSendTransaction, ethGetBalance } = require('../helpers/web3');
|
|
||||||
|
|
||||||
const HasNoEtherTest = artifacts.require('HasNoEtherTest');
|
|
||||||
const ForceEther = artifacts.require('ForceEther');
|
|
||||||
|
|
||||||
const BigNumber = web3.BigNumber;
|
|
||||||
|
|
||||||
require('chai')
|
|
||||||
.use(require('chai-bignumber')(BigNumber))
|
|
||||||
.should();
|
|
||||||
|
|
||||||
contract('HasNoEther', function ([_, owner, anyone]) {
|
|
||||||
const amount = web3.toWei('1', 'ether');
|
|
||||||
|
|
||||||
beforeEach(async function () {
|
|
||||||
this.hasNoEther = await HasNoEtherTest.new({ from: owner });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not accept ether in constructor', async function () {
|
|
||||||
await expectThrow(HasNoEtherTest.new({ value: amount }));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not accept ether', async function () {
|
|
||||||
await expectThrow(
|
|
||||||
ethSendTransaction({
|
|
||||||
from: owner,
|
|
||||||
to: this.hasNoEther.address,
|
|
||||||
value: amount,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow owner to reclaim ether', async function () {
|
|
||||||
const startBalance = await ethGetBalance(this.hasNoEther.address);
|
|
||||||
startBalance.should.be.bignumber.equal(0);
|
|
||||||
|
|
||||||
// Force ether into it
|
|
||||||
const forceEther = await ForceEther.new({ value: amount });
|
|
||||||
await forceEther.destroyAndSend(this.hasNoEther.address);
|
|
||||||
(await ethGetBalance(this.hasNoEther.address)).should.be.bignumber.equal(amount);
|
|
||||||
|
|
||||||
// Reclaim
|
|
||||||
const ownerStartBalance = await ethGetBalance(owner);
|
|
||||||
await this.hasNoEther.reclaimEther({ from: owner });
|
|
||||||
const ownerFinalBalance = await ethGetBalance(owner);
|
|
||||||
ownerFinalBalance.should.be.bignumber.gt(ownerStartBalance);
|
|
||||||
|
|
||||||
(await ethGetBalance(this.hasNoEther.address)).should.be.bignumber.equal(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow only owner to reclaim ether', async function () {
|
|
||||||
// Force ether into it
|
|
||||||
const forceEther = await ForceEther.new({ value: amount });
|
|
||||||
await forceEther.destroyAndSend(this.hasNoEther.address);
|
|
||||||
(await ethGetBalance(this.hasNoEther.address)).should.be.bignumber.equal(amount);
|
|
||||||
|
|
||||||
// Reclaim
|
|
||||||
await expectThrow(this.hasNoEther.reclaimEther({ from: anyone }));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,46 +0,0 @@
|
|||||||
const { expectThrow } = require('../helpers/expectThrow');
|
|
||||||
|
|
||||||
const HasNoTokens = artifacts.require('HasNoTokens');
|
|
||||||
const ERC223TokenMock = artifacts.require('ERC223TokenMock');
|
|
||||||
|
|
||||||
const BigNumber = web3.BigNumber;
|
|
||||||
|
|
||||||
require('chai')
|
|
||||||
.use(require('chai-bignumber')(BigNumber))
|
|
||||||
.should();
|
|
||||||
|
|
||||||
contract('HasNoTokens', function ([_, owner, initialAccount, anyone]) {
|
|
||||||
let hasNoTokens = null;
|
|
||||||
let token = null;
|
|
||||||
|
|
||||||
beforeEach(async function () {
|
|
||||||
// Create contract and token
|
|
||||||
hasNoTokens = await HasNoTokens.new({ from: owner });
|
|
||||||
token = await ERC223TokenMock.new(initialAccount, 100);
|
|
||||||
|
|
||||||
// Force token into contract
|
|
||||||
await token.transfer(hasNoTokens.address, 10, { from: initialAccount });
|
|
||||||
|
|
||||||
(await token.balanceOf(hasNoTokens.address)).should.be.bignumber.equal(10);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not accept ERC223 tokens', async function () {
|
|
||||||
await expectThrow(token.transferERC223(hasNoTokens.address, 10, '', { from: initialAccount }));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow owner to reclaim tokens', async function () {
|
|
||||||
const ownerStartBalance = await token.balanceOf(owner);
|
|
||||||
await hasNoTokens.reclaimToken(token.address, { from: owner });
|
|
||||||
|
|
||||||
const ownerFinalBalance = await token.balanceOf(owner);
|
|
||||||
ownerFinalBalance.sub(ownerStartBalance).should.be.bignumber.equal(10);
|
|
||||||
|
|
||||||
(await token.balanceOf(hasNoTokens.address)).should.be.bignumber.equal(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow only owner to reclaim tokens', async function () {
|
|
||||||
await expectThrow(
|
|
||||||
hasNoTokens.reclaimToken(token.address, { from: anyone })
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
Reference in New Issue
Block a user