编译器
0.4.26+commit.4563c3fc
文件 1 的 5:ApproveAndCallFallback.sol
pragma solidity 0.4.26;
interface ApproveAndCallFallBack {
function receiveApproval(address from, uint256 tokens, address token, bytes data) external;
}
文件 2 的 5:IERC20.sol
interface ERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address who) external view returns (uint256);
function allowance(address owner, address spender) external view returns (uint256);
function transfer(address to, uint256 value) external returns (bool);
function approve(address spender, uint256 value) external returns (bool);
function approveAndCall(address spender, uint tokens, bytes data) external returns (bool success);
function transferFrom(address from, address to, uint256 value) external returns (bool);
function burn(uint256 amount) external;
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
文件 3 的 5:SafeMath.sol
library SafeMath {
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b);
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a / b;
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a);
return a - b;
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a);
return c;
}
function ceil(uint256 a, uint256 m) internal pure returns (uint256) {
uint256 c = add(a,m);
uint256 d = sub(c,1);
return mul(div(d,m),m);
}
}
文件 4 的 5:SignedSafeMath.sol
pragma solidity 0.4.26;
library SignedSafeMath {
int256 constant private _INT256_MIN = -2**255;
function mul(int256 a, int256 b) internal pure returns (int256) {
if (a == 0) {
return 0;
}
require(!(a == -1 && b == _INT256_MIN), "SignedSafeMath: multiplication overflow");
int256 c = a * b;
require(c / a == b, "SignedSafeMath: multiplication overflow");
return c;
}
function div(int256 a, int256 b) internal pure returns (int256) {
require(b != 0, "SignedSafeMath: division by zero");
require(!(b == -1 && a == _INT256_MIN), "SignedSafeMath: division overflow");
int256 c = a / b;
return c;
}
function sub(int256 a, int256 b) internal pure returns (int256) {
int256 c = a - b;
require((b >= 0 && c <= a) || (b < 0 && c > a), "SignedSafeMath: subtraction overflow");
return c;
}
function add(int256 a, int256 b) internal pure returns (int256) {
int256 c = a + b;
require((b >= 0 && c >= a) || (b < 0 && c < a), "SignedSafeMath: addition overflow");
return c;
}
}
文件 5 的 5:staking.sol
pragma solidity 0.4.26;
import "./IERC20.sol";
import "./SafeMath.sol";
import "./SignedSafeMath.sol";
import "./ApproveAndCallFallback.sol";
contract MeridianInterface is ERC20{
function owner() external returns(address);
}
contract MeridianStaking is ApproveAndCallFallBack{
using SafeMath for uint;
using SignedSafeMath for int;
MeridianInterface public meridianToken;
mapping(address => uint256) public amountStaked;
mapping(address => int256) public payoutsTo;
mapping(address => uint256) public payoutsToTime;
mapping(address => uint256) public unclaimedDividends;
mapping(address => uint256) public dividendCheckpoints;
mapping(address => uint256) public dividendRateUsed;
uint256 public stakedTotalSum;
uint256 public divsPerShare;
uint256 constant internal magnitude = 2 ** 64;
uint256 constant internal STAKING_MINIMUM = 100 * (10 ** 18);
uint256 public STAKING_PERIOD = 1 days;
uint256 public BURN_RATE = 100;
uint public STAKE_DIV_FEE = 50;
uint256 public DIVIDEND_RATE = 10;
bool public activated = false;
uint256 public contractEndTime=0;
uint256 public nowTest=now;
event Stake(address indexed user, uint256 amount);
event UnStake(address indexed user, uint256 amount);
event WithdrawDivs(address indexed user, uint256 amount);
event ReStakeDivs(address indexed user, uint256 amount);
modifier isAdmin() {
require(msg.sender==meridianToken.owner(),"user is not admin");
_;
}
modifier isActive() {
require(activated,"staking is not yet active");
_;
}
constructor(address token) public{
meridianToken=MeridianInterface(token);
}
function setRates(uint burn,uint div,uint unstake) public isAdmin{
BURN_RATE=burn;
DIVIDEND_RATE=div;
STAKE_DIV_FEE=unstake;
}
function activateContract() public isAdmin{
activated=true;
}
function burnAfterContractEnd() public isAdmin{
meridianToken.burn(meridianToken.balanceOf(address(this)));
}
function disableDividendAccumulation() public isAdmin{
contractEndTime=now;
}
function receiveApproval(address fromAddr, uint256 tokens, address token, bytes data) external{
require(msg.sender==address(meridianToken));
require(meridianToken.transferFrom(fromAddr,address(this),tokens),"transfer failed");
_stake(tokens,fromAddr);
}
function _stake(uint256 amount,address fromAddr) private isActive{
require(amountStaked[fromAddr].add(amount) >= STAKING_MINIMUM,"amount below staking minimum");
updateCheckpoint(fromAddr,true);
stakedTotalSum = stakedTotalSum.add(amount);
amountStaked[fromAddr] = amountStaked[fromAddr].add(amount);
payoutsTo[fromAddr] = payoutsTo[fromAddr].add(int256(amount.mul(divsPerShare)));
emit Stake(fromAddr, amount);
}
function unstake(uint256 amount) public isActive{
require(amountStaked[msg.sender] >= amount);
updateCheckpoint(msg.sender,true);
uint256 divPortion=amount.mul(STAKE_DIV_FEE).div(1000);
uint256 burnPortion=amount.mul(BURN_RATE).div(1000);
uint256 unstakeFee = divPortion.add(burnPortion);
divsPerShare = divsPerShare.add(divPortion.mul(magnitude).div(stakedTotalSum));
stakedTotalSum = stakedTotalSum.sub(amount);
uint256 taxedAmount = amount.sub(unstakeFee);
amountStaked[msg.sender] = amountStaked[msg.sender].sub(amount);
payoutsTo[msg.sender] = payoutsTo[msg.sender].sub(int256(amount.mul(divsPerShare)));
meridianToken.burn(burnPortion);
meridianToken.transfer(msg.sender,taxedAmount);
emit UnStake(msg.sender, amount);
}
function withdrawDivs() public isActive{
updateCheckpoint(msg.sender,false);
uint256 burnedDivs = getBurnedDivs(msg.sender);
payoutsTo[msg.sender] = payoutsTo[msg.sender].add(int256(burnedDivs.mul(magnitude)));
uint256 timeDivs=getTotalDivsOverTime(msg.sender);
payoutsToTime[msg.sender] = payoutsToTime[msg.sender].add(timeDivs);
uint256 baseDivs=burnedDivs.add(timeDivs);
uint256 burnFee=baseDivs.mul(BURN_RATE).div(1000);
uint256 divs=baseDivs.sub(burnFee);
meridianToken.burn(burnFee);
meridianToken.transfer(msg.sender,divs);
emit WithdrawDivs(msg.sender, divs);
}
function reinvestDivs() public isActive{
updateCheckpoint(msg.sender,false);
uint256 burnedDivs = getBurnedDivs(msg.sender);
payoutsTo[msg.sender] = payoutsTo[msg.sender].add(int256(burnedDivs.mul(magnitude)));
uint256 timeDivs=getTotalDivsOverTime(msg.sender);
payoutsToTime[msg.sender] = payoutsToTime[msg.sender].add(timeDivs);
uint256 divs=burnedDivs.add(timeDivs);
_stake(divs,msg.sender);
emit ReStakeDivs(msg.sender, divs);
}
function getDividends(address user) public view returns(uint256){
return getBurnedDivs(user).add(getTotalDivsOverTime(user));
}
function getBurnedDivs(address user) public view returns(uint256){
if(int256(divsPerShare.mul(amountStaked[user])) < payoutsTo[user]){
return 0;
}
else{
return uint256(int256(divsPerShare.mul(amountStaked[user])).sub(payoutsTo[user])).div(magnitude);
}
}
function updateCheckpoint(address user,bool updateRate) private{
unclaimedDividends[user]=unclaimedDividends[user].add(getNewDivsOverTime(user));
dividendCheckpoints[user]=getNow();
if(updateRate){
dividendRateUsed[user]=DIVIDEND_RATE;
}
}
function getTotalDivsSubWithdrawFee(address user) external view returns(uint256){
uint256 baseDivs=getDividends(user);
uint256 fee=baseDivs.mul(BURN_RATE).div(1000).add(baseDivs.mul(STAKE_DIV_FEE).div(1000));
return baseDivs.sub(fee);
}
function getTotalDivsOverTime(address user) public view returns(uint256){
return unclaimedDividends[user].add(getNewDivsOverTime(user)).sub(payoutsToTime[user]);
}
function getNewDivsOverTime(address user) public view returns(uint256){
return getNow().sub(dividendCheckpoints[user]).mul(amountStaked[user]).mul(dividendRateUsed[user]).div(STAKING_PERIOD.mul(1000));
}
function getNow() public view returns(uint256){
if(contractEndTime>0 && now>contractEndTime){
return contractEndTime;
}
else{
return now;
}
}
}
{
"compilationTarget": {
"staking.sol": "MeridianStaking"
},
"evmVersion": "byzantium",
"libraries": {},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"constant":true,"inputs":[],"name":"STAKING_PERIOD","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"unclaimedDividends","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"payoutsTo","outputs":[{"name":"","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"meridianToken","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"activated","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"payoutsToTime","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"dividendRateUsed","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"amount","type":"uint256"}],"name":"unstake","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"dividendCheckpoints","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"divsPerShare","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"user","type":"address"}],"name":"getDividends","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"reinvestDivs","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"nowTest","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"user","type":"address"}],"name":"getTotalDivsSubWithdrawFee","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"user","type":"address"}],"name":"getNewDivsOverTime","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"fromAddr","type":"address"},{"name":"tokens","type":"uint256"},{"name":"token","type":"address"},{"name":"data","type":"bytes"}],"name":"receiveApproval","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"activateContract","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"withdrawDivs","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"STAKE_DIV_FEE","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"DIVIDEND_RATE","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"contractEndTime","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNow","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"user","type":"address"}],"name":"getTotalDivsOverTime","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"burn","type":"uint256"},{"name":"div","type":"uint256"},{"name":"unstake","type":"uint256"}],"name":"setRates","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"stakedTotalSum","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"disableDividendAccumulation","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"amountStaked","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"burnAfterContractEnd","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"user","type":"address"}],"name":"getBurnedDivs","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"BURN_RATE","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"token","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"user","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"Stake","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"user","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"UnStake","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"user","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"WithdrawDivs","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"user","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"ReStakeDivs","type":"event"}]