Diff
checker
텍스트
텍스트
이미지
문서
Excel
폴더
Legal
Enterprise
데스크톱
요금제
로그인
데스크톱 앱 다운로드
텍스트 비교
두 텍스트 파일의 차이점을 찾아보세요
도구
기록
실시간 편집
변경 없는 행 숨기기
줄바꿈 비활성화
레이아웃
나란히 보기
합쳐 보기
비교 단위
스마트
단어
글자
구문 강조
언어 선택
제외
텍스트 변환
첫 변경으로
수정
Diffchecker Desktop
가장 안전하게 Diffchecker를 사용하는 방법. 데스크톱 앱을 사용하면 비교 데이터가 외부로 전송되지 않습니다!
데스크톱 앱 받기
StableXSwap Code versus SushiChef.sol
생성일
6년 전
비교 결과 만료 없음
초기화
내보내기
공유
설명
94 삭제
행
총
삭제
글자
총
삭제
이 기능을 계속 사용하려면 업그레이드해 주세요
Diff
checker
Pro
요금제 보기
263 행
복사
92 추가
행
총
추가
글자
총
추가
이 기능을 계속 사용하려면 업그레이드해 주세요
Diff
checker
Pro
요금제 보기
262 행
복사
pragma solidity 0.6.12;
pragma solidity 0.6.12;
복사
복사됨
복사
복사됨
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/SafeERC20.sol";
import "@openzeppelin/contracts/utils/EnumerableSet.sol";
import "@openzeppelin/contracts/utils/EnumerableSet.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
복사
복사됨
복사
복사됨
import "./
SushiToken
.sol";
import "./
StaxToken
.sol";
interface IMigratorChef {
interface IMigratorChef {
복사
복사됨
복사
복사됨
// Perform LP token migration from legacy
UniswapV2
to
SushiSwap
.
// Perform LP token migration from legacy
PancakeSwap
to
StableX Swap
.
// Take the current LP token address and return the new LP token address.
// Take the current LP token address and return the new LP token address.
// Migrator should have full access to the caller's LP token.
// Migrator should have full access to the caller's LP token.
// Return the new LP token address.
// Return the new LP token address.
//
//
복사
복사됨
복사
복사됨
// XXX Migrator must have allowance access to
UniswapV2
LP tokens.
// XXX Migrator must have allowance access to
PancakeSwap
LP tokens.
//
SushiSwap
must mint EXACTLY the same amount of
SushiSwap
LP tokens or
//
CakeSwap
must mint EXACTLY the same amount of
CakeSwap
LP tokens or
// else something bad will happen. Traditional
UniswapV2
does not
// else something bad will happen. Traditional
PancakeSwap
does not
// do that so be careful!
// do that so be careful!
복사
복사됨
복사
복사됨
function migrate(I
ERC
20 token) external returns (I
ERC
20);
function migrate(I
BEP
20 token) external returns (I
BEP
20);
}
}
복사
복사됨
복사
복사됨
//
MasterChef
is the master of
Sushi
. He can make
Sushi
and he is a fair guy.
//
SuperChef
is the master of
StableX
. He can make
STAX
and he is a fair guy.
//
//
// Note that it's ownable and the owner wields tremendous power. The ownership
// Note that it's ownable and the owner wields tremendous power. The ownership
복사
복사됨
복사
복사됨
// will be transferred to a governance smart contract once
SUSHI
is sufficiently
// will be transferred to a governance smart contract once
STAX
is sufficiently
// distributed and the community can show to govern itself.
// distributed and the community can show to govern itself.
//
//
// Have fun reading it. Hopefully it's bug-free. God bless.
// Have fun reading it. Hopefully it's bug-free. God bless.
복사
복사됨
복사
복사됨
contract
MasterChef
is Ownable {
contract
SuperChef
is Ownable {
using SafeMath for uint256;
using SafeMath for uint256;
using SafeERC20 for IERC20;
using SafeERC20 for IERC20;
// Info of each user.
// Info of each user.
struct UserInfo {
struct UserInfo {
uint256 amount; // How many LP tokens the user has provided.
uint256 amount; // How many LP tokens the user has provided.
uint256 rewardDebt; // Reward debt. See explanation below.
uint256 rewardDebt; // Reward debt. See explanation below.
//
//
복사
복사됨
복사
복사됨
// We do some fancy math here. Basically, any point in time, the amount of
SUSHIs
// We do some fancy math here. Basically, any point in time, the amount of
STAXs
// entitled to a user but is pending to be distributed is:
// entitled to a user but is pending to be distributed is:
//
//
복사
복사됨
복사
복사됨
// pending reward = (user.amount * pool.accS
ushi
PerShare) - user.rewardDebt
// pending reward = (user.amount * pool.accS
tax
PerShare) - user.rewardDebt
//
//
// Whenever a user deposits or withdraws LP tokens to a pool. Here's what happens:
// Whenever a user deposits or withdraws LP tokens to a pool. Here's what happens:
복사
복사됨
복사
복사됨
// 1. The pool's `accS
ushi
PerShare` (and `lastRewardBlock`) gets updated.
// 1. The pool's `accS
tax
PerShare` (and `lastRewardBlock`) gets updated.
// 2. User receives the pending reward sent to his/her address.
// 2. User receives the pending reward sent to his/her address.
// 3. User's `amount` gets updated.
// 3. User's `amount` gets updated.
// 4. User's `rewardDebt` gets updated.
// 4. User's `rewardDebt` gets updated.
}
}
// Info of each pool.
// Info of each pool.
struct PoolInfo {
struct PoolInfo {
IERC20 lpToken; // Address of LP token contract.
IERC20 lpToken; // Address of LP token contract.
복사
복사됨
복사
복사됨
uint256 allocPoint; // How many allocation points assigned to this pool.
SUSHIs to distribute per block.
uint256 allocPoint; // How many allocation points assigned to this pool.
uint256 lastRewardBlock; // Last block number that
SUSHIs
distribution occurs.
uint256 lastRewardBlock; // Last block number that
STAXs
distribution occurs.
uint256 accS
ushi
PerShare; // Accumulated
SUSHIs
per share, times 1e12. See below.
uint256 accS
tax
PerShare; // Accumulated
STAXs
per share, times 1e12. See below.
}
}
복사
복사됨
복사
복사됨
// The
SUSHI
TOKEN!
// The
STAX
TOKEN!
SushiToken
public
sushi
;
StaxToken
public
stax
;
// Dev address.
// Dev address.
address public devaddr;
address public devaddr;
복사
복사됨
복사
복사됨
// Block number when bonus
SUSHI
period ends.
// Block number when bonus
STAX
period ends.
uint256 public bonusEndBlock;
uint256 public bonusEndBlock;
복사
복사됨
복사
복사됨
//
SUSHI
tokens created per block.
//
STAX
tokens created per block.
uint256 public s
ushi
PerBlock;
uint256 public s
tax
PerBlock;
// Bonus muliplier for early
sushi
makers.
// Bonus muliplier for early
stax
makers.
uint256 public constant BONUS_MULTIPLIER = 10;
uint256 public constant BONUS_MULTIPLIER = 10;
// The migrator contract. It has a lot of power. Can only be set through governance (owner).
// The migrator contract. It has a lot of power. Can only be set through governance (owner).
IMigratorChef public migrator;
IMigratorChef public migrator;
// Info of each pool.
// Info of each pool.
PoolInfo[] public poolInfo;
PoolInfo[] public poolInfo;
// Info of each user that stakes LP tokens.
// Info of each user that stakes LP tokens.
mapping (uint256 => mapping (address => UserInfo)) public userInfo;
mapping (uint256 => mapping (address => UserInfo)) public userInfo;
복사
복사됨
복사
복사됨
// Total allocation poi
nt
s. Must be the sum of all allocation points in all pools.
// Total allocation poi
tn
s. Must be the sum of all allocation points in all pools.
uint256 public totalAllocPoint = 0;
uint256 public totalAllocPoint = 0;
복사
복사됨
복사
복사됨
// The block number when
SUSHI
mining starts.
// The block number when
STAX
mining starts.
uint256 public startBlock;
uint256 public startBlock;
event Deposit(address indexed user, uint256 indexed pid, uint256 amount);
event Deposit(address indexed user, uint256 indexed pid, uint256 amount);
event Withdraw(address indexed user, uint256 indexed pid, uint256 amount);
event Withdraw(address indexed user, uint256 indexed pid, uint256 amount);
event EmergencyWithdraw(address indexed user, uint256 indexed pid, uint256 amount);
event EmergencyWithdraw(address indexed user, uint256 indexed pid, uint256 amount);
constructor(
constructor(
복사
복사됨
복사
복사됨
SushiToken _sushi
,
StaxToken _stax
,
address _devaddr,
address _devaddr,
복사
복사됨
복사
복사됨
uint256 _s
ushi
PerBlock,
uint256 _s
tax
PerBlock,
uint256 _startBlock,
uint256 _startBlock,
uint256 _bonusEndBlock
uint256 _bonusEndBlock
) public {
) public {
복사
복사됨
복사
복사됨
sushi
= _
sushi
;
stax
= _
stax
;
devaddr = _devaddr;
devaddr = _devaddr;
복사
복사됨
복사
복사됨
s
ushi
PerBlock = _s
ushi
PerBlock;
s
tax
PerBlock = _s
tax
PerBlock;
bonusEndBlock = _bonusEndBlock;
bonusEndBlock = _bonusEndBlock;
startBlock = _startBlock;
startBlock = _startBlock;
}
}
복사
복사됨
복사
복사됨
Text moved with changes from lines 130-146 (99.6% similarity)
// Set the migrator contract. Can only be called by the owner.
function setMigrator(IMigratorChef _migrator) public onlyOwner {
migrator = _migrator;
}
// Migrate lp token to another lp contract. Can be called by anyone. We trust that migrator contract is good.
function migrate(uint256 _pid) public {
require(address(migrator) != address(0), "migrate: no migrator");
PoolInfo storage pool = poolInfo[_pid];
IBEP20 lpToken = pool.lpToken;
uint256 bal = lpToken.balanceOf(address(this));
lpToken.safeApprove(address(migrator), bal);
IBEP20 newLpToken = migrator.migrate(lpToken);
require(bal == newLpToken.balanceOf(address(this)), "migrate: bad");
pool.lpToken = newLpToken;
}
function poolLength() external view returns (uint256) {
function poolLength() external view returns (uint256) {
return poolInfo.length;
return poolInfo.length;
}
}
// Add a new lp to the pool. Can only be called by the owner.
// Add a new lp to the pool. Can only be called by the owner.
// XXX DO NOT add the same LP token more than once. Rewards will be messed up if you do.
// XXX DO NOT add the same LP token more than once. Rewards will be messed up if you do.
function add(uint256 _allocPoint, IERC20 _lpToken, bool _withUpdate) public onlyOwner {
function add(uint256 _allocPoint, IERC20 _lpToken, bool _withUpdate) public onlyOwner {
if (_withUpdate) {
if (_withUpdate) {
massUpdatePools();
massUpdatePools();
}
}
uint256 lastRewardBlock = block.number > startBlock ? block.number : startBlock;
uint256 lastRewardBlock = block.number > startBlock ? block.number : startBlock;
totalAllocPoint = totalAllocPoint.add(_allocPoint);
totalAllocPoint = totalAllocPoint.add(_allocPoint);
poolInfo.push(PoolInfo({
poolInfo.push(PoolInfo({
lpToken: _lpToken,
lpToken: _lpToken,
allocPoint: _allocPoint,
allocPoint: _allocPoint,
lastRewardBlock: lastRewardBlock,
lastRewardBlock: lastRewardBlock,
복사
복사됨
복사
복사됨
accS
ushi
PerShare: 0
accS
tax
PerShare: 0
}));
}));
}
}
복사
복사됨
복사
복사됨
// Update the given pool's
SUSHI
allocation point. Can only be called by the owner.
// Update the given pool's
STAX
allocation point. Can only be called by the owner.
function set(uint256 _pid, uint256 _allocPoint, bool _withUpdate) public onlyOwner {
function set(uint256 _pid, uint256 _allocPoint, bool _withUpdate) public onlyOwner {
if (_withUpdate) {
if (_withUpdate) {
massUpdatePools();
massUpdatePools();
}
}
totalAllocPoint = totalAllocPoint.sub(poolInfo[_pid].allocPoint).add(_allocPoint);
totalAllocPoint = totalAllocPoint.sub(poolInfo[_pid].allocPoint).add(_allocPoint);
poolInfo[_pid].allocPoint = _allocPoint;
poolInfo[_pid].allocPoint = _allocPoint;
}
}
복사
복사됨
복사
복사됨
Text moved with changes to lines 100-116 (99.6% similarity)
// Set the migrator contract. Can only be called by the owner.
function setMigrator(IMigratorChef _migrator) public onlyOwner {
migrator = _migrator;
}
// Migrate lp token to another lp contract. Can be called by anyone. We trust that migrator contract is good.
function migrate(uint256 _pid) public {
require(address(migrator) != address(0), "migrate: no migrator");
PoolInfo storage pool = poolInfo[_pid];
IERC20 lpToken = pool.lpToken;
uint256 bal = lpToken.balanceOf(address(this));
lpToken.safeApprove(address(migrator), bal);
IERC20 newLpToken = migrator.migrate(lpToken);
require(bal == newLpToken.balanceOf(address(this)), "migrate: bad");
pool.lpToken = newLpToken;
}
// Return reward multiplier over the given _from to _to block.
// Return reward multiplier over the given _from to _to block.
function getMultiplier(uint256 _from, uint256 _to) public view returns (uint256) {
function getMultiplier(uint256 _from, uint256 _to) public view returns (uint256) {
if (_to <= bonusEndBlock) {
if (_to <= bonusEndBlock) {
return _to.sub(_from).mul(BONUS_MULTIPLIER);
return _to.sub(_from).mul(BONUS_MULTIPLIER);
} else if (_from >= bonusEndBlock) {
} else if (_from >= bonusEndBlock) {
return _to.sub(_from);
return _to.sub(_from);
} else {
} else {
return bonusEndBlock.sub(_from).mul(BONUS_MULTIPLIER).add(
return bonusEndBlock.sub(_from).mul(BONUS_MULTIPLIER).add(
_to.sub(bonusEndBlock)
_to.sub(bonusEndBlock)
);
);
}
}
}
}
복사
복사됨
복사
복사됨
// View function to see pending
SUSHIs
on frontend.
// View function to see pending
STAXs
on frontend.
function pendingS
ushi
(uint256 _pid, address _user) external view returns (uint256) {
function pendingS
tax
(uint256 _pid, address _user) external view returns (uint256) {
PoolInfo storage pool = poolInfo[_pid];
PoolInfo storage pool = poolInfo[_pid];
UserInfo storage user = userInfo[_pid][_user];
UserInfo storage user = userInfo[_pid][_user];
복사
복사됨
복사
복사됨
uint256 accS
ushi
PerShare = pool.accS
ushi
PerShare;
uint256 accS
tax
PerShare = pool.accS
tax
PerShare;
uint256 lpSupply = pool.lpToken.balanceOf(address(this));
uint256 lpSupply = pool.lpToken.balanceOf(address(this));
if (block.number > pool.lastRewardBlock && lpSupply != 0) {
if (block.number > pool.lastRewardBlock && lpSupply != 0) {
uint256 multiplier = getMultiplier(pool.lastRewardBlock, block.number);
uint256 multiplier = getMultiplier(pool.lastRewardBlock, block.number);
복사
복사됨
복사
복사됨
uint256 s
ushi
Reward = multiplier.mul(s
ushi
PerBlock).mul(pool.allocPoint).div(totalAllocPoint);
uint256 s
tax
Reward = multiplier.mul(s
tax
PerBlock).mul(pool.allocPoint).div(totalAllocPoint);
accS
ushi
PerShare = accS
ushi
PerShare.add(s
ushi
Reward.mul(1e12).div(lpSupply));
accS
tax
PerShare = accS
tax
PerShare.add(s
tax
Reward.mul(1e12).div(lpSupply));
}
}
복사
복사됨
복사
복사됨
return user.amount.mul(accS
ushi
PerShare).div(1e12).sub(user.rewardDebt);
return user.amount.mul(accS
tax
PerShare).div(1e12).sub(user.rewardDebt);
}
}
// Update reward variables for all pools. Be careful of gas spending!
// Update reward variables for all pools. Be careful of gas spending!
function massUpdatePools() public {
function massUpdatePools() public {
uint256 length = poolInfo.length;
uint256 length = poolInfo.length;
for (uint256 pid = 0; pid < length; ++pid) {
for (uint256 pid = 0; pid < length; ++pid) {
updatePool(pid);
updatePool(pid);
}
}
}
}
// Update reward variables of the given pool to be up-to-date.
// Update reward variables of the given pool to be up-to-date.
function updatePool(uint256 _pid) public {
function updatePool(uint256 _pid) public {
PoolInfo storage pool = poolInfo[_pid];
PoolInfo storage pool = poolInfo[_pid];
if (block.number <= pool.lastRewardBlock) {
if (block.number <= pool.lastRewardBlock) {
return;
return;
}
}
uint256 lpSupply = pool.lpToken.balanceOf(address(this));
uint256 lpSupply = pool.lpToken.balanceOf(address(this));
if (lpSupply == 0) {
if (lpSupply == 0) {
pool.lastRewardBlock = block.number;
pool.lastRewardBlock = block.number;
return;
return;
}
}
uint256 multiplier = getMultiplier(pool.lastRewardBlock, block.number);
uint256 multiplier = getMultiplier(pool.lastRewardBlock, block.number);
복사
복사됨
복사
복사됨
uint256 s
ushi
Reward = multiplier.mul(s
ushi
PerBlock).mul(pool.allocPoint).div(totalAllocPoint);
uint256 s
tax
Reward = multiplier.mul(s
tax
PerBlock).mul(pool.allocPoint).div(totalAllocPoint);
sushi
.mint(devaddr, s
ushi
Reward.div(
10
));
stax
.mint(devaddr, s
tax
Reward.div(
8
));
sushi
.mint(address(this), s
ushi
Reward);
stax
.mint(address(this), s
tax
Reward);
pool.accS
ushi
PerShare = pool.accS
ushi
PerShare.add(s
ushi
Reward.mul(1e12).div(lpSupply));
pool.accS
tax
PerShare = pool.accS
tax
PerShare.add(s
tax
Reward.mul(1e12).div(lpSupply));
pool.lastRewardBlock = block.number;
pool.lastRewardBlock = block.number;
}
}
복사
복사됨
복사
복사됨
// Deposit LP tokens to
MasterChef
for
SUSHI
allocation.
// Deposit LP tokens to
SuperChef
for
STAX
allocation.
function deposit(uint256 _pid, uint256 _amount) public {
function deposit(uint256 _pid, uint256 _amount) public {
PoolInfo storage pool = poolInfo[_pid];
PoolInfo storage pool = poolInfo[_pid];
UserInfo storage user = userInfo[_pid][msg.sender];
UserInfo storage user = userInfo[_pid][msg.sender];
updatePool(_pid);
updatePool(_pid);
if (user.amount > 0) {
if (user.amount > 0) {
복사
복사됨
복사
복사됨
uint256 pending = user.amount.mul(pool.accS
ushi
PerShare).div(1e12).sub(user.rewardDebt);
uint256 pending = user.amount.mul(pool.accS
tax
PerShare).div(1e12).sub(user.rewardDebt);
if(pending > 0) {
if(pending > 0) {
복사
복사됨
복사
복사됨
safeS
ushi
Transfer(msg.sender, pending);
safeS
tax
Transfer(msg.sender, pending);
}
}
}
}
if(_amount > 0) {
if(_amount > 0) {
pool.lpToken.safeTransferFrom(address(msg.sender), address(this), _amount);
pool.lpToken.safeTransferFrom(address(msg.sender), address(this), _amount);
user.amount = user.amount.add(_amount);
user.amount = user.amount.add(_amount);
}
}
복사
복사됨
복사
복사됨
user.rewardDebt = user.amount.mul(pool.accS
ushi
PerShare).div(1e12);
user.rewardDebt = user.amount.mul(pool.accS
tax
PerShare).div(1e12);
emit Deposit(msg.sender, _pid, _amount);
emit Deposit(msg.sender, _pid, _amount);
}
}
복사
복사됨
복사
복사됨
// Withdraw LP tokens from
MasterChef
.
// Withdraw LP tokens from
SuperChef
.
function withdraw(uint256 _pid, uint256 _amount) public {
function withdraw(uint256 _pid, uint256 _amount) public {
PoolInfo storage pool = poolInfo[_pid];
PoolInfo storage pool = poolInfo[_pid];
UserInfo storage user = userInfo[_pid][msg.sender];
UserInfo storage user = userInfo[_pid][msg.sender];
require(user.amount >= _amount, "withdraw: not good");
require(user.amount >= _amount, "withdraw: not good");
updatePool(_pid);
updatePool(_pid);
복사
복사됨
복사
복사됨
uint256 pending = user.amount.mul(pool.accS
ushi
PerShare).div(1e12).sub(user.rewardDebt);
uint256 pending = user.amount.mul(pool.accS
tax
PerShare).div(1e12).sub(user.rewardDebt);
if(pending > 0) {
if(pending > 0) {
복사
복사됨
복사
복사됨
safeS
ushi
Transfer(msg.sender, pending);
safeS
tax
Transfer(msg.sender, pending);
}
}
if(_amount > 0) {
if(_amount > 0) {
user.amount = user.amount.sub(_amount);
user.amount = user.amount.sub(_amount);
pool.lpToken.safeTransfer(address(msg.sender), _amount);
pool.lpToken.safeTransfer(address(msg.sender), _amount);
}
}
복사
복사됨
복사
복사됨
user.rewardDebt = user.amount.mul(pool.accS
ushi
PerShare).div(1e12);
user.rewardDebt = user.amount.mul(pool.accS
tax
PerShare).div(1e12);
emit Withdraw(msg.sender, _pid, _amount);
emit Withdraw(msg.sender, _pid, _amount);
}
}
// Withdraw without caring about rewards. EMERGENCY ONLY.
// Withdraw without caring about rewards. EMERGENCY ONLY.
function emergencyWithdraw(uint256 _pid) public {
function emergencyWithdraw(uint256 _pid) public {
PoolInfo storage pool = poolInfo[_pid];
PoolInfo storage pool = poolInfo[_pid];
UserInfo storage user = userInfo[_pid][msg.sender];
UserInfo storage user = userInfo[_pid][msg.sender];
pool.lpToken.safeTransfer(address(msg.sender), user.amount);
pool.lpToken.safeTransfer(address(msg.sender), user.amount);
emit EmergencyWithdraw(msg.sender, _pid, user.amount);
emit EmergencyWithdraw(msg.sender, _pid, user.amount);
user.amount = 0;
user.amount = 0;
user.rewardDebt = 0;
user.rewardDebt = 0;
}
}
복사
복사됨
복사
복사됨
// Safe
sushi
transfer function, just in case if rounding error causes pool to not have enough
SUSHIs
.
// Safe
stax
transfer function, just in case if rounding error causes pool to not have enough
STAXs
.
function safeS
ushi
Transfer(address _to, uint256 _amount) internal {
function safeS
tax
Transfer(address _to, uint256 _amount) internal {
uint256
sushiBal
=
sushi
.balanceOf(address(this));
uint256
staxBal
=
stax
.balanceOf(address(this));
if (_amount >
sushiBal
) {
if (_amount >
staxBal
) {
sushi
.transfer(_to,
sushiBal
);
stax
.transfer(_to,
staxBal
);
} else {
} else {
복사
복사됨
복사
복사됨
sushi
.transfer(_to, _amount);
stax
.transfer(_to, _amount);
}
}
}
}
// Update dev address by the previous dev.
// Update dev address by the previous dev.
function dev(address _devaddr) public {
function dev(address _devaddr) public {
require(msg.sender == devaddr, "dev: wut?");
require(msg.sender == devaddr, "dev: wut?");
devaddr = _devaddr;
devaddr = _devaddr;
}
}
}
}
저장된 비교 결과
원본
파일 열기
pragma solidity 0.6.12; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; import "@openzeppelin/contracts/utils/EnumerableSet.sol"; import "@openzeppelin/contracts/math/SafeMath.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "./SushiToken.sol"; interface IMigratorChef { // Perform LP token migration from legacy UniswapV2 to SushiSwap. // Take the current LP token address and return the new LP token address. // Migrator should have full access to the caller's LP token. // Return the new LP token address. // // XXX Migrator must have allowance access to UniswapV2 LP tokens. // SushiSwap must mint EXACTLY the same amount of SushiSwap LP tokens or // else something bad will happen. Traditional UniswapV2 does not // do that so be careful! function migrate(IERC20 token) external returns (IERC20); } // MasterChef is the master of Sushi. He can make Sushi and he is a fair guy. // // Note that it's ownable and the owner wields tremendous power. The ownership // will be transferred to a governance smart contract once SUSHI is sufficiently // distributed and the community can show to govern itself. // // Have fun reading it. Hopefully it's bug-free. God bless. contract MasterChef is Ownable { using SafeMath for uint256; using SafeERC20 for IERC20; // Info of each user. struct UserInfo { uint256 amount; // How many LP tokens the user has provided. uint256 rewardDebt; // Reward debt. See explanation below. // // We do some fancy math here. Basically, any point in time, the amount of SUSHIs // entitled to a user but is pending to be distributed is: // // pending reward = (user.amount * pool.accSushiPerShare) - user.rewardDebt // // Whenever a user deposits or withdraws LP tokens to a pool. Here's what happens: // 1. The pool's `accSushiPerShare` (and `lastRewardBlock`) gets updated. // 2. User receives the pending reward sent to his/her address. // 3. User's `amount` gets updated. // 4. User's `rewardDebt` gets updated. } // Info of each pool. struct PoolInfo { IERC20 lpToken; // Address of LP token contract. uint256 allocPoint; // How many allocation points assigned to this pool. SUSHIs to distribute per block. uint256 lastRewardBlock; // Last block number that SUSHIs distribution occurs. uint256 accSushiPerShare; // Accumulated SUSHIs per share, times 1e12. See below. } // The SUSHI TOKEN! SushiToken public sushi; // Dev address. address public devaddr; // Block number when bonus SUSHI period ends. uint256 public bonusEndBlock; // SUSHI tokens created per block. uint256 public sushiPerBlock; // Bonus muliplier for early sushi makers. uint256 public constant BONUS_MULTIPLIER = 10; // The migrator contract. It has a lot of power. Can only be set through governance (owner). IMigratorChef public migrator; // Info of each pool. PoolInfo[] public poolInfo; // Info of each user that stakes LP tokens. mapping (uint256 => mapping (address => UserInfo)) public userInfo; // Total allocation points. Must be the sum of all allocation points in all pools. uint256 public totalAllocPoint = 0; // The block number when SUSHI mining starts. uint256 public startBlock; event Deposit(address indexed user, uint256 indexed pid, uint256 amount); event Withdraw(address indexed user, uint256 indexed pid, uint256 amount); event EmergencyWithdraw(address indexed user, uint256 indexed pid, uint256 amount); constructor( SushiToken _sushi, address _devaddr, uint256 _sushiPerBlock, uint256 _startBlock, uint256 _bonusEndBlock ) public { sushi = _sushi; devaddr = _devaddr; sushiPerBlock = _sushiPerBlock; bonusEndBlock = _bonusEndBlock; startBlock = _startBlock; } function poolLength() external view returns (uint256) { return poolInfo.length; } // Add a new lp to the pool. Can only be called by the owner. // XXX DO NOT add the same LP token more than once. Rewards will be messed up if you do. function add(uint256 _allocPoint, IERC20 _lpToken, bool _withUpdate) public onlyOwner { if (_withUpdate) { massUpdatePools(); } uint256 lastRewardBlock = block.number > startBlock ? block.number : startBlock; totalAllocPoint = totalAllocPoint.add(_allocPoint); poolInfo.push(PoolInfo({ lpToken: _lpToken, allocPoint: _allocPoint, lastRewardBlock: lastRewardBlock, accSushiPerShare: 0 })); } // Update the given pool's SUSHI allocation point. Can only be called by the owner. function set(uint256 _pid, uint256 _allocPoint, bool _withUpdate) public onlyOwner { if (_withUpdate) { massUpdatePools(); } totalAllocPoint = totalAllocPoint.sub(poolInfo[_pid].allocPoint).add(_allocPoint); poolInfo[_pid].allocPoint = _allocPoint; } // Set the migrator contract. Can only be called by the owner. function setMigrator(IMigratorChef _migrator) public onlyOwner { migrator = _migrator; } // Migrate lp token to another lp contract. Can be called by anyone. We trust that migrator contract is good. function migrate(uint256 _pid) public { require(address(migrator) != address(0), "migrate: no migrator"); PoolInfo storage pool = poolInfo[_pid]; IERC20 lpToken = pool.lpToken; uint256 bal = lpToken.balanceOf(address(this)); lpToken.safeApprove(address(migrator), bal); IERC20 newLpToken = migrator.migrate(lpToken); require(bal == newLpToken.balanceOf(address(this)), "migrate: bad"); pool.lpToken = newLpToken; } // Return reward multiplier over the given _from to _to block. function getMultiplier(uint256 _from, uint256 _to) public view returns (uint256) { if (_to <= bonusEndBlock) { return _to.sub(_from).mul(BONUS_MULTIPLIER); } else if (_from >= bonusEndBlock) { return _to.sub(_from); } else { return bonusEndBlock.sub(_from).mul(BONUS_MULTIPLIER).add( _to.sub(bonusEndBlock) ); } } // View function to see pending SUSHIs on frontend. function pendingSushi(uint256 _pid, address _user) external view returns (uint256) { PoolInfo storage pool = poolInfo[_pid]; UserInfo storage user = userInfo[_pid][_user]; uint256 accSushiPerShare = pool.accSushiPerShare; uint256 lpSupply = pool.lpToken.balanceOf(address(this)); if (block.number > pool.lastRewardBlock && lpSupply != 0) { uint256 multiplier = getMultiplier(pool.lastRewardBlock, block.number); uint256 sushiReward = multiplier.mul(sushiPerBlock).mul(pool.allocPoint).div(totalAllocPoint); accSushiPerShare = accSushiPerShare.add(sushiReward.mul(1e12).div(lpSupply)); } return user.amount.mul(accSushiPerShare).div(1e12).sub(user.rewardDebt); } // Update reward variables for all pools. Be careful of gas spending! function massUpdatePools() public { uint256 length = poolInfo.length; for (uint256 pid = 0; pid < length; ++pid) { updatePool(pid); } } // Update reward variables of the given pool to be up-to-date. function updatePool(uint256 _pid) public { PoolInfo storage pool = poolInfo[_pid]; if (block.number <= pool.lastRewardBlock) { return; } uint256 lpSupply = pool.lpToken.balanceOf(address(this)); if (lpSupply == 0) { pool.lastRewardBlock = block.number; return; } uint256 multiplier = getMultiplier(pool.lastRewardBlock, block.number); uint256 sushiReward = multiplier.mul(sushiPerBlock).mul(pool.allocPoint).div(totalAllocPoint); sushi.mint(devaddr, sushiReward.div(10)); sushi.mint(address(this), sushiReward); pool.accSushiPerShare = pool.accSushiPerShare.add(sushiReward.mul(1e12).div(lpSupply)); pool.lastRewardBlock = block.number; } // Deposit LP tokens to MasterChef for SUSHI allocation. function deposit(uint256 _pid, uint256 _amount) public { PoolInfo storage pool = poolInfo[_pid]; UserInfo storage user = userInfo[_pid][msg.sender]; updatePool(_pid); if (user.amount > 0) { uint256 pending = user.amount.mul(pool.accSushiPerShare).div(1e12).sub(user.rewardDebt); if(pending > 0) { safeSushiTransfer(msg.sender, pending); } } if(_amount > 0) { pool.lpToken.safeTransferFrom(address(msg.sender), address(this), _amount); user.amount = user.amount.add(_amount); } user.rewardDebt = user.amount.mul(pool.accSushiPerShare).div(1e12); emit Deposit(msg.sender, _pid, _amount); } // Withdraw LP tokens from MasterChef. function withdraw(uint256 _pid, uint256 _amount) public { PoolInfo storage pool = poolInfo[_pid]; UserInfo storage user = userInfo[_pid][msg.sender]; require(user.amount >= _amount, "withdraw: not good"); updatePool(_pid); uint256 pending = user.amount.mul(pool.accSushiPerShare).div(1e12).sub(user.rewardDebt); if(pending > 0) { safeSushiTransfer(msg.sender, pending); } if(_amount > 0) { user.amount = user.amount.sub(_amount); pool.lpToken.safeTransfer(address(msg.sender), _amount); } user.rewardDebt = user.amount.mul(pool.accSushiPerShare).div(1e12); emit Withdraw(msg.sender, _pid, _amount); } // Withdraw without caring about rewards. EMERGENCY ONLY. function emergencyWithdraw(uint256 _pid) public { PoolInfo storage pool = poolInfo[_pid]; UserInfo storage user = userInfo[_pid][msg.sender]; pool.lpToken.safeTransfer(address(msg.sender), user.amount); emit EmergencyWithdraw(msg.sender, _pid, user.amount); user.amount = 0; user.rewardDebt = 0; } // Safe sushi transfer function, just in case if rounding error causes pool to not have enough SUSHIs. function safeSushiTransfer(address _to, uint256 _amount) internal { uint256 sushiBal = sushi.balanceOf(address(this)); if (_amount > sushiBal) { sushi.transfer(_to, sushiBal); } else { sushi.transfer(_to, _amount); } } // Update dev address by the previous dev. function dev(address _devaddr) public { require(msg.sender == devaddr, "dev: wut?"); devaddr = _devaddr; } }
수정본
파일 열기
pragma solidity 0.6.12; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; import "@openzeppelin/contracts/utils/EnumerableSet.sol"; import "@openzeppelin/contracts/math/SafeMath.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "./StaxToken.sol"; interface IMigratorChef { // Perform LP token migration from legacy PancakeSwap to StableX Swap. // Take the current LP token address and return the new LP token address. // Migrator should have full access to the caller's LP token. // Return the new LP token address. // // XXX Migrator must have allowance access to PancakeSwap LP tokens. // CakeSwap must mint EXACTLY the same amount of CakeSwap LP tokens or // else something bad will happen. Traditional PancakeSwap does not // do that so be careful! function migrate(IBEP20 token) external returns (IBEP20); } // SuperChef is the master of StableX. He can make STAX and he is a fair guy. // // Note that it's ownable and the owner wields tremendous power. The ownership // will be transferred to a governance smart contract once STAX is sufficiently // distributed and the community can show to govern itself. // // Have fun reading it. Hopefully it's bug-free. God bless. contract SuperChef is Ownable { using SafeMath for uint256; using SafeERC20 for IERC20; // Info of each user. struct UserInfo { uint256 amount; // How many LP tokens the user has provided. uint256 rewardDebt; // Reward debt. See explanation below. // // We do some fancy math here. Basically, any point in time, the amount of STAXs // entitled to a user but is pending to be distributed is: // // pending reward = (user.amount * pool.accStaxPerShare) - user.rewardDebt // // Whenever a user deposits or withdraws LP tokens to a pool. Here's what happens: // 1. The pool's `accStaxPerShare` (and `lastRewardBlock`) gets updated. // 2. User receives the pending reward sent to his/her address. // 3. User's `amount` gets updated. // 4. User's `rewardDebt` gets updated. } // Info of each pool. struct PoolInfo { IERC20 lpToken; // Address of LP token contract. uint256 allocPoint; // How many allocation points assigned to this pool. uint256 lastRewardBlock; // Last block number that STAXs distribution occurs. uint256 accStaxPerShare; // Accumulated STAXs per share, times 1e12. See below. } // The STAX TOKEN! StaxToken public stax; // Dev address. address public devaddr; // Block number when bonus STAX period ends. uint256 public bonusEndBlock; // STAX tokens created per block. uint256 public staxPerBlock; // Bonus muliplier for early stax makers. uint256 public constant BONUS_MULTIPLIER = 10; // The migrator contract. It has a lot of power. Can only be set through governance (owner). IMigratorChef public migrator; // Info of each pool. PoolInfo[] public poolInfo; // Info of each user that stakes LP tokens. mapping (uint256 => mapping (address => UserInfo)) public userInfo; // Total allocation poitns. Must be the sum of all allocation points in all pools. uint256 public totalAllocPoint = 0; // The block number when STAX mining starts. uint256 public startBlock; event Deposit(address indexed user, uint256 indexed pid, uint256 amount); event Withdraw(address indexed user, uint256 indexed pid, uint256 amount); event EmergencyWithdraw(address indexed user, uint256 indexed pid, uint256 amount); constructor( StaxToken _stax, address _devaddr, uint256 _staxPerBlock, uint256 _startBlock, uint256 _bonusEndBlock ) public { stax = _stax; devaddr = _devaddr; staxPerBlock = _staxPerBlock; bonusEndBlock = _bonusEndBlock; startBlock = _startBlock; } // Set the migrator contract. Can only be called by the owner. function setMigrator(IMigratorChef _migrator) public onlyOwner { migrator = _migrator; } // Migrate lp token to another lp contract. Can be called by anyone. We trust that migrator contract is good. function migrate(uint256 _pid) public { require(address(migrator) != address(0), "migrate: no migrator"); PoolInfo storage pool = poolInfo[_pid]; IBEP20 lpToken = pool.lpToken; uint256 bal = lpToken.balanceOf(address(this)); lpToken.safeApprove(address(migrator), bal); IBEP20 newLpToken = migrator.migrate(lpToken); require(bal == newLpToken.balanceOf(address(this)), "migrate: bad"); pool.lpToken = newLpToken; } function poolLength() external view returns (uint256) { return poolInfo.length; } // Add a new lp to the pool. Can only be called by the owner. // XXX DO NOT add the same LP token more than once. Rewards will be messed up if you do. function add(uint256 _allocPoint, IERC20 _lpToken, bool _withUpdate) public onlyOwner { if (_withUpdate) { massUpdatePools(); } uint256 lastRewardBlock = block.number > startBlock ? block.number : startBlock; totalAllocPoint = totalAllocPoint.add(_allocPoint); poolInfo.push(PoolInfo({ lpToken: _lpToken, allocPoint: _allocPoint, lastRewardBlock: lastRewardBlock, accStaxPerShare: 0 })); } // Update the given pool's STAX allocation point. Can only be called by the owner. function set(uint256 _pid, uint256 _allocPoint, bool _withUpdate) public onlyOwner { if (_withUpdate) { massUpdatePools(); } totalAllocPoint = totalAllocPoint.sub(poolInfo[_pid].allocPoint).add(_allocPoint); poolInfo[_pid].allocPoint = _allocPoint; } // Return reward multiplier over the given _from to _to block. function getMultiplier(uint256 _from, uint256 _to) public view returns (uint256) { if (_to <= bonusEndBlock) { return _to.sub(_from).mul(BONUS_MULTIPLIER); } else if (_from >= bonusEndBlock) { return _to.sub(_from); } else { return bonusEndBlock.sub(_from).mul(BONUS_MULTIPLIER).add( _to.sub(bonusEndBlock) ); } } // View function to see pending STAXs on frontend. function pendingStax(uint256 _pid, address _user) external view returns (uint256) { PoolInfo storage pool = poolInfo[_pid]; UserInfo storage user = userInfo[_pid][_user]; uint256 accStaxPerShare = pool.accStaxPerShare; uint256 lpSupply = pool.lpToken.balanceOf(address(this)); if (block.number > pool.lastRewardBlock && lpSupply != 0) { uint256 multiplier = getMultiplier(pool.lastRewardBlock, block.number); uint256 staxReward = multiplier.mul(staxPerBlock).mul(pool.allocPoint).div(totalAllocPoint); accStaxPerShare = accStaxPerShare.add(staxReward.mul(1e12).div(lpSupply)); } return user.amount.mul(accStaxPerShare).div(1e12).sub(user.rewardDebt); } // Update reward variables for all pools. Be careful of gas spending! function massUpdatePools() public { uint256 length = poolInfo.length; for (uint256 pid = 0; pid < length; ++pid) { updatePool(pid); } } // Update reward variables of the given pool to be up-to-date. function updatePool(uint256 _pid) public { PoolInfo storage pool = poolInfo[_pid]; if (block.number <= pool.lastRewardBlock) { return; } uint256 lpSupply = pool.lpToken.balanceOf(address(this)); if (lpSupply == 0) { pool.lastRewardBlock = block.number; return; } uint256 multiplier = getMultiplier(pool.lastRewardBlock, block.number); uint256 staxReward = multiplier.mul(staxPerBlock).mul(pool.allocPoint).div(totalAllocPoint); stax.mint(devaddr, staxReward.div(8)); stax.mint(address(this), staxReward); pool.accStaxPerShare = pool.accStaxPerShare.add(staxReward.mul(1e12).div(lpSupply)); pool.lastRewardBlock = block.number; } // Deposit LP tokens to SuperChef for STAX allocation. function deposit(uint256 _pid, uint256 _amount) public { PoolInfo storage pool = poolInfo[_pid]; UserInfo storage user = userInfo[_pid][msg.sender]; updatePool(_pid); if (user.amount > 0) { uint256 pending = user.amount.mul(pool.accStaxPerShare).div(1e12).sub(user.rewardDebt); if(pending > 0) { safeStaxTransfer(msg.sender, pending); } } if(_amount > 0) { pool.lpToken.safeTransferFrom(address(msg.sender), address(this), _amount); user.amount = user.amount.add(_amount); } user.rewardDebt = user.amount.mul(pool.accStaxPerShare).div(1e12); emit Deposit(msg.sender, _pid, _amount); } // Withdraw LP tokens from SuperChef. function withdraw(uint256 _pid, uint256 _amount) public { PoolInfo storage pool = poolInfo[_pid]; UserInfo storage user = userInfo[_pid][msg.sender]; require(user.amount >= _amount, "withdraw: not good"); updatePool(_pid); uint256 pending = user.amount.mul(pool.accStaxPerShare).div(1e12).sub(user.rewardDebt); if(pending > 0) { safeStaxTransfer(msg.sender, pending); } if(_amount > 0) { user.amount = user.amount.sub(_amount); pool.lpToken.safeTransfer(address(msg.sender), _amount); } user.rewardDebt = user.amount.mul(pool.accStaxPerShare).div(1e12); emit Withdraw(msg.sender, _pid, _amount); } // Withdraw without caring about rewards. EMERGENCY ONLY. function emergencyWithdraw(uint256 _pid) public { PoolInfo storage pool = poolInfo[_pid]; UserInfo storage user = userInfo[_pid][msg.sender]; pool.lpToken.safeTransfer(address(msg.sender), user.amount); emit EmergencyWithdraw(msg.sender, _pid, user.amount); user.amount = 0; user.rewardDebt = 0; } // Safe stax transfer function, just in case if rounding error causes pool to not have enough STAXs. function safeStaxTransfer(address _to, uint256 _amount) internal { uint256 staxBal = stax.balanceOf(address(this)); if (_amount > staxBal) { stax.transfer(_to, staxBal); } else { stax.transfer(_to, _amount); } } // Update dev address by the previous dev. function dev(address _devaddr) public { require(msg.sender == devaddr, "dev: wut?"); devaddr = _devaddr; } }
비교하기