Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
ERC-1404: Security Tokens and Whitelists -- Example Code

WhitelistToken.sol Explained

The WhitelistToken.sol example contract inherits from SimpleRestrictedToken.sol and Whitelist.sol. SimpleRestrictedToken.sol provides a basic ERC1404 implementation and standard ERC20 functionality. OpenZeppelin's Whitelist.sol provides a simplification of user permissions and the onlyOwner modifier.

For control over counterparty permissions, the issuer is able to update addresses included in the whitelist. This is achieved by overloading SimpleRestrictedToken.sol's detectTransferRestriction and messageForTransferRestriction functions to accomodate the whitelist restriction. In detectTransferRestriction, the whitelisted status of the sender/recipient is checked and a restriction code is returned if either counterparty is not whitelisted. Accordingly, messageForTransferRestriction is modified to return the appropriate error message, given the aforementioned code.

Commented at the bottom of the contract are some relevant inherited functions. Of particular interest to issuers are addAddressToWhitelist, removeAddressFromWhitelist, and transferOwnership. It is with these functions primarliy, that the issuer will update their token's trading permissions.

pragma solidity ^0.4.24;
import "zeppelin-solidity/contracts/access/Whitelist.sol";
import "simple-restricted-token/contracts/token/ERC1404/SimpleRestrictedToken.sol";
contract WhitelistToken is SimpleRestrictedToken, Whitelist {
uint8 public constant NON_WHITELISTED_CODE = 1;
string public constant NON_WHITELISTED_ERROR_MESSAGE = "ILLEGAL_TRANSFER_BETWEEN_NON_WHITELISTED_ADDRESSES";
function detectTransferRestriction (address from, address to, uint256 value)
public
view
returns (uint8)
{
// check if counterparties are whitelisted
bool senderIsWhitelisted = whitelist(from)
bool recipientIsWhitelisted = whitelist(to)
if (!senderIsWhitelisted || !recipientIsWhitelisted) {
return NON_WHITELISTED_CODE;
} else {
return super.detectTransferRestriction(from, to, value);
}
}
function messageForTransferRestriction (uint8 restrictionCode)
public
view
returns (string)
{
if (restrictionCode == NON_WHITELISTED_CODE) {
return NON_WHITELISTED_ERROR_MESSAGE;
} else {
return super.messageForTransferRestriction(restrictionCode);
}
}
/**
* Below are relevant functions inherited from parent contracts:
*
* SimpleRestrictedToken is ERC1404, StandardToken
* --------------------------------------------
* function detectTransferRestriction(address from, address to, uint256 value) public view returns (uint8);
* function messageForTransferRestriction(uint8 restrictionCode) public view returns (string);
* --- implemented in StandardToken.sol ---
* function totalSupply() public view returns (uint256);
* function balanceOf(address tokenOwner) public view returns (uint256 balance);
* function allowance(address tokenOwner, address spender) public view returns (uint256);
* function transfer(address to, uint256 value) public returns (bool);
* function approve(address spender, uint256 tokens) public returns (bool);
* function transferFrom(address from, address to, uint256 value) public returns (bool);
*
* Whitelist is Ownable, RBAC
* --------------------------------------------
* function addAddressToWhitelist(address addr) public onlyOwner;
* function addAddressesToWhitelist(address[] addrs) public onlyOwner returns (bool);
* function removeAddressFromWhitelist(address addr) public onlyOwner returns (bool);
* function removeAddressesFromWhitelist(address[] addrs) public onlyOwner returns (bool);
* function whitelist(address addr) public view returns (bool);
* --- implemented in Ownable.sol ---
* modifier onlyOwner();
* function isOwner() public view returns (bool);
* function owner() public view returns (address);
* function transferOwnership(address newOwner) public onlyOwner;
* function renounceOwnership() public onlyOwner;
*/
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment