diff --git a/.soliumrc.json b/.soliumrc.json index f100659..f341a79 100644 --- a/.soliumrc.json +++ b/.soliumrc.json @@ -13,12 +13,10 @@ "quotes": ["error", "double"], "uppercase": "off", "visibility-first": "error", - "missing-natspec-comments": "off", "security/enforce-explicit-visibility": ["error"], "security/no-block-members": ["warning"], - "security/no-inline-assembly": ["warning"], - - "zeppelin/missing-natspec-comments": ["off"] + "zeppelin/missing-natspec-comments": ["warning"], + "security/no-inline-assembly": ["warning"] } } diff --git a/README.md b/README.md index f371286..7a6ab8e 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,9 @@ Access to token transfer functions is guarded by the AccessList. Accounts can be 2. The AccessList contains a large number of addresses and it is impractical to require that this data is transferred if we need to upgrade the token contracts. +### Restricted Minting +In order to limit the damage which can be caused by a compromised minter account, we have implemented the concept of a restricted minting. In restricted minting, a minter is only allowed to mint to a predetermined account which is specified by the owner. This prevents an attacker from minting new supply directly to their account, since new supply can only be minted to the dedicated minting account and is subsequently transferred to its final destination as an independent action. + ## Class Diagram ![classdiagram](docs/images/class_diagram.svg) diff --git a/contracts/ENS.sol b/contracts/ENS.sol index b9b81c5..6837876 100644 --- a/contracts/ENS.sol +++ b/contracts/ENS.sol @@ -7,5 +7,5 @@ import "@ensdomains/ens/contracts/ENSRegistry.sol"; import "@ensdomains/ens/contracts/PublicResolver.sol"; import "@ensdomains/ens/contracts/ReverseRegistrar.sol"; -// Avoild recompiling every time +/** @title Contract declaration to avoid recompiling ENS every time */ contract ENSdummy { } diff --git a/contracts/TokenManager.sol b/contracts/TokenManager.sol index f97df75..b9ae993 100644 --- a/contracts/TokenManager.sol +++ b/contracts/TokenManager.sol @@ -108,8 +108,9 @@ contract TokenManager is Ownable { } /** - * @dev Returns a token of specified name - * @param _name Name of token to be returned + * @dev Finds a token of the specified name + * @param _name Name of the token to be returned + * @return The token of the given name */ function getToken (bytes32 _name) public @@ -121,14 +122,14 @@ contract TokenManager is Ownable { } /** - * @dev Returns list of tokens + * @dev Gets all token names + * @return A list of names */ function getTokens () public view returns (bytes32[]) { - // TODO: Maybe filter out 0 entries (deleted names) from the list? return names; } @@ -136,6 +137,7 @@ contract TokenManager is Ownable { * @dev Checks whether a token of specified name exists exists * in list of tokens * @param _name Name of token + * @return true if a token of the given name exists */ function _tokenExists (bytes32 _name) private diff --git a/contracts/access/Accesslist.sol b/contracts/access/Accesslist.sol index fbe1887..45bd7cc 100644 --- a/contracts/access/Accesslist.sol +++ b/contracts/access/Accesslist.sol @@ -5,10 +5,9 @@ import "./roles/WhitelistAdminRole.sol"; import "./roles/BlacklistAdminRole.sol"; /** - * @title The Accesslist contract - * @dev Contract that contains a whitelist and a blacklist and manages them + * @title The Accesslist contract + * @dev Contract that contains a whitelist and a blacklist and manages them */ - contract Accesslist is WhitelistAdminRole, BlacklistAdminRole { using Roles for Roles.Role; @@ -21,9 +20,9 @@ contract Accesslist is WhitelistAdminRole, BlacklistAdminRole { Roles.Role private blacklist; /** - * @dev Calls internal function _addWhitelisted - * to add given address to whitelist - * @param account Address to be added + * @dev Calls internal function _addWhitelisted + * to add given address to whitelist + * @param account Address to be added */ function addWhitelisted(address account) public @@ -33,9 +32,9 @@ contract Accesslist is WhitelistAdminRole, BlacklistAdminRole { } /** - * @dev Calls internal function _removeWhitelisted - * to remove given address from the whitelist - * @param account Address to be removed + * @dev Calls internal function _removeWhitelisted + * to remove given address from the whitelist + * @param account Address to be removed */ function removeWhitelisted(address account) public @@ -45,9 +44,9 @@ contract Accesslist is WhitelistAdminRole, BlacklistAdminRole { } /** - * @dev Calls internal function _addBlacklisted - * to add given address to blacklist - * @param account Address to be added + * @dev Calls internal function _addBlacklisted + * to add given address to blacklist + * @param account Address to be added */ function addBlacklisted(address account) public @@ -57,9 +56,9 @@ contract Accesslist is WhitelistAdminRole, BlacklistAdminRole { } /** - * @dev Calls internal function _removeBlacklisted - * to remove given address from blacklist - * @param account Address to be removed + * @dev Calls internal function _removeBlacklisted + * to remove given address from blacklist + * @param account Address to be removed */ function removeBlacklisted(address account) public @@ -69,8 +68,9 @@ contract Accesslist is WhitelistAdminRole, BlacklistAdminRole { } /** - * @dev Checks to see if given address is whitelisted - * @param account Address to be checked + * @dev Checks to see if the given address is whitelisted + * @param account Address to be checked + * @return true if address is whitelisted */ function isWhitelisted(address account) public @@ -81,8 +81,9 @@ contract Accesslist is WhitelistAdminRole, BlacklistAdminRole { } /** - * @dev Checks to see if given address is blacklisted - * @param account Address to be checked + * @dev Checks to see if given address is blacklisted + * @param account Address to be checked + * @return true if address is blacklisted */ function isBlacklisted(address account) public @@ -93,8 +94,9 @@ contract Accesslist is WhitelistAdminRole, BlacklistAdminRole { } /** - * @dev Checks to see if given address is whitelisted and not blacklisted - * @param account Address to be checked + * @dev Checks to see if given address is whitelisted and not blacklisted + * @param account Address to be checked + * @return true if address has access */ function hasAccess(address account) public @@ -106,8 +108,8 @@ contract Accesslist is WhitelistAdminRole, BlacklistAdminRole { /** - * @dev Adds given address to the whitelist - * @param account Address to be added + * @dev Adds given address to the whitelist + * @param account Address to be added */ function _addWhitelisted(address account) internal { whitelist.add(account); @@ -115,8 +117,8 @@ contract Accesslist is WhitelistAdminRole, BlacklistAdminRole { } /** - * @dev Removes given address to the whitelist - * @param account Address to be removed + * @dev Removes given address to the whitelist + * @param account Address to be removed */ function _removeWhitelisted(address account) internal { whitelist.remove(account); @@ -124,8 +126,8 @@ contract Accesslist is WhitelistAdminRole, BlacklistAdminRole { } /** - * @dev Adds given address to the blacklist - * @param account Address to be added + * @dev Adds given address to the blacklist + * @param account Address to be added */ function _addBlacklisted(address account) internal { blacklist.add(account); @@ -133,8 +135,8 @@ contract Accesslist is WhitelistAdminRole, BlacklistAdminRole { } /** - * @dev Removes given address to the blacklist - * @param account Address to be removed + * @dev Removes given address to the blacklist + * @param account Address to be removed */ function _removeBlacklisted(address account) internal { blacklist.remove(account); diff --git a/contracts/access/AccesslistGuarded.sol b/contracts/access/AccesslistGuarded.sol index f87adad..1c30467 100644 --- a/contracts/access/AccesslistGuarded.sol +++ b/contracts/access/AccesslistGuarded.sol @@ -3,15 +3,20 @@ pragma solidity ^0.4.24; import "./Accesslist.sol"; /** - * @title The AccesslistGuarded contract - * @dev Contract containing an accesslist and - * modifiers to ensure proper access + * @title The AccesslistGuarded contract + * @dev Contract containing an accesslist and + * modifiers to ensure proper access */ contract AccesslistGuarded { Accesslist private accesslist; bool public whitelistEnabled; + /** + * @dev Constructor. Checks if the accesslist is a zero address + * @param _accesslist The access list + * @param _whitelistEnabled If the whitelist is enabled + */ constructor( Accesslist _accesslist, bool _whitelistEnabled @@ -27,9 +32,9 @@ contract AccesslistGuarded { } /** - * @dev Modifier that requires given address - * to be whitelisted and not blacklisted - * @param account address to be checked + * @dev Modifier that requires given address + * to be whitelisted and not blacklisted + * @param account address to be checked */ modifier requireHasAccess(address account) { require(hasAccess(account), "no access"); @@ -37,8 +42,8 @@ contract AccesslistGuarded { } /** - * @dev Modifier that requires the message sender - * to be whitelisted and not blacklisted + * @dev Modifier that requires the message sender + * to be whitelisted and not blacklisted */ modifier onlyHasAccess() { require(hasAccess(msg.sender), "no access"); @@ -46,9 +51,9 @@ contract AccesslistGuarded { } /** - * @dev Modifier that requires given address - * to be whitelisted - * @param account address to be checked + * @dev Modifier that requires given address + * to be whitelisted + * @param account address to be checked */ modifier requireWhitelisted(address account) { require(isWhitelisted(account), "no access"); @@ -56,8 +61,8 @@ contract AccesslistGuarded { } /** - * @dev Modifier that requires message sender - * to be whitelisted + * @dev Modifier that requires message sender + * to be whitelisted */ modifier onlyWhitelisted() { require(isWhitelisted(msg.sender), "no access"); @@ -65,9 +70,9 @@ contract AccesslistGuarded { } /** - * @dev Modifier that requires given address - * to not be blacklisted - * @param account address to be checked + * @dev Modifier that requires given address + * to not be blacklisted + * @param account address to be checked */ modifier requireNotBlacklisted(address account) { require(isNotBlacklisted(account), "no access"); @@ -75,8 +80,8 @@ contract AccesslistGuarded { } /** - * @dev Modifier that requires message sender - * to not be blacklisted + * @dev Modifier that requires message sender + * to not be blacklisted */ modifier onlyNotBlacklisted() { require(isNotBlacklisted(msg.sender), "no access"); @@ -84,10 +89,12 @@ contract AccesslistGuarded { } /** - * @dev Returns whether account has access. - * If whitelist is enabled a whitelist check is also made, - * otherwise it only checks for blacklisting. - * @param account address to be checked + * @dev Returns whether account has access. + * If whitelist is enabled a whitelist check is also made, + * otherwise it only checks for blacklisting. + * @param account Address to be checked + * @return true if address has access or is not blacklisted when whitelist + * is disabled */ function hasAccess(address account) public view returns (bool) { if (whitelistEnabled) { @@ -98,16 +105,18 @@ contract AccesslistGuarded { } /** - * @dev Returns whether account is whitelisted - * @param account address to be checked + * @dev Returns whether account is whitelisted + * @param account Address to be checked + * @return true if address is whitelisted */ function isWhitelisted(address account) public view returns (bool) { return accesslist.isWhitelisted(account); } /** - * @dev Returns whether account is not blacklisted - * @param account address to be checked + * @dev Returns whether account is not blacklisted + * @param account Address to be checked + * @return true if address is not blacklisted */ function isNotBlacklisted(address account) public view returns (bool) { return !accesslist.isBlacklisted(account); diff --git a/contracts/access/roles/BlacklistAdminRole.sol b/contracts/access/roles/BlacklistAdminRole.sol index d4c2de8..d87b4ba 100644 --- a/contracts/access/roles/BlacklistAdminRole.sol +++ b/contracts/access/roles/BlacklistAdminRole.sol @@ -3,6 +3,7 @@ pragma solidity ^0.4.24; import "openzeppelin-solidity/contracts/access/Roles.sol"; import "openzeppelin-solidity/contracts/ownership/Ownable.sol"; +/** @title Contract managing the blacklist admin role */ contract BlacklistAdminRole is Ownable { using Roles for Roles.Role; @@ -25,27 +26,43 @@ contract BlacklistAdminRole is Ownable { _; } + /** + * @dev Checks if account is blacklist admin + * @param account Account to check + * @return Boolean indicating if account is blacklist admin + */ function isBlacklistAdmin(address account) public view returns (bool) { return blacklistAdmins.has(account); } + /** + * @dev Adds a blacklist admin account. Is only callable by owner. + * @param account Address to be added + */ function addBlacklistAdmin(address account) public onlyOwner { _addBlacklistAdmin(account); } + /** + * @dev Removes a blacklist admin account. Is only callable by owner + * @param account Address to be removed + */ function removeBlacklistAdmin(address account) public onlyOwner { _removeBlacklistAdmin(account); } + /** @dev Allows privilege holder to renounce their role */ function renounceBlacklistAdmin() public { _removeBlacklistAdmin(msg.sender); } + /** @dev Internal implementation of addBlacklistAdmin */ function _addBlacklistAdmin(address account) internal { blacklistAdmins.add(account); emit BlacklistAdminAdded(account); } + /** @dev Internal implementation of removeBlacklistAdmin */ function _removeBlacklistAdmin(address account) internal { blacklistAdmins.remove(account); emit BlacklistAdminRemoved(account); diff --git a/contracts/access/roles/BurnerRole.sol b/contracts/access/roles/BurnerRole.sol index 1ca12be..03fbc7d 100644 --- a/contracts/access/roles/BurnerRole.sol +++ b/contracts/access/roles/BurnerRole.sol @@ -3,6 +3,7 @@ pragma solidity ^0.4.24; import "openzeppelin-solidity/contracts/access/Roles.sol"; import "openzeppelin-solidity/contracts/ownership/Ownable.sol"; +/** @title Contract managing the burner role */ contract BurnerRole is Ownable { using Roles for Roles.Role; @@ -25,27 +26,45 @@ contract BurnerRole is Ownable { _; } + /** + * @dev Checks if account is burner + * @param account Account to check + * @return Boolean indicating if account is burner + */ function isBurner(address account) public view returns (bool) { return burners.has(account); } + /** + * @dev Adds a burner account + * @dev Is only callable by owner + * @param account Address to be added + */ function addBurner(address account) public onlyOwner { _addBurner(account); } + /** + * @dev Removes a burner account + * @dev Is only callable by owner + * @param account Address to be removed + */ function removeBurner(address account) public onlyOwner { _removeBurner(account); } + /** @dev Allows a privileged holder to renounce their role */ function renounceBurner() public { _removeBurner(msg.sender); } + /** @dev Internal implementation of addBurner */ function _addBurner(address account) internal { burners.add(account); emit BurnerAdded(account); } + /** @dev Internal implementation of removeBurner */ function _removeBurner(address account) internal { burners.remove(account); emit BurnerRemoved(account); diff --git a/contracts/access/roles/MinterRole.sol b/contracts/access/roles/MinterRole.sol index 82e1f45..0f67a4b 100644 --- a/contracts/access/roles/MinterRole.sol +++ b/contracts/access/roles/MinterRole.sol @@ -3,6 +3,7 @@ pragma solidity ^0.4.24; import "openzeppelin-solidity/contracts/access/Roles.sol"; import "openzeppelin-solidity/contracts/ownership/Ownable.sol"; +/** @title The minter role contract */ contract MinterRole is Ownable { using Roles for Roles.Role; @@ -11,37 +12,71 @@ contract MinterRole is Ownable { Roles.Role private minters; + /** + * @dev Checks if the message sender is a minter + */ modifier onlyMinter() { require(isMinter(msg.sender), "not minter"); _; } + /** + * @dev Checks if the given address is a minter + * @param account Address to be checked + */ modifier requireMinter(address account) { require(isMinter(account), "not minter"); _; } + /** + * @dev Checks if given address is a minter + * @param account Address to be checked + * @return Is the address a minter + */ function isMinter(address account) public view returns (bool) { return minters.has(account); } + /** + * @dev Calls internal function _addMinter with the given address. + * Can only be called by the owner. + * @param account Address to be passed + */ function addMinter(address account) public onlyOwner { _addMinter(account); } + /** + * @dev Calls internal function _removeMinter with the given address. + * Can only be called by the owner. + * @param account Address to be passed + */ function removeMinter(address account) public onlyOwner { _removeMinter(account); } + /** + * @dev Calls internal function _removeMinter with message sender + * as the parameter + */ function renounceMinter() public { _removeMinter(msg.sender); } + /** + * @dev Adds the given address to minters + * @param account Address to be added + */ function _addMinter(address account) internal { minters.add(account); emit MinterAdded(account); } + /** + * @dev Removes given address from minters + * @param account Address to be removed. + */ function _removeMinter(address account) internal { minters.remove(account); emit MinterRemoved(account); diff --git a/contracts/access/roles/PauserRole.sol b/contracts/access/roles/PauserRole.sol index 7c70a87..fb602d9 100644 --- a/contracts/access/roles/PauserRole.sol +++ b/contracts/access/roles/PauserRole.sol @@ -3,6 +3,7 @@ pragma solidity ^0.4.24; import "openzeppelin-solidity/contracts/access/Roles.sol"; import "openzeppelin-solidity/contracts/ownership/Ownable.sol"; +/** @title Contract managing the pauser role */ contract PauserRole is Ownable { using Roles for Roles.Role; @@ -25,27 +26,43 @@ contract PauserRole is Ownable { _; } + /** + * @dev Checks if account is pauser + * @param account Account to check + * @return Boolean indicating if account is pauser + */ function isPauser(address account) public view returns (bool) { return pausers.has(account); } + /** + * @dev Adds a pauser account. Is only callable by owner. + * @param account Address to be added + */ function addPauser(address account) public onlyOwner { _addPauser(account); } + /** + * @dev Removes a pauser account. Is only callable by owner. + * @param account Address to be removed + */ function removePauser(address account) public onlyOwner { _removePauser(account); } + /** @dev Allows a privileged holder to renounce their role */ function renouncePauser() public { _removePauser(msg.sender); } + /** @dev Internal implementation of addPauser */ function _addPauser(address account) internal { pausers.add(account); emit PauserAdded(account); } + /** @dev Internal implementation of removePauser */ function _removePauser(address account) internal { pausers.remove(account); emit PauserRemoved(account); diff --git a/contracts/access/roles/WhitelistAdminRole.sol b/contracts/access/roles/WhitelistAdminRole.sol index 33f519a..1a3b0ab 100644 --- a/contracts/access/roles/WhitelistAdminRole.sol +++ b/contracts/access/roles/WhitelistAdminRole.sol @@ -3,6 +3,7 @@ pragma solidity ^0.4.24; import "openzeppelin-solidity/contracts/access/Roles.sol"; import "openzeppelin-solidity/contracts/ownership/Ownable.sol"; +/** @title Contract managing the whitelist admin role */ contract WhitelistAdminRole is Ownable { using Roles for Roles.Role; @@ -25,27 +26,43 @@ contract WhitelistAdminRole is Ownable { _; } + /** + * @dev Checks if account is whitelist dmin + * @param account Account to check + * @return Boolean indicating if account is whitelist admin + */ function isWhitelistAdmin(address account) public view returns (bool) { return whitelistAdmins.has(account); } + /** + * @dev Adds a whitelist admin account. Is only callable by owner. + * @param account Address to be added + */ function addWhitelistAdmin(address account) public onlyOwner { _addWhitelistAdmin(account); } + /** + * @dev Removes a whitelist admin account. Is only callable by owner. + * @param account Address to be removed + */ function removeWhitelistAdmin(address account) public onlyOwner { _removeWhitelistAdmin(account); } + /** @dev Allows a privileged holder to renounce their role */ function renounceWhitelistAdmin() public { _removeWhitelistAdmin(msg.sender); } + /** @dev Internal implementation of addWhitelistAdmin */ function _addWhitelistAdmin(address account) internal { whitelistAdmins.add(account); emit WhitelistAdminAdded(account); } + /** @dev Internal implementation of removeWhitelistAdmin */ function _removeWhitelistAdmin(address account) internal { whitelistAdmins.remove(account); emit WhitelistAdminRemoved(account); diff --git a/contracts/lifecycle/Pausable.sol b/contracts/lifecycle/Pausable.sol index 0767be8..f273987 100644 --- a/contracts/lifecycle/Pausable.sol +++ b/contracts/lifecycle/Pausable.sol @@ -40,7 +40,7 @@ contract Pausable is PauserRole { } /** - * @dev called by the owner to pause, triggers stopped state + * @dev Called by the owner to pause, triggers stopped state */ function pause() public onlyPauser whenNotPaused { _paused = true; @@ -48,7 +48,7 @@ contract Pausable is PauserRole { } /** - * @dev called by the owner to unpause, returns to normal state + * @dev Called by the owner to unpause, returns to normal state */ function unpause() public onlyPauser whenPaused { _paused = false; diff --git a/contracts/mocks/AccesslistGuardedMock.sol b/contracts/mocks/AccesslistGuardedMock.sol index f1cd03c..6c624b3 100644 --- a/contracts/mocks/AccesslistGuardedMock.sol +++ b/contracts/mocks/AccesslistGuardedMock.sol @@ -3,10 +3,9 @@ pragma solidity ^0.4.24; import "../access/AccesslistGuarded.sol"; /** - * @title An AccesslistGuarded mock contract - * @dev Contracts to test currently unused modifiers in AccesslistGuarded + * @title An AccesslistGuarded mock contract + * @dev Contracts to test currently unused modifiers in AccesslistGuarded */ - contract AccesslistGuardedMock is AccesslistGuarded { constructor(Accesslist _accesslist, bool whitelistEnabled) @@ -17,7 +16,7 @@ contract AccesslistGuardedMock is AccesslistGuarded { /** * @dev Function that returns true if - * given address has access + * given address has access * @param account Address to check */ function requireHasAccessMock(address account) @@ -31,7 +30,7 @@ contract AccesslistGuardedMock is AccesslistGuarded { /** * @dev Function that returns true if - * message sender has access + * message sender has access */ function onlyHasAccessMock() public @@ -44,7 +43,7 @@ contract AccesslistGuardedMock is AccesslistGuarded { /** * @dev Function that returns true if - * given address is whitelisted + * given address is whitelisted * @param account Address to check */ function requireWhitelistedMock(address account) @@ -58,7 +57,7 @@ contract AccesslistGuardedMock is AccesslistGuarded { /** * @dev Function that returns true if - * message sender is Whitelisted + * message sender is Whitelisted */ function onlyWhitelistedMock() public @@ -70,9 +69,9 @@ contract AccesslistGuardedMock is AccesslistGuarded { } /** - * @dev Function that returns true if - * given address isn't blacklisted - * @param account Address to check + * @dev Function that returns true if + * given address isn't blacklisted + * @param account Address to check */ function requireNotBlacklistedMock(address account) public @@ -84,8 +83,8 @@ contract AccesslistGuardedMock is AccesslistGuarded { } /** - * @dev Function that returns true if - * message sender isn't blacklisted + * @dev Function that returns true if + * message sender isn't blacklisted */ function onlyNotBlacklistedMock() public diff --git a/contracts/mocks/BlacklistAdminRoleMock.sol b/contracts/mocks/BlacklistAdminRoleMock.sol index 4e3822d..f9712e9 100644 --- a/contracts/mocks/BlacklistAdminRoleMock.sol +++ b/contracts/mocks/BlacklistAdminRoleMock.sol @@ -2,11 +2,22 @@ pragma solidity ^0.4.24; import "../access/roles/BlacklistAdminRole.sol"; +/** + * @title An Blacklist admin mock contract + * @dev Contract to test currently unused modifiers and functions for + * the blacklist administrator role + */ contract BlacklistAdminRoleMock is BlacklistAdminRole { + /** @dev Tests the msg.sender-dependent onlyBlacklistAdmin modifier */ function onlyBlacklistAdminMock() public view onlyBlacklistAdmin { } + /** + * @dev Tests the requireBlacklistAdmin modifier which checks if the + * given address is a blacklist admin + * @param a Address to be checked + */ function requireBlacklistAdminMock(address a) public view @@ -14,11 +25,12 @@ contract BlacklistAdminRoleMock is BlacklistAdminRole { { } - // Causes compilation errors if functions are not declared internal + /** @dev Causes compilation errors if _removeBlacklistAdmin function is not declared internal */ function _removeBlacklistAdmin(address account) internal { super._removeBlacklistAdmin(account); } + /** @dev Causes compilation errors if _removeBlacklistAdmin function is not declared internal */ function _addBlacklistAdmin(address account) internal { super._addBlacklistAdmin(account); } diff --git a/contracts/mocks/BurnerRoleMock.sol b/contracts/mocks/BurnerRoleMock.sol index 1315c55..12c523b 100644 --- a/contracts/mocks/BurnerRoleMock.sol +++ b/contracts/mocks/BurnerRoleMock.sol @@ -2,19 +2,30 @@ pragma solidity ^0.4.24; import "../access/roles/BurnerRole.sol"; +/** + * @title Burner role mock contract + * @dev Contract to test currently unused modifiers and functions for + * the burner role + */ contract BurnerRoleMock is BurnerRole { + /** @dev Tests the msg.sender-dependent onlyBurner modifier */ function onlyBurnerMock() public view onlyBurner { } + /** @dev Tests the requireBurner modifier which checks if the + * given address is a blacklist admin + * @param a The address to be checked + */ function requireBurnerMock(address a) public view requireBurner(a) { } - // Causes compilation errors if functions are not declared internal + /** @dev Causes compilation errors if _removeBurner function is not declared internal */ function _removeBurner(address account) internal { super._removeBurner(account); } + /** @dev Causes compilation errors if _removeBurner function is not declared internal */ function _addBurner(address account) internal { super._addBurner(account); } diff --git a/contracts/mocks/ExternalERC20BurnableMock.sol b/contracts/mocks/ExternalERC20BurnableMock.sol index 14759c9..9051066 100644 --- a/contracts/mocks/ExternalERC20BurnableMock.sol +++ b/contracts/mocks/ExternalERC20BurnableMock.sol @@ -3,8 +3,14 @@ pragma solidity ^0.4.24; import "../token/ERC20/ExternalERC20Burnable.sol"; import "../token/ERC20/ExternalERC20Storage.sol"; +/** @title Mock contract for testing ExternalERC20Burnable */ contract ExternalERC20BurnableMock is ExternalERC20Burnable { + /** @dev Initializes an ERC20Burnable, sets up the external + * storage and mints an amount of token to the given account + * @param initialAccount The account that tokens should be minted to + * @param initialBalance The amount of tokens that should be minted + */ constructor(address initialAccount, uint256 initialBalance) ExternalERC20(new ExternalERC20Storage()) public diff --git a/contracts/mocks/ExternalERC20MintableMock.sol b/contracts/mocks/ExternalERC20MintableMock.sol index 56fc924..5b44afd 100644 --- a/contracts/mocks/ExternalERC20MintableMock.sol +++ b/contracts/mocks/ExternalERC20MintableMock.sol @@ -3,6 +3,11 @@ pragma solidity ^0.4.24; import "../token/ERC20/ExternalERC20Mintable.sol"; import "./MinterRoleMock.sol"; +/** + * @title External ERC20 Mintable mock contract + * @dev Contract to test out currently unused functions for the + * external ERC20 mintable contract + */ contract ExternalERC20MintableMock is ExternalERC20Mintable, MinterRoleMock { constructor(address initMintingRecipient) @@ -13,10 +18,19 @@ contract ExternalERC20MintableMock is ExternalERC20Mintable, MinterRoleMock { _externalERC20Storage.transferOwnership(msg.sender); } + /** + * @dev Mints a given amount to a given address + * @param to Address to be minted to + * @param amount Amount to be minted + */ function mint(address to, uint256 amount) public { _mintExplicitSender(msg.sender, to, amount); } + /** + * @dev Changes set minting recipient to given address + * @param to Address to be set + */ function changeMintingRecipient(address to) public { _changeMintingRecipient(msg.sender, to); } diff --git a/contracts/mocks/ExternalERC20Mock.sol b/contracts/mocks/ExternalERC20Mock.sol index 91e9fe0..0b0e520 100644 --- a/contracts/mocks/ExternalERC20Mock.sol +++ b/contracts/mocks/ExternalERC20Mock.sol @@ -3,7 +3,11 @@ pragma solidity ^0.4.24; import "../token/ERC20/ExternalERC20.sol"; import "../token/ERC20/ExternalERC20Storage.sol"; -// mock class using ERC20 +/** + * @title External ERC20 mock contract + * @dev Contract to test out currently unused functions for the + * external ERC20 + */ contract ExternalERC20Mock is ExternalERC20 { constructor(address initialAccount, uint256 initialBalance) @@ -15,19 +19,39 @@ contract ExternalERC20Mock is ExternalERC20 { _mint(initialAccount, initialBalance); } + /** + * @dev Mints amount to given address + * @param account Receiving address + * @param amount Amount to be minted + */ function mint(address account, uint256 amount) public { _mint(account, amount); } + /** + * @dev Burn amount from the given address + * @param account Address to burn from + * @param amount Amount to be burned + */ function burn(address account, uint256 amount) public { _burn(account, amount); } + /** + * @dev Message sender burns approved amount from the given address + * @param account Address to burn from + * @param amount Amount to be burned + */ function burnFrom(address account, uint256 amount) public { _burnFrom(msg.sender, account, amount); } - // Functions for testing + /** + * @dev Approve test function. Approves the given address to spend amount. + * @param originSender Address that approves spending + * @param spender Address to be approved + * @param value Amount to be approved + */ function approvePublicTest( address originSender, address spender, @@ -38,6 +62,13 @@ contract ExternalERC20Mock is ExternalERC20 { super._approve(originSender, spender, value); } + /** + * @dev Transfer from test function + * @param originSender Address of sender + * @param from Address to be sent from + * @param to Address to be sent to + * @param value Amount to be sent + */ function transferFromPublicTest( address originSender, address from, @@ -53,6 +84,12 @@ contract ExternalERC20Mock is ExternalERC20 { ); } + /** + * @dev Increase allowance test function + * @param originSender Address to increase allowance + * @param spender Address to get increased allowance + * @param addedValue Amount to increase by + */ function increaseAllowancePublicTest( address originSender, address spender, @@ -63,6 +100,12 @@ contract ExternalERC20Mock is ExternalERC20 { super._increaseAllowance(originSender, spender, addedValue); } + /** + * @dev Decrease allowance test function + * @param originSender Address to decrease allowance + * @param spender Address to have decreased allowance + * @param subtractedValue Amount to decrease by + */ function decreaseAllowancePublicTest( address originSender, address spender, @@ -73,6 +116,12 @@ contract ExternalERC20Mock is ExternalERC20 { super._decreaseAllowance(originSender, spender, subtractedValue); } + /** + * @dev burn from test function + * @param burner address to burn + * @param account address to burn from + * @param value amount to burn + */ function burnFromPublicTest( address burner, address account, @@ -83,7 +132,7 @@ contract ExternalERC20Mock is ExternalERC20 { super._burnFrom(burner, account, value); } - // Fails if any of the following functions are not declared as internal + /** Causes compilation errors if _approve function is not declared internal */ function _approve( address originSender, address spender, @@ -94,6 +143,7 @@ contract ExternalERC20Mock is ExternalERC20 { super._approve(originSender, spender, value); } + /** Causes compilation errors if _transferFrom function is not declared internal */ function _transferFrom( address originSender, address from, @@ -109,6 +159,7 @@ contract ExternalERC20Mock is ExternalERC20 { ); } + /** Causes compilation errors if _increaseAllowance function is not declared internal */ function _increaseAllowance( address originSender, address spender, @@ -119,6 +170,7 @@ contract ExternalERC20Mock is ExternalERC20 { super._increaseAllowance(originSender, spender, addedValue); } + /** Causes compilation errors if _decreaseAllowance function is not declared internal */ function _decreaseAllowance( address originSender, address spender, @@ -129,18 +181,22 @@ contract ExternalERC20Mock is ExternalERC20 { super._decreaseAllowance(originSender, spender, subtractedValue); } + /** Causes compilation errors if _transfer function is not declared internal */ function _transfer(address from, address to, uint256 value) internal { super._transfer(from, to, value); } + /** Causes compilation errors if _mint function is not declared internal */ function _mint(address account, uint256 value) internal { super._mint(account, value); } + /** Causes compilation errors if _burn function is not declared internal */ function _burn(address account, uint256 value) internal { super._burn(account, value); } + /** Causes compilation errors if _burnFrom function is not declared internal */ function _burnFrom( address burner, address account, diff --git a/contracts/mocks/ExternalERC20PausableMock.sol b/contracts/mocks/ExternalERC20PausableMock.sol index afbda39..a680405 100644 --- a/contracts/mocks/ExternalERC20PausableMock.sol +++ b/contracts/mocks/ExternalERC20PausableMock.sol @@ -4,9 +4,17 @@ import "../token/ERC20/ExternalERC20Pausable.sol"; import "../token/ERC20/ExternalERC20Storage.sol"; import "./PauserRoleMock.sol"; -// mock class using ERC20Pausable +/** + * @title Mock contract for testing MinterRole + */ contract ExternalERC20PausableMock is ExternalERC20Pausable, PauserRoleMock { + /** + * @dev Initializes an ERC20Pausable, sets up the external + * storage and mints an amount of token to the given account + * @param initialAccount The account that tokens should be minted to + * @param initialBalance The amount of tokens that should be minted + */ constructor(address initialAccount, uint initialBalance) ExternalERC20(new ExternalERC20Storage()) public diff --git a/contracts/mocks/MinterRoleMock.sol b/contracts/mocks/MinterRoleMock.sol index d4d6e75..cdeccc3 100644 --- a/contracts/mocks/MinterRoleMock.sol +++ b/contracts/mocks/MinterRoleMock.sol @@ -2,19 +2,29 @@ pragma solidity ^0.4.24; import "../access/roles/MinterRole.sol"; +/** + * @title Mock contract for testing MinterRole + */ contract MinterRoleMock is MinterRole { + /** Tests the msg.sender-dependent onlyMinter modifier */ function onlyMinterMock() public view onlyMinter { } + /** + * Tests the requireMinter modifier which checks if the + * given address is a minter + * @param a The address to be checked + */ function requireMinterMock(address a) public view requireMinter(a) { } - // Causes compilation errors if functions are not declared internal + /** Causes compilation errors if _removeMinter function is not declared internal */ function _removeMinter(address account) internal { super._removeMinter(account); } + /** Causes compilation errors if _addMinter function is not declared internal */ function _addMinter(address account) internal { super._addMinter(account); } diff --git a/contracts/mocks/PauserRoleMock.sol b/contracts/mocks/PauserRoleMock.sol index 19821e3..999d727 100644 --- a/contracts/mocks/PauserRoleMock.sol +++ b/contracts/mocks/PauserRoleMock.sol @@ -2,19 +2,29 @@ pragma solidity ^0.4.24; import "../access/roles/PauserRole.sol"; +/** + * @title Mock contract for testing PauserRole + */ contract PauserRoleMock is PauserRole { + /** Tests the msg.sender-dependent onlyPauser modifier */ function onlyPauserMock() public view onlyPauser { } + /** + * Tests the requirePauser modifier which checks if the + * given address is a pauser + * @param a The address to be checked + */ function requirePauserMock(address a) public view requirePauser(a) { } - // Causes compilation errors if functions are not declared internal + /** Causes compilation errors if _removePauser function is not declared internal */ function _removePauser(address account) internal { super._removePauser(account); } + /** Causes compilation errors if _removePauser function is not declared internal */ function _addPauser(address account) internal { super._addPauser(account); } diff --git a/contracts/mocks/TokenXExplicitSenderMock.sol b/contracts/mocks/TokenXExplicitSenderMock.sol index 67ac9dc..2eb8c83 100644 --- a/contracts/mocks/TokenXExplicitSenderMock.sol +++ b/contracts/mocks/TokenXExplicitSenderMock.sol @@ -2,8 +2,16 @@ pragma solidity ^0.4.24; import "../token/TokenXExplicitSender.sol"; +/** + * @title Mock contract for testing TokenXExplicitSender + */ contract TokenXExplicitSenderMock is TokenXExplicitSender { + /** + * Initializes an TokenXExplicitSender. Forwards parameters + * as is except that the initial minting recipient (see + * tokens/ERC20/ExternalERC20Mintable) is set to a static value. + */ constructor( string name, string symbol, diff --git a/contracts/mocks/TokenXMock.sol b/contracts/mocks/TokenXMock.sol index 4f04797..eb1a130 100644 --- a/contracts/mocks/TokenXMock.sol +++ b/contracts/mocks/TokenXMock.sol @@ -6,8 +6,30 @@ import "../token/TokenX.sol"; import "../token/IUpgradableTokenX.sol"; import "./PauserRoleMock.sol"; +/** @title Mock contract for testing TokenX */ contract TokenXMock is TokenX, PauserRoleMock { + /** + * Initializes a TokenX contract and optionally mint some amount to a + * given account + * @param name The name of the token + * @param symbol The symbol of the token + * @param decimals The number of decimals of the token + * @param accesslist Address of a deployed whitelist contract + * @param whitelistEnabled Create token with whitelist enabled + * @param stor Address of a deployed ERC20 storage contract + * @param mintingRecip The initial minting recipient for the token + * @param upgradedFrom The token contract that this contract upgrades. Set + * to address(0) for initial deployments + * @param initialDeployment Set to true if this is the initial deployment of + * the token. Acts as a confirmation of intention which interlocks + * upgradedFrom as follows: If initialDeployment is true, then + * upgradedFrom must be the zero address. Otherwise, upgradedFrom must not + * be the zero address. + * @param initialAccount The account that should be minted to upon creation. + * set to 0 for no minting + * @param initialBalance If minting upon creation, this balance will be minted + */ constructor( string name, string symbol, diff --git a/contracts/mocks/WhitelistAdminRoleMock.sol b/contracts/mocks/WhitelistAdminRoleMock.sol index c04cc86..546e00c 100644 --- a/contracts/mocks/WhitelistAdminRoleMock.sol +++ b/contracts/mocks/WhitelistAdminRoleMock.sol @@ -2,11 +2,18 @@ pragma solidity ^0.4.24; import "../access/roles/WhitelistAdminRole.sol"; +/** @title Mock contract for testing WhitelistAdminRole */ contract WhitelistAdminRoleMock is WhitelistAdminRole { + /** Tests the msg.sender-dependent onlyWhitelistAdmin modifier */ function onlyWhitelistAdminMock() public view onlyWhitelistAdmin { } + /** + * Tests the requireWhitelistAdmin modifier which checks if the + * given address is whitelsited + * @param a The address to be checked + */ function requireWhitelistAdminMock(address a) public view @@ -14,11 +21,12 @@ contract WhitelistAdminRoleMock is WhitelistAdminRole { { } - // Causes compilation errors if functions are not declared internal + /** Causes compilation errors if _removeWhitelistAdmin function is not declared internal */ function _removeWhitelistAdmin(address account) internal { super._removeWhitelistAdmin(account); } + /** Causes compilation errors if _addWhitelistAdmin function is not declared internal */ function _addWhitelistAdmin(address account) internal { super._addWhitelistAdmin(account); } diff --git a/contracts/token/ERC20/ExternalERC20Mintable.sol b/contracts/token/ERC20/ExternalERC20Mintable.sol index 4408da7..5cf6bf1 100644 --- a/contracts/token/ERC20/ExternalERC20Mintable.sol +++ b/contracts/token/ERC20/ExternalERC20Mintable.sol @@ -13,12 +13,17 @@ contract ExternalERC20Mintable is ExternalERC20, MinterRole { event MintingRecipientAccountChanged(address prev, address next); + /** + * @dev constructor. Sets minting recipient to given address + * @param _mintingRecipientAccount address to be set to recipient + */ constructor(address _mintingRecipientAccount) internal { _changeMintingRecipient(msg.sender, _mintingRecipientAccount); } /** - * @dev Allows the owner to change the current minting recipient account + * @dev Internal function allowing the owner to change the current minting recipient account + * @param sender The sender address of the request * @param _mintingRecipientAccount address of new minting recipient */ function _changeMintingRecipient( @@ -37,6 +42,7 @@ contract ExternalERC20Mintable is ExternalERC20, MinterRole { /** * @dev Function to mint tokens + * @param sender the sender address of the requiest * @param to The address that will receive the minted tokens. * @param value The amount of tokens to mint. * @return A boolean that indicates if the operation was successful. diff --git a/contracts/token/ERC20/ExternalERC20Pausable.sol b/contracts/token/ERC20/ExternalERC20Pausable.sol index 37b2cd1..b9ddaa9 100644 --- a/contracts/token/ERC20/ExternalERC20Pausable.sol +++ b/contracts/token/ERC20/ExternalERC20Pausable.sol @@ -6,9 +6,13 @@ import "../../lifecycle/Pausable.sol"; /** * @title ExternalERC20 Pausable token * @dev ERC20 modified with pausable transfers. - **/ + */ contract ExternalERC20Pausable is ExternalERC20, Pausable { + /** + * Wrapper for ExternalERC20.transfer which requires that the + * contract is not currently paused + */ function transfer( address to, uint256 value @@ -20,6 +24,10 @@ contract ExternalERC20Pausable is ExternalERC20, Pausable { return super.transfer(to, value); } + /** + * Wrapper for ExternalERC20.transferFrom which requires that the + * contract is not currently paused + */ function transferFrom( address from, address to, @@ -32,6 +40,10 @@ contract ExternalERC20Pausable is ExternalERC20, Pausable { return super.transferFrom(from, to, value); } + /** + * Wrapper for ExternalERC20.approve which requires that the + * contract is not currently paused + */ function approve( address spender, uint256 value @@ -43,6 +55,10 @@ contract ExternalERC20Pausable is ExternalERC20, Pausable { return super.approve(spender, value); } + /** + * Wrapper for ExternalERC20.increaseAllowance which requires + * that the contract is not currently paused + */ function increaseAllowance( address spender, uint addedValue @@ -54,6 +70,10 @@ contract ExternalERC20Pausable is ExternalERC20, Pausable { return super.increaseAllowance(spender, addedValue); } + /** + * Wrapper for ExternalERC20.decreaseAllowance which requires + * that the contract is not currently paused + */ function decreaseAllowance( address spender, uint subtractedValue diff --git a/contracts/token/ITokenX.sol b/contracts/token/ITokenX.sol index 72b5ea6..5207519 100644 --- a/contracts/token/ITokenX.sol +++ b/contracts/token/ITokenX.sol @@ -2,8 +2,14 @@ pragma solidity ^0.4.24; import "./IUpgradableTokenX.sol"; +/** + * @title TokenX interface + * @dev The interface comprising a TokenX contract + */ interface ITokenX { + /* solium-disable zeppelin/missing-natspec-comments */ + function upgrade(IUpgradableTokenX upgradedToken) external; /* Taken from ERC20Detailed in openzeppelin-solidity */ diff --git a/contracts/token/IUpgradableTokenX.sol b/contracts/token/IUpgradableTokenX.sol index 566326c..ef0c75c 100644 --- a/contracts/token/IUpgradableTokenX.sol +++ b/contracts/token/IUpgradableTokenX.sol @@ -1,5 +1,9 @@ pragma solidity ^0.4.24; +/** + * @title Interface of an upgradable token + * @dev See implementation for + */ interface IUpgradableTokenX { event Transfer(address indexed from, @@ -11,6 +15,8 @@ interface IUpgradableTokenX { uint256 value); + /* solium-disable zeppelin/missing-natspec-comments */ + function finalizeUpgrade() external; /* Taken from ERC20Detailed in openzeppelin-solidity */ diff --git a/contracts/token/TokenX.sol b/contracts/token/TokenX.sol index d90e369..4b7f52c 100644 --- a/contracts/token/TokenX.sol +++ b/contracts/token/TokenX.sol @@ -6,11 +6,28 @@ import "./TokenXExplicitSender.sol"; import "./ITokenX.sol"; import "./IUpgradableTokenX.sol"; +/** @title Main TokenX contract */ contract TokenX is ITokenX, TokenXExplicitSender { ExternalERC20Storage private externalStorage; IUpgradableTokenX public upgradedToken; + /** + * @param name The name of the token + * @param symbol The symbol of the token + * @param decimals The number of decimals of the token + * @param accesslist Address of a deployed whitelist contract + * @param whitelistEnabled Create token with whitelist enabled + * @param externalERC20Storage Address of a deployed ERC20 storage contract + * @param mintingRecipientAccount The initial minting recipient of the token + * @param upgradedFrom The token contract that this contract upgrades. Set + * to address(0) for initial deployments + * @param initialDeployment Set to true if this is the initial deployment of + * the token. Acts as a confirmation of intention which interlocks + * upgradedFrom as follows: If initialDeployment is true, then + * upgradedFrom must be the zero address. Otherwise, upgradedFrom must not + * be the zero address. + */ constructor( string name, string symbol, @@ -43,10 +60,17 @@ contract TokenX is ITokenX, TokenXExplicitSender { event Upgraded(address indexed to); + /** + * @return Is this token upgraded + */ function isUpgraded() public view returns (bool) { return upgradedToken != IUpgradableTokenX(0); } + /** + * Upgrades the current token + * @param _upgradedToken The address of the token that this token should be upgraded to + */ function upgrade(IUpgradableTokenX _upgradedToken) public onlyOwner { require(!isUpgraded(), "Token is already upgraded"); require(_upgradedToken != IUpgradableTokenX(0), @@ -62,6 +86,10 @@ contract TokenX is ITokenX, TokenXExplicitSender { emit Upgraded(_upgradedToken); } + /** + * @dev Proxies call to new token if this token is upgraded + * @return the name of the token. + */ function name() public view returns(string) { if (isUpgraded()) { return upgradedToken.nameExplicitSender(msg.sender); @@ -70,6 +98,10 @@ contract TokenX is ITokenX, TokenXExplicitSender { } } + /** + * @dev Proxies call to new token if this token is upgraded + * @return the symbol of the token. + */ function symbol() public view returns(string) { if (isUpgraded()) { return upgradedToken.symbolExplicitSender(msg.sender); @@ -78,6 +110,9 @@ contract TokenX is ITokenX, TokenXExplicitSender { } } + /** + * @return the number of decimals of the token. + */ function decimals() public view returns(uint8) { if (isUpgraded()) { return upgradedToken.decimalsExplicitSender(msg.sender); @@ -86,6 +121,10 @@ contract TokenX is ITokenX, TokenXExplicitSender { } } + /** + * @dev Proxies call to new token if this token is upgraded + * @return Total number of tokens in existence + */ function totalSupply() public view returns (uint256) { if (isUpgraded()) { return upgradedToken.totalSupplyExplicitSender(msg.sender); @@ -94,6 +133,12 @@ contract TokenX is ITokenX, TokenXExplicitSender { } } + /** + * @dev Gets the balance of the specified address. + * @dev Proxies call to new token if this token is upgraded + * @param who The address to query the balance of. + * @return An uint256 representing the amount owned by the passed address. + */ function balanceOf(address who) public view returns (uint256) { if (isUpgraded()) { return upgradedToken.balanceOfExplicitSender(msg.sender, who); @@ -102,6 +147,13 @@ contract TokenX is ITokenX, TokenXExplicitSender { } } + /** + * @dev Function to check the amount of tokens that an owner allowed to a spender. + * @dev Proxies call to new token if this token is upgraded + * @param owner address The address which owns the funds. + * @param spender address The address which will spend the funds. + * @return A uint256 specifying the amount of tokens still available for the spender. + */ function allowance(address owner, address spender) public view @@ -114,6 +166,13 @@ contract TokenX is ITokenX, TokenXExplicitSender { } } + + /** + * @dev Transfer token for a specified address + * @dev Proxies call to new token if this token is upgraded + * @param to The address to transfer to. + * @param value The amount to be transferred. + */ function transfer(address to, uint256 value) public returns (bool) { if (isUpgraded()) { return upgradedToken.transferExplicitSender(msg.sender, to, value); @@ -122,6 +181,16 @@ contract TokenX is ITokenX, TokenXExplicitSender { } } + /** + * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. + * Beware that changing an allowance with this method brings the risk that someone may use both the old + * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this + * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * @dev Proxies call to new token if this token is upgraded + * @param spender The address which will spend the funds. + * @param value The amount of tokens to be spent. + */ function approve(address spender, uint256 value) public returns (bool) { if (isUpgraded()) { return upgradedToken.approveExplicitSender(msg.sender, spender, value); @@ -130,6 +199,13 @@ contract TokenX is ITokenX, TokenXExplicitSender { } } + /** + * @dev Transfer tokens from one address to another + * @dev Proxies call to new token if this token is upgraded + * @param from address The address which you want to send tokens from + * @param to address The address which you want to transfer to + * @param value uint256 the amount of tokens to be transferred + */ function transferFrom(address from, address to, uint256 value) public returns (bool) @@ -146,6 +222,13 @@ contract TokenX is ITokenX, TokenXExplicitSender { } } + /** + * @dev Function to mint tokens + * @dev Proxies call to new token if this token is upgraded + * @param to The address that will receive the minted tokens. + * @param value The amount of tokens to mint. + * @return A boolean that indicates if the operation was successful. + */ function mint(address to, uint256 value) public returns (bool) { if (isUpgraded()) { return upgradedToken.mintExplicitSender(msg.sender, to, value); @@ -154,6 +237,11 @@ contract TokenX is ITokenX, TokenXExplicitSender { } } + /** + * @dev Burns a specific amount of tokens. + * @dev Proxies call to new token if this token is upgraded + * @param value The amount of token to be burned. + */ function burn(uint256 value) public { if (isUpgraded()) { upgradedToken.burnExplicitSender(msg.sender, value); @@ -162,6 +250,12 @@ contract TokenX is ITokenX, TokenXExplicitSender { } } + /** + * @dev Burns a specific amount of tokens from the target address and decrements allowance + * @dev Proxies call to new token if this token is upgraded + * @param from address The address which you want to send tokens from + * @param value uint256 The amount of token to be burned + */ function burnFrom(address from, uint256 value) public { if (isUpgraded()) { upgradedToken.burnFromExplicitSender(msg.sender, from, value); @@ -170,6 +264,16 @@ contract TokenX is ITokenX, TokenXExplicitSender { } } + /** + * @dev Increase the amount of tokens that an owner allowed to a spender. + * approve should be called when allowed_[_spender] == 0. To increment + * allowed value is better to use this function to avoid 2 calls (and wait until + * the first transaction is mined) + * From MonolithDAO Token.sol + * @dev Proxies call to new token if this token is upgraded + * @param spender The address which will spend the funds. + * @param addedValue The amount of tokens to increase the allowance by. + */ function increaseAllowance( address spender, uint addedValue @@ -184,6 +288,16 @@ contract TokenX is ITokenX, TokenXExplicitSender { } } + /** + * @dev Decrease the amount of tokens that an owner allowed to a spender. + * approve should be called when allowed_[_spender] == 0. To decrement + * allowed value is better to use this function to avoid 2 calls (and wait until + * the first transaction is mined) + * From MonolithDAO Token.sol + * @dev Proxies call to new token if this token is upgraded + * @param spender The address which will spend the funds. + * @param subtractedValue The amount of tokens to decrease the allowance by. + */ function decreaseAllowance( address spender, uint subtractedValue @@ -198,6 +312,10 @@ contract TokenX is ITokenX, TokenXExplicitSender { } } + /** + * @dev Allows the owner to change the current minting recipient account + * @param mintingRecip address of new minting recipient + */ function changeMintingRecipient(address mintingRecip) public { if (isUpgraded()) { upgradedToken.changeMintingRecipientExplicitSender(msg.sender, mintingRecip); @@ -206,6 +324,11 @@ contract TokenX is ITokenX, TokenXExplicitSender { } } + /** + * Allows a pauser to pause the current token. + * @dev This function will _not_ be proxied to the new + * token if this token is upgraded + */ function pause () public { if (isUpgraded()) { revert("Token is upgraded. Call pause from new token."); @@ -214,6 +337,11 @@ contract TokenX is ITokenX, TokenXExplicitSender { } } + /** + * Allows a pauser to unpause the current token. + * @dev This function will _not_ be proxied to the new + * token if this token is upgraded + */ function unpause () public { if (isUpgraded()) { revert("Token is upgraded. Call unpause from new token."); diff --git a/contracts/token/TokenXExplicitSender.sol b/contracts/token/TokenXExplicitSender.sol index 9612fa7..049fd7a 100644 --- a/contracts/token/TokenXExplicitSender.sol +++ b/contracts/token/TokenXExplicitSender.sol @@ -14,7 +14,7 @@ import "../access/AccesslistGuarded.sol"; import "./IUpgradableTokenX.sol"; /* solium-enable max-len */ - +/** @title TokenX functions accepting explicit sender params */ contract TokenXExplicitSender is IUpgradableTokenX, ExternalERC20, ExternalERC20Burnable, @@ -26,7 +26,7 @@ contract TokenXExplicitSender is IUpgradableTokenX, { /** - * Holds the address of the + * @dev Holds the address of the */ address private _upgradedFrom; @@ -37,8 +37,11 @@ contract TokenXExplicitSender is IUpgradableTokenX, /** * @param name The name of the token * @param symbol The symbol of the token + * @param decimals The number of decimals of the token * @param accesslist Address of a deployed whitelist contract + * @param whitelistEnabled Create token with whitelist enabled * @param externalERC20Storage Address of a deployed ERC20 storage contract + * @param mintingRecipientAccount The initial minting recipient of the token * @param upgradedFrom The token contract that this contract upgrades. Set * to address(0) for initial deployments * @param initialDeployment Set to true if this is the initial deployment of @@ -79,9 +82,9 @@ contract TokenXExplicitSender is IUpgradableTokenX, } /** - @dev Called by the upgraded contract in order to mark the finalization of - the upgrade and activate the new contract - */ + * @dev Called by the upgraded contract in order to mark the finalization of + * the upgrade and activate the new contract + */ function finalizeUpgrade() external { require(_upgradedFrom != address(0), "Must have a contract to upgrade from"); require(msg.sender == _upgradedFrom, "Sender is not old contract"); @@ -92,17 +95,28 @@ contract TokenXExplicitSender is IUpgradableTokenX, /** * @dev Only allow the old contract to access the functions with explicit * sender passing - */ + */ modifier senderIsProxy () { require(msg.sender == _upgradedFrom, "Proxy is the only allowed caller"); _; } + /** + * @dev Allows execution if token is enabled, i.e. it is the + * initial deployment or is upgraded from a contract which has + * called the finalizeUpgrade function. + */ modifier isEnabled () { require(enabled, "Token disabled"); _; } + /** + * @dev Like TokenX.name, but gets sender from explicit sender + * parameter rather than msg.sender. This function can only be + * called from the proxy contract (the contract that this contract + * upgraded). + */ function nameExplicitSender(address sender) public view @@ -115,6 +129,12 @@ contract TokenXExplicitSender is IUpgradableTokenX, return super.name(); } + /** + * @dev Like TokenX.symbol, but gets sender from explicit sender + * parameter rather than msg.sender. This function can only be + * called from the proxy contract (the contract that this contract + * upgraded). + */ function symbolExplicitSender(address sender) public view @@ -127,6 +147,12 @@ contract TokenXExplicitSender is IUpgradableTokenX, return super.symbol(); } + /** + * @dev Like TokenX.decimal, but gets sender from explicit sender + * parameter rather than msg.sender. This function can only be + * called from the proxy contract (the contract that this contract + * upgraded). + */ function decimalsExplicitSender(address sender) public view @@ -139,6 +165,12 @@ contract TokenXExplicitSender is IUpgradableTokenX, return super.decimals(); } + /** + * @dev Like TokenX.totalSupply, but gets sender from explicit sender + * parameter rather than msg.sender. This function can only be + * called from the proxy contract (the contract that this contract + * upgraded). + */ function totalSupplyExplicitSender(address sender) public view @@ -151,6 +183,12 @@ contract TokenXExplicitSender is IUpgradableTokenX, return super.totalSupply(); } + /** + * @dev Like TokenX.balanceOf, but gets sender from explicit sender + * parameter rather than msg.sender. This function can only be + * called from the proxy contract (the contract that this contract + * upgraded). + */ function balanceOfExplicitSender(address sender, address who) public view @@ -163,6 +201,12 @@ contract TokenXExplicitSender is IUpgradableTokenX, return super.balanceOf(who); } + /** + * @dev Like TokenX.allowance, but gets sender from explicit sender + * parameter rather than msg.sender. This function can only be + * called from the proxy contract (the contract that this contract + * upgraded). + */ function allowanceExplicitSender(address sender, address owner, address spender) public view @@ -175,6 +219,12 @@ contract TokenXExplicitSender is IUpgradableTokenX, return super.allowance(owner, spender); } + /** + * @dev Like TokenX.transfer, but gets sender from explicit sender + * parameter rather than msg.sender. This function can only be + * called from the proxy contract (the contract that this contract + * upgraded). + */ function transferExplicitSender(address sender, address to, uint256 value) public isEnabled @@ -188,6 +238,12 @@ contract TokenXExplicitSender is IUpgradableTokenX, return true; } + /** + * @dev Like TokenX.approve, but gets sender from explicit sender + * parameter rather than msg.sender. This function can only be + * called from the proxy contract (the contract that this contract + * upgraded). + */ function approveExplicitSender(address sender, address spender, uint256 value) public isEnabled @@ -203,6 +259,12 @@ contract TokenXExplicitSender is IUpgradableTokenX, } + /** + * @dev Like TokenX.transferFrom, but gets sender from explicit sender + * parameter rather than msg.sender. This function can only be + * called from the proxy contract (the contract that this contract + * upgraded). + */ function transferFromExplicitSender( address sender, address from, @@ -226,6 +288,12 @@ contract TokenXExplicitSender is IUpgradableTokenX, } + /** + * @dev Like TokenX.increaseAllowance, but gets sender from explicit sender + * parameter rather than msg.sender. This function can only be + * called from the proxy contract (the contract that this contract + * upgraded). + */ function increaseAllowanceExplicitSender( address sender, address spender, @@ -243,7 +311,12 @@ contract TokenXExplicitSender is IUpgradableTokenX, return true; } - + /** + * @dev Like TokenX.decreaseAllowance, but gets sender from explicit sender + * parameter rather than msg.sender. This function can only be + * called from the proxy contract (the contract that this contract + * upgraded). + */ function decreaseAllowanceExplicitSender(address sender, address spender, uint256 subtractedValue) @@ -258,7 +331,12 @@ contract TokenXExplicitSender is IUpgradableTokenX, return true; } - + /** + * @dev Like TokenX.burn, but gets sender from explicit sender + * parameter rather than msg.sender. This function can only be + * called from the proxy contract (the contract that this contract + * upgraded). + */ function burnExplicitSender(address sender, uint256 value) public isEnabled @@ -268,7 +346,12 @@ contract TokenXExplicitSender is IUpgradableTokenX, super._burn(sender, value); } - + /** + * @dev Like TokenX.burnFrom, but gets sender from explicit sender + * parameter rather than msg.sender. This function can only be + * called from the proxy contract (the contract that this contract + * upgraded). + */ function burnFromExplicitSender(address sender, address from, uint256 value) @@ -280,6 +363,12 @@ contract TokenXExplicitSender is IUpgradableTokenX, super._burnFrom(sender, from, value); } + /** + * @dev Like TokenX.mint, but gets sender from explicit sender + * parameter rather than msg.sender. This function can only be + * called from the proxy contract (the contract that this contract + * upgraded). + */ function mintExplicitSender(address sender, address to, uint256 value) public isEnabled @@ -290,6 +379,12 @@ contract TokenXExplicitSender is IUpgradableTokenX, return true; } + /** + * @dev Like TokenX.changeMintingRecipient, but gets sender from + * explicit sender parameter rather than msg.sender. This function + * can only be called from the proxy contract (the contract that + * this contract upgraded). + */ function changeMintingRecipientExplicitSender(address sender, address mintingRecip) public isEnabled @@ -298,6 +393,12 @@ contract TokenXExplicitSender is IUpgradableTokenX, super._changeMintingRecipient(sender, mintingRecip); } + /** + * @dev Like TokenX.transfer, but gets sender from + * explicit sender parameter rather than msg.sender. This function + * can only be called from the proxy contract (the contract that + * this contract upgraded). + */ function transfer(address to, uint256 value) public isEnabled @@ -309,6 +410,12 @@ contract TokenXExplicitSender is IUpgradableTokenX, return super.transfer(to, value); } + /** + * @dev Like TokenX.approve, but gets sender from + * explicit sender parameter rather than msg.sender. This function + * can only be called from the proxy contract (the contract that + * this contract upgraded). + */ function approve(address spender, uint256 value) public isEnabled @@ -320,6 +427,12 @@ contract TokenXExplicitSender is IUpgradableTokenX, return super.approve(spender, value); } + /** + * @dev Like TokenX.transferFrom, but gets sender from + * explicit sender parameter rather than msg.sender. This function + * can only be called from the proxy contract (the contract that + * this contract upgraded). + */ function transferFrom(address from, address to, uint256 value) public isEnabled @@ -332,6 +445,12 @@ contract TokenXExplicitSender is IUpgradableTokenX, return super.transferFrom(from, to, value); } + /** + * @dev Like TokenX.increaseAllowance, but gets sender from + * explicit sender parameter rather than msg.sender. This function + * can only be called from the proxy contract (the contract that + * this contract upgraded). + */ function increaseAllowance(address spender, uint256 addedValue) public isEnabled @@ -343,6 +462,12 @@ contract TokenXExplicitSender is IUpgradableTokenX, return super.increaseAllowance(spender, addedValue); } + /** + * @dev Like TokenX.decreaseAllowance, but gets sender from + * explicit sender parameter rather than msg.sender. This function + * can only be called from the proxy contract (the contract that + * this contract upgraded). + */ function decreaseAllowance(address spender, uint256 subtractedValue) public isEnabled @@ -354,14 +479,17 @@ contract TokenXExplicitSender is IUpgradableTokenX, return super.decreaseAllowance(spender, subtractedValue); } + /** @dev Burning function called by TokenX.burn */ function burn(uint256 value) public isEnabled onlyBurner { super.burn(value); } + /** @dev Burning function called by TokenX.burnFrom */ function burnFrom(address from, uint256 value) public isEnabled onlyBurner { super.burnFrom(from, value); } + /** @dev Minting function called by TokenX.mint */ function mint(address to, uint256 value) public isEnabled @@ -371,6 +499,7 @@ contract TokenXExplicitSender is IUpgradableTokenX, return true; } + /** @dev changeMintingRecipient function called by TokenX.changeMintingRecipient */ function changeMintingRecipient(address _mintingRecipientAddress) public isEnabled diff --git a/docs/images/contracts_overview.svg b/docs/images/contracts_overview.svg index d620d05..1fdcc4d 100644 --- a/docs/images/contracts_overview.svg +++ b/docs/images/contracts_overview.svg @@ -1,3 +1,3 @@ -
manager.etokenize.eth
manager.etokenize.eth<br>
Token Manager
Token Manager<br>
TokenX (1)
TokenX (1)
TokenX (n)
TokenX (n)
...
[Not supported by viewer]
Tokens
Tokens
MinterRole
MinterRole
PauserRole
PauserRole
BurnerRole
BurnerRole
Roles
Roles
AccessList
AccessList
blacklist.etokenize.eth
blacklist.etokenize.eth
WhitelistManagerRole
WhitelistManagerRole
ENS
ENS<br>
Token storage(1)
Token storage(1)
Token storage (n)
Token storage (n)
...
[Not supported by viewer]
Token balance storage
Token balance storage
BlacklistManagerRole
<div>BlacklistManagerRole</div>
\ No newline at end of file +
manager.etokenize.eth
manager.etokenize.eth<br>
Token Manager
Token Manager<br>
TokenX (1)
TokenX (1)
TokenX (n)
TokenX (n)
...
[Not supported by viewer]
Tokens
Tokens
MinterRole
MinterRole
PauserRole
PauserRole
BurnerRole
BurnerRole
Roles
Roles
AccessList
AccessList
accesslist.etokenize.eth
accesslist.etokenize.eth
WhitelistManagerRole
WhitelistManagerRole
ENS
ENS<br>
Token storage(1)
Token storage(1)
Token storage (n)
Token storage (n)
...
[Not supported by viewer]
Token balance storage
Token balance storage
BlacklistManagerRole
<div>BlacklistManagerRole</div>
\ No newline at end of file diff --git a/package.json b/package.json index 607175c..5043103 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "snazzy": "^8.0.0", "solidity-coverage": "^0.5.11", "solium": "^1.1.8", - "solium-plugin-zeppelin": "^0.0.2", + "solium-plugin-zeppelin": "ssh://git@github.com:OpenZeppelin/solium-plugin-zeppelin.git#44029c8391806f5ba042976e07cc53d793bd8247", "truffle-assertions": "^0.7.1" } } diff --git a/yarn.lock b/yarn.lock index 2218144..e9a1de8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1994,6 +1994,11 @@ decompress@^4.0.0: pify "^2.3.0" strip-dirs "^2.0.0" +dedent@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" + integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw= + deep-eql@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" @@ -3625,7 +3630,12 @@ global@~4.3.0: min-document "^2.19.0" process "~0.5.1" -globals@^11.0.1, globals@^11.7.0: +globals@^11.0.1: + version "11.10.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.10.0.tgz#1e09776dffda5e01816b3bb4077c8b59c24eaa50" + integrity sha512-0GZF1RiPKU97IHUO5TORo9w1PwrH/NBPl+fS7oMLdaTRiYmYbwK4NWoZWrAdd0/abG9R2BU+OiwyQpTpE6pdfQ== + +globals@^11.7.0: version "11.9.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.9.0.tgz#bde236808e987f290768a93d065060d78e6ab249" integrity sha512-5cJVtyXWH8PiJPVLZzzoIizXx944O4OmRro5MWKx5fT4MgcN7OfaMutPeaTdJCCURwbWdhhcCWcKIffPnmTzBg== @@ -4418,7 +4428,7 @@ js-tokens@^3.0.2: resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls= -js-yaml@3.x, js-yaml@^3.11.0, js-yaml@^3.9.1: +js-yaml@3.x, js-yaml@^3.11.0: version "3.12.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1" integrity sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A== @@ -4426,7 +4436,7 @@ js-yaml@3.x, js-yaml@^3.11.0, js-yaml@^3.9.1: argparse "^1.0.7" esprima "^4.0.0" -js-yaml@^3.12.0: +js-yaml@^3.12.0, js-yaml@^3.9.1: version "3.12.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.1.tgz#295c8632a18a23e054cf5c9d3cecafe678167600" integrity sha512-um46hB9wNOKlwkHgiuyEVAybXBjwFUV0Z/RaHJblRd9DXltue9FTYvzCr9ErQrK9Adz5MU4gHWVaNUfdmrC8qA== @@ -6768,11 +6778,11 @@ solium-plugin-security@0.1.1: resolved "https://registry.yarnpkg.com/solium-plugin-security/-/solium-plugin-security-0.1.1.tgz#2a87bcf8f8c3abf7d198e292e4ac080284e3f3f6" integrity sha512-kpLirBwIq4mhxk0Y/nn5cQ6qdJTI+U1LO3gpoNIcqNaW+sI058moXBe2UiHs+9wvF9IzYD49jcKhFTxcR9u9SQ== -solium-plugin-zeppelin@^0.0.2: +"solium-plugin-zeppelin@ssh://git@github.com:OpenZeppelin/solium-plugin-zeppelin.git#44029c8391806f5ba042976e07cc53d793bd8247": version "0.0.2" - resolved "https://registry.yarnpkg.com/solium-plugin-zeppelin/-/solium-plugin-zeppelin-0.0.2.tgz#da9ab8f2657a2d65fd07e4436245d045e4bcf59a" - integrity sha512-9g94tij352g8Ov21cFGfMFMQS5UL2ggxuu5mXScrSzzbKK2v4kTnkuqJXcnKOfkccVlVe9ShkDSVPOrgs3UFXQ== + resolved "ssh://git@github.com:OpenZeppelin/solium-plugin-zeppelin.git#44029c8391806f5ba042976e07cc53d793bd8247" dependencies: + dedent "^0.7.0" eslint "^4.13.1" solparse "^2.2.2" util-deprecate "^1.0.2" @@ -6795,7 +6805,7 @@ solium@^1.1.8: solparse "2.2.5" text-table "^0.2.0" -solparse@2.2.5, solparse@^2.2.2: +solparse@2.2.5: version "2.2.5" resolved "https://registry.yarnpkg.com/solparse/-/solparse-2.2.5.tgz#72709c867cd6bfc50ec2325f4b81d2b3ea365d99" integrity sha512-t7tvtR6KU6QfPYLMv1nlCh9DA8HYIu5tbjHpKu0fhGFZ1NuSp0KKDHfFHv07g6v1xgcuUY3rVqNFjZt5b9+5qA== @@ -6804,6 +6814,15 @@ solparse@2.2.5, solparse@^2.2.2: pegjs "^0.10.0" yargs "^10.0.3" +solparse@^2.2.2: + version "2.2.7" + resolved "https://registry.yarnpkg.com/solparse/-/solparse-2.2.7.tgz#5479ff4ba4ca6900df89b902b5af1ee23b816250" + integrity sha512-s2DKdvVxXcWefPgBSb+HgTylomzbNjsKdZDN6PsWi9h+UYdyw7DFozpPCGETNEz523tIjrqBRnSPIoDVL1zv5Q== + dependencies: + mocha "^4.0.1" + pegjs "^0.10.0" + yargs "^10.0.3" + source-list-map@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34"