¡El código fuente de este contrato está verificado!
Metadatos del Contrato
Compilador
0.8.7+commit.e28d00a7
Idioma
Solidity
Código Fuente del Contrato
Archivo 1 de 9: Address.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;/**
* @dev Collection of functions related to the address type
*/libraryAddress{
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*/functionisContract(address account) internalviewreturns (bool) {
// This method relies on extcodesize, which returns 0 for contracts in// construction, since the code is only stored at the end of the// constructor execution.uint256 size;
assembly {
size :=extcodesize(account)
}
return size >0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/functionsendValue(addresspayable recipient, uint256 amount) internal{
require(address(this).balance>= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/functionfunctionCall(address target, bytesmemory data) internalreturns (bytesmemory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/functionfunctionCall(address target,
bytesmemory data,
stringmemory errorMessage
) internalreturns (bytesmemory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/functionfunctionCallWithValue(address target,
bytesmemory data,
uint256 value
) internalreturns (bytesmemory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/functionfunctionCallWithValue(address target,
bytesmemory data,
uint256 value,
stringmemory errorMessage
) internalreturns (bytesmemory) {
require(address(this).balance>= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytesmemory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/functionfunctionStaticCall(address target, bytesmemory data) internalviewreturns (bytesmemory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/functionfunctionStaticCall(address target,
bytesmemory data,
stringmemory errorMessage
) internalviewreturns (bytesmemory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytesmemory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/functionfunctionDelegateCall(address target, bytesmemory data) internalreturns (bytesmemory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/functionfunctionDelegateCall(address target,
bytesmemory data,
stringmemory errorMessage
) internalreturns (bytesmemory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytesmemory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/functionverifyCallResult(bool success,
bytesmemory returndata,
stringmemory errorMessage
) internalpurereturns (bytesmemory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if presentif (returndata.length>0) {
// The easiest way to bubble the revert reason is using memory via assemblyassembly {
let returndata_size :=mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
Código Fuente del Contrato
Archivo 2 de 9: Context.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/abstractcontractContext{
function_msgSender() internalviewvirtualreturns (address) {
returnmsg.sender;
}
function_msgData() internalviewvirtualreturns (bytescalldata) {
returnmsg.data;
}
}
Código Fuente del Contrato
Archivo 3 de 9: IERC20.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/interfaceIERC20{
/**
* @dev Returns the amount of tokens in existence.
*/functiontotalSupply() externalviewreturns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/functionbalanceOf(address account) externalviewreturns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/functiontransfer(address recipient, uint256 amount) externalreturns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/functionallowance(address owner, address spender) externalviewreturns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/functionapprove(address spender, uint256 amount) externalreturns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/functiontransferFrom(address sender,
address recipient,
uint256 amount
) externalreturns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/eventTransfer(addressindexedfrom, addressindexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/eventApproval(addressindexed owner, addressindexed spender, uint256 value);
}
// SPDX-License-Identifier: UNLICENSEDpragmasolidity 0.8.7;import"@openzeppelin/contracts/access/Ownable.sol";
import"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import"../interfaces/IRewarder.sol";
import"../interfaces/IFundDistributor.sol";
import"../interfaces/ITokenUtilityModule.sol";
/* IronChef is a fork from Sushi's MiniChef v2 with slightly modification.
1. Rewards will be transferred from a seperated contract so that it will be more flexible to switch between:
[mint reward token directly] OR [transfer them instead]
2. Add a Harvest all function to quickly harvest rewards from all the deposited pools
Sharedstakes masterchef is in turn a fork of ironchef
We add a TokenUtilityModule to boost/reduce user rewards depending on variables such as veSGT & NFTs
Sushi: https://github.com/sushiswap/sushiswap/blob/canary/contracts/MasterChefV2.sol
Iron: https://github.com/chimera-defi/iron-core-v2/blob/master/contracts/IronChef.sol
Sharedstake: https://github.com/chimera-defi/SharedDeposit/blob/main/contracts/governance/MasterChef.sol
*/contractMasterChefisOwnable{
usingSafeERC20forIERC20;
structUserInfo {
uint256 amount;
int256 rewardDebt;
}
structPoolInfo {
uint256 accRewardPerShare;
uint256 lastRewardTime;
uint256 allocPoint;
}
IERC20 public reward;
IFundDistributor public fund;
/// @notice Info of each MCV2 pool.
PoolInfo[] public poolInfo;
/// @notice Address of the LP token for each MCV2 pool.
IERC20[] public lpToken;
/// @notice Address of each `IRewarder` contract in MCV2.
IRewarder[] public rewarder;
/// @notice Info of each user that stakes LP tokens.mapping(uint256=>mapping(address=> UserInfo)) public userInfo;
/// @dev Total allocation points. Must be the sum of all allocation points in all pools.uint256public totalAllocPoint =0;
uint256public rewardPerSecond;
uint256publicconstant ACC_REWARD_PRECISION =1e12;
// Additions
ITokenUtilityModule public tokenUtilityModule;
/* =============== EVENTS ==================== */eventDeposit(addressindexed user, uint256indexed pid, uint256 amount, addressindexed to);
eventWithdraw(addressindexed user, uint256indexed pid, uint256 amount, addressindexed to);
eventEmergencyWithdraw(addressindexed user, uint256indexed pid, uint256 amount, addressindexed to);
eventHarvest(addressindexed user, uint256indexed pid, uint256 amount);
eventLogPoolAddition(uint256indexed pid, uint256 allocPoint, IERC20 indexed lpToken, IRewarder indexed rewarder);
eventLogSetPool(uint256indexed pid, uint256 allocPoint, IRewarder indexed rewarder, bool overwrite);
eventLogUpdatePool(uint256indexed pid, uint256 lastRewardTime, uint256 lpSupply, uint256 accRewardPerShare);
eventLogRewardPerSecond(uint256 rewardPerSecond);
eventPoolFundChanged(addressindexed fund);
eventTokenUtilityModuleChanged(addressindexed fund);
eventErrorIgnored();
constructor(
IERC20 _reward,
IFundDistributor _fund,
ITokenUtilityModule _tum
) {
reward = _reward;
fund = _fund;
tokenUtilityModule = _tum;
}
/* ========== PUBLIC FUNCTIONS ========== *//// @notice Update reward variables for all pools. Be careful of gas spending!/// @param pids Pool IDs of all to be updated. Make sure to update all active pools.functionmassUpdatePools(uint256[] calldata pids) external{
uint256 len = pids.length;
for (uint256 i =0; i < len; ++i) {
updatePool(pids[i]);
}
}
/// @notice Deposit LP tokens to MCV2 for reward allocation./// @param pid The index of the pool. See `poolInfo`./// @param amount LP token amount to deposit./// @param to The receiver of `amount` deposit benefit.functiondeposit(uint256 pid,
uint256 amount,
address to
) external{
PoolInfo memory pool = updatePool(pid);
UserInfo storage user = userInfo[pid][to];
// Effects
user.amount += amount;
user.rewardDebt +=int256((amount * pool.accRewardPerShare) / ACC_REWARD_PRECISION);
// Interactions
IRewarder _rewarder = rewarder[pid];
if (address(_rewarder) !=address(0)) {
_rewarder.onReward(pid, to, to, 0, user.amount);
}
lpToken[pid].safeTransferFrom(msg.sender, address(this), amount);
emit Deposit(msg.sender, pid, amount, to);
}
/// @notice Withdraw LP tokens from MCV2./// @param pid The index of the pool. See `poolInfo`./// @param amount LP token amount to withdraw./// @param to Receiver of the LP tokens.functionwithdraw(uint256 pid,
uint256 amount,
address to
) external{
PoolInfo memory pool = updatePool(pid);
UserInfo storage user = userInfo[pid][msg.sender];
// Effects
user.rewardDebt -=int256((amount * pool.accRewardPerShare) / ACC_REWARD_PRECISION);
user.amount -= amount;
// Interactions
IRewarder _rewarder = rewarder[pid];
if (address(_rewarder) !=address(0)) {
_rewarder.onReward(pid, msg.sender, to, 0, user.amount);
}
lpToken[pid].safeTransfer(to, amount);
emit Withdraw(msg.sender, pid, amount, to);
}
/// @notice Harvest proceeds for transaction sender to `to`./// @param pid The index of the pool. See `poolInfo`./// @param to Receiver of rewards.functionharvest(uint256 pid, address to) external{
_harvest(pid, to);
}
/// @notice Withdraw LP tokens from MCV2 and harvest proceeds for transaction sender to `to`./// @param pid The index of the pool. See `poolInfo`./// @param amount LP token amount to withdraw./// @param to Receiver of the LP tokens and rewards.functionwithdrawAndHarvest(uint256 pid,
uint256 amount,
address to
) external{
PoolInfo memory pool = updatePool(pid);
UserInfo storage user = userInfo[pid][msg.sender];
int256 accumulatedReward =int256((user.amount * pool.accRewardPerShare) / ACC_REWARD_PRECISION);
uint256 _pendingReward =uint256(accumulatedReward - user.rewardDebt);
_pendingReward = _applyBoost(to, _pendingReward, user.amount);
// Effects
user.rewardDebt = accumulatedReward -int256((amount * pool.accRewardPerShare) / ACC_REWARD_PRECISION);
user.amount -= amount;
// Interactions
fund.distributeTo(to, _pendingReward);
IRewarder _rewarder = rewarder[pid];
if (address(_rewarder) !=address(0)) {
_rewarder.onReward(pid, msg.sender, to, _pendingReward, user.amount);
}
lpToken[pid].safeTransfer(to, amount);
emit Withdraw(msg.sender, pid, amount, to);
emit Harvest(msg.sender, pid, _pendingReward);
}
/// @notice Withdraw without caring about rewards. EMERGENCY ONLY./// @param pid The index of the pool. See `poolInfo`./// @param to Receiver of the LP tokens.functionemergencyWithdraw(uint256 pid, address to) external{
UserInfo storage user = userInfo[pid][msg.sender];
uint256 amount = user.amount;
user.amount =0;
user.rewardDebt =0;
IRewarder _rewarder = rewarder[pid];
if (address(_rewarder) !=address(0)) {
try _rewarder.onReward(pid, msg.sender, to, 0, 0) {} catch {
emit ErrorIgnored();
}
}
// Note: transfer can fail or succeed if `amount` is zero.
lpToken[pid].safeTransfer(to, amount);
emit EmergencyWithdraw(msg.sender, pid, amount, to);
}
functionharvestAllRewards(address to) external{
uint256 length = poolInfo.length;
for (uint256 pid =0; pid < length; ++pid) {
if (userInfo[pid][msg.sender].amount >0) {
_harvest(pid, to);
}
}
}
// External views/// @notice Returns the number of MCV2 pools.functionpoolLength() externalviewreturns (uint256 pools) {
pools = poolInfo.length;
}
/// @notice View function to see pending reward on frontend./// @param _pid The index of the pool. See `poolInfo`./// @param _user Address of user./// @return pending reward for a given user.functionpendingReward(uint256 _pid, address _user) externalviewreturns (uint256 pending) {
PoolInfo memory pool = poolInfo[_pid];
UserInfo storage user = userInfo[_pid][_user];
uint256 accRewardPerShare = pool.accRewardPerShare;
uint256 lpSupply = lpToken[_pid].balanceOf(address(this));
if (block.timestamp> pool.lastRewardTime && lpSupply !=0) {
uint256 time =block.timestamp- pool.lastRewardTime;
uint256 rewardAmount = (time * rewardPerSecond * pool.allocPoint) / totalAllocPoint;
accRewardPerShare += (rewardAmount * ACC_REWARD_PRECISION) / lpSupply;
}
pending =uint256(int256((user.amount * accRewardPerShare) / ACC_REWARD_PRECISION) - user.rewardDebt);
pending = _applyBoost(_user, pending, user.amount);
return pending;
}
/// @notice Update reward variables of the given pool./// @param pid The index of the pool. See `poolInfo`./// @return pool Returns the pool that was updated.functionupdatePool(uint256 pid) publicreturns (PoolInfo memory pool) {
pool = poolInfo[pid];
if (block.timestamp> pool.lastRewardTime) {
uint256 lpSupply = lpToken[pid].balanceOf(address(this));
if (lpSupply >0) {
uint256 time =block.timestamp- pool.lastRewardTime;
uint256 rewardAmount = (time * rewardPerSecond * pool.allocPoint) / totalAllocPoint;
pool.accRewardPerShare += (rewardAmount * ACC_REWARD_PRECISION) / lpSupply;
}
pool.lastRewardTime =block.timestamp;
poolInfo[pid] = pool;
emit LogUpdatePool(pid, pool.lastRewardTime, lpSupply, pool.accRewardPerShare);
}
}
/* ========== RESTRICTED FUNCTIONS ========== *//// @notice Add a new LP to the pool. Can only be called by the owner./// DO NOT add the same LP token more than once. Rewards will be messed up if you do./// @param allocPoint AP of the new pool./// @param _lpToken Address of the LP ERC-20 token./// @param _rewarder Address of the rewarder delegate.functionadd(uint256 allocPoint,
IERC20 _lpToken,
IRewarder _rewarder
) publiconlyOwner{
_checkPoolDuplicate(_lpToken);
totalAllocPoint += allocPoint;
lpToken.push(_lpToken);
rewarder.push(_rewarder);
poolInfo.push(PoolInfo({allocPoint: allocPoint, lastRewardTime: block.timestamp, accRewardPerShare: 0}));
emit LogPoolAddition(lpToken.length-1, allocPoint, _lpToken, _rewarder);
}
/// @notice Update the given pool's reward allocation point and `IRewarder` contract. Can only be called by the owner./// @param _pid The index of the pool. See `poolInfo`./// @param _allocPoint New AP of the pool./// @param _rewarder Address of the rewarder delegate./// @param overwrite True if _rewarder should be `set`. Otherwise `_rewarder` is ignored.functionset(uint256 _pid,
uint256 _allocPoint,
IRewarder _rewarder,
bool overwrite
) publiconlyOwner{
totalAllocPoint = totalAllocPoint - poolInfo[_pid].allocPoint + _allocPoint;
poolInfo[_pid].allocPoint = _allocPoint;
if (overwrite) {
rewarder[_pid] = _rewarder;
}
emit LogSetPool(_pid, _allocPoint, overwrite ? _rewarder : rewarder[_pid], overwrite);
}
/// @notice Sets the reward per second to be distributed. Can only be called by the owner./// @param _rewardPerSecond The amount of reward to be distributed per second.functionsetRewardPerSecond(uint256 _rewardPerSecond) publiconlyOwner{
rewardPerSecond = _rewardPerSecond;
emit LogRewardPerSecond(_rewardPerSecond);
}
/// @notice Set the new fund contract./// @param _fund The address of new fund contract.functionsetFund(IFundDistributor _fund) publiconlyOwner{
fund = _fund;
emit PoolFundChanged(address(_fund));
}
/// @notice Set the new token utility module/// @param _tum The address of token utility module used to get the boostfunctionsetTokenUtilityModule(ITokenUtilityModule _tum) publiconlyOwner{
tokenUtilityModule = _tum;
emit TokenUtilityModuleChanged(address(_tum));
}
/* ========== INTERNAL FUNCTIONS ========== */function_harvest(uint256 pid, address to) internal{
PoolInfo memory pool = updatePool(pid);
UserInfo storage user = userInfo[pid][msg.sender];
int256 accumulatedReward =int256((user.amount * pool.accRewardPerShare) / ACC_REWARD_PRECISION);
uint256 _pendingReward =uint256(accumulatedReward - user.rewardDebt);
_pendingReward = _applyBoost(to, _pendingReward, user.amount);
// Effects
user.rewardDebt = accumulatedReward;
// Interactions
fund.distributeTo(to, _pendingReward);
IRewarder _rewarder = rewarder[pid];
if (address(_rewarder) !=address(0)) {
_rewarder.onReward(pid, msg.sender, to, _pendingReward, user.amount);
}
emit Harvest(msg.sender, pid, _pendingReward);
}
function_applyBoost(address _user,
uint256 _pendingReward,
uint256 _supplyAmt
) internalviewreturns (uint256 boostedAmount) {
if (address(tokenUtilityModule) ==address(0)) {
boostedAmount = _pendingReward;
} else {
boostedAmount = tokenUtilityModule.getBoost(_user, address(this), _pendingReward, _supplyAmt);
}
}
function_checkPoolDuplicate(IERC20 _lpToken) internalview{
uint256 length = poolInfo.length;
for (uint256 pid =0; pid < length; ++pid) {
require(lpToken[pid] != _lpToken, "MC:AE");
}
}
}
Código Fuente del Contrato
Archivo 8 de 9: Ownable.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;import"../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/abstractcontractOwnableisContext{
addressprivate _owner;
eventOwnershipTransferred(addressindexed previousOwner, addressindexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/constructor() {
_setOwner(_msgSender());
}
/**
* @dev Returns the address of the current owner.
*/functionowner() publicviewvirtualreturns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/modifieronlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/functionrenounceOwnership() publicvirtualonlyOwner{
_setOwner(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/functiontransferOwnership(address newOwner) publicvirtualonlyOwner{
require(newOwner !=address(0), "Ownable: new owner is the zero address");
_setOwner(newOwner);
}
function_setOwner(address newOwner) private{
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
Código Fuente del Contrato
Archivo 9 de 9: SafeERC20.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;import"../IERC20.sol";
import"../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/librarySafeERC20{
usingAddressforaddress;
functionsafeTransfer(
IERC20 token,
address to,
uint256 value
) internal{
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
functionsafeTransferFrom(
IERC20 token,
addressfrom,
address to,
uint256 value
) internal{
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/functionsafeApprove(
IERC20 token,
address spender,
uint256 value
) internal{
// safeApprove should only be called when setting an initial allowance,// or when resetting it to zero. To increase and decrease it, use// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'require(
(value ==0) || (token.allowance(address(this), spender) ==0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
functionsafeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal{
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
functionsafeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal{
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/function_callOptionalReturn(IERC20 token, bytesmemory data) private{
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since// we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that// the target address contains contract code and also asserts for success in the low-level call.bytesmemory returndata =address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length>0) {
// Return data is optionalrequire(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}