Untitled diff

Created Diff never expires
57 removals
Lines
Total
Removed
Words
Total
Removed
To continue using this feature, upgrade to
Diffchecker logo
Diffchecker Pro
255 lines
46 additions
Lines
Total
Added
Words
Total
Added
To continue using this feature, upgrade to
Diffchecker logo
Diffchecker Pro
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);
}
}
}
}