Diff
checker
Texte
Texte
Images
Documents
Excel
Dossiers
Legal
Enterprise
Application de bureau
Prix
Se connecter
Télécharger Diffchecker Desktop
Comparer le texte
Trouver la différence entre deux fichiers texte
Outils
Historique
Éditeur live
Cacher identiques
Sans retour à la ligne
Vue
Divisé
Unifié
Niveau de précision
Intelligent
Mot
Caractère
Coloration syntaxique
Choisir la syntaxe
Ignorer
Transformer le texte
Aller au premier écart
Modifier l'entrée
Diffchecker Desktop
La façon la plus sécurisée d'utiliser Diffchecker. Obtenez l'application Diffchecker Desktop : vos diffs ne quittent jamais votre ordinateur !
Obtenir Desktop
StableXSwap Code versus SushiChef.sol
Créé
il y a 6 ans
Le diff n'expire jamais
Effacer
Exporter
Partager
Expliquer
94 suppressions
Lignes
Total
Supprimé
Caractères
Total
Supprimé
Pour continuer à utiliser cette fonctionnalité, passez à
Diff
checker
Pro
Voir les prix
263 lignes
Copier tout
92 ajouts
Lignes
Total
Ajouté
Caractères
Total
Ajouté
Pour continuer à utiliser cette fonctionnalité, passez à
Diff
checker
Pro
Voir les prix
262 lignes
Copier tout
pragma solidity 0.6.12;
pragma solidity 0.6.12;
Copier
Copié
Copier
Copié
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";
Copier
Copié
Copier
Copié
import "./
SushiToken
.sol";
import "./
StaxToken
.sol";
interface IMigratorChef {
interface IMigratorChef {
Copier
Copié
Copier
Copié
// 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.
//
//
Copier
Copié
Copier
Copié
// 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!
Copier
Copié
Copier
Copié
function migrate(I
ERC
20 token) external returns (I
ERC
20);
function migrate(I
BEP
20 token) external returns (I
BEP
20);
}
}
Copier
Copié
Copier
Copié
//
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
Copier
Copié
Copier
Copié
// 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.
Copier
Copié
Copier
Copié
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.
//
//
Copier
Copié
Copier
Copié
// 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:
//
//
Copier
Copié
Copier
Copié
// 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:
Copier
Copié
Copier
Copié
// 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.
Copier
Copié
Copier
Copié
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.
}
}
Copier
Copié
Copier
Copié
// The
SUSHI
TOKEN!
// The
STAX
TOKEN!
SushiToken
public
sushi
;
StaxToken
public
stax
;
// Dev address.
// Dev address.
address public devaddr;
address public devaddr;
Copier
Copié
Copier
Copié
// Block number when bonus
SUSHI
period ends.
// Block number when bonus
STAX
period ends.
uint256 public bonusEndBlock;
uint256 public bonusEndBlock;
Copier
Copié
Copier
Copié
//
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;
Copier
Copié
Copier
Copié
// 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;
Copier
Copié
Copier
Copié
// 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(
Copier
Copié
Copier
Copié
SushiToken _sushi
,
StaxToken _stax
,
address _devaddr,
address _devaddr,
Copier
Copié
Copier
Copié
uint256 _s
ushi
PerBlock,
uint256 _s
tax
PerBlock,
uint256 _startBlock,
uint256 _startBlock,
uint256 _bonusEndBlock
uint256 _bonusEndBlock
) public {
) public {
Copier
Copié
Copier
Copié
sushi
= _
sushi
;
stax
= _
stax
;
devaddr = _devaddr;
devaddr = _devaddr;
Copier
Copié
Copier
Copié
s
ushi
PerBlock = _s
ushi
PerBlock;
s
tax
PerBlock = _s
tax
PerBlock;
bonusEndBlock = _bonusEndBlock;
bonusEndBlock = _bonusEndBlock;
startBlock = _startBlock;
startBlock = _startBlock;
}
}
Copier
Copié
Copier
Copié
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,
Copier
Copié
Copier
Copié
accS
ushi
PerShare: 0
accS
tax
PerShare: 0
}));
}));
}
}
Copier
Copié
Copier
Copié
// 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;
}
}
Copier
Copié
Copier
Copié
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)
);
);
}
}
}
}
Copier
Copié
Copier
Copié
// 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];
Copier
Copié
Copier
Copié
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);
Copier
Copié
Copier
Copié
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));
}
}
Copier
Copié
Copier
Copié
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);
Copier
Copié
Copier
Copié
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;
}
}
Copier
Copié
Copier
Copié
// 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) {
Copier
Copié
Copier
Copié
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) {
Copier
Copié
Copier
Copié
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);
}
}
Copier
Copié
Copier
Copié
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);
}
}
Copier
Copié
Copier
Copié
// 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);
Copier
Copié
Copier
Copié
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) {
Copier
Copié
Copier
Copié
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);
}
}
Copier
Copié
Copier
Copié
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;
}
}
Copier
Copié
Copier
Copié
// 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 {
Copier
Copié
Copier
Copié
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;
}
}
}
}
Différences enregistrées
Texte d'origine
Ouvrir un fichier
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; } }
Texte modifié
Ouvrir un fichier
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; } }
Trouver la différence