Last active
April 8, 2019 18:38
-
-
Save MicrowaveDev/f1eae904483b52faf5346681c160fd37 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.5.2; | |
/** | |
* @title Roles | |
* @dev Library for managing addresses assigned to a Role. | |
*/ | |
library Roles { | |
struct Role { | |
mapping (address => bool) bearer; | |
} | |
/** | |
* @dev Give an account access to this role. | |
*/ | |
function add(Role storage role, address account) internal { | |
require(account != address(0)); | |
require(!has(role, account)); | |
role.bearer[account] = true; | |
} | |
/** | |
* @dev Remove an account's access to this role. | |
*/ | |
function remove(Role storage role, address account) internal { | |
require(account != address(0)); | |
require(has(role, account)); | |
role.bearer[account] = false; | |
} | |
/** | |
* @dev Check if an account has this role. | |
* @return bool | |
*/ | |
function has(Role storage role, address account) internal view returns (bool) { | |
require(account != address(0)); | |
return role.bearer[account]; | |
} | |
} | |
/** | |
* @title ERC20 interface | |
* @dev see https://eips.ethereum.org/EIPS/eip-20 | |
*/ | |
interface IERC20 { | |
function transfer(address to, uint256 value) external returns (bool); | |
function approve(address spender, uint256 value) external returns (bool); | |
function transferFrom(address from, address to, uint256 value) external returns (bool); | |
function totalSupply() external view returns (uint256); | |
function balanceOf(address who) external view returns (uint256); | |
function allowance(address owner, address spender) external view returns (uint256); | |
event Transfer(address indexed from, address indexed to, uint256 value); | |
event Approval(address indexed owner, address indexed spender, uint256 value); | |
} | |
/** | |
* @title SafeMath | |
* @dev Unsigned math operations with safety checks that revert on error. | |
*/ | |
library SafeMath { | |
/** | |
* @dev Multiplies two unsigned integers, reverts on overflow. | |
*/ | |
function mul(uint256 a, uint256 b) internal pure returns (uint256) { | |
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the | |
// benefit is lost if 'b' is also tested. | |
// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 | |
if (a == 0) { | |
return 0; | |
} | |
uint256 c = a * b; | |
require(c / a == b); | |
return c; | |
} | |
/** | |
* @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero. | |
*/ | |
function div(uint256 a, uint256 b) internal pure returns (uint256) { | |
// Solidity only automatically asserts when dividing by 0 | |
require(b > 0); | |
uint256 c = a / b; | |
// assert(a == b * c + a % b); // There is no case in which this doesn't hold | |
return c; | |
} | |
/** | |
* @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend). | |
*/ | |
function sub(uint256 a, uint256 b) internal pure returns (uint256) { | |
require(b <= a); | |
uint256 c = a - b; | |
return c; | |
} | |
/** | |
* @dev Adds two unsigned integers, reverts on overflow. | |
*/ | |
function add(uint256 a, uint256 b) internal pure returns (uint256) { | |
uint256 c = a + b; | |
require(c >= a); | |
return c; | |
} | |
/** | |
* @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo), | |
* reverts when dividing by zero. | |
*/ | |
function mod(uint256 a, uint256 b) internal pure returns (uint256) { | |
require(b != 0); | |
return a % b; | |
} | |
} | |
/** | |
* @title Standard ERC20 token | |
* | |
* @dev Implementation of the basic standard token. | |
* https://eips.ethereum.org/EIPS/eip-20 | |
* Originally based on code by FirstBlood: | |
* https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol | |
* | |
* This implementation emits additional Approval events, allowing applications to reconstruct the allowance status for | |
* all accounts just by listening to said events. Note that this isn't required by the specification, and other | |
* compliant implementations may not do it. | |
*/ | |
contract ERC20 is IERC20 { | |
using SafeMath for uint256; | |
mapping (address => uint256) private _balances; | |
mapping (address => mapping (address => uint256)) private _allowed; | |
uint256 private _totalSupply; | |
/** | |
* @dev Total number of tokens in existence. | |
*/ | |
function totalSupply() public view returns (uint256) { | |
return _totalSupply; | |
} | |
/** | |
* @dev Gets the balance of the specified address. | |
* @param owner The address to query the balance of. | |
* @return A uint256 representing the amount owned by the passed address. | |
*/ | |
function balanceOf(address owner) public view returns (uint256) { | |
return _balances[owner]; | |
} | |
/** | |
* @dev Function to check the amount of tokens that an owner allowed to a spender. | |
* @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 returns (uint256) { | |
return _allowed[owner][spender]; | |
} | |
/** | |
* @dev Transfer token to a specified address. | |
* @param to The address to transfer to. | |
* @param value The amount to be transferred. | |
*/ | |
function transfer(address to, uint256 value) public returns (bool) { | |
_transfer(msg.sender, to, value); | |
return true; | |
} | |
/** | |
* @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 | |
* @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) { | |
_approve(msg.sender, spender, value); | |
return true; | |
} | |
/** | |
* @dev Transfer tokens from one address to another. | |
* Note that while this function emits an Approval event, this is not required as per the specification, | |
* and other compliant implementations may not emit the event. | |
* @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) { | |
_transfer(from, to, value); | |
_approve(from, msg.sender, _allowed[from][msg.sender].sub(value)); | |
return true; | |
} | |
/** | |
* @dev Increase the amount of tokens that an owner allowed to a spender. | |
* approve should be called when _allowed[msg.sender][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 | |
* Emits an Approval event. | |
* @param spender The address which will spend the funds. | |
* @param addedValue The amount of tokens to increase the allowance by. | |
*/ | |
function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { | |
_approve(msg.sender, spender, _allowed[msg.sender][spender].add(addedValue)); | |
return true; | |
} | |
/** | |
* @dev Decrease the amount of tokens that an owner allowed to a spender. | |
* approve should be called when _allowed[msg.sender][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 | |
* Emits an Approval event. | |
* @param spender The address which will spend the funds. | |
* @param subtractedValue The amount of tokens to decrease the allowance by. | |
*/ | |
function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { | |
_approve(msg.sender, spender, _allowed[msg.sender][spender].sub(subtractedValue)); | |
return true; | |
} | |
/** | |
* @dev Transfer token for a specified addresses. | |
* @param from The address to transfer from. | |
* @param to The address to transfer to. | |
* @param value The amount to be transferred. | |
*/ | |
function _transfer(address from, address to, uint256 value) internal { | |
require(to != address(0)); | |
_balances[from] = _balances[from].sub(value); | |
_balances[to] = _balances[to].add(value); | |
emit Transfer(from, to, value); | |
} | |
/** | |
* @dev Internal function that mints an amount of the token and assigns it to | |
* an account. This encapsulates the modification of balances such that the | |
* proper events are emitted. | |
* @param account The account that will receive the created tokens. | |
* @param value The amount that will be created. | |
*/ | |
function _mint(address account, uint256 value) internal { | |
require(account != address(0)); | |
_totalSupply = _totalSupply.add(value); | |
_balances[account] = _balances[account].add(value); | |
emit Transfer(address(0), account, value); | |
} | |
/** | |
* @dev Internal function that burns an amount of the token of a given | |
* account. | |
* @param account The account whose tokens will be burnt. | |
* @param value The amount that will be burnt. | |
*/ | |
function _burn(address account, uint256 value) internal { | |
require(account != address(0)); | |
_totalSupply = _totalSupply.sub(value); | |
_balances[account] = _balances[account].sub(value); | |
emit Transfer(account, address(0), value); | |
} | |
/** | |
* @dev Approve an address to spend another addresses' tokens. | |
* @param owner The address that owns the tokens. | |
* @param spender The address that will spend the tokens. | |
* @param value The number of tokens that can be spent. | |
*/ | |
function _approve(address owner, address spender, uint256 value) internal { | |
require(spender != address(0)); | |
require(owner != address(0)); | |
_allowed[owner][spender] = value; | |
emit Approval(owner, spender, value); | |
} | |
/** | |
* @dev Internal function that burns an amount of the token of a given | |
* account, deducting from the sender's allowance for said account. Uses the | |
* internal burn function. | |
* Emits an Approval event (reflecting the reduced allowance). | |
* @param account The account whose tokens will be burnt. | |
* @param value The amount that will be burnt. | |
*/ | |
function _burnFrom(address account, uint256 value) internal { | |
_burn(account, value); | |
_approve(account, msg.sender, _allowed[account][msg.sender].sub(value)); | |
} | |
} | |
/** | |
* Utility library of inline functions on addresses | |
*/ | |
library Address { | |
/** | |
* Returns whether the target address is a contract | |
* @dev This function will return false if invoked during the constructor of a contract, | |
* as the code is not actually created until after the constructor finishes. | |
* @param account address of the account to check | |
* @return whether the target address is a contract | |
*/ | |
function isContract(address account) internal view returns (bool) { | |
uint256 size; | |
// XXX Currently there is no better way to check if there is a contract in an address | |
// than to check the size of the code at that address. | |
// See https://ethereum.stackexchange.com/a/14016/36603 | |
// for more details about how this works. | |
// TODO Check this again before the Serenity release, because all addresses will be | |
// contracts then. | |
// solhint-disable-next-line no-inline-assembly | |
assembly { size := extcodesize(account) } | |
return size > 0; | |
} | |
} | |
/** | |
* @title SafeERC20 | |
* @dev Wrappers around ERC20 operations that throw on failure (when the token | |
* contract returns false). Tokens that return no value (and instead revert or | |
* throw on failure) are also supported, non-reverting calls are assumed to be | |
* successful. | |
* To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract, | |
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc. | |
*/ | |
library SafeERC20 { | |
using SafeMath for uint256; | |
using Address for address; | |
function safeTransfer(IERC20 token, address to, uint256 value) internal { | |
callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); | |
} | |
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { | |
callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); | |
} | |
function safeApprove(IERC20 token, address spender, uint256 value) internal { | |
// safeApprove should only be called when setting an initial allowance, | |
// or when resetting it to zero. To increase and decrease it, use | |
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance' | |
require((value == 0) || (token.allowance(address(this), spender) == 0)); | |
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); | |
} | |
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { | |
uint256 newAllowance = token.allowance(address(this), spender).add(value); | |
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); | |
} | |
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { | |
uint256 newAllowance = token.allowance(address(this), spender).sub(value); | |
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); | |
} | |
/** | |
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement | |
* on the return value: the return value is optional (but if data is returned, it must not be false). | |
* @param token The token targeted by the call. | |
* @param data The call data (encoded using abi.encode or one of its variants). | |
*/ | |
function callOptionalReturn(IERC20 token, bytes memory data) private { | |
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since | |
// we're implementing it ourselves. | |
// A Solidity high level call has three parts: | |
// 1. The target address is checked to verify it contains contract code | |
// 2. The call itself is made, and success asserted | |
// 3. The return value is decoded, which in turn checks the size of the returned data. | |
require(address(token).isContract()); | |
// solhint-disable-next-line avoid-low-level-calls | |
(bool success, bytes memory returndata) = address(token).call(data); | |
require(success); | |
if (returndata.length > 0) { // Return data is optional | |
require(abi.decode(returndata, (bool))); | |
} | |
} | |
} | |
/** | |
* @title Helps contracts guard against reentrancy attacks. | |
* @author Remco Bloemen <remco@2π.com>, Eenae <[email protected]> | |
* @dev If you mark a function `nonReentrant`, you should also | |
* mark it `external`. | |
*/ | |
contract ReentrancyGuard { | |
/// @dev counter to allow mutex lock with only one SSTORE operation | |
uint256 private _guardCounter; | |
constructor () internal { | |
// The counter starts at one to prevent changing it from zero to a non-zero | |
// value, which is a more expensive operation. | |
_guardCounter = 1; | |
} | |
/** | |
* @dev Prevents a contract from calling itself, directly or indirectly. | |
* Calling a `nonReentrant` function from another `nonReentrant` | |
* function is not supported. It is possible to prevent this from happening | |
* by making the `nonReentrant` function external, and make it call a | |
* `private` function that does the actual work. | |
*/ | |
modifier nonReentrant() { | |
_guardCounter += 1; | |
uint256 localCounter = _guardCounter; | |
_; | |
require(localCounter == _guardCounter); | |
} | |
} | |
contract Factory { | |
/* | |
* Events | |
*/ | |
event ContractInstantiation(address sender, address instantiation); | |
/* | |
* Storage | |
*/ | |
mapping(address => bool) public isInstantiation; | |
mapping(address => address[]) public instantiations; | |
/* | |
* Public functions | |
*/ | |
/// @dev Returns number of instantiations by creator. | |
/// @param creator Contract creator. | |
/// @return Returns number of instantiations by creator. | |
function getInstantiationCount(address creator) public view returns (uint) { | |
return instantiations[creator].length; | |
} | |
/* | |
* Internal functions | |
*/ | |
/// @dev Registers contract in factory registry. | |
/// @param instantiation Address of contract instantiation. | |
function register(address instantiation) | |
internal | |
{ | |
isInstantiation[instantiation] = true; | |
instantiations[msg.sender].push(instantiation); | |
emit ContractInstantiation(msg.sender, instantiation); | |
} | |
} | |
contract AirdropAdminRole { | |
using Roles for Roles.Role; | |
event AirdropAdminAdded(address indexed account); | |
event AirdropAdminRemoved(address indexed account); | |
Roles.Role private _airdropAdmins; | |
constructor () internal { | |
_addAirdropAdmin(msg.sender); | |
} | |
modifier onlyAirdropAdmin() { | |
require(isAirdropAdmin(msg.sender)); | |
_; | |
} | |
function isAirdropAdmin(address account) public view returns (bool) { | |
return _airdropAdmins.has(account); | |
} | |
function addAirdropAdmin(address account) public onlyAirdropAdmin { | |
_addAirdropAdmin(account); | |
} | |
function renounceAirdropAdmin() public { | |
_removeAirdropAdmin(msg.sender); | |
} | |
function _addAirdropAdmin(address account) internal { | |
_airdropAdmins.add(account); | |
emit AirdropAdminAdded(account); | |
} | |
function _removeAirdropAdmin(address account) internal { | |
_airdropAdmins.remove(account); | |
emit AirdropAdminRemoved(account); | |
} | |
} | |
contract Airdrop is ReentrancyGuard, AirdropAdminRole { | |
using SafeERC20 for IERC20; | |
function multiValueSend(address _tokenAddr, address[] calldata _to, uint256[] calldata _value) external nonReentrant onlyAirdropAdmin returns (bool) { | |
assert(_to.length == _value.length); | |
assert(_to.length <= 250); | |
// loop through to addresses and send value | |
for (uint8 i = 0; i < _to.length; i++) { | |
IERC20(_tokenAddr).safeTransfer(_to[i], _value[i]); | |
} | |
return true; | |
} | |
function singleValueSend(address _tokenAddr, address[] calldata _to, uint256 _value) external nonReentrant onlyAirdropAdmin returns (bool) { | |
assert(_to.length <= 250); | |
// loop through to addresses and send value | |
for (uint8 i = 0; i < _to.length; i++) { | |
IERC20(_tokenAddr).safeTransfer(_to[i], _value); | |
} | |
return true; | |
} | |
} | |
contract AirdropFactory is Factory { | |
function create() public returns (address) { | |
Airdrop c = new Airdrop(); | |
c.addAirdropAdmin(msg.sender); | |
c.renounceAirdropAdmin(); | |
register(address(c)); | |
return address(c); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.5.2; | |
/** | |
* @title Roles | |
* @dev Library for managing addresses assigned to a Role. | |
*/ | |
library Roles { | |
struct Role { | |
mapping (address => bool) bearer; | |
} | |
/** | |
* @dev Give an account access to this role. | |
*/ | |
function add(Role storage role, address account) internal { | |
require(account != address(0)); | |
require(!has(role, account)); | |
role.bearer[account] = true; | |
} | |
/** | |
* @dev Remove an account's access to this role. | |
*/ | |
function remove(Role storage role, address account) internal { | |
require(account != address(0)); | |
require(has(role, account)); | |
role.bearer[account] = false; | |
} | |
/** | |
* @dev Check if an account has this role. | |
* @return bool | |
*/ | |
function has(Role storage role, address account) internal view returns (bool) { | |
require(account != address(0)); | |
return role.bearer[account]; | |
} | |
} | |
/** | |
* @title ERC20 interface | |
* @dev see https://eips.ethereum.org/EIPS/eip-20 | |
*/ | |
interface IERC20 { | |
function transfer(address to, uint256 value) external returns (bool); | |
function approve(address spender, uint256 value) external returns (bool); | |
function transferFrom(address from, address to, uint256 value) external returns (bool); | |
function totalSupply() external view returns (uint256); | |
function balanceOf(address who) external view returns (uint256); | |
function allowance(address owner, address spender) external view returns (uint256); | |
event Transfer(address indexed from, address indexed to, uint256 value); | |
event Approval(address indexed owner, address indexed spender, uint256 value); | |
} | |
/** | |
* @title SafeMath | |
* @dev Unsigned math operations with safety checks that revert on error. | |
*/ | |
library SafeMath { | |
/** | |
* @dev Multiplies two unsigned integers, reverts on overflow. | |
*/ | |
function mul(uint256 a, uint256 b) internal pure returns (uint256) { | |
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the | |
// benefit is lost if 'b' is also tested. | |
// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 | |
if (a == 0) { | |
return 0; | |
} | |
uint256 c = a * b; | |
require(c / a == b); | |
return c; | |
} | |
/** | |
* @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero. | |
*/ | |
function div(uint256 a, uint256 b) internal pure returns (uint256) { | |
// Solidity only automatically asserts when dividing by 0 | |
require(b > 0); | |
uint256 c = a / b; | |
// assert(a == b * c + a % b); // There is no case in which this doesn't hold | |
return c; | |
} | |
/** | |
* @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend). | |
*/ | |
function sub(uint256 a, uint256 b) internal pure returns (uint256) { | |
require(b <= a); | |
uint256 c = a - b; | |
return c; | |
} | |
/** | |
* @dev Adds two unsigned integers, reverts on overflow. | |
*/ | |
function add(uint256 a, uint256 b) internal pure returns (uint256) { | |
uint256 c = a + b; | |
require(c >= a); | |
return c; | |
} | |
/** | |
* @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo), | |
* reverts when dividing by zero. | |
*/ | |
function mod(uint256 a, uint256 b) internal pure returns (uint256) { | |
require(b != 0); | |
return a % b; | |
} | |
} | |
/** | |
* @title Standard ERC20 token | |
* | |
* @dev Implementation of the basic standard token. | |
* https://eips.ethereum.org/EIPS/eip-20 | |
* Originally based on code by FirstBlood: | |
* https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol | |
* | |
* This implementation emits additional Approval events, allowing applications to reconstruct the allowance status for | |
* all accounts just by listening to said events. Note that this isn't required by the specification, and other | |
* compliant implementations may not do it. | |
*/ | |
contract ERC20 is IERC20 { | |
using SafeMath for uint256; | |
mapping (address => uint256) private _balances; | |
mapping (address => mapping (address => uint256)) private _allowed; | |
uint256 private _totalSupply; | |
/** | |
* @dev Total number of tokens in existence. | |
*/ | |
function totalSupply() public view returns (uint256) { | |
return _totalSupply; | |
} | |
/** | |
* @dev Gets the balance of the specified address. | |
* @param owner The address to query the balance of. | |
* @return A uint256 representing the amount owned by the passed address. | |
*/ | |
function balanceOf(address owner) public view returns (uint256) { | |
return _balances[owner]; | |
} | |
/** | |
* @dev Function to check the amount of tokens that an owner allowed to a spender. | |
* @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 returns (uint256) { | |
return _allowed[owner][spender]; | |
} | |
/** | |
* @dev Transfer token to a specified address. | |
* @param to The address to transfer to. | |
* @param value The amount to be transferred. | |
*/ | |
function transfer(address to, uint256 value) public returns (bool) { | |
_transfer(msg.sender, to, value); | |
return true; | |
} | |
/** | |
* @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 | |
* @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) { | |
_approve(msg.sender, spender, value); | |
return true; | |
} | |
/** | |
* @dev Transfer tokens from one address to another. | |
* Note that while this function emits an Approval event, this is not required as per the specification, | |
* and other compliant implementations may not emit the event. | |
* @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) { | |
_transfer(from, to, value); | |
_approve(from, msg.sender, _allowed[from][msg.sender].sub(value)); | |
return true; | |
} | |
/** | |
* @dev Increase the amount of tokens that an owner allowed to a spender. | |
* approve should be called when _allowed[msg.sender][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 | |
* Emits an Approval event. | |
* @param spender The address which will spend the funds. | |
* @param addedValue The amount of tokens to increase the allowance by. | |
*/ | |
function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { | |
_approve(msg.sender, spender, _allowed[msg.sender][spender].add(addedValue)); | |
return true; | |
} | |
/** | |
* @dev Decrease the amount of tokens that an owner allowed to a spender. | |
* approve should be called when _allowed[msg.sender][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 | |
* Emits an Approval event. | |
* @param spender The address which will spend the funds. | |
* @param subtractedValue The amount of tokens to decrease the allowance by. | |
*/ | |
function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { | |
_approve(msg.sender, spender, _allowed[msg.sender][spender].sub(subtractedValue)); | |
return true; | |
} | |
/** | |
* @dev Transfer token for a specified addresses. | |
* @param from The address to transfer from. | |
* @param to The address to transfer to. | |
* @param value The amount to be transferred. | |
*/ | |
function _transfer(address from, address to, uint256 value) internal { | |
require(to != address(0)); | |
_balances[from] = _balances[from].sub(value); | |
_balances[to] = _balances[to].add(value); | |
emit Transfer(from, to, value); | |
} | |
/** | |
* @dev Internal function that mints an amount of the token and assigns it to | |
* an account. This encapsulates the modification of balances such that the | |
* proper events are emitted. | |
* @param account The account that will receive the created tokens. | |
* @param value The amount that will be created. | |
*/ | |
function _mint(address account, uint256 value) internal { | |
require(account != address(0)); | |
_totalSupply = _totalSupply.add(value); | |
_balances[account] = _balances[account].add(value); | |
emit Transfer(address(0), account, value); | |
} | |
/** | |
* @dev Internal function that burns an amount of the token of a given | |
* account. | |
* @param account The account whose tokens will be burnt. | |
* @param value The amount that will be burnt. | |
*/ | |
function _burn(address account, uint256 value) internal { | |
require(account != address(0)); | |
_totalSupply = _totalSupply.sub(value); | |
_balances[account] = _balances[account].sub(value); | |
emit Transfer(account, address(0), value); | |
} | |
/** | |
* @dev Approve an address to spend another addresses' tokens. | |
* @param owner The address that owns the tokens. | |
* @param spender The address that will spend the tokens. | |
* @param value The number of tokens that can be spent. | |
*/ | |
function _approve(address owner, address spender, uint256 value) internal { | |
require(spender != address(0)); | |
require(owner != address(0)); | |
_allowed[owner][spender] = value; | |
emit Approval(owner, spender, value); | |
} | |
/** | |
* @dev Internal function that burns an amount of the token of a given | |
* account, deducting from the sender's allowance for said account. Uses the | |
* internal burn function. | |
* Emits an Approval event (reflecting the reduced allowance). | |
* @param account The account whose tokens will be burnt. | |
* @param value The amount that will be burnt. | |
*/ | |
function _burnFrom(address account, uint256 value) internal { | |
_burn(account, value); | |
_approve(account, msg.sender, _allowed[account][msg.sender].sub(value)); | |
} | |
} | |
/** | |
* Utility library of inline functions on addresses | |
*/ | |
library Address { | |
/** | |
* Returns whether the target address is a contract | |
* @dev This function will return false if invoked during the constructor of a contract, | |
* as the code is not actually created until after the constructor finishes. | |
* @param account address of the account to check | |
* @return whether the target address is a contract | |
*/ | |
function isContract(address account) internal view returns (bool) { | |
uint256 size; | |
// XXX Currently there is no better way to check if there is a contract in an address | |
// than to check the size of the code at that address. | |
// See https://ethereum.stackexchange.com/a/14016/36603 | |
// for more details about how this works. | |
// TODO Check this again before the Serenity release, because all addresses will be | |
// contracts then. | |
// solhint-disable-next-line no-inline-assembly | |
assembly { size := extcodesize(account) } | |
return size > 0; | |
} | |
} | |
/** | |
* @title SafeERC20 | |
* @dev Wrappers around ERC20 operations that throw on failure (when the token | |
* contract returns false). Tokens that return no value (and instead revert or | |
* throw on failure) are also supported, non-reverting calls are assumed to be | |
* successful. | |
* To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract, | |
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc. | |
*/ | |
library SafeERC20 { | |
using SafeMath for uint256; | |
using Address for address; | |
function safeTransfer(IERC20 token, address to, uint256 value) internal { | |
callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); | |
} | |
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { | |
callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); | |
} | |
function safeApprove(IERC20 token, address spender, uint256 value) internal { | |
// safeApprove should only be called when setting an initial allowance, | |
// or when resetting it to zero. To increase and decrease it, use | |
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance' | |
require((value == 0) || (token.allowance(address(this), spender) == 0)); | |
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); | |
} | |
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { | |
uint256 newAllowance = token.allowance(address(this), spender).add(value); | |
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); | |
} | |
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { | |
uint256 newAllowance = token.allowance(address(this), spender).sub(value); | |
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); | |
} | |
/** | |
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement | |
* on the return value: the return value is optional (but if data is returned, it must not be false). | |
* @param token The token targeted by the call. | |
* @param data The call data (encoded using abi.encode or one of its variants). | |
*/ | |
function callOptionalReturn(IERC20 token, bytes memory data) private { | |
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since | |
// we're implementing it ourselves. | |
// A Solidity high level call has three parts: | |
// 1. The target address is checked to verify it contains contract code | |
// 2. The call itself is made, and success asserted | |
// 3. The return value is decoded, which in turn checks the size of the returned data. | |
require(address(token).isContract()); | |
// solhint-disable-next-line avoid-low-level-calls | |
(bool success, bytes memory returndata) = address(token).call(data); | |
require(success); | |
if (returndata.length > 0) { // Return data is optional | |
require(abi.decode(returndata, (bool))); | |
} | |
} | |
} | |
/** | |
* @title Helps contracts guard against reentrancy attacks. | |
* @author Remco Bloemen <remco@2π.com>, Eenae <[email protected]> | |
* @dev If you mark a function `nonReentrant`, you should also | |
* mark it `external`. | |
*/ | |
contract ReentrancyGuard { | |
/// @dev counter to allow mutex lock with only one SSTORE operation | |
uint256 private _guardCounter; | |
constructor () internal { | |
// The counter starts at one to prevent changing it from zero to a non-zero | |
// value, which is a more expensive operation. | |
_guardCounter = 1; | |
} | |
/** | |
* @dev Prevents a contract from calling itself, directly or indirectly. | |
* Calling a `nonReentrant` function from another `nonReentrant` | |
* function is not supported. It is possible to prevent this from happening | |
* by making the `nonReentrant` function external, and make it call a | |
* `private` function that does the actual work. | |
*/ | |
modifier nonReentrant() { | |
_guardCounter += 1; | |
uint256 localCounter = _guardCounter; | |
_; | |
require(localCounter == _guardCounter); | |
} | |
} | |
contract Factory { | |
/* | |
* Events | |
*/ | |
event ContractInstantiation(address sender, address instantiation); | |
/* | |
* Storage | |
*/ | |
mapping(address => bool) public isInstantiation; | |
mapping(address => address[]) public instantiations; | |
/* | |
* Public functions | |
*/ | |
/// @dev Returns number of instantiations by creator. | |
/// @param creator Contract creator. | |
/// @return Returns number of instantiations by creator. | |
function getInstantiationCount(address creator) public view returns (uint) { | |
return instantiations[creator].length; | |
} | |
/* | |
* Internal functions | |
*/ | |
/// @dev Registers contract in factory registry. | |
/// @param instantiation Address of contract instantiation. | |
function register(address instantiation) | |
internal | |
{ | |
isInstantiation[instantiation] = true; | |
instantiations[msg.sender].push(instantiation); | |
emit ContractInstantiation(msg.sender, instantiation); | |
} | |
} | |
/** | |
* @title Crowdsale | |
* @dev Crowdsale is a base contract for managing a token crowdsale, | |
* allowing investors to purchase tokens with ether. This contract implements | |
* such functionality in its most fundamental form and can be extended to provide additional | |
* functionality and/or custom behavior. | |
* The external interface represents the basic interface for purchasing tokens, and conforms | |
* the base architecture for crowdsales. It is *not* intended to be modified / overridden. | |
* The internal interface conforms the extensible and modifiable surface of crowdsales. Override | |
* the methods to add functionality. Consider using 'super' where appropriate to concatenate | |
* behavior. | |
*/ | |
contract Crowdsale is ReentrancyGuard { | |
using SafeMath for uint256; | |
using SafeERC20 for IERC20; | |
// The token being sold | |
IERC20 private _token; | |
// Address where funds are collected | |
address payable private _wallet; | |
// How many token units a buyer gets per wei. | |
// The rate is the conversion between wei and the smallest and indivisible token unit. | |
// So, if you are using a rate of 1 with a ERC20Detailed token with 3 decimals called TOK | |
// 1 wei will give you 1 unit, or 0.001 TOK. | |
uint256 private _rate; | |
// Amount of wei raised | |
uint256 private _weiRaised; | |
/** | |
* Event for token purchase logging | |
* @param purchaser who paid for the tokens | |
* @param beneficiary who got the tokens | |
* @param value weis paid for purchase | |
* @param amount amount of tokens purchased | |
*/ | |
event TokensPurchased(address indexed purchaser, address indexed beneficiary, uint256 value, uint256 amount); | |
/** | |
* @param rate Number of token units a buyer gets per wei | |
* @dev The rate is the conversion between wei and the smallest and indivisible | |
* token unit. So, if you are using a rate of 1 with a ERC20Detailed token | |
* with 3 decimals called TOK, 1 wei will give you 1 unit, or 0.001 TOK. | |
* @param wallet Address where collected funds will be forwarded to | |
* @param token Address of the token being sold | |
*/ | |
constructor (uint256 rate, address payable wallet, IERC20 token) public { | |
require(rate > 0); | |
require(wallet != address(0)); | |
require(address(token) != address(0)); | |
_rate = rate; | |
_wallet = wallet; | |
_token = token; | |
} | |
/** | |
* @dev fallback function ***DO NOT OVERRIDE*** | |
* Note that other contracts will transfer funds with a base gas stipend | |
* of 2300, which is not enough to call buyTokens. Consider calling | |
* buyTokens directly when purchasing tokens from a contract. | |
*/ | |
function () external payable { | |
buyTokens(msg.sender); | |
} | |
/** | |
* @return the token being sold. | |
*/ | |
function token() public view returns (IERC20) { | |
return _token; | |
} | |
/** | |
* @return the address where funds are collected. | |
*/ | |
function wallet() public view returns (address payable) { | |
return _wallet; | |
} | |
/** | |
* @return the number of token units a buyer gets per wei. | |
*/ | |
function rate() public view returns (uint256) { | |
return _rate; | |
} | |
/** | |
* @return the amount of wei raised. | |
*/ | |
function weiRaised() public view returns (uint256) { | |
return _weiRaised; | |
} | |
/** | |
* @dev low level token purchase ***DO NOT OVERRIDE*** | |
* This function has a non-reentrancy guard, so it shouldn't be called by | |
* another `nonReentrant` function. | |
* @param beneficiary Recipient of the token purchase | |
*/ | |
function buyTokens(address beneficiary) public nonReentrant payable { | |
uint256 weiAmount = msg.value; | |
_preValidatePurchase(beneficiary, weiAmount); | |
// calculate token amount to be created | |
uint256 tokens = _getTokenAmount(weiAmount); | |
// update state | |
_weiRaised = _weiRaised.add(weiAmount); | |
_processPurchase(beneficiary, tokens); | |
emit TokensPurchased(msg.sender, beneficiary, weiAmount, tokens); | |
_updatePurchasingState(beneficiary, weiAmount); | |
_forwardFunds(); | |
_postValidatePurchase(beneficiary, weiAmount); | |
} | |
/** | |
* @dev Validation of an incoming purchase. Use require statements to revert state when conditions are not met. | |
* Use `super` in contracts that inherit from Crowdsale to extend their validations. | |
* Example from CappedCrowdsale.sol's _preValidatePurchase method: | |
* super._preValidatePurchase(beneficiary, weiAmount); | |
* require(weiRaised().add(weiAmount) <= cap); | |
* @param beneficiary Address performing the token purchase | |
* @param weiAmount Value in wei involved in the purchase | |
*/ | |
function _preValidatePurchase(address beneficiary, uint256 weiAmount) internal view { | |
require(beneficiary != address(0)); | |
require(weiAmount != 0); | |
} | |
/** | |
* @dev Validation of an executed purchase. Observe state and use revert statements to undo rollback when valid | |
* conditions are not met. | |
* @param beneficiary Address performing the token purchase | |
* @param weiAmount Value in wei involved in the purchase | |
*/ | |
function _postValidatePurchase(address beneficiary, uint256 weiAmount) internal view { | |
// solhint-disable-previous-line no-empty-blocks | |
} | |
/** | |
* @dev Source of tokens. Override this method to modify the way in which the crowdsale ultimately gets and sends | |
* its tokens. | |
* @param beneficiary Address performing the token purchase | |
* @param tokenAmount Number of tokens to be emitted | |
*/ | |
function _deliverTokens(address beneficiary, uint256 tokenAmount) internal { | |
_token.safeTransfer(beneficiary, tokenAmount); | |
} | |
/** | |
* @dev Executed when a purchase has been validated and is ready to be executed. Doesn't necessarily emit/send | |
* tokens. | |
* @param beneficiary Address receiving the tokens | |
* @param tokenAmount Number of tokens to be purchased | |
*/ | |
function _processPurchase(address beneficiary, uint256 tokenAmount) internal { | |
_deliverTokens(beneficiary, tokenAmount); | |
} | |
/** | |
* @dev Override for extensions that require an internal state to check for validity (current user contributions, | |
* etc.) | |
* @param beneficiary Address receiving the tokens | |
* @param weiAmount Value in wei involved in the purchase | |
*/ | |
function _updatePurchasingState(address beneficiary, uint256 weiAmount) internal { | |
// solhint-disable-previous-line no-empty-blocks | |
} | |
/** | |
* @dev Override to extend the way in which ether is converted to tokens. | |
* @param weiAmount Value in wei to be converted into tokens | |
* @return Number of tokens that can be purchased with the specified _weiAmount | |
*/ | |
function _getTokenAmount(uint256 weiAmount) internal view returns (uint256) { | |
return weiAmount.mul(_rate); | |
} | |
/** | |
* @dev Determines how ETH is stored/forwarded on purchases. | |
*/ | |
function _forwardFunds() internal { | |
_wallet.transfer(msg.value); | |
} | |
} | |
/** | |
* @title WhitelistAdminRole | |
* @dev WhitelistAdmins are responsible for assigning and removing Whitelisted accounts. | |
*/ | |
contract WhitelistAdminRole { | |
using Roles for Roles.Role; | |
event WhitelistAdminAdded(address indexed account); | |
event WhitelistAdminRemoved(address indexed account); | |
Roles.Role private _whitelistAdmins; | |
constructor () internal { | |
_addWhitelistAdmin(msg.sender); | |
} | |
modifier onlyWhitelistAdmin() { | |
require(isWhitelistAdmin(msg.sender)); | |
_; | |
} | |
function isWhitelistAdmin(address account) public view returns (bool) { | |
return _whitelistAdmins.has(account); | |
} | |
function addWhitelistAdmin(address account) public onlyWhitelistAdmin { | |
_addWhitelistAdmin(account); | |
} | |
function renounceWhitelistAdmin() public { | |
_removeWhitelistAdmin(msg.sender); | |
} | |
function _addWhitelistAdmin(address account) internal { | |
_whitelistAdmins.add(account); | |
emit WhitelistAdminAdded(account); | |
} | |
function _removeWhitelistAdmin(address account) internal { | |
_whitelistAdmins.remove(account); | |
emit WhitelistAdminRemoved(account); | |
} | |
} | |
/** | |
* @title WhitelistedRole | |
* @dev Whitelisted accounts have been approved by a WhitelistAdmin to perform certain actions (e.g. participate in a | |
* crowdsale). This role is special in that the only accounts that can add it are WhitelistAdmins (who can also remove | |
* it), and not Whitelisteds themselves. | |
*/ | |
contract WhitelistedRole is WhitelistAdminRole { | |
using Roles for Roles.Role; | |
event WhitelistedAdded(address indexed account); | |
event WhitelistedRemoved(address indexed account); | |
Roles.Role private _whitelisteds; | |
modifier onlyWhitelisted() { | |
require(isWhitelisted(msg.sender)); | |
_; | |
} | |
function isWhitelisted(address account) public view returns (bool) { | |
return _whitelisteds.has(account); | |
} | |
function addWhitelisted(address account) public onlyWhitelistAdmin { | |
_addWhitelisted(account); | |
} | |
function removeWhitelisted(address account) public onlyWhitelistAdmin { | |
_removeWhitelisted(account); | |
} | |
function renounceWhitelisted() public { | |
_removeWhitelisted(msg.sender); | |
} | |
function _addWhitelisted(address account) internal { | |
_whitelisteds.add(account); | |
emit WhitelistedAdded(account); | |
} | |
function _removeWhitelisted(address account) internal { | |
_whitelisteds.remove(account); | |
emit WhitelistedRemoved(account); | |
} | |
} | |
/** | |
* @title WhitelistCrowdsale | |
* @dev Crowdsale in which only whitelisted users can contribute. | |
*/ | |
contract WhitelistCrowdsale is WhitelistedRole, Crowdsale { | |
constructor (uint256 rate, address payable wallet, IERC20 token) public Crowdsale(rate, wallet, token) { } | |
/** | |
* @dev Extend parent behavior requiring beneficiary to be whitelisted. Note that no | |
* restriction is imposed on the account sending the transaction. | |
* @param _beneficiary Token beneficiary | |
* @param _weiAmount Amount of wei contributed | |
*/ | |
function _preValidatePurchase(address _beneficiary, uint256 _weiAmount) internal view { | |
require(isWhitelisted(_beneficiary)); | |
super._preValidatePurchase(_beneficiary, _weiAmount); | |
} | |
} | |
contract CrowdsaleFactory is Factory { | |
function create(uint256 rate, address payable wallet, IERC20 token) public returns (address) { | |
Crowdsale c = new Crowdsale(rate, wallet, token); | |
register(address(c)); | |
return address(c); | |
} | |
} | |
contract WhitelistedCrowdsaleFactory is Factory { | |
function create(uint256 rate, address payable wallet, IERC20 token) public returns (address) { | |
WhitelistCrowdsale c = new WhitelistCrowdsale(rate, wallet, token); | |
c.addWhitelistAdmin(msg.sender); | |
c.renounceWhitelistAdmin(); | |
register(address(c)); | |
return address(c); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.5.2; | |
/** | |
* @title Roles | |
* @dev Library for managing addresses assigned to a Role. | |
*/ | |
library Roles { | |
struct Role { | |
mapping (address => bool) bearer; | |
} | |
/** | |
* @dev Give an account access to this role. | |
*/ | |
function add(Role storage role, address account) internal { | |
require(account != address(0)); | |
require(!has(role, account)); | |
role.bearer[account] = true; | |
} | |
/** | |
* @dev Remove an account's access to this role. | |
*/ | |
function remove(Role storage role, address account) internal { | |
require(account != address(0)); | |
require(has(role, account)); | |
role.bearer[account] = false; | |
} | |
/** | |
* @dev Check if an account has this role. | |
* @return bool | |
*/ | |
function has(Role storage role, address account) internal view returns (bool) { | |
require(account != address(0)); | |
return role.bearer[account]; | |
} | |
} | |
/** | |
* @title ERC20 interface | |
* @dev see https://eips.ethereum.org/EIPS/eip-20 | |
*/ | |
interface IERC20 { | |
function transfer(address to, uint256 value) external returns (bool); | |
function approve(address spender, uint256 value) external returns (bool); | |
function transferFrom(address from, address to, uint256 value) external returns (bool); | |
function totalSupply() external view returns (uint256); | |
function balanceOf(address who) external view returns (uint256); | |
function allowance(address owner, address spender) external view returns (uint256); | |
event Transfer(address indexed from, address indexed to, uint256 value); | |
event Approval(address indexed owner, address indexed spender, uint256 value); | |
} | |
/** | |
* @title SafeMath | |
* @dev Unsigned math operations with safety checks that revert on error. | |
*/ | |
library SafeMath { | |
/** | |
* @dev Multiplies two unsigned integers, reverts on overflow. | |
*/ | |
function mul(uint256 a, uint256 b) internal pure returns (uint256) { | |
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the | |
// benefit is lost if 'b' is also tested. | |
// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 | |
if (a == 0) { | |
return 0; | |
} | |
uint256 c = a * b; | |
require(c / a == b); | |
return c; | |
} | |
/** | |
* @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero. | |
*/ | |
function div(uint256 a, uint256 b) internal pure returns (uint256) { | |
// Solidity only automatically asserts when dividing by 0 | |
require(b > 0); | |
uint256 c = a / b; | |
// assert(a == b * c + a % b); // There is no case in which this doesn't hold | |
return c; | |
} | |
/** | |
* @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend). | |
*/ | |
function sub(uint256 a, uint256 b) internal pure returns (uint256) { | |
require(b <= a); | |
uint256 c = a - b; | |
return c; | |
} | |
/** | |
* @dev Adds two unsigned integers, reverts on overflow. | |
*/ | |
function add(uint256 a, uint256 b) internal pure returns (uint256) { | |
uint256 c = a + b; | |
require(c >= a); | |
return c; | |
} | |
/** | |
* @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo), | |
* reverts when dividing by zero. | |
*/ | |
function mod(uint256 a, uint256 b) internal pure returns (uint256) { | |
require(b != 0); | |
return a % b; | |
} | |
} | |
/** | |
* @title Standard ERC20 token | |
* | |
* @dev Implementation of the basic standard token. | |
* https://eips.ethereum.org/EIPS/eip-20 | |
* Originally based on code by FirstBlood: | |
* https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol | |
* | |
* This implementation emits additional Approval events, allowing applications to reconstruct the allowance status for | |
* all accounts just by listening to said events. Note that this isn't required by the specification, and other | |
* compliant implementations may not do it. | |
*/ | |
contract ERC20 is IERC20 { | |
using SafeMath for uint256; | |
mapping (address => uint256) private _balances; | |
mapping (address => mapping (address => uint256)) private _allowed; | |
uint256 private _totalSupply; | |
/** | |
* @dev Total number of tokens in existence. | |
*/ | |
function totalSupply() public view returns (uint256) { | |
return _totalSupply; | |
} | |
/** | |
* @dev Gets the balance of the specified address. | |
* @param owner The address to query the balance of. | |
* @return A uint256 representing the amount owned by the passed address. | |
*/ | |
function balanceOf(address owner) public view returns (uint256) { | |
return _balances[owner]; | |
} | |
/** | |
* @dev Function to check the amount of tokens that an owner allowed to a spender. | |
* @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 returns (uint256) { | |
return _allowed[owner][spender]; | |
} | |
/** | |
* @dev Transfer token to a specified address. | |
* @param to The address to transfer to. | |
* @param value The amount to be transferred. | |
*/ | |
function transfer(address to, uint256 value) public returns (bool) { | |
_transfer(msg.sender, to, value); | |
return true; | |
} | |
/** | |
* @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 | |
* @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) { | |
_approve(msg.sender, spender, value); | |
return true; | |
} | |
/** | |
* @dev Transfer tokens from one address to another. | |
* Note that while this function emits an Approval event, this is not required as per the specification, | |
* and other compliant implementations may not emit the event. | |
* @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) { | |
_transfer(from, to, value); | |
_approve(from, msg.sender, _allowed[from][msg.sender].sub(value)); | |
return true; | |
} | |
/** | |
* @dev Increase the amount of tokens that an owner allowed to a spender. | |
* approve should be called when _allowed[msg.sender][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 | |
* Emits an Approval event. | |
* @param spender The address which will spend the funds. | |
* @param addedValue The amount of tokens to increase the allowance by. | |
*/ | |
function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { | |
_approve(msg.sender, spender, _allowed[msg.sender][spender].add(addedValue)); | |
return true; | |
} | |
/** | |
* @dev Decrease the amount of tokens that an owner allowed to a spender. | |
* approve should be called when _allowed[msg.sender][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 | |
* Emits an Approval event. | |
* @param spender The address which will spend the funds. | |
* @param subtractedValue The amount of tokens to decrease the allowance by. | |
*/ | |
function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { | |
_approve(msg.sender, spender, _allowed[msg.sender][spender].sub(subtractedValue)); | |
return true; | |
} | |
/** | |
* @dev Transfer token for a specified addresses. | |
* @param from The address to transfer from. | |
* @param to The address to transfer to. | |
* @param value The amount to be transferred. | |
*/ | |
function _transfer(address from, address to, uint256 value) internal { | |
require(to != address(0)); | |
_balances[from] = _balances[from].sub(value); | |
_balances[to] = _balances[to].add(value); | |
emit Transfer(from, to, value); | |
} | |
/** | |
* @dev Internal function that mints an amount of the token and assigns it to | |
* an account. This encapsulates the modification of balances such that the | |
* proper events are emitted. | |
* @param account The account that will receive the created tokens. | |
* @param value The amount that will be created. | |
*/ | |
function _mint(address account, uint256 value) internal { | |
require(account != address(0)); | |
_totalSupply = _totalSupply.add(value); | |
_balances[account] = _balances[account].add(value); | |
emit Transfer(address(0), account, value); | |
} | |
/** | |
* @dev Internal function that burns an amount of the token of a given | |
* account. | |
* @param account The account whose tokens will be burnt. | |
* @param value The amount that will be burnt. | |
*/ | |
function _burn(address account, uint256 value) internal { | |
require(account != address(0)); | |
_totalSupply = _totalSupply.sub(value); | |
_balances[account] = _balances[account].sub(value); | |
emit Transfer(account, address(0), value); | |
} | |
/** | |
* @dev Approve an address to spend another addresses' tokens. | |
* @param owner The address that owns the tokens. | |
* @param spender The address that will spend the tokens. | |
* @param value The number of tokens that can be spent. | |
*/ | |
function _approve(address owner, address spender, uint256 value) internal { | |
require(spender != address(0)); | |
require(owner != address(0)); | |
_allowed[owner][spender] = value; | |
emit Approval(owner, spender, value); | |
} | |
/** | |
* @dev Internal function that burns an amount of the token of a given | |
* account, deducting from the sender's allowance for said account. Uses the | |
* internal burn function. | |
* Emits an Approval event (reflecting the reduced allowance). | |
* @param account The account whose tokens will be burnt. | |
* @param value The amount that will be burnt. | |
*/ | |
function _burnFrom(address account, uint256 value) internal { | |
_burn(account, value); | |
_approve(account, msg.sender, _allowed[account][msg.sender].sub(value)); | |
} | |
} | |
contract MinterRole { | |
using Roles for Roles.Role; | |
event MinterAdded(address indexed account); | |
event MinterRemoved(address indexed account); | |
Roles.Role private _minters; | |
constructor () internal { | |
_addMinter(msg.sender); | |
} | |
modifier onlyMinter() { | |
require(isMinter(msg.sender)); | |
_; | |
} | |
function isMinter(address account) public view returns (bool) { | |
return _minters.has(account); | |
} | |
function addMinter(address account) public onlyMinter { | |
_addMinter(account); | |
} | |
function renounceMinter() public { | |
_removeMinter(msg.sender); | |
} | |
function _addMinter(address account) internal { | |
_minters.add(account); | |
emit MinterAdded(account); | |
} | |
function _removeMinter(address account) internal { | |
_minters.remove(account); | |
emit MinterRemoved(account); | |
} | |
} | |
/** | |
* @title ERC20Mintable | |
* @dev ERC20 minting logic. | |
*/ | |
contract ERC20Mintable is ERC20, MinterRole { | |
constructor() public MinterRole() {} | |
/** | |
* @dev Function to mint tokens | |
* @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 onlyMinter returns (bool) { | |
_mint(to, value); | |
return true; | |
} | |
} | |
contract StandartERC20 is ERC20Mintable { | |
string public name; | |
string public symbol; | |
uint8 public constant decimals = 18; | |
constructor(string memory _name, string memory _symbol) public ERC20Mintable() { | |
name = _name; | |
symbol = _symbol; | |
} | |
} | |
contract Factory { | |
/* | |
* Events | |
*/ | |
event ContractInstantiation(address sender, address instantiation); | |
/* | |
* Storage | |
*/ | |
mapping(address => bool) public isInstantiation; | |
mapping(address => address[]) public instantiations; | |
/* | |
* Public functions | |
*/ | |
/// @dev Returns number of instantiations by creator. | |
/// @param creator Contract creator. | |
/// @return Returns number of instantiations by creator. | |
function getInstantiationCount(address creator) public view returns (uint) { | |
return instantiations[creator].length; | |
} | |
/* | |
* Internal functions | |
*/ | |
/// @dev Registers contract in factory registry. | |
/// @param instantiation Address of contract instantiation. | |
function register(address instantiation) | |
internal | |
{ | |
isInstantiation[instantiation] = true; | |
instantiations[msg.sender].push(instantiation); | |
emit ContractInstantiation(msg.sender, instantiation); | |
} | |
} | |
contract ERC20Factory is Factory { | |
function create(string memory _name, string memory _symbol) public returns (address) { | |
StandartERC20 c = new StandartERC20(_name, _symbol); | |
c.addMinter(msg.sender); | |
c.renounceMinter(); | |
register(address(c)); | |
return address(c); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.15; | |
contract Factory { | |
/* | |
* Events | |
*/ | |
event ContractInstantiation(address sender, address instantiation); | |
/* | |
* Storage | |
*/ | |
mapping(address => bool) public isInstantiation; | |
mapping(address => address[]) public instantiations; | |
/* | |
* Public functions | |
*/ | |
/// @dev Returns number of instantiations by creator. | |
/// @param creator Contract creator. | |
/// @return Returns number of instantiations by creator. | |
function getInstantiationCount(address creator) | |
public | |
constant | |
returns (uint) | |
{ | |
return instantiations[creator].length; | |
} | |
/* | |
* Internal functions | |
*/ | |
/// @dev Registers contract in factory registry. | |
/// @param instantiation Address of contract instantiation. | |
function register(address instantiation) | |
internal | |
{ | |
isInstantiation[instantiation] = true; | |
instantiations[msg.sender].push(instantiation); | |
ContractInstantiation(msg.sender, instantiation); | |
} | |
} | |
/// @title Multisignature wallet - Allows multiple parties to agree on transactions before execution. | |
/// @author Stefan George - <[email protected]> | |
contract MultiSigWallet { | |
/* | |
* Events | |
*/ | |
event Confirmation(address indexed sender, uint indexed transactionId); | |
event Revocation(address indexed sender, uint indexed transactionId); | |
event Submission(uint indexed transactionId); | |
event Execution(uint indexed transactionId); | |
event ExecutionFailure(uint indexed transactionId); | |
event Deposit(address indexed sender, uint value); | |
event OwnerAddition(address indexed owner); | |
event OwnerRemoval(address indexed owner); | |
event RequirementChange(uint required); | |
/* | |
* Constants | |
*/ | |
uint constant public MAX_OWNER_COUNT = 50; | |
/* | |
* Storage | |
*/ | |
mapping (uint => Transaction) public transactions; | |
mapping (uint => mapping (address => bool)) public confirmations; | |
mapping (address => bool) public isOwner; | |
address[] public owners; | |
uint public required; | |
uint public transactionCount; | |
struct Transaction { | |
address destination; | |
uint value; | |
bytes data; | |
bool executed; | |
} | |
/* | |
* Modifiers | |
*/ | |
modifier onlyWallet() { | |
require(msg.sender == address(this)); | |
_; | |
} | |
modifier ownerDoesNotExist(address owner) { | |
require(!isOwner[owner]); | |
_; | |
} | |
modifier ownerExists(address owner) { | |
require(isOwner[owner]); | |
_; | |
} | |
modifier transactionExists(uint transactionId) { | |
require(transactions[transactionId].destination != 0); | |
_; | |
} | |
modifier confirmed(uint transactionId, address owner) { | |
require(confirmations[transactionId][owner]); | |
_; | |
} | |
modifier notConfirmed(uint transactionId, address owner) { | |
require(!confirmations[transactionId][owner]); | |
_; | |
} | |
modifier notExecuted(uint transactionId) { | |
require(!transactions[transactionId].executed); | |
_; | |
} | |
modifier notNull(address _address) { | |
require(_address != 0); | |
_; | |
} | |
modifier validRequirement(uint ownerCount, uint _required) { | |
require(ownerCount <= MAX_OWNER_COUNT | |
&& _required <= ownerCount | |
&& _required != 0 | |
&& ownerCount != 0); | |
_; | |
} | |
/// @dev Fallback function allows to deposit ether. | |
function() | |
payable | |
{ | |
if (msg.value > 0) | |
Deposit(msg.sender, msg.value); | |
} | |
/* | |
* Public functions | |
*/ | |
/// @dev Contract constructor sets initial owners and required number of confirmations. | |
/// @param _owners List of initial owners. | |
/// @param _required Number of required confirmations. | |
function MultiSigWallet(address[] _owners, uint _required) | |
public | |
validRequirement(_owners.length, _required) | |
{ | |
for (uint i=0; i<_owners.length; i++) { | |
require(!isOwner[_owners[i]] && _owners[i] != 0); | |
isOwner[_owners[i]] = true; | |
} | |
owners = _owners; | |
required = _required; | |
} | |
/// @dev Allows to add a new owner. Transaction has to be sent by wallet. | |
/// @param owner Address of new owner. | |
function addOwner(address owner) | |
public | |
onlyWallet | |
ownerDoesNotExist(owner) | |
notNull(owner) | |
validRequirement(owners.length + 1, required) | |
{ | |
isOwner[owner] = true; | |
owners.push(owner); | |
OwnerAddition(owner); | |
} | |
/// @dev Allows to remove an owner. Transaction has to be sent by wallet. | |
/// @param owner Address of owner. | |
function removeOwner(address owner) | |
public | |
onlyWallet | |
ownerExists(owner) | |
{ | |
isOwner[owner] = false; | |
for (uint i=0; i<owners.length - 1; i++) | |
if (owners[i] == owner) { | |
owners[i] = owners[owners.length - 1]; | |
break; | |
} | |
owners.length -= 1; | |
if (required > owners.length) | |
changeRequirement(owners.length); | |
OwnerRemoval(owner); | |
} | |
/// @dev Allows to replace an owner with a new owner. Transaction has to be sent by wallet. | |
/// @param owner Address of owner to be replaced. | |
/// @param newOwner Address of new owner. | |
function replaceOwner(address owner, address newOwner) | |
public | |
onlyWallet | |
ownerExists(owner) | |
ownerDoesNotExist(newOwner) | |
{ | |
for (uint i=0; i<owners.length; i++) | |
if (owners[i] == owner) { | |
owners[i] = newOwner; | |
break; | |
} | |
isOwner[owner] = false; | |
isOwner[newOwner] = true; | |
OwnerRemoval(owner); | |
OwnerAddition(newOwner); | |
} | |
/// @dev Allows to change the number of required confirmations. Transaction has to be sent by wallet. | |
/// @param _required Number of required confirmations. | |
function changeRequirement(uint _required) | |
public | |
onlyWallet | |
validRequirement(owners.length, _required) | |
{ | |
required = _required; | |
RequirementChange(_required); | |
} | |
/// @dev Allows an owner to submit and confirm a transaction. | |
/// @param destination Transaction target address. | |
/// @param value Transaction ether value. | |
/// @param data Transaction data payload. | |
/// @return Returns transaction ID. | |
function submitTransaction(address destination, uint value, bytes data) | |
public | |
returns (uint transactionId) | |
{ | |
transactionId = addTransaction(destination, value, data); | |
confirmTransaction(transactionId); | |
} | |
/// @dev Allows an owner to confirm a transaction. | |
/// @param transactionId Transaction ID. | |
function confirmTransaction(uint transactionId) | |
public | |
ownerExists(msg.sender) | |
transactionExists(transactionId) | |
notConfirmed(transactionId, msg.sender) | |
{ | |
confirmations[transactionId][msg.sender] = true; | |
Confirmation(msg.sender, transactionId); | |
executeTransaction(transactionId); | |
} | |
/// @dev Allows an owner to revoke a confirmation for a transaction. | |
/// @param transactionId Transaction ID. | |
function revokeConfirmation(uint transactionId) | |
public | |
ownerExists(msg.sender) | |
confirmed(transactionId, msg.sender) | |
notExecuted(transactionId) | |
{ | |
confirmations[transactionId][msg.sender] = false; | |
Revocation(msg.sender, transactionId); | |
} | |
/// @dev Allows anyone to execute a confirmed transaction. | |
/// @param transactionId Transaction ID. | |
function executeTransaction(uint transactionId) | |
public | |
ownerExists(msg.sender) | |
confirmed(transactionId, msg.sender) | |
notExecuted(transactionId) | |
{ | |
if (isConfirmed(transactionId)) { | |
Transaction storage txn = transactions[transactionId]; | |
txn.executed = true; | |
if (external_call(txn.destination, txn.value, txn.data.length, txn.data)) | |
Execution(transactionId); | |
else { | |
ExecutionFailure(transactionId); | |
txn.executed = false; | |
} | |
} | |
} | |
// call has been separated into its own function in order to take advantage | |
// of the Solidity's code generator to produce a loop that copies tx.data into memory. | |
function external_call(address destination, uint value, uint dataLength, bytes data) internal returns (bool) { | |
bool result; | |
assembly { | |
let x := mload(0x40) // "Allocate" memory for output (0x40 is where "free memory" pointer is stored by convention) | |
let d := add(data, 32) // First 32 bytes are the padded length of data, so exclude that | |
result := call( | |
sub(gas, 34710), // 34710 is the value that solidity is currently emitting | |
// It includes callGas (700) + callVeryLow (3, to pay for SUB) + callValueTransferGas (9000) + | |
// callNewAccountGas (25000, in case the destination address does not exist and needs creating) | |
destination, | |
value, | |
d, | |
dataLength, // Size of the input (in bytes) - this is what fixes the padding problem | |
x, | |
0 // Output is ignored, therefore the output size is zero | |
) | |
} | |
return result; | |
} | |
/// @dev Returns the confirmation status of a transaction. | |
/// @param transactionId Transaction ID. | |
/// @return Confirmation status. | |
function isConfirmed(uint transactionId) | |
public | |
constant | |
returns (bool) | |
{ | |
uint count = 0; | |
for (uint i=0; i<owners.length; i++) { | |
if (confirmations[transactionId][owners[i]]) | |
count += 1; | |
if (count == required) | |
return true; | |
} | |
} | |
/* | |
* Internal functions | |
*/ | |
/// @dev Adds a new transaction to the transaction mapping, if transaction does not exist yet. | |
/// @param destination Transaction target address. | |
/// @param value Transaction ether value. | |
/// @param data Transaction data payload. | |
/// @return Returns transaction ID. | |
function addTransaction(address destination, uint value, bytes data) | |
internal | |
notNull(destination) | |
returns (uint transactionId) | |
{ | |
transactionId = transactionCount; | |
transactions[transactionId] = Transaction({ | |
destination: destination, | |
value: value, | |
data: data, | |
executed: false | |
}); | |
transactionCount += 1; | |
Submission(transactionId); | |
} | |
/* | |
* Web3 call functions | |
*/ | |
/// @dev Returns number of confirmations of a transaction. | |
/// @param transactionId Transaction ID. | |
/// @return Number of confirmations. | |
function getConfirmationCount(uint transactionId) | |
public | |
constant | |
returns (uint count) | |
{ | |
for (uint i=0; i<owners.length; i++) | |
if (confirmations[transactionId][owners[i]]) | |
count += 1; | |
} | |
/// @dev Returns total number of transactions after filers are applied. | |
/// @param pending Include pending transactions. | |
/// @param executed Include executed transactions. | |
/// @return Total number of transactions after filters are applied. | |
function getTransactionCount(bool pending, bool executed) | |
public | |
constant | |
returns (uint count) | |
{ | |
for (uint i=0; i<transactionCount; i++) | |
if ( pending && !transactions[i].executed | |
|| executed && transactions[i].executed) | |
count += 1; | |
} | |
/// @dev Returns list of owners. | |
/// @return List of owner addresses. | |
function getOwners() | |
public | |
constant | |
returns (address[]) | |
{ | |
return owners; | |
} | |
/// @dev Returns array with owner addresses, which confirmed transaction. | |
/// @param transactionId Transaction ID. | |
/// @return Returns array of owner addresses. | |
function getConfirmations(uint transactionId) | |
public | |
constant | |
returns (address[] _confirmations) | |
{ | |
address[] memory confirmationsTemp = new address[](owners.length); | |
uint count = 0; | |
uint i; | |
for (i=0; i<owners.length; i++) | |
if (confirmations[transactionId][owners[i]]) { | |
confirmationsTemp[count] = owners[i]; | |
count += 1; | |
} | |
_confirmations = new address[](count); | |
for (i=0; i<count; i++) | |
_confirmations[i] = confirmationsTemp[i]; | |
} | |
/// @dev Returns list of transaction IDs in defined range. | |
/// @param from Index start position of transaction array. | |
/// @param to Index end position of transaction array. | |
/// @param pending Include pending transactions. | |
/// @param executed Include executed transactions. | |
/// @return Returns array of transaction IDs. | |
function getTransactionIds(uint from, uint to, bool pending, bool executed) | |
public | |
constant | |
returns (uint[] _transactionIds) | |
{ | |
uint[] memory transactionIdsTemp = new uint[](transactionCount); | |
uint count = 0; | |
uint i; | |
for (i=0; i<transactionCount; i++) | |
if ( pending && !transactions[i].executed | |
|| executed && transactions[i].executed) | |
{ | |
transactionIdsTemp[count] = i; | |
count += 1; | |
} | |
_transactionIds = new uint[](to - from); | |
for (i=from; i<to; i++) | |
_transactionIds[i - from] = transactionIdsTemp[i]; | |
} | |
} | |
contract MultiSigWalletWithDailyLimit is MultiSigWallet { | |
/* | |
* Events | |
*/ | |
event DailyLimitChange(uint dailyLimit); | |
/* | |
* Storage | |
*/ | |
uint public dailyLimit; | |
uint public lastDay; | |
uint public spentToday; | |
/* | |
* Public functions | |
*/ | |
/// @dev Contract constructor sets initial owners, required number of confirmations and daily withdraw limit. | |
/// @param _owners List of initial owners. | |
/// @param _required Number of required confirmations. | |
/// @param _dailyLimit Amount in wei, which can be withdrawn without confirmations on a daily basis. | |
function MultiSigWalletWithDailyLimit(address[] _owners, uint _required, uint _dailyLimit) | |
public | |
MultiSigWallet(_owners, _required) | |
{ | |
dailyLimit = _dailyLimit; | |
} | |
/// @dev Allows to change the daily limit. Transaction has to be sent by wallet. | |
/// @param _dailyLimit Amount in wei. | |
function changeDailyLimit(uint _dailyLimit) | |
public | |
onlyWallet | |
{ | |
dailyLimit = _dailyLimit; | |
DailyLimitChange(_dailyLimit); | |
} | |
/// @dev Allows anyone to execute a confirmed transaction or ether withdraws until daily limit is reached. | |
/// @param transactionId Transaction ID. | |
function executeTransaction(uint transactionId) | |
public | |
ownerExists(msg.sender) | |
confirmed(transactionId, msg.sender) | |
notExecuted(transactionId) | |
{ | |
Transaction storage txn = transactions[transactionId]; | |
bool _confirmed = isConfirmed(transactionId); | |
if (_confirmed || txn.data.length == 0 && isUnderLimit(txn.value)) { | |
txn.executed = true; | |
if (!_confirmed) | |
spentToday += txn.value; | |
if (external_call(txn.destination, txn.value, txn.data.length, txn.data)) | |
Execution(transactionId); | |
else { | |
ExecutionFailure(transactionId); | |
txn.executed = false; | |
if (!_confirmed) | |
spentToday -= txn.value; | |
} | |
} | |
} | |
/* | |
* Internal functions | |
*/ | |
/// @dev Returns if amount is within daily limit and resets spentToday after one day. | |
/// @param amount Amount to withdraw. | |
/// @return Returns if amount is under daily limit. | |
function isUnderLimit(uint amount) | |
internal | |
returns (bool) | |
{ | |
if (now > lastDay + 24 hours) { | |
lastDay = now; | |
spentToday = 0; | |
} | |
if (spentToday + amount > dailyLimit || spentToday + amount < spentToday) | |
return false; | |
return true; | |
} | |
/* | |
* Web3 call functions | |
*/ | |
/// @dev Returns maximum withdraw amount. | |
/// @return Returns amount. | |
function calcMaxWithdraw() | |
public | |
constant | |
returns (uint) | |
{ | |
if (now > lastDay + 24 hours) | |
return dailyLimit; | |
if (dailyLimit < spentToday) | |
return 0; | |
return dailyLimit - spentToday; | |
} | |
} | |
/// @title Multisignature wallet factory - Allows creation of multisig wallet. | |
/// @author Stefan George - <[email protected]> | |
contract MultiSigWalletWithDailyLimitFactory is Factory { | |
/* | |
* Public functions | |
*/ | |
/// @dev Allows verified creation of multisignature wallet. | |
/// @param _owners List of initial owners. | |
/// @param _required Number of required confirmations. | |
/// @param _dailyLimit Amount in wei, which can be withdrawn without confirmations on a daily basis. | |
/// @return Returns wallet address. | |
function create(address[] _owners, uint _required, uint _dailyLimit) | |
public | |
returns (address wallet) | |
{ | |
wallet = new MultiSigWalletWithDailyLimit(_owners, _required, _dailyLimit); | |
register(wallet); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment