账户
0xed...bc13
0xEd...Bc13

0xEd...Bc13

$500
此合同的源代码已经过验证!
合同元数据
编译器
0.7.5+commit.eb77ed08
语言
Solidity
合同源代码
文件 1 的 1:ss.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <0.8.0;

/**
 * @title SafeMath
 * @dev Math operations with safety checks that throw on error
 */
library SafeMath {

  function mul(uint a, uint b) internal pure returns (uint c) {
    // Gas optimization: this is cheaper than asserting 'a' not being zero, but the
    // benefit is lost if 'b' is also tested.
    // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
    if (a == 0) {
      return 0;
    }

    c = a * b;
    assert(c / a == b);
    return c;
  }

  function div(uint a, uint b) internal pure returns (uint) {
    // assert(b > 0); // Solidity automatically throws when dividing by 0
    // uint c = a / b;
    // assert(a == b * c + a % b); // There is no case in which this doesn't hold
    return a / b;
  }

  function sub(uint a, uint b) internal pure returns (uint) {
    assert(b <= a);
    return a - b;
  }

  function add(uint a, uint b) internal pure returns (uint c) {
    c = a + b;
    assert(c >= a);
    return c;
  }
}

pragma solidity >=0.6.2 <0.8.0;

/**
 * @dev Collection of functions related to the address type
 */
library Address {

    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        // solhint-disable-next-line no-inline-assembly
        assembly { size := extcodesize(account) }
        return size > 0;
    }

    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
        (bool success, ) = recipient.call{ value: amount }("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
      return functionCall(target, data, "Address: low-level call failed");
    }

    function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.call{ value: value }(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.staticcall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {

    function totalSupply() external view returns (uint256);

    function balanceOf(address account) external view returns (uint256);

    function transfer(address recipient, uint256 amount) external returns (bool);

    function allowance(address owner, address spender) external view returns (uint256);

    function approve(address spender, uint256 amount) external returns (bool);

    function transferFrom(address sender, address recipient, uint256 amount) 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);
}

pragma solidity >=0.6.0 <0.8.0;

contract Staking {

  using SafeMath for uint;

  IERC20 public stakingToken;                       //staking Token
  uint public rewardAmount;                         //Amount that is paid for staking 1 second
  uint public oneUnit;                              //Amount that is calculated as unit
  uint public stakeFee;                             //fee in 0.01%
  uint public unstakeFee;                           //fee in 0.01%
  uint internal amountForRewards;                   //Amount deposited for rewards
  uint internal amountClaimed;                      //Amount claimed for rewards
  uint internal amountFees;                         //Amount of fees collected
  uint internal amountBurned;                       //Amount of fees burned
  mapping (address => uint) internal stakedAmounts;
  mapping (address => uint) internal lastClaims;
  mapping (address => uint) internal claimableAmounts;
  mapping (address => uint) internal claimedAmounts;
  mapping (address => uint) internal admins;

  event Stake(
    address indexed owner,
    uint amount,
    uint fee
  );

  event Unstake(
    address indexed owner,
    uint amount,
    uint fee
  );

  event Claimed(
    address indexed owner,
    uint amount
  );

  event Compound(
    address indexed owner,
    uint amount,
    uint fee
  );

  constructor(
    address __stakingToken,
    uint __rewardAmount,
    uint __oneUnit,
    uint __stakeFee,
    uint __unstakeFee
  ) {
    require(Address.isContract(__stakingToken), "Error: Address should be a contract");
    stakingToken = IERC20(__stakingToken);

    rewardAmount = __rewardAmount;
    oneUnit = __oneUnit;
    stakeFee = __stakeFee;
    unstakeFee = __unstakeFee;
    amountForRewards = 0;
    amountClaimed = 0;
    amountFees = 0;
    amountBurned = 0;

    admins[msg.sender] = block.timestamp;
  }

  function isAdmin(address __address) view public returns(bool) {
    if (admins[__address] > 0) {
        return (true);
    }
    return (false);
  }

  function addAdmin(address __address) external onlyAdmin {
    require(__address != address(0), "Error: new admin is the zero address");
    admins[__address] = block.timestamp;
  }

  function fund(uint __amount) external onlyAdmin {
    require(__amount > 0, "You are trying to fund with 0 assets");

    stakingToken.transferFrom(msg.sender, address(this), __amount);
    amountForRewards = amountForRewards.add(__amount);
  }

  function burn() external onlyAdmin {
      require(amountFees.sub(amountBurned) > 0, "Error: you are trying to burn all tokens");
      stakingToken.burn(amountFees.sub(amountBurned));
      amountBurned = amountFees;
  }

  function balance() view public returns(uint, uint, int, uint, uint) {
    return (amountForRewards, amountClaimed, int(amountForRewards - amountClaimed), amountFees, amountBurned);
  }

  function deleteAdmin(address __address) external onlyAdmin {
    admins[__address] = 0;
  }

  modifier onlyAdmin() {
    require(admins[msg.sender] > 0, "Error: caller is not the admin");
    _;
  }

  function isStaker(address __address) view public returns(bool, uint, uint, uint, uint) {
    if (stakedAmounts[__address] == 0) {
      return (false, 0, 0, 0, 0);
    }
    uint __claimableAmount = claimableAmounts[__address].add(stakedAmounts[__address].div(oneUnit).mul(block.timestamp.sub(lastClaims[__address])).mul(rewardAmount));
    return (true, stakedAmounts[__address], lastClaims[__address], __claimableAmount, claimedAmounts[__address]);
  }

  function update(address __address, uint __stakedAmount, uint __lastClaim, uint __claimableAmount, uint __claimedAmount) private {
    if (stakedAmounts[__address] != __stakedAmount) {
      stakedAmounts[__address] = __stakedAmount;
    }
    if (lastClaims[__address] != __lastClaim) {
      lastClaims[__address] = __lastClaim;
    }
    if (claimableAmounts[__address] != __claimableAmount) {
      claimableAmounts[__address] = __claimableAmount;
    }
    if (__claimedAmount > 0 && claimedAmounts[__address] != __claimedAmount) {
      claimedAmounts[__address] = __claimedAmount;
    }
  }

  function claim() external {
    (bool __isStaker, uint __stakedAmount, , uint __claimableAmount, uint __claimedAmount) = isStaker(msg.sender);
    require(__isStaker == true, "Error: you are not staking");

    update(msg.sender, __stakedAmount, block.timestamp, 0, __claimedAmount.add(__claimableAmount));
    amountClaimed = amountClaimed.add(__claimableAmount);

    stakingToken.transfer(msg.sender, __claimableAmount);
    emit Claimed(msg.sender, __claimableAmount);
  }

  function compound() external {
    (bool __isStaker, uint __stakedAmount, , uint __claimableAmount, uint __claimedAmount) = isStaker(msg.sender);
    require(__isStaker == true, "Error: you are not staking");

    uint __fee = __claimableAmount.mul(stakeFee).div(10000);
    uint __stakeAmount = __claimableAmount.sub(__fee);

    update(msg.sender, __stakedAmount.add(__stakeAmount), block.timestamp, 0, __claimedAmount.add(__claimableAmount));

    amountClaimed = amountClaimed.add(__claimableAmount);
    amountFees = amountFees.add(__fee);

    emit Compound(msg.sender, __stakeAmount, __fee);
  }

  function stake(uint __amount) external {
    require(__amount > 0, "Error: you are trying to stake 0 tokens");
    stakingToken.transferFrom(msg.sender, address(this), __amount);

    (bool __isStaker, uint __stakedAmount, , uint __claimableAmount, ) = isStaker(msg.sender);
    uint __fee = __amount.mul(stakeFee).div(10000);
    uint __stakeAmount = __amount.sub(__fee);

    if (__isStaker) {
      update(msg.sender, __stakedAmount.add(__stakeAmount), block.timestamp, __claimableAmount, 0);
    } else {
      update(msg.sender, __stakeAmount, block.timestamp, 0, 0);
    }

    amountFees = amountFees.add(__fee);
    emit Stake(msg.sender, __stakeAmount, __fee);
  }

  function unstake() external {
    (bool __isStaker, uint __stakedAmount, , uint __claimableAmount, uint __claimedAmount) = isStaker(msg.sender);
    require(__isStaker == true, "Error: you are not staking");

    uint __fee = __stakedAmount.mul(unstakeFee).div(10000);
    uint __unstakeAmount = __stakedAmount.sub(__fee).add(__claimableAmount);

    update(msg.sender, 0, block.timestamp, 0, __claimedAmount.add(__claimableAmount));

    amountClaimed = amountClaimed.sub(__claimableAmount);
    amountFees = amountFees.add(__fee);

    stakingToken.transfer(msg.sender, __unstakeAmount);
    emit Unstake(msg.sender, __unstakeAmount, __fee);
  }

  function transferStake(address __to, uint __amount) external {
    (bool __isStaker, uint __stakedAmount, , uint __claimableAmount, ) = isStaker(msg.sender);
    require(__isStaker == true, "Error: you are not staking");
    require(__to != address(0), "Error: new owner is the zero address");
    require(__stakedAmount > __amount, "Error: you are trying to transfer more then you have");
    if (__amount == 0) {
        __amount = __stakedAmount;
    }

    update(msg.sender, __stakedAmount.add(__amount), block.timestamp, __claimableAmount, 0);

    (__isStaker, __stakedAmount, , __claimableAmount, ) = isStaker(__to);
    update(__to, __stakedAmount.add(__amount), block.timestamp, __claimableAmount, 0);
  }

}
设置
{
  "compilationTarget": {
    "browser/ss.sol": "Staking"
  },
  "evmVersion": "istanbul",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "optimizer": {
    "enabled": false,
    "runs": 200
  },
  "remappings": []
}
ABI
[{"inputs":[{"internalType":"address","name":"__stakingToken","type":"address"},{"internalType":"uint256","name":"__rewardAmount","type":"uint256"},{"internalType":"uint256","name":"__oneUnit","type":"uint256"},{"internalType":"uint256","name":"__stakeFee","type":"uint256"},{"internalType":"uint256","name":"__unstakeFee","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"Compound","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"Stake","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"Unstake","type":"event"},{"inputs":[{"internalType":"address","name":"__address","type":"address"}],"name":"addAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"balance","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"int256","name":"","type":"int256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"compound","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"__address","type":"address"}],"name":"deleteAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"__amount","type":"uint256"}],"name":"fund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"__address","type":"address"}],"name":"isAdmin","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"__address","type":"address"}],"name":"isStaker","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oneUnit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"__amount","type":"uint256"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakeFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stakingToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"__to","type":"address"},{"internalType":"uint256","name":"__amount","type":"uint256"}],"name":"transferStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unstakeFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]