pragma solidity ^0.4.24;
/**
* @title The STT Token contract.
*
* By Nikita Fuchs
* Credit: Taking ideas from BAT token, NET token and Nimiq token.
*/
/**
* @title Safe math operations that throw error on overflow.
*
* Credit: Taking ideas from FirstBlood token
*/
library SafeMath {
/**
* @dev Safely add two numbers.
*
* @param x First operant.
* @param y Second operant.
* @return The result of x+y.
*/
function add(uint256 x, uint256 y)
internal pure
returns(uint256) {
uint256 z = x + y;
assert((z >= x) && (z >= y));
return z;
}
/**
* @dev Safely substract two numbers.
*
* @param x First operant.
* @param y Second operant.
* @return The result of x-y.
*/
function sub(uint256 x, uint256 y)
internal pure
returns(uint256) {
assert(x >= y);
uint256 z = x - y;
return z;
}
/**
* @dev Safely multiply two numbers.
*
* @param x First operant.
* @param y Second operant.
* @return The result of x*y.
*/
function mul(uint256 x, uint256 y)
internal pure
returns(uint256) {
uint256 z = x * y;
assert((x == 0) || (z/x == y));
return z;
}
}
/**
* @title The abstract ERC-20 Token Standard definition.
*
* https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md
*/
contract Token {
/// @dev Returns the total token supply.
uint256 public totalSupply;
function balanceOf(address _owner) public view returns (uint256 balance);
function transfer(address _to, uint256 _value) public returns (bool success);
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);
function approve(address _spender, uint256 _value) public returns (bool success);
function allowance(address _owner, address _spender) public view returns (uint256 remaining);
/// @dev MUST trigger when tokens are transferred, including zero value transfers.
event Transfer(address indexed _from, address indexed _to, uint256 _value);
/// @dev MUST trigger on any successful call to approve(address _spender, uint256 _value).
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}
/**
* @title Default implementation of the ERC-20 Token Standard.
*/
contract StandardToken is Token {
mapping (address => uint256) balances;
mapping (address => mapping (address => uint256)) allowed;
/**
* @dev Transfers _value amount of tokens to address _to, and MUST fire the Transfer event.
* @dev The function SHOULD throw if the _from account balance does not have enough tokens to spend.
*
* @dev A token contract which creates new tokens SHOULD trigger a Transfer event with the _from address set to 0x0 when tokens are created.
*
* Note Transfers of 0 values MUST be treated as normal transfers and fire the Transfer event.
*
* @param _to The receiver of the tokens.
* @param _value The amount of tokens to send.
* @return True on success, false otherwise.
*/
function transfer(address _to, uint256 _value)
public
returns (bool success) {
if (balances[msg.sender] >= _value && _value > 0 && balances[_to] + _value > balances[_to]) {
balances[msg.sender] = SafeMath.sub(balances[msg.sender], _value);
balances[_to] = SafeMath.add(balances[_to], _value);
emit Transfer(msg.sender, _to, _value);
return true;
} else {
return false;
}
}
/**
* @dev Transfers _value amount of tokens from address _from to address _to, and MUST fire the Transfer event.
*
* @dev The transferFrom method is used for a withdraw workflow, allowing contracts to transfer tokens on your behalf.
* @dev This can be used for example to allow a contract to transfer tokens on your behalf and/or to charge fees in
* @dev sub-currencies. The function SHOULD throw unless the _from account has deliberately authorized the sender of
* @dev the message via some mechanism.
*
* Note Transfers of 0 values MUST be treated as normal transfers and fire the Transfer event.
*
* @param _from The sender of the tokens.
* @param _to The receiver of the tokens.
* @param _value The amount of tokens to send.
* @return True on success, false otherwise.
*/
function transferFrom(address _from, address _to, uint256 _value)
public
returns (bool success) {
if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value && _value > 0 && balances[_to] + _value > balances[_to]) {
balances[_to] = SafeMath.add(balances[_to], _value);
balances[_from] = SafeMath.sub(balances[_from], _value);
allowed[_from][msg.sender] = SafeMath.sub(allowed[_from][msg.sender], _value);
emit Transfer(_from, _to, _value);
return true;
} else {
return false;
}
}
/**
* @dev Returns the account balance of another account with address _owner.
*
* @param _owner The address of the account to check.
* @return The account balance.
*/
function balanceOf(address _owner)
public view
returns (uint256 balance) {
return balances[_owner];
}
/**
* @dev Allows _spender to withdraw from your account multiple times, up to the _value amount.
* @dev If this function is called again it overwrites the current allowance with _value.
*
* @dev NOTE: To prevent attack vectors like the one described in [1] and discussed in [2], clients
* @dev SHOULD make sure to create user interfaces in such a way that they set the allowance first
* @dev to 0 before setting it to another value for the same spender. THOUGH The contract itself
* @dev shouldn't enforce it, to allow backwards compatilibilty with contracts deployed before.
* @dev [1] https://docs.google.com/document/d/1YLPtQxZu1UAvO9cZ1O2RPXBbT0mooh4DYKjA_jp-RLM/
* @dev [2] 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.
* @return True on success, false otherwise.
*/
function approve(address _spender, uint256 _value)
public
returns (bool success) {
allowed[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
/**
* @dev Returns the amount which _spender is still allowed to withdraw from _owner.
*
* @param _owner The address of the sender.
* @param _spender The address of the receiver.
* @return The allowed withdrawal amount.
*/
function allowance(address _owner, address _spender)
public view
returns (uint256 remaining) {
return allowed[_owner][_spender];
}
}
contract RelocationToken {
// function of possible new contract to recieve tokenbalance to relocate - to be protected by msg.sender == StarambaToken
function recieveRelocation(address _creditor, uint _balance) external returns (bool);
}
/*is StandardToken */
contract StarambaToken is StandardToken {
// Token metadata
string public constant name = "STARAMBA.Token";
string public constant symbol = "STT";
uint256 public constant decimals = 18;
string public constant version = "1";
uint256 public TOKEN_CREATION_CAP = 1000 * (10**6) * 10**decimals; // 1000 million STTs
uint256 public constant TOKEN_MIN = 1 * 10**decimals; // 1 STT
address public STTadmin1; // First administrator for multi-sig mechanism
address public STTadmin2; // Second administrator for multi-sig mechanism
// Contracts current state (transactions still paused during sale or already publicly available)
bool public transactionsActive;
// Indicate if the token is in relocation mode
bool public relocationActive;
address public newTokenContractAddress;
// How often was the supply adjusted ? (See STT Whitepaper Version 1.0 from 23. May 2018 )
uint8 supplyAdjustmentCount = 0;
// Keep track of holders and icoBuyers
mapping (address => bool) public isHolder; // track if a user is a known token holder to the smart contract - important for payouts later
address[] public holders; // array of all known holders - important for payouts later
// Store the hashes of admins' msg.data
mapping (address => bytes32) private multiSigHashes;
// Declare vendor keys
mapping (address => bool) public vendors;
// Count amount of vendors for easier verification of correct contract deployment
uint8 public vendorCount;
// Events used for logging
event LogDeliverSTT(address indexed _to, uint256 _value);
//event Log
modifier onlyVendor() {
require(vendors[msg.sender] == true);
_;
}
modifier isTransferable() {
require (transactionsActive == true);
_;
}
modifier onlyOwner() {
// check if transaction sender is admin.
require (msg.sender == STTadmin1 || msg.sender == STTadmin2);
// if yes, store his msg.data.
multiSigHashes[msg.sender] = keccak256(msg.data);
// check if his stored msg.data hash equals to the one of the other admin
if ((multiSigHashes[STTadmin1]) == (multiSigHashes[STTadmin2])) {
// if yes, both admins agreed - continue.
_;
// Reset hashes after successful execution
multiSigHashes[STTadmin1] = 0x0;
multiSigHashes[STTadmin2] = 0x0;
} else {
// if not (yet), return.
return;
}
}
/**
* @dev Create a new STTToken contract.
*
* _admin1 The first admin account that owns this contract.
* _admin2 The second admin account that owns this contract.
* _vendors List of exactly 10 addresses that are allowed to deliver tokens.
*/
constructor(address _admin1, address _admin2, address[] _vendors)
public
{
// Check if the parameters make sense
// admin1 and admin2 address must be set and must be different
require (_admin1 != 0x0);
require (_admin2 != 0x0);
require (_admin1 != _admin2);
// 10 vendor instances for delivering token purchases
require (_vendors.length == 10);
totalSupply = 0;
// define state
STTadmin1 = _admin1;
STTadmin2 = _admin2;
for (uint8 i = 0; i < _vendors.length; i++){
vendors[_vendors[i]] = true;
vendorCount++;
}
}
// Overridden method to check for end of fundraising before allowing transfer of tokens
function transfer(address _to, uint256 _value)
public
isTransferable // Only allow token transfer after the fundraising has ended
returns (bool success)
{
bool result = super.transfer(_to, _value);
if (result) {
trackHolder(_to); // track the owner for later payouts
}
return result;
}
// Overridden method to check for end of fundraising before allowing transfer of tokens
function transferFrom(address _from, address _to, uint256 _value)
public
isTransferable // Only allow token transfer after the fundraising has ended
returns (bool success)
{
bool result = super.transferFrom(_from, _to, _value);
if (result) {
trackHolder(_to); // track the owner for later payouts
}
return result;
}
// Allow for easier balance checking
function getBalanceOf(address _owner)
public
view
returns (uint256 _balance)
{
return balances[_owner];
}
// Perform an atomic swap between two token contracts
function relocate()
external
{
// Check if relocation was activated
require (relocationActive == true);
// Define new token contract is
RelocationToken newSTT = RelocationToken(newTokenContractAddress);
// Burn the old balance
uint256 balance = balances[msg.sender];
balances[msg.sender] = 0;
// Perform the relocation of balances to new contract
require(newSTT.recieveRelocation(msg.sender, balance));
}
// Allows to figure out the amount of known token holders
function getHolderCount()
public
view
returns (uint256 _holderCount)
{
return holders.length;
}
// Allows for easier retrieval of holder by array index
function getHolder(uint256 _index)
public
view
returns (address _holder)
{
return holders[_index];
}
function trackHolder(address _to)
private
returns (bool success)
{
// Check if the recipient is a known token holder
if (isHolder[_to] == false) {
// if not, add him to the holders array and mark him as a known holder
holders.push(_to);
isHolder[_to] = true;
}
return true;
}
/// @dev delivers STT tokens from Leondra (Leondrino Exchange Germany)
function deliverTokens(address _buyer, uint256 _amount)
external
onlyVendor
{
require(_amount >= TOKEN_MIN);
uint256 checkedSupply = SafeMath.add(totalSupply, _amount);
require(checkedSupply <= TOKEN_CREATION_CAP);
// Adjust the balance
uint256 oldBalance = balances[_buyer];
balances[_buyer] = SafeMath.add(oldBalance, _amount);
totalSupply = checkedSupply;
trackHolder(_buyer);
// Log the creation of these tokens
emit LogDeliverSTT(_buyer, _amount);
}
/// @dev Creates new STT tokens
function deliverTokensBatch(address[] _buyer, uint256[] _amount)
external
onlyVendor
{
require(_buyer.length == _amount.length);
for (uint8 i = 0 ; i < _buyer.length; i++) {
require(_amount[i] >= TOKEN_MIN);
require(_buyer[i] != 0x0);
uint256 checkedSupply = SafeMath.add(totalSupply, _amount[i]);
require(checkedSupply <= TOKEN_CREATION_CAP);
// Adjust the balance
uint256 oldBalance = balances[_buyer[i]];
balances[_buyer[i]] = SafeMath.add(oldBalance, _amount[i]);
totalSupply = checkedSupply;
trackHolder(_buyer[i]);
// Log the creation of these tokens
emit LogDeliverSTT(_buyer[i], _amount[i]);
}
}
// Allow / Deny transfer of tokens
function transactionSwitch(bool _transactionsActive)
external
onlyOwner
{
transactionsActive = _transactionsActive;
}
// For eventual later moving to another token contract
function relocationSwitch(bool _relocationActive, address _newTokenContractAddress)
external
onlyOwner
{
if (_relocationActive) {
require(_newTokenContractAddress != 0x0);
} else {
require(_newTokenContractAddress == 0x0);
}
relocationActive = _relocationActive;
newTokenContractAddress = _newTokenContractAddress;
}
// Adjust the cap according to the white paper terms (See STT Whitepaper Version 1.0 from 23. May 2018 )
function adjustCap()
external
onlyOwner
{
require (supplyAdjustmentCount < 4);
TOKEN_CREATION_CAP = SafeMath.add(TOKEN_CREATION_CAP, 50 * (10**6) * 10**decimals); // 50 million STTs
supplyAdjustmentCount++;
}
// Burn function - name indicating the burn of ALL owner's tokens
function burnWholeBalance()
external
{
require(balances[msg.sender] > 0);
totalSupply = SafeMath.sub(totalSupply, balances[msg.sender]);
balances[msg.sender] = 0;
}
}
{
"compilationTarget": {
"StarambaToken.sol": "StarambaToken"
},
"evmVersion": "byzantium",
"libraries": {},
"optimizer": {
"enabled": false,
"runs": 0
},
"remappings": []
}
[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"newTokenContractAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"vendors","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"holders","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_buyer","type":"address"},{"name":"_amount","type":"uint256"}],"name":"deliverTokens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"STTadmin2","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"version","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"adjustCap","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"STTadmin1","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getHolderCount","outputs":[{"name":"_holderCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_transactionsActive","type":"bool"}],"name":"transactionSwitch","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"vendorCount","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"getBalanceOf","outputs":[{"name":"_balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_relocationActive","type":"bool"},{"name":"_newTokenContractAddress","type":"address"}],"name":"relocationSwitch","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"relocate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"burnWholeBalance","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"transactionsActive","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_buyer","type":"address[]"},{"name":"_amount","type":"uint256[]"}],"name":"deliverTokensBatch","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"isHolder","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"remaining","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"relocationActive","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"TOKEN_MIN","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_index","type":"uint256"}],"name":"getHolder","outputs":[{"name":"_holder","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"TOKEN_CREATION_CAP","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_admin1","type":"address"},{"name":"_admin2","type":"address"},{"name":"_vendors","type":"address[]"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"LogDeliverSTT","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_spender","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Approval","type":"event"}]