编译器
0.6.11+commit.5ef660b1
文件 1 的 72:AccessControl.sol
pragma solidity ^0.6.0;
import "./EnumerableSet.sol";
import "./Address.sol";
import "./Context.sol";
abstract contract AccessControl is Context {
using EnumerableSet for EnumerableSet.AddressSet;
using Address for address;
struct RoleData {
EnumerableSet.AddressSet members;
bytes32 adminRole;
}
mapping (bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
function hasRole(bytes32 role, address account) public view returns (bool) {
return _roles[role].members.contains(account);
}
function getRoleMemberCount(bytes32 role) public view returns (uint256) {
return _roles[role].members.length();
}
function getRoleMember(bytes32 role, uint256 index) public view returns (address) {
return _roles[role].members.at(index);
}
function getRoleAdmin(bytes32 role) public view returns (bytes32) {
return _roles[role].adminRole;
}
function grantRole(bytes32 role, address account) public virtual {
require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to grant");
_grantRole(role, account);
}
function revokeRole(bytes32 role, address account) public virtual {
require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to revoke");
_revokeRole(role, account);
}
function renounceRole(bytes32 role, address account) public virtual {
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
}
function _setupRole(bytes32 role, address account) internal virtual {
_grantRole(role, account);
}
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
emit RoleAdminChanged(role, _roles[role].adminRole, adminRole);
_roles[role].adminRole = adminRole;
}
function _grantRole(bytes32 role, address account) private {
if (_roles[role].members.add(account)) {
emit RoleGranted(role, account, _msgSender());
}
}
function _revokeRole(bytes32 role, address account) private {
if (_roles[role].members.remove(account)) {
emit RoleRevoked(role, account, _msgSender());
}
}
}
文件 2 的 72:Address.sol
pragma solidity 0.6.11;
library Address {
function isContract(address account) internal view returns (bool) {
uint256 size;
assembly { size := extcodesize(account) }
return size > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{ value: amount }("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
return _functionCallWithValue(target, data, 0, errorMessage);
}
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");
}
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");
(bool success, bytes memory returndata) = target.call{ value: weiValue }(data);
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 3 的 72:AggregatorV3Interface.sol
pragma solidity >=0.6.0;
interface AggregatorV3Interface {
function decimals() external view returns (uint8);
function description() external view returns (string memory);
function version() external view returns (uint256);
function getRoundData(uint80 _roundId)
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
function latestRoundData()
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
}
文件 4 的 72:Babylonian.sol
pragma solidity 0.6.11;
library Babylonian {
function sqrt(uint y) internal pure returns (uint z) {
if (y > 3) {
z = y;
uint x = y / 2 + 1;
while (x < z) {
z = x;
x = (y / x + x) / 2;
}
} else if (y != 0) {
z = 1;
}
}
}
文件 5 的 72:BlockMiner.sol
pragma solidity 0.6.11;
contract BlockMiner {
uint256 public blocksMined;
constructor () public {
blocksMined = 0;
}
function mine() public {
blocksMined += 1;
}
function blockTime() external view returns (uint256) {
return block.timestamp;
}
}
文件 6 的 72:ChainlinkETHUSDPriceConsumer.sol
pragma solidity 0.6.11;
pragma experimental ABIEncoderV2;
import "./AggregatorV3Interface.sol";
contract ChainlinkETHUSDPriceConsumer {
AggregatorV3Interface internal priceFeed;
constructor() public {
priceFeed = AggregatorV3Interface(0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419);
}
function getLatestPrice() public view returns (int) {
(
,
int price,
,
,
) = priceFeed.latestRoundData();
return price;
}
function getDecimals() public view returns (uint8) {
return priceFeed.decimals();
}
}
文件 7 的 72:ChainlinkETHUSDPriceConsumerTest.sol
pragma solidity 0.6.11;
pragma experimental ABIEncoderV2;
import "./AggregatorV3Interface.sol";
contract ChainlinkETHUSDPriceConsumerTest {
constructor() public {
}
function getLatestPrice() public pure returns (int) {
return 59000000000;
}
function getDecimals() public pure returns (uint8) {
return 8;
}
}
文件 8 的 72:Context.sol
pragma solidity 0.6.11;
contract Context {
constructor () internal { }
function _msgSender() internal view virtual returns (address payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this;
return msg.data;
}
}
文件 9 的 72:ERC20.sol
pragma solidity 0.6.11;
import "./Context.sol";
import "./IERC20.sol";
import "./SafeMath.sol";
import "./Address.sol";
contract ERC20 is Context, IERC20 {
using SafeMath for uint256;
mapping (address => uint256) private _balances;
mapping (address => mapping (address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
uint8 private _decimals;
constructor (string memory name, string memory symbol) public {
_name = name;
_symbol = symbol;
_decimals = 18;
}
function name() public view returns (string memory) {
return _name;
}
function symbol() public view returns (string memory) {
return _symbol;
}
function decimals() public view returns (uint8) {
return _decimals;
}
function totalSupply() public view override returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view override returns (uint256) {
return _balances[account];
}
function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(_msgSender(), 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(_msgSender(), spender, amount);
return true;
}
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;
}
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][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(0), account, amount);
_totalSupply = _totalSupply.add(amount);
_balances[account] = _balances[account].add(amount);
emit Transfer(address(0), account, amount);
}
function burn(uint256 amount) public virtual {
_burn(_msgSender(), amount);
}
function burnFrom(address account, uint256 amount) public virtual {
uint256 decreasedAllowance = allowance(account, _msgSender()).sub(amount, "ERC20: burn amount exceeds allowance");
_approve(account, _msgSender(), decreasedAllowance);
_burn(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 _burnFrom(address account, uint256 amount) internal virtual {
_burn(account, amount);
_approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount, "ERC20: burn amount exceeds allowance"));
}
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
}
文件 10 的 72:ERC20Custom.sol
pragma solidity 0.6.11;
import "./Context.sol";
import "./IERC20.sol";
import "./SafeMath.sol";
import "./Address.sol";
contract ERC20Custom is Context, IERC20 {
using SafeMath for uint256;
mapping (address => uint256) internal _balances;
mapping (address => mapping (address => uint256)) internal _allowances;
uint256 private _totalSupply;
function totalSupply() public view override returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view override returns (uint256) {
return _balances[account];
}
function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(_msgSender(), 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(_msgSender(), spender, amount);
return true;
}
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;
}
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][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(0), account, amount);
_totalSupply = _totalSupply.add(amount);
_balances[account] = _balances[account].add(amount);
emit Transfer(address(0), account, amount);
}
function burn(uint256 amount) public virtual {
_burn(_msgSender(), amount);
}
function burnFrom(address account, uint256 amount) public virtual {
uint256 decreasedAllowance = allowance(account, _msgSender()).sub(amount, "ERC20: burn amount exceeds allowance");
_approve(account, _msgSender(), decreasedAllowance);
_burn(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 _burnFrom(address account, uint256 amount) internal virtual {
_burn(account, amount);
_approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount, "ERC20: burn amount exceeds allowance"));
}
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
}
文件 11 的 72:EnumerableSet.sol
pragma solidity ^0.6.0;
library EnumerableSet {
struct Set {
bytes32[] _values;
mapping (bytes32 => uint256) _indexes;
}
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
function _remove(Set storage set, bytes32 value) private returns (bool) {
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
bytes32 lastvalue = set._values[lastIndex];
set._values[toDeleteIndex] = lastvalue;
set._indexes[lastvalue] = toDeleteIndex + 1;
set._values.pop();
delete set._indexes[value];
return true;
} else {
return false;
}
}
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
function _length(Set storage set) private view returns (uint256) {
return set._values.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];
}
struct AddressSet {
Set _inner;
}
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(value)));
}
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(value)));
}
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(value)));
}
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint256(_at(set._inner, index)));
}
struct UintSet {
Set _inner;
}
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
}
文件 12 的 72:FXS.sol
pragma solidity 0.6.11;
pragma experimental ABIEncoderV2;
import "./Context.sol";
import "./ERC20Custom.sol";
import "./IERC20.sol";
import "./Frax.sol";
import "./SafeMath.sol";
import "./AccessControl.sol";
contract FRAXShares is ERC20Custom, AccessControl {
using SafeMath for uint256;
string public symbol;
string public name;
uint8 public constant decimals = 18;
address public FRAXStablecoinAdd;
uint256 public constant genesis_supply = 100000000e18;
uint256 public FXS_DAO_min;
address public owner_address;
address public oracle_address;
address public timelock_address;
FRAXStablecoin private FRAX;
bool public trackingVotes = true;
struct Checkpoint {
uint32 fromBlock;
uint96 votes;
}
mapping (address => mapping (uint32 => Checkpoint)) public checkpoints;
mapping (address => uint32) public numCheckpoints;
modifier onlyPools() {
require(FRAX.frax_pools(msg.sender) == true, "Only frax pools can mint new FRAX");
_;
}
modifier onlyByOwnerOrGovernance() {
require(msg.sender == owner_address || msg.sender == timelock_address, "You are not an owner or the governance timelock");
_;
}
constructor(
string memory _name,
string memory _symbol,
address _oracle_address,
address _owner_address,
address _timelock_address
) public {
name = _name;
symbol = _symbol;
owner_address = _owner_address;
oracle_address = _oracle_address;
timelock_address = _timelock_address;
_setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
_mint(owner_address, genesis_supply);
_writeCheckpoint(owner_address, 0, 0, uint96(genesis_supply));
}
function setOracle(address new_oracle) external onlyByOwnerOrGovernance {
oracle_address = new_oracle;
}
function setTimelock(address new_timelock) external onlyByOwnerOrGovernance {
timelock_address = new_timelock;
}
function setFRAXAddress(address frax_contract_address) external onlyByOwnerOrGovernance {
FRAX = FRAXStablecoin(frax_contract_address);
}
function setFXSMinDAO(uint256 min_FXS) external onlyByOwnerOrGovernance {
FXS_DAO_min = min_FXS;
}
function setOwner(address _owner_address) external onlyByOwnerOrGovernance {
owner_address = _owner_address;
}
function mint(address to, uint256 amount) public onlyPools {
_mint(to, amount);
}
function pool_mint(address m_address, uint256 m_amount) external onlyPools {
if(trackingVotes){
uint32 srcRepNum = numCheckpoints[address(this)];
uint96 srcRepOld = srcRepNum > 0 ? checkpoints[address(this)][srcRepNum - 1].votes : 0;
uint96 srcRepNew = add96(srcRepOld, uint96(m_amount), "pool_mint new votes overflows");
_writeCheckpoint(address(this), srcRepNum, srcRepOld, srcRepNew);
trackVotes(address(this), m_address, uint96(m_amount));
}
super._mint(m_address, m_amount);
emit FXSMinted(address(this), m_address, m_amount);
}
function pool_burn_from(address b_address, uint256 b_amount) external onlyPools {
if(trackingVotes){
trackVotes(b_address, address(this), uint96(b_amount));
uint32 srcRepNum = numCheckpoints[address(this)];
uint96 srcRepOld = srcRepNum > 0 ? checkpoints[address(this)][srcRepNum - 1].votes : 0;
uint96 srcRepNew = sub96(srcRepOld, uint96(b_amount), "pool_burn_from new votes underflows");
_writeCheckpoint(address(this), srcRepNum, srcRepOld, srcRepNew);
}
super._burnFrom(b_address, b_amount);
emit FXSBurned(b_address, address(this), b_amount);
}
function toggleVotes() external onlyByOwnerOrGovernance {
trackingVotes = !trackingVotes;
}
function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
if(trackingVotes){
trackVotes(_msgSender(), recipient, uint96(amount));
}
_transfer(_msgSender(), recipient, amount);
return true;
}
function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
if(trackingVotes){
trackVotes(sender, recipient, uint96(amount));
}
_transfer(sender, recipient, amount);
_approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
return true;
}
function getCurrentVotes(address account) external view returns (uint96) {
uint32 nCheckpoints = numCheckpoints[account];
return nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : 0;
}
function getPriorVotes(address account, uint blockNumber) public view returns (uint96) {
require(blockNumber < block.number, "FXS::getPriorVotes: not yet determined");
uint32 nCheckpoints = numCheckpoints[account];
if (nCheckpoints == 0) {
return 0;
}
if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) {
return checkpoints[account][nCheckpoints - 1].votes;
}
if (checkpoints[account][0].fromBlock > blockNumber) {
return 0;
}
uint32 lower = 0;
uint32 upper = nCheckpoints - 1;
while (upper > lower) {
uint32 center = upper - (upper - lower) / 2;
Checkpoint memory cp = checkpoints[account][center];
if (cp.fromBlock == blockNumber) {
return cp.votes;
} else if (cp.fromBlock < blockNumber) {
lower = center;
} else {
upper = center - 1;
}
}
return checkpoints[account][lower].votes;
}
function trackVotes(address srcRep, address dstRep, uint96 amount) internal {
if (srcRep != dstRep && amount > 0) {
if (srcRep != address(0)) {
uint32 srcRepNum = numCheckpoints[srcRep];
uint96 srcRepOld = srcRepNum > 0 ? checkpoints[srcRep][srcRepNum - 1].votes : 0;
uint96 srcRepNew = sub96(srcRepOld, amount, "FXS::_moveVotes: vote amount underflows");
_writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew);
}
if (dstRep != address(0)) {
uint32 dstRepNum = numCheckpoints[dstRep];
uint96 dstRepOld = dstRepNum > 0 ? checkpoints[dstRep][dstRepNum - 1].votes : 0;
uint96 dstRepNew = add96(dstRepOld, amount, "FXS::_moveVotes: vote amount overflows");
_writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew);
}
}
}
function _writeCheckpoint(address voter, uint32 nCheckpoints, uint96 oldVotes, uint96 newVotes) internal {
uint32 blockNumber = safe32(block.number, "FXS::_writeCheckpoint: block number exceeds 32 bits");
if (nCheckpoints > 0 && checkpoints[voter][nCheckpoints - 1].fromBlock == blockNumber) {
checkpoints[voter][nCheckpoints - 1].votes = newVotes;
} else {
checkpoints[voter][nCheckpoints] = Checkpoint(blockNumber, newVotes);
numCheckpoints[voter] = nCheckpoints + 1;
}
emit VoterVotesChanged(voter, oldVotes, newVotes);
}
function safe32(uint n, string memory errorMessage) internal pure returns (uint32) {
require(n < 2**32, errorMessage);
return uint32(n);
}
function safe96(uint n, string memory errorMessage) internal pure returns (uint96) {
require(n < 2**96, errorMessage);
return uint96(n);
}
function add96(uint96 a, uint96 b, string memory errorMessage) internal pure returns (uint96) {
uint96 c = a + b;
require(c >= a, errorMessage);
return c;
}
function sub96(uint96 a, uint96 b, string memory errorMessage) internal pure returns (uint96) {
require(b <= a, errorMessage);
return a - b;
}
function getChainId() internal pure returns (uint) {
uint256 chainId;
assembly { chainId := chainid() }
return chainId;
}
event VoterVotesChanged(address indexed voter, uint previousBalance, uint newBalance);
event FXSBurned(address indexed from, address indexed to, uint256 amount);
event FXSMinted(address indexed from, address indexed to, uint256 amount);
}
文件 13 的 72:FakeCollateral.sol
pragma solidity 0.6.11;
import "./Context.sol";
import "./IERC20.sol";
import "./SafeMath.sol";
import "./Address.sol";
contract FakeCollateral is Context, IERC20 {
using SafeMath for uint256;
string public symbol;
uint8 public decimals;
address public creator_address;
uint256 public genesis_supply;
uint256 private _totalSupply;
mapping (address => uint256) private _balances;
mapping (address => mapping (address => uint256)) private _allowances;
mapping (address => bool) used;
constructor(
address _creator_address,
uint256 _genesis_supply,
string memory _symbol,
uint8 _decimals
) public {
genesis_supply = _genesis_supply;
creator_address = _creator_address;
symbol = _symbol;
decimals = _decimals;
_mint(creator_address, genesis_supply);
}
function faucet() public {
if (used[msg.sender] == false) {
used[msg.sender] = true;
_mint(msg.sender, 1000 * (10 ** uint256(decimals)));
}
}
function totalSupply() public view override returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view override returns (uint256) {
return _balances[account];
}
function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(_msgSender(), 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(_msgSender(), spender, amount);
return true;
}
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;
}
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][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(0), account, amount);
_totalSupply = _totalSupply.add(amount);
_balances[account] = _balances[account].add(amount);
emit Transfer(address(0), account, amount);
}
function burn(uint256 amount) public virtual {
_burn(_msgSender(), amount);
}
function burnFrom(address account, uint256 amount) public virtual {
uint256 decreasedAllowance = allowance(account, _msgSender()).sub(amount, "ERC20: burn amount exceeds allowance");
_approve(account, _msgSender(), decreasedAllowance);
_burn(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 _burnFrom(address account, uint256 amount) internal virtual {
_burn(account, amount);
_approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount, "ERC20: burn amount exceeds allowance"));
}
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
}
文件 14 的 72:FakeCollateral_USDC.sol
pragma solidity 0.6.11;
import "./FakeCollateral.sol";
contract FakeCollateral_USDC is FakeCollateral {
constructor(
address _creator_address,
uint256 _genesis_supply,
string memory _symbol,
uint8 _decimals
)
FakeCollateral(_creator_address, _genesis_supply, _symbol, _decimals)
public {}
}
文件 15 的 72:FakeCollateral_USDT.sol
pragma solidity 0.6.11;
import "./FakeCollateral.sol";
contract FakeCollateral_USDT is FakeCollateral {
constructor(
address _creator_address,
uint256 _genesis_supply,
string memory _symbol,
uint8 _decimals
)
FakeCollateral(_creator_address, _genesis_supply, _symbol, _decimals)
public {}
}
文件 16 的 72:FakeCollateral_WETH.sol
pragma solidity 0.6.11;
import "./FakeCollateral.sol";
contract FakeCollateral_WETH is FakeCollateral {
constructor(
address _creator_address,
uint256 _genesis_supply,
string memory _symbol,
uint8 _decimals
)
FakeCollateral(_creator_address, _genesis_supply, _symbol, _decimals)
public {}
}
文件 17 的 72:FixedPoint.sol
pragma solidity 0.6.11;
import './Babylonian.sol';
library FixedPoint {
struct uq112x112 {
uint224 _x;
}
struct uq144x112 {
uint _x;
}
uint8 private constant RESOLUTION = 112;
uint private constant Q112 = uint(1) << RESOLUTION;
uint private constant Q224 = Q112 << RESOLUTION;
function encode(uint112 x) internal pure returns (uq112x112 memory) {
return uq112x112(uint224(x) << RESOLUTION);
}
function encode144(uint144 x) internal pure returns (uq144x112 memory) {
return uq144x112(uint256(x) << RESOLUTION);
}
function div(uq112x112 memory self, uint112 x) internal pure returns (uq112x112 memory) {
require(x != 0, 'FixedPoint: DIV_BY_ZERO');
return uq112x112(self._x / uint224(x));
}
function mul(uq112x112 memory self, uint y) internal pure returns (uq144x112 memory) {
uint z;
require(y == 0 || (z = uint(self._x) * y) / y == uint(self._x), "FixedPoint: MULTIPLICATION_OVERFLOW");
return uq144x112(z);
}
function fraction(uint112 numerator, uint112 denominator) internal pure returns (uq112x112 memory) {
require(denominator > 0, "FixedPoint: DIV_BY_ZERO");
return uq112x112((uint224(numerator) << RESOLUTION) / denominator);
}
function decode(uq112x112 memory self) internal pure returns (uint112) {
return uint112(self._x >> RESOLUTION);
}
function decode144(uq144x112 memory self) internal pure returns (uint144) {
return uint144(self._x >> RESOLUTION);
}
function reciprocal(uq112x112 memory self) internal pure returns (uq112x112 memory) {
require(self._x != 0, 'FixedPoint: ZERO_RECIPROCAL');
return uq112x112(uint224(Q224 / self._x));
}
function sqrt(uq112x112 memory self) internal pure returns (uq112x112 memory) {
return uq112x112(uint224(Babylonian.sqrt(uint256(self._x)) << 56));
}
}
文件 18 的 72:Frax.sol
pragma solidity 0.6.11;
pragma experimental ABIEncoderV2;
import "./Context.sol";
import "./IERC20.sol";
import "./ERC20Custom.sol";
import "./ERC20.sol";
import "./SafeMath.sol";
import "./FXS.sol";
import "./FraxPool.sol";
import "./UniswapPairOracle.sol";
import "./ChainlinkETHUSDPriceConsumer.sol";
import "./AccessControl.sol";
contract FRAXStablecoin is ERC20Custom, AccessControl {
using SafeMath for uint256;
enum PriceChoice { FRAX, FXS }
ChainlinkETHUSDPriceConsumer private eth_usd_pricer;
uint8 private eth_usd_pricer_decimals;
UniswapPairOracle private fraxEthOracle;
UniswapPairOracle private fxsEthOracle;
string public symbol;
string public name;
uint8 public constant decimals = 18;
address public owner_address;
address public creator_address;
address public timelock_address;
address public controller_address;
address public fxs_address;
address public frax_eth_oracle_address;
address public fxs_eth_oracle_address;
address public weth_address;
address public eth_usd_consumer_address;
uint256 public constant genesis_supply = 2000000e18;
address[] public frax_pools_array;
mapping(address => bool) public frax_pools;
uint256 private constant PRICE_PRECISION = 1e6;
uint256 public global_collateral_ratio;
uint256 public redemption_fee;
uint256 public minting_fee;
uint256 public frax_step;
uint256 public refresh_cooldown;
uint256 public price_target;
uint256 public price_band;
address public DEFAULT_ADMIN_ADDRESS;
bytes32 public constant COLLATERAL_RATIO_PAUSER = keccak256("COLLATERAL_RATIO_PAUSER");
bool public collateral_ratio_paused = false;
modifier onlyCollateralRatioPauser() {
require(hasRole(COLLATERAL_RATIO_PAUSER, msg.sender));
_;
}
modifier onlyPools() {
require(frax_pools[msg.sender] == true, "Only frax pools can call this function");
_;
}
modifier onlyByOwnerOrGovernance() {
require(msg.sender == owner_address || msg.sender == timelock_address || msg.sender == controller_address, "You are not the owner, controller, or the governance timelock");
_;
}
modifier onlyByOwnerGovernanceOrPool() {
require(
msg.sender == owner_address
|| msg.sender == timelock_address
|| frax_pools[msg.sender] == true,
"You are not the owner, the governance timelock, or a pool");
_;
}
constructor(
string memory _name,
string memory _symbol,
address _creator_address,
address _timelock_address
) public {
name = _name;
symbol = _symbol;
creator_address = _creator_address;
timelock_address = _timelock_address;
_setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
DEFAULT_ADMIN_ADDRESS = _msgSender();
owner_address = _creator_address;
_mint(creator_address, genesis_supply);
grantRole(COLLATERAL_RATIO_PAUSER, creator_address);
grantRole(COLLATERAL_RATIO_PAUSER, timelock_address);
frax_step = 2500;
global_collateral_ratio = 1000000;
refresh_cooldown = 3600;
price_target = 1000000;
price_band = 5000;
}
function oracle_price(PriceChoice choice) internal view returns (uint256) {
uint256 eth_usd_price = uint256(eth_usd_pricer.getLatestPrice()).mul(PRICE_PRECISION).div(uint256(10) ** eth_usd_pricer_decimals);
uint256 price_vs_eth;
if (choice == PriceChoice.FRAX) {
price_vs_eth = uint256(fraxEthOracle.consult(weth_address, PRICE_PRECISION));
}
else if (choice == PriceChoice.FXS) {
price_vs_eth = uint256(fxsEthOracle.consult(weth_address, PRICE_PRECISION));
}
else revert("INVALID PRICE CHOICE. Needs to be either 0 (FRAX) or 1 (FXS)");
return eth_usd_price.mul(PRICE_PRECISION).div(price_vs_eth);
}
function frax_price() public view returns (uint256) {
return oracle_price(PriceChoice.FRAX);
}
function fxs_price() public view returns (uint256) {
return oracle_price(PriceChoice.FXS);
}
function eth_usd_price() public view returns (uint256) {
return uint256(eth_usd_pricer.getLatestPrice()).mul(PRICE_PRECISION).div(uint256(10) ** eth_usd_pricer_decimals);
}
function frax_info() public view returns (uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256) {
return (
oracle_price(PriceChoice.FRAX),
oracle_price(PriceChoice.FXS),
totalSupply(),
global_collateral_ratio,
globalCollateralValue(),
minting_fee,
redemption_fee,
uint256(eth_usd_pricer.getLatestPrice()).mul(PRICE_PRECISION).div(uint256(10) ** eth_usd_pricer_decimals)
);
}
function globalCollateralValue() public view returns (uint256) {
uint256 total_collateral_value_d18 = 0;
for (uint i = 0; i < frax_pools_array.length; i++){
if (frax_pools_array[i] != address(0)){
total_collateral_value_d18 = total_collateral_value_d18.add(FraxPool(frax_pools_array[i]).collatDollarBalance());
}
}
return total_collateral_value_d18;
}
uint256 public last_call_time;
function refreshCollateralRatio() public {
require(collateral_ratio_paused == false, "Collateral Ratio has been paused");
uint256 frax_price_cur = frax_price();
require(block.timestamp - last_call_time >= refresh_cooldown, "Must wait for the refresh cooldown since last refresh");
if (frax_price_cur > price_target.add(price_band)) {
if(global_collateral_ratio <= frax_step){
global_collateral_ratio = 0;
} else {
global_collateral_ratio = global_collateral_ratio.sub(frax_step);
}
} else if (frax_price_cur < price_target.sub(price_band)) {
if(global_collateral_ratio.add(frax_step) >= 1000000){
global_collateral_ratio = 1000000;
} else {
global_collateral_ratio = global_collateral_ratio.add(frax_step);
}
}
last_call_time = block.timestamp;
}
function pool_burn_from(address b_address, uint256 b_amount) public onlyPools {
super._burnFrom(b_address, b_amount);
emit FRAXBurned(b_address, msg.sender, b_amount);
}
function pool_mint(address m_address, uint256 m_amount) public onlyPools {
super._mint(m_address, m_amount);
emit FRAXMinted(msg.sender, m_address, m_amount);
}
function addPool(address pool_address) public onlyByOwnerOrGovernance {
require(frax_pools[pool_address] == false, "address already exists");
frax_pools[pool_address] = true;
frax_pools_array.push(pool_address);
}
function removePool(address pool_address) public onlyByOwnerOrGovernance {
require(frax_pools[pool_address] == true, "address doesn't exist already");
delete frax_pools[pool_address];
for (uint i = 0; i < frax_pools_array.length; i++){
if (frax_pools_array[i] == pool_address) {
frax_pools_array[i] = address(0);
break;
}
}
}
function setOwner(address _owner_address) external onlyByOwnerOrGovernance {
owner_address = _owner_address;
}
function setRedemptionFee(uint256 red_fee) public onlyByOwnerOrGovernance {
redemption_fee = red_fee;
}
function setMintingFee(uint256 min_fee) public onlyByOwnerOrGovernance {
minting_fee = min_fee;
}
function setFraxStep(uint256 _new_step) public onlyByOwnerOrGovernance {
frax_step = _new_step;
}
function setPriceTarget (uint256 _new_price_target) public onlyByOwnerOrGovernance {
price_target = _new_price_target;
}
function setRefreshCooldown(uint256 _new_cooldown) public onlyByOwnerOrGovernance {
refresh_cooldown = _new_cooldown;
}
function setFXSAddress(address _fxs_address) public onlyByOwnerOrGovernance {
fxs_address = _fxs_address;
}
function setETHUSDOracle(address _eth_usd_consumer_address) public onlyByOwnerOrGovernance {
eth_usd_consumer_address = _eth_usd_consumer_address;
eth_usd_pricer = ChainlinkETHUSDPriceConsumer(eth_usd_consumer_address);
eth_usd_pricer_decimals = eth_usd_pricer.getDecimals();
}
function setTimelock(address new_timelock) external onlyByOwnerOrGovernance {
timelock_address = new_timelock;
}
function setController(address _controller_address) external onlyByOwnerOrGovernance {
controller_address = _controller_address;
}
function setPriceBand(uint256 _price_band) external onlyByOwnerOrGovernance {
price_band = _price_band;
}
function setFRAXEthOracle(address _frax_oracle_addr, address _weth_address) public onlyByOwnerOrGovernance {
frax_eth_oracle_address = _frax_oracle_addr;
fraxEthOracle = UniswapPairOracle(_frax_oracle_addr);
weth_address = _weth_address;
}
function setFXSEthOracle(address _fxs_oracle_addr, address _weth_address) public onlyByOwnerOrGovernance {
fxs_eth_oracle_address = _fxs_oracle_addr;
fxsEthOracle = UniswapPairOracle(_fxs_oracle_addr);
weth_address = _weth_address;
}
function toggleCollateralRatio() public onlyCollateralRatioPauser {
collateral_ratio_paused = !collateral_ratio_paused;
}
event FRAXBurned(address indexed from, address indexed to, uint256 amount);
event FRAXMinted(address indexed from, address indexed to, uint256 amount);
}
文件 19 的 72:FraxPool.sol
pragma solidity 0.6.11;
pragma experimental ABIEncoderV2;
import "./SafeMath.sol";
import "./FXS.sol";
import "./Frax.sol";
import "./ERC20.sol";
import "./UniswapPairOracle.sol";
import "./AccessControl.sol";
import "./FraxPoolLibrary.sol";
contract FraxPool is AccessControl {
using SafeMath for uint256;
ERC20 private collateral_token;
address private collateral_address;
address private owner_address;
address private frax_contract_address;
address private fxs_contract_address;
address private timelock_address;
FRAXShares private FXS;
FRAXStablecoin private FRAX;
UniswapPairOracle private collatEthOracle;
address public collat_eth_oracle_address;
address private weth_address;
uint256 public minting_fee;
uint256 public redemption_fee;
uint256 public buyback_fee;
uint256 public recollat_fee;
mapping (address => uint256) public redeemFXSBalances;
mapping (address => uint256) public redeemCollateralBalances;
uint256 public unclaimedPoolCollateral;
uint256 public unclaimedPoolFXS;
mapping (address => uint256) public lastRedeemed;
uint256 private constant PRICE_PRECISION = 1e6;
uint256 private constant COLLATERAL_RATIO_PRECISION = 1e6;
uint256 private constant COLLATERAL_RATIO_MAX = 1e6;
uint256 private immutable missing_decimals;
uint256 public pool_ceiling = 0;
uint256 public pausedPrice = 0;
uint256 public bonus_rate = 7500;
uint256 public redemption_delay = 1;
bytes32 private constant MINT_PAUSER = keccak256("MINT_PAUSER");
bytes32 private constant REDEEM_PAUSER = keccak256("REDEEM_PAUSER");
bytes32 private constant BUYBACK_PAUSER = keccak256("BUYBACK_PAUSER");
bytes32 private constant RECOLLATERALIZE_PAUSER = keccak256("RECOLLATERALIZE_PAUSER");
bytes32 private constant COLLATERAL_PRICE_PAUSER = keccak256("COLLATERAL_PRICE_PAUSER");
bool public mintPaused = false;
bool public redeemPaused = false;
bool public recollateralizePaused = false;
bool public buyBackPaused = false;
bool public collateralPricePaused = false;
modifier onlyByOwnerOrGovernance() {
require(msg.sender == timelock_address || msg.sender == owner_address, "You are not the owner or the governance timelock");
_;
}
modifier notRedeemPaused() {
require(redeemPaused == false, "Redeeming is paused");
_;
}
modifier notMintPaused() {
require(mintPaused == false, "Minting is paused");
_;
}
constructor(
address _frax_contract_address,
address _fxs_contract_address,
address _collateral_address,
address _creator_address,
address _timelock_address,
uint256 _pool_ceiling
) public {
FRAX = FRAXStablecoin(_frax_contract_address);
FXS = FRAXShares(_fxs_contract_address);
frax_contract_address = _frax_contract_address;
fxs_contract_address = _fxs_contract_address;
collateral_address = _collateral_address;
timelock_address = _timelock_address;
owner_address = _creator_address;
collateral_token = ERC20(_collateral_address);
pool_ceiling = _pool_ceiling;
missing_decimals = uint(18).sub(collateral_token.decimals());
_setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
grantRole(MINT_PAUSER, timelock_address);
grantRole(REDEEM_PAUSER, timelock_address);
grantRole(RECOLLATERALIZE_PAUSER, timelock_address);
grantRole(BUYBACK_PAUSER, timelock_address);
grantRole(COLLATERAL_PRICE_PAUSER, timelock_address);
}
function collatDollarBalance() public view returns (uint256) {
if(collateralPricePaused == true){
return (collateral_token.balanceOf(address(this)).sub(unclaimedPoolCollateral)).mul(10 ** missing_decimals).mul(pausedPrice).div(PRICE_PRECISION);
} else {
uint256 eth_usd_price = FRAX.eth_usd_price();
uint256 eth_collat_price = collatEthOracle.consult(weth_address, (PRICE_PRECISION * (10 ** missing_decimals)));
uint256 collat_usd_price = eth_usd_price.mul(PRICE_PRECISION).div(eth_collat_price);
return (collateral_token.balanceOf(address(this)).sub(unclaimedPoolCollateral)).mul(10 ** missing_decimals).mul(collat_usd_price).div(PRICE_PRECISION);
}
}
function availableExcessCollatDV() public view returns (uint256) {
uint256 total_supply = FRAX.totalSupply();
uint256 global_collateral_ratio = FRAX.global_collateral_ratio();
uint256 global_collat_value = FRAX.globalCollateralValue();
if (global_collateral_ratio > COLLATERAL_RATIO_PRECISION) global_collateral_ratio = COLLATERAL_RATIO_PRECISION;
uint256 required_collat_dollar_value_d18 = (total_supply.mul(global_collateral_ratio)).div(COLLATERAL_RATIO_PRECISION);
if (global_collat_value > required_collat_dollar_value_d18) return global_collat_value.sub(required_collat_dollar_value_d18);
else return 0;
}
function getCollateralPrice() public view returns (uint256) {
if(collateralPricePaused == true){
return pausedPrice;
} else {
uint256 eth_usd_price = FRAX.eth_usd_price();
return eth_usd_price.mul(PRICE_PRECISION).div(collatEthOracle.consult(weth_address, PRICE_PRECISION * (10 ** missing_decimals)));
}
}
function setCollatETHOracle(address _collateral_weth_oracle_address, address _weth_address) external onlyByOwnerOrGovernance {
collat_eth_oracle_address = _collateral_weth_oracle_address;
collatEthOracle = UniswapPairOracle(_collateral_weth_oracle_address);
weth_address = _weth_address;
}
function mint1t1FRAX(uint256 collateral_amount, uint256 FRAX_out_min) external notMintPaused {
uint256 collateral_amount_d18 = collateral_amount * (10 ** missing_decimals);
require(FRAX.global_collateral_ratio() >= COLLATERAL_RATIO_MAX, "Collateral ratio must be >= 1");
require((collateral_token.balanceOf(address(this))).sub(unclaimedPoolCollateral).add(collateral_amount) <= pool_ceiling, "[Pool's Closed]: Ceiling reached");
(uint256 frax_amount_d18) = FraxPoolLibrary.calcMint1t1FRAX(
getCollateralPrice(),
collateral_amount_d18
);
frax_amount_d18 = (frax_amount_d18.mul(uint(1e6).sub(minting_fee))).div(1e6);
require(FRAX_out_min <= frax_amount_d18, "Slippage limit reached");
collateral_token.transferFrom(msg.sender, address(this), collateral_amount);
FRAX.pool_mint(msg.sender, frax_amount_d18);
}
function mintAlgorithmicFRAX(uint256 fxs_amount_d18, uint256 FRAX_out_min) external notMintPaused {
uint256 fxs_price = FRAX.fxs_price();
require(FRAX.global_collateral_ratio() == 0, "Collateral ratio must be 0");
(uint256 frax_amount_d18) = FraxPoolLibrary.calcMintAlgorithmicFRAX(
fxs_price,
fxs_amount_d18
);
frax_amount_d18 = (frax_amount_d18.mul(uint(1e6).sub(minting_fee))).div(1e6);
require(FRAX_out_min <= frax_amount_d18, "Slippage limit reached");
FXS.pool_burn_from(msg.sender, fxs_amount_d18);
FRAX.pool_mint(msg.sender, frax_amount_d18);
}
function mintFractionalFRAX(uint256 collateral_amount, uint256 fxs_amount, uint256 FRAX_out_min) external notMintPaused {
uint256 fxs_price = FRAX.fxs_price();
uint256 global_collateral_ratio = FRAX.global_collateral_ratio();
require(global_collateral_ratio < COLLATERAL_RATIO_MAX && global_collateral_ratio > 0, "Collateral ratio needs to be between .000001 and .999999");
require(collateral_token.balanceOf(address(this)).sub(unclaimedPoolCollateral).add(collateral_amount) <= pool_ceiling, "Pool ceiling reached, no more FRAX can be minted with this collateral");
uint256 collateral_amount_d18 = collateral_amount * (10 ** missing_decimals);
FraxPoolLibrary.MintFF_Params memory input_params = FraxPoolLibrary.MintFF_Params(
fxs_price,
getCollateralPrice(),
fxs_amount,
collateral_amount_d18,
global_collateral_ratio
);
(uint256 mint_amount, uint256 fxs_needed) = FraxPoolLibrary.calcMintFractionalFRAX(input_params);
mint_amount = (mint_amount.mul(uint(1e6).sub(minting_fee))).div(1e6);
require(FRAX_out_min <= mint_amount, "Slippage limit reached");
require(fxs_needed <= fxs_amount, "Not enough FXS inputted");
FXS.pool_burn_from(msg.sender, fxs_needed);
collateral_token.transferFrom(msg.sender, address(this), collateral_amount);
FRAX.pool_mint(msg.sender, mint_amount);
}
function redeem1t1FRAX(uint256 FRAX_amount, uint256 COLLATERAL_out_min) external notRedeemPaused {
require(FRAX.global_collateral_ratio() == COLLATERAL_RATIO_MAX, "Collateral ratio must be == 1");
uint256 FRAX_amount_precision = FRAX_amount.div(10 ** missing_decimals);
(uint256 collateral_needed) = FraxPoolLibrary.calcRedeem1t1FRAX(
getCollateralPrice(),
FRAX_amount_precision
);
collateral_needed = (collateral_needed.mul(uint(1e6).sub(redemption_fee))).div(1e6);
require(collateral_needed <= collateral_token.balanceOf(address(this)).sub(unclaimedPoolCollateral), "Not enough collateral in pool");
require(COLLATERAL_out_min <= collateral_needed, "Slippage limit reached");
redeemCollateralBalances[msg.sender] = redeemCollateralBalances[msg.sender].add(collateral_needed);
unclaimedPoolCollateral = unclaimedPoolCollateral.add(collateral_needed);
lastRedeemed[msg.sender] = block.number;
FRAX.pool_burn_from(msg.sender, FRAX_amount);
}
function redeemFractionalFRAX(uint256 FRAX_amount, uint256 FXS_out_min, uint256 COLLATERAL_out_min) external notRedeemPaused {
uint256 fxs_price = FRAX.fxs_price();
uint256 global_collateral_ratio = FRAX.global_collateral_ratio();
require(global_collateral_ratio < COLLATERAL_RATIO_MAX && global_collateral_ratio > 0, "Collateral ratio needs to be between .000001 and .999999");
uint256 col_price_usd = getCollateralPrice();
uint256 FRAX_amount_post_fee = (FRAX_amount.mul(uint(1e6).sub(redemption_fee))).div(PRICE_PRECISION);
uint256 fxs_dollar_value_d18 = FRAX_amount_post_fee.sub(FRAX_amount_post_fee.mul(global_collateral_ratio).div(PRICE_PRECISION));
uint256 fxs_amount = fxs_dollar_value_d18.mul(PRICE_PRECISION).div(fxs_price);
uint256 FRAX_amount_precision = FRAX_amount_post_fee.div(10 ** missing_decimals);
uint256 collateral_dollar_value = FRAX_amount_precision.mul(global_collateral_ratio).div(PRICE_PRECISION);
uint256 collateral_amount = collateral_dollar_value.mul(PRICE_PRECISION).div(col_price_usd);
require(collateral_amount <= collateral_token.balanceOf(address(this)).sub(unclaimedPoolCollateral), "Not enough collateral in pool");
require(COLLATERAL_out_min <= collateral_amount, "Slippage limit reached [collateral]");
require(FXS_out_min <= fxs_amount, "Slippage limit reached [FXS]");
redeemCollateralBalances[msg.sender] = redeemCollateralBalances[msg.sender].add(collateral_amount);
unclaimedPoolCollateral = unclaimedPoolCollateral.add(collateral_amount);
redeemFXSBalances[msg.sender] = redeemFXSBalances[msg.sender].add(fxs_amount);
unclaimedPoolFXS = unclaimedPoolFXS.add(fxs_amount);
lastRedeemed[msg.sender] = block.number;
FRAX.pool_burn_from(msg.sender, FRAX_amount);
FXS.pool_mint(address(this), fxs_amount);
}
function redeemAlgorithmicFRAX(uint256 FRAX_amount, uint256 FXS_out_min) external notRedeemPaused {
uint256 fxs_price = FRAX.fxs_price();
uint256 global_collateral_ratio = FRAX.global_collateral_ratio();
require(global_collateral_ratio == 0, "Collateral ratio must be 0");
uint256 fxs_dollar_value_d18 = FRAX_amount;
fxs_dollar_value_d18 = (fxs_dollar_value_d18.mul(uint(1e6).sub(redemption_fee))).div(PRICE_PRECISION);
uint256 fxs_amount = fxs_dollar_value_d18.mul(PRICE_PRECISION).div(fxs_price);
redeemFXSBalances[msg.sender] = redeemFXSBalances[msg.sender].add(fxs_amount);
unclaimedPoolFXS = unclaimedPoolFXS.add(fxs_amount);
lastRedeemed[msg.sender] = block.number;
require(FXS_out_min <= fxs_amount, "Slippage limit reached");
FRAX.pool_burn_from(msg.sender, FRAX_amount);
FXS.pool_mint(address(this), fxs_amount);
}
function collectRedemption() external {
require((lastRedeemed[msg.sender].add(redemption_delay)) <= block.number, "Must wait for redemption_delay blocks before collecting redemption");
bool sendFXS = false;
bool sendCollateral = false;
uint FXSAmount;
uint CollateralAmount;
if(redeemFXSBalances[msg.sender] > 0){
FXSAmount = redeemFXSBalances[msg.sender];
redeemFXSBalances[msg.sender] = 0;
unclaimedPoolFXS = unclaimedPoolFXS.sub(FXSAmount);
sendFXS = true;
}
if(redeemCollateralBalances[msg.sender] > 0){
CollateralAmount = redeemCollateralBalances[msg.sender];
redeemCollateralBalances[msg.sender] = 0;
unclaimedPoolCollateral = unclaimedPoolCollateral.sub(CollateralAmount);
sendCollateral = true;
}
if(sendFXS == true){
FXS.transfer(msg.sender, FXSAmount);
}
if(sendCollateral == true){
collateral_token.transfer(msg.sender, CollateralAmount);
}
}
function recollateralizeFRAX(uint256 collateral_amount, uint256 FXS_out_min) external {
require(recollateralizePaused == false, "Recollateralize is paused");
uint256 collateral_amount_d18 = collateral_amount * (10 ** missing_decimals);
uint256 fxs_price = FRAX.fxs_price();
uint256 frax_total_supply = FRAX.totalSupply();
uint256 global_collateral_ratio = FRAX.global_collateral_ratio();
uint256 global_collat_value = FRAX.globalCollateralValue();
(uint256 collateral_units, uint256 amount_to_recollat) = FraxPoolLibrary.calcRecollateralizeFRAXInner(
collateral_amount_d18,
getCollateralPrice(),
global_collat_value,
frax_total_supply,
global_collateral_ratio
);
uint256 collateral_units_precision = collateral_units.div(10 ** missing_decimals);
uint256 fxs_paid_back = amount_to_recollat.mul(uint(1e6).add(bonus_rate).sub(recollat_fee)).div(fxs_price);
require(FXS_out_min <= fxs_paid_back, "Slippage limit reached");
collateral_token.transferFrom(msg.sender, address(this), collateral_units_precision);
FXS.pool_mint(msg.sender, fxs_paid_back);
}
function buyBackFXS(uint256 FXS_amount, uint256 COLLATERAL_out_min) external {
require(buyBackPaused == false, "Buyback is paused");
uint256 fxs_price = FRAX.fxs_price();
FraxPoolLibrary.BuybackFXS_Params memory input_params = FraxPoolLibrary.BuybackFXS_Params(
availableExcessCollatDV(),
fxs_price,
getCollateralPrice(),
FXS_amount
);
(uint256 collateral_equivalent_d18) = (FraxPoolLibrary.calcBuyBackFXS(input_params)).mul(uint(1e6).sub(buyback_fee)).div(1e6);
uint256 collateral_precision = collateral_equivalent_d18.div(10 ** missing_decimals);
require(COLLATERAL_out_min <= collateral_precision, "Slippage limit reached");
FXS.pool_burn_from(msg.sender, FXS_amount);
collateral_token.transfer(msg.sender, collateral_precision);
}
function toggleMinting() external {
require(hasRole(MINT_PAUSER, msg.sender));
mintPaused = !mintPaused;
}
function toggleRedeeming() external {
require(hasRole(REDEEM_PAUSER, msg.sender));
redeemPaused = !redeemPaused;
}
function toggleRecollateralize() external {
require(hasRole(RECOLLATERALIZE_PAUSER, msg.sender));
recollateralizePaused = !recollateralizePaused;
}
function toggleBuyBack() external {
require(hasRole(BUYBACK_PAUSER, msg.sender));
buyBackPaused = !buyBackPaused;
}
function toggleCollateralPrice(uint256 _new_price) external {
require(hasRole(COLLATERAL_PRICE_PAUSER, msg.sender));
if(collateralPricePaused == false){
pausedPrice = _new_price;
} else {
pausedPrice = 0;
}
collateralPricePaused = !collateralPricePaused;
}
function setPoolParameters(uint256 new_ceiling, uint256 new_bonus_rate, uint256 new_redemption_delay, uint256 new_mint_fee, uint256 new_redeem_fee, uint256 new_buyback_fee, uint256 new_recollat_fee) external onlyByOwnerOrGovernance {
pool_ceiling = new_ceiling;
bonus_rate = new_bonus_rate;
redemption_delay = new_redemption_delay;
minting_fee = new_mint_fee;
redemption_fee = new_redeem_fee;
buyback_fee = new_buyback_fee;
recollat_fee = new_recollat_fee;
}
function setTimelock(address new_timelock) external onlyByOwnerOrGovernance {
timelock_address = new_timelock;
}
function setOwner(address _owner_address) external onlyByOwnerOrGovernance {
owner_address = _owner_address;
}
}
文件 20 的 72:FraxPoolLibrary.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "./SafeMath.sol";
library FraxPoolLibrary {
using SafeMath for uint256;
uint256 private constant PRICE_PRECISION = 1e6;
struct MintFF_Params {
uint256 fxs_price_usd;
uint256 col_price_usd;
uint256 fxs_amount;
uint256 collateral_amount;
uint256 col_ratio;
}
struct BuybackFXS_Params {
uint256 excess_collateral_dollar_value_d18;
uint256 fxs_price_usd;
uint256 col_price_usd;
uint256 FXS_amount;
}
function calcMint1t1FRAX(uint256 col_price, uint256 collateral_amount_d18) public pure returns (uint256) {
return (collateral_amount_d18.mul(col_price)).div(1e6);
}
function calcMintAlgorithmicFRAX(uint256 fxs_price_usd, uint256 fxs_amount_d18) public pure returns (uint256) {
return fxs_amount_d18.mul(fxs_price_usd).div(1e6);
}
function calcMintFractionalFRAX(MintFF_Params memory params) internal pure returns (uint256, uint256) {
uint256 fxs_dollar_value_d18;
uint256 c_dollar_value_d18;
{
fxs_dollar_value_d18 = params.fxs_amount.mul(params.fxs_price_usd).div(1e6);
c_dollar_value_d18 = params.collateral_amount.mul(params.col_price_usd).div(1e6);
}
uint calculated_fxs_dollar_value_d18 =
(c_dollar_value_d18.mul(1e6).div(params.col_ratio))
.sub(c_dollar_value_d18);
uint calculated_fxs_needed = calculated_fxs_dollar_value_d18.mul(1e6).div(params.fxs_price_usd);
return (
c_dollar_value_d18.add(calculated_fxs_dollar_value_d18),
calculated_fxs_needed
);
}
function calcRedeem1t1FRAX(uint256 col_price_usd, uint256 FRAX_amount) public pure returns (uint256) {
return FRAX_amount.mul(1e6).div(col_price_usd);
}
function calcBuyBackFXS(BuybackFXS_Params memory params) internal pure returns (uint256) {
require(params.excess_collateral_dollar_value_d18 > 0, "No excess collateral to buy back!");
uint256 fxs_dollar_value_d18 = params.FXS_amount.mul(params.fxs_price_usd).div(1e6);
require(fxs_dollar_value_d18 <= params.excess_collateral_dollar_value_d18, "You are trying to buy back more than the excess!");
uint256 collateral_equivalent_d18 = fxs_dollar_value_d18.mul(1e6).div(params.col_price_usd);
return (
collateral_equivalent_d18
);
}
function recollateralizeAmount(uint256 total_supply, uint256 global_collateral_ratio, uint256 global_collat_value) public pure returns (uint256) {
uint256 target_collat_value = total_supply.mul(global_collateral_ratio).div(1e6);
return target_collat_value.sub(global_collat_value);
}
function calcRecollateralizeFRAXInner(
uint256 collateral_amount,
uint256 col_price,
uint256 global_collat_value,
uint256 frax_total_supply,
uint256 global_collateral_ratio
) public pure returns (uint256, uint256) {
uint256 collat_value_attempted = collateral_amount.mul(col_price).div(1e6);
uint256 effective_collateral_ratio = global_collat_value.mul(1e6).div(frax_total_supply);
uint256 recollat_possible = (global_collateral_ratio.mul(frax_total_supply).sub(frax_total_supply.mul(effective_collateral_ratio))).div(1e6);
uint256 amount_to_recollat;
if(collat_value_attempted <= recollat_possible){
amount_to_recollat = collat_value_attempted;
} else {
amount_to_recollat = recollat_possible;
}
return (amount_to_recollat.mul(1e6).div(col_price), amount_to_recollat);
}
}
文件 21 的 72:Governance.sol
pragma solidity 0.6.11;
pragma experimental ABIEncoderV2;
import "./FXS.sol";
contract GovernorAlpha {
string public constant name = "FXS Governor Alpha";
function quorumVotes() public pure returns (uint) { return 4000000e18; }
function proposalThreshold() public pure returns (uint) { return 1000000e18; }
function proposalMaxOperations() public pure returns (uint) { return 10; }
function votingDelay() public pure returns (uint) { return 1; }
uint public votingPeriod = 17280;
TimelockInterface public timelock;
FRAXShares public fxs;
address public guardian;
uint public proposalCount = 0;
struct Proposal {
uint id;
address proposer;
uint eta;
address[] targets;
uint[] values;
string[] signatures;
bytes[] calldatas;
uint startBlock;
uint endBlock;
uint forVotes;
uint againstVotes;
bool canceled;
bool executed;
string title;
string description;
mapping (address => Receipt) receipts;
}
struct Receipt {
bool hasVoted;
bool support;
uint96 votes;
}
enum ProposalState {
Pending,
Active,
Canceled,
Defeated,
Succeeded,
Queued,
Expired,
Executed
}
mapping (uint => Proposal) public proposals;
mapping (address => uint) public latestProposalIds;
bytes32 public constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)");
bytes32 public constant BALLOT_TYPEHASH = keccak256("Ballot(uint256 proposalId,bool support)");
event ProposalCreated(uint id, address proposer, address[] targets, uint[] values, string[] signatures, bytes[] calldatas, uint startBlock, uint endBlock, string description);
event VoteCast(address voter, uint proposalId, bool support, uint votes);
event ProposalCanceled(uint id);
event ProposalQueued(uint id, uint eta);
event ProposalExecuted(uint id);
constructor(address timelock_, address fxs_, address guardian_) public {
timelock = TimelockInterface(timelock_);
fxs = FRAXShares(fxs_);
guardian = guardian_;
}
function propose(address[] memory targets, uint[] memory values, string[] memory signatures, bytes[] memory calldatas, string memory title, string memory description) public returns (uint) {
require(fxs.getPriorVotes(msg.sender, sub256(block.number, 1)) >= proposalThreshold(), "GovernorAlpha::propose: proposer votes below proposal threshold");
require(targets.length == values.length && targets.length == signatures.length && targets.length == calldatas.length, "GovernorAlpha::propose: proposal function information arity mismatch");
require(targets.length != 0, "GovernorAlpha::propose: must provide actions");
require(targets.length <= proposalMaxOperations(), "GovernorAlpha::propose: too many actions");
uint latestProposalId = latestProposalIds[msg.sender];
if (latestProposalId != 0) {
ProposalState proposersLatestProposalState = state(latestProposalId);
require(proposersLatestProposalState != ProposalState.Active, "GovernorAlpha::propose: one live proposal per proposer, found an already active proposal");
require(proposersLatestProposalState != ProposalState.Pending, "GovernorAlpha::propose: one live proposal per proposer, found an already pending proposal");
}
uint startBlock = add256(block.number, votingDelay());
uint endBlock = add256(startBlock, votingPeriod);
proposalCount++;
Proposal memory newProposal = Proposal({
id: proposalCount,
proposer: msg.sender,
eta: 0,
targets: targets,
values: values,
signatures: signatures,
calldatas: calldatas,
startBlock: startBlock,
endBlock: endBlock,
forVotes: 0,
againstVotes: 0,
canceled: false,
executed: false,
title: title,
description: description
});
proposals[newProposal.id] = newProposal;
latestProposalIds[newProposal.proposer] = newProposal.id;
emit ProposalCreated(newProposal.id, msg.sender, targets, values, signatures, calldatas, startBlock, endBlock, description);
return newProposal.id;
}
function queue(uint proposalId) public {
require(state(proposalId) == ProposalState.Succeeded, "GovernorAlpha::queue: proposal can only be queued if it succeeded");
Proposal storage proposal = proposals[proposalId];
uint eta = add256(block.timestamp, timelock.delay());
for (uint i = 0; i < proposal.targets.length; i++) {
_queueOrRevert(proposal.targets[i], proposal.values[i], proposal.signatures[i], proposal.calldatas[i], eta);
}
proposal.eta = eta;
emit ProposalQueued(proposalId, eta);
}
function _queueOrRevert(address target, uint value, string memory signature, bytes memory data, uint eta) internal {
require(!timelock.queuedTransactions(keccak256(abi.encode(target, value, signature, data, eta))), "GovernorAlpha::_queueOrRevert: proposal action already queued at eta");
timelock.queueTransaction(target, value, signature, data, eta);
}
function execute(uint proposalId) public payable {
require(state(proposalId) == ProposalState.Queued, "GovernorAlpha::execute: proposal can only be executed if it is queued");
Proposal storage proposal = proposals[proposalId];
proposal.executed = true;
for (uint i = 0; i < proposal.targets.length; i++) {
timelock.executeTransaction(proposal.targets[i], proposal.values[i], proposal.signatures[i], proposal.calldatas[i], proposal.eta);
}
emit ProposalExecuted(proposalId);
}
function cancel(uint proposalId) public {
ProposalState state = state(proposalId);
require(state != ProposalState.Executed, "GovernorAlpha::cancel: cannot cancel executed proposal");
Proposal storage proposal = proposals[proposalId];
require(msg.sender == guardian || fxs.getPriorVotes(proposal.proposer, sub256(block.number, 1)) < proposalThreshold(), "GovernorAlpha::cancel: proposer at or above threshold");
proposal.canceled = true;
for (uint i = 0; i < proposal.targets.length; i++) {
timelock.cancelTransaction(proposal.targets[i], proposal.values[i], proposal.signatures[i], proposal.calldatas[i], proposal.eta);
}
emit ProposalCanceled(proposalId);
}
function getActions(uint proposalId) public view returns (address[] memory targets, uint[] memory values, string[] memory signatures, bytes[] memory calldatas) {
Proposal storage p = proposals[proposalId];
return (p.targets, p.values, p.signatures, p.calldatas);
}
function getReceipt(uint proposalId, address voter) public view returns (Receipt memory) {
return proposals[proposalId].receipts[voter];
}
function state(uint proposalId) public view returns (ProposalState) {
require(proposalCount >= proposalId && proposalId > 0, "GovernorAlpha::state: invalid proposal id");
Proposal storage proposal = proposals[proposalId];
if (proposal.canceled) {
return ProposalState.Canceled;
} else if (block.number <= proposal.startBlock) {
return ProposalState.Pending;
} else if (block.number <= proposal.endBlock) {
return ProposalState.Active;
} else if (proposal.forVotes <= proposal.againstVotes || proposal.forVotes < quorumVotes()) {
return ProposalState.Defeated;
} else if (proposal.eta == 0) {
return ProposalState.Succeeded;
} else if (proposal.executed) {
return ProposalState.Executed;
} else if (block.timestamp >= add256(proposal.eta, timelock.GRACE_PERIOD())) {
return ProposalState.Expired;
} else {
return ProposalState.Queued;
}
}
function castVote(uint proposalId, bool support) public {
return _castVote(msg.sender, proposalId, support);
}
function castVoteBySig(uint proposalId, bool support, uint8 v, bytes32 r, bytes32 s) public {
bytes32 domainSeparator = keccak256(abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name)), getChainId(), address(this)));
bytes32 structHash = keccak256(abi.encode(BALLOT_TYPEHASH, proposalId, support));
bytes32 digest = keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
address signatory = ecrecover(digest, v, r, s);
require(signatory != address(0), "GovernorAlpha::castVoteBySig: invalid signature");
return _castVote(signatory, proposalId, support);
}
function _castVote(address voter, uint proposalId, bool support) internal {
require(state(proposalId) == ProposalState.Active, "GovernorAlpha::_castVote: voting is closed");
Proposal storage proposal = proposals[proposalId];
Receipt storage receipt = proposal.receipts[voter];
require(receipt.hasVoted == false, "GovernorAlpha::_castVote: voter already voted");
uint96 votes = fxs.getPriorVotes(voter, proposal.startBlock);
if (support) {
proposal.forVotes = add256(proposal.forVotes, votes);
} else {
proposal.againstVotes = add256(proposal.againstVotes, votes);
}
receipt.hasVoted = true;
receipt.support = support;
receipt.votes = votes;
emit VoteCast(voter, proposalId, support, votes);
}
function __acceptAdmin() public {
require(msg.sender == guardian, "GovernorAlpha::__acceptAdmin: sender must be gov guardian");
timelock.acceptAdmin();
}
function __abdicate() public {
require(msg.sender == guardian, "GovernorAlpha::__abdicate: sender must be gov guardian");
guardian = address(0);
}
function __setVotingPeriod(uint period) public {
require(msg.sender == guardian, "GovernorAlpha::__setVotingPeriod: sender must be gov guardian");
votingPeriod = period;
}
function __setTimelockAddress(address timelock_) public {
require(msg.sender == guardian, "GovernorAlpha::__setTimelockAddress: sender must be gov guardian");
timelock = TimelockInterface(timelock_);
}
function __queueSetTimelockPendingAdmin(address newPendingAdmin, uint eta) public {
require(msg.sender == guardian, "GovernorAlpha::__queueSetTimelockPendingAdmin: sender must be gov guardian");
timelock.queueTransaction(address(timelock), 0, "setPendingAdmin(address)", abi.encode(newPendingAdmin), eta);
}
function __executeSetTimelockPendingAdmin(address newPendingAdmin, uint eta) public {
require(msg.sender == guardian, "GovernorAlpha::__executeSetTimelockPendingAdmin: sender must be gov guardian");
timelock.executeTransaction(address(timelock), 0, "setPendingAdmin(address)", abi.encode(newPendingAdmin), eta);
}
function add256(uint256 a, uint256 b) internal pure returns (uint) {
uint c = a + b;
require(c >= a, "addition overflow");
return c;
}
function sub256(uint256 a, uint256 b) internal pure returns (uint) {
require(b <= a, "subtraction underflow");
return a - b;
}
function getChainId() internal pure returns (uint) {
uint chainId;
assembly { chainId := chainid() }
return chainId;
}
}
interface TimelockInterface {
function delay() external view returns (uint);
function GRACE_PERIOD() external view returns (uint);
function acceptAdmin() external;
function queuedTransactions(bytes32 hash) external view returns (bool);
function queueTransaction(address target, uint value, string calldata signature, bytes calldata data, uint eta) external returns (bytes32);
function cancelTransaction(address target, uint value, string calldata signature, bytes calldata data, uint eta) external;
function executeTransaction(address target, uint value, string calldata signature, bytes calldata data, uint eta) external payable returns (bytes memory);
}
文件 22 的 72:IERC20.sol
pragma solidity 0.6.11;
import "./Context.sol";
import "./SafeMath.sol";
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
文件 23 的 72:IStakingRewards.sol
pragma solidity 0.6.11;
interface IStakingRewards {
function lastTimeRewardApplicable() external view returns (uint256);
function rewardPerToken() external view returns (uint256);
function earned(address account) external view returns (uint256);
function getRewardForDuration() external view returns (uint256);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function stake(uint256 amount) external;
function withdraw(uint256 amount) external;
function getReward() external;
}
文件 24 的 72:IUniswapV2Callee.sol
pragma solidity 0.6.11;
interface IUniswapV2Callee {
function uniswapV2Call(address sender, uint amount0, uint amount1, bytes calldata data) external;
}
文件 25 的 72:IUniswapV2ERC20.sol
pragma solidity 0.6.11;
interface IUniswapV2ERC20 {
event Approval(address indexed owner, address indexed spender, uint value);
event Transfer(address indexed from, address indexed to, uint value);
function name() external pure returns (string memory);
function symbol() external pure returns (string memory);
function decimals() external pure returns (uint8);
function totalSupply() external view returns (uint);
function balanceOf(address owner) external view returns (uint);
function allowance(address owner, address spender) external view returns (uint);
function approve(address spender, uint value) external returns (bool);
function transfer(address to, uint value) external returns (bool);
function transferFrom(address from, address to, uint value) external returns (bool);
function DOMAIN_SEPARATOR() external view returns (bytes32);
function PERMIT_TYPEHASH() external pure returns (bytes32);
function nonces(address owner) external view returns (uint);
function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
}
文件 26 的 72:IUniswapV2Factory.sol
pragma solidity 0.6.11;
interface IUniswapV2Factory {
event PairCreated(address indexed token0, address indexed token1, address pair, uint);
function feeTo() external view returns (address);
function feeToSetter() external view returns (address);
function getPair(address tokenA, address tokenB) external view returns (address pair);
function allPairs(uint) external view returns (address pair);
function allPairsLength() external view returns (uint);
function createPair(address tokenA, address tokenB) external returns (address pair);
function setFeeTo(address) external;
function setFeeToSetter(address) external;
}
文件 27 的 72:IUniswapV2Pair.sol
pragma solidity 0.6.11;
interface IUniswapV2Pair {
event Approval(address indexed owner, address indexed spender, uint value);
event Transfer(address indexed from, address indexed to, uint value);
function name() external pure returns (string memory);
function symbol() external pure returns (string memory);
function decimals() external pure returns (uint8);
function totalSupply() external view returns (uint);
function balanceOf(address owner) external view returns (uint);
function allowance(address owner, address spender) external view returns (uint);
function approve(address spender, uint value) external returns (bool);
function transfer(address to, uint value) external returns (bool);
function transferFrom(address from, address to, uint value) external returns (bool);
function DOMAIN_SEPARATOR() external view returns (bytes32);
function PERMIT_TYPEHASH() external pure returns (bytes32);
function nonces(address owner) external view returns (uint);
function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
event Mint(address indexed sender, uint amount0, uint amount1);
event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
event Swap(
address indexed sender,
uint amount0In,
uint amount1In,
uint amount0Out,
uint amount1Out,
address indexed to
);
event Sync(uint112 reserve0, uint112 reserve1);
function MINIMUM_LIQUIDITY() external pure returns (uint);
function factory() external view returns (address);
function token0() external view returns (address);
function token1() external view returns (address);
function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
function price0CumulativeLast() external view returns (uint);
function price1CumulativeLast() external view returns (uint);
function kLast() external view returns (uint);
function mint(address to) external returns (uint liquidity);
function burn(address to) external returns (uint amount0, uint amount1);
function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
function skim(address to) external;
function sync() external;
function initialize(address, address) external;
}
文件 28 的 72:IUniswapV2Router01.sol
pragma solidity 0.6.11;
interface IUniswapV2Router01 {
function factory() external pure returns (address);
function WETH() external pure returns (address);
function addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB, uint liquidity);
function addLiquidityETH(
address token,
uint amountTokenDesired,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external payable returns (uint amountToken, uint amountETH, uint liquidity);
function removeLiquidity(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB);
function removeLiquidityETH(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external returns (uint amountToken, uint amountETH);
function removeLiquidityWithPermit(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountA, uint amountB);
function removeLiquidityETHWithPermit(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountToken, uint amountETH);
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapTokensForExactTokens(
uint amountOut,
uint amountInMax,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
external
payable
returns (uint[] memory amounts);
function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
external
returns (uint[] memory amounts);
function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
external
returns (uint[] memory amounts);
function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
external
payable
returns (uint[] memory amounts);
function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
}
文件 29 的 72:IUniswapV2Router02.sol
pragma solidity 0.6.11;
import './IUniswapV2Router01.sol';
interface IUniswapV2Router02 is IUniswapV2Router01 {
function removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external returns (uint amountETH);
function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountETH);
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
function swapExactETHForTokensSupportingFeeOnTransferTokens(
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external payable;
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
}
文件 30 的 72:IWETH.sol
pragma solidity 0.6.11;
interface IWETH {
function deposit() external payable;
function transfer(address to, uint value) external returns (bool);
function transferFrom(address src, address dst, uint wad) external returns (bool);
function withdraw(uint) external;
}
文件 31 的 72:Math.sol
pragma solidity 0.6.11;
library Math {
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a >= b ? a : b;
}
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
function average(uint256 a, uint256 b) internal pure returns (uint256) {
return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
}
function sqrt(uint y) internal pure returns (uint z) {
if (y > 3) {
z = y;
uint x = y / 2 + 1;
while (x < z) {
z = x;
x = (y / x + x) / 2;
}
} else if (y != 0) {
z = 1;
}
}
}
文件 32 的 72:MigrationHelper.sol
pragma solidity 0.6.11;
contract MigrationHelper {
address public owner;
uint256 public gov_to_timelock_eta;
modifier restricted() {
if (msg.sender == owner) _;
}
constructor(address _owner) public {
owner = _owner;
}
function setGovToTimeLockETA(uint256 _eta) public restricted {
gov_to_timelock_eta = _eta;
}
}
文件 33 的 72:Migrations.sol
pragma solidity 0.6.11;
contract Migrations {
address public owner;
uint public last_completed_migration;
modifier restricted() {
if (msg.sender == owner) _;
}
constructor() public {
owner = msg.sender;
}
function setCompleted(uint completed) public restricted {
last_completed_migration = completed;
}
}
文件 34 的 72:Owned.sol
pragma solidity 0.6.11;
contract Owned {
address public owner;
address public nominatedOwner;
constructor(address _owner) public {
require(_owner != address(0), "Owner address cannot be 0");
owner = _owner;
emit OwnerChanged(address(0), _owner);
}
function nominateNewOwner(address _owner) external onlyOwner {
nominatedOwner = _owner;
emit OwnerNominated(_owner);
}
function acceptOwnership() external {
require(msg.sender == nominatedOwner, "You must be nominated before you can accept ownership");
emit OwnerChanged(owner, nominatedOwner);
owner = nominatedOwner;
nominatedOwner = address(0);
}
modifier onlyOwner {
require(msg.sender == owner, "Only the contract owner may perform this action");
_;
}
event OwnerNominated(address newOwner);
event OwnerChanged(address oldOwner, address newOwner);
}
文件 35 的 72:Pausable.sol
pragma solidity 0.6.11;
import "./Owned.sol";
abstract contract Pausable is Owned {
uint public lastPauseTime;
bool public paused;
constructor() internal {
require(owner != address(0), "Owner must be set");
}
function setPaused(bool _paused) external onlyOwner {
if (_paused == paused) {
return;
}
paused = _paused;
if (paused) {
lastPauseTime = now;
}
emit PauseChanged(paused);
}
event PauseChanged(bool isPaused);
modifier notPaused {
require(!paused, "This action cannot be performed while the contract is paused");
_;
}
}
文件 36 的 72:Pool_USDC.sol
pragma solidity 0.6.11;
import "./FraxPool.sol";
contract Pool_USDC is FraxPool {
address public USDC_address;
constructor(
address _frax_contract_address,
address _fxs_contract_address,
address _collateral_address,
address _creator_address,
address _timelock_address,
uint256 _pool_ceiling
)
FraxPool(_frax_contract_address, _fxs_contract_address, _collateral_address, _creator_address, _timelock_address, _pool_ceiling)
public {
_setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
USDC_address = _collateral_address;
}
}
文件 37 的 72:Pool_USDT.sol
pragma solidity 0.6.11;
import "./FraxPool.sol";
contract Pool_USDT is FraxPool {
address public USDT_address;
constructor(
address _frax_contract_address,
address _fxs_contract_address,
address _collateral_address,
address _creator_address,
address _timelock_address,
uint256 _pool_ceiling
)
FraxPool(_frax_contract_address, _fxs_contract_address, _collateral_address, _creator_address, _timelock_address, _pool_ceiling)
public {
_setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
USDT_address = _collateral_address;
}
}
文件 38 的 72:ReentrancyGuard.sol
pragma solidity 0.6.11;
contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor () internal {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
}
文件 39 的 72:RewardsDistributionRecipient.sol
pragma solidity 0.6.11;
import "./Owned.sol";
abstract contract RewardsDistributionRecipient is Owned {
address public rewardsDistribution;
modifier onlyRewardsDistribution() {
require(msg.sender == rewardsDistribution, "Caller is not RewardsDistribution contract");
_;
}
function setRewardsDistribution(address _rewardsDistribution) external onlyOwner {
rewardsDistribution = _rewardsDistribution;
}
}
文件 40 的 72:SafeERC20.sol
pragma solidity 0.6.11;
import "./IERC20.sol";
import "./SafeMath.sol";
import "./Address.sol";
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));
}
function safeApprove(IERC20 token, address spender, uint256 value) internal {
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));
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
文件 41 的 72:SafeMath.sol
pragma solidity 0.6.11;
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 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 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 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;
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;
}
}
文件 42 的 72:Stake_FRAX_FXS.sol
pragma solidity 0.6.11;
pragma experimental ABIEncoderV2;
import "./StakingRewards.sol";
contract Stake_FRAX_FXS is StakingRewards {
constructor(
address _owner,
address _rewardsDistribution,
address _rewardsToken,
address _stakingToken,
address _frax_address,
address _timelock_address,
uint256 _pool_weight
)
StakingRewards(_owner, _rewardsDistribution, _rewardsToken, _stakingToken, _frax_address, _timelock_address, _pool_weight)
public {}
}
文件 43 的 72:Stake_FRAX_USDC.sol
pragma solidity 0.6.11;
pragma experimental ABIEncoderV2;
import "./StakingRewards.sol";
contract Stake_FRAX_USDC is StakingRewards {
constructor(
address _owner,
address _rewardsDistribution,
address _rewardsToken,
address _stakingToken,
address _frax_address,
address _timelock_address,
uint256 _pool_weight
)
StakingRewards(_owner, _rewardsDistribution, _rewardsToken, _stakingToken, _frax_address, _timelock_address, _pool_weight)
public {}
}
文件 44 的 72:Stake_FRAX_WETH.sol
pragma solidity 0.6.11;
pragma experimental ABIEncoderV2;
import "./StakingRewards.sol";
contract Stake_FRAX_WETH is StakingRewards {
constructor(
address _owner,
address _rewardsDistribution,
address _rewardsToken,
address _stakingToken,
address _frax_address,
address _timelock_address,
uint256 _pool_weight
)
StakingRewards(_owner, _rewardsDistribution, _rewardsToken, _stakingToken, _frax_address, _timelock_address, _pool_weight)
public {}
}
文件 45 的 72:Stake_FXS_WETH.sol
pragma solidity 0.6.11;
pragma experimental ABIEncoderV2;
import "./StakingRewards.sol";
contract Stake_FXS_WETH is StakingRewards {
constructor(
address _owner,
address _rewardsDistribution,
address _rewardsToken,
address _stakingToken,
address _frax_address,
address _timelock_address,
uint256 _pool_weight
)
StakingRewards(_owner, _rewardsDistribution, _rewardsToken, _stakingToken, _frax_address, _timelock_address, _pool_weight)
public {}
}
文件 46 的 72:StakingRewards.sol
pragma solidity 0.6.11;
pragma experimental ABIEncoderV2;
import "./Math.sol";
import "./SafeMath.sol";
import "./ERC20.sol";
import './TransferHelper.sol';
import "./SafeERC20.sol";
import "./Frax.sol";
import "./ReentrancyGuard.sol";
import "./StringHelpers.sol";
import "./IStakingRewards.sol";
import "./RewardsDistributionRecipient.sol";
import "./Pausable.sol";
contract StakingRewards is IStakingRewards, RewardsDistributionRecipient, ReentrancyGuard, Pausable {
using SafeMath for uint256;
using SafeERC20 for ERC20;
FRAXStablecoin private FRAX;
ERC20 public rewardsToken;
ERC20 public stakingToken;
uint256 public periodFinish;
uint256 private constant PRICE_PRECISION = 1e6;
uint256 private constant MULTIPLIER_BASE = 1e6;
uint256 public rewardRate;
uint256 public rewardsDuration = 604800;
uint256 public lastUpdateTime;
uint256 public rewardPerTokenStored = 0;
uint256 private pool_weight;
address public owner_address;
address public timelock_address;
uint256 public locked_stake_max_multiplier = 3000000;
uint256 public locked_stake_time_for_max_multiplier = 3 * 365 * 86400;
uint256 public locked_stake_min_time = 604800;
string private locked_stake_min_time_str = "604800";
uint256 public cr_boost_max_multiplier = 3000000;
mapping(address => uint256) public userRewardPerTokenPaid;
mapping(address => uint256) public rewards;
uint256 private _staking_token_supply = 0;
uint256 private _staking_token_boosted_supply = 0;
mapping(address => uint256) private _unlocked_balances;
mapping(address => uint256) private _locked_balances;
mapping(address => uint256) private _boosted_balances;
mapping(address => LockedStake[]) private lockedStakes;
mapping(address => bool) public greylist;
bool public unlockedStakes;
struct LockedStake {
bytes32 kek_id;
uint256 start_timestamp;
uint256 amount;
uint256 ending_timestamp;
uint256 multiplier;
}
constructor(
address _owner,
address _rewardsDistribution,
address _rewardsToken,
address _stakingToken,
address _frax_address,
address _timelock_address,
uint256 _pool_weight
) public Owned(_owner){
owner_address = _owner;
rewardsToken = ERC20(_rewardsToken);
stakingToken = ERC20(_stakingToken);
FRAX = FRAXStablecoin(_frax_address);
rewardsDistribution = _rewardsDistribution;
lastUpdateTime = block.timestamp;
timelock_address = _timelock_address;
pool_weight = _pool_weight;
rewardRate = 380517503805175038;
rewardRate = rewardRate.mul(pool_weight).div(1e6);
unlockedStakes = false;
}
function totalSupply() external override view returns (uint256) {
return _staking_token_supply;
}
function totalBoostedSupply() external view returns (uint256) {
return _staking_token_boosted_supply;
}
function stakingMultiplier(uint256 secs) public view returns (uint256) {
uint256 multiplier = uint(MULTIPLIER_BASE).add(secs.mul(locked_stake_max_multiplier.sub(MULTIPLIER_BASE)).div(locked_stake_time_for_max_multiplier));
if (multiplier > locked_stake_max_multiplier) multiplier = locked_stake_max_multiplier;
return multiplier;
}
function crBoostMultiplier() public view returns (uint256) {
uint256 multiplier = uint(MULTIPLIER_BASE).add((uint(MULTIPLIER_BASE).sub(FRAX.global_collateral_ratio())).mul(cr_boost_max_multiplier.sub(MULTIPLIER_BASE)).div(MULTIPLIER_BASE) );
return multiplier;
}
function balanceOf(address account) external override view returns (uint256) {
return (_unlocked_balances[account]).add(_locked_balances[account]);
}
function unlockedBalanceOf(address account) external view returns (uint256) {
return _unlocked_balances[account];
}
function lockedBalanceOf(address account) public view returns (uint256) {
return _locked_balances[account];
}
function boostedBalanceOf(address account) external view returns (uint256) {
return _boosted_balances[account];
}
function lockedStakesOf(address account) external view returns (LockedStake[] memory) {
return lockedStakes[account];
}
function stakingDecimals() external view returns (uint256) {
return stakingToken.decimals();
}
function rewardsFor(address account) external view returns (uint256) {
return rewards[account];
}
function lastTimeRewardApplicable() public override view returns (uint256) {
return Math.min(block.timestamp, periodFinish);
}
function rewardPerToken() public override view returns (uint256) {
if (_staking_token_supply == 0) {
return rewardPerTokenStored;
}
else {
return rewardPerTokenStored.add(
lastTimeRewardApplicable().sub(lastUpdateTime).mul(rewardRate).mul(crBoostMultiplier()).mul(1e18).div(PRICE_PRECISION).div(_staking_token_boosted_supply)
);
}
}
function earned(address account) public override view returns (uint256) {
return _boosted_balances[account].mul(rewardPerToken().sub(userRewardPerTokenPaid[account])).div(1e18).add(rewards[account]);
}
function getRewardForDuration() external override view returns (uint256) {
return rewardRate.mul(rewardsDuration).mul(crBoostMultiplier()).div(PRICE_PRECISION);
}
function stake(uint256 amount) external override nonReentrant notPaused updateReward(msg.sender) {
require(amount > 0, "Cannot stake 0");
require(greylist[msg.sender] == false, "address has been greylisted");
TransferHelper.safeTransferFrom(address(stakingToken), msg.sender, address(this), amount);
_staking_token_supply = _staking_token_supply.add(amount);
_staking_token_boosted_supply = _staking_token_boosted_supply.add(amount);
_unlocked_balances[msg.sender] = _unlocked_balances[msg.sender].add(amount);
_boosted_balances[msg.sender] = _boosted_balances[msg.sender].add(amount);
emit Staked(msg.sender, amount);
}
function stakeLocked(uint256 amount, uint256 secs) external nonReentrant notPaused updateReward(msg.sender) {
require(amount > 0, "Cannot stake 0");
require(secs > 0, "Cannot wait for a negative number");
require(greylist[msg.sender] == false, "address has been greylisted");
require(secs >= locked_stake_min_time, StringHelpers.strConcat("Minimum stake time not met (", locked_stake_min_time_str, ")") );
uint256 multiplier = stakingMultiplier(secs);
uint256 boostedAmount = amount.mul(multiplier).div(PRICE_PRECISION);
lockedStakes[msg.sender].push(LockedStake(
keccak256(abi.encodePacked(msg.sender, block.timestamp, amount)),
block.timestamp,
amount,
block.timestamp.add(secs),
multiplier
));
TransferHelper.safeTransferFrom(address(stakingToken), msg.sender, address(this), amount);
_staking_token_supply = _staking_token_supply.add(amount);
_staking_token_boosted_supply = _staking_token_boosted_supply.add(boostedAmount);
_locked_balances[msg.sender] = _locked_balances[msg.sender].add(amount);
_boosted_balances[msg.sender] = _boosted_balances[msg.sender].add(boostedAmount);
emit StakeLocked(msg.sender, amount, secs);
}
function withdraw(uint256 amount) public override nonReentrant updateReward(msg.sender) {
require(amount > 0, "Cannot withdraw 0");
_unlocked_balances[msg.sender] = _unlocked_balances[msg.sender].sub(amount);
_boosted_balances[msg.sender] = _boosted_balances[msg.sender].sub(amount);
_staking_token_supply = _staking_token_supply.sub(amount);
_staking_token_boosted_supply = _staking_token_boosted_supply.sub(amount);
stakingToken.safeTransfer(msg.sender, amount);
emit Withdrawn(msg.sender, amount);
}
function withdrawLocked(bytes32 kek_id) public nonReentrant updateReward(msg.sender) {
LockedStake memory thisStake;
thisStake.amount = 0;
uint theIndex;
for (uint i = 0; i < lockedStakes[msg.sender].length; i++){
if (kek_id == lockedStakes[msg.sender][i].kek_id){
thisStake = lockedStakes[msg.sender][i];
theIndex = i;
break;
}
}
require(thisStake.kek_id == kek_id, "Stake not found");
require(block.timestamp >= thisStake.ending_timestamp || unlockedStakes == true, "Stake is still locked!");
uint256 theAmount = thisStake.amount;
uint256 boostedAmount = theAmount.mul(thisStake.multiplier).div(PRICE_PRECISION);
if (theAmount > 0){
_locked_balances[msg.sender] = _locked_balances[msg.sender].sub(theAmount);
_boosted_balances[msg.sender] = _boosted_balances[msg.sender].sub(boostedAmount);
_staking_token_supply = _staking_token_supply.sub(theAmount);
_staking_token_boosted_supply = _staking_token_boosted_supply.sub(boostedAmount);
delete lockedStakes[msg.sender][theIndex];
stakingToken.safeTransfer(msg.sender, theAmount);
emit WithdrawnLocked(msg.sender, theAmount, kek_id);
}
}
function getReward() public override nonReentrant updateReward(msg.sender) {
uint256 reward = rewards[msg.sender];
if (reward > 0) {
rewards[msg.sender] = 0;
rewardsToken.transfer(msg.sender, reward);
emit RewardPaid(msg.sender, reward);
}
}
function renewIfApplicable() external {
if (block.timestamp > periodFinish) {
retroCatchUp();
}
}
function retroCatchUp() internal {
require(block.timestamp > periodFinish, "Period has not expired yet!");
uint256 num_periods_elapsed = uint256(block.timestamp.sub(periodFinish)) / rewardsDuration;
uint balance = rewardsToken.balanceOf(address(this));
require(rewardRate.mul(rewardsDuration).mul(crBoostMultiplier()).mul(num_periods_elapsed + 1).div(PRICE_PRECISION) <= balance, "Not enough FXS available for rewards!");
periodFinish = periodFinish.add((num_periods_elapsed.add(1)).mul(rewardsDuration));
rewardPerTokenStored = rewardPerToken();
lastUpdateTime = lastTimeRewardApplicable();
emit RewardsPeriodRenewed(address(stakingToken));
}
function recoverERC20(address tokenAddress, uint256 tokenAmount) external onlyByOwnerOrGovernance {
require(tokenAddress != address(stakingToken));
ERC20(tokenAddress).transfer(owner_address, tokenAmount);
emit Recovered(tokenAddress, tokenAmount);
}
function setRewardsDuration(uint256 _rewardsDuration) external onlyByOwnerOrGovernance {
require(
periodFinish == 0 || block.timestamp > periodFinish,
"Previous rewards period must be complete before changing the duration for the new period"
);
rewardsDuration = _rewardsDuration;
emit RewardsDurationUpdated(rewardsDuration);
}
function setMultipliers(uint256 _locked_stake_max_multiplier, uint256 _cr_boost_max_multiplier) external onlyByOwnerOrGovernance {
require(_locked_stake_max_multiplier >= 1, "Multiplier must be greater than or equal to 1");
require(_cr_boost_max_multiplier >= 1, "Max CR Boost must be greater than or equal to 1");
locked_stake_max_multiplier = _locked_stake_max_multiplier;
cr_boost_max_multiplier = _cr_boost_max_multiplier;
emit MaxCRBoostMultiplier(cr_boost_max_multiplier);
emit LockedStakeMaxMultiplierUpdated(locked_stake_max_multiplier);
}
function setLockedStakeTimeForMinAndMaxMultiplier(uint256 _locked_stake_time_for_max_multiplier, uint256 _locked_stake_min_time) external onlyByOwnerOrGovernance {
require(_locked_stake_time_for_max_multiplier >= 1, "Multiplier Max Time must be greater than or equal to 1");
require(_locked_stake_min_time >= 1, "Multiplier Min Time must be greater than or equal to 1");
locked_stake_time_for_max_multiplier = _locked_stake_time_for_max_multiplier;
locked_stake_min_time = _locked_stake_min_time;
locked_stake_min_time_str = StringHelpers.uint2str(_locked_stake_min_time);
emit LockedStakeTimeForMaxMultiplier(locked_stake_time_for_max_multiplier);
emit LockedStakeMinTime(_locked_stake_min_time);
}
function initializeDefault() external onlyByOwnerOrGovernance {
lastUpdateTime = block.timestamp;
periodFinish = block.timestamp.add(rewardsDuration);
emit DefaultInitialization();
}
function greylistAddress(address _address) external onlyByOwnerOrGovernance {
greylist[_address] = !(greylist[_address]);
}
function unlockStakes() external onlyByOwnerOrGovernance {
unlockedStakes = !unlockedStakes;
}
function setRewardRate(uint256 _new_rate) external onlyByOwnerOrGovernance {
rewardRate = _new_rate;
}
function setOwnerAndTimelock(address _new_owner, address _new_timelock) external onlyByOwnerOrGovernance {
owner_address = _new_owner;
timelock_address = _new_timelock;
}
modifier updateReward(address account) {
if (block.timestamp > periodFinish) {
retroCatchUp();
}
else {
rewardPerTokenStored = rewardPerToken();
lastUpdateTime = lastTimeRewardApplicable();
}
if (account != address(0)) {
rewards[account] = earned(account);
userRewardPerTokenPaid[account] = rewardPerTokenStored;
}
_;
}
modifier onlyByOwnerOrGovernance() {
require(msg.sender == owner_address || msg.sender == timelock_address, "You are not the owner or the governance timelock");
_;
}
event RewardAdded(uint256 reward);
event Staked(address indexed user, uint256 amount);
event StakeLocked(address indexed user, uint256 amount, uint256 secs);
event Withdrawn(address indexed user, uint256 amount);
event WithdrawnLocked(address indexed user, uint256 amount, bytes32 kek_id);
event RewardPaid(address indexed user, uint256 reward);
event RewardsDurationUpdated(uint256 newDuration);
event Recovered(address token, uint256 amount);
event RewardsPeriodRenewed(address token);
event DefaultInitialization();
event LockedStakeMaxMultiplierUpdated(uint256 multiplier);
event LockedStakeTimeForMaxMultiplier(uint256 secs);
event LockedStakeMinTime(uint256 secs);
event MaxCRBoostMultiplier(uint256 multiplier);
}
文件 47 的 72:StringHelpers.sol
pragma solidity 0.6.11;
library StringHelpers {
function parseAddr(string memory _a) internal pure returns (address _parsedAddress) {
bytes memory tmp = bytes(_a);
uint160 iaddr = 0;
uint160 b1;
uint160 b2;
for (uint i = 2; i < 2 + 2 * 20; i += 2) {
iaddr *= 256;
b1 = uint160(uint8(tmp[i]));
b2 = uint160(uint8(tmp[i + 1]));
if ((b1 >= 97) && (b1 <= 102)) {
b1 -= 87;
} else if ((b1 >= 65) && (b1 <= 70)) {
b1 -= 55;
} else if ((b1 >= 48) && (b1 <= 57)) {
b1 -= 48;
}
if ((b2 >= 97) && (b2 <= 102)) {
b2 -= 87;
} else if ((b2 >= 65) && (b2 <= 70)) {
b2 -= 55;
} else if ((b2 >= 48) && (b2 <= 57)) {
b2 -= 48;
}
iaddr += (b1 * 16 + b2);
}
return address(iaddr);
}
function strCompare(string memory _a, string memory _b) internal pure returns (int _returnCode) {
bytes memory a = bytes(_a);
bytes memory b = bytes(_b);
uint minLength = a.length;
if (b.length < minLength) {
minLength = b.length;
}
for (uint i = 0; i < minLength; i ++) {
if (a[i] < b[i]) {
return -1;
} else if (a[i] > b[i]) {
return 1;
}
}
if (a.length < b.length) {
return -1;
} else if (a.length > b.length) {
return 1;
} else {
return 0;
}
}
function indexOf(string memory _haystack, string memory _needle) internal pure returns (int _returnCode) {
bytes memory h = bytes(_haystack);
bytes memory n = bytes(_needle);
if (h.length < 1 || n.length < 1 || (n.length > h.length)) {
return -1;
} else if (h.length > (2 ** 128 - 1)) {
return -1;
} else {
uint subindex = 0;
for (uint i = 0; i < h.length; i++) {
if (h[i] == n[0]) {
subindex = 1;
while(subindex < n.length && (i + subindex) < h.length && h[i + subindex] == n[subindex]) {
subindex++;
}
if (subindex == n.length) {
return int(i);
}
}
}
return -1;
}
}
function strConcat(string memory _a, string memory _b) internal pure returns (string memory _concatenatedString) {
return strConcat(_a, _b, "", "", "");
}
function strConcat(string memory _a, string memory _b, string memory _c) internal pure returns (string memory _concatenatedString) {
return strConcat(_a, _b, _c, "", "");
}
function strConcat(string memory _a, string memory _b, string memory _c, string memory _d) internal pure returns (string memory _concatenatedString) {
return strConcat(_a, _b, _c, _d, "");
}
function strConcat(string memory _a, string memory _b, string memory _c, string memory _d, string memory _e) internal pure returns (string memory _concatenatedString) {
bytes memory _ba = bytes(_a);
bytes memory _bb = bytes(_b);
bytes memory _bc = bytes(_c);
bytes memory _bd = bytes(_d);
bytes memory _be = bytes(_e);
string memory abcde = new string(_ba.length + _bb.length + _bc.length + _bd.length + _be.length);
bytes memory babcde = bytes(abcde);
uint k = 0;
uint i = 0;
for (i = 0; i < _ba.length; i++) {
babcde[k++] = _ba[i];
}
for (i = 0; i < _bb.length; i++) {
babcde[k++] = _bb[i];
}
for (i = 0; i < _bc.length; i++) {
babcde[k++] = _bc[i];
}
for (i = 0; i < _bd.length; i++) {
babcde[k++] = _bd[i];
}
for (i = 0; i < _be.length; i++) {
babcde[k++] = _be[i];
}
return string(babcde);
}
function safeParseInt(string memory _a) internal pure returns (uint _parsedInt) {
return safeParseInt(_a, 0);
}
function safeParseInt(string memory _a, uint _b) internal pure returns (uint _parsedInt) {
bytes memory bresult = bytes(_a);
uint mint = 0;
bool decimals = false;
for (uint i = 0; i < bresult.length; i++) {
if ((uint(uint8(bresult[i])) >= 48) && (uint(uint8(bresult[i])) <= 57)) {
if (decimals) {
if (_b == 0) break;
else _b--;
}
mint *= 10;
mint += uint(uint8(bresult[i])) - 48;
} else if (uint(uint8(bresult[i])) == 46) {
require(!decimals, 'More than one decimal encountered in string!');
decimals = true;
} else {
revert("Non-numeral character encountered in string!");
}
}
if (_b > 0) {
mint *= 10 ** _b;
}
return mint;
}
function parseInt(string memory _a) internal pure returns (uint _parsedInt) {
return parseInt(_a, 0);
}
function parseInt(string memory _a, uint _b) internal pure returns (uint _parsedInt) {
bytes memory bresult = bytes(_a);
uint mint = 0;
bool decimals = false;
for (uint i = 0; i < bresult.length; i++) {
if ((uint(uint8(bresult[i])) >= 48) && (uint(uint8(bresult[i])) <= 57)) {
if (decimals) {
if (_b == 0) {
break;
} else {
_b--;
}
}
mint *= 10;
mint += uint(uint8(bresult[i])) - 48;
} else if (uint(uint8(bresult[i])) == 46) {
decimals = true;
}
}
if (_b > 0) {
mint *= 10 ** _b;
}
return mint;
}
function uint2str(uint _i) internal pure returns (string memory _uintAsString) {
if (_i == 0) {
return "0";
}
uint j = _i;
uint len;
while (j != 0) {
len++;
j /= 10;
}
bytes memory bstr = new bytes(len);
uint k = len - 1;
while (_i != 0) {
bstr[k--] = byte(uint8(48 + _i % 10));
_i /= 10;
}
return string(bstr);
}
}
文件 48 的 72:SwapToPrice.sol
pragma solidity 0.6.11;
import './IUniswapV2Pair.sol';
import './Babylonian.sol';
import './SafeMath.sol';
import './TransferHelper.sol';
import './IERC20.sol';
import './IUniswapV2Router01.sol';
import './UniswapV2Library.sol';
contract SwapToPrice {
using SafeMath for uint256;
IUniswapV2Router01 public immutable router;
address public immutable factory;
constructor(address factory_, IUniswapV2Router01 router_) public {
factory = factory_;
router = router_;
}
function computeProfitMaximizingTrade(
uint256 truePriceTokenA,
uint256 truePriceTokenB,
uint256 reserveA,
uint256 reserveB
) pure public returns (bool aToB, uint256 amountIn) {
aToB = reserveA.mul(truePriceTokenB) / reserveB < truePriceTokenA;
uint256 invariant = reserveA.mul(reserveB);
uint256 leftSide = Babylonian.sqrt(
invariant.mul(aToB ? truePriceTokenA : truePriceTokenB).mul(1000) /
uint256(aToB ? truePriceTokenB : truePriceTokenA).mul(997)
);
uint256 rightSide = (aToB ? reserveA.mul(1000) : reserveB.mul(1000)) / 997;
amountIn = leftSide.sub(rightSide);
}
function swapToPrice(
address tokenA,
address tokenB,
uint256 truePriceTokenA,
uint256 truePriceTokenB,
uint256 maxSpendTokenA,
uint256 maxSpendTokenB,
address to,
uint256 deadline
) public {
require(truePriceTokenA != 0 && truePriceTokenB != 0, "ExampleSwapToPrice: ZERO_PRICE");
require(maxSpendTokenA != 0 || maxSpendTokenB != 0, "ExampleSwapToPrice: ZERO_SPEND");
bool aToB;
uint256 amountIn;
{
(uint256 reserveA, uint256 reserveB) = UniswapV2Library.getReserves(factory, tokenA, tokenB);
(aToB, amountIn) = computeProfitMaximizingTrade(
truePriceTokenA, truePriceTokenB,
reserveA, reserveB
);
}
uint256 maxSpend = aToB ? maxSpendTokenA : maxSpendTokenB;
if (amountIn > maxSpend) {
amountIn = maxSpend;
}
address tokenIn = aToB ? tokenA : tokenB;
address tokenOut = aToB ? tokenB : tokenA;
TransferHelper.safeTransferFrom(tokenIn, msg.sender, address(this), amountIn);
TransferHelper.safeApprove(tokenIn, address(router), amountIn);
address[] memory path = new address[](2);
path[0] = tokenIn;
path[1] = tokenOut;
router.swapExactTokensForTokens(
amountIn,
0,
path,
to,
deadline
);
}
}
文件 49 的 72:TestSwap.sol
pragma solidity 0.6.11;
import "./FakeCollateral_USDT.sol";
import "./FakeCollateral_WETH.sol";
import "./UniswapV2Router02_Modified.sol";
contract TestSwap {
address public USDT_address;
address public WETH_address;
UniswapV2Router02_Modified public router;
FakeCollateral_USDT USDT = FakeCollateral_USDT(USDT);
FakeCollateral_WETH WETH = FakeCollateral_WETH(WETH);
constructor(
address _USDT_address,
address _WETH_address,
UniswapV2Router02_Modified _router_address
) public {
USDT_address = _USDT_address;
WETH_address = _WETH_address;
router = UniswapV2Router02_Modified(_router_address);
}
function getPath() public returns (address[] memory) {
address[] memory path = new address[](2);
path[0] = USDT_address;
path[1] = WETH_address;
return path;
}
function swapUSDTforETH(uint256 amountIn, uint256 amountOutMin) public payable {
require(USDT.transferFrom(msg.sender, address(this), amountIn), "transferFrom failed.");
require(USDT.approve(address(router), amountIn), "approve failed.");
address[] memory path = new address[](2);
path[0] = USDT_address;
path[1] = WETH_address;
router.swapExactTokensForETH(amountIn, amountOutMin, path, msg.sender, block.timestamp);
}
}
文件 50 的 72:Timelock.sol
pragma solidity 0.6.11;
import "./SafeMath.sol";
contract Timelock {
using SafeMath for uint;
event NewAdmin(address indexed newAdmin);
event NewPendingAdmin(address indexed newPendingAdmin);
event NewDelay(uint indexed newDelay);
event CancelTransaction(bytes32 indexed txHash, address indexed target, uint value, string signature, bytes data, uint eta);
event ExecuteTransaction(bytes32 indexed txHash, address indexed target, uint value, string signature, bytes data, uint eta);
event QueueTransaction(bytes32 indexed txHash, address indexed target, uint value, string signature, bytes data, uint eta);
uint public constant GRACE_PERIOD = 14 days;
uint public constant MINIMUM_DELAY = 2 days;
uint public constant MAXIMUM_DELAY = 30 days;
address public admin;
address public pendingAdmin;
uint public delay;
mapping (bytes32 => bool) public queuedTransactions;
constructor(address admin_, uint delay_) public {
require(delay_ >= MINIMUM_DELAY, "Timelock::constructor: Delay must exceed minimum delay.");
require(delay_ <= MAXIMUM_DELAY, "Timelock::setDelay: Delay must not exceed maximum delay.");
admin = admin_;
delay = delay_;
}
function setDelay(uint delay_) public {
require(msg.sender == address(this), "Timelock::setDelay: Call must come from Timelock.");
require(delay_ >= MINIMUM_DELAY, "Timelock::setDelay: Delay must exceed minimum delay.");
require(delay_ <= MAXIMUM_DELAY, "Timelock::setDelay: Delay must not exceed maximum delay.");
delay = delay_;
emit NewDelay(delay);
}
function acceptAdmin() public {
require(msg.sender == pendingAdmin, "Timelock::acceptAdmin: Call must come from pendingAdmin.");
admin = msg.sender;
pendingAdmin = address(0);
emit NewAdmin(admin);
}
function setPendingAdmin(address pendingAdmin_) public {
require(msg.sender == address(this), "Timelock::setPendingAdmin: Call must come from Timelock.");
pendingAdmin = pendingAdmin_;
emit NewPendingAdmin(pendingAdmin);
}
function queueTransaction(address target, uint value, string memory signature, bytes memory data, uint eta) public returns (bytes32) {
require(msg.sender == admin, "Timelock::queueTransaction: Call must come from admin.");
require(eta >= getBlockTimestamp().add(delay), "Timelock::queueTransaction: Estimated execution block must satisfy delay.");
bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));
queuedTransactions[txHash] = true;
emit QueueTransaction(txHash, target, value, signature, data, eta);
return txHash;
}
function cancelTransaction(address target, uint value, string memory signature, bytes memory data, uint eta) public {
require(msg.sender == admin, "Timelock::cancelTransaction: Call must come from admin.");
bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));
queuedTransactions[txHash] = false;
emit CancelTransaction(txHash, target, value, signature, data, eta);
}
function executeTransaction(address target, uint value, string memory signature, bytes memory data, uint eta) public payable returns (bytes memory) {
require(msg.sender == admin, "Timelock::executeTransaction: Call must come from admin.");
bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));
require(queuedTransactions[txHash], "Timelock::executeTransaction: Transaction hasn't been queued.");
require(getBlockTimestamp() >= eta, "Timelock::executeTransaction: Transaction hasn't surpassed time lock.");
require(getBlockTimestamp() <= eta.add(GRACE_PERIOD), "Timelock::executeTransaction: Transaction is stale.");
queuedTransactions[txHash] = false;
bytes memory callData;
if (bytes(signature).length == 0) {
callData = data;
} else {
callData = abi.encodePacked(bytes4(keccak256(bytes(signature))), data);
}
(bool success, bytes memory returnData) = target.call{ value: value }(callData);
require(success, "Timelock::executeTransaction: Transaction execution reverted.");
emit ExecuteTransaction(txHash, target, value, signature, data, eta);
return returnData;
}
function getBlockTimestamp() internal view returns (uint) {
return block.timestamp;
}
}
文件 51 的 72:TokenVesting.sol
pragma solidity 0.6.11;
import "./ERC20Custom.sol";
import "./ERC20.sol";
import "./SafeMath.sol";
contract TokenVesting {
using SafeMath for uint256;
event TokensReleased(uint256 amount);
event TokenVestingRevoked();
address private _beneficiary;
address private _owner;
uint256 private _cliff;
uint256 private _start;
uint256 private _duration;
address public _FXS_contract_address;
ERC20 FXS;
address public _timelock_address;
bool public _revocable;
uint256 private _released;
bool public _revoked;
constructor(
address beneficiary,
uint256 start,
uint256 cliffDuration,
uint256 duration,
bool revocable
) public {
require(beneficiary != address(0), "TokenVesting: beneficiary is the zero address");
require(cliffDuration <= duration, "TokenVesting: cliff is longer than duration");
require(duration > 0, "TokenVesting: duration is 0");
require(start.add(duration) > block.timestamp, "TokenVesting: final time is before current time");
_beneficiary = beneficiary;
_revocable = revocable;
_duration = duration;
_cliff = start.add(cliffDuration);
_start = start;
_owner = msg.sender;
}
function setFXSAddress(address FXS_address) public {
require(msg.sender == _owner, "must be set by the owner");
_FXS_contract_address = FXS_address;
FXS = ERC20(FXS_address);
}
function setTimelockAddress(address timelock_address) public {
require(msg.sender == _owner, "must be set by the owner");
_timelock_address = timelock_address;
}
function getBeneficiary() public view returns (address) {
return _beneficiary;
}
function getCliff() public view returns (uint256) {
return _cliff;
}
function getStart() public view returns (uint256) {
return _start;
}
function getDuration() public view returns (uint256) {
return _duration;
}
function getRevocable() public view returns (bool) {
return _revocable;
}
function getReleased() public view returns (uint256) {
return _released;
}
function getRevoked() public view returns (bool) {
return _revoked;
}
function release() public {
require(msg.sender == _beneficiary, "must be the beneficiary to release tokens");
uint256 unreleased = _releasableAmount();
require(unreleased > 0, "TokenVesting: no tokens are due");
_released = _released.add(unreleased);
FXS.transfer(_beneficiary, unreleased);
emit TokensReleased(unreleased);
}
function revoke() public {
require(msg.sender == _timelock_address, "Must be called by the timelock contract");
require(_revocable, "TokenVesting: cannot revoke");
require(!_revoked, "TokenVesting: token already revoked");
uint256 balance = FXS.balanceOf(address(this));
uint256 unreleased = _releasableAmount();
uint256 refund = balance.sub(unreleased);
_revoked = true;
FXS.transfer(_owner, refund);
emit TokenVestingRevoked();
}
function recoverERC20(address tokenAddress, uint256 tokenAmount) external {
require(msg.sender == _beneficiary, "Must be called by the beneficiary");
require(tokenAddress != _FXS_contract_address, "Cannot withdraw the FXS through this function");
ERC20(tokenAddress).transfer(_beneficiary, tokenAmount);
}
function _releasableAmount() private view returns (uint256) {
return _vestedAmount().sub(_released);
}
function _vestedAmount() private view returns (uint256) {
uint256 currentBalance = FXS.balanceOf(address(this));
uint256 totalBalance = currentBalance.add(_released);
if (block.timestamp < _cliff) {
return 0;
} else if (block.timestamp >= _start.add(_duration) || _revoked) {
return totalBalance;
} else {
return totalBalance.mul(block.timestamp.sub(_start)).div(_duration);
}
}
uint256[44] private __gap;
}
文件 52 的 72:TransferHelper.sol
pragma solidity 0.6.11;
library TransferHelper {
function safeApprove(address token, address to, uint value) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: APPROVE_FAILED');
}
function safeTransfer(address token, address to, uint value) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FAILED');
}
function safeTransferFrom(address token, address from, address to, uint value) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FROM_FAILED');
}
function safeTransferETH(address to, uint value) internal {
(bool success,) = to.call{value:value}(new bytes(0));
require(success, 'TransferHelper: ETH_TRANSFER_FAILED');
}
}
文件 53 的 72:UQ112x112.sol
pragma solidity 0.6.11;
library UQ112x112 {
uint224 constant Q112 = 2**112;
function encode(uint112 y) internal pure returns (uint224 z) {
z = uint224(y) * Q112;
}
function uqdiv(uint224 x, uint112 y) internal pure returns (uint224 z) {
z = x / uint224(y);
}
}
文件 54 的 72:UniswapPairOracle.sol
pragma solidity 0.6.11;
import './IUniswapV2Factory.sol';
import './IUniswapV2Pair.sol';
import './FixedPoint.sol';
import './UniswapV2OracleLibrary.sol';
import './UniswapV2Library.sol';
contract UniswapPairOracle {
using FixedPoint for *;
address owner_address;
address timelock_address;
uint public PERIOD = 3600;
uint public CONSULT_LENIENCY = 120;
bool public ALLOW_STALE_CONSULTS = false;
IUniswapV2Pair public immutable pair;
address public immutable token0;
address public immutable token1;
uint public price0CumulativeLast;
uint public price1CumulativeLast;
uint32 public blockTimestampLast;
FixedPoint.uq112x112 public price0Average;
FixedPoint.uq112x112 public price1Average;
modifier onlyByOwnerOrGovernance() {
require(msg.sender == owner_address || msg.sender == timelock_address, "You are not an owner or the governance timelock");
_;
}
constructor(address factory, address tokenA, address tokenB, address _owner_address, address _timelock_address) public {
IUniswapV2Pair _pair = IUniswapV2Pair(UniswapV2Library.pairFor(factory, tokenA, tokenB));
pair = _pair;
token0 = _pair.token0();
token1 = _pair.token1();
price0CumulativeLast = _pair.price0CumulativeLast();
price1CumulativeLast = _pair.price1CumulativeLast();
uint112 reserve0;
uint112 reserve1;
(reserve0, reserve1, blockTimestampLast) = _pair.getReserves();
require(reserve0 != 0 && reserve1 != 0, 'UniswapPairOracle: NO_RESERVES');
owner_address = _owner_address;
timelock_address = _timelock_address;
}
function setOwner(address _owner_address) external onlyByOwnerOrGovernance {
owner_address = _owner_address;
}
function setTimelock(address _timelock_address) external onlyByOwnerOrGovernance {
timelock_address = _timelock_address;
}
function setPeriod(uint _period) external onlyByOwnerOrGovernance {
PERIOD = _period;
}
function setConsultLeniency(uint _consult_leniency) external onlyByOwnerOrGovernance {
CONSULT_LENIENCY = _consult_leniency;
}
function setAllowStaleConsults(bool _allow_stale_consults) external onlyByOwnerOrGovernance {
ALLOW_STALE_CONSULTS = _allow_stale_consults;
}
function canUpdate() public view returns (bool) {
uint32 blockTimestamp = UniswapV2OracleLibrary.currentBlockTimestamp();
uint32 timeElapsed = blockTimestamp - blockTimestampLast;
return (timeElapsed >= PERIOD);
}
function update() external {
(uint price0Cumulative, uint price1Cumulative, uint32 blockTimestamp) =
UniswapV2OracleLibrary.currentCumulativePrices(address(pair));
uint32 timeElapsed = blockTimestamp - blockTimestampLast;
require(timeElapsed >= PERIOD, 'UniswapPairOracle: PERIOD_NOT_ELAPSED');
price0Average = FixedPoint.uq112x112(uint224((price0Cumulative - price0CumulativeLast) / timeElapsed));
price1Average = FixedPoint.uq112x112(uint224((price1Cumulative - price1CumulativeLast) / timeElapsed));
price0CumulativeLast = price0Cumulative;
price1CumulativeLast = price1Cumulative;
blockTimestampLast = blockTimestamp;
}
function consult(address token, uint amountIn) external view returns (uint amountOut) {
uint32 blockTimestamp = UniswapV2OracleLibrary.currentBlockTimestamp();
uint32 timeElapsed = blockTimestamp - blockTimestampLast;
require((timeElapsed < (PERIOD + CONSULT_LENIENCY)) || ALLOW_STALE_CONSULTS, 'UniswapPairOracle: PRICE_IS_STALE_NEED_TO_CALL_UPDATE');
if (token == token0) {
amountOut = price0Average.mul(amountIn).decode144();
} else {
require(token == token1, 'UniswapPairOracle: INVALID_TOKEN');
amountOut = price1Average.mul(amountIn).decode144();
}
}
}
文件 55 的 72:UniswapPairOracle_FRAX_FXS.sol
pragma solidity 0.6.11;
import './UniswapPairOracle.sol';
contract UniswapPairOracle_FRAX_FXS is UniswapPairOracle {
constructor(address factory, address tokenA, address tokenB, address owner_address, address timelock_address)
UniswapPairOracle(factory, tokenA, tokenB, owner_address, timelock_address)
public {}
}
文件 56 的 72:UniswapPairOracle_FRAX_USDC.sol
pragma solidity 0.6.11;
import './UniswapPairOracle.sol';
contract UniswapPairOracle_FRAX_USDC is UniswapPairOracle {
constructor(address factory, address tokenA, address tokenB, address owner_address, address timelock_address)
UniswapPairOracle(factory, tokenA, tokenB, owner_address, timelock_address)
public {}
}
文件 57 的 72:UniswapPairOracle_FRAX_USDT.sol
pragma solidity 0.6.11;
import './UniswapPairOracle.sol';
contract UniswapPairOracle_FRAX_USDT is UniswapPairOracle {
constructor(address factory, address tokenA, address tokenB, address owner_address, address timelock_address)
UniswapPairOracle(factory, tokenA, tokenB, owner_address, timelock_address)
public {}
}
文件 58 的 72:UniswapPairOracle_FRAX_WETH.sol
pragma solidity 0.6.11;
import './UniswapPairOracle.sol';
contract UniswapPairOracle_FRAX_WETH is UniswapPairOracle {
constructor(address factory, address tokenA, address tokenB, address owner_address, address timelock_address)
UniswapPairOracle(factory, tokenA, tokenB, owner_address, timelock_address)
public {}
}
文件 59 的 72:UniswapPairOracle_FXS_USDC.sol
pragma solidity 0.6.11;
import './UniswapPairOracle.sol';
contract UniswapPairOracle_FXS_USDC is UniswapPairOracle {
constructor(address factory, address tokenA, address tokenB, address owner_address, address timelock_address)
UniswapPairOracle(factory, tokenA, tokenB, owner_address, timelock_address)
public {}
}
文件 60 的 72:UniswapPairOracle_FXS_USDT.sol
pragma solidity 0.6.11;
import './UniswapPairOracle.sol';
contract UniswapPairOracle_FXS_USDT is UniswapPairOracle {
constructor(address factory, address tokenA, address tokenB, address owner_address, address timelock_address)
UniswapPairOracle(factory, tokenA, tokenB, owner_address, timelock_address)
public {}
}
文件 61 的 72:UniswapPairOracle_FXS_WETH.sol
pragma solidity 0.6.11;
import './UniswapPairOracle.sol';
contract UniswapPairOracle_FXS_WETH is UniswapPairOracle {
constructor(address factory, address tokenA, address tokenB, address owner_address, address timelock_address)
UniswapPairOracle(factory, tokenA, tokenB, owner_address, timelock_address)
public {}
}
文件 62 的 72:UniswapPairOracle_OLD.sol
pragma solidity 0.6.11;
import './IUniswapV2Factory.sol';
import './IUniswapV2Pair.sol';
import './FixedPoint.sol';
import './UniswapV2OracleLibrary.sol';
import './UniswapV2Library.sol';
contract UniswapPairOracle_OLD {
using FixedPoint for *;
address owner_address;
address timelock_address;
uint public PERIOD = 3600;
IUniswapV2Pair public immutable pair;
address public immutable token0;
address public immutable token1;
uint public price0CumulativeLast;
uint public price1CumulativeLast;
uint32 public blockTimestampLast;
FixedPoint.uq112x112 public price0Average;
FixedPoint.uq112x112 public price1Average;
modifier onlyByOwnerOrGovernance() {
require(msg.sender == owner_address || msg.sender == timelock_address, "You are not an owner or the governance timelock");
_;
}
constructor(address factory, address tokenA, address tokenB, address _owner_address, address _timelock_address) public {
IUniswapV2Pair _pair = IUniswapV2Pair(UniswapV2Library.pairFor(factory, tokenA, tokenB));
pair = _pair;
token0 = _pair.token0();
token1 = _pair.token1();
price0CumulativeLast = _pair.price0CumulativeLast();
price1CumulativeLast = _pair.price1CumulativeLast();
uint112 reserve0;
uint112 reserve1;
(reserve0, reserve1, blockTimestampLast) = _pair.getReserves();
require(reserve0 != 0 && reserve1 != 0, 'UniswapPairOracle: NO_RESERVES');
owner_address = _owner_address;
timelock_address = _timelock_address;
}
function setOwner(address _owner_address) external onlyByOwnerOrGovernance {
owner_address = _owner_address;
}
function setTimelock(address _timelock_address) external onlyByOwnerOrGovernance {
timelock_address = _timelock_address;
}
function setPeriod(uint _period) external onlyByOwnerOrGovernance {
PERIOD = _period;
}
function update() external {
(uint price0Cumulative, uint price1Cumulative, uint32 blockTimestamp) =
UniswapV2OracleLibrary.currentCumulativePrices(address(pair));
uint32 timeElapsed = blockTimestamp - blockTimestampLast;
require(timeElapsed >= PERIOD, 'UniswapPairOracle: PERIOD_NOT_ELAPSED');
price0Average = FixedPoint.uq112x112(uint224((price0Cumulative - price0CumulativeLast) / timeElapsed));
price1Average = FixedPoint.uq112x112(uint224((price1Cumulative - price1CumulativeLast) / timeElapsed));
price0CumulativeLast = price0Cumulative;
price1CumulativeLast = price1Cumulative;
blockTimestampLast = blockTimestamp;
}
function consult(address token, uint amountIn) external view returns (uint amountOut) {
if (token == token0) {
amountOut = price0Average.mul(amountIn).decode144();
} else {
require(token == token1, 'UniswapPairOracle: INVALID_TOKEN');
amountOut = price1Average.mul(amountIn).decode144();
}
}
}
文件 63 的 72:UniswapPairOracle_USDC_WETH.sol
pragma solidity 0.6.11;
import './UniswapPairOracle.sol';
contract UniswapPairOracle_USDC_WETH is UniswapPairOracle {
constructor(address factory, address tokenA, address tokenB, address owner_address, address timelock_address)
UniswapPairOracle(factory, tokenA, tokenB, owner_address, timelock_address)
public {}
}
文件 64 的 72:UniswapPairOracle_USDT_WETH.sol
pragma solidity 0.6.11;
import './UniswapPairOracle.sol';
contract UniswapPairOracle_USDT_WETH is UniswapPairOracle {
constructor(address factory, address tokenA, address tokenB, address owner_address, address timelock_address)
UniswapPairOracle(factory, tokenA, tokenB, owner_address, timelock_address)
public {}
}
文件 65 的 72:UniswapV2ERC20.sol
pragma solidity 0.6.11;
import './IUniswapV2ERC20.sol';
import './SafeMath.sol';
contract UniswapV2ERC20 is IUniswapV2ERC20 {
using SafeMath for uint;
string public override constant name = 'Uniswap V2';
string public override constant symbol = 'UNI-V2';
uint8 public override constant decimals = 18;
uint public override totalSupply;
mapping(address => uint) public override balanceOf;
mapping(address => mapping(address => uint)) public override allowance;
bytes32 public override DOMAIN_SEPARATOR;
bytes32 public constant override PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
mapping(address => uint) public override nonces;
event Approval(address indexed owner, address indexed spender, uint value);
event Transfer(address indexed from, address indexed to, uint value);
constructor() public {
uint 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')),
chainId,
address(this)
)
);
}
function _mint(address to, uint value) internal {
totalSupply = totalSupply.add(value);
balanceOf[to] = balanceOf[to].add(value);
emit Transfer(address(0), to, value);
}
function _burn(address from, uint value) internal {
balanceOf[from] = balanceOf[from].sub(value);
totalSupply = totalSupply.sub(value);
emit Transfer(from, address(0), value);
}
function _approve(address owner, address spender, uint value) private {
allowance[owner][spender] = value;
emit Approval(owner, spender, value);
}
function _transfer(address from, address to, uint value) private {
balanceOf[from] = balanceOf[from].sub(value);
balanceOf[to] = balanceOf[to].add(value);
emit Transfer(from, to, value);
}
function approve(address spender, uint value) external override returns (bool) {
_approve(msg.sender, spender, value);
return true;
}
function transfer(address to, uint value) external override returns (bool) {
_transfer(msg.sender, to, value);
return true;
}
function transferFrom(address from, address to, uint value) external override returns (bool) {
if (allowance[from][msg.sender] != uint(-1)) {
allowance[from][msg.sender] = allowance[from][msg.sender].sub(value);
}
_transfer(from, to, value);
return true;
}
function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external override {
require(deadline >= block.timestamp, 'UniswapV2: EXPIRED');
bytes32 digest = keccak256(
abi.encodePacked(
'\x19\x01',
DOMAIN_SEPARATOR,
keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))
)
);
address recoveredAddress = ecrecover(digest, v, r, s);
require(recoveredAddress != address(0) && recoveredAddress == owner, 'UniswapV2: INVALID_SIGNATURE');
_approve(owner, spender, value);
}
}
文件 66 的 72:UniswapV2Factory.sol
pragma solidity 0.6.11;
import './IUniswapV2Factory.sol';
import './UniswapV2Pair.sol';
contract UniswapV2Factory is IUniswapV2Factory {
address public override feeTo;
address public override feeToSetter;
mapping(address => mapping(address => address)) public override getPair;
address[] public override allPairs;
event PairCreated(address indexed token0, address indexed token1, address pair, uint);
constructor(address _feeToSetter) public {
feeToSetter = _feeToSetter;
}
function allPairsLength() external override view returns (uint) {
return allPairs.length;
}
function createPair(address tokenA, address tokenB) external override returns (address pair) {
require(tokenA != tokenB, 'UniswapV2: IDENTICAL_ADDRESSES');
(address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
require(token0 != address(0), 'UniswapV2: ZERO_ADDRESS');
require(getPair[token0][token1] == address(0), 'UniswapV2: PAIR_EXISTS');
bytes memory bytecode = type(UniswapV2Pair).creationCode;
bytes32 salt = keccak256(abi.encodePacked(token0, token1));
assembly {
pair := create2(0, add(bytecode, 32), mload(bytecode), salt)
}
IUniswapV2Pair(pair).initialize(token0, token1);
getPair[token0][token1] = pair;
getPair[token1][token0] = pair;
allPairs.push(pair);
emit PairCreated(token0, token1, pair, allPairs.length);
}
function setFeeTo(address _feeTo) external override {
require(msg.sender == feeToSetter, 'UniswapV2: FORBIDDEN');
feeTo = _feeTo;
}
function setFeeToSetter(address _feeToSetter) external override {
require(msg.sender == feeToSetter, 'UniswapV2: FORBIDDEN');
feeToSetter = _feeToSetter;
}
}
文件 67 的 72:UniswapV2Library.sol
pragma solidity 0.6.11;
import './IUniswapV2Pair.sol';
import './IUniswapV2Factory.sol';
import "./SafeMath.sol";
library UniswapV2Library {
using SafeMath for uint;
function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) {
require(tokenA != tokenB, 'UniswapV2Library: IDENTICAL_ADDRESSES');
(token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
require(token0 != address(0), 'UniswapV2Library: ZERO_ADDRESS');
}
function pairFor(address factory, address tokenA, address tokenB) internal view returns (address pair) {
(address token0, address token1) = sortTokens(tokenA, tokenB);
pair = IUniswapV2Factory(factory).getPair(token0, token1);
}
function pairForCreate2(address factory, address tokenA, address tokenB) internal pure returns (address pair) {
(address token0, address token1) = sortTokens(tokenA, tokenB);
pair = address(uint(keccak256(abi.encodePacked(
hex'ff',
factory,
keccak256(abi.encodePacked(token0, token1)),
hex'96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f'
))));
}
function getReserves(address factory, address tokenA, address tokenB) internal view returns (uint reserveA, uint reserveB) {
(address token0,) = sortTokens(tokenA, tokenB);
(uint reserve0, uint reserve1,) = IUniswapV2Pair(pairFor(factory, tokenA, tokenB)).getReserves();
(reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
}
function quote(uint amountA, uint reserveA, uint reserveB) internal pure returns (uint amountB) {
require(amountA > 0, 'UniswapV2Library: INSUFFICIENT_AMOUNT');
require(reserveA > 0 && reserveB > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY');
amountB = amountA.mul(reserveB) / reserveA;
}
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) internal pure returns (uint amountOut) {
require(amountIn > 0, 'UniswapV2Library: INSUFFICIENT_INPUT_AMOUNT');
require(reserveIn > 0 && reserveOut > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY');
uint amountInWithFee = amountIn.mul(997);
uint numerator = amountInWithFee.mul(reserveOut);
uint denominator = reserveIn.mul(1000).add(amountInWithFee);
amountOut = numerator / denominator;
}
function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) internal pure returns (uint amountIn) {
require(amountOut > 0, 'UniswapV2Library: INSUFFICIENT_OUTPUT_AMOUNT');
require(reserveIn > 0 && reserveOut > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY');
uint numerator = reserveIn.mul(amountOut).mul(1000);
uint denominator = reserveOut.sub(amountOut).mul(997);
amountIn = (numerator / denominator).add(1);
}
function getAmountsOut(address factory, uint amountIn, address[] memory path) internal view returns (uint[] memory amounts) {
require(path.length >= 2, 'UniswapV2Library: INVALID_PATH');
amounts = new uint[](path.length);
amounts[0] = amountIn;
for (uint i; i < path.length - 1; i++) {
(uint reserveIn, uint reserveOut) = getReserves(factory, path[i], path[i + 1]);
amounts[i + 1] = getAmountOut(amounts[i], reserveIn, reserveOut);
}
}
function getAmountsIn(address factory, uint amountOut, address[] memory path) internal view returns (uint[] memory amounts) {
require(path.length >= 2, 'UniswapV2Library: INVALID_PATH');
amounts = new uint[](path.length);
amounts[amounts.length - 1] = amountOut;
for (uint i = path.length - 1; i > 0; i--) {
(uint reserveIn, uint reserveOut) = getReserves(factory, path[i - 1], path[i]);
amounts[i - 1] = getAmountIn(amounts[i], reserveIn, reserveOut);
}
}
}
文件 68 的 72:UniswapV2OracleLibrary.sol
pragma solidity 0.6.11;
import './IUniswapV2Pair.sol';
import './FixedPoint.sol';
library UniswapV2OracleLibrary {
using FixedPoint for *;
function currentBlockTimestamp() internal view returns (uint32) {
return uint32(block.timestamp % 2 ** 32);
}
function currentCumulativePrices(
address pair
) internal view returns (uint price0Cumulative, uint price1Cumulative, uint32 blockTimestamp) {
blockTimestamp = currentBlockTimestamp();
price0Cumulative = IUniswapV2Pair(pair).price0CumulativeLast();
price1Cumulative = IUniswapV2Pair(pair).price1CumulativeLast();
(uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast) = IUniswapV2Pair(pair).getReserves();
if (blockTimestampLast != blockTimestamp) {
uint32 timeElapsed = blockTimestamp - blockTimestampLast;
price0Cumulative += uint(FixedPoint.fraction(reserve1, reserve0)._x) * timeElapsed;
price1Cumulative += uint(FixedPoint.fraction(reserve0, reserve1)._x) * timeElapsed;
}
}
}
文件 69 的 72:UniswapV2Pair.sol
pragma solidity 0.6.11;
import './IUniswapV2Pair.sol';
import './UniswapV2ERC20.sol';
import './Math.sol';
import './UQ112x112.sol';
import './IERC20.sol';
import './IUniswapV2Factory.sol';
import './IUniswapV2Callee.sol';
contract UniswapV2Pair is IUniswapV2Pair {
using SafeMath for uint;
using UQ112x112 for uint224;
string public override constant name = 'Uniswap V2';
string public override constant symbol = 'UNI-V2';
uint8 public override constant decimals = 18;
uint public override totalSupply;
mapping(address => uint) public override balanceOf;
mapping(address => mapping(address => uint)) public override allowance;
uint public override constant MINIMUM_LIQUIDITY = 10**3;
bytes4 private constant SELECTOR = bytes4(keccak256(bytes('transfer(address,uint256)')));
bytes32 public override DOMAIN_SEPARATOR;
bytes32 public constant override PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
mapping(address => uint) public override nonces;
address public override factory;
address public override token0;
address public override token1;
uint112 private reserve0;
uint112 private reserve1;
uint32 private blockTimestampLast;
uint public override price0CumulativeLast;
uint public override price1CumulativeLast;
uint public override kLast;
uint private unlocked = 1;
modifier lock() {
require(unlocked == 1, 'UniswapV2: LOCKED');
unlocked = 0;
_;
unlocked = 1;
}
function getReserves() public override view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast) {
_reserve0 = reserve0;
_reserve1 = reserve1;
_blockTimestampLast = blockTimestampLast;
}
function _safeTransfer(address token, address to, uint value) private {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(SELECTOR, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'UniswapV2: TRANSFER_FAILED');
}
event Mint(address indexed sender, uint amount0, uint amount1);
event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
event Swap(
address indexed sender,
uint amount0In,
uint amount1In,
uint amount0Out,
uint amount1Out,
address indexed to
);
event Sync(uint112 reserve0, uint112 reserve1);
constructor() public {
factory = msg.sender;
}
function initialize(address _token0, address _token1) external override {
require(msg.sender == factory, 'UniswapV2: FORBIDDEN');
token0 = _token0;
token1 = _token1;
}
function _update(uint balance0, uint balance1, uint112 _reserve0, uint112 _reserve1) private {
require(balance0 <= uint112(-1) && balance1 <= uint112(-1), 'UniswapV2: OVERFLOW');
uint32 blockTimestamp = uint32(block.timestamp % 2**32);
uint32 timeElapsed = blockTimestamp - blockTimestampLast;
if (timeElapsed > 0 && _reserve0 != 0 && _reserve1 != 0) {
price0CumulativeLast += uint(UQ112x112.encode(_reserve1).uqdiv(_reserve0)) * timeElapsed;
price1CumulativeLast += uint(UQ112x112.encode(_reserve0).uqdiv(_reserve1)) * timeElapsed;
}
reserve0 = uint112(balance0);
reserve1 = uint112(balance1);
blockTimestampLast = blockTimestamp;
emit Sync(reserve0, reserve1);
}
function _mintFee(uint112 _reserve0, uint112 _reserve1) private returns (bool feeOn) {
address feeTo = IUniswapV2Factory(factory).feeTo();
feeOn = feeTo != address(0);
uint _kLast = kLast;
if (feeOn) {
if (_kLast != 0) {
uint rootK = Math.sqrt(uint(_reserve0).mul(_reserve1));
uint rootKLast = Math.sqrt(_kLast);
if (rootK > rootKLast) {
uint numerator = totalSupply.mul(rootK.sub(rootKLast));
uint denominator = rootK.mul(5).add(rootKLast);
uint liquidity = numerator / denominator;
if (liquidity > 0) _mint(feeTo, liquidity);
}
}
} else if (_kLast != 0) {
kLast = 0;
}
}
function mint(address to) external override lock returns (uint liquidity) {
(uint112 _reserve0, uint112 _reserve1,) = getReserves();
uint balance0 = IERC20(token0).balanceOf(address(this));
uint balance1 = IERC20(token1).balanceOf(address(this));
uint amount0 = balance0.sub(_reserve0);
uint amount1 = balance1.sub(_reserve1);
bool feeOn = _mintFee(_reserve0, _reserve1);
uint _totalSupply = totalSupply;
if (_totalSupply == 0) {
liquidity = Math.sqrt(amount0.mul(amount1)).sub(MINIMUM_LIQUIDITY);
_mint(address(0), MINIMUM_LIQUIDITY);
} else {
liquidity = Math.min(amount0.mul(_totalSupply) / _reserve0, amount1.mul(_totalSupply) / _reserve1);
}
require(liquidity > 0, 'UniswapV2: INSUFFICIENT_LIQUIDITY_MINTED');
_mint(to, liquidity);
_update(balance0, balance1, _reserve0, _reserve1);
if (feeOn) kLast = uint(reserve0).mul(reserve1);
emit Mint(msg.sender, amount0, amount1);
}
function burn(address to) external override lock returns (uint amount0, uint amount1) {
(uint112 _reserve0, uint112 _reserve1,) = getReserves();
address _token0 = token0;
address _token1 = token1;
uint balance0 = IERC20(_token0).balanceOf(address(this));
uint balance1 = IERC20(_token1).balanceOf(address(this));
uint liquidity = balanceOf[address(this)];
bool feeOn = _mintFee(_reserve0, _reserve1);
uint _totalSupply = totalSupply;
amount0 = liquidity.mul(balance0) / _totalSupply;
amount1 = liquidity.mul(balance1) / _totalSupply;
require(amount0 > 0 && amount1 > 0, 'UniswapV2: INSUFFICIENT_LIQUIDITY_BURNED');
_burn(address(this), liquidity);
_safeTransfer(_token0, to, amount0);
_safeTransfer(_token1, to, amount1);
balance0 = IERC20(_token0).balanceOf(address(this));
balance1 = IERC20(_token1).balanceOf(address(this));
_update(balance0, balance1, _reserve0, _reserve1);
if (feeOn) kLast = uint(reserve0).mul(reserve1);
emit Burn(msg.sender, amount0, amount1, to);
}
function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external override lock {
require(amount0Out > 0 || amount1Out > 0, 'UniswapV2: INSUFFICIENT_OUTPUT_AMOUNT');
(uint112 _reserve0, uint112 _reserve1,) = getReserves();
require(amount0Out < _reserve0 && amount1Out < _reserve1, 'UniswapV2: INSUFFICIENT_LIQUIDITY');
uint balance0;
uint balance1;
{
address _token0 = token0;
address _token1 = token1;
require(to != _token0 && to != _token1, 'UniswapV2: INVALID_TO');
if (amount0Out > 0) _safeTransfer(_token0, to, amount0Out);
if (amount1Out > 0) _safeTransfer(_token1, to, amount1Out);
if (data.length > 0) IUniswapV2Callee(to).uniswapV2Call(msg.sender, amount0Out, amount1Out, data);
balance0 = IERC20(_token0).balanceOf(address(this));
balance1 = IERC20(_token1).balanceOf(address(this));
}
uint amount0In = balance0 > _reserve0 - amount0Out ? balance0 - (_reserve0 - amount0Out) : 0;
uint amount1In = balance1 > _reserve1 - amount1Out ? balance1 - (_reserve1 - amount1Out) : 0;
require(amount0In > 0 || amount1In > 0, 'UniswapV2: INSUFFICIENT_INPUT_AMOUNT');
{
uint balance0Adjusted = balance0.mul(1000).sub(amount0In.mul(3));
uint balance1Adjusted = balance1.mul(1000).sub(amount1In.mul(3));
require(balance0Adjusted.mul(balance1Adjusted) >= uint(_reserve0).mul(_reserve1).mul(1000**2), 'UniswapV2: K');
}
_update(balance0, balance1, _reserve0, _reserve1);
emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to);
}
function skim(address to) external override lock {
address _token0 = token0;
address _token1 = token1;
_safeTransfer(_token0, to, IERC20(_token0).balanceOf(address(this)).sub(reserve0));
_safeTransfer(_token1, to, IERC20(_token1).balanceOf(address(this)).sub(reserve1));
}
function sync() external override lock {
_update(IERC20(token0).balanceOf(address(this)), IERC20(token1).balanceOf(address(this)), reserve0, reserve1);
}
function _mint(address to, uint value) internal {
totalSupply = totalSupply.add(value);
balanceOf[to] = balanceOf[to].add(value);
emit Transfer(address(0), to, value);
}
function _burn(address from, uint value) internal {
balanceOf[from] = balanceOf[from].sub(value);
totalSupply = totalSupply.sub(value);
emit Transfer(from, address(0), value);
}
function _approve(address owner, address spender, uint value) private {
allowance[owner][spender] = value;
emit Approval(owner, spender, value);
}
function _transfer(address from, address to, uint value) private {
balanceOf[from] = balanceOf[from].sub(value);
balanceOf[to] = balanceOf[to].add(value);
emit Transfer(from, to, value);
}
function approve(address spender, uint value) external override returns (bool) {
_approve(msg.sender, spender, value);
return true;
}
function transfer(address to, uint value) external override returns (bool) {
_transfer(msg.sender, to, value);
return true;
}
function transferFrom(address from, address to, uint value) external override returns (bool) {
if (allowance[from][msg.sender] != uint(-1)) {
allowance[from][msg.sender] = allowance[from][msg.sender].sub(value);
}
_transfer(from, to, value);
return true;
}
function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external override {
require(deadline >= block.timestamp, 'UniswapV2: EXPIRED');
bytes32 digest = keccak256(
abi.encodePacked(
'\x19\x01',
DOMAIN_SEPARATOR,
keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))
)
);
address recoveredAddress = ecrecover(digest, v, r, s);
require(recoveredAddress != address(0) && recoveredAddress == owner, 'UniswapV2: INVALID_SIGNATURE');
_approve(owner, spender, value);
}
}
文件 70 的 72:UniswapV2Router02.sol
pragma solidity 0.6.11;
import './IUniswapV2Factory.sol';
import './TransferHelper.sol';
import './IUniswapV2Router02.sol';
import './UniswapV2Library.sol';
import './SafeMath.sol';
import './IERC20.sol';
import './IWETH.sol';
contract UniswapV2Router02 is IUniswapV2Router02 {
using SafeMath for uint;
address public immutable override factory;
address public immutable override WETH;
modifier ensure(uint deadline) {
require(deadline >= block.timestamp, 'UniswapV2Router: EXPIRED');
_;
}
constructor(address _factory, address _WETH) public {
factory = _factory;
WETH = _WETH;
}
receive() external payable {
assert(msg.sender == WETH);
}
function _addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin
) internal virtual returns (uint amountA, uint amountB) {
if (IUniswapV2Factory(factory).getPair(tokenA, tokenB) == address(0)) {
IUniswapV2Factory(factory).createPair(tokenA, tokenB);
}
(uint reserveA, uint reserveB) = UniswapV2Library.getReserves(factory, tokenA, tokenB);
if (reserveA == 0 && reserveB == 0) {
(amountA, amountB) = (amountADesired, amountBDesired);
} else {
uint amountBOptimal = UniswapV2Library.quote(amountADesired, reserveA, reserveB);
if (amountBOptimal <= amountBDesired) {
require(amountBOptimal >= amountBMin, 'UniswapV2Router: INSUFFICIENT_B_AMOUNT');
(amountA, amountB) = (amountADesired, amountBOptimal);
} else {
uint amountAOptimal = UniswapV2Library.quote(amountBDesired, reserveB, reserveA);
assert(amountAOptimal <= amountADesired);
require(amountAOptimal >= amountAMin, 'UniswapV2Router: INSUFFICIENT_A_AMOUNT');
(amountA, amountB) = (amountAOptimal, amountBDesired);
}
}
}
function addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external virtual override ensure(deadline) returns (uint amountA, uint amountB, uint liquidity) {
(amountA, amountB) = _addLiquidity(tokenA, tokenB, amountADesired, amountBDesired, amountAMin, amountBMin);
address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB);
TransferHelper.safeTransferFrom(tokenA, msg.sender, pair, amountA);
TransferHelper.safeTransferFrom(tokenB, msg.sender, pair, amountB);
liquidity = IUniswapV2Pair(pair).mint(to);
}
function addLiquidityETH(
address token,
uint amountTokenDesired,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external virtual override payable ensure(deadline) returns (uint amountToken, uint amountETH, uint liquidity) {
(amountToken, amountETH) = _addLiquidity(
token,
WETH,
amountTokenDesired,
msg.value,
amountTokenMin,
amountETHMin
);
address pair = UniswapV2Library.pairFor(factory, token, WETH);
TransferHelper.safeTransferFrom(token, msg.sender, pair, amountToken);
IWETH(WETH).deposit{value: amountETH}();
assert(IWETH(WETH).transfer(pair, amountETH));
liquidity = IUniswapV2Pair(pair).mint(to);
if (msg.value > amountETH) TransferHelper.safeTransferETH(msg.sender, msg.value - amountETH);
}
function removeLiquidity(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) public virtual override ensure(deadline) returns (uint amountA, uint amountB) {
address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB);
IUniswapV2Pair(pair).transferFrom(msg.sender, pair, liquidity);
(uint amount0, uint amount1) = IUniswapV2Pair(pair).burn(to);
(address token0,) = UniswapV2Library.sortTokens(tokenA, tokenB);
(amountA, amountB) = tokenA == token0 ? (amount0, amount1) : (amount1, amount0);
require(amountA >= amountAMin, 'UniswapV2Router: INSUFFICIENT_A_AMOUNT');
require(amountB >= amountBMin, 'UniswapV2Router: INSUFFICIENT_B_AMOUNT');
}
function removeLiquidityETH(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) public virtual override ensure(deadline) returns (uint amountToken, uint amountETH) {
(amountToken, amountETH) = removeLiquidity(
token,
WETH,
liquidity,
amountTokenMin,
amountETHMin,
address(this),
deadline
);
TransferHelper.safeTransfer(token, to, amountToken);
IWETH(WETH).withdraw(amountETH);
TransferHelper.safeTransferETH(to, amountETH);
}
function removeLiquidityWithPermit(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external virtual override returns (uint amountA, uint amountB) {
address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB);
uint value = approveMax ? uint(-1) : liquidity;
IUniswapV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
(amountA, amountB) = removeLiquidity(tokenA, tokenB, liquidity, amountAMin, amountBMin, to, deadline);
}
function removeLiquidityETHWithPermit(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external virtual override returns (uint amountToken, uint amountETH) {
address pair = UniswapV2Library.pairFor(factory, token, WETH);
uint value = approveMax ? uint(-1) : liquidity;
IUniswapV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
(amountToken, amountETH) = removeLiquidityETH(token, liquidity, amountTokenMin, amountETHMin, to, deadline);
}
function removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) public virtual override ensure(deadline) returns (uint amountETH) {
(, amountETH) = removeLiquidity(
token,
WETH,
liquidity,
amountTokenMin,
amountETHMin,
address(this),
deadline
);
TransferHelper.safeTransfer(token, to, IERC20(token).balanceOf(address(this)));
IWETH(WETH).withdraw(amountETH);
TransferHelper.safeTransferETH(to, amountETH);
}
function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external virtual override returns (uint amountETH) {
address pair = UniswapV2Library.pairFor(factory, token, WETH);
uint value = approveMax ? uint(-1) : liquidity;
IUniswapV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
amountETH = removeLiquidityETHSupportingFeeOnTransferTokens(
token, liquidity, amountTokenMin, amountETHMin, to, deadline
);
}
function _swap(uint[] memory amounts, address[] memory path, address _to) internal virtual {
for (uint i; i < path.length - 1; i++) {
(address input, address output) = (path[i], path[i + 1]);
(address token0,) = UniswapV2Library.sortTokens(input, output);
uint amountOut = amounts[i + 1];
(uint amount0Out, uint amount1Out) = input == token0 ? (uint(0), amountOut) : (amountOut, uint(0));
address to = i < path.length - 2 ? UniswapV2Library.pairFor(factory, output, path[i + 2]) : _to;
IUniswapV2Pair(UniswapV2Library.pairFor(factory, input, output)).swap(
amount0Out, amount1Out, to, new bytes(0)
);
}
}
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external virtual override ensure(deadline) returns (uint[] memory amounts) {
amounts = UniswapV2Library.getAmountsOut(factory, amountIn, path);
require(amounts[amounts.length - 1] >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
TransferHelper.safeTransferFrom(
path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]
);
_swap(amounts, path, to);
}
function swapTokensForExactTokens(
uint amountOut,
uint amountInMax,
address[] calldata path,
address to,
uint deadline
) external virtual override ensure(deadline) returns (uint[] memory amounts) {
amounts = UniswapV2Library.getAmountsIn(factory, amountOut, path);
require(amounts[0] <= amountInMax, 'UniswapV2Router: EXCESSIVE_INPUT_AMOUNT');
TransferHelper.safeTransferFrom(
path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]
);
_swap(amounts, path, to);
}
function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
external
virtual
override
payable
ensure(deadline)
returns (uint[] memory amounts)
{
require(path[0] == WETH, 'UniswapV2Router: INVALID_PATH');
amounts = UniswapV2Library.getAmountsOut(factory, msg.value, path);
require(amounts[amounts.length - 1] >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
IWETH(WETH).deposit{value: amounts[0]}();
assert(IWETH(WETH).transfer(UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]));
_swap(amounts, path, to);
}
function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
external
virtual
override
ensure(deadline)
returns (uint[] memory amounts)
{
require(path[path.length - 1] == WETH, 'UniswapV2Router: INVALID_PATH');
amounts = UniswapV2Library.getAmountsIn(factory, amountOut, path);
require(amounts[0] <= amountInMax, 'UniswapV2Router: EXCESSIVE_INPUT_AMOUNT');
TransferHelper.safeTransferFrom(
path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]
);
_swap(amounts, path, address(this));
IWETH(WETH).withdraw(amounts[amounts.length - 1]);
TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]);
}
function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
external
virtual
override
ensure(deadline)
returns (uint[] memory amounts)
{
require(path[path.length - 1] == WETH, 'UniswapV2Router: INVALID_PATH');
amounts = UniswapV2Library.getAmountsOut(factory, amountIn, path);
require(amounts[amounts.length - 1] >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
TransferHelper.safeTransferFrom(
path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]
);
_swap(amounts, path, address(this));
IWETH(WETH).withdraw(amounts[amounts.length - 1]);
TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]);
}
function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
external
virtual
override
payable
ensure(deadline)
returns (uint[] memory amounts)
{
require(path[0] == WETH, 'UniswapV2Router: INVALID_PATH');
amounts = UniswapV2Library.getAmountsIn(factory, amountOut, path);
require(amounts[0] <= msg.value, 'UniswapV2Router: EXCESSIVE_INPUT_AMOUNT');
IWETH(WETH).deposit{value: amounts[0]}();
assert(IWETH(WETH).transfer(UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]));
_swap(amounts, path, to);
if (msg.value > amounts[0]) TransferHelper.safeTransferETH(msg.sender, msg.value - amounts[0]);
}
function _swapSupportingFeeOnTransferTokens(address[] memory path, address _to) internal virtual {
for (uint i; i < path.length - 1; i++) {
(address input, address output) = (path[i], path[i + 1]);
(address token0,) = UniswapV2Library.sortTokens(input, output);
IUniswapV2Pair pair = IUniswapV2Pair(UniswapV2Library.pairFor(factory, input, output));
uint amountInput;
uint amountOutput;
{
(uint reserve0, uint reserve1,) = pair.getReserves();
(uint reserveInput, uint reserveOutput) = input == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
amountInput = IERC20(input).balanceOf(address(pair)).sub(reserveInput);
amountOutput = UniswapV2Library.getAmountOut(amountInput, reserveInput, reserveOutput);
}
(uint amount0Out, uint amount1Out) = input == token0 ? (uint(0), amountOutput) : (amountOutput, uint(0));
address to = i < path.length - 2 ? UniswapV2Library.pairFor(factory, output, path[i + 2]) : _to;
pair.swap(amount0Out, amount1Out, to, new bytes(0));
}
}
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external virtual override ensure(deadline) {
TransferHelper.safeTransferFrom(
path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amountIn
);
uint balanceBefore = IERC20(path[path.length - 1]).balanceOf(to);
_swapSupportingFeeOnTransferTokens(path, to);
require(
IERC20(path[path.length - 1]).balanceOf(to).sub(balanceBefore) >= amountOutMin,
'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT'
);
}
function swapExactETHForTokensSupportingFeeOnTransferTokens(
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
)
external
virtual
override
payable
ensure(deadline)
{
require(path[0] == WETH, 'UniswapV2Router: INVALID_PATH');
uint amountIn = msg.value;
IWETH(WETH).deposit{value: amountIn}();
assert(IWETH(WETH).transfer(UniswapV2Library.pairFor(factory, path[0], path[1]), amountIn));
uint balanceBefore = IERC20(path[path.length - 1]).balanceOf(to);
_swapSupportingFeeOnTransferTokens(path, to);
require(
IERC20(path[path.length - 1]).balanceOf(to).sub(balanceBefore) >= amountOutMin,
'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT'
);
}
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
)
external
virtual
override
ensure(deadline)
{
require(path[path.length - 1] == WETH, 'UniswapV2Router: INVALID_PATH');
TransferHelper.safeTransferFrom(
path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amountIn
);
_swapSupportingFeeOnTransferTokens(path, address(this));
uint amountOut = IERC20(WETH).balanceOf(address(this));
require(amountOut >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
IWETH(WETH).withdraw(amountOut);
TransferHelper.safeTransferETH(to, amountOut);
}
function quote(uint amountA, uint reserveA, uint reserveB) public pure virtual override returns (uint amountB) {
return UniswapV2Library.quote(amountA, reserveA, reserveB);
}
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut)
public
pure
virtual
override
returns (uint amountOut)
{
return UniswapV2Library.getAmountOut(amountIn, reserveIn, reserveOut);
}
function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut)
public
pure
virtual
override
returns (uint amountIn)
{
return UniswapV2Library.getAmountIn(amountOut, reserveIn, reserveOut);
}
function getAmountsOut(uint amountIn, address[] memory path)
public
view
virtual
override
returns (uint[] memory amounts)
{
return UniswapV2Library.getAmountsOut(factory, amountIn, path);
}
function getAmountsIn(uint amountOut, address[] memory path)
public
view
virtual
override
returns (uint[] memory amounts)
{
return UniswapV2Library.getAmountsIn(factory, amountOut, path);
}
}
文件 71 的 72:UniswapV2Router02_Modified.sol
pragma solidity 0.6.11;
import './IUniswapV2Factory.sol';
import './TransferHelper.sol';
import './IUniswapV2Router02.sol';
import './UniswapV2Library.sol';
import './SafeMath.sol';
import './IERC20.sol';
import './IWETH.sol';
contract UniswapV2Router02_Modified is IUniswapV2Router02 {
using SafeMath for uint;
address public immutable override factory;
address public immutable override WETH;
modifier ensure(uint deadline) {
require(deadline >= block.timestamp, 'UniswapV2Router: EXPIRED');
_;
}
constructor(address _factory, address _WETH) public {
factory = _factory;
WETH = _WETH;
}
receive() external payable {
assert(msg.sender == WETH);
}
function _addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin
) internal virtual returns (uint amountA, uint amountB) {
if (IUniswapV2Factory(factory).getPair(tokenA, tokenB) == address(0)) {
IUniswapV2Factory(factory).createPair(tokenA, tokenB);
}
(uint reserveA, uint reserveB) = UniswapV2Library.getReserves(factory, tokenA, tokenB);
if (reserveA == 0 && reserveB == 0) {
(amountA, amountB) = (amountADesired, amountBDesired);
} else {
uint amountBOptimal = UniswapV2Library.quote(amountADesired, reserveA, reserveB);
if (amountBOptimal <= amountBDesired) {
require(amountBOptimal >= amountBMin, 'UniswapV2Router: INSUFFICIENT_B_AMOUNT');
(amountA, amountB) = (amountADesired, amountBOptimal);
} else {
uint amountAOptimal = UniswapV2Library.quote(amountBDesired, reserveB, reserveA);
assert(amountAOptimal <= amountADesired);
require(amountAOptimal >= amountAMin, 'UniswapV2Router: INSUFFICIENT_A_AMOUNT');
(amountA, amountB) = (amountAOptimal, amountBDesired);
}
}
}
function addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external virtual override ensure(deadline) returns (uint amountA, uint amountB, uint liquidity) {
(amountA, amountB) = _addLiquidity(tokenA, tokenB, amountADesired, amountBDesired, amountAMin, amountBMin);
address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB);
TransferHelper.safeTransferFrom(tokenA, msg.sender, pair, amountA);
TransferHelper.safeTransferFrom(tokenB, msg.sender, pair, amountB);
liquidity = IUniswapV2Pair(pair).mint(to);
}
function addLiquidityETH(
address token,
uint amountTokenDesired,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external virtual override payable ensure(deadline) returns (uint amountToken, uint amountETH, uint liquidity) {
(amountToken, amountETH) = _addLiquidity(
token,
WETH,
amountTokenDesired,
msg.value,
amountTokenMin,
amountETHMin
);
address pair = UniswapV2Library.pairFor(factory, token, WETH);
TransferHelper.safeTransferFrom(token, msg.sender, pair, amountToken);
TransferHelper.safeTransferFrom(WETH, msg.sender, pair, amountETH);
liquidity = IUniswapV2Pair(pair).mint(to);
if (msg.value > amountETH) TransferHelper.safeTransferETH(msg.sender, msg.value - amountETH);
}
function removeLiquidity(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) public virtual override ensure(deadline) returns (uint amountA, uint amountB) {
address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB);
IUniswapV2Pair(pair).transferFrom(msg.sender, pair, liquidity);
(uint amount0, uint amount1) = IUniswapV2Pair(pair).burn(to);
(address token0,) = UniswapV2Library.sortTokens(tokenA, tokenB);
(amountA, amountB) = tokenA == token0 ? (amount0, amount1) : (amount1, amount0);
require(amountA >= amountAMin, 'UniswapV2Router: INSUFFICIENT_A_AMOUNT');
require(amountB >= amountBMin, 'UniswapV2Router: INSUFFICIENT_B_AMOUNT');
}
function removeLiquidityETH(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) public virtual override ensure(deadline) returns (uint amountToken, uint amountETH) {
(amountToken, amountETH) = removeLiquidity(
token,
WETH,
liquidity,
amountTokenMin,
amountETHMin,
address(this),
deadline
);
TransferHelper.safeTransfer(token, to, amountToken);
IWETH(WETH).withdraw(amountETH);
TransferHelper.safeTransferETH(to, amountETH);
}
function removeLiquidityWithPermit(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external virtual override returns (uint amountA, uint amountB) {
address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB);
uint value = approveMax ? uint(-1) : liquidity;
IUniswapV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
(amountA, amountB) = removeLiquidity(tokenA, tokenB, liquidity, amountAMin, amountBMin, to, deadline);
}
function removeLiquidityETHWithPermit(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external virtual override returns (uint amountToken, uint amountETH) {
address pair = UniswapV2Library.pairFor(factory, token, WETH);
uint value = approveMax ? uint(-1) : liquidity;
IUniswapV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
(amountToken, amountETH) = removeLiquidityETH(token, liquidity, amountTokenMin, amountETHMin, to, deadline);
}
function removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) public virtual override ensure(deadline) returns (uint amountETH) {
(, amountETH) = removeLiquidity(
token,
WETH,
liquidity,
amountTokenMin,
amountETHMin,
address(this),
deadline
);
TransferHelper.safeTransfer(token, to, IERC20(token).balanceOf(address(this)));
IWETH(WETH).withdraw(amountETH);
TransferHelper.safeTransferETH(to, amountETH);
}
function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external virtual override returns (uint amountETH) {
address pair = UniswapV2Library.pairFor(factory, token, WETH);
uint value = approveMax ? uint(-1) : liquidity;
IUniswapV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
amountETH = removeLiquidityETHSupportingFeeOnTransferTokens(
token, liquidity, amountTokenMin, amountETHMin, to, deadline
);
}
function _swap(uint[] memory amounts, address[] memory path, address _to) internal virtual {
for (uint i; i < path.length - 1; i++) {
(address input, address output) = (path[i], path[i + 1]);
(address token0,) = UniswapV2Library.sortTokens(input, output);
uint amountOut = amounts[i + 1];
(uint amount0Out, uint amount1Out) = input == token0 ? (uint(0), amountOut) : (amountOut, uint(0));
address to = i < path.length - 2 ? UniswapV2Library.pairFor(factory, output, path[i + 2]) : _to;
IUniswapV2Pair(UniswapV2Library.pairFor(factory, input, output)).swap(
amount0Out, amount1Out, to, new bytes(0)
);
}
}
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external virtual override ensure(deadline) returns (uint[] memory amounts) {
amounts = UniswapV2Library.getAmountsOut(factory, amountIn, path);
require(amounts[amounts.length - 1] >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
TransferHelper.safeTransferFrom(
path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]
);
_swap(amounts, path, to);
}
function swapTokensForExactTokens(
uint amountOut,
uint amountInMax,
address[] calldata path,
address to,
uint deadline
) external virtual override ensure(deadline) returns (uint[] memory amounts) {
amounts = UniswapV2Library.getAmountsIn(factory, amountOut, path);
require(amounts[0] <= amountInMax, 'UniswapV2Router: EXCESSIVE_INPUT_AMOUNT');
TransferHelper.safeTransferFrom(
path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]
);
_swap(amounts, path, to);
}
function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
external
virtual
override
payable
ensure(deadline)
returns (uint[] memory amounts)
{
require(path[0] == WETH, 'UniswapV2Router: INVALID_PATH');
amounts = UniswapV2Library.getAmountsOut(factory, msg.value, path);
require(amounts[amounts.length - 1] >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
IWETH(WETH).deposit{value: amounts[0]}();
assert(IWETH(WETH).transfer(UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]));
_swap(amounts, path, to);
}
function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
external
virtual
override
ensure(deadline)
returns (uint[] memory amounts)
{
require(path[path.length - 1] == WETH, 'UniswapV2Router: INVALID_PATH');
amounts = UniswapV2Library.getAmountsIn(factory, amountOut, path);
require(amounts[0] <= amountInMax, 'UniswapV2Router: EXCESSIVE_INPUT_AMOUNT');
TransferHelper.safeTransferFrom(
path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]
);
_swap(amounts, path, address(this));
IWETH(WETH).withdraw(amounts[amounts.length - 1]);
TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]);
}
function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
external
virtual
override
ensure(deadline)
returns (uint[] memory amounts)
{
require(path[path.length - 1] == WETH, 'UniswapV2Router: INVALID_PATH');
amounts = UniswapV2Library.getAmountsOut(factory, amountIn, path);
require(amounts[amounts.length - 1] >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
TransferHelper.safeTransferFrom(
path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]
);
_swap(amounts, path, address(this));
IWETH(WETH).withdraw(amounts[amounts.length - 1]);
TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]);
}
function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
external
virtual
override
payable
ensure(deadline)
returns (uint[] memory amounts)
{
require(path[0] == WETH, 'UniswapV2Router: INVALID_PATH');
amounts = UniswapV2Library.getAmountsIn(factory, amountOut, path);
require(amounts[0] <= msg.value, 'UniswapV2Router: EXCESSIVE_INPUT_AMOUNT');
IWETH(WETH).deposit{value: amounts[0]}();
assert(IWETH(WETH).transfer(UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]));
_swap(amounts, path, to);
if (msg.value > amounts[0]) TransferHelper.safeTransferETH(msg.sender, msg.value - amounts[0]);
}
function _swapSupportingFeeOnTransferTokens(address[] memory path, address _to) internal virtual {
}
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external virtual override ensure(deadline) {
}
function swapExactETHForTokensSupportingFeeOnTransferTokens(
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
)
external
virtual
override
payable
ensure(deadline)
{
}
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
)
external
virtual
override
ensure(deadline)
{
}
function quote(uint amountA, uint reserveA, uint reserveB) public pure virtual override returns (uint amountB) {
return UniswapV2Library.quote(amountA, reserveA, reserveB);
}
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut)
public
pure
virtual
override
returns (uint amountOut)
{
return UniswapV2Library.getAmountOut(amountIn, reserveIn, reserveOut);
}
function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut)
public
pure
virtual
override
returns (uint amountIn)
{
return UniswapV2Library.getAmountIn(amountOut, reserveIn, reserveOut);
}
function getAmountsOut(uint amountIn, address[] memory path)
public
view
virtual
override
returns (uint[] memory amounts)
{
return UniswapV2Library.getAmountsOut(factory, amountIn, path);
}
function getAmountsIn(uint amountOut, address[] memory path)
public
view
virtual
override
returns (uint[] memory amounts)
{
return UniswapV2Library.getAmountsIn(factory, amountOut, path);
}
}
文件 72 的 72:WETH.sol
pragma solidity 0.6.11;
import './IWETH.sol';
contract WETH is IWETH {
string public name = "Wrapped Ether";
string public symbol = "WETH";
uint8 public decimals = 18;
event Approval(address indexed src, address indexed guy, uint wad);
event Transfer(address indexed src, address indexed dst, uint wad);
event Deposit(address indexed dst, uint wad);
event Withdrawal(address indexed src, uint wad);
mapping (address => uint) public balanceOf;
mapping (address => mapping (address => uint)) public allowance;
fallback() external payable {
deposit();
}
receive() external payable { }
constructor (address _creator_address ) public
{
balanceOf[_creator_address] = 1000000e18;
}
function deposit() public override payable {
balanceOf[msg.sender] += msg.value;
emit Deposit(msg.sender, msg.value);
}
function withdraw(uint wad) override public {
require(balanceOf[msg.sender] >= wad);
balanceOf[msg.sender] -= wad;
msg.sender.transfer(wad);
emit Withdrawal(msg.sender, wad);
}
function totalSupply() public view returns (uint) {
return address(this).balance;
}
function approve(address guy, uint wad) public returns (bool) {
allowance[msg.sender][guy] = wad;
emit Approval(msg.sender, guy, wad);
return true;
}
function transfer(address dst, uint wad) public override returns (bool) {
return transferFrom(msg.sender, dst, wad);
}
function transferFrom(address src, address dst, uint wad)
public
override
returns (bool)
{
require(balanceOf[src] >= wad);
if (src != msg.sender && allowance[src][msg.sender] != uint(-1)) {
require(allowance[src][msg.sender] >= wad);
allowance[src][msg.sender] -= wad;
}
balanceOf[src] -= wad;
balanceOf[dst] += wad;
emit Transfer(src, dst, wad);
return true;
}
}
{
"compilationTarget": {
"Pool_USDC.sol": "Pool_USDC"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 100000
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_frax_contract_address","type":"address"},{"internalType":"address","name":"_fxs_contract_address","type":"address"},{"internalType":"address","name":"_collateral_address","type":"address"},{"internalType":"address","name":"_creator_address","type":"address"},{"internalType":"address","name":"_timelock_address","type":"address"},{"internalType":"uint256","name":"_pool_ceiling","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"USDC_address","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"availableExcessCollatDV","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bonus_rate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"FXS_amount","type":"uint256"},{"internalType":"uint256","name":"COLLATERAL_out_min","type":"uint256"}],"name":"buyBackFXS","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"buyBackPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"buyback_fee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"collatDollarBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"collat_eth_oracle_address","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"collateralPricePaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"collectRedemption","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getCollateralPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"lastRedeemed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"collateral_amount","type":"uint256"},{"internalType":"uint256","name":"FRAX_out_min","type":"uint256"}],"name":"mint1t1FRAX","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"fxs_amount_d18","type":"uint256"},{"internalType":"uint256","name":"FRAX_out_min","type":"uint256"}],"name":"mintAlgorithmicFRAX","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"collateral_amount","type":"uint256"},{"internalType":"uint256","name":"fxs_amount","type":"uint256"},{"internalType":"uint256","name":"FRAX_out_min","type":"uint256"}],"name":"mintFractionalFRAX","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mintPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minting_fee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pausedPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pool_ceiling","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"recollat_fee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"collateral_amount","type":"uint256"},{"internalType":"uint256","name":"FXS_out_min","type":"uint256"}],"name":"recollateralizeFRAX","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"recollateralizePaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"FRAX_amount","type":"uint256"},{"internalType":"uint256","name":"COLLATERAL_out_min","type":"uint256"}],"name":"redeem1t1FRAX","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"FRAX_amount","type":"uint256"},{"internalType":"uint256","name":"FXS_out_min","type":"uint256"}],"name":"redeemAlgorithmicFRAX","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"redeemCollateralBalances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"redeemFXSBalances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"FRAX_amount","type":"uint256"},{"internalType":"uint256","name":"FXS_out_min","type":"uint256"},{"internalType":"uint256","name":"COLLATERAL_out_min","type":"uint256"}],"name":"redeemFractionalFRAX","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"redeemPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"redemption_delay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"redemption_fee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_collateral_weth_oracle_address","type":"address"},{"internalType":"address","name":"_weth_address","type":"address"}],"name":"setCollatETHOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner_address","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"new_ceiling","type":"uint256"},{"internalType":"uint256","name":"new_bonus_rate","type":"uint256"},{"internalType":"uint256","name":"new_redemption_delay","type":"uint256"},{"internalType":"uint256","name":"new_mint_fee","type":"uint256"},{"internalType":"uint256","name":"new_redeem_fee","type":"uint256"},{"internalType":"uint256","name":"new_buyback_fee","type":"uint256"},{"internalType":"uint256","name":"new_recollat_fee","type":"uint256"}],"name":"setPoolParameters","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"new_timelock","type":"address"}],"name":"setTimelock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"toggleBuyBack","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_new_price","type":"uint256"}],"name":"toggleCollateralPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"toggleMinting","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"toggleRecollateralize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"toggleRedeeming","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unclaimedPoolCollateral","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unclaimedPoolFXS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]