文件 1 的 9:FloorAccessControlled.sol
pragma solidity >=0.7.5;
import "../interfaces/IFloorAuthority.sol";
abstract contract FloorAccessControlled {
event AuthorityUpdated(IFloorAuthority indexed authority);
string UNAUTHORIZED = "UNAUTHORIZED";
IFloorAuthority public authority;
constructor(IFloorAuthority _authority) {
authority = _authority;
emit AuthorityUpdated(_authority);
}
modifier onlyGovernor() {
require(msg.sender == authority.governor(), UNAUTHORIZED);
_;
}
modifier onlyGuardian() {
require(msg.sender == authority.guardian(), UNAUTHORIZED);
_;
}
modifier onlyPolicy() {
require(msg.sender == authority.policy(), UNAUTHORIZED);
_;
}
modifier onlyVault() {
require(msg.sender == authority.vault(), UNAUTHORIZED);
_;
}
function setAuthority(IFloorAuthority _newAuthority) external onlyGovernor {
authority = _newAuthority;
emit AuthorityUpdated(_newAuthority);
}
}
文件 2 的 9:IDistributor.sol
pragma solidity >=0.7.5;
interface IDistributor {
function distribute() external;
function bounty() external view returns (uint256);
function retrieveBounty() external returns (uint256);
function nextRewardAt(uint256 _rate) external view returns (uint256);
function nextRewardFor(address _recipient) external view returns (uint256);
function setBounty(uint256 _bounty) external;
function addRecipient(address _recipient, uint256 _rewardRate) external;
function removeRecipient(uint256 _index) external;
function setAdjustment(
uint256 _index,
bool _add,
uint256 _rate,
uint256 _target
) external;
}
文件 3 的 9:IERC20.sol
pragma solidity >=0.7.5;
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);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
文件 4 的 9:IFloorAuthority.sol
pragma solidity >=0.7.5;
interface IFloorAuthority {
event GovernorPushed(address indexed from, address indexed to, bool _effectiveImmediately);
event GuardianPushed(address indexed from, address indexed to, bool _effectiveImmediately);
event PolicyPushed(address indexed from, address indexed to, bool _effectiveImmediately);
event VaultPushed(address indexed from, address indexed to, bool _effectiveImmediately);
event GovernorPulled(address indexed from, address indexed to);
event GuardianPulled(address indexed from, address indexed to);
event PolicyPulled(address indexed from, address indexed to);
event VaultPulled(address indexed from, address indexed to);
function governor() external view returns (address);
function guardian() external view returns (address);
function policy() external view returns (address);
function vault() external view returns (address);
}
文件 5 的 9:IgFLOOR.sol
pragma solidity >=0.7.5;
import "./IERC20.sol";
interface IgFLOOR is IERC20 {
function mint(address _to, uint256 _amount) external;
function burn(address _from, uint256 _amount) external;
function index() external view returns (uint256);
function balanceFrom(uint256 _amount) external view returns (uint256);
function balanceTo(uint256 _amount) external view returns (uint256);
}
文件 6 的 9:IsFLOOR.sol
pragma solidity >=0.7.5;
import "./IERC20.sol";
interface IsFLOOR is IERC20 {
function rebase( uint256 floorProfit_, uint epoch_) external returns (uint256);
function circulatingSupply() external view returns (uint256);
function gonsForBalance( uint amount ) external view returns ( uint );
function balanceForGons( uint gons ) external view returns ( uint );
function index() external view returns ( uint );
function toG(uint amount) external view returns (uint);
function fromG(uint amount) external view returns (uint);
function changeDebt(
uint256 amount,
address debtor,
bool add
) external;
function debtBalances(address _address) external view returns (uint256);
}
文件 7 的 9:SafeERC20.sol
pragma solidity >=0.7.5;
import {IERC20} from "../interfaces/IERC20.sol";
library SafeERC20 {
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 amount
) internal {
(bool success, bytes memory data) = address(token).call(
abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, amount)
);
require(success && (data.length == 0 || abi.decode(data, (bool))), "TRANSFER_FROM_FAILED");
}
function safeTransfer(
IERC20 token,
address to,
uint256 amount
) internal {
(bool success, bytes memory data) = address(token).call(
abi.encodeWithSelector(IERC20.transfer.selector, to, amount)
);
require(success && (data.length == 0 || abi.decode(data, (bool))), "TRANSFER_FAILED");
}
function safeApprove(
IERC20 token,
address to,
uint256 amount
) internal {
(bool success, bytes memory data) = address(token).call(
abi.encodeWithSelector(IERC20.approve.selector, to, amount)
);
require(success && (data.length == 0 || abi.decode(data, (bool))), "APPROVE_FAILED");
}
function safeTransferETH(address to, uint256 amount) internal {
(bool success, ) = to.call{value: amount}(new bytes(0));
require(success, "ETH_TRANSFER_FAILED");
}
}
文件 8 的 9:SafeMath.sol
pragma solidity ^0.7.5;
library SafeMath {
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
uint256 c = a / b;
assert(a == b * c + a % b);
return c;
}
function sqrrt(uint256 a) internal pure returns (uint c) {
if (a > 3) {
c = a;
uint b = add( div( a, 2), 1 );
while (b < c) {
c = b;
b = div( add( div( a, b ), b), 2 );
}
} else if (a != 0) {
c = 1;
}
}
}
文件 9 的 9:Staking.sol
pragma solidity ^0.7.5;
import "./libraries/SafeMath.sol";
import "./libraries/SafeERC20.sol";
import "./interfaces/IERC20.sol";
import "./interfaces/IsFLOOR.sol";
import "./interfaces/IgFLOOR.sol";
import "./interfaces/IDistributor.sol";
import "./types/FloorAccessControlled.sol";
contract FloorStaking is FloorAccessControlled {
using SafeMath for uint256;
using SafeERC20 for IERC20;
using SafeERC20 for IsFLOOR;
using SafeERC20 for IgFLOOR;
event DistributorSet(address distributor);
event WarmupSet(uint256 warmup);
struct Epoch {
uint256 length;
uint256 number;
uint256 end;
uint256 distribute;
}
struct Claim {
uint256 deposit;
uint256 gons;
uint256 expiry;
bool lock;
}
IERC20 public immutable FLOOR;
IsFLOOR public immutable sFLOOR;
IgFLOOR public immutable gFLOOR;
Epoch public epoch;
IDistributor public distributor;
mapping(address => Claim) public warmupInfo;
uint256 public warmupPeriod;
uint256 private gonsInWarmup;
constructor(
address _floor,
address _sFLOOR,
address _gFLOOR,
uint256 _epochLength,
uint256 _firstEpochNumber,
uint256 _firstEpochTime,
address _authority
) FloorAccessControlled(IFloorAuthority(_authority)) {
require(_floor != address(0), "Zero address: FLOOR");
FLOOR = IERC20(_floor);
require(_sFLOOR != address(0), "Zero address: sFLOOR");
sFLOOR = IsFLOOR(_sFLOOR);
require(_gFLOOR != address(0), "Zero address: gFLOOR");
gFLOOR = IgFLOOR(_gFLOOR);
epoch = Epoch({length: _epochLength, number: _firstEpochNumber, end: _firstEpochTime, distribute: 0});
}
function stake(
address _to,
uint256 _amount,
bool _rebasing,
bool _claim
) external returns (uint256) {
FLOOR.safeTransferFrom(msg.sender, address(this), _amount);
_amount = _amount.add(rebase());
if (_claim && warmupPeriod == 0) {
return _send(_to, _amount, _rebasing);
} else {
Claim memory info = warmupInfo[_to];
if (!info.lock) {
require(_to == msg.sender, "External deposits for account are locked");
}
warmupInfo[_to] = Claim({
deposit: info.deposit.add(_amount),
gons: info.gons.add(sFLOOR.gonsForBalance(_amount)),
expiry: epoch.number.add(warmupPeriod),
lock: info.lock
});
gonsInWarmup = gonsInWarmup.add(sFLOOR.gonsForBalance(_amount));
return _amount;
}
}
function claim(address _to, bool _rebasing) public returns (uint256) {
Claim memory info = warmupInfo[_to];
if (!info.lock) {
require(_to == msg.sender, "External claims for account are locked");
}
if (epoch.number >= info.expiry && info.expiry != 0) {
delete warmupInfo[_to];
gonsInWarmup = gonsInWarmup.sub(info.gons);
return _send(_to, sFLOOR.balanceForGons(info.gons), _rebasing);
}
return 0;
}
function forfeit() external returns (uint256) {
Claim memory info = warmupInfo[msg.sender];
delete warmupInfo[msg.sender];
gonsInWarmup = gonsInWarmup.sub(info.gons);
FLOOR.safeTransfer(msg.sender, info.deposit);
return info.deposit;
}
function toggleLock() external {
warmupInfo[msg.sender].lock = !warmupInfo[msg.sender].lock;
}
function unstake(
address _to,
uint256 _amount,
bool _trigger,
bool _rebasing
) external returns (uint256 amount_) {
amount_ = _amount;
uint256 bounty;
if (_trigger) {
bounty = rebase();
}
if (_rebasing) {
sFLOOR.safeTransferFrom(msg.sender, address(this), _amount);
amount_ = amount_.add(bounty);
} else {
gFLOOR.burn(msg.sender, _amount);
amount_ = gFLOOR.balanceFrom(amount_).add(bounty);
}
require(amount_ <= FLOOR.balanceOf(address(this)), "Insufficient FLOOR balance in contract");
FLOOR.safeTransfer(_to, amount_);
}
function wrap(address _to, uint256 _amount) external returns (uint256 gBalance_) {
sFLOOR.safeTransferFrom(msg.sender, address(this), _amount);
gBalance_ = gFLOOR.balanceTo(_amount);
gFLOOR.mint(_to, gBalance_);
}
function unwrap(address _to, uint256 _amount) external returns (uint256 sBalance_) {
gFLOOR.burn(msg.sender, _amount);
sBalance_ = gFLOOR.balanceFrom(_amount);
sFLOOR.safeTransfer(_to, sBalance_);
}
function rebase() public returns (uint256) {
uint256 bounty;
if (epoch.end <= block.timestamp) {
sFLOOR.rebase(epoch.distribute, epoch.number);
epoch.end = epoch.end.add(epoch.length);
epoch.number++;
if (address(distributor) != address(0)) {
distributor.distribute();
bounty = distributor.retrieveBounty();
}
uint256 balance = FLOOR.balanceOf(address(this));
uint256 staked = sFLOOR.circulatingSupply();
if (balance <= staked.add(bounty)) {
epoch.distribute = 0;
} else {
epoch.distribute = balance.sub(staked).sub(bounty);
}
}
return bounty;
}
function _send(
address _to,
uint256 _amount,
bool _rebasing
) internal returns (uint256) {
if (_rebasing) {
sFLOOR.safeTransfer(_to, _amount);
return _amount;
} else {
gFLOOR.mint(_to, gFLOOR.balanceTo(_amount));
return gFLOOR.balanceTo(_amount);
}
}
function index() public view returns (uint256) {
return sFLOOR.index();
}
function supplyInWarmup() public view returns (uint256) {
return sFLOOR.balanceForGons(gonsInWarmup);
}
function secondsToNextEpoch() external view returns (uint256) {
return epoch.end.sub(block.timestamp);
}
function setDistributor(address _distributor) external onlyGovernor {
distributor = IDistributor(_distributor);
emit DistributorSet(_distributor);
}
function setWarmupLength(uint256 _warmupPeriod) external onlyGovernor {
warmupPeriod = _warmupPeriod;
emit WarmupSet(_warmupPeriod);
}
}
{
"compilationTarget": {
"contracts/Staking.sol": "FloorStaking"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "none",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_floor","type":"address"},{"internalType":"address","name":"_sFLOOR","type":"address"},{"internalType":"address","name":"_gFLOOR","type":"address"},{"internalType":"uint256","name":"_epochLength","type":"uint256"},{"internalType":"uint256","name":"_firstEpochNumber","type":"uint256"},{"internalType":"uint256","name":"_firstEpochTime","type":"uint256"},{"internalType":"address","name":"_authority","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IFloorAuthority","name":"authority","type":"address"}],"name":"AuthorityUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"distributor","type":"address"}],"name":"DistributorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"warmup","type":"uint256"}],"name":"WarmupSet","type":"event"},{"inputs":[],"name":"FLOOR","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"authority","outputs":[{"internalType":"contract IFloorAuthority","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"bool","name":"_rebasing","type":"bool"}],"name":"claim","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"distributor","outputs":[{"internalType":"contract IDistributor","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"epoch","outputs":[{"internalType":"uint256","name":"length","type":"uint256"},{"internalType":"uint256","name":"number","type":"uint256"},{"internalType":"uint256","name":"end","type":"uint256"},{"internalType":"uint256","name":"distribute","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"forfeit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"gFLOOR","outputs":[{"internalType":"contract IgFLOOR","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"index","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rebase","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sFLOOR","outputs":[{"internalType":"contract IsFLOOR","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"secondsToNextEpoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IFloorAuthority","name":"_newAuthority","type":"address"}],"name":"setAuthority","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_distributor","type":"address"}],"name":"setDistributor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_warmupPeriod","type":"uint256"}],"name":"setWarmupLength","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bool","name":"_rebasing","type":"bool"},{"internalType":"bool","name":"_claim","type":"bool"}],"name":"stake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"supplyInWarmup","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"toggleLock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bool","name":"_trigger","type":"bool"},{"internalType":"bool","name":"_rebasing","type":"bool"}],"name":"unstake","outputs":[{"internalType":"uint256","name":"amount_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"unwrap","outputs":[{"internalType":"uint256","name":"sBalance_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"warmupInfo","outputs":[{"internalType":"uint256","name":"deposit","type":"uint256"},{"internalType":"uint256","name":"gons","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"bool","name":"lock","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"warmupPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"wrap","outputs":[{"internalType":"uint256","name":"gBalance_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]