Diff
checker
텍스트
텍스트
이미지
문서
Excel
폴더
Legal
Enterprise
데스크톱
요금제
로그인
데스크톱 앱 다운로드
텍스트 비교
두 텍스트 파일의 차이점을 찾아보세요
도구
기록
실시간 편집
변경 없는 행 숨기기
줄바꿈 비활성화
레이아웃
나란히 보기
합쳐 보기
비교 단위
스마트
단어
글자
구문 강조
언어 선택
제외
텍스트 변환
첫 변경으로
수정
Diffchecker Desktop
가장 안전하게 Diffchecker를 사용하는 방법. 데스크톱 앱을 사용하면 비교 데이터가 외부로 전송되지 않습니다!
데스크톱 앱 받기
Acropolis vs Masonry
생성일
4년 전
비교 결과 만료 없음
초기화
내보내기
공유
설명
100 삭제
행
총
삭제
글자
총
삭제
이 기능을 계속 사용하려면 업그레이드해 주세요
Diff
checker
Pro
요금제 보기
266 행
복사
107 추가
행
총
추가
글자
총
추가
이 기능을 계속 사용하려면 업그레이드해 주세요
Diff
checker
Pro
요금제 보기
266 행
복사
// SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT
복사
복사됨
복사
복사됨
pragma solidity
0.6.12
;
pragma solidity
^0.8.0
;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
복사
복사됨
복사
복사됨
import "@openzeppelin/contracts/token/ERC20/
SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/
utils/
SafeERC20.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "./utils/ContractGuard.sol";
import "./utils/ContractGuard.sol";
import "./interfaces/IBasisAsset.sol";
import "./interfaces/IBasisAsset.sol";
import "./interfaces/ITreasury.sol";
import "./interfaces/ITreasury.sol";
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
mason
Share = _balances[msg.sender];
uint256
andras
Share = _balances[msg.sender];
require(
mason
Share >= amount, "
Masonry
: withdraw request greater than staked amount");
require(
andras
Share >= amount, "
Acropolis
: withdraw request greater than staked amount");
_totalSupply = _totalSupply.sub(amount);
_totalSupply = _totalSupply.sub(amount);
복사
복사됨
복사
복사됨
_balances[msg.sender] =
mason
Share.sub(amount);
_balances[msg.sender] =
andras
Share.sub(amount);
share.safeTransfer(msg.sender, amount);
share.safeTransfer(msg.sender, amount);
}
}
}
}
/*
/*
복사
복사됨
복사
복사됨
______
__
_______
____
______
.___ ____
_______
.__
/
_
__/
___ ____
___ / /
_
/
____
(_)
___ ____
____
_
____
____
\______ \____
_
___
___ ____
__| _/ \
_
____
_/|__| _
___ ____
_
____
____
____
/
/
/ __ \
/ __
`__ \/
__
\ /
/_ /
/ __ \
/ __
`/
__ \
/
___/
_ \
| | _/\__ \
/
___/_
/ __ \
/ __
| | __) | | / \ \
__
\ /
\ _/ ___\_
/ __ \
/ /
/ /_/
/ / / / / / /_/ /
/ __
/ / / / / / /_/ / / / /
/__
/ __/
| | \
/ __
\_ \_
__ \
\
___/
/ /_/
| | \ | || | \
/ __
\_| | \\ \___\ ___/
/_/
\____
/_/ /_/ /_/_.
___
/
/
_/
/_/_/ /_/\__,_/_/ /_/
\___
/
\___
/
|______ /(____ /
/__
__ > \___ >
\____
| \
___
/
|__||___| /(____ /|___| /
\___
>
\___
>
\/ \/ \/ \/ \/ \/ \/ \/ \/ \/ \/
http://tomb.finance
*/
*/
복사
복사됨
복사
복사됨
contract
Masonry
is ShareWrapper, ContractGuard {
contract
Acropolis
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
Ecclesiaseat
{
uint256 lastSnapshotIndex;
uint256 lastSnapshotIndex;
uint256 rewardEarned;
uint256 rewardEarned;
uint256 epochTimerStart;
uint256 epochTimerStart;
}
}
복사
복사됨
복사
복사됨
struct
MasonrySnapshot
{
struct
AcropolisSnapshot
{
uint256 time;
uint256 time;
uint256 rewardReceived;
uint256 rewardReceived;
uint256 rewardPerShare;
uint256 rewardPerShare;
}
}
/* ========== STATE VARIABLES ========== */
/* ========== STATE VARIABLES ========== */
// governance
// governance
address public operator;
address public operator;
// flags
// flags
bool public initialized = false;
bool public initialized = false;
복사
복사됨
복사
복사됨
IERC20 public
tomb
;
IERC20 public
based
;
ITreasury public treasury;
ITreasury public treasury;
복사
복사됨
복사
복사됨
mapping(address =>
Masonseat
) public
masons
;
mapping(address =>
Ecclesiaseat
) public
demos
;
MasonrySnapshot
[] public
masonryHistory
;
AcropolisSnapshot
[] public
acropolisHistory
;
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 onlyOperator() {
복사
복사됨
복사
복사됨
require(operator == msg.sender, "
Masonry
: caller is not the operator");
require(operator == msg.sender, "
Acropolis
: caller is not the operator");
_;
_;
}
}
복사
복사됨
복사
복사됨
modifier
mason
Exists {
modifier
andras
Exists {
require(balanceOf(msg.sender) > 0, "
Masonry
: The
mason
does not exist");
require(balanceOf(msg.sender) > 0, "
Acropolis
: The
andras
does not exist");
_;
_;
}
}
복사
복사됨
복사
복사됨
modifier updateReward(address
mason
) {
modifier updateReward(address
andras
) {
if (
mason
!= address(0)) {
if (
andras
!= address(0)) {
Masonseat
memory seat =
masons[mason
];
Ecclesiaseat
memory seat =
demos[andras
];
seat.rewardEarned = earned(
mason
);
seat.rewardEarned = earned(
andras
);
seat.lastSnapshotIndex = latestSnapshotIndex();
seat.lastSnapshotIndex = latestSnapshotIndex();
복사
복사됨
복사
복사됨
masons[mason
] = seat;
demos[andras
] = seat;
}
}
_;
_;
}
}
modifier notInitialized {
modifier notInitialized {
복사
복사됨
복사
복사됨
require(!initialized, "
Masonry
: already initialized");
require(!initialized, "
Acropolis
: already initialized");
_;
_;
}
}
/* ========== GOVERNANCE ========== */
/* ========== GOVERNANCE ========== */
function initialize(
function initialize(
복사
복사됨
복사
복사됨
IERC20 _
tomb
,
IERC20 _
based
,
IERC20 _share,
IERC20 _share,
ITreasury _treasury
ITreasury _treasury
) public notInitialized {
) public notInitialized {
복사
복사됨
복사
복사됨
tomb
= _
tomb
;
based
= _
based
;
share = _share;
share = _share;
treasury = _treasury;
treasury = _treasury;
복사
복사됨
복사
복사됨
MasonrySnapshot
memory genesisSnapshot =
MasonrySnapshot
({time : block.number, rewardReceived : 0, rewardPerShare : 0});
AcropolisSnapshot
memory genesisSnapshot =
AcropolisSnapshot
({time : block.number, rewardReceived : 0, rewardPerShare : 0});
masonryHistory
.push(genesisSnapshot);
acropolisHistory
.push(genesisSnapshot);
복사
복사됨
복사
복사됨
withdrawLockupEpochs =
6
; // Lock for 6 epochs (36h) before release withdraw
withdrawLockupEpochs =
4
; // Lock for 6 epochs (36h) before release withdraw
rewardLockupEpochs =
3
; // Lock for 3 epochs (18h) before release claimReward
rewardLockupEpochs =
2
; // Lock for 3 epochs (18h) before release claimReward
!!! THIS IS ALTERED TO SMALLER PERIODS
initialized = true;
initialized = true;
operator = msg.sender;
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;
operator = _operator;
}
}
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
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
acropolisHistory
.length.sub(1);
}
}
복사
복사됨
복사
복사됨
function getLatestSnapshot() internal view returns (
MasonrySnapshot
memory) {
function getLatestSnapshot() internal view returns (
AcropolisSnapshot
memory) {
return
masonryHistory
[latestSnapshotIndex()];
return
acropolisHistory
[latestSnapshotIndex()];
}
}
복사
복사됨
복사
복사됨
function getLastSnapshotIndexOf(address
mason
) public view returns (uint256) {
function getLastSnapshotIndexOf(address
andras
) public view returns (uint256) {
return
masons[mason
].lastSnapshotIndex;
return
demos[andras
].lastSnapshotIndex;
}
}
복사
복사됨
복사
복사됨
function getLastSnapshotOf(address
mason
) internal view returns (
MasonrySnapshot
memory) {
function getLastSnapshotOf(address
andras
) internal view returns (
AcropolisSnapshot
memory) {
return
masonryHistory
[getLastSnapshotIndexOf(
mason
)];
return
acropolisHistory
[getLastSnapshotIndexOf(
andras
)];
}
}
복사
복사됨
복사
복사됨
function canWithdraw(address
mason
) external view returns (bool) {
function canWithdraw(address
andras
) external view returns (bool) {
return
masons[mason
].epochTimerStart.add(withdrawLockupEpochs) <= treasury.epoch();
return
demos[andras
].epochTimerStart.add(withdrawLockupEpochs) <= treasury.epoch();
}
}
복사
복사됨
복사
복사됨
function canClaimReward(address
mason
) external view returns (bool) {
function canClaimReward(address
andras
) external view returns (bool) {
return
masons[mason
].epochTimerStart.add(rewardLockupEpochs) <= treasury.epoch();
return
demos[andras
].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
getBasedPrice
() external view returns (uint256) {
return treasury.
getTombPrice
();
return treasury.
getBasedPrice
();
}
}
복사
복사됨
복사
복사됨
// ===========
Mason
getters
// ===========
Andras
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
andras
) public view returns (uint256) {
uint256 latestRPS = getLatestSnapshot().rewardPerShare;
uint256 latestRPS = getLatestSnapshot().rewardPerShare;
복사
복사됨
복사
복사됨
uint256 storedRPS = getLastSnapshotOf(
mason
).rewardPerShare;
uint256 storedRPS = getLastSnapshotOf(
andras
).rewardPerShare;
복사
복사됨
복사
복사됨
return balanceOf(
mason
).mul(latestRPS.sub(storedRPS)).div(1e18).add(
masons[mason
].rewardEarned);
return balanceOf(
andras
).mul(latestRPS.sub(storedRPS)).div(1e18).add(
demos[andras
].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, "
Acropolis
: Cannot stake 0");
super.stake(amount);
super.stake(amount);
복사
복사됨
복사
복사됨
masons
[msg.sender].epochTimerStart = treasury.epoch(); // reset timer
demos
[msg.sender].epochTimerStart = treasury.epoch(); // reset timer
emit Staked(msg.sender, amount);
emit Staked(msg.sender, amount);
}
}
복사
복사됨
복사
복사됨
function withdraw(uint256 amount) public override onlyOneBlock
mason
Exists updateReward(msg.sender) {
function withdraw(uint256 amount) public override onlyOneBlock
andras
Exists updateReward(msg.sender) {
require(amount > 0, "
Masonry
: Cannot withdraw 0");
require(amount > 0, "
Acropolis
: Cannot withdraw 0");
require(
masons
[msg.sender].epochTimerStart.add(withdrawLockupEpochs) <= treasury.epoch(), "
Masonry
: still in withdraw lockup");
require(
demos
[msg.sender].epochTimerStart.add(withdrawLockupEpochs) <= treasury.epoch(), "
Acropolis
: 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 =
demos
[msg.sender].rewardEarned;
if (reward > 0) {
if (reward > 0) {
복사
복사됨
복사
복사됨
require(
masons
[msg.sender].epochTimerStart.add(rewardLockupEpochs) <= treasury.epoch(), "
Masonry
: still in reward lockup");
require(
demos
[msg.sender].epochTimerStart.add(rewardLockupEpochs) <= treasury.epoch(), "
Acropolis
: still in reward lockup");
masons
[msg.sender].epochTimerStart = treasury.epoch(); // reset timer
demos
[msg.sender].epochTimerStart = treasury.epoch(); // reset timer
masons
[msg.sender].rewardEarned = 0;
demos
[msg.sender].rewardEarned = 0;
tomb
.safeTransfer(msg.sender, reward);
based
.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, "
Acropolis
: Cannot allocate 0");
require(totalSupply() > 0, "
Masonry
: Cannot allocate when totalSupply is 0");
require(totalSupply() > 0, "
Acropolis
: 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
({
AcropolisSnapshot
memory newSnapshot =
AcropolisSnapshot
({
time: block.number,
time: block.number,
rewardReceived: amount,
rewardReceived: amount,
rewardPerShare: nextRPS
rewardPerShare: nextRPS
});
});
복사
복사됨
복사
복사됨
masonryHistory
.push(newSnapshot);
acropolisHistory
.push(newSnapshot);
복사
복사됨
복사
복사됨
tomb
.safeTransferFrom(msg.sender, address(this), amount);
based
.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(
based
), "
based
");
require(address(_token) != address(share), "share");
require(address(_token) != address(share), "share");
_token.safeTransfer(_to, _amount);
_token.safeTransfer(_to, _amount);
}
}
}
}
저장된 비교 결과
원본
파일 열기
// SPDX-License-Identifier: MIT pragma solidity 0.6.12; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; import "./utils/ContractGuard.sol"; import "./interfaces/IBasisAsset.sol"; import "./interfaces/ITreasury.sol"; contract ShareWrapper { using SafeMath for uint256; using SafeERC20 for IERC20; IERC20 public share; uint256 private _totalSupply; mapping(address => uint256) private _balances; function totalSupply() public view returns (uint256) { return _totalSupply; } function balanceOf(address account) public view returns (uint256) { return _balances[account]; } function stake(uint256 amount) public virtual { _totalSupply = _totalSupply.add(amount); _balances[msg.sender] = _balances[msg.sender].add(amount); share.safeTransferFrom(msg.sender, address(this), amount); } function withdraw(uint256 amount) public virtual { uint256 masonShare = _balances[msg.sender]; require(masonShare >= amount, "Masonry: withdraw request greater than staked amount"); _totalSupply = _totalSupply.sub(amount); _balances[msg.sender] = masonShare.sub(amount); share.safeTransfer(msg.sender, amount); } } /* ______ __ _______ /_ __/___ ____ ___ / /_ / ____(_)___ ____ _____ ________ / / / __ \/ __ `__ \/ __ \ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ / / / /_/ / / / / / / /_/ / / __/ / / / / / /_/ / / / / /__/ __/ /_/ \____/_/ /_/ /_/_.___/ /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ http://tomb.finance */ contract Masonry is ShareWrapper, ContractGuard { using SafeERC20 for IERC20; using Address for address; using SafeMath for uint256; /* ========== DATA STRUCTURES ========== */ struct Masonseat { uint256 lastSnapshotIndex; uint256 rewardEarned; uint256 epochTimerStart; } struct MasonrySnapshot { uint256 time; uint256 rewardReceived; uint256 rewardPerShare; } /* ========== STATE VARIABLES ========== */ // governance address public operator; // flags bool public initialized = false; IERC20 public tomb; ITreasury public treasury; mapping(address => Masonseat) public masons; MasonrySnapshot[] public masonryHistory; uint256 public withdrawLockupEpochs; uint256 public rewardLockupEpochs; /* ========== EVENTS ========== */ event Initialized(address indexed executor, uint256 at); event Staked(address indexed user, uint256 amount); event Withdrawn(address indexed user, uint256 amount); event RewardPaid(address indexed user, uint256 reward); event RewardAdded(address indexed user, uint256 reward); /* ========== Modifiers =============== */ modifier onlyOperator() { require(operator == msg.sender, "Masonry: caller is not the operator"); _; } modifier masonExists { require(balanceOf(msg.sender) > 0, "Masonry: The mason does not exist"); _; } modifier updateReward(address mason) { if (mason != address(0)) { Masonseat memory seat = masons[mason]; seat.rewardEarned = earned(mason); seat.lastSnapshotIndex = latestSnapshotIndex(); masons[mason] = seat; } _; } modifier notInitialized { require(!initialized, "Masonry: already initialized"); _; } /* ========== GOVERNANCE ========== */ function initialize( IERC20 _tomb, IERC20 _share, ITreasury _treasury ) public notInitialized { tomb = _tomb; share = _share; treasury = _treasury; MasonrySnapshot memory genesisSnapshot = MasonrySnapshot({time : block.number, rewardReceived : 0, rewardPerShare : 0}); masonryHistory.push(genesisSnapshot); withdrawLockupEpochs = 6; // Lock for 6 epochs (36h) before release withdraw rewardLockupEpochs = 3; // Lock for 3 epochs (18h) before release claimReward initialized = true; operator = msg.sender; emit Initialized(msg.sender, block.number); } function setOperator(address _operator) external onlyOperator { operator = _operator; } function setLockUp(uint256 _withdrawLockupEpochs, uint256 _rewardLockupEpochs) external onlyOperator { require(_withdrawLockupEpochs >= _rewardLockupEpochs && _withdrawLockupEpochs <= 56, "_withdrawLockupEpochs: out of range"); // <= 2 week withdrawLockupEpochs = _withdrawLockupEpochs; rewardLockupEpochs = _rewardLockupEpochs; } /* ========== VIEW FUNCTIONS ========== */ // =========== Snapshot getters function latestSnapshotIndex() public view returns (uint256) { return masonryHistory.length.sub(1); } function getLatestSnapshot() internal view returns (MasonrySnapshot memory) { return masonryHistory[latestSnapshotIndex()]; } function getLastSnapshotIndexOf(address mason) public view returns (uint256) { return masons[mason].lastSnapshotIndex; } function getLastSnapshotOf(address mason) internal view returns (MasonrySnapshot memory) { return masonryHistory[getLastSnapshotIndexOf(mason)]; } function canWithdraw(address mason) external view returns (bool) { return masons[mason].epochTimerStart.add(withdrawLockupEpochs) <= treasury.epoch(); } function canClaimReward(address mason) external view returns (bool) { return masons[mason].epochTimerStart.add(rewardLockupEpochs) <= treasury.epoch(); } function epoch() external view returns (uint256) { return treasury.epoch(); } function nextEpochPoint() external view returns (uint256) { return treasury.nextEpochPoint(); } function getTombPrice() external view returns (uint256) { return treasury.getTombPrice(); } // =========== Mason getters function rewardPerShare() public view returns (uint256) { return getLatestSnapshot().rewardPerShare; } function earned(address mason) public view returns (uint256) { uint256 latestRPS = getLatestSnapshot().rewardPerShare; uint256 storedRPS = getLastSnapshotOf(mason).rewardPerShare; return balanceOf(mason).mul(latestRPS.sub(storedRPS)).div(1e18).add(masons[mason].rewardEarned); } /* ========== MUTATIVE FUNCTIONS ========== */ function stake(uint256 amount) public override onlyOneBlock updateReward(msg.sender) { require(amount > 0, "Masonry: Cannot stake 0"); super.stake(amount); masons[msg.sender].epochTimerStart = treasury.epoch(); // reset timer emit Staked(msg.sender, amount); } function withdraw(uint256 amount) public override onlyOneBlock masonExists updateReward(msg.sender) { require(amount > 0, "Masonry: Cannot withdraw 0"); require(masons[msg.sender].epochTimerStart.add(withdrawLockupEpochs) <= treasury.epoch(), "Masonry: still in withdraw lockup"); claimReward(); super.withdraw(amount); emit Withdrawn(msg.sender, amount); } function exit() external { withdraw(balanceOf(msg.sender)); } function claimReward() public updateReward(msg.sender) { uint256 reward = masons[msg.sender].rewardEarned; if (reward > 0) { 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].rewardEarned = 0; tomb.safeTransfer(msg.sender, reward); emit RewardPaid(msg.sender, reward); } } function allocateSeigniorage(uint256 amount) external onlyOneBlock onlyOperator { require(amount > 0, "Masonry: Cannot allocate 0"); require(totalSupply() > 0, "Masonry: Cannot allocate when totalSupply is 0"); // Create & add new snapshot uint256 prevRPS = getLatestSnapshot().rewardPerShare; uint256 nextRPS = prevRPS.add(amount.mul(1e18).div(totalSupply())); MasonrySnapshot memory newSnapshot = MasonrySnapshot({ time: block.number, rewardReceived: amount, rewardPerShare: nextRPS }); masonryHistory.push(newSnapshot); tomb.safeTransferFrom(msg.sender, address(this), amount); emit RewardAdded(msg.sender, amount); } function governanceRecoverUnsupported(IERC20 _token, uint256 _amount, address _to) external onlyOperator { // do not allow to drain core tokens require(address(_token) != address(tomb), "tomb"); require(address(_token) != address(share), "share"); _token.safeTransfer(_to, _amount); } }
수정본
파일 열기
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/utils/math/SafeMath.sol"; import "./utils/ContractGuard.sol"; import "./interfaces/IBasisAsset.sol"; import "./interfaces/ITreasury.sol"; contract ShareWrapper { using SafeMath for uint256; using SafeERC20 for IERC20; IERC20 public share; uint256 private _totalSupply; mapping(address => uint256) private _balances; function totalSupply() public view returns (uint256) { return _totalSupply; } function balanceOf(address account) public view returns (uint256) { return _balances[account]; } function stake(uint256 amount) public virtual { _totalSupply = _totalSupply.add(amount); _balances[msg.sender] = _balances[msg.sender].add(amount); share.safeTransferFrom(msg.sender, address(this), amount); } function withdraw(uint256 amount) public virtual { uint256 andrasShare = _balances[msg.sender]; require(andrasShare >= amount, "Acropolis: withdraw request greater than staked amount"); _totalSupply = _totalSupply.sub(amount); _balances[msg.sender] = andrasShare.sub(amount); share.safeTransfer(msg.sender, amount); } } /* __________ .___ ___________.__ \______ \_____ ______ ____ __| _/ \_ _____/|__| ____ _____ ____ ____ ____ | | _/\__ \ / ___/_/ __ \ / __ | | __) | | / \ \__ \ / \ _/ ___\_/ __ \ | | \ / __ \_ \___ \ \ ___/ / /_/ | | \ | || | \ / __ \_| | \\ \___\ ___/ |______ /(____ //____ > \___ >\____ | \___ / |__||___| /(____ /|___| / \___ >\___ > \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ */ contract Acropolis is ShareWrapper, ContractGuard { using SafeERC20 for IERC20; using Address for address; using SafeMath for uint256; /* ========== DATA STRUCTURES ========== */ struct Ecclesiaseat { uint256 lastSnapshotIndex; uint256 rewardEarned; uint256 epochTimerStart; } struct AcropolisSnapshot { uint256 time; uint256 rewardReceived; uint256 rewardPerShare; } /* ========== STATE VARIABLES ========== */ // governance address public operator; // flags bool public initialized = false; IERC20 public based; ITreasury public treasury; mapping(address => Ecclesiaseat) public demos; AcropolisSnapshot[] public acropolisHistory; uint256 public withdrawLockupEpochs; uint256 public rewardLockupEpochs; /* ========== EVENTS ========== */ event Initialized(address indexed executor, uint256 at); event Staked(address indexed user, uint256 amount); event Withdrawn(address indexed user, uint256 amount); event RewardPaid(address indexed user, uint256 reward); event RewardAdded(address indexed user, uint256 reward); /* ========== Modifiers =============== */ modifier onlyOperator() { require(operator == msg.sender, "Acropolis: caller is not the operator"); _; } modifier andrasExists { require(balanceOf(msg.sender) > 0, "Acropolis: The andras does not exist"); _; } modifier updateReward(address andras) { if (andras != address(0)) { Ecclesiaseat memory seat = demos[andras]; seat.rewardEarned = earned(andras); seat.lastSnapshotIndex = latestSnapshotIndex(); demos[andras] = seat; } _; } modifier notInitialized { require(!initialized, "Acropolis: already initialized"); _; } /* ========== GOVERNANCE ========== */ function initialize( IERC20 _based, IERC20 _share, ITreasury _treasury ) public notInitialized { based = _based; share = _share; treasury = _treasury; AcropolisSnapshot memory genesisSnapshot = AcropolisSnapshot({time : block.number, rewardReceived : 0, rewardPerShare : 0}); acropolisHistory.push(genesisSnapshot); withdrawLockupEpochs = 4; // Lock for 6 epochs (36h) before release withdraw rewardLockupEpochs = 2; // Lock for 3 epochs (18h) before release claimReward !!! THIS IS ALTERED TO SMALLER PERIODS initialized = true; operator = msg.sender; emit Initialized(msg.sender, block.number); } function setOperator(address _operator) external onlyOperator { operator = _operator; } function setLockUp(uint256 _withdrawLockupEpochs, uint256 _rewardLockupEpochs) external onlyOperator { require(_withdrawLockupEpochs >= _rewardLockupEpochs && _withdrawLockupEpochs <= 56, "_withdrawLockupEpochs: out of range"); // <= 2 week withdrawLockupEpochs = _withdrawLockupEpochs; rewardLockupEpochs = _rewardLockupEpochs; } /* ========== VIEW FUNCTIONS ========== */ // =========== Snapshot getters =========== // function latestSnapshotIndex() public view returns (uint256) { return acropolisHistory.length.sub(1); } function getLatestSnapshot() internal view returns (AcropolisSnapshot memory) { return acropolisHistory[latestSnapshotIndex()]; } function getLastSnapshotIndexOf(address andras) public view returns (uint256) { return demos[andras].lastSnapshotIndex; } function getLastSnapshotOf(address andras) internal view returns (AcropolisSnapshot memory) { return acropolisHistory[getLastSnapshotIndexOf(andras)]; } function canWithdraw(address andras) external view returns (bool) { return demos[andras].epochTimerStart.add(withdrawLockupEpochs) <= treasury.epoch(); } function canClaimReward(address andras) external view returns (bool) { return demos[andras].epochTimerStart.add(rewardLockupEpochs) <= treasury.epoch(); } function epoch() external view returns (uint256) { return treasury.epoch(); } function nextEpochPoint() external view returns (uint256) { return treasury.nextEpochPoint(); } function getBasedPrice() external view returns (uint256) { return treasury.getBasedPrice(); } // =========== Andras getters =========== // function rewardPerShare() public view returns (uint256) { return getLatestSnapshot().rewardPerShare; } function earned(address andras) public view returns (uint256) { uint256 latestRPS = getLatestSnapshot().rewardPerShare; uint256 storedRPS = getLastSnapshotOf(andras).rewardPerShare; return balanceOf(andras).mul(latestRPS.sub(storedRPS)).div(1e18).add(demos[andras].rewardEarned); } /* ========== MUTATIVE FUNCTIONS ========== */ function stake(uint256 amount) public override onlyOneBlock updateReward(msg.sender) { require(amount > 0, "Acropolis: Cannot stake 0"); super.stake(amount); demos[msg.sender].epochTimerStart = treasury.epoch(); // reset timer emit Staked(msg.sender, amount); } function withdraw(uint256 amount) public override onlyOneBlock andrasExists updateReward(msg.sender) { require(amount > 0, "Acropolis: Cannot withdraw 0"); require(demos[msg.sender].epochTimerStart.add(withdrawLockupEpochs) <= treasury.epoch(), "Acropolis: still in withdraw lockup"); claimReward(); super.withdraw(amount); emit Withdrawn(msg.sender, amount); } function exit() external { withdraw(balanceOf(msg.sender)); } function claimReward() public updateReward(msg.sender) { uint256 reward = demos[msg.sender].rewardEarned; if (reward > 0) { require(demos[msg.sender].epochTimerStart.add(rewardLockupEpochs) <= treasury.epoch(), "Acropolis: still in reward lockup"); demos[msg.sender].epochTimerStart = treasury.epoch(); // reset timer demos[msg.sender].rewardEarned = 0; based.safeTransfer(msg.sender, reward); emit RewardPaid(msg.sender, reward); } } function allocateSeigniorage(uint256 amount) external onlyOneBlock onlyOperator { require(amount > 0, "Acropolis: Cannot allocate 0"); require(totalSupply() > 0, "Acropolis: Cannot allocate when totalSupply is 0"); // Create & add new snapshot uint256 prevRPS = getLatestSnapshot().rewardPerShare; uint256 nextRPS = prevRPS.add(amount.mul(1e18).div(totalSupply())); AcropolisSnapshot memory newSnapshot = AcropolisSnapshot({ time: block.number, rewardReceived: amount, rewardPerShare: nextRPS }); acropolisHistory.push(newSnapshot); based.safeTransferFrom(msg.sender, address(this), amount); emit RewardAdded(msg.sender, amount); } function governanceRecoverUnsupported(IERC20 _token, uint256 _amount, address _to) external onlyOperator { // do not allow to drain core tokens require(address(_token) != address(based), "based"); require(address(_token) != address(share), "share"); _token.safeTransfer(_to, _amount); } }
비교하기