// File: solidity/contracts/token/interfaces/IERC20Token.sol
// SPDX-License-Identifier: SEE LICENSE IN LICENSE
pragma solidity 0.6.12;
/*
ERC20 Standard Token interface
*/
interface IERC20Token {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
function totalSupply() external view returns (uint256);
function balanceOf(address _owner) external view returns (uint256);
function allowance(address _owner, address _spender) external view returns (uint256);
function transfer(address _to, uint256 _value) external returns (bool);
function transferFrom(address _from, address _to, uint256 _value) external returns (bool);
function approve(address _spender, uint256 _value) external returns (bool);
}
// File: solidity/contracts/utility/Utils.sol
pragma solidity 0.6.12;
/**
* @dev Utilities & Common Modifiers
*/
contract Utils {
// verifies that a value is greater than zero
modifier greaterThanZero(uint256 _value) {
_greaterThanZero(_value);
_;
}
// error message binary size optimization
function _greaterThanZero(uint256 _value) internal pure {
require(_value > 0, "ERR_ZERO_VALUE");
}
// validates an address - currently only checks that it isn't null
modifier validAddress(address _address) {
_validAddress(_address);
_;
}
// error message binary size optimization
function _validAddress(address _address) internal pure {
require(_address != address(0), "ERR_INVALID_ADDRESS");
}
// verifies that the address is different than this contract address
modifier notThis(address _address) {
_notThis(_address);
_;
}
// error message binary size optimization
function _notThis(address _address) internal view {
require(_address != address(this), "ERR_ADDRESS_IS_SELF");
}
}
// File: solidity/contracts/utility/SafeMath.sol
pragma solidity 0.6.12;
/**
* @dev Library for basic math operations with overflow/underflow protection
*/
library SafeMath {
/**
* @dev returns the sum of _x and _y, reverts if the calculation overflows
*
* @param _x value 1
* @param _y value 2
*
* @return sum
*/
function add(uint256 _x, uint256 _y) internal pure returns (uint256) {
uint256 z = _x + _y;
require(z >= _x, "ERR_OVERFLOW");
return z;
}
/**
* @dev returns the difference of _x minus _y, reverts if the calculation underflows
*
* @param _x minuend
* @param _y subtrahend
*
* @return difference
*/
function sub(uint256 _x, uint256 _y) internal pure returns (uint256) {
require(_x >= _y, "ERR_UNDERFLOW");
return _x - _y;
}
/**
* @dev returns the product of multiplying _x by _y, reverts if the calculation overflows
*
* @param _x factor 1
* @param _y factor 2
*
* @return product
*/
function mul(uint256 _x, uint256 _y) internal pure returns (uint256) {
// gas optimization
if (_x == 0)
return 0;
uint256 z = _x * _y;
require(z / _x == _y, "ERR_OVERFLOW");
return z;
}
/**
* @dev Integer division of two numbers truncating the quotient, reverts on division by zero.
*
* @param _x dividend
* @param _y divisor
*
* @return quotient
*/
function div(uint256 _x, uint256 _y) internal pure returns (uint256) {
require(_y > 0, "ERR_DIVIDE_BY_ZERO");
uint256 c = _x / _y;
return c;
}
}
// File: solidity/contracts/token/ERC20Token.sol
pragma solidity 0.6.12;
/**
* @dev ERC20 Standard Token implementation
*/
contract ERC20Token is IERC20Token, Utils {
using SafeMath for uint256;
string public override name;
string public override symbol;
uint8 public override decimals;
uint256 public override totalSupply;
mapping (address => uint256) public override balanceOf;
mapping (address => mapping (address => uint256)) public override allowance;
/**
* @dev triggered when tokens are transferred between wallets
*
* @param _from source address
* @param _to target address
* @param _value transfer amount
*/
event Transfer(address indexed _from, address indexed _to, uint256 _value);
/**
* @dev triggered when a wallet allows another wallet to transfer tokens from on its behalf
*
* @param _owner wallet that approves the allowance
* @param _spender wallet that receives the allowance
* @param _value allowance amount
*/
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
/**
* @dev initializes a new ERC20Token instance
*
* @param _name token name
* @param _symbol token symbol
* @param _decimals decimal points, for display purposes
* @param _totalSupply total supply of token units
*/
constructor(string memory _name, string memory _symbol, uint8 _decimals, uint256 _totalSupply) public {
// validate input
require(bytes(_name).length > 0, "ERR_INVALID_NAME");
require(bytes(_symbol).length > 0, "ERR_INVALID_SYMBOL");
name = _name;
symbol = _symbol;
decimals = _decimals;
totalSupply = _totalSupply;
balanceOf[msg.sender] = _totalSupply;
}
/**
* @dev transfers tokens to a given address
* throws on any error rather then return a false flag to minimize user errors
*
* @param _to target address
* @param _value transfer amount
*
* @return true if the transfer was successful, false if it wasn't
*/
function transfer(address _to, uint256 _value)
public
virtual
override
validAddress(_to)
returns (bool)
{
balanceOf[msg.sender] = balanceOf[msg.sender].sub(_value);
balanceOf[_to] = balanceOf[_to].add(_value);
emit Transfer(msg.sender, _to, _value);
return true;
}
/**
* @dev transfers tokens to a given address on behalf of another address
* throws on any error rather then return a false flag to minimize user errors
*
* @param _from source address
* @param _to target address
* @param _value transfer amount
*
* @return true if the transfer was successful, false if it wasn't
*/
function transferFrom(address _from, address _to, uint256 _value)
public
virtual
override
validAddress(_from)
validAddress(_to)
returns (bool)
{
allowance[_from][msg.sender] = allowance[_from][msg.sender].sub(_value);
balanceOf[_from] = balanceOf[_from].sub(_value);
balanceOf[_to] = balanceOf[_to].add(_value);
emit Transfer(_from, _to, _value);
return true;
}
/**
* @dev allows another account/contract to transfers tokens on behalf of the caller
* throws on any error rather then return a false flag to minimize user errors
*
* also, to minimize the risk of the approve/transferFrom attack vector
* (see https://docs.google.com/document/d/1YLPtQxZu1UAvO9cZ1O2RPXBbT0mooh4DYKjA_jp-RLM/), approve has to be called twice
* in 2 separate transactions - once to change the allowance to 0 and secondly to change it to the new allowance value
*
* @param _spender approved address
* @param _value allowance amount
*
* @return true if the approval was successful, false if it wasn't
*/
function approve(address _spender, uint256 _value)
public
virtual
override
validAddress(_spender)
returns (bool)
{
// if the allowance isn't 0, it can only be updated to 0 to prevent an allowance change immediately after withdrawal
require(_value == 0 || allowance[msg.sender][_spender] == 0, "ERR_INVALID_AMOUNT");
allowance[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
}
// File: solidity/contracts/utility/interfaces/IOwned.sol
pragma solidity 0.6.12;
/*
Owned contract interface
*/
interface IOwned {
// this function isn't since the compiler emits automatically generated getter functions as external
function owner() external view returns (address);
function transferOwnership(address _newOwner) external;
function acceptOwnership() external;
}
// File: solidity/contracts/utility/interfaces/ITokenHolder.sol
pragma solidity 0.6.12;
/*
Token Holder interface
*/
interface ITokenHolder is IOwned {
function withdrawTokens(IERC20Token _token, address _to, uint256 _amount) external;
}
// File: solidity/contracts/converter/interfaces/IConverterAnchor.sol
pragma solidity 0.6.12;
/*
Converter Anchor interface
*/
interface IConverterAnchor is IOwned, ITokenHolder {
}
// File: solidity/contracts/token/interfaces/ISmartToken.sol
pragma solidity 0.6.12;
/*
Smart Token interface
*/
interface ISmartToken is IConverterAnchor, IERC20Token {
function disableTransfers(bool _disable) external;
function issue(address _to, uint256 _amount) external;
function destroy(address _from, uint256 _amount) external;
}
// File: solidity/contracts/utility/Owned.sol
pragma solidity 0.6.12;
/**
* @dev Provides support and utilities for contract ownership
*/
contract Owned is IOwned {
address public override owner;
address public newOwner;
/**
* @dev triggered when the owner is updated
*
* @param _prevOwner previous owner
* @param _newOwner new owner
*/
event OwnerUpdate(address indexed _prevOwner, address indexed _newOwner);
/**
* @dev initializes a new Owned instance
*/
constructor() public {
owner = msg.sender;
}
// allows execution by the owner only
modifier ownerOnly {
_ownerOnly();
_;
}
// error message binary size optimization
function _ownerOnly() internal view {
require(msg.sender == owner, "ERR_ACCESS_DENIED");
}
/**
* @dev allows transferring the contract ownership
* the new owner still needs to accept the transfer
* can only be called by the contract owner
*
* @param _newOwner new contract owner
*/
function transferOwnership(address _newOwner) public override ownerOnly {
require(_newOwner != owner, "ERR_SAME_OWNER");
newOwner = _newOwner;
}
/**
* @dev used by a new owner to accept an ownership transfer
*/
function acceptOwnership() override public {
require(msg.sender == newOwner, "ERR_ACCESS_DENIED");
emit OwnerUpdate(owner, newOwner);
owner = newOwner;
newOwner = address(0);
}
}
// File: solidity/contracts/utility/TokenHandler.sol
pragma solidity 0.6.12;
contract TokenHandler {
bytes4 private constant APPROVE_FUNC_SELECTOR = bytes4(keccak256("approve(address,uint256)"));
bytes4 private constant TRANSFER_FUNC_SELECTOR = bytes4(keccak256("transfer(address,uint256)"));
bytes4 private constant TRANSFER_FROM_FUNC_SELECTOR = bytes4(keccak256("transferFrom(address,address,uint256)"));
/**
* @dev executes the ERC20 token's `approve` function and reverts upon failure
* the main purpose of this function is to prevent a non standard ERC20 token
* from failing silently
*
* @param _token ERC20 token address
* @param _spender approved address
* @param _value allowance amount
*/
function safeApprove(IERC20Token _token, address _spender, uint256 _value) internal {
(bool success, bytes memory data) = address(_token).call(abi.encodeWithSelector(APPROVE_FUNC_SELECTOR, _spender, _value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'ERR_APPROVE_FAILED');
}
/**
* @dev executes the ERC20 token's `transfer` function and reverts upon failure
* the main purpose of this function is to prevent a non standard ERC20 token
* from failing silently
*
* @param _token ERC20 token address
* @param _to target address
* @param _value transfer amount
*/
function safeTransfer(IERC20Token _token, address _to, uint256 _value) internal {
(bool success, bytes memory data) = address(_token).call(abi.encodeWithSelector(TRANSFER_FUNC_SELECTOR, _to, _value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'ERR_TRANSFER_FAILED');
}
/**
* @dev executes the ERC20 token's `transferFrom` function and reverts upon failure
* the main purpose of this function is to prevent a non standard ERC20 token
* from failing silently
*
* @param _token ERC20 token address
* @param _from source address
* @param _to target address
* @param _value transfer amount
*/
function safeTransferFrom(IERC20Token _token, address _from, address _to, uint256 _value) internal {
(bool success, bytes memory data) = address(_token).call(abi.encodeWithSelector(TRANSFER_FROM_FUNC_SELECTOR, _from, _to, _value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'ERR_TRANSFER_FROM_FAILED');
}
}
// File: solidity/contracts/utility/TokenHolder.sol
pragma solidity 0.6.12;
/**
* @dev We consider every contract to be a 'token holder' since it's currently not possible
* for a contract to deny receiving tokens.
*
* The TokenHolder's contract sole purpose is to provide a safety mechanism that allows
* the owner to send tokens that were sent to the contract by mistake back to their sender.
*
* Note that we use the non standard ERC-20 interface which has no return value for transfer
* in order to support both non standard as well as standard token contracts.
* see https://github.com/ethereum/solidity/issues/4116
*/
contract TokenHolder is ITokenHolder, TokenHandler, Owned, Utils {
/**
* @dev withdraws tokens held by the contract and sends them to an account
* can only be called by the owner
*
* @param _token ERC20 token contract address
* @param _to account to receive the new amount
* @param _amount amount to withdraw
*/
function withdrawTokens(IERC20Token _token, address _to, uint256 _amount)
public
virtual
override
ownerOnly
validAddress(address(_token))
validAddress(_to)
notThis(_to)
{
safeTransfer(_token, _to, _amount);
}
}
// File: solidity/contracts/token/SmartToken.sol
pragma solidity 0.6.12;
/**
* @dev Smart Token
*
* 'Owned' is specified here for readability reasons
*/
contract SmartToken is ISmartToken, Owned, ERC20Token, TokenHolder {
using SafeMath for uint256;
uint16 public constant version = 4;
bool public transfersEnabled = true; // true if transfer/transferFrom are enabled, false otherwise
/**
* @dev triggered when the total supply is increased
*
* @param _amount amount that gets added to the supply
*/
event Issuance(uint256 _amount);
/**
* @dev triggered when the total supply is decreased
*
* @param _amount amount that gets removed from the supply
*/
event Destruction(uint256 _amount);
/**
* @dev initializes a new SmartToken instance
*
* @param _name token name
* @param _symbol token short symbol, minimum 1 character
* @param _decimals for display purposes only
*/
constructor(string memory _name, string memory _symbol, uint8 _decimals)
public
ERC20Token(_name, _symbol, _decimals, 0)
{
}
// allows execution only when transfers are enabled
modifier transfersAllowed {
_transfersAllowed();
_;
}
// error message binary size optimization
function _transfersAllowed() internal view {
require(transfersEnabled, "ERR_TRANSFERS_DISABLED");
}
/**
* @dev disables/enables transfers
* can only be called by the contract owner
*
* @param _disable true to disable transfers, false to enable them
*/
function disableTransfers(bool _disable) public override ownerOnly {
transfersEnabled = !_disable;
}
/**
* @dev increases the token supply and sends the new tokens to the given account
* can only be called by the contract owner
*
* @param _to account to receive the new amount
* @param _amount amount to increase the supply by
*/
function issue(address _to, uint256 _amount)
public
override
ownerOnly
validAddress(_to)
notThis(_to)
{
totalSupply = totalSupply.add(_amount);
balanceOf[_to] = balanceOf[_to].add(_amount);
emit Issuance(_amount);
emit Transfer(address(0), _to, _amount);
}
/**
* @dev removes tokens from the given account and decreases the token supply
* can only be called by the contract owner
*
* @param _from account to remove the amount from
* @param _amount amount to decrease the supply by
*/
function destroy(address _from, uint256 _amount) public override ownerOnly {
balanceOf[_from] = balanceOf[_from].sub(_amount);
totalSupply = totalSupply.sub(_amount);
emit Transfer(_from, address(0), _amount);
emit Destruction(_amount);
}
// ERC20 standard method overrides with some extra functionality
/**
* @dev send coins
* throws on any error rather then return a false flag to minimize user errors
* in addition to the standard checks, the function throws if transfers are disabled
*
* @param _to target address
* @param _value transfer amount
*
* @return true if the transfer was successful, false if it wasn't
*/
function transfer(address _to, uint256 _value)
public
override(IERC20Token, ERC20Token)
transfersAllowed
returns (bool)
{
return super.transfer(_to, _value);
}
/**
* @dev an account/contract attempts to get the coins
* throws on any error rather then return a false flag to minimize user errors
* in addition to the standard checks, the function throws if transfers are disabled
*
* @param _from source address
* @param _to target address
* @param _value transfer amount
*
* @return true if the transfer was successful, false if it wasn't
*/
function transferFrom(address _from, address _to, uint256 _value)
public
override(IERC20Token, ERC20Token)
transfersAllowed
returns (bool)
{
return super.transferFrom(_from, _to, _value);
}
}
{
"compilationTarget": {
"SmartToken.sol": "SmartToken"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint8","name":"_decimals","type":"uint8"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_owner","type":"address"},{"indexed":true,"internalType":"address","name":"_spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"Destruction","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"Issuance","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_prevOwner","type":"address"},{"indexed":true,"internalType":"address","name":"_newOwner","type":"address"}],"name":"OwnerUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_from","type":"address"},{"indexed":true,"internalType":"address","name":"_to","type":"address"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"destroy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_disable","type":"bool"}],"name":"disableTransfers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"issue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"newOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"transfersEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20Token","name":"_token","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawTokens","outputs":[],"stateMutability":"nonpayable","type":"function"}]