+
+
+
diff --git a/config/blockchain.json b/config/blockchain.json
index 9dccb92..638c816 100644
--- a/config/blockchain.json
+++ b/config/blockchain.json
@@ -9,12 +9,12 @@
"maxpeers": 0,
"rpcHost": "localhost",
"rpcPort": 8545,
- "rpcCorsDomain": "http://localhost:8000",
+ "rpcCorsDomain": "auto",
"account": {
"password": "config/development/password"
},
"targetGasLimit": 8000000,
- "wsOrigins": "http://localhost:8000",
+ "wsOrigins": "auto",
"wsRPC": true,
"wsHost": "localhost",
"wsPort": 8546,
diff --git a/config/contracts.json b/config/contracts.json
index 3ebb190..87eb4db 100644
--- a/config/contracts.json
+++ b/config/contracts.json
@@ -15,6 +15,15 @@
],
"gas": "auto",
"contracts": {
+ "ERC20Receiver": {
+ "deploy": false
+ },
+ "MiniMeToken": {
+ "deploy": false
+ },
+ "MiniMeTokenFactory": {
+ "deploy": true
+ }
}
}
}
diff --git a/config/development/genesis.json b/config/development/genesis.json
index 4b6ce0d..1a9501b 100644
--- a/config/development/genesis.json
+++ b/config/development/genesis.json
@@ -1,6 +1,8 @@
{
"config": {
- "homesteadBlock": 1
+ "homesteadBlock": 1,
+ "byzantiumBlock": 1,
+ "daoForkSupport": true
},
"nonce": "0x0000000000000042",
"difficulty": "0x0",
diff --git a/contracts/common/Controlled.sol b/contracts/common/Controlled.sol
index d2773f3..7b615b6 100644
--- a/contracts/common/Controlled.sol
+++ b/contracts/common/Controlled.sol
@@ -10,7 +10,7 @@ contract Controlled {
address public controller;
- constructor() public {
+ constructor() internal {
controller = msg.sender;
}
diff --git a/contracts/common/MessageSigned.sol b/contracts/common/MessageSigned.sol
new file mode 100644
index 0000000..5a5a262
--- /dev/null
+++ b/contracts/common/MessageSigned.sol
@@ -0,0 +1,77 @@
+pragma solidity ^0.4.21;
+
+/**
+ * @notice Uses ethereum signed messages
+ */
+contract MessageSigned {
+
+ constructor() internal {
+
+ }
+
+ /**
+ * @notice recovers address who signed the message
+ * @param _signHash operation ethereum signed message hash
+ * @param _messageSignature message `_signHash` signature
+ */
+ function recoverAddress(
+ bytes32 _signHash,
+ bytes _messageSignature
+ )
+ pure
+ internal
+ returns(address)
+ {
+ uint8 v;
+ bytes32 r;
+ bytes32 s;
+ (v,r,s) = signatureSplit(_messageSignature);
+ return ecrecover(
+ _signHash,
+ v,
+ r,
+ s
+ );
+ }
+
+ /**
+ * @notice Hash a hash with `"\x19Ethereum Signed Message:\n32"`
+ * @param _hash Sign to hash.
+ * @return signHash Hash to be signed.
+ */
+ function getSignHash(
+ bytes32 _hash
+ )
+ pure
+ internal
+ returns (bytes32 signHash)
+ {
+ signHash = keccak256("\x19Ethereum Signed Message:\n32", _hash);
+ }
+
+ /**
+ * @dev divides bytes signature into `uint8 v, bytes32 r, bytes32 s`
+ */
+ function signatureSplit(bytes _signature)
+ pure
+ internal
+ returns (uint8 v, bytes32 r, bytes32 s)
+ {
+ // The signature format is a compact form of:
+ // {bytes32 r}{bytes32 s}{uint8 v}
+ // Compact means, uint8 is not padded to 32 bytes.
+ assembly {
+ r := mload(add(_signature, 32))
+ s := mload(add(_signature, 64))
+ // Here we are loading the last 32 bytes, including 31 bytes
+ // of 's'. There is no 'mload8' to do this.
+ //
+ // 'byte' is not working due to the Solidity parser, so lets
+ // use the second best option, 'and'
+ v := and(mload(add(_signature, 65)), 0xff)
+ }
+
+ require(v == 27 || v == 28);
+ }
+
+}
\ No newline at end of file
diff --git a/contracts/common/Owned.sol b/contracts/common/Owned.sol
index 177bf0f..18f03e7 100644
--- a/contracts/common/Owned.sol
+++ b/contracts/common/Owned.sol
@@ -14,7 +14,7 @@ contract Owned {
address public owner;
/// @notice The Constructor assigns the message sender to be `owner`
- constructor() public {
+ constructor() internal {
owner = msg.sender;
}
diff --git a/contracts/token/ApproveAndCallFallBack.sol b/contracts/token/ApproveAndCallFallBack.sol
index 01bbf9b..864b988 100644
--- a/contracts/token/ApproveAndCallFallBack.sol
+++ b/contracts/token/ApproveAndCallFallBack.sol
@@ -1,5 +1,10 @@
-pragma solidity ^0.4.14;
+pragma solidity ^0.4.23;
-contract ApproveAndCallFallBack {
- function receiveApproval(address from, uint256 _amount, address _token, bytes _data) public ;
+interface ApproveAndCallFallBack {
+ function receiveApproval(
+ address from,
+ uint256 _amount,
+ address _token,
+ bytes _data
+ ) external;
}
diff --git a/contracts/token/ERC20Receiver.sol b/contracts/token/ERC20Receiver.sol
new file mode 100644
index 0000000..9a6af70
--- /dev/null
+++ b/contracts/token/ERC20Receiver.sol
@@ -0,0 +1,90 @@
+pragma solidity ^0.4.23;
+
+import "./ERC20Token.sol";
+
+contract ERC20Receiver {
+
+ event TokenDeposited(address indexed token, address indexed sender, uint256 amount);
+ event TokenWithdrawn(address indexed token, address indexed sender, uint256 amount);
+
+ mapping (address => mapping(address => uint256)) tokenBalances;
+
+ constructor() public {
+
+ }
+
+ function depositToken(
+ ERC20Token _token
+ )
+ external
+ {
+ _depositToken(
+ msg.sender,
+ _token,
+ _token.allowance(
+ msg.sender,
+ address(this)
+ )
+ );
+ }
+
+ function withdrawToken(
+ ERC20Token _token,
+ uint256 _amount
+ )
+ external
+ {
+ _withdrawToken(msg.sender, _token, _amount);
+ }
+
+ function depositToken(
+ ERC20Token _token,
+ uint256 _amount
+ )
+ external
+ {
+ require(_token.allowance(msg.sender, address(this)) >= _amount);
+ _depositToken(msg.sender, _token, _amount);
+ }
+
+ function tokenBalanceOf(
+ ERC20Token _token,
+ address _from
+ )
+ external
+ view
+ returns(uint256 fromTokenBalance)
+ {
+ return tokenBalances[address(_token)][_from];
+ }
+
+ function _depositToken(
+ address _from,
+ ERC20Token _token,
+ uint256 _amount
+ )
+ private
+ {
+ require(_amount > 0);
+ if (_token.transferFrom(_from, address(this), _amount)) {
+ tokenBalances[address(_token)][_from] += _amount;
+ emit TokenDeposited(address(_token), _from, _amount);
+ }
+ }
+
+ function _withdrawToken(
+ address _from,
+ ERC20Token _token,
+ uint256 _amount
+ )
+ private
+ {
+ require(_amount > 0);
+ require(tokenBalances[address(_token)][_from] >= _amount);
+ tokenBalances[address(_token)][_from] -= _amount;
+ require(_token.transfer(_from, _amount));
+ emit TokenWithdrawn(address(_token), _from, _amount);
+ }
+
+
+}
\ No newline at end of file
diff --git a/contracts/token/ERC20Token.sol b/contracts/token/ERC20Token.sol
index c210342..ff8de15 100644
--- a/contracts/token/ERC20Token.sol
+++ b/contracts/token/ERC20Token.sol
@@ -1,48 +1,52 @@
-pragma solidity ^0.4.17;
+pragma solidity ^0.4.23;
// Abstract contract for the full ERC 20 Token standard
// https://github.com/ethereum/EIPs/issues/20
-contract ERC20Token {
- /* This is a slight change to the ERC20 base standard.
- function totalSupply() constant returns (uint256 supply);
- is replaced with:
- uint256 public totalSupply;
- This automatically creates a getter function for the totalSupply.
- This is moved to the base contract since public getter functions are not
- currently recognised as an implementation of the matching abstract
- function by the compiler.
- */
- /// total amount of tokens
- uint256 public totalSupply;
+interface ERC20Token {
- /// @notice send `_value` token to `_to` from `msg.sender`
- /// @param _to The address of the recipient
- /// @param _value The amount of token to be transferred
- /// @return Whether the transfer was successful or not
- function transfer(address _to, uint256 _value) public returns (bool success);
+ /**
+ * @notice send `_value` token to `_to` from `msg.sender`
+ * @param _to The address of the recipient
+ * @param _value The amount of token to be transferred
+ * @return Whether the transfer was successful or not
+ */
+ function transfer(address _to, uint256 _value) external returns (bool success);
- /// @notice `msg.sender` approves `_spender` to spend `_value` tokens
- /// @param _spender The address of the account able to transfer the tokens
- /// @param _value The amount of tokens to be approved for transfer
- /// @return Whether the approval was successful or not
- function approve(address _spender, uint256 _value) public returns (bool success);
+ /**
+ * @notice `msg.sender` approves `_spender` to spend `_value` tokens
+ * @param _spender The address of the account able to transfer the tokens
+ * @param _value The amount of tokens to be approved for transfer
+ * @return Whether the approval was successful or not
+ */
+ function approve(address _spender, uint256 _value) external returns (bool success);
- /// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from`
- /// @param _from The address of the sender
- /// @param _to The address of the recipient
- /// @param _value The amount of token to be transferred
- /// @return Whether the transfer was successful or not
- function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);
+ /**
+ * @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from`
+ * @param _from The address of the sender
+ * @param _to The address of the recipient
+ * @param _value The amount of token to be transferred
+ * @return Whether the transfer was successful or not
+ */
+ function transferFrom(address _from, address _to, uint256 _value) external returns (bool success);
- /// @param _owner The address from which the balance will be retrieved
- /// @return The balance
- function balanceOf(address _owner) public view returns (uint256 balance);
+ /**
+ * @param _owner The address from which the balance will be retrieved
+ * @return The balance
+ */
+ function balanceOf(address _owner) external view returns (uint256 balance);
- /// @param _owner The address of the account owning tokens
- /// @param _spender The address of the account able to transfer the tokens
- /// @return Amount of remaining tokens allowed to spent
- function allowance(address _owner, address _spender) public view returns (uint256 remaining);
+ /**
+ * @param _owner The address of the account owning tokens
+ * @param _spender The address of the account able to transfer the tokens
+ * @return Amount of remaining tokens allowed to spent
+ */
+ function allowance(address _owner, address _spender) external view returns (uint256 remaining);
+
+ /**
+ * @notice return total supply of tokens
+ */
+ function totalSupply() external view returns (uint256 supply);
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
diff --git a/contracts/token/MiniMeToken.sol b/contracts/token/MiniMeToken.sol
index bf4378b..67b2c56 100644
--- a/contracts/token/MiniMeToken.sol
+++ b/contracts/token/MiniMeToken.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.6;
+pragma solidity ^0.4.23;
/*
Copyright 2016, Jordi Baylina
@@ -16,14 +16,15 @@ pragma solidity ^0.4.6;
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
-
-/// @title MiniMeToken Contract
-/// @author Jordi Baylina
-/// @dev This token contract's goal is to make it easy for anyone to clone this
-/// token using the token distribution at a given block, this will allow DAO's
-/// and DApps to upgrade their features in a decentralized manner without
-/// affecting the original token
-/// @dev It is ERC20 compliant, but still needs to under go further testing.
+/**
+ * @title MiniMeToken Contract
+ * @author Jordi Baylina
+ * @dev This token contract's goal is to make it easy for anyone to clone this
+ * token using the token distribution at a given block, this will allow DAO's
+ * and DApps to upgrade their features in a decentralized manner without
+ * affecting the original token
+ * @dev It is ERC20 compliant, but still needs to under go further testing.
+ */
import "../common/Controlled.sol";
import "./TokenController.sol";
@@ -31,9 +32,11 @@ import "./ApproveAndCallFallBack.sol";
import "./MiniMeTokenInterface.sol";
import "./MiniMeTokenFactory.sol";
-/// @dev The actual token contract, the default controller is the msg.sender
-/// that deploys the contract, so usually this token will be deployed by a
-/// token controller contract, which Giveth will call a "Campaign"
+/**
+ * @dev The actual token contract, the default controller is the msg.sender
+ * that deploys the contract, so usually this token will be deployed by a
+ * token controller contract, which Giveth will call a "Campaign"
+ */
contract MiniMeToken is MiniMeTokenInterface, Controlled {
string public name; //The Token's name: e.g. DigixDAO Tokens
@@ -41,10 +44,11 @@ contract MiniMeToken is MiniMeTokenInterface, Controlled {
string public symbol; //An identifier: e.g. REP
string public version = "MMT_0.1"; //An arbitrary versioning scheme
-
- /// @dev `Checkpoint` is the structure that attaches a block number to a
- /// given value, the block number attached is the one that last changed the
- /// value
+ /**
+ * @dev `Checkpoint` is the structure that attaches a block number to a
+ * given value, the block number attached is the one that last changed the
+ * value
+ */
struct Checkpoint {
// `fromBlock` is the block number that the value was generated from
@@ -86,20 +90,22 @@ contract MiniMeToken is MiniMeTokenInterface, Controlled {
// Constructor
////////////////
- /// @notice Constructor to create a MiniMeToken
- /// @param _tokenFactory The address of the MiniMeTokenFactory contract that
- /// will create the Clone token contracts, the token factory needs to be
- /// deployed first
- /// @param _parentToken Address of the parent token, set to 0x0 if it is a
- /// new token
- /// @param _parentSnapShotBlock Block of the parent token that will
- /// determine the initial distribution of the clone token, set to 0 if it
- /// is a new token
- /// @param _tokenName Name of the new token
- /// @param _decimalUnits Number of decimals of the new token
- /// @param _tokenSymbol Token Symbol for the new token
- /// @param _transfersEnabled If true, tokens will be able to be transferred
- function MiniMeToken(
+ /**
+ * @notice Constructor to create a MiniMeToken
+ * @param _tokenFactory The address of the MiniMeTokenFactory contract that
+ * will create the Clone token contracts, the token factory needs to be
+ * deployed first
+ * @param _parentToken Address of the parent token, set to 0x0 if it is a
+ * new token
+ * @param _parentSnapShotBlock Block of the parent token that will
+ * determine the initial distribution of the clone token, set to 0 if it
+ * is a new token
+ * @param _tokenName Name of the new token
+ * @param _decimalUnits Number of decimals of the new token
+ * @param _tokenSymbol Token Symbol for the new token
+ * @param _transfersEnabled If true, tokens will be able to be transferred
+ */
+ constructor(
address _tokenFactory,
address _parentToken,
uint _parentSnapShotBlock,
@@ -110,6 +116,7 @@ contract MiniMeToken is MiniMeTokenInterface, Controlled {
)
public
{
+ require(_tokenFactory != address(0)); //if not set, clone feature will not work properly
tokenFactory = MiniMeTokenFactory(_tokenFactory);
name = _tokenName; // Set the name
decimals = _decimalUnits; // Set the decimals
@@ -125,21 +132,25 @@ contract MiniMeToken is MiniMeTokenInterface, Controlled {
// ERC20 Methods
///////////////////
- /// @notice Send `_amount` tokens to `_to` from `msg.sender`
- /// @param _to The address of the recipient
- /// @param _amount The amount of tokens to be transferred
- /// @return Whether the transfer was successful or not
+ /**
+ * @notice Send `_amount` tokens to `_to` from `msg.sender`
+ * @param _to The address of the recipient
+ * @param _amount The amount of tokens to be transferred
+ * @return Whether the transfer was successful or not
+ */
function transfer(address _to, uint256 _amount) public returns (bool success) {
require(transfersEnabled);
return doTransfer(msg.sender, _to, _amount);
}
- /// @notice Send `_amount` tokens to `_to` from `_from` on the condition it
- /// is approved by `_from`
- /// @param _from The address holding the tokens being transferred
- /// @param _to The address of the recipient
- /// @param _amount The amount of tokens to be transferred
- /// @return True if the transfer was successful
+ /**
+ * @notice Send `_amount` tokens to `_to` from `_from` on the condition it
+ * is approved by `_from`
+ * @param _from The address holding the tokens being transferred
+ * @param _to The address of the recipient
+ * @param _amount The amount of tokens to be transferred
+ * @return True if the transfer was successful
+ */
function transferFrom(
address _from,
address _to,
@@ -165,12 +176,14 @@ contract MiniMeToken is MiniMeTokenInterface, Controlled {
return doTransfer(_from, _to, _amount);
}
- /// @dev This is the actual transfer function in the token contract, it can
- /// only be called by other functions in this contract.
- /// @param _from The address holding the tokens being transferred
- /// @param _to The address of the recipient
- /// @param _amount The amount of tokens to be transferred
- /// @return True if the transfer was successful
+ /**
+ * @dev This is the actual transfer function in the token contract, it can
+ * only be called by other functions in this contract.
+ * @param _from The address holding the tokens being transferred
+ * @param _to The address of the recipient
+ * @param _amount The amount of tokens to be transferred
+ * @return True if the transfer was successful
+ */
function doTransfer(
address _from,
address _to,
@@ -180,106 +193,124 @@ contract MiniMeToken is MiniMeTokenInterface, Controlled {
returns(bool)
{
- if (_amount == 0) {
- return true;
- }
+ if (_amount == 0) {
+ return true;
+ }
- require(parentSnapShotBlock < block.number);
+ require(parentSnapShotBlock < block.number);
- // Do not allow transfer to 0x0 or the token contract itself
- require((_to != 0) && (_to != address(this)));
+ // Do not allow transfer to 0x0 or the token contract itself
+ require((_to != 0) && (_to != address(this)));
- // If the amount being transfered is more than the balance of the
- // account the transfer returns false
- var previousBalanceFrom = balanceOfAt(_from, block.number);
- if (previousBalanceFrom < _amount) {
- return false;
- }
+ // If the amount being transfered is more than the balance of the
+ // account the transfer returns false
+ uint256 previousBalanceFrom = balanceOfAt(_from, block.number);
+ if (previousBalanceFrom < _amount) {
+ return false;
+ }
- // Alerts the token controller of the transfer
- if (isContract(controller)) {
- require(TokenController(controller).onTransfer(_from, _to, _amount));
- }
+ // Alerts the token controller of the transfer
+ if (isContract(controller)) {
+ require(TokenController(controller).onTransfer(_from, _to, _amount));
+ }
- // First update the balance array with the new value for the address
- // sending the tokens
- updateValueAtNow(balances[_from], previousBalanceFrom - _amount);
+ // First update the balance array with the new value for the address
+ // sending the tokens
+ updateValueAtNow(balances[_from], previousBalanceFrom - _amount);
- // Then update the balance array with the new value for the address
- // receiving the tokens
- var previousBalanceTo = balanceOfAt(_to, block.number);
- require(previousBalanceTo + _amount >= previousBalanceTo); // Check for overflow
- updateValueAtNow(balances[_to], previousBalanceTo + _amount);
+ // Then update the balance array with the new value for the address
+ // receiving the tokens
+ uint256 previousBalanceTo = balanceOfAt(_to, block.number);
+ require(previousBalanceTo + _amount >= previousBalanceTo); // Check for overflow
+ updateValueAtNow(balances[_to], previousBalanceTo + _amount);
- // An event to make the transfer easy to find on the blockchain
- Transfer(_from, _to, _amount);
+ // An event to make the transfer easy to find on the blockchain
+ emit Transfer(_from, _to, _amount);
- return true;
+ return true;
}
- /// @param _owner The address that's balance is being requested
- /// @return The balance of `_owner` at the current block
- function balanceOf(address _owner) public constant returns (uint256 balance) {
- return balanceOfAt(_owner, block.number);
- }
-
- /// @notice `msg.sender` approves `_spender` to spend `_amount` tokens on
- /// its behalf. This is a modified version of the ERC20 approve function
- /// to be a little bit safer
- /// @param _spender The address of the account able to transfer the tokens
- /// @param _amount The amount of tokens to be approved for transfer
- /// @return True if the approval was successful
- function approve(address _spender, uint256 _amount) public returns (bool success) {
+ function doApprove(
+ address _from,
+ address _spender,
+ uint256 _amount
+ )
+ internal
+ returns (bool)
+ {
require(transfersEnabled);
// To change the approve amount you first have to reduce the addresses`
// allowance to zero by calling `approve(_spender,0)` if it is not
// already 0 to mitigate the race condition described here:
// https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
- require((_amount == 0) || (allowed[msg.sender][_spender] == 0));
+ require((_amount == 0) || (allowed[_from][_spender] == 0));
// Alerts the token controller of the approve function call
if (isContract(controller)) {
- require(TokenController(controller).onApprove(msg.sender, _spender, _amount));
+ require(TokenController(controller).onApprove(_from, _spender, _amount));
}
- allowed[msg.sender][_spender] = _amount;
- Approval(msg.sender, _spender, _amount);
+ allowed[_from][_spender] = _amount;
+ emit Approval(_from, _spender, _amount);
return true;
}
- /// @dev This function makes it easy to read the `allowed[]` map
- /// @param _owner The address of the account that owns the token
- /// @param _spender The address of the account able to transfer the tokens
- /// @return Amount of remaining tokens of _owner that _spender is allowed
- /// to spend
+ /**
+ * @param _owner The address that's balance is being requested
+ * @return The balance of `_owner` at the current block
+ */
+ function balanceOf(address _owner) external view returns (uint256 balance) {
+ return balanceOfAt(_owner, block.number);
+ }
+
+ /**
+ * @notice `msg.sender` approves `_spender` to spend `_amount` tokens on
+ * its behalf. This is a modified version of the ERC20 approve function
+ * to be a little bit safer
+ * @param _spender The address of the account able to transfer the tokens
+ * @param _amount The amount of tokens to be approved for transfer
+ * @return True if the approval was successful
+ */
+ function approve(address _spender, uint256 _amount) external returns (bool success) {
+ doApprove(msg.sender, _spender, _amount);
+ }
+
+ /**
+ * @dev This function makes it easy to read the `allowed[]` map
+ * @param _owner The address of the account that owns the token
+ * @param _spender The address of the account able to transfer the tokens
+ * @return Amount of remaining tokens of _owner that _spender is allowed
+ * to spend
+ */
function allowance(
address _owner,
address _spender
)
- public
- constant
+ external
+ view
returns (uint256 remaining)
{
return allowed[_owner][_spender];
}
-
- /// @notice `msg.sender` approves `_spender` to send `_amount` tokens on
- /// its behalf, and then a function is triggered in the contract that is
- /// being approved, `_spender`. This allows users to use their tokens to
- /// interact with contracts in one function call instead of two
- /// @param _spender The address of the contract able to transfer the tokens
- /// @param _amount The amount of tokens to be approved for transfer
- /// @return True if the function call was successful
+ /**
+ * @notice `msg.sender` approves `_spender` to send `_amount` tokens on
+ * its behalf, and then a function is triggered in the contract that is
+ * being approved, `_spender`. This allows users to use their tokens to
+ * interact with contracts in one function call instead of two
+ * @param _spender The address of the contract able to transfer the tokens
+ * @param _amount The amount of tokens to be approved for transfer
+ * @return True if the function call was successful
+ */
function approveAndCall(
address _spender,
uint256 _amount,
bytes _extraData
)
- public
+ external
returns (bool success)
{
- require(approve(_spender, _amount));
+ require(doApprove(msg.sender, _spender, _amount));
ApproveAndCallFallBack(_spender).receiveApproval(
msg.sender,
@@ -291,9 +322,11 @@ contract MiniMeToken is MiniMeTokenInterface, Controlled {
return true;
}
- /// @dev This function makes it easy to get the total number of tokens
- /// @return The total number of tokens
- function totalSupply() public constant returns (uint) {
+ /**
+ * @dev This function makes it easy to get the total number of tokens
+ * @return The total number of tokens
+ */
+ function totalSupply() external view returns (uint) {
return totalSupplyAt(block.number);
}
@@ -302,16 +335,18 @@ contract MiniMeToken is MiniMeTokenInterface, Controlled {
// Query balance and totalSupply in History
////////////////
- /// @dev Queries the balance of `_owner` at a specific `_blockNumber`
- /// @param _owner The address from which the balance will be retrieved
- /// @param _blockNumber The block number when the balance is queried
- /// @return The balance at `_blockNumber`
+ /**
+ * @dev Queries the balance of `_owner` at a specific `_blockNumber`
+ * @param _owner The address from which the balance will be retrieved
+ * @param _blockNumber The block number when the balance is queried
+ * @return The balance at `_blockNumber`
+ */
function balanceOfAt(
address _owner,
uint _blockNumber
)
public
- constant
+ view
returns (uint)
{
@@ -320,8 +355,7 @@ contract MiniMeToken is MiniMeTokenInterface, Controlled {
// requires that the `parentToken.balanceOfAt` be queried at the
// genesis block for that token as this contains initial balance of
// this token
- if ((balances[_owner].length == 0)
- || (balances[_owner][0].fromBlock > _blockNumber)) {
+ if ((balances[_owner].length == 0) || (balances[_owner][0].fromBlock > _blockNumber)) {
if (address(parentToken) != 0) {
return parentToken.balanceOfAt(_owner, min(_blockNumber, parentSnapShotBlock));
} else {
@@ -335,18 +369,19 @@ contract MiniMeToken is MiniMeTokenInterface, Controlled {
}
}
- /// @notice Total amount of tokens at a specific `_blockNumber`.
- /// @param _blockNumber The block number when the totalSupply is queried
- /// @return The total amount of tokens at `_blockNumber`
- function totalSupplyAt(uint _blockNumber) public constant returns(uint) {
+ /**
+ * @notice Total amount of tokens at a specific `_blockNumber`.
+ * @param _blockNumber The block number when the totalSupply is queried
+ * @return The total amount of tokens at `_blockNumber`
+ */
+ function totalSupplyAt(uint _blockNumber) public view returns(uint) {
// These next few lines are used when the totalSupply of the token is
// requested before a check point was ever created for this token, it
// requires that the `parentToken.totalSupplyAt` be queried at the
// genesis block for this token as that contains totalSupply of this
// token at this block number.
- if ((totalSupplyHistory.length == 0)
- || (totalSupplyHistory[0].fromBlock > _blockNumber)) {
+ if ((totalSupplyHistory.length == 0) || (totalSupplyHistory[0].fromBlock > _blockNumber)) {
if (address(parentToken) != 0) {
return parentToken.totalSupplyAt(min(_blockNumber, parentSnapShotBlock));
} else {
@@ -363,16 +398,18 @@ contract MiniMeToken is MiniMeTokenInterface, Controlled {
// Clone Token Method
////////////////
- /// @notice Creates a new clone token with the initial distribution being
- /// this token at `_snapshotBlock`
- /// @param _cloneTokenName Name of the clone token
- /// @param _cloneDecimalUnits Number of decimals of the smallest unit
- /// @param _cloneTokenSymbol Symbol of the clone token
- /// @param _snapshotBlock Block when the distribution of the parent token is
- /// copied to set the initial distribution of the new clone token;
- /// if the block is zero than the actual block, the current block is used
- /// @param _transfersEnabled True if transfers are allowed in the clone
- /// @return The address of the new MiniMeToken Contract
+ /**
+ * @notice Creates a new clone token with the initial distribution being
+ * this token at `_snapshotBlock`
+ * @param _cloneTokenName Name of the clone token
+ * @param _cloneDecimalUnits Number of decimals of the smallest unit
+ * @param _cloneTokenSymbol Symbol of the clone token
+ * @param _snapshotBlock Block when the distribution of the parent token is
+ * copied to set the initial distribution of the new clone token;
+ * if the block is zero than the actual block, the current block is used
+ * @param _transfersEnabled True if transfers are allowed in the clone
+ * @return The address of the new MiniMeToken Contract
+ */
function createCloneToken(
string _cloneTokenName,
uint8 _cloneDecimalUnits,
@@ -383,12 +420,13 @@ contract MiniMeToken is MiniMeTokenInterface, Controlled {
public
returns(address)
{
- if (_snapshotBlock == 0) {
- _snapshotBlock = block.number;
+ uint snapshotBlock = _snapshotBlock;
+ if (snapshotBlock == 0) {
+ snapshotBlock = block.number;
}
MiniMeToken cloneToken = tokenFactory.createCloneToken(
this,
- _snapshotBlock,
+ snapshotBlock,
_cloneTokenName,
_cloneDecimalUnits,
_cloneTokenSymbol,
@@ -398,18 +436,20 @@ contract MiniMeToken is MiniMeTokenInterface, Controlled {
cloneToken.changeController(msg.sender);
// An event to make the token easy to find on the blockchain
- NewCloneToken(address(cloneToken), _snapshotBlock);
+ emit NewCloneToken(address(cloneToken), snapshotBlock);
return address(cloneToken);
}
////////////////
// Generate and destroy tokens
////////////////
-
- /// @notice Generates `_amount` tokens that are assigned to `_owner`
- /// @param _owner The address that will be assigned the new tokens
- /// @param _amount The quantity of tokens generated
- /// @return True if the tokens are generated correctly
+
+ /**
+ * @notice Generates `_amount` tokens that are assigned to `_owner`
+ * @param _owner The address that will be assigned the new tokens
+ * @param _amount The quantity of tokens generated
+ * @return True if the tokens are generated correctly
+ */
function generateTokens(
address _owner,
uint _amount
@@ -418,21 +458,22 @@ contract MiniMeToken is MiniMeTokenInterface, Controlled {
onlyController
returns (bool)
{
- uint curTotalSupply = totalSupply();
+ uint curTotalSupply = totalSupplyAt(block.number);
require(curTotalSupply + _amount >= curTotalSupply); // Check for overflow
- uint previousBalanceTo = balanceOf(_owner);
+ uint previousBalanceTo = balanceOfAt(_owner, block.number);
require(previousBalanceTo + _amount >= previousBalanceTo); // Check for overflow
updateValueAtNow(totalSupplyHistory, curTotalSupply + _amount);
updateValueAtNow(balances[_owner], previousBalanceTo + _amount);
- Transfer(0, _owner, _amount);
+ emit Transfer(0, _owner, _amount);
return true;
}
-
- /// @notice Burns `_amount` tokens from `_owner`
- /// @param _owner The address that will lose the tokens
- /// @param _amount The quantity of tokens to burn
- /// @return True if the tokens are burned correctly
+ /**
+ * @notice Burns `_amount` tokens from `_owner`
+ * @param _owner The address that will lose the tokens
+ * @param _amount The quantity of tokens to burn
+ * @return True if the tokens are burned correctly
+ */
function destroyTokens(
address _owner,
uint _amount
@@ -441,13 +482,13 @@ contract MiniMeToken is MiniMeTokenInterface, Controlled {
onlyController
returns (bool)
{
- uint curTotalSupply = totalSupply();
+ uint curTotalSupply = totalSupplyAt(block.number);
require(curTotalSupply >= _amount);
- uint previousBalanceFrom = balanceOf(_owner);
+ uint previousBalanceFrom = balanceOfAt(_owner, block.number);
require(previousBalanceFrom >= _amount);
updateValueAtNow(totalSupplyHistory, curTotalSupply - _amount);
updateValueAtNow(balances[_owner], previousBalanceFrom - _amount);
- Transfer(_owner, 0, _amount);
+ emit Transfer(_owner, 0, _amount);
return true;
}
@@ -455,9 +496,10 @@ contract MiniMeToken is MiniMeTokenInterface, Controlled {
// Enable tokens transfers
////////////////
-
- /// @notice Enables token holders to transfer their tokens freely if true
- /// @param _transfersEnabled True if transfers are allowed in the clone
+ /**
+ * @notice Enables token holders to transfer their tokens freely if true
+ * @param _transfersEnabled True if transfers are allowed in the clone
+ */
function enableTransfers(bool _transfersEnabled) public onlyController {
transfersEnabled = _transfersEnabled;
}
@@ -466,20 +508,22 @@ contract MiniMeToken is MiniMeTokenInterface, Controlled {
// Internal helper functions to query and set a value in a snapshot array
////////////////
- /// @dev `getValueAt` retrieves the number of tokens at a given block number
- /// @param checkpoints The history of values being queried
- /// @param _block The block number to retrieve the value at
- /// @return The number of tokens being queried
+ /**
+ * @dev `getValueAt` retrieves the number of tokens at a given block number
+ * @param checkpoints The history of values being queried
+ * @param _block The block number to retrieve the value at
+ * @return The number of tokens being queried
+ */
function getValueAt(
Checkpoint[] storage checkpoints,
uint _block
)
- constant
+ view
internal
returns (uint)
{
if (checkpoints.length == 0) {
- return 0;
+ return 0;
}
// Shortcut for the actual value
@@ -504,44 +548,54 @@ contract MiniMeToken is MiniMeTokenInterface, Controlled {
return checkpoints[min].value;
}
- /// @dev `updateValueAtNow` used to update the `balances` map and the
- /// `totalSupplyHistory`
- /// @param checkpoints The history of data being updated
- /// @param _value The new number of tokens
+ /**
+ * @dev `updateValueAtNow` used to update the `balances` map and the
+ * `totalSupplyHistory`
+ * @param checkpoints The history of data being updated
+ * @param _value The new number of tokens
+ */
function updateValueAtNow(Checkpoint[] storage checkpoints, uint _value) internal {
- if ((checkpoints.length == 0)
- || (checkpoints[checkpoints.length -1].fromBlock < block.number)) {
- Checkpoint storage newCheckPoint = checkpoints[ checkpoints.length++ ];
- newCheckPoint.fromBlock = uint128(block.number);
- newCheckPoint.value = uint128(_value);
- } else {
- Checkpoint storage oldCheckPoint = checkpoints[checkpoints.length-1];
- oldCheckPoint.value = uint128(_value);
- }
+ if (
+ (checkpoints.length == 0) ||
+ (checkpoints[checkpoints.length - 1].fromBlock < block.number))
+ {
+ Checkpoint storage newCheckPoint = checkpoints[checkpoints.length++];
+ newCheckPoint.fromBlock = uint128(block.number);
+ newCheckPoint.value = uint128(_value);
+ } else {
+ Checkpoint storage oldCheckPoint = checkpoints[checkpoints.length-1];
+ oldCheckPoint.value = uint128(_value);
+ }
}
- /// @dev Internal function to determine if an address is a contract
- /// @param _addr The address being queried
- /// @return True if `_addr` is a contract
- function isContract(address _addr) constant internal returns(bool) {
+ /**
+ * @dev Internal function to determine if an address is a contract
+ * @param _addr The address being queried
+ * @return True if `_addr` is a contract
+ */
+ function isContract(address _addr) internal view returns(bool) {
uint size;
- if (_addr == 0){
+ if (_addr == 0) {
return false;
}
assembly {
size := extcodesize(_addr)
}
- return size>0;
+ return size > 0;
}
- /// @dev Helper function to return a min betwen the two uints
+ /**
+ * @dev Helper function to return a min betwen the two uints
+ */
function min(uint a, uint b) internal returns (uint) {
return a < b ? a : b;
}
- /// @notice The fallback function: If the contract's controller has not been
- /// set to 0, then the `proxyPayment` method is called which relays the
- /// ether and creates tokens as described in the token controller contract
+ /**
+ * @notice The fallback function: If the contract's controller has not been
+ * set to 0, then the `proxyPayment` method is called which relays the
+ * ether and creates tokens as described in the token controller contract
+ */
function () public payable {
require(isContract(controller));
require(TokenController(controller).proxyPayment.value(msg.value)(msg.sender));
@@ -551,20 +605,22 @@ contract MiniMeToken is MiniMeTokenInterface, Controlled {
// Safety Methods
//////////
- /// @notice This method can be used by the controller to extract mistakenly
- /// sent tokens to this contract.
- /// @param _token The address of the token contract that you want to recover
- /// set to 0 in case you want to extract ether.
+ /**
+ * @notice This method can be used by the controller to extract mistakenly
+ * sent tokens to this contract.
+ * @param _token The address of the token contract that you want to recover
+ * set to 0 in case you want to extract ether.
+ */
function claimTokens(address _token) public onlyController {
if (_token == 0x0) {
- controller.transfer(this.balance);
+ controller.transfer(address(this).balance);
return;
}
MiniMeToken token = MiniMeToken(_token);
- uint balance = token.balanceOf(this);
+ uint balance = token.balanceOf(address(this));
token.transfer(controller, balance);
- ClaimedTokens(_token, controller, balance);
+ emit ClaimedTokens(_token, controller, balance);
}
////////////////
@@ -572,11 +628,11 @@ contract MiniMeToken is MiniMeTokenInterface, Controlled {
////////////////
event ClaimedTokens(address indexed _token, address indexed _controller, uint _amount);
event Transfer(address indexed _from, address indexed _to, uint256 _amount);
- event NewCloneToken(address indexed _cloneToken, uint _snapshotBlock);
+ event NewCloneToken(address indexed _cloneToken, uint snapshotBlock);
event Approval(
address indexed _owner,
address indexed _spender,
uint256 _amount
- );
+ );
}
\ No newline at end of file
diff --git a/contracts/token/MiniMeTokenFactory.sol b/contracts/token/MiniMeTokenFactory.sol
index a57eea4..3793f09 100644
--- a/contracts/token/MiniMeTokenFactory.sol
+++ b/contracts/token/MiniMeTokenFactory.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity ^0.4.23;
import "./MiniMeToken.sol";
@@ -6,21 +6,25 @@ import "./MiniMeToken.sol";
// MiniMeTokenFactory
////////////////
-/// @dev This contract is used to generate clone contracts from a contract.
-/// In solidity this is the way to create a contract from a contract of the
-/// same class
+/**
+ * @dev This contract is used to generate clone contracts from a contract.
+ * In solidity this is the way to create a contract from a contract of the
+ * same class
+ */
contract MiniMeTokenFactory {
- /// @notice Update the DApp by creating a new token with new functionalities
- /// the msg.sender becomes the controller of this clone token
- /// @param _parentToken Address of the token being cloned
- /// @param _snapshotBlock Block of the parent token that will
- /// determine the initial distribution of the clone token
- /// @param _tokenName Name of the new token
- /// @param _decimalUnits Number of decimals of the new token
- /// @param _tokenSymbol Token Symbol for the new token
- /// @param _transfersEnabled If true, tokens will be able to be transferred
- /// @return The address of the new token contract
+ /**
+ * @notice Update the DApp by creating a new token with new functionalities
+ * the msg.sender becomes the controller of this clone token
+ * @param _parentToken Address of the token being cloned
+ * @param _snapshotBlock Block of the parent token that will
+ * determine the initial distribution of the clone token
+ * @param _tokenName Name of the new token
+ * @param _decimalUnits Number of decimals of the new token
+ * @param _tokenSymbol Token Symbol for the new token
+ * @param _transfersEnabled If true, tokens will be able to be transferred
+ * @return The address of the new token contract
+ */
function createCloneToken(
address _parentToken,
uint _snapshotBlock,
diff --git a/contracts/token/MiniMeTokenInterface.sol b/contracts/token/MiniMeTokenInterface.sol
index e315956..8e7b3d0 100644
--- a/contracts/token/MiniMeTokenInterface.sol
+++ b/contracts/token/MiniMeTokenInterface.sol
@@ -1,68 +1,39 @@
-pragma solidity ^0.4.17;
+pragma solidity ^0.4.23;
-contract MiniMeTokenInterface {
+import "./ERC20Token.sol";
- event Transfer(address indexed _from, address indexed _to, uint256 _value);
- event Approval(address indexed _owner, address indexed _spender, uint256 _value);
-
- /// @dev This function makes it easy to get the total number of tokens
- /// @return The total number of tokens
- function totalSupply() public constant returns (uint);
- /// @param _owner The address from which the balance will be retrieved
- /// @return The balance
- function balanceOf(address _owner) public constant returns (uint256 balance);
+contract MiniMeTokenInterface is ERC20Token {
- /// @notice send `_value` token to `_to` from `msg.sender`
- /// @param _to The address of the recipient
- /// @param _value The amount of token to be transferred
- /// @return Whether the transfer was successful or not
- function transfer(address _to, uint256 _value) public returns (bool success);
-
- /// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from`
- /// @param _from The address of the sender
- /// @param _to The address of the recipient
- /// @param _value The amount of token to be transferred
- /// @return Whether the transfer was successful or not
- function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);
-
- /// @notice `msg.sender` approves `_spender` to spend `_value` tokens
- /// @param _spender The address of the account able to transfer the tokens
- /// @param _value The amount of tokens to be approved for transfer
- /// @return Whether the approval was successful or not
- function approve(address _spender, uint256 _value) public returns (bool success);
-
- /// @param _owner The address of the account owning tokens
- /// @param _spender The address of the account able to transfer the tokens
- /// @return Amount of remaining tokens allowed to spent
- function allowance(address _owner, address _spender) public constant returns (uint256 remaining);
-
- /// @notice `msg.sender` approves `_spender` to send `_amount` tokens on
- /// its behalf, and then a function is triggered in the contract that is
- /// being approved, `_spender`. This allows users to use their tokens to
- /// interact with contracts in one function call instead of two
- /// @param _spender The address of the contract able to transfer the tokens
- /// @param _amount The amount of tokens to be approved for transfer
- /// @return True if the function call was successful
+ /**
+ * @notice `msg.sender` approves `_spender` to send `_amount` tokens on
+ * its behalf, and then a function is triggered in the contract that is
+ * being approved, `_spender`. This allows users to use their tokens to
+ * interact with contracts in one function call instead of two
+ * @param _spender The address of the contract able to transfer the tokens
+ * @param _amount The amount of tokens to be approved for transfer
+ * @return True if the function call was successful
+ */
function approveAndCall(
address _spender,
uint256 _amount,
bytes _extraData
)
- public
+ external
returns (bool success);
-
- /// @notice Creates a new clone token with the initial distribution being
- /// this token at `_snapshotBlock`
- /// @param _cloneTokenName Name of the clone token
- /// @param _cloneDecimalUnits Number of decimals of the smallest unit
- /// @param _cloneTokenSymbol Symbol of the clone token
- /// @param _snapshotBlock Block when the distribution of the parent token is
- /// copied to set the initial distribution of the new clone token;
- /// if the block is zero than the actual block, the current block is used
- /// @param _transfersEnabled True if transfers are allowed in the clone
- /// @return The address of the new MiniMeToken Contract
+ /**
+ * @notice Creates a new clone token with the initial distribution being
+ * this token at `_snapshotBlock`
+ * @param _cloneTokenName Name of the clone token
+ * @param _cloneDecimalUnits Number of decimals of the smallest unit
+ * @param _cloneTokenSymbol Symbol of the clone token
+ * @param _snapshotBlock Block when the distribution of the parent token is
+ * copied to set the initial distribution of the new clone token;
+ * if the block is zero than the actual block, the current block is used
+ * @param _transfersEnabled True if transfers are allowed in the clone
+ * @return The address of the new MiniMeToken Contract
+ */
function createCloneToken(
string _cloneTokenName,
uint8 _cloneDecimalUnits,
@@ -72,11 +43,13 @@ contract MiniMeTokenInterface {
)
public
returns(address);
-
- /// @notice Generates `_amount` tokens that are assigned to `_owner`
- /// @param _owner The address that will be assigned the new tokens
- /// @param _amount The quantity of tokens generated
- /// @return True if the tokens are generated correctly
+
+ /**
+ * @notice Generates `_amount` tokens that are assigned to `_owner`
+ * @param _owner The address that will be assigned the new tokens
+ * @param _amount The quantity of tokens generated
+ * @return True if the tokens are generated correctly
+ */
function generateTokens(
address _owner,
uint _amount
@@ -84,10 +57,12 @@ contract MiniMeTokenInterface {
public
returns (bool);
- /// @notice Burns `_amount` tokens from `_owner`
- /// @param _owner The address that will lose the tokens
- /// @param _amount The quantity of tokens to burn
- /// @return True if the tokens are burned correctly
+ /**
+ * @notice Burns `_amount` tokens from `_owner`
+ * @param _owner The address that will lose the tokens
+ * @param _amount The quantity of tokens to burn
+ * @return True if the tokens are burned correctly
+ */
function destroyTokens(
address _owner,
uint _amount
@@ -95,22 +70,26 @@ contract MiniMeTokenInterface {
public
returns (bool);
-
- /// @notice Enables token holders to transfer their tokens freely if true
- /// @param _transfersEnabled True if transfers are allowed in the clone
+ /**
+ * @notice Enables token holders to transfer their tokens freely if true
+ * @param _transfersEnabled True if transfers are allowed in the clone
+ */
function enableTransfers(bool _transfersEnabled) public;
-
- /// @notice This method can be used by the controller to extract mistakenly
- /// sent tokens to this contract.
- /// @param _token The address of the token contract that you want to recover
- /// set to 0 in case you want to extract ether.
+ /**
+ * @notice This method can be used by the controller to extract mistakenly
+ * sent tokens to this contract.
+ * @param _token The address of the token contract that you want to recover
+ * set to 0 in case you want to extract ether.
+ */
function claimTokens(address _token) public;
- /// @dev Queries the balance of `_owner` at a specific `_blockNumber`
- /// @param _owner The address from which the balance will be retrieved
- /// @param _blockNumber The block number when the balance is queried
- /// @return The balance at `_blockNumber`
+ /**
+ * @dev Queries the balance of `_owner` at a specific `_blockNumber`
+ * @param _owner The address from which the balance will be retrieved
+ * @param _blockNumber The block number when the balance is queried
+ * @return The balance at `_blockNumber`
+ */
function balanceOfAt(
address _owner,
uint _blockNumber
@@ -119,11 +98,11 @@ contract MiniMeTokenInterface {
constant
returns (uint);
- /// @notice Total amount of tokens at a specific `_blockNumber`.
- /// @param _blockNumber The block number when the totalSupply is queried
- /// @return The total amount of tokens at `_blockNumber`
- function totalSupplyAt(uint _blockNumber) public constant returns(uint);
-
-
+ /**
+ * @notice Total amount of tokens at a specific `_blockNumber`.
+ * @param _blockNumber The block number when the totalSupply is queried
+ * @return The total amount of tokens at `_blockNumber`
+ */
+ function totalSupplyAt(uint _blockNumber) public view returns(uint);
}
\ No newline at end of file
diff --git a/contracts/token/StandardToken.sol b/contracts/token/StandardToken.sol
index 10ca74a..b80c513 100644
--- a/contracts/token/StandardToken.sol
+++ b/contracts/token/StandardToken.sol
@@ -4,23 +4,24 @@ import "./ERC20Token.sol";
contract StandardToken is ERC20Token {
+ uint256 private supply;
mapping (address => uint256) balances;
mapping (address => mapping (address => uint256)) allowed;
constructor() internal { }
-
+
function transfer(
address _to,
uint256 _value
)
- public
+ external
returns (bool success)
{
return transfer(msg.sender, _to, _value);
}
function approve(address _spender, uint256 _value)
- public
+ external
returns (bool success)
{
allowed[msg.sender][_spender] = _value;
@@ -33,7 +34,7 @@ contract StandardToken is ERC20Token {
address _to,
uint256 _value
)
- public
+ external
returns (bool success)
{
if (balances[_from] >= _value &&
@@ -47,7 +48,7 @@ contract StandardToken is ERC20Token {
}
function allowance(address _owner, address _spender)
- public
+ external
view
returns (uint256 remaining)
{
@@ -55,12 +56,31 @@ contract StandardToken is ERC20Token {
}
function balanceOf(address _owner)
- public
+ external
view
returns (uint256 balance)
{
return balances[_owner];
}
+
+ function totalSupply()
+ external
+ view
+ returns(uint256 currentTotalSupply)
+ {
+ return supply;
+ }
+
+ function mint(
+ address _to,
+ uint256 _amount
+ )
+ internal
+ {
+ balances[_to] += _amount;
+ supply += _amount;
+ emit Transfer(0x0, _to, _amount);
+ }
function transfer(
address _from,
diff --git a/contracts/token/TestToken.sol b/contracts/token/TestToken.sol
new file mode 100644
index 0000000..2afff21
--- /dev/null
+++ b/contracts/token/TestToken.sol
@@ -0,0 +1,19 @@
+pragma solidity ^0.4.23;
+
+import "./StandardToken.sol";
+
+/**
+ * @notice ERC20Token for test scripts, can be minted by anyone.
+ */
+contract TestToken is StandardToken {
+
+ constructor() public { }
+
+ /**
+ * @notice any caller can mint any `_amount`
+ * @param _amount how much to be minted
+ */
+ function mint(uint256 _amount) public {
+ mint(msg.sender, _amount);
+ }
+}
diff --git a/contracts/token/TokenController.sol b/contracts/token/TokenController.sol
index 9dd7f91..9b9d4f0 100644
--- a/contracts/token/TokenController.sol
+++ b/contracts/token/TokenController.sol
@@ -1,26 +1,33 @@
-pragma solidity ^0.4.14;
+pragma solidity ^0.4.23;
+/**
+ * @dev The token controller contract must implement these functions
+ */
+interface TokenController {
+ /**
+ * @notice Called when `_owner` sends ether to the MiniMe Token contract
+ * @param _owner The address that sent the ether to create tokens
+ * @return True if the ether is accepted, false if it throws
+ */
+ function proxyPayment(address _owner) external payable returns(bool);
-/// @dev The token controller contract must implement these functions
-contract TokenController {
- /// @notice Called when `_owner` sends ether to the MiniMe Token contract
- /// @param _owner The address that sent the ether to create tokens
- /// @return True if the ether is accepted, false if it throws
- function proxyPayment(address _owner) payable returns(bool);
+ /**
+ * @notice Notifies the controller about a token transfer allowing the
+ * controller to react if desired
+ * @param _from The origin of the transfer
+ * @param _to The destination of the transfer
+ * @param _amount The amount of the transfer
+ * @return False if the controller does not authorize the transfer
+ */
+ function onTransfer(address _from, address _to, uint _amount) external returns(bool);
- /// @notice Notifies the controller about a token transfer allowing the
- /// controller to react if desired
- /// @param _from The origin of the transfer
- /// @param _to The destination of the transfer
- /// @param _amount The amount of the transfer
- /// @return False if the controller does not authorize the transfer
- function onTransfer(address _from, address _to, uint _amount) returns(bool);
-
- /// @notice Notifies the controller about an approval allowing the
- /// controller to react if desired
- /// @param _owner The address that calls `approve()`
- /// @param _spender The spender in the `approve()` call
- /// @param _amount The amount in the `approve()` call
- /// @return False if the controller does not authorize the approval
- function onApprove(address _owner, address _spender, uint _amount)
+ /**
+ * @notice Notifies the controller about an approval allowing the
+ * controller to react if desired
+ * @param _owner The address that calls `approve()`
+ * @param _spender The spender in the `approve()` call
+ * @param _amount The amount in the `approve()` call
+ * @return False if the controller does not authorize the approval
+ */
+ function onApprove(address _owner, address _spender, uint _amount) external
returns(bool);
}
diff --git a/embark.json b/embark.json
index ba742a4..7bd3d48 100644
--- a/embark.json
+++ b/embark.json
@@ -1,10 +1,17 @@
{
"contracts": ["contracts/**"],
+ "app": {
+ "js/dapp.js": ["app/dapp.js"],
+ "index.html": "app/index.html",
+ "images/": ["app/images/**"]
+ },
"buildDir": "dist/",
"config": "config/",
- "plugins": {
- },
"versions": {
- "solc": "0.4.23"
+ "web3": "1.0.0-beta",
+ "solc": "0.4.23",
+ "ipfs-api": "17.2.4"
+ },
+ "plugins": {
}
}
diff --git a/package.json b/package.json
index 7cf6084..fb83081 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,7 @@
{
"name": "status-contracts",
- "version": "1.0.0",
+ "version": "0.0.1",
+ "description": "",
"scripts": {
"solidity-coverage": "./node_modules/.bin/solidity-coverage",
"test": "embark test"
@@ -15,13 +16,10 @@
"url": "https://github.com/status-im/contracts/issues"
},
"homepage": "https://github.com/status-im/contracts#readme",
- "devDependencies": {
- "solidity-coverage": "^0.5.0",
- "elliptic": "^6.4.0"
- },
"dependencies": {
- "embark": "^2.7.0",
- "elliptic-curve": "^0.1.0",
- "ethereumjs-util": "^5.1.5"
+ "react": "^16.3.2",
+ "react-blockies": "^1.3.0",
+ "react-bootstrap": "^0.32.1",
+ "react-dom": "^16.3.2"
}
}
diff --git a/test/controlled.js b/test/controlled.js
new file mode 100644
index 0000000..d2b14b4
--- /dev/null
+++ b/test/controlled.js
@@ -0,0 +1,29 @@
+
+exports.Test = (contractsConfig, afterDeploy) => {
+
+ describe("Controlled", async function() {
+ this.timeout(0);
+ var Controlled;
+ var accountsArr;
+ before(function(done) {
+ EmbarkSpec.deployAll(contractsConfig, async function(accounts) {
+ Controlled = Contract;
+ accountsArr = accounts;
+ await afterDeploy(accounts, Contract);
+ done()
+ });
+ });
+
+
+ it("should start with msg.sender as controller", async function() {
+ var controller = await Controlled.methods.controller().call();
+ assert(controller, accountsArr[0]);
+ });
+
+ it("should allow controller to set new controller", async function() {
+ await Controlled.methods.changeController(accountsArr[1]).send({from: accountsArr[0]});
+ var controller = await Controlled.methods.controller().call();
+ assert(controller, accountsArr[1]);
+ });
+ });
+}
\ No newline at end of file
diff --git a/test/erc20token.js b/test/erc20token.js
new file mode 100644
index 0000000..6889734
--- /dev/null
+++ b/test/erc20token.js
@@ -0,0 +1,78 @@
+
+exports.Test = (contractsConfig, afterDeploy) => {
+ describe("ERC20Token", async function() {
+ this.timeout(0);
+ var ERC20Token;
+ var accountsArr;
+ before(function(done) {
+ contractsConfig["ERC20Receiver"] = {};
+ EmbarkSpec.deployAll(contractsConfig, async function(accounts) {
+ ERC20Token = Contract;
+ accountsArr = accounts;
+ await afterDeploy(accounts, Contract);
+ done()
+ });
+ });
+
+ it("should transfer 1 token", async function() {
+ let initialBalance0 = await ERC20Token.methods.balanceOf(accountsArr[0]).call();
+ let initialBalance1 = await ERC20Token.methods.balanceOf(accountsArr[1]).call();
+ await ERC20Token.methods.transfer(accountsArr[1],1).send({from: accountsArr[0]});
+ let result0 = await ERC20Token.methods.balanceOf(accountsArr[0]).call();
+ let result1 = await ERC20Token.methods.balanceOf(accountsArr[1]).call();
+
+ assert.equal(result0, +initialBalance0-1, "account 0 balance unexpected");
+ assert.equal(result1, +initialBalance1+1, "account 1 balance unexpected");
+ });
+
+ it("should set approved amount", async function() {
+ await ERC20Token.methods.approve(accountsArr[2],10000000).send({from: accountsArr[0]});
+ let result = await ERC20Token.methods.allowance(accountsArr[0], accountsArr[2]).call();
+ assert.equal(result, 10000000);
+ });
+
+ it("should consume allowance amount", async function() {
+ let initialAllowance = await ERC20Token.methods.allowance(accountsArr[0], accountsArr[2]).call();
+ await ERC20Token.methods.transferFrom(accountsArr[0], accountsArr[0],1).send({from: accountsArr[2]});
+ let result = await ERC20Token.methods.allowance(accountsArr[0], accountsArr[2]).call();
+
+ assert.equal(result, +initialAllowance-1);
+ });
+
+ it("should transfer approved amount", async function() {
+ let initialBalance0 = await ERC20Token.methods.balanceOf(accountsArr[0]).call();
+ let initialBalance1 = await ERC20Token.methods.balanceOf(accountsArr[1]).call();
+ await ERC20Token.methods.transferFrom(accountsArr[0], accountsArr[1],1).send({from: accountsArr[2]});
+ let result0 = await ERC20Token.methods.balanceOf(accountsArr[0]).call();
+ let result1 = await ERC20Token.methods.balanceOf(accountsArr[1]).call();
+
+ assert.equal(result0, +initialBalance0-1);
+ assert.equal(result1, +initialBalance1+1);
+ });
+
+
+ it("should unset approved amount", async function() {
+ await ERC20Token.methods.approve(accountsArr[2],0).send({from: accountsArr[0]});
+ let result = await ERC20Token.methods.allowance(accountsArr[0], accountsArr[2]).call();
+ assert.equal(result, 0);
+ });
+
+ it("should deposit approved amount to contract ERC20Receiver", async function() {
+ await ERC20Token.methods.approve(ERC20Receiver.address,10).send({from: accountsArr[0]});
+ await ERC20Receiver.methods.depositToken(ERC20Token.address).send({from: accountsArr[0]});
+ let result = await ERC20Receiver.methods.tokenBalanceOf(ERC20Token.address, accountsArr[0]).call();
+ assert.equal(result, 10, "ERC20Receiver.tokenBalanceOf("+ERC20Token.address+","+accountsArr[0]+") wrong");
+ });
+
+ it("should witdraw approved amount from contract ERC20Receiver", async function() {
+ let tokenBalance = await ERC20Receiver.methods.tokenBalanceOf(ERC20Token.address, accountsArr[0]).call();
+ await ERC20Receiver.methods.withdrawToken(ERC20Token.address, tokenBalance).send({from: accountsArr[0]});
+ tokenBalance = await ERC20Receiver.methods.tokenBalanceOf(ERC20Token.address, accountsArr[0]).call();
+ assert.equal(tokenBalance, 0, "ERC20Receiver.tokenBalanceOf("+ERC20Token.address+","+accountsArr[0]+") wrong");
+ });
+
+ //TODO: include checks for expected events fired
+
+
+ });
+}
\ No newline at end of file
diff --git a/test/minimetoken.js b/test/minimetoken.js
new file mode 100644
index 0000000..d911652
--- /dev/null
+++ b/test/minimetoken.js
@@ -0,0 +1,135 @@
+const utils = require('../utils/testUtils')
+const ERC20Token = require('./erc20token');
+const Controlled = require('./controlled');
+
+describe("MiniMeToken", async function() {
+ this.timeout(0);
+ var accounts;
+ var miniMeTokenClone;
+ const b = [];
+
+ before(function(done) {
+ var contractsConfig = {
+ "MiniMeTokenFactory": {
+ },
+ "MiniMeToken": {
+ "args": [
+ "$MiniMeTokenFactory",
+ utils.zeroAddress,
+ 0,
+ "TestMiniMeToken",
+ 18,
+ "TST",
+ true
+ ]
+ }
+ };
+ EmbarkSpec.deployAll(contractsConfig, async function(accountsArr) {
+ accounts = accountsArr
+ done()
+ });
+ });
+
+
+ it('should generate tokens for address 1', async () => {
+ await MiniMeToken.methods.generateTokens(accounts[1], 10).send();
+ assert.equal(await MiniMeToken.methods.totalSupply().call(), 10);
+ assert.equal(await MiniMeToken.methods.balanceOf(accounts[1]).call(), 10);
+ b[0] = await web3.eth.getBlockNumber();
+ });
+
+ it('should transfer tokens from address 1 to address 3', async () => {
+ await MiniMeToken.methods.transfer(accounts[3], 1).send({from: accounts[1]});
+ assert.equal(await MiniMeToken.methods.totalSupply().call(), 10);
+ assert.equal(await MiniMeToken.methods.balanceOf(accounts[1]).call(), 9);
+ assert.equal(await MiniMeToken.methods.balanceOf(accounts[3]).call(), 1);
+ b[1] = await web3.eth.getBlockNumber();
+ });
+
+ it('should destroy 3 tokens from 1 and 1 from 2', async () => {
+ await MiniMeToken.methods.destroyTokens(accounts[1], 3).send({ from: accounts[0] });
+ assert.equal(await MiniMeToken.methods.totalSupply().call(), 7);
+ assert.equal(await MiniMeToken.methods.balanceOf(accounts[1]).call(), 6);
+ b[2] = await web3.eth.getBlockNumber();
+ });
+
+
+ it('should create the clone token', async () => {
+ const miniMeTokenCloneTx = await MiniMeToken.methods.createCloneToken(
+ 'Clone Token 1',
+ 18,
+ 'MMTc',
+ 0,
+ true).send({ from: accounts[0]});
+ let addr = miniMeTokenCloneTx.events.NewCloneToken.raw.topics[1];
+ addr = `0x${addr.slice(26)}`;
+ addr = web3.utils.toChecksumAddress(addr);
+ miniMeTokenClone = new web3.eth.Contract(MiniMeToken._jsonInterface, addr);
+
+ b[3] = await web3.eth.getBlockNumber();
+
+ assert.equal(await miniMeTokenClone.methods.parentToken().call(), MiniMeToken.address);
+ assert.equal(await miniMeTokenClone.methods.parentSnapShotBlock().call(), b[3]);
+ assert.equal(await miniMeTokenClone.methods.totalSupply().call(), 7);
+ assert.equal(await MiniMeToken.methods.balanceOf(accounts[1]).call(), 6);
+
+ assert.equal(await miniMeTokenClone.methods.totalSupplyAt(b[2]).call(), 7);
+ assert.equal(await miniMeTokenClone.methods.balanceOfAt(accounts[3], b[2]).call(), 1);
+ });
+
+ it('should move tokens in the clone token from 2 to 3', async () => {
+
+ await miniMeTokenClone.methods.transfer(accounts[2], 4).send({ from: accounts[1], gas: 1000000 });
+ b[4] = await web3.eth.getBlockNumber();
+
+ assert.equal(await MiniMeToken.methods.balanceOfAt(accounts[1], b[3]).call(), 6);
+ assert.equal(await MiniMeToken.methods.balanceOfAt(accounts[2], b[3]).call(), 0);
+ assert.equal(await miniMeTokenClone.methods.totalSupply().call(), 7);
+ assert.equal(await miniMeTokenClone.methods.balanceOf(accounts[1]).call(), 2);
+ assert.equal(await miniMeTokenClone.methods.balanceOf(accounts[2]).call(), 4);
+ assert.equal(await miniMeTokenClone.methods.balanceOfAt(accounts[1], b[3]).call(), 6);
+ assert.equal(await miniMeTokenClone.methods.balanceOfAt(accounts[2], b[3]).call(), 0);
+ assert.equal(await miniMeTokenClone.methods.balanceOfAt(accounts[1], b[2]).call(), 6);
+ assert.equal(await miniMeTokenClone.methods.balanceOfAt(accounts[2], b[2]).call(), 0);
+ assert.equal(await miniMeTokenClone.methods.totalSupplyAt(b[3]).call(), 7);
+ assert.equal(await miniMeTokenClone.methods.totalSupplyAt(b[2]).call(), 7);
+ });
+
+ it('should create tokens in the child token', async () => {
+ await miniMeTokenClone.methods.generateTokens(accounts[1], 10).send({ from: accounts[0], gas: 1000000});
+ assert.equal(await miniMeTokenClone.methods.totalSupply().call(), 17);
+ assert.equal(await miniMeTokenClone.methods.balanceOf(accounts[1]).call(), 12);
+ assert.equal(await miniMeTokenClone.methods.balanceOf(accounts[2]).call(), 4);
+ });
+
+ var erc20tokenConfig = {
+ "MiniMeTokenFactory": {
+ },
+ "Contract": {
+ "instanceOf" : "MiniMeToken",
+ "args": [
+ "$MiniMeTokenFactory",
+ utils.zeroAddress,
+ 0,
+ "TestMiniMeToken",
+ 18,
+ "TST",
+ true
+ ]
+ }
+ }
+
+ ERC20Token.Test(erc20tokenConfig, async function (accounts, MiniMeToken) {
+ for(i=0;i
(...args) => {
return new Promise((resolve, reject) => {
@@ -95,3 +93,147 @@ exports.promisify = (func) =>
});
}
+
+// This has been tested with the real Ethereum network and Testrpc.
+// Copied and edited from: https://gist.github.com/xavierlepretre/d5583222fde52ddfbc58b7cfa0d2d0a9
+exports.assertReverts = (contractMethodCall, maxGasAvailable) => {
+ return new Promise((resolve, reject) => {
+ try {
+ resolve(contractMethodCall())
+ } catch (error) {
+ reject(error)
+ }
+ })
+ .then(tx => {
+ assert.equal(tx.receipt.gasUsed, maxGasAvailable, "tx successful, the max gas available was not consumed")
+ })
+ .catch(error => {
+ if ((error + "").indexOf("invalid opcode") < 0 && (error + "").indexOf("out of gas") < 0) {
+ // Checks if the error is from TestRpc. If it is then ignore it.
+ // Otherwise relay/throw the error produced by the above assertion.
+ // Note that no error is thrown when using a real Ethereum network AND the assertion above is true.
+ throw error
+ }
+ })
+}
+
+exports.listenForEvent = event => new Promise((resolve, reject) => {
+ event({}, (error, response) => {
+ if (!error) {
+ resolve(response.args)
+ } else {
+ reject(error)
+ }
+ event.stopWatching()
+ })
+});
+
+exports.eventValues = (receipt, eventName) => {
+ if(receipt.events[eventName])
+ return receipt.events[eventName].returnValues;
+}
+
+exports.addressToBytes32 = (address) => {
+ const stringed = "0000000000000000000000000000000000000000000000000000000000000000" + address.slice(2);
+ return "0x" + stringed.substring(stringed.length - 64, stringed.length);
+}
+
+
+// OpenZeppelin's expectThrow helper -
+// Source: https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/test/helpers/expectThrow.js
+exports.expectThrow = async promise => {
+ try {
+ await promise;
+ } catch (error) {
+ // TODO: Check jump destination to destinguish between a throw
+ // and an actual invalid jump.
+ const invalidOpcode = error.message.search('invalid opcode') >= 0;
+ // TODO: When we contract A calls contract B, and B throws, instead
+ // of an 'invalid jump', we get an 'out of gas' error. How do
+ // we distinguish this from an actual out of gas event? (The
+ // testrpc log actually show an 'invalid jump' event.)
+ const outOfGas = error.message.search('out of gas') >= 0;
+ const revert = error.message.search('revert') >= 0;
+ assert(
+ invalidOpcode || outOfGas || revert,
+ 'Expected throw, got \'' + error + '\' instead',
+ );
+ return;
+ }
+ assert.fail('Expected throw not received');
+ };
+
+exports.assertJump = (error) => {
+ assert(error.message.search('revert') > -1, 'Revert should happen');
+}
+
+var callbackToResolve = function (resolve, reject) {
+ return function (error, value) {
+ if (error) {
+ reject(error);
+ } else {
+ resolve(value);
+ }
+ };
+};
+
+exports.promisify = (func) =>
+ (...args) => {
+ return new Promise((resolve, reject) => {
+ const callback = (err, data) => err ? reject(err) : resolve(data);
+ func.apply(this, [...args, callback]);
+ });
+ }
+
+exports.zeroAddress = '0x0000000000000000000000000000000000000000';
+exports.zeroBytes32 = "0x0000000000000000000000000000000000000000000000000000000000000000";
+exports.timeUnits = {
+ seconds: 1,
+ minutes: 60,
+ hours: 60 * 60,
+ days: 24 * 60 * 60,
+ weeks: 7 * 24 * 60 * 60,
+ years: 365 * 24 * 60 * 60
+}
+
+exports.ensureException = function(error) {
+ assert(isException(error), error.toString());
+};
+
+function isException(error) {
+ let strError = error.toString();
+ return strError.includes('invalid opcode') || strError.includes('invalid JUMP') || strError.includes('revert');
+}
+
+exports.increaseTime = async (amount) => {
+ return new Promise(function(resolve, reject) {
+ web3.currentProvider.sendAsync(
+ {
+ jsonrpc: '2.0',
+ method: 'evm_increaseTime',
+ params: [+amount],
+ id: new Date().getSeconds()
+ },
+ (error) => {
+ if (error) {
+ console.log(error);
+ return reject(err);
+ }
+ web3.currentProvider.sendAsync(
+ {
+ jsonrpc: '2.0',
+ method: 'evm_mine',
+ params: [],
+ id: new Date().getSeconds()
+ }, (error) => {
+ if (error) {
+ console.log(error);
+ return reject(err);
+ }
+ resolve();
+ }
+ )
+ }
+ )
+ });
+}