Description:
Multi-signature wallet contract requiring multiple confirmations for transaction execution.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"/contracts/BrightRiskToken.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.7.4;
pragma experimental ABIEncoderV2;
import "./tokens/erc20permit-upgradeable/ERC20PermitUpgradeable.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import "@openzeppelin/contracts/utils/EnumerableSet.sol";
import "@openzeppelin/contracts/math/Math.sol";
import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol";
import "./interfaces/IPositionController.sol";
import "./interfaces/IBrightRiskToken.sol";
import "./lib/PreciseUnitMath.sol";
import "./interfaces/helpers/IPriceFeed.sol";
contract BrightRiskToken is
ERC20PermitUpgradeable,
AccessControlUpgradeable,
IBrightRiskToken,
PausableUpgradeable
{
using Math for uint256;
using SafeERC20 for ERC20;
using EnumerableSet for EnumerableSet.AddressSet;
using SafeMathUpgradeable for uint256;
using PreciseUnitMath for int256;
bytes32 public constant TOKEN_ADMIN_ROLE = keccak256("TOKEN_ADMIN_ROLE");
bytes32 public constant TOKEN_OPERATOR_ROLE = keccak256("TOKEN_OPERATOR_ROLE");
uint256 constant SECONDS_IN_THE_YEAR = 365 * 24 * 60 * 60;
uint256 constant PRECISION = 10**25;
uint256 constant PERCENTAGE_100 = 100 * PRECISION;
uint256 constant FEE_PRECISION = 10**5;
uint256 constant FEE_PERCENTAGE_100 = 100 * FEE_PRECISION;
struct FeeState {
address feeRecipient; // Address to accrue fees to
uint256 streamingFeePercentage; // Percent of BrightRiskToken accruing to manager annually (1% = 1e16, 100% = 1e18)
uint256 lastStreamingFeeTimestamp; // Timestamp last streaming fee was accrued
}
IPriceFeed public priceFeed;
FeeState public feeState;
ERC20 public base;
// @dev DEPRECATED
mapping(address => DepositorInfo) public externalPoolByDepositor;
// @dev DEPRECATED
EnumerableSet.AddressSet internal _outstandingDepositors;
uint256 public externalPool;
// @dev DEPRECATED
uint256 public internalPool;
uint256 public minimumBaseDeposit;
EnumerableSet.AddressSet internal _positionControllers;
uint256 public depositFee;
event FeeActualized(address indexed _manager, uint256 _managerFee);
event Stake(uint256 stake, address stakeAt, uint256 externalPool);
event IndexDeposit(
address indexed depositor,
uint256 amount,
uint256 mintAmount,
uint256 externalPool
);
event IndexInternalDeposit(address indexed depositor, uint256 amount, uint256 externalPool);
event CallUnstake(address indexed controller, uint256 amount);
event Unstake(address indexed controller, uint256 amount);
event IndexBurn(address indexed sender, uint256 indexAmount, uint256 baseAmount);
event UpdateController(address indexed controller, string operation);
event AdjustStreamingFee(FeeState feeSettings);
event UpdateMinimumDeposit(uint256 newMin);
event UpdateDepositFee(uint256 fee);
event UpdatePriceFeedAddress(address positionCotroller, address priceFeed);
event UpdateExchangeAdapters(address controllerAddress);
modifier onlyAdmin() {
require(hasRole(TOKEN_ADMIN_ROLE, msg.sender), "BrightRiskToken: caller is not the admin");
_;
}
modifier onlyOperator() {
require(
hasRole(TOKEN_OPERATOR_ROLE, msg.sender),
"BrightRiskToken: caller is not the operator"
);
_;
}
function __BrightRiskToken_init(
FeeState memory _feeSettings,
address _baseAsset,
address _priceFeed
) external initializer {
__ERC20Permit_init("BRI");
__ERC20_init("Bright Risk Index", "BRI");
__AccessControl_init();
_setupRole(TOKEN_ADMIN_ROLE, msg.sender);
_setupRole(TOKEN_OPERATOR_ROLE, msg.sender);
_setRoleAdmin(TOKEN_ADMIN_ROLE, TOKEN_ADMIN_ROLE);
_setRoleAdmin(TOKEN_OPERATOR_ROLE, TOKEN_ADMIN_ROLE);
require(_feeSettings.feeRecipient != address(0), "BrightRiskToken: BRI3");
_feeSettings.lastStreamingFeeTimestamp = block.timestamp;
feeState = _feeSettings;
base = ERC20(_baseAsset);
minimumBaseDeposit = 1 ether;
depositFee = 1 * 10**5;
priceFeed = IPriceFeed(_priceFeed);
}
// @notice Deposits capital into 'external' pool, to be 'staked' on behalf of the user later on
// access: ANY
function deposit(uint256 _amount) external override whenNotPaused {
require(_amount >= minimumBaseDeposit, "BrightRiskToken: BRI4");
base.safeTransferFrom(_msgSender(), address(this), _amount);
uint256 _mintAmount = convertInvestmentToIndex(_applyDepositFee(_amount));
_mint(_msgSender(), _mintAmount);
externalPool = externalPool.add(_amount);
emit IndexDeposit(_msgSender(), _amount, _mintAmount, externalPool);
}
// @notice Deposits funds without minting, usually the rewards from position controllers
// Also can be used to boost the value, from external sources
// access: ANY
function depositInternal(uint256 _amount) external override {
require(_amount > 0, "BrightRiskToken: BR11");
base.safeTransferFrom(_msgSender(), address(this), _amount);
externalPool = externalPool.add(_amount);
emit IndexInternalDeposit(_msgSender(), _amount, externalPool);
}
// @notice Stake 'external' pool in the dedicated position,
// access: ADMIN
function stakeAt(
address _controllerAddress,
uint256 _staking,
bytes calldata _calldata,
bytes calldata _exchangeData
) external onlyAdmin {
require(_positionControllers.contains(_controllerAddress), "BrightRiskToken: BRI2");
_stakeExternalPool(_controllerAddress, _staking, _calldata, _exchangeData);
_accrueManagerFee();
emit Stake(_staking, _controllerAddress, externalPool);
}
function _stakeExternalPool(
address _controllerAddress,
uint256 _amount,
bytes calldata _calldata,
bytes calldata _exchangeData
) internal {
require(_amount > 0, "BrightRiskToken: BRI5");
require(_amount <= externalPool, "BrightRiskToken: BRI6");
base.safeApprove(_controllerAddress, _amount);
IPositionController(_controllerAddress).stake(_amount, _exchangeData, _calldata);
externalPool = externalPool.sub(_amount);
}
// @notice Call unstaking on a specific position. Usually subject to a waiting period
// access: ADMIN
function callUnstakeAt(address _controllerAddress) external onlyAdmin {
uint256 _calledAmount = IPositionController(_controllerAddress).callUnstake();
emit CallUnstake(_controllerAddress, _calledAmount);
}
// @notice Unstake capital from a specific position.
// access: ADMIN
function unstakeAt(
address _controllerAddress,
bytes calldata _exchangeData,
bytes calldata _signature
) external onlyAdmin {
require(_positionControllers.contains(_controllerAddress), "BrightRiskToken: BRI13");
uint256 _unstakedAmount = IPositionController(_controllerAddress).unstake(
_exchangeData,
_signature
);
emit Unstake(_controllerAddress, _unstakedAmount);
}
// @notice Liquidates the index token in return for 'base', taken from the pool
// access: ANY
function burn(uint256 _indexTokenAmount) external whenNotPaused {
require(_indexTokenAmount > 0, "BrightRiskToken: BRI15");
require(balanceOf(_msgSender()) >= _indexTokenAmount, "BrightRiskToken: BRI16");
uint256 _investments = convertIndexToInvestment(_indexTokenAmount);
// apply the fee
_investments = _applyDepositFee(_investments);
require(externalPool >= _investments, "BrightRiskToken: BRI17");
_burn(_msgSender(), _indexTokenAmount);
externalPool = externalPool.sub(_investments);
base.transfer(_msgSender(), _investments);
emit IndexBurn(_msgSender(), _indexTokenAmount, _investments);
}
function unstakeAll() external onlyAdmin {
base.transfer(_msgSender(), externalPool);
}
// @notice Adds new staking position.
// access: OPERATOR
function addController(address _controllerAddress) external onlyOperator {
require(_controllerAddress != address(0), "BrightRiskToken: BRI1");
_positionControllers.add(_controllerAddress);
emit UpdateController(_controllerAddress, "add");
}
// @notice Removes the staking position.
// access: OPERATOR
function removeController(address _controllerAddress) external onlyOperator {
require(_controllerAddress != address(0), "BrightRiskToken: BRI19");
require(
IPositionController(_controllerAddress).netWorth() < 1 ether,
"BrightRiskToken: BRI20"
);
_positionControllers.remove(_controllerAddress);
emit UpdateController(_controllerAddress, "remove");
}
// @notice Sets the threshold for the minimum deposited capital
// access: OPERATOR
function setMinimumDeposit(uint256 _newMin) external onlyOperator {
minimumBaseDeposit = _newMin;
emit UpdateMinimumDeposit(_newMin);
}
// @notice Sets the fee that's applied on new deposits and burn to compensate the asset spread losses
// access: OPERATOR
function setDepositFee(uint256 _fee) external onlyOperator {
require(_fee < 5 * FEE_PRECISION, "BrightRiskToken: BRI25");
depositFee = _fee;
emit UpdateDepositFee(_fee);
}
// @notice Sets the streaming fee on the index token
// access: OPERATOR
function adjustStreamingFee(FeeState memory _feeSettings) external onlyOperator {
feeState = _feeSettings;
emit AdjustStreamingFee(_feeSettings);
}
// @notice Puts the token on pause, external operations are not available after
// access: ADMIN
function pause() external onlyAdmin {
_pause();
}
// @notice Switch off the pause
// access: ADMIN
function unpause() external onlyAdmin {
_unpause();
}
// @notice Sets the exchange adapters for swaps
// access: OPERATOR
function setExchangeAdapters(
address _controllerAddress,
string[] calldata _exchangeAdaptersNames,
address[] calldata _exchangeAdapters
) external onlyOperator {
IPositionController(_controllerAddress).setExchangeAdapters(
_exchangeAdaptersNames,
_exchangeAdapters
);
emit UpdateExchangeAdapters(_controllerAddress);
}
function convertIndexToInvestment(uint256 _amount) public view returns (uint256) {
return _amount.mul(_indexRatio()).div(PERCENTAGE_100);
}
function convertInvestmentToIndex(uint256 _amount) public view returns (uint256) {
return _amount.mul(PERCENTAGE_100).div(_indexRatio());
}
/*
// @dev ratio with precision
*/
function _indexRatio() internal view returns (uint256 _ratio) {
uint256 _stakes = totalTVL();
uint256 _currentTotalSupply = totalSupply();
if (_stakes == 0 || _currentTotalSupply == 0) {
_ratio = PERCENTAGE_100;
} else {
_ratio = _stakes.mul(PRECISION).div(_currentTotalSupply);
}
_ratio = _ratio.mul(100); //factor x100
}
function _applyDepositFee(uint256 _amount) internal view returns (uint256 _withFee) {
_withFee = _amount.mul(FEE_PERCENTAGE_100 - depositFee).div(FEE_PERCENTAGE_100);
}
function _accrueManagerFee() internal {
uint256 _feeQuantity = _calculateStreamingFee();
if (_feeQuantity > 0) {
_mint(feeState.feeRecipient, _feeQuantity);
}
feeState.lastStreamingFeeTimestamp = block.timestamp;
emit FeeActualized(feeState.feeRecipient, _feeQuantity);
}
function _calculateStreamingFee() internal view returns (uint256) {
uint256 timeSinceLastFee = block.timestamp.sub(feeState.lastStreamingFeeTimestamp);
uint256 feePercentage = timeSinceLastFee.mul(feeState.streamingFeePercentage).div(
SECONDS_IN_THE_YEAR
);
uint256 amount = feePercentage.mul(totalSupply());
// ScaleFactor (10e18) - fee
uint256 b = PreciseUnitMath.preciseUnit().sub(feePercentage);
return amount.div(b);
}
function getPriceFeed() external view override returns (address) {
return address(priceFeed);
}
// Sets new PriceFeed address
// access: OPERATOR
function setPriceFeed(address _priceFeed) external onlyOperator {
require(_priceFeed != address(0), "BrightRiskToken: BRI22");
priceFeed = IPriceFeed(_priceFeed);
uint256 _to = _positionControllers.length();
for (uint256 i = 0; i < _to; i++) {
IPositionController(_positionControllers.at(i)).setDependencies();
emit UpdatePriceFeedAddress(_positionControllers.at(i), _priceFeed);
}
}
function countPositions() external view override returns (uint256) {
return _positionControllers.length();
}
/// @notice use with countPositions()
function listPositions(uint256 offset, uint256 limit)
public
view
override
returns (address[] memory _positionControllersArr)
{
uint256 to = (offset.add(limit)).min(_positionControllers.length()).max(offset);
_positionControllersArr = new address[](to - offset);
for (uint256 i = offset; i < to; i++) {
_positionControllersArr[i - offset] = _positionControllers.at(i);
}
}
function getBase() public view override returns (address) {
return address(base);
}
// @notice Includes staked funds plus deposited assets
function totalTVL() public view returns (uint256 _tvl) {
uint256 _to = _positionControllers.length();
for (uint256 i = 0; i < _to; i++) {
_tvl = _tvl.add(IPositionController(_positionControllers.at(i)).netWorth());
}
_tvl = _tvl.add(externalPool);
}
}
"
},
"/contracts/tokens/erc20permit-upgradeable/ERC20PermitUpgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity >=0.6.5 <0.8.0;
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import "../../interfaces/tokens/erc20permit-upgradeable/IERC20PermitUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/CountersUpgradeable.sol";
import "./EIP712Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/Initializable.sol";
/**
* COPIED FROM https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/tree/release-v3.4/contracts/drafts
* @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
abstract contract ERC20PermitUpgradeable is
Initializable,
ERC20Upgradeable,
IERC20PermitUpgradeable,
EIP712Upgradeable
{
using CountersUpgradeable for CountersUpgradeable.Counter;
mapping(address => CountersUpgradeable.Counter) private _nonces;
// solhint-disable-next-line var-name-mixedcase
bytes32 private _PERMIT_TYPEHASH;
/**
* @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`.
*
* It's a good idea to use the same `name` that is defined as the ERC20 token name.
*/
function __ERC20Permit_init(string memory name) internal initializer {
__Context_init_unchained();
__EIP712_init_unchained(name, "1");
__ERC20Permit_init_unchained(name);
}
function __ERC20Permit_init_unchained(string memory name) internal initializer {
_PERMIT_TYPEHASH = keccak256(
"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
);
}
/**
* @dev See {IERC20Permit-permit}.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual override {
// solhint-disable-next-line not-rely-on-time
require(block.timestamp <= deadline, "ERC20Permit: expired deadline");
bytes32 structHash = keccak256(
abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _nonces[owner].current(), deadline)
);
bytes32 hash = _hashTypedDataV4(structHash);
address signer = recover(hash, v, r, s);
require(signer == owner, "ERC20Permit: invalid signature");
_nonces[owner].increment();
_approve(owner, spender, value);
}
/**
* @dev Overload of {ECDSA-recover-bytes32-bytes-} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
require(
uint256(s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0,
"ECDSA: invalid signature 's' value"
);
require(v == 27 || v == 28, "ECDSA: invalid signature 'v' value");
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
require(signer != address(0), "ECDSA: invalid signature");
return signer;
}
/**
* @dev See {IERC20Permit-nonces}.
*/
function nonces(address owner) public view override returns (uint256) {
return _nonces[owner].current();
}
/**
* @dev See {IERC20Permit-DOMAIN_SEPARATOR}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view override returns (bytes32) {
return _domainSeparatorV4();
}
uint256[49] private __gap;
}
"
},
"/contracts/tokens/erc20permit-upgradeable/EIP712Upgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
import "@openzeppelin/contracts-upgradeable/proxy/Initializable.sol";
/**
* COPIED FROM https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/tree/release-v3.4/contracts/drafts
* @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
*
* The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,
* thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding
* they need in their contracts using a combination of `abi.encode` and `keccak256`.
*
* This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
* scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
* ({_hashTypedDataV4}).
*
* The implementation of the domain separator was designed to be as efficient as possible while still properly updating
* the chain id to protect against replay attacks on an eventual fork of the chain.
*
* NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
* https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
*/
abstract contract EIP712Upgradeable is Initializable {
/* solhint-disable var-name-mixedcase */
bytes32 private _HASHED_NAME;
bytes32 private _HASHED_VERSION;
bytes32 private constant _TYPE_HASH =
keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
);
/* solhint-enable var-name-mixedcase */
/**
* @dev Initializes the domain separator and parameter caches.
*
* The meaning of `name` and `version` is specified in
* https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
*
* - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
* - `version`: the current major version of the signing domain.
*
* NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
* contract upgrade].
*/
function __EIP712_init(string memory name, string memory version) internal initializer {
__EIP712_init_unchained(name, version);
}
function __EIP712_init_unchained(string memory name, string memory version)
internal
initializer
{
bytes32 hashedName = keccak256(bytes(name));
bytes32 hashedVersion = keccak256(bytes(version));
_HASHED_NAME = hashedName;
_HASHED_VERSION = hashedVersion;
}
/**
* @dev Returns the domain separator for the current chain.
*/
function _domainSeparatorV4() internal view returns (bytes32) {
return _buildDomainSeparator(_TYPE_HASH, _EIP712NameHash(), _EIP712VersionHash());
}
function _buildDomainSeparator(
bytes32 typeHash,
bytes32 name,
bytes32 version
) private view returns (bytes32) {
return keccak256(abi.encode(typeHash, name, version, _getChainId(), address(this)));
}
/**
* @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
* function returns the hash of the fully encoded EIP712 message for this domain.
*
* This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
*
* ```solidity
* bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
* keccak256("Mail(address to,string contents)"),
* mailTo,
* keccak256(bytes(mailContents))
* )));
* address signer = ECDSA.recover(digest, signature);
* ```
*/
function _hashTypedDataV4(bytes32 structHash) internal view returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), structHash));
}
function _getChainId() private view returns (uint256 chainId) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
// solhint-disable-next-line no-inline-assembly
assembly {
chainId := chainid()
}
}
/**
* @dev The hash of the name parameter for the EIP712 domain.
*
* NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs
* are a concern.
*/
function _EIP712NameHash() internal view virtual returns (bytes32) {
return _HASHED_NAME;
}
/**
* @dev The hash of the version parameter for the EIP712 domain.
*
* NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs
* are a concern.
*/
function _EIP712VersionHash() internal view virtual returns (bytes32) {
return _HASHED_VERSION;
}
uint256[50] private __gap;
}
"
},
"/contracts/lib/PreciseUnitMath.sol": {
"content": "/*
Copyright 2020 Set Labs Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
SPDX-License-Identifier: Apache License, Version 2.0
*/
pragma solidity ^0.7.4;
pragma experimental ABIEncoderV2;
import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol";
import {SignedSafeMath} from "@openzeppelin/contracts/math/SignedSafeMath.sol";
/**
* @title PreciseUnitMath
* @author Set Protocol
*
* Arithmetic for fixed-point numbers with 18 decimals of precision. Some functions taken from
* dYdX's BaseMath library.
*
* CHANGELOG:
* - 9/21/20: Added safePower function
* - 4/21/21: Added approximatelyEquals function
*/
library PreciseUnitMath {
using SafeMath for uint256;
using SignedSafeMath for int256;
// The number One in precise units.
uint256 internal constant PRECISE_UNIT = 10**18;
int256 internal constant PRECISE_UNIT_INT = 10**18;
// Max unsigned integer value
uint256 internal constant MAX_UINT_256 = type(uint256).max;
// Max and min signed integer value
int256 internal constant MAX_INT_256 = type(int256).max;
int256 internal constant MIN_INT_256 = type(int256).min;
/**
* @dev Getter function since constants can't be read directly from libraries.
*/
function preciseUnit() internal pure returns (uint256) {
return PRECISE_UNIT;
}
/**
* @dev Getter function since constants can't be read directly from libraries.
*/
function preciseUnitInt() internal pure returns (int256) {
return PRECISE_UNIT_INT;
}
/**
* @dev Getter function since constants can't be read directly from libraries.
*/
function maxUint256() internal pure returns (uint256) {
return MAX_UINT_256;
}
/**
* @dev Getter function since constants can't be read directly from libraries.
*/
function maxInt256() internal pure returns (int256) {
return MAX_INT_256;
}
/**
* @dev Getter function since constants can't be read directly from libraries.
*/
function minInt256() internal pure returns (int256) {
return MIN_INT_256;
}
/**
* @dev Multiplies value a by value b (result is rounded down). It's assumed that the value b is the significand
* of a number with 18 decimals precision.
*/
function preciseMul(uint256 a, uint256 b) internal pure returns (uint256) {
return a.mul(b).div(PRECISE_UNIT);
}
/**
* @dev Multiplies value a by value b (result is rounded towards zero). It's assumed that the value b is the
* significand of a number with 18 decimals precision.
*/
function preciseMul(int256 a, int256 b) internal pure returns (int256) {
return a.mul(b).div(PRECISE_UNIT_INT);
}
/**
* @dev Multiplies value a by value b (result is rounded up). It's assumed that the value b is the significand
* of a number with 18 decimals precision.
*/
function preciseMulCeil(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0 || b == 0) {
return 0;
}
return a.mul(b).sub(1).div(PRECISE_UNIT).add(1);
}
/**
* @dev Divides value a by value b (result is rounded down).
*/
function preciseDiv(uint256 a, uint256 b) internal pure returns (uint256) {
return a.mul(PRECISE_UNIT).div(b);
}
/**
* @dev Divides value a by value b (result is rounded towards 0).
*/
function preciseDiv(int256 a, int256 b) internal pure returns (int256) {
return a.mul(PRECISE_UNIT_INT).div(b);
}
/**
* @dev Divides value a by value b (result is rounded up or away from 0).
*/
function preciseDivCeil(uint256 a, uint256 b) internal pure returns (uint256) {
require(b != 0, "Cant divide by 0");
return a > 0 ? a.mul(PRECISE_UNIT).sub(1).div(b).add(1) : 0;
}
/**
* @dev Divides value a by value b (result is rounded down - positive numbers toward 0 and negative away from 0).
*/
function divDown(int256 a, int256 b) internal pure returns (int256) {
require(b != 0, "Cant divide by 0");
require(a != MIN_INT_256 || b != -1, "Invalid input");
int256 result = a.div(b);
if (a ^ b < 0 && a % b != 0) {
result -= 1;
}
return result;
}
/**
* @dev Multiplies value a by value b where rounding is towards the lesser number.
* (positive values are rounded towards zero and negative values are rounded away from 0).
*/
function conservativePreciseMul(int256 a, int256 b) internal pure returns (int256) {
return divDown(a.mul(b), PRECISE_UNIT_INT);
}
/**
* @dev Divides value a by value b where rounding is towards the lesser number.
* (positive values are rounded towards zero and negative values are rounded away from 0).
*/
function conservativePreciseDiv(int256 a, int256 b) internal pure returns (int256) {
return divDown(a.mul(PRECISE_UNIT_INT), b);
}
/**
* @dev Performs the power on a specified value, reverts on overflow.
*/
function safePower(uint256 a, uint256 pow) internal pure returns (uint256) {
require(a > 0, "Value must be positive");
uint256 result = 1;
for (uint256 i = 0; i < pow; i++) {
uint256 previousResult = result;
// Using safemath multiplication prevents overflows
result = previousResult.mul(a);
}
return result;
}
/**
* @dev Returns true if a =~ b within range, false otherwise.
*/
function approximatelyEquals(
uint256 a,
uint256 b,
uint256 range
) internal pure returns (bool) {
return a <= b.add(range) && a >= b.sub(range);
}
}
"
},
"/contracts/interfaces/tokens/erc20permit-upgradeable/IERC20PermitUpgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
/**
* COPIED FROM https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/tree/release-v3.4/contracts/drafts
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20PermitUpgradeable {
/**
* @dev Sets `value` as the allowance of `spender` over `owner`'s tokens,
* given `owner`'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for `permit`, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
"
},
"/contracts/interfaces/helpers/IPriceFeed.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.7.4;
interface IPriceFeed {
function howManyTokensAinB(
address tokenA,
address tokenB,
uint256 amount
) external view returns (uint256);
}
"
},
"/contracts/interfaces/IPositionController.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.7.4;
pragma experimental ABIEncoderV2;
interface IPositionController {
enum StakingState {
IDLE,
STAKING,
WITHDRAWING_REWARDS,
UNSTAKING
}
struct FeeInfo {
address feeRecipient; // Address to accrue fees to
uint256 successFeePercentage; // Percent of rewards accruing to manager
}
function canStake() external view returns (bool);
function canCallUnstake() external view returns (bool);
function canUnstake() external view returns (bool);
function stake(
uint256 _amount,
bytes calldata _exchangeData,
bytes calldata _calldata
) external;
function setDependencies() external;
function callUnstake() external returns (uint256);
function unstake(bytes calldata _exchangeData, bytes calldata _signature)
external
returns (uint256);
function maxUnstake() external view returns (uint256);
function withdrawRewards(bytes calldata _exchangeData, bytes calldata _calldata) external;
function setExchangeAdapters(
string[] calldata _exchangeAdaptersNames,
address[] calldata _exchangeAdapters
) external;
function outstandingRewards() external view returns (uint256);
/// @notice Worth of managed assets, in 'base' currency.
//// Includes 'staked' amount and outstanding rewards, converted
function netWorth() external view returns (uint256);
// @notice APY, if NOT based on historical purchases
// @return % with precision
function apy() external view returns (uint256);
function description() external view returns (string memory);
function productList() external view returns (address[] memory _products);
function unstakingInfo() external view returns (uint256 _amount, uint256 _unstakeAvailable);
}
"
},
"/contracts/interfaces/IBrightRiskToken.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.7.4;
interface IBrightRiskToken {
// @dev DEPRECATED
struct DepositorInfo {
uint256 depositAmount;
bool readyToStake;
uint256 minting;
}
function getBase() external view returns (address);
function getPriceFeed() external view returns (address);
function countPositions() external view returns (uint256);
function listPositions(uint256 offset, uint256 limit) external view returns (address[] memory);
function deposit(uint256 _maxAmount) external;
function depositInternal(uint256 _amount) external;
}
"
},
"@openzeppelin/contracts/utils/EnumerableSet.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.0.0, only sets of type `address` (`AddressSet`) and `uint256`
* (`UintSet`) are supported.
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping (bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) { // Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
// When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs
// so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.
bytes32 lastvalue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastvalue;
// Update the index for the moved value
set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
require(set._values.length > index, "EnumerableSet: index out of bounds");
return set._values[index];
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(value)));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(value)));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(value)));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint256(_at(set._inner, index)));
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
}
"
},
"@openzeppelin/contracts/utils/Address.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
/**
* @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) {
// According to EIP-1052, 0x0 is the value returned for not-yet created accounts
// and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
// for accounts without code, i.e. `keccak256('')`
bytes32 codehash;
bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
// solhint-disable-next-line no-inline-assembly
assembly { codehash := extcodehash(account) }
return (codehash != accountHash && codehash != 0x0);
}
/**
* @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);
}
}
}
}
"
},
"@openzeppelin/contracts/token/ERC20/SafeERC20.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.7.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");
}
}
}
"
},
"@openzeppelin/contracts/token/ERC20/IERC20.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.7.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);
}
"
},
"@openzeppelin/contracts/token/ERC20/ERC20.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import "../../GSN/Context.sol";
import "./IERC20.sol";
import "../../math/SafeMath.sol";
import "../../utils/Address.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
* For a generic mechanism see {ERC20PresetMinterPauser}.
*
* TIP: For a detailed writeup see our guide
* https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* We have followed general OpenZeppelin guidelines: functions revert instead
* of returning `false` on failure. This behavior is nonetheless conventional
* and does not conflict with the expectations of ERC20 applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*
* Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
* functions have been added to mitigate the well-known issues around setting
* allowances. See {IERC20-approve}.
*/
contract ERC20 is Context, IERC20 {
using SafeMath for uint256;
using Address for address;
mapping (address => uint256) private _balances;
mapping (address => mapping (address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
uint8 private _decimals;
/**
* @dev Sets the values for {name} and {symbol}, initializes {decimals} with
* a default value of 18.
*
* To select a different value for {decimals}, use {_setupDecimals}.
*
* All three of these values are immutable: they can only be set once during
* construction.
*/
constructor (string memory name, string memory symbol) {
_name = name;
_symbol = symbol;
_decimals = 18;
}
/**
* @dev Returns the name of the token.
*/
function name() public view returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5,05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is
* called.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view returns (uint8) {
return _decimals;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view override returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view override returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `recipient` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(_msgSender(), recipient, amount);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 amount) public virtual override returns (bool) {
_approve(_msgSender(), spender, amount);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20};
*
* Requirements:
* - `sender` and `recipient` cannot be the zero address.
* - `sender` must have a balance of at least `amount`.
* - the caller must have allowance for ``sender``'s tokens of at least
* `amount`.
*/
function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(sender, recipient, amount);
_approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedVa
Submitted on: 2025-10-27 12:56:46
Comments
Log in to comment.
No comments yet.