Skip to content

Commit

Permalink
Merge pull request #99 from PolymathNetwork/burnable-token
Browse files Browse the repository at this point in the history
burn securities
  • Loading branch information
pabloruiz55 authored May 10, 2018
2 parents 9e11eeb + e4011d0 commit e9efd58
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 5 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ All notable changes to this project will be documented in this file.
* `takeFee()` new function introduced to extract the POLY token from the factory. It only be called by the owner of the factory.
* Added ability for issuer to provide a signed piece of data to allow investors to whitelist themselves.
* `_securityTokenAddress` get indexed in the `LogNewSecurityToken` event.
* Now each investor have its `expiryTime` for the KYC. After the expiryTime limit reached, investor will not abe to use transfer related functions.
* Now each investor have its `expiryTime` for the KYC. After the expiryTime limit reached, investor will not abe to use transfer related functions.
* Transfers of tokens gets paused at the level of all TM as well as on the ST level. To facilitate this 3 functions get added namely
`pause()`, `unpause()`,`freezeTransfers()`. All 3 functions are called by the issuer of the securityToken only.
* Security token has got a new feature of burning the tokens, To use this feature user need to call the `burn()` function but before that issuer need to deploy the `TokenBurner` contract and set its address into the SecurityToken contract using the function `setTokenBurner()`.

## Remove

Expand Down
21 changes: 21 additions & 0 deletions contracts/helpers/TokenBurner.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
pragma solidity ^0.4.23;

import "../interfaces/ISecurityToken.sol";
import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";

contract TokenBurner {

address public securityToken;

constructor (address _securityToken) {
securityToken = _securityToken;
}

function burn(address _burner, uint256 _value) public returns(bool) {
require(msg.sender == securityToken);
// Add the schematics for the burner( token holder) that backing the burning of the securities
return true;
}


}
5 changes: 4 additions & 1 deletion contracts/interfaces/IST20.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ contract IST20 is StandardToken, DetailedERC20 {
//transfer, transferFrom must respect use respect the result of verifyTransfer
function verifyTransfer(address _from, address _to, uint256 _amount) public view returns (bool success);

//used to create tokens
// used to create tokens
function mint(address _investor, uint256 _amount) public returns (bool success);

// used to burn the tokens
function burn(uint256 _value) public;
}
38 changes: 35 additions & 3 deletions contracts/tokens/SecurityToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import "../interfaces/IST20.sol";
import "../modules/TransferManager/ITransferManager.sol";
import "../modules/PermissionManager/IPermissionManager.sol";
import "../interfaces/ISecurityTokenRegistry.sol";

import "../helpers/TokenBurner.sol";

/**
* @title SecurityToken
Expand All @@ -23,6 +23,10 @@ contract SecurityToken is ISecurityToken {
using SafeMath for uint256;

bytes32 public securityTokenVersion = "0.0.1";

// Reference to token burner contract
TokenBurner public tokenBurner;

// Use to halt all the transactions
bool public freeze = false;
// Reference to the POLY token.
Expand Down Expand Up @@ -51,10 +55,12 @@ contract SecurityToken is ISecurityToken {
uint256 _timestamp
);

event LogUpdateTokenDetails(bytes32 _oldDetails, bytes32 _newDetails);
event LogGranularityChanged(uint256 _oldGranularity, uint256 _newGranularity);
event LogModuleRemoved(uint8 indexed _type, address _module, uint256 _timestamp);
event LogModuleBudgetChanged(uint8 indexed _moduleType, address _module, uint256 _budget);
event Mint(address indexed to, uint256 amount);
event Minted(address indexed to, uint256 amount);
event Burnt(address indexed _burner, uint256 _value);
event LogFreezeTransfers(bool _freeze, uint256 _timestamp);

//if _fallback is true, then we only allow the module if it is set, if it is not set we only allow the owner
Expand Down Expand Up @@ -214,6 +220,15 @@ contract SecurityToken is ISecurityToken {
emit LogModuleBudgetChanged(_moduleType, modules[_moduleType][_moduleIndex].moduleAddress, _budget);
}

/**
* @dev change the tokenDetails
*/
function updateTokenDetails(bytes32 _newTokenDetails) public onlyOwner {
bytes32 _oldTokenDetails = tokenDetails;
tokenDetails = _newTokenDetails;
emit LogUpdateTokenDetails(_oldTokenDetails, tokenDetails);
}

/**
* @dev allows owner to change token granularity
*/
Expand Down Expand Up @@ -310,7 +325,7 @@ contract SecurityToken is ISecurityToken {
require(verifyTransfer(address(0), _investor, _amount), "Transfer is not valid");
totalSupply_ = totalSupply_.add(_amount);
balances[_investor] = balances[_investor].add(_amount);
emit Mint(_investor, _amount);
emit Minted(_investor, _amount);
emit Transfer(address(0), _investor, _amount);
return true;
}
Expand All @@ -329,4 +344,21 @@ contract SecurityToken is ISecurityToken {
}
}
}

function setTokenBurner(address _tokenBurner) public onlyOwner {
tokenBurner = TokenBurner(_tokenBurner);
}

function burn(uint256 _value) checkGranularity(_value) public {
require(tokenBurner != address(0), "Token Burner contract address is not set yet");
require(_value <= balances[msg.sender], "Value should no be greater than the balance of msg.sender");
// no need to require value <= totalSupply, since that would imply the
// sender's balance is greater than the totalSupply, which *should* be an assertion failure

balances[msg.sender] = balances[msg.sender].sub(_value);
require(tokenBurner.burn(msg.sender, _value), "Token burner process is not validated");
totalSupply_ = totalSupply_.sub(_value);
emit Burnt(msg.sender, _value);
emit Transfer(msg.sender, address(0), _value);
}
}
28 changes: 28 additions & 0 deletions test/security_token.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const GeneralTransferManager = artifacts.require('./GeneralTransferManager');
const GeneralPermissionManager = artifacts.require('./GeneralPermissionManager');
const PolyToken = artifacts.require('./PolyToken.sol');
const PolyTokenFaucet = artifacts.require('./helpers/contracts/PolyTokenFaucet.sol');
const TokenBurner = artifacts.require('./TokenBurner.sol');

const Web3 = require('web3');
const BigNumber = require('bignumber.js');
Expand Down Expand Up @@ -56,6 +57,7 @@ contract('SecurityToken', accounts => {
let I_SecurityToken;
let I_CappedSTO;
let I_PolyToken;
let I_TokenBurner;

// SecurityToken Details (Launched ST on the behalf of the issuer)
const swarmHash = "dagwrgwgvwergwrvwrg";
Expand Down Expand Up @@ -684,6 +686,32 @@ contract('SecurityToken', accounts => {
console.log(await I_SecurityToken.balanceOf(account_investor1));
await I_SecurityToken.transfer(account_investor1, web3.utils.toWei('1', 'ether'), {from: account_temp});
});

it("Should fail to call the burn the tokens because token burner contract is not set", async() => {
// Deploy the token burner contract
I_TokenBurner = await TokenBurner.new(I_SecurityToken.address, { from: token_owner });

let errorThrown = false;
try {
await I_SecurityToken.burn(web3.utils.toWei('1', 'ether'),{ from: account_temp });
} catch(error) {
console.log('failed in calling burn function because token burner contract is not set');
errorThrown = true;
ensureException(error);
}
assert.ok(errorThrown, message);
});

it("Should burn the tokens", async ()=> {
// Deploy the token burner contract
I_TokenBurner = await TokenBurner.new(I_SecurityToken.address, { from: token_owner });

await I_SecurityToken.setTokenBurner(I_TokenBurner.address, { from: token_owner });
assert.equal(await I_SecurityToken.tokenBurner.call(), I_TokenBurner.address);

let tx = await I_SecurityToken.burn(web3.utils.toWei('1', 'ether'),{ from: account_temp });
assert.equal(tx.logs[0].args._value, web3.utils.toWei('1', 'ether'));
});
});

});

0 comments on commit e9efd58

Please sign in to comment.