diff --git a/contracts/Stoppable.sol b/contracts/Stoppable.sol index d649ce019..99ad5ad3b 100644 --- a/contracts/Stoppable.sol +++ b/contracts/Stoppable.sol @@ -2,7 +2,7 @@ pragma solidity ^0.4.0; /* * Stoppable * Abstract contract that allows children to implement an - * emergency stop mechanism. + * emergency stop mechanism. */ contract Stoppable { address public curator; @@ -21,4 +21,9 @@ contract Stoppable { stopped = true; } + function release() external onlyInEmergency { + if (msg.sender != curator) throw; + stopped = false; + } + } diff --git a/contracts/test-helpers/StandardTokenMock.sol b/contracts/test-helpers/StandardTokenMock.sol new file mode 100644 index 000000000..38be987bd --- /dev/null +++ b/contracts/test-helpers/StandardTokenMock.sol @@ -0,0 +1,11 @@ +pragma solidity ^0.4.0; +import '../StandardToken.sol'; + +// mock class using StandardToken +contract StandardTokenMock is StandardToken { + + function StandardTokenMock(address initialAccount, uint initialBalance) { + balances[initialAccount] = initialBalance; + } + +} diff --git a/contracts/test-helpers/StoppableMock.sol b/contracts/test-helpers/StoppableMock.sol new file mode 100644 index 000000000..dcb9834f5 --- /dev/null +++ b/contracts/test-helpers/StoppableMock.sol @@ -0,0 +1,22 @@ +pragma solidity ^0.4.0; +import '../Stoppable.sol'; + +// mock class using Stoppable +contract StoppableMock is Stoppable(msg.sender) { + bool public drasticMeasureTaken; + uint public count; + + function StoppableMock() Stoppable(msg.sender){ + drasticMeasureTaken = false; + count = 0; + } + + function normalProcess() external stopInEmergency { + count++; + } + + function drasticMeasure() external onlyInEmergency { + drasticMeasureTaken = true; + } + +} diff --git a/test/StandardToken.js b/test/StandardToken.js new file mode 100644 index 000000000..40382c175 --- /dev/null +++ b/test/StandardToken.js @@ -0,0 +1,81 @@ +contract('StandardToken', function(accounts) { + + it("should return the correct allowance amount after approval", function(done) { + var token; + return StandardTokenMock.new() + .then(function(_token) { + token = _token; + return token.approve(accounts[1], 100); + }) + .then(function() { + return token.allowance(accounts[0], accounts[1]); + }) + .then(function(allowance) { + assert.equal(allowance, 100); + }) + .then(done); + }); + + it("should return correct balances after transfer", function(done) { + var token; + return StandardTokenMock.new(accounts[0], 100) + .then(function(_token) { + token = _token; + return token.transfer(accounts[1], 100); + }) + .then(function() { + return token.balanceOf(accounts[0]); + }) + .then(function(balance) { + assert.equal(balance, 0); + }) + .then(function() { + return token.balanceOf(accounts[1]); + }) + .then(function(balance) { + assert.equal(balance, 100); + }) + .then(done); + }); + + it("should throw an error when trying to transfer more than balance", function(done) { + var token; + return StandardTokenMock.new(accounts[0], 100) + .then(function(_token) { + token = _token; + return token.transfer(accounts[1], 101); + }) + .catch(function(error) { + if (error.message.search('invalid JUMP') == -1) throw error + }) + .then(done); + }); + + it("should return correct balances after transfering from another account", function(done) { + var token; + return StandardTokenMock.new(accounts[0], 100) + .then(function(_token) { + token = _token; + return token.approve(accounts[1], 100); + }) + .then(function() { + return token.transferFrom(accounts[0], accounts[2], 100, {from: accounts[1]}); + }) + .then(function() { + return token.balanceOf(accounts[0]); + }) + .then(function(balance) { + assert.equal(balance, 0); + return token.balanceOf(accounts[2]); + }) + .then(function(balance) { + assert.equal(balance, 100) + return token.balanceOf(accounts[1]); + }) + .then(function(balance) { + assert.equal(balance, 0); + }) + .then(done); + }); + +}); diff --git a/test/Stoppable.js b/test/Stoppable.js new file mode 100644 index 000000000..f4ecc0e34 --- /dev/null +++ b/test/Stoppable.js @@ -0,0 +1,108 @@ +contract('Stoppable', function(accounts) { + + it("can perform normal process in non-emergency", function(done) { + var stoppable; + return StoppableMock.new(accounts[0]) + .then(function(_stoppable) { + stoppable = _stoppable; + return stoppable.count(); + }) + .then(function(count) { + assert.equal(count, 0); + }) + .then(function () { + return stoppable.normalProcess(); + }) + .then(function() { + return stoppable.count(); + }) + .then(function(count) { + assert.equal(count, 1); + }) + .then(done); + }); + + it("can not perform normal process in emergency", function(done) { + var stoppable; + return StoppableMock.new(accounts[0]) + .then(function(_stoppable) { + stoppable = _stoppable; + return stoppable.emergencyStop(); + }) + .then(function () { + return stoppable.count(); + }) + .then(function(count) { + assert.equal(count, 0); + }) + .then(function () { + return stoppable.normalProcess(); + }) + .then(function() { + return stoppable.count(); + }) + .then(function(count) { + assert.equal(count, 0); + }) + .then(done); + }); + + + it("can not take drastic measure in non-emergency", function(done) { + var stoppable; + return StoppableMock.new(accounts[0]) + .then(function(_stoppable) { + stoppable = _stoppable; + return stoppable.drasticMeasure(); + }) + .then(function() { + return stoppable.drasticMeasureTaken(); + }) + .then(function(taken) { + assert.isFalse(taken); + }) + .then(done); + }); + + it("can take a drastic measure in an emergency", function(done) { + var stoppable; + return StoppableMock.new(accounts[0]) + .then(function(_stoppable) { + stoppable = _stoppable; + return stoppable.emergencyStop(); + }) + .then(function() { + return stoppable.drasticMeasure(); + }) + .then(function() { + return stoppable.drasticMeasureTaken(); + }) + .then(function(taken) { + assert.isTrue(taken); + }) + .then(done); + }); + + it("should resume allowing normal process after emergency is over", function(done) { + var stoppable; + return StoppableMock.new(accounts[0]) + .then(function(_stoppable) { + stoppable = _stoppable; + return stoppable.emergencyStop(); + }) + .then(function () { + return stoppable.release(); + }) + .then(function() { + return stoppable.normalProcess(); + }) + .then(function() { + return stoppable.count(); + }) + .then(function(count) { + assert.equal(count, 1); + }) + .then(done); + }); + +});