Untitled diff

Created Diff never expires
57 removals
Words removed136
Total words799
Words removed (%)17.02
255 lines
46 additions
Words added64
Total words727
Words added (%)8.80
243 lines
contract ShareWrapper {
contract ShareWrapper {
using SafeMath for uint256;
using SafeMath for uint256;
using SafeERC20 for IERC20;
using SafeERC20 for IERC20;


IERC20 public share;
IERC20 public share;


uint256 private _totalSupply;
uint256 private _totalSupply;
mapping(address => uint256) private _balances;
mapping(address => uint256) private _balances;


function totalSupply() public view returns (uint256) {
function totalSupply() public view returns (uint256) {
return _totalSupply;
return _totalSupply;
}
}


function balanceOf(address account) public view returns (uint256) {
function balanceOf(address account) public view returns (uint256) {
return _balances[account];
return _balances[account];
}
}


function stake(uint256 amount) public virtual {
function stake(uint256 amount) public virtual {
_totalSupply = _totalSupply.add(amount);
_totalSupply = _totalSupply.add(amount);
_balances[msg.sender] = _balances[msg.sender].add(amount);
_balances[msg.sender] = _balances[msg.sender].add(amount);
share.safeTransferFrom(msg.sender, address(this), amount);
share.safeTransferFrom(msg.sender, address(this), amount);
}
}


function withdraw(uint256 amount) public virtual {
function withdraw(uint256 amount) public virtual {
uint256 masonShare = _balances[msg.sender];
uint256 masonUserShare = _balances[msg.sender];
require(masonShare >= amount, "Masonry: withdraw request greater than staked amount");
require(masonUserShare >= amount, "Masonry: withdraw request greater than staked amount");
_totalSupply = _totalSupply.sub(amount);
_totalSupply = _totalSupply.sub(amount);
_balances[msg.sender] = masonShare.sub(amount);
_balances[msg.sender] = masonUserShare.sub(amount);
share.safeTransfer(msg.sender, amount);
share.safeTransfer(msg.sender, amount);
}
}
}
}


/*
contract Masonry is ShareWrapper, ContractGuard, Operator {
______ __ _______
/_ __/___ ____ ___ / /_ / ____(_)___ ____ _____ ________
/ / / __ \/ __ `__ \/ __ \ / /_ / / __ \/ __ `/ __ \/ ___/ _ \
/ / / /_/ / / / / / / /_/ / / __/ / / / / / /_/ / / / / /__/ __/
/_/ \____/_/ /_/ /_/_.___/ /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/

http://tomb.finance
*/
contract Masonry is ShareWrapper, ContractGuard {
using SafeERC20 for IERC20;
using SafeERC20 for IERC20;
using Address for address;
using Address for address;
using SafeMath for uint256;
using SafeMath for uint256;


/* ========== DATA STRUCTURES ========== */
/* ========== DATA STRUCTURES ========== */


struct Masonseat {
struct MasonSeat {
uint256 lastSnapshotIndex;
uint256 lastSnapshotIndex;
uint256 rewardEarned;
uint256 rewardEarned;
uint256 epochTimerStart;
uint256 epochTimerStart;
}
}


struct MasonrySnapshot {
struct MasonrySnapshot {
uint256 time;
uint256 time;
uint256 rewardReceived;
uint256 rewardReceived;
uint256 rewardPerShare;
uint256 rewardPerShare;
}
}


/* ========== STATE VARIABLES ========== */
/* ========== STATE VARIABLES ========== */


// governance
address public operator;

// flags
// flags
bool public initialized = false;
bool public initialized = false;


IERC20 public tomb;
IERC20 public hog;
ITreasury public treasury;
ITreasury public treasury;


mapping(address => Masonseat) public masons;
mapping(address => MasonSeat) public masons;
MasonrySnapshot[] public masonryHistory;
MasonrySnapshot[] public masonryHistory;


uint256 public withdrawLockupEpochs;
uint256 public withdrawLockupEpochs;
uint256 public rewardLockupEpochs;
uint256 public rewardLockupEpochs;


/* ========== EVENTS ========== */
/* ========== EVENTS ========== */


event Initialized(address indexed executor, uint256 at);
event Initialized(address indexed executor, uint256 at);
event Staked(address indexed user, uint256 amount);
event Staked(address indexed user, uint256 amount);
event Withdrawn(address indexed user, uint256 amount);
event Withdrawn(address indexed user, uint256 amount);
event RewardPaid(address indexed user, uint256 reward);
event RewardPaid(address indexed user, uint256 reward);
event RewardAdded(address indexed user, uint256 reward);
event RewardAdded(address indexed user, uint256 reward);


/* ========== Modifiers =============== */
/* ========== Modifiers =============== */


modifier onlyOperator() {
modifier masonUserExists {
require(operator == msg.sender, "Masonry: caller is not the operator");
require(balanceOf(msg.sender) > 0, "Masonry: The masonUser does not exist");
_;
}

modifier masonExists {
require(balanceOf(msg.sender) > 0, "Masonry: The mason does not exist");
_;
_;
}
}


modifier updateReward(address mason) {
modifier updateReward(address masonUser) {
if (mason != address(0)) {
if (masonUser != address(0)) {
Masonseat memory seat = masons[mason];
MasonSeat memory seat = masons[masonUser];
seat.rewardEarned = earned(mason);
seat.rewardEarned = earned(masonUser);
seat.lastSnapshotIndex = latestSnapshotIndex();
seat.lastSnapshotIndex = latestSnapshotIndex();
masons[mason] = seat;
masons[masonUser] = seat;
}
}
_;
_;
}
}


modifier notInitialized {
modifier notInitialized {
require(!initialized, "Masonry: already initialized");
require(!initialized, "Masonry: already initialized");
_;
_;
}
}


/* ========== GOVERNANCE ========== */
/* ========== GOVERNANCE ========== */


function initialize(
function initialize(
IERC20 _tomb,
IERC20 _hog,
IERC20 _share,
IERC20 _share,
ITreasury _treasury
ITreasury _treasury
) public notInitialized {
) public notInitialized onlyOperator {
tomb = _tomb;
hog = _hog;
share = _share;
share = _share;
treasury = _treasury;
treasury = _treasury;


MasonrySnapshot memory genesisSnapshot = MasonrySnapshot({time : block.number, rewardReceived : 0, rewardPerShare : 0});
MasonrySnapshot memory genesisSnapshot = MasonrySnapshot({time : block.number, rewardReceived : 0, rewardPerShare : 0});
masonryHistory.push(genesisSnapshot);
masonryHistory.push(genesisSnapshot);


withdrawLockupEpochs = 6; // Lock for 6 epochs (36h) before release withdraw
withdrawLockupEpochs = 6; // Lock for 6 epochs (36h) before release withdraw
rewardLockupEpochs = 3; // Lock for 3 epochs (18h) before release claimReward
rewardLockupEpochs = 3; // Lock for 3 epochs (18h) before release claimReward


initialized = true;
initialized = true;
operator = msg.sender;
emit Initialized(msg.sender, block.number);
emit Initialized(msg.sender, block.number);
}
}


function setOperator(address _operator) external onlyOperator {
function setOperator(address _operator) external onlyOperator {
operator = _operator;
transferOperator(_operator);
}

function renounceOperator() external onlyOperator {
_renounceOperator();
}
}


function setLockUp(uint256 _withdrawLockupEpochs, uint256 _rewardLockupEpochs) external onlyOperator {
function setLockUp(uint256 _withdrawLockupEpochs, uint256 _rewardLockupEpochs) external onlyOperator {
require(_withdrawLockupEpochs >= _rewardLockupEpochs && _withdrawLockupEpochs <= 56, "_withdrawLockupEpochs: out of range"); // <= 2 week
require(_withdrawLockupEpochs >= _rewardLockupEpochs && _withdrawLockupEpochs <= 56, "_withdrawLockupEpochs: out of range"); // <= 2 week
require(_withdrawLockupEpochs > 0 && _rewardLockupEpochs > 0, "lockupEpochs must be greater than 0");
withdrawLockupEpochs = _withdrawLockupEpochs;
withdrawLockupEpochs = _withdrawLockupEpochs;
rewardLockupEpochs = _rewardLockupEpochs;
rewardLockupEpochs = _rewardLockupEpochs;
}
}


/* ========== VIEW FUNCTIONS ========== */
/* ========== VIEW FUNCTIONS ========== */


// =========== Snapshot getters
// =========== Snapshot getters =========== //


function latestSnapshotIndex() public view returns (uint256) {
function latestSnapshotIndex() public view returns (uint256) {
return masonryHistory.length.sub(1);
return masonryHistory.length.sub(1);
}
}


function getLatestSnapshot() internal view returns (MasonrySnapshot memory) {
function getLatestSnapshot() internal view returns (MasonrySnapshot memory) {
return masonryHistory[latestSnapshotIndex()];
return masonryHistory[latestSnapshotIndex()];
}
}


function getLastSnapshotIndexOf(address mason) public view returns (uint256) {
function getLastSnapshotIndexOf(address masonUser) public view returns (uint256) {
return masons[mason].lastSnapshotIndex;
return masons[masonUser].lastSnapshotIndex;
}
}


function getLastSnapshotOf(address mason) internal view returns (MasonrySnapshot memory) {
function getLastSnapshotOf(address masonUser) internal view returns (MasonrySnapshot memory) {
return masonryHistory[getLastSnapshotIndexOf(mason)];
return masonryHistory[getLastSnapshotIndexOf(masonUser)];
}
}


function canWithdraw(address mason) external view returns (bool) {
function canWithdraw(address masonUser) external view returns (bool) {
return masons[mason].epochTimerStart.add(withdrawLockupEpochs) <= treasury.epoch();
return masons[masonUser].epochTimerStart.add(withdrawLockupEpochs) <= treasury.epoch();
}
}


function canClaimReward(address mason) external view returns (bool) {
function canClaimReward(address masonUser) external view returns (bool) {
return masons[mason].epochTimerStart.add(rewardLockupEpochs) <= treasury.epoch();
return masons[masonUser].epochTimerStart.add(rewardLockupEpochs) <= treasury.epoch();
}
}


function epoch() external view returns (uint256) {
function epoch() external view returns (uint256) {
return treasury.epoch();
return treasury.epoch();
}
}


function nextEpochPoint() external view returns (uint256) {
function nextEpochPoint() external view returns (uint256) {
return treasury.nextEpochPoint();
return treasury.nextEpochPoint();
}
}


function getTombPrice() external view returns (uint256) {
function getHogPrice() external view returns (uint256) {
return treasury.getTombPrice();
return treasury.getHogPrice();
}
}


// =========== Mason getters
// =========== Users getters =========== //


function rewardPerShare() public view returns (uint256) {
function rewardPerShare() public view returns (uint256) {
return getLatestSnapshot().rewardPerShare;
return getLatestSnapshot().rewardPerShare;
}
}


function earned(address mason) public view returns (uint256) {
function earned(address masonUser) public view returns (uint256) {
uint256 latestRPS = getLatestSnapshot().rewardPerShare;
uint256 latestRPS = getLatestSnapshot().rewardPerShare;
uint256 storedRPS = getLastSnapshotOf(mason).rewardPerShare;
uint256 storedRPS = getLastSnapshotOf(masonUser).rewardPerShare;


return balanceOf(mason).mul(latestRPS.sub(storedRPS)).div(1e18).add(masons[mason].rewardEarned);
return balanceOf(masonUser).mul(latestRPS.sub(storedRPS)).div(1e18).add(masons[masonUser].rewardEarned);
}
}


/* ========== MUTATIVE FUNCTIONS ========== */
/* ========== MUTATIVE FUNCTIONS ========== */


function stake(uint256 amount) public override onlyOneBlock updateReward(msg.sender) {
function stake(uint256 amount) public override onlyOneBlock updateReward(msg.sender) {
require(amount > 0, "Masonry: Cannot stake 0");
require(amount > 0, "Masonry: Cannot stake 0");
super.stake(amount);
super.stake(amount);
masons[msg.sender].epochTimerStart = treasury.epoch(); // reset timer
masons[msg.sender].epochTimerStart = treasury.epoch(); // reset timer
emit Staked(msg.sender, amount);
emit Staked(msg.sender, amount);
}
}


function withdraw(uint256 amount) public override onlyOneBlock masonExists updateReward(msg.sender) {
function withdraw(uint256 amount) public override onlyOneBlock masonUserExists updateReward(msg.sender) {
require(amount > 0, "Masonry: Cannot withdraw 0");
require(amount > 0, "Masonry: Cannot withdraw 0");
require(masons[msg.sender].epochTimerStart.add(withdrawLockupEpochs) <= treasury.epoch(), "Masonry: still in withdraw lockup");
require(masons[msg.sender].epochTimerStart.add(withdrawLockupEpochs) <= treasury.epoch(), "Masonry: still in withdraw lockup");
claimReward();
claimReward();
super.withdraw(amount);
super.withdraw(amount);
emit Withdrawn(msg.sender, amount);
emit Withdrawn(msg.sender, amount);
}
}


function exit() external {
function exit() external {
withdraw(balanceOf(msg.sender));
withdraw(balanceOf(msg.sender));
}
}


function claimReward() public updateReward(msg.sender) {
function claimReward() public updateReward(msg.sender) {
uint256 reward = masons[msg.sender].rewardEarned;
uint256 reward = masons[msg.sender].rewardEarned;
if (reward > 0) {
if (reward > 0) {
require(masons[msg.sender].epochTimerStart.add(rewardLockupEpochs) <= treasury.epoch(), "Masonry: still in reward lockup");
require(masons[msg.sender].epochTimerStart.add(rewardLockupEpochs) <= treasury.epoch(), "Masonry: still in reward lockup");
masons[msg.sender].epochTimerStart = treasury.epoch(); // reset timer
masons[msg.sender].epochTimerStart = treasury.epoch(); // reset timer
masons[msg.sender].rewardEarned = 0;
masons[msg.sender].rewardEarned = 0;
tomb.safeTransfer(msg.sender, reward);
hog.safeTransfer(msg.sender, reward);
emit RewardPaid(msg.sender, reward);
emit RewardPaid(msg.sender, reward);
}
}
}
}


function allocateSeigniorage(uint256 amount) external onlyOneBlock onlyOperator {
function allocateSeigniorage(uint256 amount) external onlyOneBlock onlyOperator {
require(amount > 0, "Masonry: Cannot allocate 0");
require(amount > 0, "Masonry: Cannot allocate 0");
require(totalSupply() > 0, "Masonry: Cannot allocate when totalSupply is 0");
require(totalSupply() > 0, "Masonry: Cannot allocate when totalSupply is 0");


// Create & add new snapshot
// Create & add new snapshot
uint256 prevRPS = getLatestSnapshot().rewardPerShare;
uint256 prevRPS = getLatestSnapshot().rewardPerShare;
uint256 nextRPS = prevRPS.add(amount.mul(1e18).div(totalSupply()));
uint256 nextRPS = prevRPS.add(amount.mul(1e18).div(totalSupply()));


MasonrySnapshot memory newSnapshot = MasonrySnapshot({
MasonrySnapshot memory newSnapshot = MasonrySnapshot({
time: block.number,
time: block.number,
rewardReceived: amount,
rewardReceived: amount,
rewardPerShare: nextRPS
rewardPerShare: nextRPS
});
});
masonryHistory.push(newSnapshot);
masonryHistory.push(newSnapshot);


tomb.safeTransferFrom(msg.sender, address(this), amount);
hog.safeTransferFrom(msg.sender, address(this), amount);
emit RewardAdded(msg.sender, amount);
emit RewardAdded(msg.sender, amount);
}
}


function governanceRecoverUnsupported(IERC20 _token, uint256 _amount, address _to) external onlyOperator {
function governanceRecoverUnsupported(IERC20 _token, uint256 _amount, address _to) external onlyOperator {
// do not allow to drain core tokens
// do not allow to drain core tokens
require(address(_token) != address(tomb), "tomb");
require(address(_token) != address(hog), "hog");
require(address(_token) != address(share), "share");
require(address(_token) != address(share), "share");
_token.safeTransfer(_to, _amount);
_token.safeTransfer(_to, _amount);
}
}
}
}