编译器
0.8.23+commit.f704f362
文件 1 的 18:AbstractLST.sol
pragma solidity ^0.8.23;
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {PseudoCappedERC20} from "../token/PseudoCappedERC20.sol";
abstract contract AbstractLST is PseudoCappedERC20, Ownable, ReentrancyGuard {
using Address for address;
using SafeERC20 for IERC20;
address public distributionAddress;
bool public buyActive;
bool public whitelistActive;
uint256 public minAmountBuy;
mapping(address => bool) public whitelist;
event BuyTokens(address indexed user, uint256 amount, uint256 newTotalSupply);
event SoftMaxSupplyChanged(uint256 newSoftMaxSupply);
event MinAmountBuyChanged(uint256 newMinAmountBuy);
event BuyActivated(address indexed activator);
event BuyDeactivated(address indexed deactivator);
event WhitelistActivated(address indexed activator);
event WhitelistDeactivated(address indexed deactivator);
event WhitelistUpdated(address indexed addr, bool whitelisted);
event DistributionAddressUpdated(address indexed newDistributionAddress);
constructor(
string memory _name,
string memory _symbol,
uint256 _totalMaxSupply
) PseudoCappedERC20(_name, _symbol, _totalMaxSupply) Ownable(msg.sender) {}
function setMinAmountBuy(uint256 _newMinAmountBuy) external onlyOwner {
require(_newMinAmountBuy > 0, "Min amount buy must be greater than 0");
minAmountBuy = _newMinAmountBuy;
emit MinAmountBuyChanged(_newMinAmountBuy);
}
function setBuyActive(bool _buyActive) external onlyOwner {
buyActive = _buyActive;
if (_buyActive) {
emit BuyActivated(msg.sender);
} else {
emit BuyDeactivated(msg.sender);
}
}
function setWhitelistActive(bool _whitelistActive) external onlyOwner {
whitelistActive = _whitelistActive;
if (_whitelistActive) {
emit WhitelistActivated(msg.sender);
} else {
emit WhitelistDeactivated(msg.sender);
}
}
function updateWhitelist(address _addr, bool _whitelisted) external onlyOwner {
whitelist[_addr] = _whitelisted;
emit WhitelistUpdated(_addr, _whitelisted);
}
function setDistributionAddress(address _distributionAddress) external onlyOwner {
distributionAddress = _distributionAddress;
emit DistributionAddressUpdated(_distributionAddress);
}
function setCap(uint256 _newCap) external onlyOwner {
_setCap(_newCap);
emit SoftMaxSupplyChanged(_newCap);
}
modifier onlyBuyActive() {
require(buyActive, "Abstract LST: buy not active");
_;
}
modifier onlyWhitelist() {
if (whitelistActive) {
require(whitelist[msg.sender], "Abstract LST: caller is not whitelisted");
}
_;
}
function buyTokensWithEth() external virtual payable;
function buyTokens(uint amount) external virtual;
function mint(uint amount) external virtual;
function mintWithCap(uint amount) external virtual;
function setRewardsAddress(address _rewardsAddress) external virtual;
function setTokenPriceCalculator(address _tokenPriceCalculator) external virtual;
function _forwardEth(uint256 _amount) internal {
require(distributionAddress != address(0), "Abstract LST: distributor address not set");
require(_amount > 0, "Abstract LST: amount must be greater than 0");
Address.sendValue(payable(distributionAddress), _amount);
}
function _forwardERC20(address _token, uint256 _amount) internal {
require(_token != address(0), "Abstract LST: token address cannot be the zero address");
require(_amount > 0, "Abstract LST: amount must be greater than 0");
IERC20(_token).safeTransfer(distributionAddress, _amount);
}
function _afterBuy(address _user, uint256 _amount) internal {
emit BuyTokens(_user, _amount, totalSupply());
}
function withdrawETH() external onlyOwner {
require(owner() != address(0), "AbstractLST: owner cannot be the zero address");
Address.sendValue(payable(owner()), address(this).balance);
}
function withdrawERC20(address token) external onlyOwner {
require(owner() != address(0), "AbstractLST: owner cannot be the zero address");
IERC20(token).safeTransfer(owner(), IERC20(token).balanceOf(address(this)));
}
}
文件 2 的 18:AbstractRewards.sol
pragma solidity ^0.8.23;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import {IRewards} from "../../interfaces/IRewards.sol";
import {ITokenPriceCalculator} from "../../interfaces/ITokenPriceCalculator.sol";
abstract contract AbstractRewards is IRewards {
using EnumerableSet for EnumerableSet.AddressSet;
enum Update {FROM, TO}
struct UserRecord {
uint256 userBalance;
uint256 lastUpdateTime;
uint256 cumulativeBalance;
uint256 cumCirculatingSupplyLastClaim;
uint256 lastClaimTime;
}
address public rewardsAddress;
ITokenPriceCalculator public tokenPriceCalculator;
uint public immutable apy;
uint public immutable aqtisApy;
uint public constant DENOMINATOR = 1000;
struct Supply {
uint totalSupply;
uint lastUpdateTime;
uint currentCirculatingSupply;
uint cumulativeCirculatingSupply;
}
Supply internal _supply;
mapping(address => bool) public whitelistedContracts;
constructor(uint _apy, uint _aqtisApy) {
apy = _apy;
aqtisApy = _aqtisApy;
}
modifier onlyRewards {
require(msg.sender == rewardsAddress, "Rewards: Only rewards contract can call this function");
_;
}
mapping(address => UserRecord) internal _userRecords;
function _setRewardsAddress(address _rewardsAddress) internal {
rewardsAddress = _rewardsAddress;
}
function _setTokenPriceCalculator(address _tokenPriceCalculator) internal {
tokenPriceCalculator = ITokenPriceCalculator(_tokenPriceCalculator);
}
function getRewardsFor(address user) external view virtual returns (RewardsDistribution memory);
function _beforeUpdate(address user, uint256 value, Update updateType) internal virtual;
function _beforeReset(address user) internal virtual;
function resetUser(address user) external onlyRewards {
_resetUser(user);
}
function _updateSupply(address user, uint256 value, Update updateType) internal {
uint updateDiff = block.timestamp - _supply.lastUpdateTime;
_supply.cumulativeCirculatingSupply += _supply.currentCirculatingSupply * updateDiff;
if (user == address(0)) {
if (updateType == Update.FROM) {
_supply.totalSupply += value;
} else if (updateType == Update.TO) {
_supply.totalSupply -= value;
}
}
bool userIsContract = isContract(user);
if (userIsContract && _userRecords[user].userBalance != 0) {
if (updateType == Update.FROM)
_supply.currentCirculatingSupply -= (_userRecords[user].userBalance - value);
else if (updateType == Update.TO) {
_supply.currentCirculatingSupply -= (_userRecords[user].userBalance + value);
}
delete _userRecords[user];
} else if (updateType == Update.FROM && (user == address(0) || userIsContract)) {
_supply.currentCirculatingSupply += value;
} else if (updateType == Update.TO && (user == address(0) || userIsContract)) {
_supply.currentCirculatingSupply -= value;
}
_supply.lastUpdateTime = block.timestamp;
}
function _updateRecord(address user, uint256 value, Update updateType) internal {
_beforeUpdate(user, value, updateType);
_updateSupply(user, value, updateType);
if (user == address(0) || isContract(user)) {
return;
}
UserRecord storage record = _userRecords[user];
uint256 timeElapsed = 0;
if (record.lastUpdateTime == 0) {
record.cumulativeBalance = 0;
record.cumCirculatingSupplyLastClaim = _supply.cumulativeCirculatingSupply;
record.lastClaimTime = block.timestamp;
} else {
timeElapsed = block.timestamp - record.lastUpdateTime;
record.cumulativeBalance += record.userBalance * timeElapsed;
}
if (updateType == Update.FROM) {
record.userBalance -= value;
} else {
record.userBalance += value;
}
record.lastUpdateTime = block.timestamp;
}
function _getTWAB(address user) internal view returns (uint256) {
UserRecord memory record = _userRecords[user];
uint256 claimTime = block.timestamp - record.lastClaimTime;
if (claimTime == 0) {
return 0;
}
uint256 timeDifference = block.timestamp - record.lastUpdateTime;
return (record.cumulativeBalance + (record.userBalance * timeDifference)) / claimTime;
}
function _resetUser(address user) internal {
_beforeReset(user);
UserRecord storage record = _userRecords[user];
record.lastClaimTime = block.timestamp;
record.lastUpdateTime = block.timestamp;
record.cumulativeBalance = 0;
record.cumCirculatingSupplyLastClaim = cumulativeCirculatingSupply();
}
function _setWhitelistedContract(address _contract, bool _isWhitelisted) internal {
whitelistedContracts[_contract] = _isWhitelisted;
}
function twaCircSupplySinceLastClaim(address user) public view returns (uint) {
UserRecord memory record = _userRecords[user];
uint claimTime = block.timestamp - record.lastClaimTime;
require(claimTime > 0, "Rewards: Claim time is 0");
return (cumulativeCirculatingSupply() - record.cumCirculatingSupplyLastClaim) / claimTime;
}
function circulatingSupply() public view returns (uint) {
return _supply.currentCirculatingSupply;
}
function cumulativeCirculatingSupply() public view returns (uint){
uint updateDiff = block.timestamp - _supply.lastUpdateTime;
return _supply.cumulativeCirculatingSupply + _supply.currentCirculatingSupply * updateDiff;
}
function userTWAB(address user) external view returns (uint) {
return _getTWAB(user);
}
function lastClaimTime(address user) external view returns (uint) {
return _userRecords[user].lastClaimTime;
}
function isContract(address addr) internal view returns (bool) {
if (whitelistedContracts[addr]) {
return false;
}
uint size;
assembly {
size := extcodesize(addr)
}
return size > 0;
}
}
文件 3 的 18:Address.sol
pragma solidity ^0.8.20;
library Address {
error AddressInsufficientBalance(address account);
error AddressEmptyCode(address target);
error FailedInnerCall();
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
function _revert(bytes memory returndata) private pure {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}
文件 4 的 18:Context.sol
pragma solidity ^0.8.20;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
文件 5 的 18:ERC20.sol
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC20Metadata} from "./extensions/IERC20Metadata.sol";
import {Context} from "../../utils/Context.sol";
import {IERC20Errors} from "../../interfaces/draft-IERC6093.sol";
abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
mapping(address account => uint256) private _balances;
mapping(address account => mapping(address spender => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
function name() public view virtual returns (string memory) {
return _name;
}
function symbol() public view virtual returns (string memory) {
return _symbol;
}
function decimals() public view virtual returns (uint8) {
return 18;
}
function totalSupply() public view virtual returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view virtual returns (uint256) {
return _balances[account];
}
function transfer(address to, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_transfer(owner, to, value);
return true;
}
function allowance(address owner, address spender) public view virtual returns (uint256) {
return _allowances[owner][spender];
}
function approve(address spender, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, value);
return true;
}
function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, value);
_transfer(from, to, value);
return true;
}
function _transfer(address from, address to, uint256 value) internal {
if (from == address(0)) {
revert ERC20InvalidSender(address(0));
}
if (to == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(from, to, value);
}
function _update(address from, address to, uint256 value) internal virtual {
if (from == address(0)) {
_totalSupply += value;
} else {
uint256 fromBalance = _balances[from];
if (fromBalance < value) {
revert ERC20InsufficientBalance(from, fromBalance, value);
}
unchecked {
_balances[from] = fromBalance - value;
}
}
if (to == address(0)) {
unchecked {
_totalSupply -= value;
}
} else {
unchecked {
_balances[to] += value;
}
}
emit Transfer(from, to, value);
}
function _mint(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(address(0), account, value);
}
function _burn(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidSender(address(0));
}
_update(account, address(0), value);
}
function _approve(address owner, address spender, uint256 value) internal {
_approve(owner, spender, value, true);
}
function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
if (owner == address(0)) {
revert ERC20InvalidApprover(address(0));
}
if (spender == address(0)) {
revert ERC20InvalidSpender(address(0));
}
_allowances[owner][spender] = value;
if (emitEvent) {
emit Approval(owner, spender, value);
}
}
function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
if (currentAllowance < value) {
revert ERC20InsufficientAllowance(spender, currentAllowance, value);
}
unchecked {
_approve(owner, spender, currentAllowance - value, false);
}
}
}
}
文件 6 的 18:EnumerableSet.sol
pragma solidity ^0.8.20;
library EnumerableSet {
struct Set {
bytes32[] _values;
mapping(bytes32 value => uint256) _positions;
}
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
set._positions[value] = set._values.length;
return true;
} else {
return false;
}
}
function _remove(Set storage set, bytes32 value) private returns (bool) {
uint256 position = set._positions[value];
if (position != 0) {
uint256 valueIndex = position - 1;
uint256 lastIndex = set._values.length - 1;
if (valueIndex != lastIndex) {
bytes32 lastValue = set._values[lastIndex];
set._values[valueIndex] = lastValue;
set._positions[lastValue] = position;
}
set._values.pop();
delete set._positions[value];
return true;
} else {
return false;
}
}
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._positions[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) {
return set._values[index];
}
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
struct Bytes32Set {
Set _inner;
}
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
assembly {
result := store
}
return result;
}
struct AddressSet {
Set _inner;
}
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(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(uint160(uint256(_at(set._inner, index))));
}
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
assembly {
result := store
}
return result;
}
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));
}
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
assembly {
result := store
}
return result;
}
}
文件 7 的 18:IERC20.sol
pragma solidity ^0.8.20;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 value) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
文件 8 的 18:IERC20Metadata.sol
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
interface IERC20Metadata is IERC20 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
}
文件 9 的 18:IERC20Permit.sol
pragma solidity ^0.8.20;
interface IERC20Permit {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function nonces(address owner) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
文件 10 的 18:IRewards.sol
pragma solidity ^0.8.23;
interface IRewards {
struct RewardsDistribution {
uint256 usdcRewards;
uint256 ethRewards;
uint256 aqtisRewards;
uint256 cappedLSTRewards;
}
function getRewardsFor(address user) external view returns (RewardsDistribution memory);
function resetUser(address user) external;
function twaCircSupplySinceLastClaim(address user) external view returns (uint);
function circulatingSupply() external view returns (uint);
function cumulativeCirculatingSupply() external view returns (uint);
function userTWAB(address user) external view returns (uint);
function lastClaimTime(address user) external view returns (uint);
}
文件 11 的 18:ITokenPriceCalculator.sol
pragma solidity ^0.8.23;
interface ITokenPriceCalculator {
function update() external;
function getAqtisPriceInWETH() external view returns (uint256);
function getAqtisPriceInUSD() external view returns (uint256);
function getLatestUsdPrice() external view returns (uint256);
function getLatestEthPrice() external view returns (uint256);
}
文件 12 的 18:Ownable.sol
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
error OwnableUnauthorizedAccount(address account);
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return _owner;
}
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 13 的 18:PseudoCappedERC20.sol
pragma solidity ^0.8.23;
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract PseudoCappedERC20 is ERC20 {
uint256 internal _cap;
constructor(
string memory __name,
string memory __symbol,
uint256 __cap
)
ERC20(__name, __symbol)
{
_cap = __cap;
}
function _setCap(uint256 __newCap) internal {
_cap = __newCap;
}
function _exceedsCap(uint256 amount) internal view returns (bool) {
return totalSupply() + amount > _cap;
}
function cap() external view returns (uint256) {
return _cap;
}
}
文件 14 的 18:Qrt.sol
pragma solidity ^0.8.23;
import {AbstractLST} from "./AbstractLST.sol";
import {ITokenPriceCalculator} from "../interfaces/ITokenPriceCalculator.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {QrtRewards} from "./rewards/QrtRewards.sol";
contract Qrt is AbstractLST, QrtRewards {
using SafeERC20 for IERC20;
uint constant public QRT_PRICE = 10;
address public immutable usdAddress;
constructor(address _usd)
AbstractLST("Quant Reserve Token", "QRT", 100_000_000 * 1e6)
QrtRewards(175, 25)
{
usdAddress = _usd;
}
function decimals() public view virtual override returns (uint8) {
return 6;
}
function buyTokensWithEth() external override payable onlyBuyActive onlyWhitelist {
uint tokensToMint = calculateTokensToMintWithEth(msg.value);
require(!_exceedsCap(tokensToMint), "Qrt: Buy exceeds cap");
require(msg.value >= minAmountBuy, "Qrt: Insufficient buy amount");
_mint(msg.sender, tokensToMint);
_forwardEth(msg.value);
_afterBuy(msg.sender, tokensToMint);
}
function buyTokens(uint amount) external override onlyBuyActive onlyWhitelist {
uint tokensToMint = calculateTokensToMintWithUSD(amount);
require(!_exceedsCap(tokensToMint), "Qrt: Buy exceeds cap");
require(amount >= minAmountBuy, "Qrt: Insufficient buy amount");
IERC20(usdAddress).safeTransferFrom(msg.sender, address(this), amount);
_mint(msg.sender, tokensToMint);
_forwardERC20(usdAddress, amount);
_afterBuy(msg.sender, tokensToMint);
}
function mint(uint amount) external override onlyRewards {
_mint(msg.sender, amount);
}
function mintWithCap(uint amount) external override onlyRewards {
require(!_exceedsCap(amount), "Qrt: Mint exceeds cap");
_mint(msg.sender, amount);
}
function setRewardsAddress(address _rewardsAddress) external override onlyOwner {
_setRewardsAddress(_rewardsAddress);
}
function setContractRewardsWhitelist(address _contract, bool _whitelisted) external onlyOwner {
_setWhitelistedContract(_contract, _whitelisted);
}
function setTokenPriceCalculator(address _tokenPriceCalculator) external override onlyOwner {
_setTokenPriceCalculator(_tokenPriceCalculator);
}
function calculateTokensToMintWithUSD(uint amount) public view returns (uint) {
uint usdPrice = tokenPriceCalculator.getLatestUsdPrice();
return (amount * usdPrice) / (QRT_PRICE * 1e8);
}
function calculateTokensToMintWithEth(uint ethAmount) public view returns (uint) {
uint ethPrice = tokenPriceCalculator.getLatestEthPrice();
return (ethAmount * ethPrice) / (QRT_PRICE * 1e8 * 1e12);
}
function _update(address from, address to, uint256 value) internal virtual override {
super._update(from, to, value);
_updateRecord(from, value, Update.FROM);
_updateRecord(to, value, Update.TO);
}
}
文件 15 的 18:QrtRewards.sol
pragma solidity ^0.8.23;
import {AbstractRewards} from "./AbstractRewards.sol";
contract QrtRewards is AbstractRewards {
mapping(address => uint) public cumSupplyLastClaim;
uint public currentCumSupply;
uint public lastSupplyUpdateTime;
constructor(uint _apy, uint _aqtisApy) AbstractRewards(_apy, _aqtisApy){}
function getRewardsFor(address user) external view override returns (RewardsDistribution memory) {
uint256 twab = _getTWAB(user);
uint timeSinceLastClaim = block.timestamp - _userRecords[user].lastClaimTime;
uint qrtRewards = ((apy - aqtisApy) * _twaSupplySinceLastClaim(user) * twab * timeSinceLastClaim) / (DENOMINATOR * twaCircSupplySinceLastClaim(user) * 365 days);
uint aqtisRewards = _getAqtisRewards(twab, timeSinceLastClaim);
return RewardsDistribution(0, 0, aqtisRewards, qrtRewards);
}
function _beforeUpdate(address user, uint256 , Update ) internal override {
if (user == address(0)) {
uint timeDiff = block.timestamp - lastSupplyUpdateTime;
currentCumSupply += _supply.totalSupply * timeDiff;
lastSupplyUpdateTime = block.timestamp;
} else if (cumSupplyLastClaim[user] == 0) {
cumSupplyLastClaim[user] = currentCumSupply;
}
}
function _beforeReset(address user) internal override {
cumSupplyLastClaim[user] = currentCumSupply;
}
function _currentCumulativeSupply() public view returns (uint) {
uint timeDiff = block.timestamp - lastSupplyUpdateTime;
return currentCumSupply + _supply.totalSupply * timeDiff;
}
function _twaSupplySinceLastClaim(address user) public view returns (uint) {
uint timeDiff = block.timestamp - _userRecords[user].lastClaimTime;
return (_currentCumulativeSupply() - cumSupplyLastClaim[user]) / timeDiff;
}
function _getAqtisRewards(uint twab, uint duration) internal view returns (uint) {
uint aqtisPrice = tokenPriceCalculator.getAqtisPriceInUSD();
return aqtisApy * 10 * twab * duration * 1e18 * 1e12 / (DENOMINATOR * aqtisPrice * 365 days);
}
}
文件 16 的 18:ReentrancyGuard.sol
pragma solidity ^0.8.20;
abstract contract ReentrancyGuard {
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
uint256 private _status;
error ReentrancyGuardReentrantCall();
constructor() {
_status = NOT_ENTERED;
}
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
_status = ENTERED;
}
function _nonReentrantAfter() private {
_status = NOT_ENTERED;
}
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == ENTERED;
}
}
文件 17 的 18:SafeERC20.sol
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";
library SafeERC20 {
using Address for address;
error SafeERC20FailedOperation(address token);
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
(bool success, bytes memory returndata) = address(token).call(data);
return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
}
}
文件 18 的 18:draft-IERC6093.sol
pragma solidity ^0.8.20;
interface IERC20Errors {
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
error ERC20InvalidSender(address sender);
error ERC20InvalidReceiver(address receiver);
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
error ERC20InvalidApprover(address approver);
error ERC20InvalidSpender(address spender);
}
interface IERC721Errors {
error ERC721InvalidOwner(address owner);
error ERC721NonexistentToken(uint256 tokenId);
error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
error ERC721InvalidSender(address sender);
error ERC721InvalidReceiver(address receiver);
error ERC721InsufficientApproval(address operator, uint256 tokenId);
error ERC721InvalidApprover(address approver);
error ERC721InvalidOperator(address operator);
}
interface IERC1155Errors {
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
error ERC1155InvalidSender(address sender);
error ERC1155InvalidReceiver(address receiver);
error ERC1155MissingApprovalForAll(address operator, address owner);
error ERC1155InvalidApprover(address approver);
error ERC1155InvalidOperator(address operator);
error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}
{
"compilationTarget": {
"contracts/lst/Qrt.sol": "Qrt"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 1000
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_usd","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC20InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC20InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC20InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"ERC20InvalidSpender","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"activator","type":"address"}],"name":"BuyActivated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"deactivator","type":"address"}],"name":"BuyDeactivated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTotalSupply","type":"uint256"}],"name":"BuyTokens","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newDistributionAddress","type":"address"}],"name":"DistributionAddressUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newMinAmountBuy","type":"uint256"}],"name":"MinAmountBuyChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newSoftMaxSupply","type":"uint256"}],"name":"SoftMaxSupplyChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"activator","type":"address"}],"name":"WhitelistActivated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"deactivator","type":"address"}],"name":"WhitelistDeactivated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"addr","type":"address"},{"indexed":false,"internalType":"bool","name":"whitelisted","type":"bool"}],"name":"WhitelistUpdated","type":"event"},{"inputs":[],"name":"DENOMINATOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"QRT_PRICE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_currentCumulativeSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"_twaSupplySinceLastClaim","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"apy","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"aqtisApy","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"buyActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"buyTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"buyTokensWithEth","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"ethAmount","type":"uint256"}],"name":"calculateTokensToMintWithEth","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"calculateTokensToMintWithUSD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"circulatingSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"cumSupplyLastClaim","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cumulativeCirculatingSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentCumSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"distributionAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getRewardsFor","outputs":[{"components":[{"internalType":"uint256","name":"usdcRewards","type":"uint256"},{"internalType":"uint256","name":"ethRewards","type":"uint256"},{"internalType":"uint256","name":"aqtisRewards","type":"uint256"},{"internalType":"uint256","name":"cappedLSTRewards","type":"uint256"}],"internalType":"struct IRewards.RewardsDistribution","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"lastClaimTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastSupplyUpdateTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minAmountBuy","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mintWithCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"resetUser","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardsAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_buyActive","type":"bool"}],"name":"setBuyActive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newCap","type":"uint256"}],"name":"setCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_contract","type":"address"},{"internalType":"bool","name":"_whitelisted","type":"bool"}],"name":"setContractRewardsWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_distributionAddress","type":"address"}],"name":"setDistributionAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newMinAmountBuy","type":"uint256"}],"name":"setMinAmountBuy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_rewardsAddress","type":"address"}],"name":"setRewardsAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenPriceCalculator","type":"address"}],"name":"setTokenPriceCalculator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_whitelistActive","type":"bool"}],"name":"setWhitelistActive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenPriceCalculator","outputs":[{"internalType":"contract ITokenPriceCalculator","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"twaCircSupplySinceLastClaim","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_addr","type":"address"},{"internalType":"bool","name":"_whitelisted","type":"bool"}],"name":"updateWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"usdAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"userTWAB","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"whitelist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"whitelistActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"whitelistedContracts","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"withdrawERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawETH","outputs":[],"stateMutability":"nonpayable","type":"function"}]