Skip to content

Instantly share code, notes, and snippets.

@vamshi4001
Created September 5, 2017 00:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vamshi4001/9876665133983449ef7bafae327a1171 to your computer and use it in GitHub Desktop.
Save vamshi4001/9876665133983449ef7bafae327a1171 to your computer and use it in GitHub Desktop.
pragma solidity ^0.4.8;
/**
* Math operations with safety checks
*/
library SafeMath {
function mul(uint a, uint b) internal returns (uint) {
uint c = a * b;
assert(a == 0 || c / a == b);
return c;
}
function div(uint a, uint b) internal returns (uint) {
assert(b > 0);
uint c = a / b;
assert(a == b * c + a % b);
return c;
}
function sub(uint a, uint b) internal returns (uint) {
assert(b <= a);
return a - b;
}
function add(uint a, uint b) internal returns (uint) {
uint c = a + b;
assert(c >= a);
return c;
}
function max64(uint64 a, uint64 b) internal constant returns (uint64) {
return a >= b ? a : b;
}
function min64(uint64 a, uint64 b) internal constant returns (uint64) {
return a < b ? a : b;
}
function max256(uint256 a, uint256 b) internal constant returns (uint256) {
return a >= b ? a : b;
}
function min256(uint256 a, uint256 b) internal constant returns (uint256) {
return a < b ? a : b;
}
function assert(bool assertion) internal {
if (!assertion) {
throw;
}
}
}
/*
* ERC20Basic
* Simpler version of ERC20 interface
* see https://github.com/ethereum/EIPs/issues/20
*/
contract ERC20Basic {
uint public totalSupply;
function balanceOf(address who) constant returns (uint);
function transfer(address to, uint value);
event Transfer(address indexed from, address indexed to, uint value);
}
/*
* ERC20 interface
* see https://github.com/ethereum/EIPs/issues/20
*/
contract ERC20 is ERC20Basic {
function allowance(address owner, address spender) constant returns (uint);
function transferFrom(address from, address to, uint value);
function approve(address spender, uint value);
event Approval(address indexed owner, address indexed spender, uint value);
}
/*
* Basic token
* Basic version of StandardToken, with no allowances
*/
contract BasicToken is ERC20Basic {
using SafeMath for uint;
mapping(address => uint) balances;
/*
* Fix for the ERC20 short address attack
*/
modifier onlyPayloadSize(uint size) {
if(msg.data.length < size + 4) {
throw;
}
_;
}
function transfer(address _to, uint _value) onlyPayloadSize(2 * 32) {
balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(_value);
Transfer(msg.sender, _to, _value);
}
function balanceOf(address _owner) constant returns (uint balance) {
return balances[_owner];
}
}
/**
* Standard ERC20 token
*
* https://github.com/ethereum/EIPs/issues/20
* Based on code by FirstBlood:
* https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
*/
contract StandardToken is BasicToken, ERC20 {
mapping (address => mapping (address => uint)) allowed;
function transferFrom(address _from, address _to, uint _value) {
var _allowance = allowed[_from][msg.sender];
// Check is not needed because sub(_allowance, _value) will already throw if this condition is not met
// if (_value > _allowance) throw;
balances[_to] = balances[_to].add(_value);
balances[_from] = balances[_from].sub(_value);
allowed[_from][msg.sender] = _allowance.sub(_value);
Transfer(_from, _to, _value);
}
function approve(address _spender, uint _value) {
allowed[msg.sender][_spender] = _value;
Approval(msg.sender, _spender, _value);
}
function allowance(address _owner, address _spender) constant returns (uint remaining) {
return allowed[_owner][_spender];
}
}
/*
* Ownable
*
* Base contract with an owner.
* Provides onlyOwner modifier, which prevents function from running if it is called by anyone other than the owner.
*/
contract Ownable {
address public owner;
function Ownable() {
owner = msg.sender;
}
modifier onlyOwner() {
if (msg.sender != owner) {
throw;
}
_;
}
function transferOwnership(address newOwner) onlyOwner {
if (newOwner != address(0)) {
owner = newOwner;
}
}
}
contract RKCToken is StandardToken, Ownable {
using SafeMath for uint;
//-------------- Info for ERC20 explorers -----------------//
string public name = "Vamshi Kingdom Coin";
string public symbol = "VKC";
uint public decimals = 18;
//--------------------- Constants ------------------------//
bool public constant TEST_MODE = false;
uint public constant atto = 1000000000000000000;
uint public constant INITIAL_SUPPLY = 15000000 * atto; // 15 mln RKC. Impossible to mint more than this
address public teamWallet = 0xEA018EFd6108d782add96B02f23f682a8019f448;
// Made up ICO address (designating the token pool reserved for ICO, no one has access to it)
address public ico_address = 0x1c01C01C01C01c01C01c01c01c01C01c01c01c01;
uint public constant ICO_START_TIME = 1499810400;
//---------------------- Variables -------------------------//
uint public current_supply = 0; // Holding the number of all the coins in existence
uint public ico_starting_supply = 0; // How many atto tokens *were* available for sale at the beginning of the ICO
uint public current_price_atto_tokens_per_wei = 0; // Holding current price (determined by the algorithm in buy())
//------------- Flags describing ICO stages --------------//
bool public preSoldSharesDistributed = false; // Prevents accidental re-distribution of shares
bool public isICOOpened = true;
bool public isICOClosed = false;
// 3 stages:
// Contract has just been deployed and initialized. isICOOpened == false, isICOClosed == false
// ICO has started, now anybody can buy(). isICOOpened == true, isICOClosed == false
// ICO has finished, now the team can receive the ether. isICOOpened == false, isICOClosed == true
//--------------------- Premiums -------------------------//
uint[] public premiumPacks;
mapping(address => uint) premiumPacksPaid;
//---------------------- Events ---------------------------//
event ICOOpened();
event ICOClosed();
event PriceChanged(uint old_price, uint new_price);
event SupplyChanged(uint supply, uint old_supply);
event RKCAcquired(address account, uint amount_in_wei, uint amount_in_rkc);
// ***************************************************************************
// Constructor
function RKCToken() {
// Some percentage of the tokens is already reserved by early employees and investors
// Here we're initializing their balances
distributePreSoldShares();
// Starting price
current_price_atto_tokens_per_wei = calculateCurrentPrice(1);
// Some other initializations
premiumPacks.length = 0;
}
// Sending ether directly to the contract invokes buy() and assigns tokens to the sender
function () payable {
buy();
}
// ***************************************************************************
// Buy token by sending ether here
//
// Price is being determined by the algorithm in recalculatePrice()
// You can also send the ether directly to the contract address
function buy() payable {
if (msg.value == 0) throw; // no tokens for you
// Only works in the ICO stage, after that the token is going to be traded on the exchanges
if (!isICOOpened) throw;
if (isICOClosed) throw;
// Deciding how many tokens can be bought with the ether received
uint tokens = getAttoTokensAmountPerWeiInternal(msg.value);
// Don't allow to buy more than 1% per transaction (secures from huge investors swalling the whole thing in 1 second)
uint allowedInOneTransaction = current_supply / 100;
if (tokens > allowedInOneTransaction) throw;
// Just in case
if (tokens > balances[ico_address]) throw;
// Transfer from the ICO pool
balances[ico_address] = balances[ico_address].sub(tokens); // if not enough, will throw
balances[msg.sender] = balances[msg.sender].add(tokens);
// Kick the price changing algo
uint old_price = current_price_atto_tokens_per_wei;
current_price_atto_tokens_per_wei = calculateCurrentPrice(getAttoTokensBoughtInICO());
if (current_price_atto_tokens_per_wei == 0) current_price_atto_tokens_per_wei = 1; // in case it is too small that it gets rounded to zero
if (current_price_atto_tokens_per_wei > old_price) current_price_atto_tokens_per_wei = old_price; // in case some weird overflow happens
// Broadcasting price change event
if (old_price != current_price_atto_tokens_per_wei) PriceChanged(old_price, current_price_atto_tokens_per_wei);
// Broadcasting the buying event
RKCAcquired(msg.sender, msg.value, tokens);
}
// Formula for the dynamic price change algorithm
function calculateCurrentPrice(uint attoTokensBought) constant returns (uint result) {
// see http://www.wolframalpha.com/input/?i=f(x)+%3D+395500000+%2F+(x+%2B+150000)+-+136
return (395500000 / ((attoTokensBought / atto) + 150000)).sub(136); // mixing safe and usual math here because the division will throw on inconsistency
}
// ***************************************************************************
// Functions for the contract owner
function openICO() onlyOwner {
if (isICOOpened) throw;
if (isICOClosed) throw;
isICOOpened = true;
ICOOpened();
}
function closeICO() onlyOwner {
if (isICOClosed) throw;
if (!isICOOpened) throw;
isICOOpened = false;
isICOClosed = true;
// Redistribute ICO Tokens that were not bought as the first premiums
premiumPacks.length = 1;
premiumPacks[0] = balances[ico_address];
balances[ico_address] = 0;
ICOClosed();
}
function pullEtherFromContract() onlyOwner {
// Only when ICO is closed
if (!isICOClosed) throw;
if (!teamWallet.send(this.balance)) {
throw;
}
}
// ***************************************************************************
// Some percentage of the tokens is already reserved by early employees and investors
// Here we're initializing their balances
function distributePreSoldShares() onlyOwner {
// Making it impossible to call this function twice
if (preSoldSharesDistributed) throw;
preSoldSharesDistributed = true;
// Values are in atto tokens
balances[0x7A3c869603E28b0242c129440c9dD97F8A5bEe80] = 7508811 * atto;
balances[0x24a541dEAe0Fc87C990A208DE28a293fb2A982d9] = 4025712 * atto;
balances[0xEcF843458e76052E6363fFb78C7535Cd87AA3AB2] = 300275 * atto;
balances[0x947963ED2da750a0712AE0BF96E08C798813F277] = 150000 * atto;
balances[0x82Bc8452Ab76fBA446e16b57C080F5258F557734] = 150000 * atto;
balances[0x0959Ed48d55e580BB58df6E5ee01BAa787d80848] = 90000 * atto;
balances[0x530A8016fB5B3d7A0F92910b4814e383835Bd51E] = 75000 * atto;
balances[0xC3e934D3ADE0Ab9F61F824a9a824462c790e47B0] = 202 * atto;
current_supply = (7508811 + 4025712 + 300275 + 150000 + 150000 + 90000 + 75000 + 202) * atto;
// Sending the rest to ICO pool
balances[ico_address] = INITIAL_SUPPLY.sub(current_supply);
// Initializing the supply variables
ico_starting_supply = balances[ico_address];
current_supply = INITIAL_SUPPLY;
SupplyChanged(0, current_supply);
}
// ***************************************************************************
// Some useful getters (although you can just query the public variables)
function getCurrentPriceAttoTokensPerWei() constant returns (uint result) {
return current_price_atto_tokens_per_wei;
}
function getAttoTokensAmountPerWeiInternal(uint value) payable returns (uint result) {
return value * current_price_atto_tokens_per_wei;
}
function getAttoTokensAmountPerWei(uint value) constant returns (uint result) {
return value * current_price_atto_tokens_per_wei;
}
function getSupply() constant returns (uint result) {
return current_supply;
}
function getAttoTokensLeftForICO() constant returns (uint result) {
return balances[ico_address];
}
function getAttoTokensBoughtInICO() constant returns (uint result) {
return ico_starting_supply - getAttoTokensLeftForICO();
}
function getBalance(address addr) constant returns (uint balance) {
return balances[addr];
}
function getPremiumPack(uint index) constant returns (uint premium) {
return premiumPacks[index];
}
function getPremiumCount() constant returns (uint length) {
return premiumPacks.length;
}
function getBalancePremiumsPaid(address account) constant returns (uint result) {
return premiumPacksPaid[account];
}
// ***************************************************************************
// Premiums
function sendPremiumPack(uint amount) onlyOwner allowedPayments(msg.sender, amount) {
premiumPacks.length += 1;
premiumPacks[premiumPacks.length-1] = amount;
balances[msg.sender] = balances[msg.sender].sub(amount); // will throw and revert the whole thing if doesn't have this amount
}
function updatePremiums(address account) private {
if (premiumPacks.length > premiumPacksPaid[account]) {
uint startPackIndex = premiumPacksPaid[account];
uint finishPackIndex = premiumPacks.length - 1;
for(uint i = startPackIndex; i <= finishPackIndex; i++) {
if (current_supply != 0) { // just in case
uint owing = balances[account] * premiumPacks[i] / current_supply;
balances[account] = balances[account].add(owing);
}
}
premiumPacksPaid[account] = premiumPacks.length;
}
}
// ***************************************************************************
// Overriding payment functions to take control over the logic
modifier allowedPayments(address payer, uint value) {
// Don't allow to transfer coins until the ICO ends
if (isICOOpened) throw;
if (!isICOClosed) throw;
// Limit the quick dump possibility
uint diff = 0;
uint allowed = 0;
if (balances[payer] > current_supply / 100) { // for balances > 1% of total supply
if (block.timestamp > ICO_START_TIME) {
diff = block.timestamp - ICO_START_TIME;
} else {
diff = ICO_START_TIME - block.timestamp;
}
allowed = (current_supply / 20) * (diff / (60 * 60 * 24 * 30)); // 5% unlocked every month
if (value > allowed) throw;
}
_;
}
function transferFrom(address _from, address _to, uint _value) allowedPayments(_from, _value) {
updatePremiums(_from);
updatePremiums(_to);
super.transferFrom(_from, _to, _value);
}
function transfer(address _to, uint _value) onlyPayloadSize(2 * 32) allowedPayments(msg.sender, _value) {
updatePremiums(msg.sender);
updatePremiums(_to);
super.transfer(_to, _value);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment