Skip to content

Commit

Permalink
Added script for disabling tokens (#101)
Browse files Browse the repository at this point in the history
* Added support for crippling tokens

* Added test for DisableToken's upgrade method
  • Loading branch information
peteremiljensen committed Mar 5, 2019
1 parent e06c05d commit 58a6e00
Show file tree
Hide file tree
Showing 6 changed files with 327 additions and 0 deletions.
196 changes: 196 additions & 0 deletions contracts/token/DisableToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
pragma solidity ^0.4.24;

import "./IETokenProxy.sol";

/**
* @title A token that doesn't work
* @dev Implements a proxy interface which always reverts. Used for
* testing if upgraded tokens actually forwards calls to the proxy.
*/
contract DisableToken is IETokenProxy {

/* solium-disable zeppelin/missing-natspec-comments */

function upgrade(IETokenProxy upgradedToken) public pure {
// Silence warnings
upgradedToken;
revert("Token is disabled");
}

function finalizeUpgrade() public {
}

function nameProxy(address sender)
public
view
returns(string)
{
sender;
return "DO NOT USE - Disabled";
}

function symbolProxy(address sender)
public
view
returns(string)
{
sender;
return "DEAD";
}

function decimalsProxy(address sender)
public
view
returns(uint8)
{
// Silence warnings
sender;
return 0;
}

function totalSupplyProxy(address sender)
public
view
returns(uint256)
{
// Silence warnings
sender;
return 0;
}

function balanceOfProxy(address sender, address who)
public
view
returns(uint256)
{
// Silence warnings
sender;
who;
return 0;
}

function allowanceProxy(address sender, address owner, address spender)
public
view
returns(uint256)
{
// Silence warnings
sender;
owner;
spender;
return 0;
}

function transferProxy(address sender, address to, uint256 value)
public
returns (bool)
{
sender;
to;
value;
revert("Token is disabled");
}

function approveProxy(address sender, address spender, uint256 value)
public
returns (bool)
{
sender;
spender;
value;
revert("Token is disabled");
}

function transferFromProxy(
address sender,
address from,
address to,
uint256 value
)
public
returns (bool)
{
sender;
from;
to;
value;
revert("Token is disabled");
}

function increaseAllowanceProxy(
address sender,
address spender,
uint256 addedValue
)
public
returns (bool)
{
sender;
spender;
addedValue;
revert("Token is disabled");
}

function decreaseAllowanceProxy(address sender,
address spender,
uint256 subtractedValue)
public
returns (bool) {
sender;
spender;
subtractedValue;
revert("Token is disabled");
}

function burnProxy(address sender, uint256 value)
public
{
sender;
value;
revert("Token is disabled");
}

function burnFromProxy(address sender,
address from,
uint256 value)
public
{
sender;
from;
value;
revert("Token is disabled");
}

function mintProxy(address sender, address to, uint256 value)
public
returns (bool)
{
sender;
to;
value;
revert("Token is disabled");
}

function changeMintingRecipientProxy(address sender, address mintingRecip)
public
{
sender;
mintingRecip;
revert("Token is disabled");
}

function pauseProxy(address sender) external {
sender;
revert("Token is disabled");
}

function unpauseProxy(address sender) external {
sender;
revert("Token is disabled");
}

function pausedProxy(address sender) external view returns (bool) {
sender;
revert("Token is disabled");
}
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"eth-ens-namehash": "2.0.8",
"ganache-cli": "6.2.3",
"openzeppelin-solidity": "2.0.0",
"readline-sync": "^1.4.9",
"truffle": "4.1.14",
"truffle-hdwallet-provider": "0.0.6",
"truffle-ledger-provider": "^1.0.0"
Expand Down
13 changes: 13 additions & 0 deletions scripts/disableToken/disableToken.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
'use strict';

const oneAddress = '0x1111111111111111111111111111111111111111';

async function disableToken (DisableTokenArtifact, token, tokenOwner) {
const disableToken = await DisableTokenArtifact.new({ from: tokenOwner });

await token.pause({ from: tokenOwner });
await token.upgrade(disableToken.address, { from: tokenOwner });
await token.transferOwnership(oneAddress, { from: tokenOwner });
}

module.exports = disableToken;
42 changes: 42 additions & 0 deletions scripts/disableToken/disableTokenWrapper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/* global artifacts */

'use strict';

const DisableToken = artifacts.require('DisableToken.sol');
const EToken = artifacts.require('EToken.sol');

const readlineSync = require('readline-sync');

const argv = require('optimist')
.usage('Usage: --network [name] --token [address] --tokenOwner [address]')
.describe('network', 'truffle network configuration name')
.string(['token', 'tokenOwner'])
.demand(['token', 'tokenOwner'])
.argv;

const disableToken = require('./disableToken');

async function disableTokenWrapper () {
const token = EToken.at(argv.token);
const tokenOwner = argv.tokenOwner.toLowerCase();

if ((await token.owner()) !== tokenOwner) {
throw Error('tokenOwner is not correct');
}

const answer = readlineSync.question(
'WARNING: This will permentaly disable your token. Enter \'I understand\' to proceed...\n');

if (answer !== 'I understand') {
throw Error('You do not understand');
}

await disableToken(DisableToken, token, tokenOwner);
}

module.exports = (callback, test) => {
disableTokenWrapper().then(
() => callback(),
(err) => callback(err)
);
};
70 changes: 70 additions & 0 deletions test/DisableToken.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/* global artifacts, web3, contract */
/* eslint-env mocha */

'use strict';

const Accesslist = artifacts.require('Accesslist');
const ETokenMock = artifacts.require('ETokenMock');
const DisableToken = artifacts.require('DisableToken');

const utils = require('./utils.js');
const disableTokenAction = require('../scripts/disableToken/disableToken.js');

const BigNumber = web3.BigNumber;

require('chai')
.use(require('chai-bignumber')(BigNumber))
.should();

contract('Disable Token', async function ([_, owner, otherAccount]) {
it('Should properly disable token',
async function () {
const tokenName = 'test';
const tokenSymbol = 'test';
const tokenDecimals = 4;

const accesslist = await Accesslist.new();

const token = await ETokenMock.new(
tokenName, tokenSymbol, tokenDecimals,
accesslist.address, false, utils.ZERO_ADDRESS, owner, 0, true,
owner, 10000,
{ from: owner }
);

await token.approve(otherAccount, 100, { from: owner });

(await token.name()).should.be.equal(tokenName);
(await token.symbol()).should.be.equal(tokenSymbol);
(await token.decimals()).should.be.bignumber.equal(tokenDecimals);
(await token.totalSupply()).should.be.bignumber.equal(10000);
(await token.balanceOf(owner)).should.be.bignumber.equal(10000);
(await token.allowance(owner, otherAccount)).should.be.bignumber.equal(100);

await disableTokenAction(DisableToken, token, owner);

(await token.name()).should.be.equal('DO NOT USE - Disabled');
(await token.symbol()).should.be.equal('DEAD');
(await token.decimals()).should.be.bignumber.equal(0);
(await token.totalSupply()).should.be.bignumber.equal(0);
(await token.balanceOf(owner)).should.be.bignumber.equal(0);
(await token.allowance(owner, otherAccount)).should.be.bignumber.equal(0);

const crippledText = 'Token is disabled';
await utils.assertRevertsReason(token.transfer(owner, 100), crippledText);
await utils.assertRevertsReason(token.approve(owner, 100), crippledText);
await utils.assertRevertsReason(token.transferFrom(owner, owner, 100), crippledText);
await utils.assertRevertsReason(token.increaseAllowance(owner, 100), crippledText);
await utils.assertRevertsReason(token.decreaseAllowance(owner, 100), crippledText);
await utils.assertRevertsReason(token.burn(100), crippledText);
await utils.assertRevertsReason(token.burnFrom(owner, 100), crippledText);
await utils.assertRevertsReason(token.mint(owner, 100), crippledText);
await utils.assertRevertsReason(token.changeMintingRecipient(owner), crippledText);
await utils.assertRevertsReason(token.pause(), crippledText);
await utils.assertRevertsReason(token.unpause(), crippledText);
await utils.assertRevertsReason(token.paused(), crippledText);

const disabledToken = DisableToken.at(await token.getUpgradedToken());
await utils.assertRevertsReason(disabledToken.upgrade(utils.ZERO_ADDRESS), crippledText);
});
});
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6280,6 +6280,11 @@ readdirp@^2.0.0:
micromatch "^3.1.10"
readable-stream "^2.0.2"

readline-sync@^1.4.9:
version "1.4.9"
resolved "https://registry.yarnpkg.com/readline-sync/-/readline-sync-1.4.9.tgz#3eda8e65f23cd2a17e61301b1f0003396af5ecda"
integrity sha1-PtqOZfI80qF+YTAbHwADOWr17No=

rechoir@^0.6.2:
version "0.6.2"
resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
Expand Down

0 comments on commit 58a6e00

Please sign in to comment.