創建一個基於以太坊平台的分紅幣MNC,根據持有的代幣數量,進行分紅的算法。github地址:
https://github.com/lxr1907/MNC
1.使用以太坊根據比例換購token MNC
2.定期根據使用用戶資金購買的礦機挖ETH,打入該合約,觸發分紅方法根據token持有比例分紅
3.衰減,由於礦機有折舊衰減損壞的概率,token會隨着持有時間而衰減。
代碼如下
pragma solidity ^0.4.19; contract owned { address public owner; function owned() public { owner = msg.sender; } modifier onlyOwner { require(msg.sender == owner); _; } function transferOwnership(address newOwner) onlyOwner public { owner = newOwner; } } contract LxrContract is owned{ struct miner{ //MNC余額 uint256 balance; //挖礦份額 uint256 mining; //上一次分紅,衰減日期 uint256 lastDate; //上一次收益 uint256 lastBonus; } //虛擬幣名稱 string public name; //虛擬幣名稱縮寫 string public symbol; //18 decimals 極力推薦使用默認值,盡量別改 uint8 public constant decimals = 18; //和以太坊兌換的匯率 uint32 public ethExchangeRate = 1000; //總發行 uint256 public totalSupply; //創始人保留百分比 uint8 constant ownerInitial=10; //合約擁有者 address public owner; //創建所有賬戶余額數組 mapping (address => miner) public miners; //挖礦需要募集的挖礦資金,100個eth,后續可以增加 uint256 public collectAmountLeft=ethExchangeRate*100; //0.01個ETH起計算挖礦收益 uint256 startMiningMin=ethExchangeRate/100; //挖礦人地址數組 address[] minersArray; //分紅日期 uint256 public bonusTimePoint; //分紅歷史總數 uint256 public bonusTotal; //階段分紅累計數,分紅后清零 uint256 public bonusPeriodCumulative; //每日折舊率千分比,例如每日千分之2,一年后48.15%,3,一年后剩余33%,4一年后23.15% uint16 depreciationRate=3; //每次折舊時間,測試情況下設置為1分鍾以便調試 uint256 depreciationTime=1 minutes; //從挖礦賬戶提現手續費百分比 uint miningDepositFee=30; // 在區塊鏈上創建一個公共事件,它觸發就會通知所有客戶端 event Transfer(address indexed from, address indexed to, uint256 value); event BalanceToMine(address indexed from, uint256 value); event MiningDeposit(address indexed from, uint256 value, uint256 fee); event TransferMining(address indexed from,address indexed to, uint256 value); event Bonus(address indexed to, uint256 value); event Burn(address indexed from, uint256 value); /** * 初始化合約,將最初的令牌中的一部分打入創建者的賬戶中 * @param initialSupply 初始發行量 * @param tokenName 虛擬幣名稱 * @param tokenSymbol 虛擬幣名稱縮寫 */ function LxrContract( uint256 initialSupply, string tokenName, string tokenSymbol ) public { //初始化合約所有人 owner=msg.sender; //合約賬戶余額初始 _mintToken(this,initialSupply-initialSupply * ownerInitial/100); //所有人賬戶余額初始 _mintToken(owner,initialSupply * ownerInitial/100); // 設置顯示名稱 name = tokenName; // 設置顯示縮寫,例如比特幣是BTC symbol = tokenSymbol; //初始化分紅時間點 bonusTimePoint=now/depreciationTime; } /** * 內部轉賬,只能被該合約調用 */ function _transfer(address _from, address _to, uint _value) internal { // 檢查發送者是否擁有足夠的幣 require(miners[_from].balance >= _value); // 檢查越界 require(miners[_to].balance + _value > miners[_to].balance); // 從發送者扣幣 miners[_from].balance -= _value; // 給接收者加相同數量幣 miners[_to].balance += _value; //通知 Transfer(_from, _to, _value); } /** * 賬戶余額兌換挖礦份額 */ function balanceToMining( uint256 _value) public { //檢查挖礦募集剩余 require(collectAmountLeft > 0); require(miners[msg.sender].balance > 0); uint256 effectValue=_value; //傳0或不傳則所有余額兌換挖礦份額 if(effectValue==0){ effectValue=miners[msg.sender].balance/(10**uint256(decimals)); } // 檢查越界 require(miners[msg.sender].mining + effectValue > miners[msg.sender].mining); // 檢查發送者是否擁有足夠的幣 if(miners[msg.sender].balance < effectValue){ effectValue=miners[msg.sender].balance/(10**uint256(decimals)); } //檢查挖礦募集剩余是否足夠,不足只轉一部分 if(collectAmountLeft < _value){ effectValue=collectAmountLeft; } //賬戶ETH余額不足,無法投資 if(this.balance<effectValue* 10 ** uint256(decimals)/ethExchangeRate){ return; } //如果不存在,將該挖礦地址加入數組,用於以后遍歷訪問 addToMinersArray(msg.sender); // 從余額銷毀 burn(msg.sender,effectValue); // 給挖礦賬戶加相同數量幣 miners[msg.sender].mining += effectValue* 10 ** uint256(decimals); //募集剩余資金減少 collectAmountLeft -=effectValue; //將挖礦所需以太坊轉到擁有者賬戶,以便所有者使用這些eth購買礦機挖礦 owner.transfer(effectValue* 10 ** uint256(decimals)/ethExchangeRate); //通知 BalanceToMine(msg.sender, effectValue); } /** * * 將挖礦份額轉換為賬戶余額,需要按百分比支付手續費 * * @param _value 提出金額 */ function miningDeposit( uint256 _value) public { uint depositFee=_value* 10 ** uint256(decimals)*miningDepositFee/100; uint depositValue=_value* 10 ** uint256(decimals); // 檢查發送者是否擁有足夠的幣 require(miners[msg.sender].mining >= depositValue); // 檢查越界 require(miners[msg.sender].balance + depositValue > miners[msg.sender].balance); // 從挖礦余額扣除 miners[msg.sender].mining -= depositValue; //挖礦余額剩余為0,全部提現,則時間重置 if(miners[msg.sender].mining==0){ miners[msg.sender].lastDate=0; } //給賬戶加相同數量幣,扣除一定百分比手續費 miners[msg.sender].balance += depositValue-depositFee; //將手續費支付給合約管理員 miners[owner].balance += depositFee; //通知 MiningDeposit(msg.sender, depositValue,depositFee); } //將該挖礦地址加入數組 function addToMinersArray(address _miner) internal{ //如果不存在,將該挖礦地址加入數組,用於以后遍歷訪問 bool hasAdd=false; for (uint i = 0; i < minersArray.length; i++) { if(minersArray[i]==_miner){ hasAdd=true; break; } } if(!hasAdd){ minersArray.push(_miner); } } /** * 將挖礦份額轉讓 */ function transferMining(address _to, uint256 _value) public { // 檢查發送者是否擁有足夠的幣 require(miners[msg.sender].mining >= _value); // 檢查越界 require(miners[_to].mining + _value > miners[_to].mining); //將該挖礦地址加入數組 addToMinersArray(_to); // 從發送者扣幣 miners[msg.sender].mining -= _value; // 給接收者加相同數量幣 miners[_to].mining += _value; TransferMining(msg.sender,_to, _value); } /** *計算總挖礦份額 */ function getMiningAmountTotal() public view returns ( uint256 _totalMinigAmount){ for (uint i = 0; i < minersArray.length; i++) { uint256 miningAmount = miners[minersArray[i]].mining; _totalMinigAmount += miningAmount; } _totalMinigAmount=_totalMinigAmount/(10**uint256(decimals)); } /** *根據挖礦份額給每個人分紅 ,匿名方法,直接轉賬觸發 * bonusMNCtoMiner */ function () payable public { //階段收益MNC bonusPeriodCumulative += msg.value*ethExchangeRate; require(bonusPeriodCumulative>0); //該階段已經分紅過,只累加分紅數量 if(bonusTimePoint>=now/depreciationTime){ return; } //更新分紅時間點 bonusTimePoint=now/depreciationTime; uint256 totalMinigAmount=getMiningAmountTotal(); if(totalMinigAmount==0){ return; } //加發行量 _mintToken(this,bonusPeriodCumulative/(10**uint256(decimals))); //總歷史收益增加 bonusTotal += bonusPeriodCumulative; //計算每個人的收益 for (uint i = 0; i < minersArray.length; i++) { uint256 miningAmount = miners[minersArray[i]].mining/(10**uint256(decimals)); if(miningAmount<startMiningMin){ continue; } //礦機折舊衰減 if(miners[minersArray[i]].lastDate==0){ //第一次不折舊,記錄時間 miners[minersArray[i]].lastDate=now/depreciationTime; //第一次也不分紅 continue; }else{ //計算出衰減段數 uint256 depreciationPeriods=now/depreciationTime-miners[minersArray[i]].lastDate; //每段衰減一次 for(uint m=0;m<depreciationPeriods;m++) miners[minersArray[i]].mining=miners[minersArray[i]].mining* (1000-depreciationRate)/1000; //更新時間 miners[minersArray[i]].lastDate=now/depreciationTime; } //分紅數量 uint256 oneBonus = bonusPeriodCumulative*miningAmount/totalMinigAmount; miners[minersArray[i]].lastBonus=oneBonus; } //階段收益清零 bonusPeriodCumulative=0; //發放收益 for (uint j = 0; j < minersArray.length; j++) { bonusToken(minersArray[j]); } } /** *獎勵挖礦收益MNC * */ function bonusToken(address _to) internal{ miners[_to].balance+= miners[_to].lastBonus ; Bonus(_to, miners[_to].lastBonus*(10**uint256(decimals))); } /** * 發送MNC * * 從你的賬戶發送個`_value` 令牌到 `_to` * * @param _to 接收地址 * @param _value 發送數量 */ function transfer(address _to, uint256 _value) public { _transfer(msg.sender, _to, _value); } /** *增發MNC * */ function _mintToken(address _to, uint256 mintedAmount) internal{ totalSupply += mintedAmount*(10**uint256(decimals)); miners[_to].balance+= mintedAmount*(10**uint256(decimals)); Transfer(0, _to, mintedAmount*(10**uint256(decimals))); } //增發MNC function MintToken( uint256 mintedAmount) onlyOwner public{ _mintToken(this,mintedAmount); } /** *銷毀MNC * */ function burn( address _from,uint256 mintedAmount) internal{ totalSupply -= mintedAmount*(10**uint256(decimals)); miners[_from].balance-= mintedAmount*(10**uint256(decimals)); Burn(_from, mintedAmount*(10**uint256(decimals))); } /** * *增加募集金額 * @param amount 需要的MNC數量 */ function addCollection( uint256 amount) onlyOwner public{ collectAmountLeft += amount; } /// 使用以太坊購買token function buy() payable public { uint amount = msg.value; //合約余額充足 require(miners[this].balance>=amount * ethExchangeRate); _transfer( this,msg.sender, amount * ethExchangeRate); } //出售token換回以太坊 function sell(uint256 amount) public { _transfer(msg.sender, this, amount* 10 ** uint256(decimals)); msg.sender.transfer(amount* 10 ** uint256(decimals)/ethExchangeRate); } //調整和以太坊的兌換比例 function setEthMncRate(uint32 _rate) onlyOwner public{ //調整幅度限制到原價20% require(_rate>ethExchangeRate*8/10); require(_rate<ethExchangeRate*12/10); ethExchangeRate=_rate; } //折舊率千分比調整 function setDepreciationRate(uint16 _rate) onlyOwner public{ //調整幅度限制到100% require(_rate>depreciationRate/2); require(_rate<depreciationRate*2); require(_rate<1000); depreciationRate=_rate; } //折舊時間調整 function setDepreciationTime(uint8 _rate) onlyOwner public{ require(_rate!=0); //天數 depreciationTime=_rate*1 days; //初始化分紅時間點 bonusTimePoint=now/depreciationTime; } //-------------------------------------------一下為調試方法 //獲取當前分紅時間 function getBonusTimeNow() public view returns(uint256 _time){ _time= now/depreciationTime; } /** * *獲取合約余額 */ function getContractBalance( ) public view returns (uint _contractBalance,uint _ethBanlance){ _contractBalance=miners[this].balance/(10**uint256(decimals)); _ethBanlance=this.balance/(10**uint256(decimals)); } /** * *獲取我的余額 */ function getMyBalance( ) public view returns (uint _myBalance,uint _myMining,uint _lastBonus,uint _date){ _myBalance=miners[msg.sender].balance/(10**uint256(decimals)); _myMining=miners[msg.sender].mining/(10**uint256(decimals)); _lastBonus=miners[msg.sender].lastBonus/(10**uint256(decimals)); _date=miners[msg.sender].lastDate; } }
給我的ETH捐贈地址:0xdc834D429b3098f0568Af873c2d73b08790BF677