Transaction Hash:
Block:
13401857 at Oct-12-2021 05:42:23 AM +UTC
Transaction Fee:
0.00504969791025804 ETH
$16.61
Gas Used:
52,546 Gas / 96.10051974 Gwei
Account State Difference:
| Address | Before | After | State Difference | ||
|---|---|---|---|---|---|
| 0xe1213Fe4...6C6f00F88 |
0.076880678300310382 Eth
Nonce: 84
|
0.071830980390052342 Eth
Nonce: 85
| 0.00504969791025804 | ||
|
0xEA674fdD...16B898ec8
Miner
| (Ethermine) | 2,971.152634416422250936 Eth | 2,971.152820102519978092 Eth | 0.000185686097727156 |
Execution Trace
0x11bf850d1b85ea02ef9f06cf09488e443655b586.CALL( )
-
ManyToOneImplementationHolder.STATICCALL( )
-
StakingRewards.DELEGATECALL( )
File 1 of 2: ManyToOneImplementationHolder
File 2 of 2: StakingRewards
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.6.0;
/**
* @dev Because we use the code hashes of the proxy contracts for proxy address
* derivation, it is important that other packages have access to the correct
* values when they import the salt library.
*/
library CodeHashes {
bytes32 internal constant ONE_TO_ONE_CODEHASH = 0x63d9f7b5931b69188c8f6b806606f25892f1bb17b7f7e966fe3a32c04493aee4;
bytes32 internal constant MANY_TO_ONE_CODEHASH = 0xa035ad05a1663db5bfd455b99cd7c6ac6bd49269738458eda140e0b78ed53f79;
bytes32 internal constant IMPLEMENTATION_HOLDER_CODEHASH = 0x11c370493a726a0ffa93d42b399ad046f1b5a543b6e72f1a64f1488dc1c58f2c;
}// SPDX-License-Identifier: GPL-3.0
pragma solidity =0.6.12;
/* ========== External Libraries ========== */
import { Create2 } from "@openzeppelin/contracts/utils/Create2.sol";
import { Address } from "@openzeppelin/contracts/utils/Address.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
/* ========== Proxy Contracts ========== */
import "./ManyToOneImplementationHolder.sol";
import { DelegateCallProxyManyToOne } from "./DelegateCallProxyManyToOne.sol";
import { DelegateCallProxyOneToOne } from "./DelegateCallProxyOneToOne.sol";
/* ========== Internal Libraries ========== */
import { SaltyLib as Salty } from "./SaltyLib.sol";
import { CodeHashes } from "./CodeHashes.sol";
/* ========== Inheritance ========== */
import "./interfaces/IDelegateCallProxyManager.sol";
/**
* @dev Contract that manages deployment and upgrades of delegatecall proxies.
*
* An implementation identifier can be created on the proxy manager which is
* used to specify the logic address for a particular contract type, and to
* upgrade the implementation as needed.
*
* ====== Proxy Types ======
* A one-to-one proxy is a single proxy contract with an upgradeable implementation
* address.
*
* A many-to-one proxy is a single upgradeable implementation address that may be
* used by many proxy contracts.
*
* ====== Access Control ======
* The proxy manager has a single address as its owner.
*
* The owner is the sole account with the following permissions:
* - Create new many-to-one implementations
* - Create new one-to-one proxies
* - Modify the implementation address of existing proxies
* - Lock proxies
* - Designate approved deployers
* - Remove approved deployers
* - Modify the owner address
*
* Approved deployers may only deploy many-to-one proxies.
*
* ====== Upgrades ======
* Proxies can be upgraded by the owner if they are not locked.
*
* Many-to-one proxy implementations are upgraded by calling the holder contract
* for the implementation ID being upgraded.
* One-to-one proxies are upgraded by calling the proxy contract directly.
*
* The owner can lock a one-to-one proxy or many-to-one implementation ID so that
* it becomes impossible to upgrade.
*/
contract DelegateCallProxyManager is Ownable, IDelegateCallProxyManager {
/* ========== Events ========== */
event DeploymentApprovalGranted(address deployer);
event DeploymentApprovalRevoked(address deployer);
event ManyToOne_ImplementationCreated(
bytes32 implementationID,
address implementationAddress
);
event ManyToOne_ImplementationUpdated(
bytes32 implementationID,
address implementationAddress
);
event ManyToOne_ImplementationLocked(bytes32 implementationID);
event ManyToOne_ProxyDeployed(
bytes32 implementationID,
address proxyAddress
);
event OneToOne_ProxyDeployed(
address proxyAddress,
address implementationAddress
);
event OneToOne_ImplementationUpdated(
address proxyAddress,
address implementationAddress
);
event OneToOne_ImplementationLocked(address proxyAddress);
/* ========== Storage ========== */
// Addresses allowed to deploy many-to-one proxies.
mapping(address => bool) internal _approvedDeployers;
// Maps implementation holders to their implementation IDs.
mapping(bytes32 => address) internal _implementationHolders;
// Maps implementation holders & proxy addresses to bool stating if they are locked.
mapping(address => bool) internal _lockedImplementations;
// Temporary value used in the many-to-one proxy constructor.
// The many-to-one proxy contract is deployed with create2 and
// uses static initialization code for simple address derivation,
// so it calls the proxy manager in the constructor to get this
// address in order to save it as an immutable in the bytecode.
address internal _implementationHolder;
/* ========== Modifiers ========== */
modifier onlyApprovedDeployer {
address sender = _msgSender();
require(_approvedDeployers[sender] || sender == owner(), "ERR_NOT_APPROVED");
_;
}
/* ========== Constructor ========== */
constructor() public Ownable() {}
/* ========== Access Control ========== */
/**
* @dev Allows `deployer` to deploy many-to-one proxies.
*/
function approveDeployer(address deployer) external override onlyOwner {
_approvedDeployers[deployer] = true;
emit DeploymentApprovalGranted(deployer);
}
/**
* @dev Prevents `deployer` from deploying many-to-one proxies.
*/
function revokeDeployerApproval(address deployer) external override onlyOwner {
_approvedDeployers[deployer] = false;
emit DeploymentApprovalRevoked(deployer);
}
/* ========== Implementation Management ========== */
/**
* @dev Creates a many-to-one proxy relationship.
*
* Deploys an implementation holder contract which stores the
* implementation address for many proxies. The implementation
* address can be updated on the holder to change the runtime
* code used by all its proxies.
*
* @param implementationID ID for the implementation, used to identify the
* proxies that use it. Also used as the salt in the create2 call when
* deploying the implementation holder contract.
* @param implementation Address with the runtime code the proxies
* should use.
*/
function createManyToOneProxyRelationship(
bytes32 implementationID,
address implementation
)
external
override
onlyOwner
{
// Deploy the implementation holder contract with the implementation
// ID as the create2 salt.
address implementationHolder = Create2.deploy(
0,
implementationID,
type(ManyToOneImplementationHolder).creationCode
);
// Store the implementation holder address
_implementationHolders[implementationID] = implementationHolder;
// Sets the implementation address.
_setImplementation(implementationHolder, implementation);
emit ManyToOne_ImplementationCreated(
implementationID,
implementation
);
}
/**
* @dev Lock the current implementation for `implementationID` so that it can never be upgraded again.
*/
function lockImplementationManyToOne(bytes32 implementationID) external override onlyOwner {
// Read the implementation holder address from storage.
address implementationHolder = _implementationHolders[implementationID];
// Verify that the implementation exists.
require(implementationHolder != address(0), "ERR_IMPLEMENTATION_ID");
_lockedImplementations[implementationHolder] = true;
emit ManyToOne_ImplementationLocked(implementationID);
}
/**
* @dev Lock the current implementation for `proxyAddress` so that it can never be upgraded again.
*/
function lockImplementationOneToOne(address proxyAddress) external override onlyOwner {
_lockedImplementations[proxyAddress] = true;
emit OneToOne_ImplementationLocked(proxyAddress);
}
/**
* @dev Updates the implementation address for a many-to-one
* proxy relationship.
*
* @param implementationID Identifier for the implementation.
* @param implementation Address with the runtime code the proxies
* should use.
*/
function setImplementationAddressManyToOne(
bytes32 implementationID,
address implementation
)
external
override
onlyOwner
{
// Read the implementation holder address from storage.
address implementationHolder = _implementationHolders[implementationID];
// Verify that the implementation exists.
require(implementationHolder != address(0), "ERR_IMPLEMENTATION_ID");
// Verify implementation is not locked
require(!_lockedImplementations[implementationHolder], "ERR_IMPLEMENTATION_LOCKED");
// Set the implementation address
_setImplementation(implementationHolder, implementation);
emit ManyToOne_ImplementationUpdated(
implementationID,
implementation
);
}
/**
* @dev Updates the implementation address for a one-to-one proxy.
*
* Note: This could work for many-to-one as well if the caller
* provides the implementation holder address in place of the
* proxy address, as they use the same access control and update
* mechanism.
*
* @param proxyAddress Address of the deployed proxy
* @param implementation Address with the runtime code for
* the proxy to use.
*/
function setImplementationAddressOneToOne(
address proxyAddress,
address implementation
)
external
override
onlyOwner
{
// Verify proxy is not locked
require(!_lockedImplementations[proxyAddress], "ERR_IMPLEMENTATION_LOCKED");
// Set the implementation address
_setImplementation(proxyAddress, implementation);
emit OneToOne_ImplementationUpdated(proxyAddress, implementation);
}
/* ========== Proxy Deployment ========== */
/**
* @dev Deploy a proxy contract with a one-to-one relationship
* with its implementation.
*
* The proxy will have its own implementation address which can
* be updated by the proxy manager.
*
* @param suppliedSalt Salt provided by the account requesting deployment.
* @param implementation Address of the contract with the runtime
* code that the proxy should use.
*/
function deployProxyOneToOne(
bytes32 suppliedSalt,
address implementation
)
external
override
onlyOwner
returns(address proxyAddress)
{
// Derive the create2 salt from the deployment requester's address
// and the requester-supplied salt.
bytes32 salt = Salty.deriveOneToOneSalt(_msgSender(), suppliedSalt);
// Deploy the proxy
proxyAddress = Create2.deploy(
0,
salt,
type(DelegateCallProxyOneToOne).creationCode
);
// Set the implementation address on the new proxy.
_setImplementation(proxyAddress, implementation);
emit OneToOne_ProxyDeployed(proxyAddress, implementation);
}
/**
* @dev Deploy a proxy with a many-to-one relationship with its implemenation.
*
* The proxy will call the implementation holder for every transaction to
* determine the address to use in calls.
*
* @param implementationID Identifier for the proxy's implementation.
* @param suppliedSalt Salt provided by the account requesting deployment.
*/
function deployProxyManyToOne(bytes32 implementationID, bytes32 suppliedSalt)
external
override
onlyApprovedDeployer
returns(address proxyAddress)
{
// Read the implementation holder address from storage.
address implementationHolder = _implementationHolders[implementationID];
// Verify that the implementation exists.
require(implementationHolder != address(0), "ERR_IMPLEMENTATION_ID");
// Derive the create2 salt from the deployment requester's address, the
// implementation ID and the requester-supplied salt.
bytes32 salt = Salty.deriveManyToOneSalt(
_msgSender(),
implementationID,
suppliedSalt
);
// Set the implementation holder address in storage so the proxy
// constructor can query it.
_implementationHolder = implementationHolder;
// Deploy the proxy, which will query the implementation holder address
// and save it as an immutable in the contract bytecode.
proxyAddress = Create2.deploy(
0,
salt,
type(DelegateCallProxyManyToOne).creationCode
);
// Remove the address from temporary storage.
_implementationHolder = address(0);
emit ManyToOne_ProxyDeployed(
implementationID,
proxyAddress
);
}
/* ========== Queries ========== */
/**
* @dev Returns a boolean stating whether `implementationID` is locked.
*/
function isImplementationLocked(bytes32 implementationID) external override view returns (bool) {
// Read the implementation holder address from storage.
address implementationHolder = _implementationHolders[implementationID];
// Verify that the implementation exists.
require(implementationHolder != address(0), "ERR_IMPLEMENTATION_ID");
return _lockedImplementations[implementationHolder];
}
/**
* @dev Returns a boolean stating whether `proxyAddress` is locked.
*/
function isImplementationLocked(address proxyAddress) external override view returns (bool) {
return _lockedImplementations[proxyAddress];
}
/**
* @dev Returns a boolean stating whether `deployer` is allowed to deploy many-to-one
* proxies.
*/
function isApprovedDeployer(address deployer) external override view returns (bool) {
return _approvedDeployers[deployer];
}
/**
* @dev Queries the temporary storage value `_implementationHolder`.
* This is used in the constructor of the many-to-one proxy contract
* so that the create2 address is static (adding constructor arguments
* would change the codehash) and the implementation holder can be
* stored as a constant.
*/
function getImplementationHolder()
external
override
view
returns (address)
{
return _implementationHolder;
}
/**
* @dev Returns the address of the implementation holder contract
* for `implementationID`.
*/
function getImplementationHolder(
bytes32 implementationID
)
external
override
view
returns (address)
{
return _implementationHolders[implementationID];
}
/**
* @dev Computes the create2 address for a one-to-one proxy requested
* by `originator` using `suppliedSalt`.
*
* @param originator Address of the account requesting deployment.
* @param suppliedSalt Salt provided by the account requesting deployment.
*/
function computeProxyAddressOneToOne(
address originator,
bytes32 suppliedSalt
)
external
override
view
returns (address)
{
bytes32 salt = Salty.deriveOneToOneSalt(originator, suppliedSalt);
return Create2.computeAddress(salt, CodeHashes.ONE_TO_ONE_CODEHASH);
}
/**
* @dev Computes the create2 address for a many-to-one proxy for the
* implementation `implementationID` requested by `originator` using
* `suppliedSalt`.
*
* @param originator Address of the account requesting deployment.
* @param implementationID The identifier for the contract implementation.
* @param suppliedSalt Salt provided by the account requesting deployment.
*/
function computeProxyAddressManyToOne(
address originator,
bytes32 implementationID,
bytes32 suppliedSalt
)
external
override
view
returns (address)
{
bytes32 salt = Salty.deriveManyToOneSalt(
originator,
implementationID,
suppliedSalt
);
return Create2.computeAddress(salt, CodeHashes.MANY_TO_ONE_CODEHASH);
}
/**
* @dev Computes the create2 address of the implementation holder
* for `implementationID`.
*
* @param implementationID The identifier for the contract implementation.
*/
function computeHolderAddressManyToOne(bytes32 implementationID)
public
override
view
returns (address)
{
return Create2.computeAddress(
implementationID,
CodeHashes.IMPLEMENTATION_HOLDER_CODEHASH
);
}
/* ========== Internal Functions ========== */
/**
* @dev Sets the implementation address for a one-to-one proxy or
* many-to-one implementation holder. Both use the same access
* control and update mechanism, which is the receipt of a call
* from the proxy manager with the abi-encoded implementation address
* as the only calldata.
*
* Note: Verifies that the implementation address is a contract.
*
* @param proxyOrHolder Address of the one-to-one proxy or
* many-to-one implementation holder contract.
* @param implementation Address of the contract with the runtime
* code that the proxy or proxies should use.
*/
function _setImplementation(
address proxyOrHolder,
address implementation
) internal {
// Verify that the implementation address is a contract.
require(Address.isContract(implementation), "ERR_NOT_CONTRACT");
// Set the implementation address on the contract.
// solium-disable-next-line security/no-low-level-calls
(bool success,) = proxyOrHolder.call(abi.encode(implementation));
require(success, "ERR_SET_ADDRESS_REVERT");
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
/**
* @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer.
* `CREATE2` can be used to compute in advance the address where a smart
* contract will be deployed, which allows for interesting new mechanisms known
* as 'counterfactual interactions'.
*
* See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more
* information.
*/
library Create2 {
/**
* @dev Deploys a contract using `CREATE2`. The address where the contract
* will be deployed can be known in advance via {computeAddress}.
*
* The bytecode for a contract can be obtained from Solidity with
* `type(contractName).creationCode`.
*
* Requirements:
*
* - `bytecode` must not be empty.
* - `salt` must have not been used for `bytecode` already.
* - the factory must have a balance of at least `amount`.
* - if `amount` is non-zero, `bytecode` must have a `payable` constructor.
*/
function deploy(uint256 amount, bytes32 salt, bytes memory bytecode) internal returns (address) {
address addr;
require(address(this).balance >= amount, "Create2: insufficient balance");
require(bytecode.length != 0, "Create2: bytecode length is zero");
// solhint-disable-next-line no-inline-assembly
assembly {
addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt)
}
require(addr != address(0), "Create2: Failed on deploy");
return addr;
}
/**
* @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the
* `bytecodeHash` or `salt` will result in a new destination address.
*/
function computeAddress(bytes32 salt, bytes32 bytecodeHash) internal view returns (address) {
return computeAddress(salt, bytecodeHash, address(this));
}
/**
* @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at
* `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}.
*/
function computeAddress(bytes32 salt, bytes32 bytecodeHash, address deployer) internal pure returns (address) {
bytes32 _data = keccak256(
abi.encodePacked(bytes1(0xff), deployer, salt, bytecodeHash)
);
return address(uint256(_data));
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.2;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @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
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies in extcodesize, which returns 0 for contracts in
// construction, since the code is only stored at the end of the
// constructor execution.
uint256 size;
// solhint-disable-next-line no-inline-assembly
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].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
// solhint-disable-next-line avoid-low-level-calls, avoid-call-value
(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._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
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._
*/
function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
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._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
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._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
return _functionCallWithValue(target, data, value, errorMessage);
}
function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) {
require(isContract(target), "Address: call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = target.call{ value: weiValue }(data);
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
// solhint-disable-next-line no-inline-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
import "../GSN/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.
*/
contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor () internal {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
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.
*/
function renounceOwnership() public virtual onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.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 GSN 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.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
return msg.data;
}
}
// SPDX-License-Identifier: GPL-3.0
pragma solidity =0.6.12;
/**
* @dev The ManyToOneImplementationHolder stores an upgradeable implementation address
* in storage, which many-to-one proxies query at execution time to determine which
* contract to delegate to.
*
* The manager can upgrade the implementation address by calling the holder with the
* abi-encoded address as calldata. If any other account calls the implementation holder,
* it will return the implementation address.
*
* This pattern was inspired by the DharmaUpgradeBeacon from 0age
* https://github.com/dharma-eng/dharma-smart-wallet/blob/master/contracts/upgradeability/smart-wallet/DharmaUpgradeBeacon.sol
*/
contract ManyToOneImplementationHolder {
/* --- Storage --- */
address internal immutable _manager;
address internal _implementation;
/* --- Constructor --- */
constructor() public {
_manager = msg.sender;
}
/**
* @dev Fallback function for the contract.
*
* Used by proxies to read the implementation address and used
* by the proxy manager to set the implementation address.
*
* If called by the owner, reads the implementation address from
* calldata (must be abi-encoded) and stores it to the first slot.
*
* Otherwise, returns the stored implementation address.
*/
fallback() external payable {
if (msg.sender != _manager) {
assembly {
mstore(0, sload(0))
return(0, 32)
}
}
assembly { sstore(0, calldataload(0)) }
}
}// SPDX-License-Identifier: GPL-3.0
pragma solidity =0.6.12;
import { Proxy } from "@openzeppelin/contracts/proxy/Proxy.sol";
/**
* @dev Proxy contract which uses an implementation address shared with many
* other proxies.
*
* An implementation holder contract stores the upgradeable implementation address.
* When the proxy is called, it queries the implementation address from the holder
* contract and delegatecalls the returned address, forwarding the received calldata
* and ether.
*
* Note: This contract does not verify that the implementation
* address is a valid delegation target. The manager must perform
* this safety check before updating the implementation on the holder.
*/
contract DelegateCallProxyManyToOne is Proxy {
/* ========== Constants ========== */
// Address that stores the implementation address.
address internal immutable _implementationHolder;
/* ========== Constructor ========== */
constructor() public {
// Calls the sender rather than receiving the address in the constructor
// arguments so that the address is computable using create2.
_implementationHolder = ProxyDeployer(msg.sender).getImplementationHolder();
}
/* ========== Internal Overrides ========== */
/**
* @dev Queries the implementation address from the implementation holder.
*/
function _implementation() internal override view returns (address) {
// Queries the implementation address from the implementation holder.
(bool success, bytes memory data) = _implementationHolder.staticcall("");
require(success, string(data));
address implementation = abi.decode((data), (address));
require(implementation != address(0), "ERR_NULL_IMPLEMENTATION");
return implementation;
}
}
interface ProxyDeployer {
function getImplementationHolder() external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
/**
* @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
* instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
* be specified by overriding the virtual {_implementation} function.
*
* Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
* different contract through the {_delegate} function.
*
* The success and return data of the delegated call will be returned back to the caller of the proxy.
*/
abstract contract Proxy {
/**
* @dev Delegates the current call to `implementation`.
*
* This function does not return to its internall call site, it will return directly to the external caller.
*/
function _delegate(address implementation) internal {
// solhint-disable-next-line no-inline-assembly
assembly {
// Copy msg.data. We take full control of memory in this inline assembly
// block because it will not return to Solidity code. We overwrite the
// Solidity scratch pad at memory position 0.
calldatacopy(0, 0, calldatasize())
// Call the implementation.
// out and outsize are 0 because we don't know the size yet.
let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
// Copy the returned data.
returndatacopy(0, 0, returndatasize())
switch result
// delegatecall returns 0 on error.
case 0 { revert(0, returndatasize()) }
default { return(0, returndatasize()) }
}
}
/**
* @dev This is a virtual function that should be overriden so it returns the address to which the fallback function
* and {_fallback} should delegate.
*/
function _implementation() internal virtual view returns (address);
/**
* @dev Delegates the current call to the address returned by `_implementation()`.
*
* This function does not return to its internall call site, it will return directly to the external caller.
*/
function _fallback() internal {
_beforeFallback();
_delegate(_implementation());
}
/**
* @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
* function in the contract matches the call data.
*/
fallback () payable external {
_fallback();
}
/**
* @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
* is empty.
*/
receive () payable external {
_fallback();
}
/**
* @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
* call, or as part of the Solidity `fallback` or `receive` functions.
*
* If overriden should call `super._beforeFallback()`.
*/
function _beforeFallback() internal virtual {
}
}
// SPDX-License-Identifier: GPL-3.0
pragma solidity =0.6.12;
import { Proxy } from "@openzeppelin/contracts/proxy/Proxy.sol";
/**
* @dev Upgradeable delegatecall proxy for a single contract.
*
* This proxy stores an implementation address which can be upgraded by the proxy manager.
*
* To upgrade the implementation, the manager calls the proxy with the abi encoded implementation address.
*
* If any other account calls the proxy, it will delegatecall the implementation address with the received
* calldata and ether. If the call succeeds, it will return with the received returndata.
* If it reverts, it will revert with the received revert data.
*
* Note: The storage slot for the implementation address is:
* `bytes32(uint256(keccak256("IMPLEMENTATION_ADDRESS")) + 1)`
* This slot must not be used by the implementation contract.
*
* Note: This contract does not verify that the implementation address is a valid delegation target.
* The manager must perform this safety check.
*/
contract DelegateCallProxyOneToOne is Proxy {
/* ========== Constants ========== */
address internal immutable _manager;
/* ========== Constructor ========== */
constructor() public {
_manager = msg.sender ;
}
/* ========== Internal Overrides ========== */
/**
* @dev Reads the implementation address from storage.
*/
function _implementation() internal override view returns (address) {
address implementation;
assembly {
implementation := sload(
// bytes32(uint256(keccak256("IMPLEMENTATION_ADDRESS")) + 1)
0x913bd12b32b36f36cedaeb6e043912bceb97022755958701789d3108d33a045a
)
}
return implementation;
}
/**
* @dev Hook that is called before falling back to the implementation.
*
* Checks if the call is from the owner.
* If it is, reads the abi-encoded implementation address from calldata and stores
* it at the slot `bytes32(uint256(keccak256("IMPLEMENTATION_ADDRESS")) + 1)`,
* then returns with no data.
* If it is not, continues execution with the fallback function.
*/
function _beforeFallback() internal override {
if (msg.sender != _manager) {
super._beforeFallback();
} else {
assembly {
sstore(
// bytes32(uint256(keccak256("IMPLEMENTATION_ADDRESS")) + 1)
0x913bd12b32b36f36cedaeb6e043912bceb97022755958701789d3108d33a045a,
calldataload(0)
)
return(0, 0)
}
}
}
}
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.6.0;
/* --- External Libraries --- */
import { Create2 } from "@openzeppelin/contracts/utils/Create2.sol";
/* --- Proxy Contracts --- */
import { CodeHashes } from "./CodeHashes.sol";
/**
* @dev Library for computing create2 salts and addresses for proxies
* deployed by `DelegateCallProxyManager`.
*
* Because the proxy factory is meant to be used by multiple contracts,
* we use a salt derivation pattern that includes the address of the
* contract that requested the proxy deployment, a salt provided by that
* contract and the implementation ID used (for many-to-one proxies only).
*/
library SaltyLib {
/* --- Salt Derivation --- */
/**
* @dev Derives the create2 salt for a many-to-one proxy.
*
* Many different contracts in the Indexed framework may use the
* same implementation contract, and they all use the same init
* code, so we derive the actual create2 salt from a combination
* of the implementation ID, the address of the account requesting
* deployment and the user-supplied salt.
*
* @param originator Address of the account requesting deployment.
* @param implementationID The identifier for the contract implementation.
* @param suppliedSalt Salt provided by the account requesting deployment.
*/
function deriveManyToOneSalt(
address originator,
bytes32 implementationID,
bytes32 suppliedSalt
)
internal
pure
returns (bytes32)
{
return keccak256(
abi.encodePacked(
originator,
implementationID,
suppliedSalt
)
);
}
/**
* @dev Derives the create2 salt for a one-to-one proxy.
*
* @param originator Address of the account requesting deployment.
* @param suppliedSalt Salt provided by the account requesting deployment.
*/
function deriveOneToOneSalt(
address originator,
bytes32 suppliedSalt
)
internal
pure
returns (bytes32)
{
return keccak256(abi.encodePacked(originator, suppliedSalt));
}
/* --- Address Derivation --- */
/**
* @dev Computes the create2 address for a one-to-one proxy deployed
* by `deployer` (the factory) when requested by `originator` using
* `suppliedSalt`.
*
* @param deployer Address of the proxy factory.
* @param originator Address of the account requesting deployment.
* @param suppliedSalt Salt provided by the account requesting deployment.
*/
function computeProxyAddressOneToOne(
address deployer,
address originator,
bytes32 suppliedSalt
)
internal
pure
returns (address)
{
bytes32 salt = deriveOneToOneSalt(originator, suppliedSalt);
return Create2.computeAddress(salt, CodeHashes.ONE_TO_ONE_CODEHASH, deployer);
}
/**
* @dev Computes the create2 address for a many-to-one proxy for the
* implementation `implementationID` deployed by `deployer` (the factory)
* when requested by `originator` using `suppliedSalt`.
*
* @param deployer Address of the proxy factory.
* @param originator Address of the account requesting deployment.
* @param implementationID The identifier for the contract implementation.
* @param suppliedSalt Salt provided by the account requesting deployment.
*/
function computeProxyAddressManyToOne(
address deployer,
address originator,
bytes32 implementationID,
bytes32 suppliedSalt
)
internal
pure
returns (address)
{
bytes32 salt = deriveManyToOneSalt(
originator,
implementationID,
suppliedSalt
);
return Create2.computeAddress(salt, CodeHashes.MANY_TO_ONE_CODEHASH, deployer);
}
/**
* @dev Computes the create2 address of the implementation holder
* for `implementationID`.
*
* @param deployer Address of the proxy factory.
* @param implementationID The identifier for the contract implementation.
*/
function computeHolderAddressManyToOne(
address deployer,
bytes32 implementationID
)
internal
pure
returns (address)
{
return Create2.computeAddress(
implementationID,
CodeHashes.IMPLEMENTATION_HOLDER_CODEHASH,
deployer
);
}
}// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.6.0;
/**
* @dev Contract that manages deployment and upgrades of delegatecall proxies.
*
* An implementation identifier can be created on the proxy manager which is
* used to specify the logic address for a particular contract type, and to
* upgrade the implementation as needed.
*
* A one-to-one proxy is a single proxy contract with an upgradeable implementation
* address.
*
* A many-to-one proxy is a single upgradeable implementation address that may be
* used by many proxy contracts.
*/
interface IDelegateCallProxyManager {
/* ========== Events ========== */
event DeploymentApprovalGranted(address deployer);
event DeploymentApprovalRevoked(address deployer);
event ManyToOne_ImplementationCreated(
bytes32 implementationID,
address implementationAddress
);
event ManyToOne_ImplementationUpdated(
bytes32 implementationID,
address implementationAddress
);
event ManyToOne_ProxyDeployed(
bytes32 implementationID,
address proxyAddress
);
event OneToOne_ProxyDeployed(
address proxyAddress,
address implementationAddress
);
event OneToOne_ImplementationUpdated(
address proxyAddress,
address implementationAddress
);
/* ========== Controls ========== */
/**
* @dev Allows `deployer` to deploy many-to-one proxies.
*/
function approveDeployer(address deployer) external;
/**
* @dev Prevents `deployer` from deploying many-to-one proxies.
*/
function revokeDeployerApproval(address deployer) external;
/* ========== Implementation Management ========== */
/**
* @dev Creates a many-to-one proxy relationship.
*
* Deploys an implementation holder contract which stores the
* implementation address for many proxies. The implementation
* address can be updated on the holder to change the runtime
* code used by all its proxies.
*
* @param implementationID ID for the implementation, used to identify the
* proxies that use it. Also used as the salt in the create2 call when
* deploying the implementation holder contract.
* @param implementation Address with the runtime code the proxies
* should use.
*/
function createManyToOneProxyRelationship(
bytes32 implementationID,
address implementation
) external;
/**
* @dev Lock the current implementation for `proxyAddress` so that it can never be upgraded again.
*/
function lockImplementationManyToOne(bytes32 implementationID) external;
/**
* @dev Lock the current implementation for `proxyAddress` so that it can never be upgraded again.
*/
function lockImplementationOneToOne(address proxyAddress) external;
/**
* @dev Updates the implementation address for a many-to-one
* proxy relationship.
*
* @param implementationID Identifier for the implementation.
* @param implementation Address with the runtime code the proxies
* should use.
*/
function setImplementationAddressManyToOne(
bytes32 implementationID,
address implementation
) external;
/**
* @dev Updates the implementation address for a one-to-one proxy.
*
* Note: This could work for many-to-one as well if the caller
* provides the implementation holder address in place of the
* proxy address, as they use the same access control and update
* mechanism.
*
* @param proxyAddress Address of the deployed proxy
* @param implementation Address with the runtime code for
* the proxy to use.
*/
function setImplementationAddressOneToOne(
address proxyAddress,
address implementation
) external;
/* ========== Proxy Deployment ========== */
/**
* @dev Deploy a proxy contract with a one-to-one relationship
* with its implementation.
*
* The proxy will have its own implementation address which can
* be updated by the proxy manager.
*
* @param suppliedSalt Salt provided by the account requesting deployment.
* @param implementation Address of the contract with the runtime
* code that the proxy should use.
*/
function deployProxyOneToOne(
bytes32 suppliedSalt,
address implementation
) external returns(address proxyAddress);
/**
* @dev Deploy a proxy with a many-to-one relationship with its implemenation.
*
* The proxy will call the implementation holder for every transaction to
* determine the address to use in calls.
*
* @param implementationID Identifier for the proxy's implementation.
* @param suppliedSalt Salt provided by the account requesting deployment.
*/
function deployProxyManyToOne(
bytes32 implementationID,
bytes32 suppliedSalt
) external returns(address proxyAddress);
/* ========== Queries ========== */
/**
* @dev Returns a boolean stating whether `implementationID` is locked.
*/
function isImplementationLocked(bytes32 implementationID) external view returns (bool);
/**
* @dev Returns a boolean stating whether `proxyAddress` is locked.
*/
function isImplementationLocked(address proxyAddress) external view returns (bool);
/**
* @dev Returns a boolean stating whether `deployer` is allowed to deploy many-to-one
* proxies.
*/
function isApprovedDeployer(address deployer) external view returns (bool);
/**
* @dev Queries the temporary storage value `_implementationHolder`.
* This is used in the constructor of the many-to-one proxy contract
* so that the create2 address is static (adding constructor arguments
* would change the codehash) and the implementation holder can be
* stored as a constant.
*/
function getImplementationHolder() external view returns (address);
/**
* @dev Returns the address of the implementation holder contract
* for `implementationID`.
*/
function getImplementationHolder(bytes32 implementationID) external view returns (address);
/**
* @dev Computes the create2 address for a one-to-one proxy requested
* by `originator` using `suppliedSalt`.
*
* @param originator Address of the account requesting deployment.
* @param suppliedSalt Salt provided by the account requesting deployment.
*/
function computeProxyAddressOneToOne(
address originator,
bytes32 suppliedSalt
) external view returns (address);
/**
* @dev Computes the create2 address for a many-to-one proxy for the
* implementation `implementationID` requested by `originator` using
* `suppliedSalt`.
*
* @param originator Address of the account requesting deployment.
* @param implementationID The identifier for the contract implementation.
* @param suppliedSalt Salt provided by the account requesting deployment.
*/
function computeProxyAddressManyToOne(
address originator,
bytes32 implementationID,
bytes32 suppliedSalt
) external view returns (address);
/**
* @dev Computes the create2 address of the implementation holder
* for `implementationID`.
*
* @param implementationID The identifier for the contract implementation.
*/
function computeHolderAddressManyToOne(bytes32 implementationID) external view returns (address);
}File 2 of 2: StakingRewards
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
abstract contract RewardsDistributionRecipient {
address public immutable rewardsDistribution;
function notifyRewardAmount(uint256 reward) external virtual;
constructor(address rewardsDistribution_) public {
rewardsDistribution = rewardsDistribution_;
}
modifier onlyRewardsDistribution() {
require(
msg.sender == rewardsDistribution,
"Caller is not RewardsDistribution contract"
);
_;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
/* ========== External Libraries ========== */
import "@openzeppelin/contracts/math/Math.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
/* ========== External Inheritance ========== */
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
/* ========== Internal Inheritance ========== */
import "./RewardsDistributionRecipient.sol";
import "../interfaces/IStakingRewards.sol";
contract StakingRewards is
IStakingRewards,
RewardsDistributionRecipient,
ReentrancyGuard
{
using SafeMath for uint256;
using SafeERC20 for IERC20;
/* ========== Constants ========== */
uint256 public override rewardsDuration = 60 days;
/* ========== Immutables ========== */
IERC20 public override immutable rewardsToken;
/* ========== Events ========== */
event RewardAdded(uint256 reward);
event Staked(address indexed user, uint256 amount);
event Withdrawn(address indexed user, uint256 amount);
event RewardPaid(address indexed user, uint256 reward);
event RewardsDurationUpdated(uint256 newDuration);
event Recovered(address token, uint256 amount);
/* ========== Modifiers ========== */
modifier updateReward(address account) {
rewardPerTokenStored = rewardPerToken();
lastUpdateTime = lastTimeRewardApplicable();
if (account != address(0)) {
rewards[account] = earned(account);
userRewardPerTokenPaid[account] = rewardPerTokenStored;
}
_;
}
/* ========== State Variables ========== */
IERC20 public override stakingToken;
uint256 public override periodFinish = 0;
uint256 public override rewardRate = 0;
uint256 public override lastUpdateTime;
uint256 public override rewardPerTokenStored;
mapping(address => uint256) public userRewardPerTokenPaid;
mapping(address => uint256) public rewards;
uint256 private _totalSupply;
mapping(address => uint256) private _balances;
/* ========== Constructor & Initializer ========== */
constructor(
address rewardsDistribution_,
address rewardsToken_
) public RewardsDistributionRecipient(rewardsDistribution_) {
rewardsToken = IERC20(rewardsToken_);
}
function initialize(address stakingToken_, uint256 rewardsDuration_) external override {
require(address(stakingToken) == address(0), "Already initialized");
require(address(stakingToken_) != address(0), "Can not set null staking token");
require(rewardsDuration_ > 0, "Can not set null rewards duration");
stakingToken = IERC20(stakingToken_);
rewardsDuration = rewardsDuration_;
}
/* ========== Mutative Functions ========== */
function stake(uint256 amount)
external
override
nonReentrant
updateReward(msg.sender)
{
require(amount > 0, "Cannot stake 0");
_totalSupply = _totalSupply.add(amount);
_balances[msg.sender] = _balances[msg.sender].add(amount);
stakingToken.safeTransferFrom(msg.sender, address(this), amount);
emit Staked(msg.sender, amount);
}
function withdraw(uint256 amount)
public
override
nonReentrant
updateReward(msg.sender)
{
require(amount > 0, "Cannot withdraw 0");
_totalSupply = _totalSupply.sub(amount);
_balances[msg.sender] = _balances[msg.sender].sub(amount);
stakingToken.safeTransfer(msg.sender, amount);
emit Withdrawn(msg.sender, amount);
}
function getReward()
public
override
nonReentrant
updateReward(msg.sender)
{
uint256 reward = rewards[msg.sender];
if (reward > 0) {
rewards[msg.sender] = 0;
rewardsToken.safeTransfer(msg.sender, reward);
emit RewardPaid(msg.sender, reward);
}
}
function exit() external override {
withdraw(_balances[msg.sender]);
getReward();
}
/* ========== Restricted Functions ========== */
function notifyRewardAmount(uint256 reward)
external
override(IStakingRewards, RewardsDistributionRecipient)
onlyRewardsDistribution
updateReward(address(0))
{
if (block.timestamp >= periodFinish) {
rewardRate = reward.div(rewardsDuration);
} else {
uint256 remaining = periodFinish.sub(block.timestamp);
uint256 leftover = remaining.mul(rewardRate);
rewardRate = reward.add(leftover).div(rewardsDuration);
}
// Ensure the provided reward amount is not more than the balance in the contract.
// This keeps the reward rate in the right range, preventing overflows due to
// very high values of rewardRate in the earned and rewardsPerToken functions;
// Reward + leftover must be less than 2^256 / 10^18 to avoid overflow.
uint256 balance = rewardsToken.balanceOf(address(this));
require(
rewardRate <= balance.div(rewardsDuration),
"Provided reward too high"
);
lastUpdateTime = block.timestamp;
periodFinish = block.timestamp.add(rewardsDuration);
emit RewardAdded(reward);
}
// Added to support recovering LP Rewards from other systems such as BAL to be distributed to holders
function recoverERC20(address tokenAddress, address recipient) external override onlyRewardsDistribution {
// Cannot recover the staking token or the rewards token
require(
tokenAddress != address(stakingToken) && tokenAddress != address(rewardsToken),
"Cannot withdraw the staking or rewards tokens"
);
uint256 balance = IERC20(tokenAddress).balanceOf(address(this));
IERC20(tokenAddress).safeTransfer(recipient, balance);
emit Recovered(tokenAddress, balance);
}
function setRewardsDuration(uint256 _rewardsDuration) external override onlyRewardsDistribution {
require(
block.timestamp > periodFinish,
"Previous rewards period must be complete before changing the duration for the new period"
);
require(_rewardsDuration > 0, "Can not set null rewards duration.");
rewardsDuration = _rewardsDuration;
emit RewardsDurationUpdated(rewardsDuration);
}
/* ========== Views ========== */
function totalSupply() external override view returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) external override view returns (uint256) {
return _balances[account];
}
function lastTimeRewardApplicable() public override view returns (uint256) {
return Math.min(block.timestamp, periodFinish);
}
function rewardPerToken() public override view returns (uint256) {
if (_totalSupply == 0) {
return rewardPerTokenStored;
}
return
rewardPerTokenStored.add(
lastTimeRewardApplicable()
.sub(lastUpdateTime)
.mul(rewardRate)
.mul(1e18)
.div(_totalSupply)
);
}
function earned(address account) public override view returns (uint256) {
return _balances[account]
.mul(rewardPerToken().sub(userRewardPerTokenPaid[account]))
.div(1e18)
.add(rewards[account]);
}
function getRewardForDuration() external override view returns (uint256) {
return rewardRate.mul(rewardsDuration);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a >= b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow, so we distribute
return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts with custom message when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
import "./IERC20.sol";
import "../../math/SafeMath.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.
*/
library SafeERC20 {
using SafeMath for uint256;
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, 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.
*/
function safeApprove(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'
// solhint-disable-next-line max-line-length
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));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).add(value);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
_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, bytes memory 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.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) { // Return data is optional
// solhint-disable-next-line max-line-length
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (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.
*/
function transfer(address recipient, uint256 amount) external returns (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.
*/
function allowance(address owner, address spender) external view returns (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.
*/
function approve(address spender, uint256 amount) external returns (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.
*/
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed 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.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.2;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @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
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies in extcodesize, which returns 0 for contracts in
// construction, since the code is only stored at the end of the
// constructor execution.
uint256 size;
// solhint-disable-next-line no-inline-assembly
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].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
// solhint-disable-next-line avoid-low-level-calls, avoid-call-value
(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._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
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._
*/
function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
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._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
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._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
return _functionCallWithValue(target, data, value, errorMessage);
}
function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) {
require(isContract(target), "Address: call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = target.call{ value: weiValue }(data);
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
// solhint-disable-next-line no-inline-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor () internal {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and make it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
// On the first call to nonReentrant, _notEntered will be true
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
_;
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
}
pragma solidity ^0.6.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IStakingRewards {
// Time Views
function lastTimeRewardApplicable() external view returns (uint256);
function lastUpdateTime() external view returns (uint256);
function periodFinish() external view returns (uint256);
function rewardsDuration() external view returns (uint256);
// Reward Views
function rewardPerToken() external view returns (uint256);
function rewardPerTokenStored() external view returns (uint256);
function getRewardForDuration() external view returns (uint256);
function rewardRate() external view returns (uint256);
function earned(address account) external view returns (uint256);
// Token Views
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
// Configuration Views
function stakingToken() external view returns (IERC20);
function rewardsToken() external view returns (IERC20);
// Mutative
function initialize(address stakingToken, uint256 rewardsDuration) external;
function stake(uint256 amount) external;
function withdraw(uint256 amount) external;
function getReward() external;
function exit() external;
// Restricted
function notifyRewardAmount(uint256 reward) external;
function recoverERC20(address tokenAddress, address recipient) external;
function setRewardsDuration(uint256 rewardsDuration) external;
}