Contract Source Code:
// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity 0.7.5;
import "./SafeMath.sol";
library Counters {
using SafeMath for uint256;
struct Counter {
uint256 _value; // default: 0
}
function current(Counter storage counter) internal view returns (uint256) {
return counter._value;
}
function increment(Counter storage counter) internal {
counter._value += 1;
}
function decrement(Counter storage counter) internal {
counter._value = counter._value.sub(1);
}
}
// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity 0.7.5;
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];
}
function _getValues(
Set storage set_
) private view returns (bytes32[] storage) {
return set_._values;
}
// TODO needs insert function that maintains order.
// TODO needs NatSpec documentation comment.
/**
* Inserts new value by moving existing value at provided index to end
* of array and setting provided value at provided index
*/
function _insert(
Set storage set_,
uint256 index_,
bytes32 valueToInsert_
) private returns (bool) {
require(set_._values.length > index_);
require(
!_contains(set_, valueToInsert_),
"Remove value you wish to insert if you wish to reorder array."
);
bytes32 existingValue_ = _at(set_, index_);
set_._values[index_] = valueToInsert_;
return _add(set_, existingValue_);
}
struct Bytes4Set {
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(Bytes4Set storage set, bytes4 value) internal returns (bool) {
return _add(set._inner, 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(
Bytes4Set storage set,
bytes4 value
) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(
Bytes4Set storage set,
bytes4 value
) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function length(Bytes4Set 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(
Bytes4Set storage set,
uint256 index
) internal view returns (bytes4) {
return bytes4(_at(set._inner, index));
}
function getValues(
Bytes4Set storage set_
) internal view returns (bytes4[] memory) {
bytes4[] memory bytes4Array_;
for (
uint256 iteration_ = 0;
_length(set_._inner) > iteration_;
iteration_++
) {
bytes4Array_[iteration_] = bytes4(_at(set_._inner, iteration_));
}
return bytes4Array_;
}
function insert(
Bytes4Set storage set_,
uint256 index_,
bytes4 valueToInsert_
) internal returns (bool) {
return _insert(set_._inner, index_, valueToInsert_);
}
struct Bytes32Set {
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(
Bytes32Set storage set,
bytes32 value
) internal returns (bool) {
return _add(set._inner, 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(
Bytes32Set storage set,
bytes32 value
) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(
Bytes32Set storage set,
bytes32 value
) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function length(Bytes32Set 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(
Bytes32Set storage set,
uint256 index
) internal view returns (bytes32) {
return _at(set._inner, index);
}
function getValues(
Bytes32Set storage set_
) internal view returns (bytes4[] memory) {
bytes4[] memory bytes4Array_;
for (
uint256 iteration_ = 0;
_length(set_._inner) >= iteration_;
iteration_++
) {
bytes4Array_[iteration_] = bytes4(at(set_, iteration_));
}
return bytes4Array_;
}
function insert(
Bytes32Set storage set_,
uint256 index_,
bytes32 valueToInsert_
) internal returns (bool) {
return _insert(set_._inner, index_, valueToInsert_);
}
// 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)));
}
/**
* TODO Might require explicit conversion of bytes32[] to address[].
* Might require iteration.
*/
function getValues(
AddressSet storage set_
) internal view returns (address[] memory) {
address[] memory addressArray;
for (
uint256 iteration_ = 0;
_length(set_._inner) >= iteration_;
iteration_++
) {
addressArray[iteration_] = at(set_, iteration_);
}
return addressArray;
}
function insert(
AddressSet storage set_,
uint256 index_,
address valueToInsert_
) internal returns (bool) {
return _insert(set_._inner, index_, bytes32(uint256(valueToInsert_)));
}
// 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));
}
struct UInt256Set {
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(
UInt256Set 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(
UInt256Set 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(
UInt256Set 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(UInt256Set 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(
UInt256Set storage set,
uint256 index
) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
}
// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity 0.7.5;
import "./IERC20.sol";
import "./SafeMath.sol";
abstract contract ERC20 is IERC20 {
using SafeMath for uint256;
// TODO comment actual hash value.
bytes32 private constant ERC20TOKEN_ERC1820_INTERFACE_ID =
keccak256("ERC20Token");
// Present in ERC777
mapping(address => uint256) internal _balances;
// Present in ERC777
mapping(address => mapping(address => uint256)) internal _allowances;
// Present in ERC777
uint256 internal _totalSupply;
// Present in ERC777
string internal _name;
// Present in ERC777
string internal _symbol;
// Present in ERC777
uint8 internal _decimals;
constructor(string memory name_, string memory symbol_, uint8 decimals_) {
_name = name_;
_symbol = symbol_;
_decimals = decimals_;
}
function name() public view returns (string memory) {
return _name;
}
function symbol() public view returns (string memory) {
return _symbol;
}
function decimals() public view override returns (uint8) {
return _decimals;
}
function totalSupply() public view override returns (uint256) {
return _totalSupply;
}
function balanceOf(
address account
) public view virtual override returns (uint256) {
return _balances[account];
}
function transfer(
address recipient,
uint256 amount
) public virtual override returns (bool) {
_transfer(msg.sender, recipient, amount);
return true;
}
function allowance(
address owner,
address spender
) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
function approve(
address spender,
uint256 amount
) public virtual override returns (bool) {
_approve(msg.sender, spender, amount);
return true;
}
function transferFrom(
address sender,
address recipient,
uint256 amount
) public virtual override returns (bool) {
_transfer(sender, recipient, amount);
_approve(
sender,
msg.sender,
_allowances[sender][msg.sender].sub(
amount,
"ERC20: transfer amount exceeds allowance"
)
);
return true;
}
function increaseAllowance(
address spender,
uint256 addedValue
) public virtual returns (bool) {
_approve(
msg.sender,
spender,
_allowances[msg.sender][spender].add(addedValue)
);
return true;
}
function decreaseAllowance(
address spender,
uint256 subtractedValue
) public virtual returns (bool) {
_approve(
msg.sender,
spender,
_allowances[msg.sender][spender].sub(
subtractedValue,
"ERC20: decreased allowance below zero"
)
);
return true;
}
function _transfer(
address sender,
address recipient,
uint256 amount
) internal virtual {
require(sender != address(0), "ERC20: transfer from the zero address");
require(recipient != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(sender, recipient, amount);
_balances[sender] = _balances[sender].sub(
amount,
"ERC20: transfer amount exceeds balance"
);
_balances[recipient] = _balances[recipient].add(amount);
emit Transfer(sender, recipient, amount);
}
function _mint(address account_, uint256 amount_) internal virtual {
require(account_ != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(this), account_, amount_);
_totalSupply = _totalSupply.add(amount_);
_balances[account_] = _balances[account_].add(amount_);
emit Transfer(address(this), account_, amount_);
}
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
_balances[account] = _balances[account].sub(
amount,
"ERC20: burn amount exceeds balance"
);
_totalSupply = _totalSupply.sub(amount);
emit Transfer(account, address(0), amount);
}
function _approve(
address owner,
address spender,
uint256 amount
) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
function _beforeTokenTransfer(
address from_,
address to_,
uint256 amount_
) internal virtual {}
}
// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity 0.7.5;
import "./IERC20.sol";
import "./IERC2612Permit.sol";
import "./Counters.sol";
import "./ERC20.sol";
abstract contract ERC20Permit is ERC20, IERC2612Permit {
using Counters for Counters.Counter;
mapping(address => Counters.Counter) private _nonces;
// keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
bytes32 public constant PERMIT_TYPEHASH =
0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
bytes32 public DOMAIN_SEPARATOR;
constructor() {
uint256 chainID;
assembly {
chainID := chainid()
}
DOMAIN_SEPARATOR = keccak256(
abi.encode(
keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
),
keccak256(bytes(name())),
keccak256(bytes("1")), // Version
chainID,
address(this)
)
);
}
/**
* @dev See {IERC2612Permit-permit}.
*
*/
function permit(
address owner,
address spender,
uint256 amount,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual override {
require(block.timestamp <= deadline, "Permit: expired deadline");
bytes32 hashStruct = keccak256(
abi.encode(
PERMIT_TYPEHASH,
owner,
spender,
amount,
_nonces[owner].current(),
deadline
)
);
bytes32 _hash = keccak256(
abi.encodePacked(uint16(0x1901), DOMAIN_SEPARATOR, hashStruct)
);
address signer = ecrecover(_hash, v, r, s);
require(
signer != address(0) && signer == owner,
"ZeroSwapPermit: Invalid signature"
);
_nonces[owner].increment();
_approve(owner, spender, amount);
}
/**
* @dev See {IERC2612Permit-nonces}.
*/
function nonces(address owner) public view override returns (uint256) {
return _nonces[owner].current();
}
}
// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity 0.7.5;
interface IERC20 {
function decimals() external view returns (uint8);
/**
* @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: AGPL-3.0-or-later
pragma solidity 0.7.5;
interface IERC2612Permit {
function permit(
address owner,
address spender,
uint256 amount,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function nonces(address owner) external view returns (uint256);
}
// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity 0.7.5;
interface IOwnable {
function owner() external view returns (address);
function renounceOwnership() external;
function transferOwnership(address newOwner_) external;
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.7.5;
interface IPairFactory {
event FEE_TOO_HIGH();
event ZERO_FEE();
/// @dev invalid assortment
event IA();
/// @dev zero address
event ZA();
/// @dev pair exists
event PE();
event NOT_AUTHORIZED();
event INVALID_FEE_SPLIT();
event PairCreated(
address indexed token0,
address indexed token1,
address pair,
uint256
);
event SetFee(uint256 indexed fee);
event SetPairFee(address indexed pair, uint256 indexed fee);
event SetFeeSplit(uint256 indexed _feeSplit);
event SetPairFeeSplit(address indexed pair, uint256 indexed _feeSplit);
event SkimStatus(address indexed _pair, bool indexed _status);
event NewTreasury(address indexed _caller, address indexed _newTreasury);
event FeeSplitWhenNoGauge(address indexed _caller, bool indexed _status);
event SetFeeRecipient(address indexed pair, address indexed feeRecipient);
/// @notice returns the total length of legacy pairs
/// @return _length the length
function allPairsLength() external view returns (uint256 _length);
/// @notice calculates if the address is a legacy pair
/// @param pair the address to check
/// @return _boolean the bool return
function isPair(address pair) external view returns (bool _boolean);
/// @notice calculates the pairCodeHash
/// @return _hash the pair code hash
function pairCodeHash() external view returns (bytes32 _hash);
/// @param tokenA address of tokenA
/// @param tokenB address of tokenB
/// @param stable whether it uses the stable curve
/// @return _pair the address of the pair
function getPair(
address tokenA,
address tokenB,
bool stable
) external view returns (address _pair);
/// @notice creates a new legacy pair
/// @param tokenA address of tokenA
/// @param tokenB address of tokenB
/// @param stable whether it uses the stable curve
/// @return pair the address of the created pair
function createPair(
address tokenA,
address tokenB,
bool stable
) external returns (address pair);
/// @notice the address of the voter
/// @return _voter the address of the voter
function voter() external view returns (address _voter);
/// @notice returns the address of a pair based on the index
/// @param _index the index to check for a pair
/// @return _pair the address of the pair at the index
function allPairs(uint256 _index) external view returns (address _pair);
/// @notice the swap fee of a pair
/// @param _pair the address of the pair
/// @return _fee the fee
function pairFee(address _pair) external view returns (uint256 _fee);
/// @notice the split of fees
/// @return _split the feeSplit
function feeSplit() external view returns (uint256 _split);
/// @notice sets the swap fee for a pair
/// @param _pair the address of the pair
/// @param _fee the fee for the pair
function setPairFee(address _pair, uint256 _fee) external;
/// @notice set the swap fees of the pair
/// @param _fee the fee, scaled to MAX 10% of 100_000
function setFee(uint256 _fee) external;
/// @notice the address for the treasury
/// @return _treasury address of the treasury
function treasury() external view returns (address _treasury);
/// @notice sets the pairFees contract
/// @param _pair the address of the pair
/// @param _pairFees the address of the new Pair Fees
function setFeeRecipient(address _pair, address _pairFees) external;
/// @notice sets the feeSplit for a pair
/// @param _pair the address of the pair
/// @param _feeSplit the feeSplit
function setPairFeeSplit(address _pair, uint256 _feeSplit) external;
/// @notice whether there is feeSplit when there's no gauge
/// @return _boolean whether there is a feesplit when no gauge
function feeSplitWhenNoGauge() external view returns (bool _boolean);
/// @notice whether a pair can be skimmed
/// @param _pair the pair address
/// @return _boolean whether skim is enabled
function skimEnabled(address _pair) external view returns (bool _boolean);
/// @notice set whether skim is enabled for a specific pair
function setSkimEnabled(address _pair, bool _status) external;
/// @notice sets a new treasury address
/// @param _treasury the new treasury address
function setTreasury(address _treasury) external;
/// @notice set whether there should be a feesplit without gauges
/// @param status whether enabled or not
function setFeeSplitWhenNoGauge(bool status) external;
/// @notice sets the feesSplit globally
/// @param _feeSplit the fee split
function setFeeSplit(uint256 _feeSplit) external;
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.7.5;
interface IRouter {
event EXPIRED();
event IDENTICAL();
event ZERO_ADDRESS();
event INSUFFICIENT_AMOUNT();
event INSUFFICIENT_LIQUIDITY();
event INSUFFICIENT_OUTPUT_AMOUNT();
event INVALID_PATH();
event INSUFFICIENT_B_AMOUNT();
event INSUFFICIENT_A_AMOUNT();
event EXCESSIVE_INPUT_AMOUNT();
event ETH_TRANSFER_FAILED();
event INVALID_RESERVES();
function WETH() external view returns (address);
function factory() external view returns (address);
/// @notice sorts the tokens to see what the expected LP output would be for token0 and token1 (A/B)
/// @param tokenA the address of tokenA
/// @param tokenB the address of tokenB
/// @return token0 address of which becomes token0
/// @return token1 address of which becomes token1
function sortTokens(
address tokenA,
address tokenB
) external pure returns (address token0, address token1);
/// @notice calculates the CREATE2 address for a pair without making any external calls
/// @param tokenA the address of tokenA
/// @param tokenB the address of tokenB
/// @param stable if the pair is using the stable curve
/// @return pair address of the pair
function pairFor(
address tokenA,
address tokenB,
bool stable
) external view returns (address pair);
/// @notice fetches and sorts the reserves for a pair
/// @param tokenA the address of tokenA
/// @param tokenB the address of tokenB
/// @param stable if the pair is using the stable curve
/// @return reserveA get the reserves for tokenA
/// @return reserveB get the reserves for tokenB
function getReserves(
address tokenA,
address tokenB,
bool stable
) external view returns (uint256 reserveA, uint256 reserveB);
/// @notice performs chained getAmountOut calculations on any number of pairs
/// @param amountIn amount of tokenIn
/// @param tokenIn address of the token going in
/// @param tokenOut address of the token coming out
/// @return amount uint amount out
/// @return stable if the curve used is stable or not
function getAmountOut(
uint256 amountIn,
address tokenIn,
address tokenOut
) external view returns (uint256 amount, bool stable);
/// @notice performs calculations to determine the expected state when adding liquidity
/// @param tokenA the address of tokenA
/// @param tokenB the address of tokenB
/// @param stable if the pair is using the stable curve
/// @param amountADesired amount of tokenA desired to be added
/// @param amountBDesired amount of tokenB desired to be added
/// @return amountA amount of tokenA added
/// @return amountB amount of tokenB added
/// @return liquidity liquidity value added
function quoteAddLiquidity(
address tokenA,
address tokenB,
bool stable,
uint256 amountADesired,
uint256 amountBDesired
)
external
view
returns (uint256 amountA, uint256 amountB, uint256 liquidity);
/// @param tokenA the address of tokenA
/// @param tokenB the address of tokenB
/// @param stable if the pair is using the stable curve
/// @param liquidity liquidity value to remove
/// @return amountA amount of tokenA removed
/// @return amountB amount of tokenB removed
function quoteRemoveLiquidity(
address tokenA,
address tokenB,
bool stable,
uint256 liquidity
) external view returns (uint256 amountA, uint256 amountB);
/// @param tokenA the address of tokenA
/// @param tokenB the address of tokenB
/// @param stable if the pair is using the stable curve
/// @param amountADesired amount of tokenA desired to be added
/// @param amountBDesired amount of tokenB desired to be added
/// @param amountAMin slippage for tokenA calculated from this param
/// @param amountBMin slippage for tokenB calculated from this param
/// @param to the address the liquidity tokens should be minted to
/// @param deadline timestamp deadline
/// @return amountA amount of tokenA used
/// @return amountB amount of tokenB used
/// @return liquidity amount of liquidity minted
function addLiquidity(
address tokenA,
address tokenB,
bool stable,
uint256 amountADesired,
uint256 amountBDesired,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
) external returns (uint256 amountA, uint256 amountB, uint256 liquidity);
/// @param token the address of token
/// @param stable if the pair is using the stable curve
/// @param amountTokenDesired desired amount for token
/// @param amountTokenMin slippage for token
/// @param amountETHMin minimum amount of ETH added (slippage)
/// @param to the address the liquidity tokens should be minted to
/// @param deadline timestamp deadline
/// @return amountToken amount of the token used
/// @return amountETH amount of ETH used
/// @return liquidity amount of liquidity minted
function addLiquidityETH(
address token,
bool stable,
uint256 amountTokenDesired,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
)
external
payable
returns (uint256 amountToken, uint256 amountETH, uint256 liquidity);
/// @param tokenA the address of tokenA
/// @param tokenB the address of tokenB
/// @param stable if the pair is using the stable curve
/// @param amountADesired amount of tokenA desired to be added
/// @param amountBDesired amount of tokenB desired to be added
/// @param amountAMin slippage for tokenA calculated from this param
/// @param amountBMin slippage for tokenB calculated from this param
/// @param to the address the liquidity tokens should be minted to
/// @param deadline timestamp deadline
/// @return amountA amount of tokenA used
/// @return amountB amount of tokenB used
/// @return liquidity amount of liquidity minted
function addLiquidityAndStake(
address tokenA,
address tokenB,
bool stable,
uint256 amountADesired,
uint256 amountBDesired,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
) external returns (uint256 amountA, uint256 amountB, uint256 liquidity);
/// @notice adds liquidity to a legacy pair using ETH, and stakes it into a gauge on "to's" behalf
/// @param token the address of token
/// @param stable if the pair is using the stable curve
/// @param amountTokenDesired amount of token to be used
/// @param amountTokenMin slippage of token
/// @param amountETHMin slippage of ETH
/// @param to the address the liquidity tokens should be minted to
/// @param deadline timestamp deadline
/// @return amountA amount of tokenA used
/// @return amountB amount of tokenB used
/// @return liquidity amount of liquidity minted
function addLiquidityETHAndStake(
address token,
bool stable,
uint256 amountTokenDesired,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
)
external
payable
returns (uint256 amountA, uint256 amountB, uint256 liquidity);
/// @param tokenA the address of tokenA
/// @param tokenB the address of tokenB
/// @param stable if the pair is using the stable curve
/// @param liquidity amount of LP tokens to remove
/// @param amountAMin slippage of tokenA
/// @param amountBMin slippage of tokenB
/// @param to the address the liquidity tokens should be minted to
/// @param deadline timestamp deadline
/// @return amountA amount of tokenA used
/// @return amountB amount of tokenB used
function removeLiquidity(
address tokenA,
address tokenB,
bool stable,
uint256 liquidity,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
) external returns (uint256 amountA, uint256 amountB);
/// @param token address of the token
/// @param stable if the pair is using the stable curve
/// @param liquidity liquidity tokens to remove
/// @param amountTokenMin slippage of token
/// @param amountETHMin slippage of ETH
/// @param to the address the liquidity tokens should be minted to
/// @param deadline timestamp deadline
/// @return amountToken amount of token used
/// @return amountETH amount of ETH used
function removeLiquidityETH(
address token,
bool stable,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
) external returns (uint256 amountToken, uint256 amountETH);
/// @notice **** REMOVE LIQUIDITY (supporting fee-on-transfer tokens)****
/// @param token address of the token
/// @param stable if the swap curve is stable
/// @param liquidity liquidity value (lp tokens)
/// @param amountTokenMin slippage of token
/// @param amountETHMin slippage of ETH
/// @param to address to send to
/// @param deadline timestamp deadline
/// @return amountToken amount of token received
/// @return amountETH amount of ETH received
function removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
bool stable,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
) external returns (uint256 amountToken, uint256 amountETH);
}
// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity 0.7.5;
import "./IOwnable.sol";
contract Ownable is IOwnable {
address internal _owner;
event OwnershipTransferred(
address indexed previousOwner,
address indexed newOwner
);
constructor() {
_owner = msg.sender;
emit OwnershipTransferred(address(0), _owner);
}
function owner() public view override returns (address) {
return _owner;
}
modifier onlyOwner() {
require(_owner == msg.sender, "Ownable: caller is not the owner");
_;
}
function renounceOwnership() public virtual override onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
function transferOwnership(
address newOwner_
) public virtual override onlyOwner {
require(
newOwner_ != address(0),
"Ownable: new owner is the zero address"
);
emit OwnershipTransferred(_owner, newOwner_);
_owner = newOwner_;
}
}
// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity 0.7.5;
library SafeMath {
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function add32(uint32 a, uint32 b) internal pure returns (uint32) {
uint32 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
function sub(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
function sub32(uint32 a, uint32 b) internal pure returns (uint32) {
return sub32(a, b, "SafeMath: subtraction overflow");
}
function sub32(
uint32 a,
uint32 b,
string memory errorMessage
) internal pure returns (uint32) {
require(b <= a, errorMessage);
uint32 c = a - b;
return c;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
function mul32(uint32 a, uint32 b) internal pure returns (uint32) {
if (a == 0) {
return 0;
}
uint32 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by 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;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
function mod(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
function sqrrt(uint256 a) internal pure returns (uint c) {
if (a > 3) {
c = a;
uint b = add(div(a, 2), 1);
while (b < c) {
c = b;
b = div(add(div(a, b), b), 2);
}
} else if (a != 0) {
c = 1;
}
}
function percentageAmount(
uint256 total_,
uint8 percentage_
) internal pure returns (uint256 percentAmount_) {
return div(mul(total_, percentage_), 1000);
}
function substractPercentage(
uint256 total_,
uint8 percentageToSub_
) internal pure returns (uint256 result_) {
return sub(total_, div(mul(total_, percentageToSub_), 1000));
}
function percentageOfTotal(
uint256 part_,
uint256 total_
) internal pure returns (uint256 percent_) {
return div(mul(part_, 100), total_);
}
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);
}
function quadraticPricing(
uint256 payment_,
uint256 multiplier_
) internal pure returns (uint256) {
return sqrrt(mul(multiplier_, payment_));
}
function bondingCurve(
uint256 supply_,
uint256 multiplier_
) internal pure returns (uint256) {
return mul(multiplier_, supply_);
}
}
// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity 0.7.5;
import "./Ownable.sol";
contract VaultOwned is Ownable {
address internal _vault;
function setVault(address vault_) external onlyOwner returns (bool) {
_vault = vault_;
return true;
}
function vault() public view returns (address) {
return _vault;
}
modifier onlyVault() {
require(_vault == msg.sender, "VaultOwned: caller is not the Vault");
_;
}
}
// SPDX-License-Identifier: AGPL-3.0-or-later
pragma abicoder v2;
pragma solidity 0.7.5;
import "./lib/EnumerableSet.sol";
import "./lib/IERC2612Permit.sol";
import "./lib/IERC20.sol";
import "./lib/ERC20Permit.sol";
import "./lib/VaultOwned.sol";
import "./lib/IRouter.sol";
import "./lib/IPairFactory.sol";
contract Solis is ERC20Permit, VaultOwned {
using SafeMath for uint256;
address public shadowPair;
address private treasury;
uint256 public buyTax = 5;
uint256 public sellTax = 15;
mapping(address => bool) private _isExcludedFromTaxes;
mapping(address => bool) public automatedMarketMakerPairs;
receive() external payable {}
constructor() ERC20("Solis", "SOLIS", 9) {
_mint(msg.sender, 4_000_000_000 * 1e9);
treasury = msg.sender;
excludeFromTaxes(owner(), true);
excludeFromTaxes(address(this), true);
excludeFromTaxes(address(0xdead), true);
}
function mint(address account_, uint256 amount_) external onlyVault {
_mint(account_, amount_);
}
function burn(uint256 amount) public virtual {
_burn(msg.sender, amount);
}
function burnFrom(address account_, uint256 amount_) public virtual {
_burnFrom(account_, amount_);
}
function _burnFrom(address account_, uint256 amount_) public virtual {
uint256 decreasedAllowance_ = allowance(account_, msg.sender).sub(
amount_,
"ERC20: burn amount exceeds allowance"
);
_approve(account_, msg.sender, decreasedAllowance_);
_burn(account_, amount_);
}
function excludeFromTaxes(address account, bool excluded) public onlyOwner {
_isExcludedFromTaxes[account] = excluded;
}
function setAutomatedMarketMakerPair(
address pair,
bool value
) public onlyOwner {
_setAutomatedMarketMakerPair(pair, value);
}
function _setAutomatedMarketMakerPair(address pair, bool value) private {
automatedMarketMakerPairs[pair] = value;
}
function updateBuyTax(uint256 _buyTax) external onlyOwner {
require(_buyTax <= 100, "Cannot set tax higher than 100%");
buyTax = _buyTax;
}
function updateSellTax(uint256 _sellTax) external onlyOwner {
require(_sellTax <= 100, "Cannot set tax higher than 100%");
sellTax = _sellTax;
}
function updateTaxes(uint256 _buyTax, uint256 _sellTax) external onlyOwner {
require(
_sellTax <= 100 && _buyTax <= 100,
"Cannot set taxes higher than 100%"
);
buyTax = _buyTax;
sellTax = _sellTax;
}
function _transfer(
address from,
address to,
uint256 amount
) internal override {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
if (amount == 0) {
super._transfer(from, to, 0);
return;
}
bool takeTax = true;
if (_isExcludedFromTaxes[from] || _isExcludedFromTaxes[to]) {
takeTax = false;
}
uint256 taxes = 0;
if (takeTax) {
if (automatedMarketMakerPairs[to] && sellTax > 0) {
taxes = amount.mul(sellTax).div(100);
} else if (automatedMarketMakerPairs[from] && buyTax > 0) {
taxes = amount.mul(buyTax).div(100);
}
if (taxes > 0) {
super._transfer(from, treasury, taxes);
}
amount -= taxes;
}
super._transfer(from, to, amount);
}
function setTreasury(address _treasury) external onlyOwner {
treasury = _treasury;
}
}