pragma solidity ^0.4.24; import "../ownership/Ownable.sol"; import "../math/SafeMath.sol"; import "./ElectroGem.sol"; contract ElectroJewel is Ownable { using SafeMath for uint256; string public name = "ElectroJewel"; string public symbol = "JEWEL"; uint public decimals = 18; uint public startTime; //chain start time uint public startBlock; //chain start block number uint public stakeStartTime; //stake start time uint public stakeMinAge = 3 days; // minimum age for coin age: 3D uint public stakeMaxAge = 90 days; //stake age of full weight: 90D uint public maxMintProofOfStake = 10**17; // default 10% annual interest uint public totalSupply; uint public maxTotalSupply; uint public totalInitialSupply; ElectroGem gem; struct transfers{ uint128 amount; uint64 time; } mapping(address => uint256) balances; mapping(address => mapping (address => uint256)) allowed; mapping(address => transfers[]) transferIns; event Burn(address indexed burner, uint256 value); event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed _sender, address indexed _spender, uint256 amount); event Mint(address indexed _sender, uint indexed amount); constructor(address _gem) public { maxTotalSupply = 10**25; // 10 Million totalInitialSupply = 10**24; //1 Million gem = ElectroGem(_gem); startTime = now; startBlock = block.number; balances[msg.sender] = totalInitialSupply; totalSupply = totalInitialSupply; } function transfer(address _to, uint256 _value) public onlyPayloadSize(2 * 32) returns (bool) { require(_to != 0x0, "null recepient address"); require(balances[msg.sender] >= _value, "insufficient balance"); require(balances[_to] + _value > balances[_to], "Overflow detected"); balances[msg.sender] = balances[msg.sender].sub(_value); balances[_to] = balances[_to].add(_value); emit Transfer(msg.sender, _to, _value); if(transferIns[msg.sender].length > 0) delete transferIns[msg.sender]; uint64 _now = uint64(now); transferIns[msg.sender].push(transfers(uint128(balances[msg.sender]),_now)); transferIns[_to].push(transfers(uint128(_value),_now)); return true; } function transferFrom(address _from, address _to, uint256 _value) public onlyPayloadSize(3 * 32) returns (bool) { require(_to != address(0)); uint _allowance = allowed[_from][msg.sender]; // Check is not needed because sub(_allowance, _value) will already throw if this condition is not met // require (_value <= _allowance); balances[_from] = balances[_from].sub(_value); balances[_to] = balances[_to].add(_value); allowed[_from][msg.sender] = _allowance.sub(_value); emit Transfer(_from, _to, _value); if(transferIns[_from].length > 0) delete transferIns[_from]; uint64 _now = uint64(now); transferIns[_from].push(transfers(uint128(balances[_from]),_now)); transferIns[_to].push(transfers(uint128(_value),_now)); return true; } function approve(address _spender, uint256 _value) public returns (bool) { require((_value == 0) || (allowed[msg.sender][_spender] == 0)); allowed[msg.sender][_spender] = _value; emit Approval(msg.sender, _spender, _value); return true; } function allowance(address _owner, address _spender) public view returns (uint256){ return allowed[_owner][_spender]; } function mint() canPoSMint public returns (bool) { if(gem.balanceOf(msg.sender) <= 0) return false; require(gem.checkLogs(msg.sender)); uint reward = getPOSReward(msg.sender); require(reward > 0); totalSupply = totalSupply.add(reward); balances[msg.sender] = balances[msg.sender].add(reward); delete transferIns[msg.sender]; transferIns[msg.sender].push(transfers(uint128(balances[msg.sender]),uint64(now))); emit Mint(msg.sender, reward); return true; } function getBlockNumber() public view returns (uint blockNumber) { blockNumber = block.number.sub(startBlock); } function coinAge() public view returns (uint myCoinAge) { myCoinAge = getCoinAge(msg.sender,now); } function annualInterest() public view returns(uint interest) { uint _now = now; interest = maxMintProofOfStake; if((_now.sub(stakeStartTime)).div(365 days) == 0) { interest = (770 * maxMintProofOfStake).div(100); } else if((_now.sub(stakeStartTime)).div(365 days) == 1){ interest = (435 * maxMintProofOfStake).div(100); } } function getPOSReward(address _addr) internal view returns(uint) { require( (now >= stakeStartTime) && (stakeStartTime > 0)); uint _now = now; uint _coinAge = getCoinAge(_addr, _now); require(_coinAge > 0); uint interest = maxMintProofOfStake; if((_now.sub(stakeStartTime)).div(365 days) == 0) { interest = (770 * maxMintProofOfStake).div(100); } else if((_now.sub(stakeStartTime)).div(365 days) == 1){ interest = (435 * maxMintProofOfStake).div(100); } return (_coinAge * interest).div(365 * (10**decimals)); } function getCoinAge(address _addr, uint _now) internal view returns (uint _coinAge){ require(transferIns[_addr].length > 0); for (uint i = 0; i < transferIns[_addr].length; i++){ if(_now < uint(transferIns[_addr][i].time).add(stakeMinAge)) continue; uint nCoinsSeconds = _now.sub(uint(transferIns[_addr][i].time)); if( nCoinsSeconds > stakeMaxAge ) nCoinsSeconds = stakeMaxAge; _coinAge = _coinAge.add(uint(transferIns[_addr][i].amount) * nCoinsSeconds.div(1 days)); } } function posStartTime(uint _time) public onlyOwner { require((stakeStartTime <= 0) && (_time >= startTime)); stakeStartTime = _time; } /** * @dev fix for the ERC20 short address attack. */ modifier onlyPayloadSize(uint size) { require(msg.data.length >= size + 4); _; } modifier canPoSMint() { require(totalSupply < maxTotalSupply); _; } }
0.4.18