编译器
0.8.19+commit.7dd6d404
文件 1 的 17:Casting.sol
pragma solidity >=0.8.19;
import "../Common.sol" as Common;
import "./Errors.sol" as CastingErrors;
import { SD59x18 } from "../sd59x18/ValueType.sol";
import { UD2x18 } from "../ud2x18/ValueType.sol";
import { UD60x18 } from "../ud60x18/ValueType.sol";
import { SD1x18 } from "./ValueType.sol";
function intoSD59x18(SD1x18 x) pure returns (SD59x18 result) {
result = SD59x18.wrap(int256(SD1x18.unwrap(x)));
}
function intoUD2x18(SD1x18 x) pure returns (UD2x18 result) {
int64 xInt = SD1x18.unwrap(x);
if (xInt < 0) {
revert CastingErrors.PRBMath_SD1x18_ToUD2x18_Underflow(x);
}
result = UD2x18.wrap(uint64(xInt));
}
function intoUD60x18(SD1x18 x) pure returns (UD60x18 result) {
int64 xInt = SD1x18.unwrap(x);
if (xInt < 0) {
revert CastingErrors.PRBMath_SD1x18_ToUD60x18_Underflow(x);
}
result = UD60x18.wrap(uint64(xInt));
}
function intoUint256(SD1x18 x) pure returns (uint256 result) {
int64 xInt = SD1x18.unwrap(x);
if (xInt < 0) {
revert CastingErrors.PRBMath_SD1x18_ToUint256_Underflow(x);
}
result = uint256(uint64(xInt));
}
function intoUint128(SD1x18 x) pure returns (uint128 result) {
int64 xInt = SD1x18.unwrap(x);
if (xInt < 0) {
revert CastingErrors.PRBMath_SD1x18_ToUint128_Underflow(x);
}
result = uint128(uint64(xInt));
}
function intoUint40(SD1x18 x) pure returns (uint40 result) {
int64 xInt = SD1x18.unwrap(x);
if (xInt < 0) {
revert CastingErrors.PRBMath_SD1x18_ToUint40_Underflow(x);
}
if (xInt > int64(uint64(Common.MAX_UINT40))) {
revert CastingErrors.PRBMath_SD1x18_ToUint40_Overflow(x);
}
result = uint40(uint64(xInt));
}
function sd1x18(int64 x) pure returns (SD1x18 result) {
result = SD1x18.wrap(x);
}
function unwrap(SD1x18 x) pure returns (int64 result) {
result = SD1x18.unwrap(x);
}
function wrap(int64 x) pure returns (SD1x18 result) {
result = SD1x18.wrap(x);
}
文件 2 的 17:Common.sol
pragma solidity >=0.8.19;
error PRBMath_MulDiv_Overflow(uint256 x, uint256 y, uint256 denominator);
error PRBMath_MulDiv18_Overflow(uint256 x, uint256 y);
error PRBMath_MulDivSigned_InputTooSmall();
error PRBMath_MulDivSigned_Overflow(int256 x, int256 y);
uint128 constant MAX_UINT128 = type(uint128).max;
uint40 constant MAX_UINT40 = type(uint40).max;
uint256 constant UNIT = 1e18;
uint256 constant UNIT_INVERSE = 78156646155174841979727994598816262306175212592076161876661_508869554232690281;
uint256 constant UNIT_LPOTD = 262144;
function exp2(uint256 x) pure returns (uint256 result) {
unchecked {
result = 0x800000000000000000000000000000000000000000000000;
if (x & 0xFF00000000000000 > 0) {
if (x & 0x8000000000000000 > 0) {
result = (result * 0x16A09E667F3BCC909) >> 64;
}
if (x & 0x4000000000000000 > 0) {
result = (result * 0x1306FE0A31B7152DF) >> 64;
}
if (x & 0x2000000000000000 > 0) {
result = (result * 0x1172B83C7D517ADCE) >> 64;
}
if (x & 0x1000000000000000 > 0) {
result = (result * 0x10B5586CF9890F62A) >> 64;
}
if (x & 0x800000000000000 > 0) {
result = (result * 0x1059B0D31585743AE) >> 64;
}
if (x & 0x400000000000000 > 0) {
result = (result * 0x102C9A3E778060EE7) >> 64;
}
if (x & 0x200000000000000 > 0) {
result = (result * 0x10163DA9FB33356D8) >> 64;
}
if (x & 0x100000000000000 > 0) {
result = (result * 0x100B1AFA5ABCBED61) >> 64;
}
}
if (x & 0xFF000000000000 > 0) {
if (x & 0x80000000000000 > 0) {
result = (result * 0x10058C86DA1C09EA2) >> 64;
}
if (x & 0x40000000000000 > 0) {
result = (result * 0x1002C605E2E8CEC50) >> 64;
}
if (x & 0x20000000000000 > 0) {
result = (result * 0x100162F3904051FA1) >> 64;
}
if (x & 0x10000000000000 > 0) {
result = (result * 0x1000B175EFFDC76BA) >> 64;
}
if (x & 0x8000000000000 > 0) {
result = (result * 0x100058BA01FB9F96D) >> 64;
}
if (x & 0x4000000000000 > 0) {
result = (result * 0x10002C5CC37DA9492) >> 64;
}
if (x & 0x2000000000000 > 0) {
result = (result * 0x1000162E525EE0547) >> 64;
}
if (x & 0x1000000000000 > 0) {
result = (result * 0x10000B17255775C04) >> 64;
}
}
if (x & 0xFF0000000000 > 0) {
if (x & 0x800000000000 > 0) {
result = (result * 0x1000058B91B5BC9AE) >> 64;
}
if (x & 0x400000000000 > 0) {
result = (result * 0x100002C5C89D5EC6D) >> 64;
}
if (x & 0x200000000000 > 0) {
result = (result * 0x10000162E43F4F831) >> 64;
}
if (x & 0x100000000000 > 0) {
result = (result * 0x100000B1721BCFC9A) >> 64;
}
if (x & 0x80000000000 > 0) {
result = (result * 0x10000058B90CF1E6E) >> 64;
}
if (x & 0x40000000000 > 0) {
result = (result * 0x1000002C5C863B73F) >> 64;
}
if (x & 0x20000000000 > 0) {
result = (result * 0x100000162E430E5A2) >> 64;
}
if (x & 0x10000000000 > 0) {
result = (result * 0x1000000B172183551) >> 64;
}
}
if (x & 0xFF00000000 > 0) {
if (x & 0x8000000000 > 0) {
result = (result * 0x100000058B90C0B49) >> 64;
}
if (x & 0x4000000000 > 0) {
result = (result * 0x10000002C5C8601CC) >> 64;
}
if (x & 0x2000000000 > 0) {
result = (result * 0x1000000162E42FFF0) >> 64;
}
if (x & 0x1000000000 > 0) {
result = (result * 0x10000000B17217FBB) >> 64;
}
if (x & 0x800000000 > 0) {
result = (result * 0x1000000058B90BFCE) >> 64;
}
if (x & 0x400000000 > 0) {
result = (result * 0x100000002C5C85FE3) >> 64;
}
if (x & 0x200000000 > 0) {
result = (result * 0x10000000162E42FF1) >> 64;
}
if (x & 0x100000000 > 0) {
result = (result * 0x100000000B17217F8) >> 64;
}
}
if (x & 0xFF000000 > 0) {
if (x & 0x80000000 > 0) {
result = (result * 0x10000000058B90BFC) >> 64;
}
if (x & 0x40000000 > 0) {
result = (result * 0x1000000002C5C85FE) >> 64;
}
if (x & 0x20000000 > 0) {
result = (result * 0x100000000162E42FF) >> 64;
}
if (x & 0x10000000 > 0) {
result = (result * 0x1000000000B17217F) >> 64;
}
if (x & 0x8000000 > 0) {
result = (result * 0x100000000058B90C0) >> 64;
}
if (x & 0x4000000 > 0) {
result = (result * 0x10000000002C5C860) >> 64;
}
if (x & 0x2000000 > 0) {
result = (result * 0x1000000000162E430) >> 64;
}
if (x & 0x1000000 > 0) {
result = (result * 0x10000000000B17218) >> 64;
}
}
if (x & 0xFF0000 > 0) {
if (x & 0x800000 > 0) {
result = (result * 0x1000000000058B90C) >> 64;
}
if (x & 0x400000 > 0) {
result = (result * 0x100000000002C5C86) >> 64;
}
if (x & 0x200000 > 0) {
result = (result * 0x10000000000162E43) >> 64;
}
if (x & 0x100000 > 0) {
result = (result * 0x100000000000B1721) >> 64;
}
if (x & 0x80000 > 0) {
result = (result * 0x10000000000058B91) >> 64;
}
if (x & 0x40000 > 0) {
result = (result * 0x1000000000002C5C8) >> 64;
}
if (x & 0x20000 > 0) {
result = (result * 0x100000000000162E4) >> 64;
}
if (x & 0x10000 > 0) {
result = (result * 0x1000000000000B172) >> 64;
}
}
if (x & 0xFF00 > 0) {
if (x & 0x8000 > 0) {
result = (result * 0x100000000000058B9) >> 64;
}
if (x & 0x4000 > 0) {
result = (result * 0x10000000000002C5D) >> 64;
}
if (x & 0x2000 > 0) {
result = (result * 0x1000000000000162E) >> 64;
}
if (x & 0x1000 > 0) {
result = (result * 0x10000000000000B17) >> 64;
}
if (x & 0x800 > 0) {
result = (result * 0x1000000000000058C) >> 64;
}
if (x & 0x400 > 0) {
result = (result * 0x100000000000002C6) >> 64;
}
if (x & 0x200 > 0) {
result = (result * 0x10000000000000163) >> 64;
}
if (x & 0x100 > 0) {
result = (result * 0x100000000000000B1) >> 64;
}
}
if (x & 0xFF > 0) {
if (x & 0x80 > 0) {
result = (result * 0x10000000000000059) >> 64;
}
if (x & 0x40 > 0) {
result = (result * 0x1000000000000002C) >> 64;
}
if (x & 0x20 > 0) {
result = (result * 0x10000000000000016) >> 64;
}
if (x & 0x10 > 0) {
result = (result * 0x1000000000000000B) >> 64;
}
if (x & 0x8 > 0) {
result = (result * 0x10000000000000006) >> 64;
}
if (x & 0x4 > 0) {
result = (result * 0x10000000000000003) >> 64;
}
if (x & 0x2 > 0) {
result = (result * 0x10000000000000001) >> 64;
}
if (x & 0x1 > 0) {
result = (result * 0x10000000000000001) >> 64;
}
}
result *= UNIT;
result >>= (191 - (x >> 64));
}
}
function msb(uint256 x) pure returns (uint256 result) {
assembly ("memory-safe") {
let factor := shl(7, gt(x, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))
x := shr(factor, x)
result := or(result, factor)
}
assembly ("memory-safe") {
let factor := shl(6, gt(x, 0xFFFFFFFFFFFFFFFF))
x := shr(factor, x)
result := or(result, factor)
}
assembly ("memory-safe") {
let factor := shl(5, gt(x, 0xFFFFFFFF))
x := shr(factor, x)
result := or(result, factor)
}
assembly ("memory-safe") {
let factor := shl(4, gt(x, 0xFFFF))
x := shr(factor, x)
result := or(result, factor)
}
assembly ("memory-safe") {
let factor := shl(3, gt(x, 0xFF))
x := shr(factor, x)
result := or(result, factor)
}
assembly ("memory-safe") {
let factor := shl(2, gt(x, 0xF))
x := shr(factor, x)
result := or(result, factor)
}
assembly ("memory-safe") {
let factor := shl(1, gt(x, 0x3))
x := shr(factor, x)
result := or(result, factor)
}
assembly ("memory-safe") {
let factor := gt(x, 0x1)
result := or(result, factor)
}
}
function mulDiv(uint256 x, uint256 y, uint256 denominator) pure returns (uint256 result) {
uint256 prod0;
uint256 prod1;
assembly ("memory-safe") {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
if (prod1 == 0) {
unchecked {
return prod0 / denominator;
}
}
if (prod1 >= denominator) {
revert PRBMath_MulDiv_Overflow(x, y, denominator);
}
uint256 remainder;
assembly ("memory-safe") {
remainder := mulmod(x, y, denominator)
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
unchecked {
uint256 lpotdod = denominator & (~denominator + 1);
uint256 flippedLpotdod;
assembly ("memory-safe") {
denominator := div(denominator, lpotdod)
prod0 := div(prod0, lpotdod)
flippedLpotdod := add(div(sub(0, lpotdod), lpotdod), 1)
}
prod0 |= prod1 * flippedLpotdod;
uint256 inverse = (3 * denominator) ^ 2;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
result = prod0 * inverse;
}
}
function mulDiv18(uint256 x, uint256 y) pure returns (uint256 result) {
uint256 prod0;
uint256 prod1;
assembly ("memory-safe") {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
if (prod1 == 0) {
unchecked {
return prod0 / UNIT;
}
}
if (prod1 >= UNIT) {
revert PRBMath_MulDiv18_Overflow(x, y);
}
uint256 remainder;
assembly ("memory-safe") {
remainder := mulmod(x, y, UNIT)
result :=
mul(
or(
div(sub(prod0, remainder), UNIT_LPOTD),
mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, UNIT_LPOTD), UNIT_LPOTD), 1))
),
UNIT_INVERSE
)
}
}
function mulDivSigned(int256 x, int256 y, int256 denominator) pure returns (int256 result) {
if (x == type(int256).min || y == type(int256).min || denominator == type(int256).min) {
revert PRBMath_MulDivSigned_InputTooSmall();
}
uint256 xAbs;
uint256 yAbs;
uint256 dAbs;
unchecked {
xAbs = x < 0 ? uint256(-x) : uint256(x);
yAbs = y < 0 ? uint256(-y) : uint256(y);
dAbs = denominator < 0 ? uint256(-denominator) : uint256(denominator);
}
uint256 resultAbs = mulDiv(xAbs, yAbs, dAbs);
if (resultAbs > uint256(type(int256).max)) {
revert PRBMath_MulDivSigned_Overflow(x, y);
}
uint256 sx;
uint256 sy;
uint256 sd;
assembly ("memory-safe") {
sx := sgt(x, sub(0, 1))
sy := sgt(y, sub(0, 1))
sd := sgt(denominator, sub(0, 1))
}
unchecked {
result = sx ^ sy ^ sd == 0 ? -int256(resultAbs) : int256(resultAbs);
}
}
function sqrt(uint256 x) pure returns (uint256 result) {
if (x == 0) {
return 0;
}
uint256 xAux = uint256(x);
result = 1;
if (xAux >= 2 ** 128) {
xAux >>= 128;
result <<= 64;
}
if (xAux >= 2 ** 64) {
xAux >>= 64;
result <<= 32;
}
if (xAux >= 2 ** 32) {
xAux >>= 32;
result <<= 16;
}
if (xAux >= 2 ** 16) {
xAux >>= 16;
result <<= 8;
}
if (xAux >= 2 ** 8) {
xAux >>= 8;
result <<= 4;
}
if (xAux >= 2 ** 4) {
xAux >>= 4;
result <<= 2;
}
if (xAux >= 2 ** 2) {
result <<= 1;
}
unchecked {
result = (result + x / result) >> 1;
result = (result + x / result) >> 1;
result = (result + x / result) >> 1;
result = (result + x / result) >> 1;
result = (result + x / result) >> 1;
result = (result + x / result) >> 1;
result = (result + x / result) >> 1;
uint256 roundedDownResult = x / result;
if (result >= roundedDownResult) {
result = roundedDownResult;
}
}
}
文件 3 的 17:Constants.sol
pragma solidity >=0.8.19;
import { SD1x18 } from "./ValueType.sol";
SD1x18 constant E = SD1x18.wrap(2_718281828459045235);
int64 constant uMAX_SD1x18 = 9_223372036854775807;
SD1x18 constant MAX_SD1x18 = SD1x18.wrap(uMAX_SD1x18);
int64 constant uMIN_SD1x18 = -9_223372036854775808;
SD1x18 constant MIN_SD1x18 = SD1x18.wrap(uMIN_SD1x18);
SD1x18 constant PI = SD1x18.wrap(3_141592653589793238);
SD1x18 constant UNIT = SD1x18.wrap(1e18);
int256 constant uUNIT = 1e18;
文件 4 的 17:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 5 的 17:Conversions.sol
pragma solidity >=0.8.19;
import { uMAX_UD60x18, uUNIT } from "./Constants.sol";
import { PRBMath_UD60x18_Convert_Overflow } from "./Errors.sol";
import { UD60x18 } from "./ValueType.sol";
function convert(UD60x18 x) pure returns (uint256 result) {
result = UD60x18.unwrap(x) / uUNIT;
}
function convert(uint256 x) pure returns (UD60x18 result) {
if (x > uMAX_UD60x18 / uUNIT) {
revert PRBMath_UD60x18_Convert_Overflow(x);
}
unchecked {
result = UD60x18.wrap(x * uUNIT);
}
}
文件 6 的 17:ERC20.sol
pragma solidity ^0.8.0;
import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";
contract ERC20 is Context, IERC20, IERC20Metadata {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => 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 override returns (string memory) {
return _name;
}
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
function decimals() public view virtual override returns (uint8) {
return 18;
}
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, 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) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, allowance(owner, spender) + addedValue);
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = allowance(owner, spender);
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
function _transfer(
address from,
address to,
uint256 amount
) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
_balances[to] += amount;
}
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, 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 += amount;
unchecked {
_balances[account] += amount;
}
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), 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);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
_totalSupply -= amount;
}
emit Transfer(account, address(0), amount);
_afterTokenTransfer(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 _spendAllowance(
address owner,
address spender,
uint256 amount
) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
function _afterTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
}
文件 7 的 17:Errors.sol
pragma solidity >=0.8.19;
import { UD60x18 } from "./ValueType.sol";
error PRBMath_UD60x18_Ceil_Overflow(UD60x18 x);
error PRBMath_UD60x18_Convert_Overflow(uint256 x);
error PRBMath_UD60x18_Exp_InputTooBig(UD60x18 x);
error PRBMath_UD60x18_Exp2_InputTooBig(UD60x18 x);
error PRBMath_UD60x18_Gm_Overflow(UD60x18 x, UD60x18 y);
error PRBMath_UD60x18_IntoSD1x18_Overflow(UD60x18 x);
error PRBMath_UD60x18_IntoSD59x18_Overflow(UD60x18 x);
error PRBMath_UD60x18_IntoUD2x18_Overflow(UD60x18 x);
error PRBMath_UD60x18_IntoUint128_Overflow(UD60x18 x);
error PRBMath_UD60x18_IntoUint40_Overflow(UD60x18 x);
error PRBMath_UD60x18_Log_InputTooSmall(UD60x18 x);
error PRBMath_UD60x18_Sqrt_Overflow(UD60x18 x);
文件 8 的 17:Fenix.sol
pragma solidity ^0.8.17;
import { UD60x18, convert, wrap, unwrap, ud, E, ZERO } from "@prb/math/UD60x18.sol";
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import { IERC165 } from "@openzeppelin/contracts/interfaces/IERC165.sol";
import { IBurnableToken } from "xen-crypto/interfaces/IBurnableToken.sol";
import { IBurnRedeemable } from "xen-crypto/interfaces/IBurnRedeemable.sol";
enum Status {
ACTIVE,
DEFER,
END
}
struct Stake {
Status status;
uint40 startTs;
uint40 deferralTs;
uint40 endTs;
uint16 term;
uint256 fenix;
uint256 shares;
uint256 payout;
}
struct Reward {
uint40 id;
uint40 rewardTs;
uint256 fenix;
address caller;
}
library FenixError {
error WrongCaller(address caller);
error AddressZero();
error BalanceZero();
error TermZero();
error TermGreaterThanMax();
error StakeNotActive();
error StakeNotEnded();
error StakeLate();
error CooldownActive();
error StakeStatusAlreadySet(Status status);
error SizeGreaterThanMax();
}
contract Fenix is IBurnRedeemable, IERC165, ERC20("FENIX", "FENIX") {
address public constant XEN_ADDRESS = 0x06450dEe7FD2Fb8E39061434BAbCFC05599a6Fb8;
uint256 public constant XEN_BURN_RATIO = 10_000;
uint256 public constant MAX_STAKE_LENGTH_DAYS = 7_777;
uint256 internal constant UINT256_MAX = type(uint256).max;
uint256 internal constant ONE_DAY_TS = 86_400;
uint256 internal constant ONE_EIGHTY_DAYS_TS = 15_552_000;
uint256 internal constant REWARD_COOLDOWN_TS = 7_862_400;
uint256 internal constant REWARD_LAUNCH_COOLDOWN_TS = 1_814_400;
UD60x18 public constant ANNUAL_INFLATION_RATE = UD60x18.wrap(0.016180339887498948e18);
UD60x18 internal constant ONE = UD60x18.wrap(1e18);
UD60x18 internal constant ONE_YEAR_DAYS = UD60x18.wrap(365);
uint40 public immutable genesisTs;
uint256 public cooldownUnlockTs;
uint256 public rewardPoolSupply = 0;
uint256 public shareRate = 1e18;
uint256 public equityPoolSupply = 0;
uint256 public equityPoolTotalShares = 0;
mapping(address => Stake[]) internal stakes;
Reward[] internal rewards;
event StartStake(Stake indexed _stake);
event DeferStake(Stake indexed _stake);
event EndStake(Stake indexed _stake);
event FlushRewardPool(Reward indexed reward);
event UpdateShareRate(uint256 indexed _shareRate);
constructor() {
genesisTs = uint40(block.timestamp);
cooldownUnlockTs = block.timestamp + REWARD_LAUNCH_COOLDOWN_TS;
}
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IBurnRedeemable).interfaceId || interfaceId == this.supportsInterface.selector;
}
function onTokenBurned(address user, uint256 amount) external {
if (_msgSender() != XEN_ADDRESS) revert FenixError.WrongCaller(_msgSender());
if (user == address(0)) revert FenixError.AddressZero();
if (amount == 0) revert FenixError.BalanceZero();
uint256 fenix = amount / XEN_BURN_RATIO;
rewardPoolSupply += fenix;
_mint(user, fenix);
emit Redeemed(user, XEN_ADDRESS, address(this), amount, fenix);
}
function burnXEN(uint256 xen) public {
IBurnableToken(XEN_ADDRESS).burn(_msgSender(), xen);
}
function startStake(uint256 fenix, uint256 term) public {
if (fenix == 0) revert FenixError.BalanceZero();
if (term == 0) revert FenixError.TermZero();
uint40 startTs = uint40(block.timestamp);
uint40 endTs = uint40(block.timestamp + (term * ONE_DAY_TS));
uint256 bonus = calculateBonus(fenix, term);
uint256 shares = calculateShares(bonus);
UD60x18 time = ud(term).div(ONE_YEAR_DAYS);
uint256 inflatedSupply = unwrap(ud(fenix).mul((ONE.add(ANNUAL_INFLATION_RATE)).pow(time)));
uint256 newShares = unwrap(ud(shares).mul(ud(inflatedSupply)));
equityPoolSupply += inflatedSupply;
equityPoolTotalShares += newShares;
Stake memory _stake = Stake(Status.ACTIVE, startTs, 0, endTs, uint16(term), fenix, newShares, 0);
stakes[_msgSender()].push(_stake);
_burn(_msgSender(), fenix);
emit StartStake(_stake);
}
function deferStake(uint256 stakeIndex, address stakerAddress) public {
if (stakes[stakerAddress].length <= stakeIndex) revert FenixError.StakeNotActive();
Stake memory _stake = stakes[stakerAddress][stakeIndex];
if (_stake.status != Status.ACTIVE) return;
if (block.timestamp < _stake.endTs && _msgSender() != stakerAddress)
revert FenixError.WrongCaller(_msgSender());
UD60x18 rewardPercent = ZERO;
if (block.timestamp > _stake.endTs) {
rewardPercent = ud(calculateLatePayout(_stake));
} else {
rewardPercent = ud(calculateEarlyPayout(_stake));
}
UD60x18 poolSharePercent = ud(_stake.shares).div(ud(equityPoolTotalShares));
UD60x18 stakerPoolSupplyPercent = poolSharePercent.mul(rewardPercent);
uint256 equitySupply = unwrap(ud(equityPoolSupply).mul(stakerPoolSupplyPercent));
Stake memory deferredStake = Stake(
Status.DEFER,
_stake.startTs,
uint40(block.timestamp),
_stake.endTs,
_stake.term,
_stake.fenix,
_stake.shares,
equitySupply
);
stakes[stakerAddress][stakeIndex] = deferredStake;
equityPoolTotalShares -= _stake.shares;
equityPoolSupply -= equitySupply;
emit DeferStake(deferredStake);
}
function endStake(uint256 stakeIndex) public {
deferStake(stakeIndex, _msgSender());
Stake memory _stake = stakes[_msgSender()][stakeIndex];
if (_stake.status == Status.END) revert FenixError.StakeStatusAlreadySet(Status.END);
_mint(_msgSender(), _stake.payout);
uint256 returnOnStake = unwrap(ud(_stake.payout).div(ud(_stake.fenix)));
if (returnOnStake > shareRate) {
shareRate = returnOnStake;
emit UpdateShareRate(shareRate);
}
Stake memory endedStake = Stake(
Status.END,
_stake.startTs,
_stake.deferralTs,
_stake.endTs,
_stake.term,
_stake.fenix,
_stake.shares,
_stake.payout
);
stakes[_msgSender()][stakeIndex] = endedStake;
emit EndStake(endedStake);
}
function calculateBonus(uint256 fenix, uint256 term) public pure returns (uint256) {
UD60x18 sizeBonus = ud(calculateSizeBonus(fenix));
UD60x18 timeBonus = ud(calculateTimeBonus(term));
UD60x18 bonus = sizeBonus.mul(E.pow(timeBonus));
return unwrap(bonus);
}
function calculateSizeBonus(uint256 fenix) public pure returns (uint256) {
if (fenix >= (UINT256_MAX - 3)) revert FenixError.SizeGreaterThanMax();
return unwrap(ONE.sub((ud(fenix).add(ONE)).inv()));
}
function calculateTimeBonus(uint256 term) public pure returns (uint256) {
if (term > MAX_STAKE_LENGTH_DAYS) revert FenixError.TermGreaterThanMax();
UD60x18 timeBonus = ONE.add(ud(term).div(ud(MAX_STAKE_LENGTH_DAYS)));
return unwrap(timeBonus);
}
function calculateShares(uint256 bonus) public view returns (uint256) {
UD60x18 shares = ud(bonus).div(ud(shareRate));
return unwrap(shares);
}
function calculateEarlyPayout(Stake memory stake) public view returns (uint256) {
if (block.timestamp < stake.startTs || stake.status != Status.ACTIVE) revert FenixError.StakeNotActive();
if (block.timestamp > stake.endTs) revert FenixError.StakeLate();
uint256 termDelta = block.timestamp - stake.startTs;
uint256 scaleTerm = stake.term * ONE_DAY_TS;
UD60x18 reward = (convert(termDelta).div(convert(scaleTerm))).powu(2);
return unwrap(reward);
}
function calculateLatePayout(Stake memory stake) public view returns (uint256) {
if (block.timestamp < stake.startTs || stake.status != Status.ACTIVE) revert FenixError.StakeNotActive();
if (block.timestamp < stake.endTs) revert FenixError.StakeNotEnded();
uint256 lateTs = block.timestamp - stake.endTs;
if (lateTs > ONE_EIGHTY_DAYS_TS) return 0;
UD60x18 penalty = ud(lateTs).div(ud(ONE_EIGHTY_DAYS_TS)).powu(3);
UD60x18 reward = ONE.sub(penalty);
return unwrap(reward);
}
function flushRewardPool() public {
if (block.timestamp < cooldownUnlockTs) revert FenixError.CooldownActive();
uint256 cooldownPeriods = (block.timestamp - cooldownUnlockTs) / REWARD_COOLDOWN_TS;
equityPoolSupply += rewardPoolSupply;
cooldownUnlockTs += REWARD_COOLDOWN_TS + (cooldownPeriods * REWARD_COOLDOWN_TS);
Reward memory reward = Reward(uint40(rewards.length), uint40(block.timestamp), rewardPoolSupply, _msgSender());
rewardPoolSupply = 0;
rewards.push(reward);
emit FlushRewardPool(reward);
}
function stakeFor(address stakerAddress, uint256 stakeIndex) public view returns (Stake memory) {
return stakes[stakerAddress][stakeIndex];
}
function stakeCount(address stakerAddress) public view returns (uint256) {
return stakes[stakerAddress].length;
}
function rewardFor(uint256 index) public view returns (Reward memory) {
return rewards[index];
}
function rewardCount() public view returns (uint256) {
return rewards.length;
}
}
文件 9 的 17:Helpers.sol
pragma solidity >=0.8.19;
import { wrap } from "./Casting.sol";
import { SD59x18 } from "./ValueType.sol";
function add(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
return wrap(x.unwrap() + y.unwrap());
}
function and(SD59x18 x, int256 bits) pure returns (SD59x18 result) {
return wrap(x.unwrap() & bits);
}
function and2(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
return wrap(x.unwrap() & y.unwrap());
}
function eq(SD59x18 x, SD59x18 y) pure returns (bool result) {
result = x.unwrap() == y.unwrap();
}
function gt(SD59x18 x, SD59x18 y) pure returns (bool result) {
result = x.unwrap() > y.unwrap();
}
function gte(SD59x18 x, SD59x18 y) pure returns (bool result) {
result = x.unwrap() >= y.unwrap();
}
function isZero(SD59x18 x) pure returns (bool result) {
result = x.unwrap() == 0;
}
function lshift(SD59x18 x, uint256 bits) pure returns (SD59x18 result) {
result = wrap(x.unwrap() << bits);
}
function lt(SD59x18 x, SD59x18 y) pure returns (bool result) {
result = x.unwrap() < y.unwrap();
}
function lte(SD59x18 x, SD59x18 y) pure returns (bool result) {
result = x.unwrap() <= y.unwrap();
}
function mod(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
result = wrap(x.unwrap() % y.unwrap());
}
function neq(SD59x18 x, SD59x18 y) pure returns (bool result) {
result = x.unwrap() != y.unwrap();
}
function not(SD59x18 x) pure returns (SD59x18 result) {
result = wrap(~x.unwrap());
}
function or(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
result = wrap(x.unwrap() | y.unwrap());
}
function rshift(SD59x18 x, uint256 bits) pure returns (SD59x18 result) {
result = wrap(x.unwrap() >> bits);
}
function sub(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
result = wrap(x.unwrap() - y.unwrap());
}
function unary(SD59x18 x) pure returns (SD59x18 result) {
result = wrap(-x.unwrap());
}
function uncheckedAdd(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
unchecked {
result = wrap(x.unwrap() + y.unwrap());
}
}
function uncheckedSub(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
unchecked {
result = wrap(x.unwrap() - y.unwrap());
}
}
function uncheckedUnary(SD59x18 x) pure returns (SD59x18 result) {
unchecked {
result = wrap(-x.unwrap());
}
}
function xor(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
result = wrap(x.unwrap() ^ y.unwrap());
}
文件 10 的 17:IBurnRedeemable.sol
pragma solidity ^0.8.10;
interface IBurnRedeemable {
event Redeemed(
address indexed user,
address indexed xenContract,
address indexed tokenContract,
uint256 xenAmount,
uint256 tokenAmount
);
function onTokenBurned(address user, uint256 amount) external;
}
文件 11 的 17:IBurnableToken.sol
pragma solidity ^0.8.10;
interface IBurnableToken {
function burn(address user, uint256 amount) external;
}
文件 12 的 17:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 13 的 17:IERC20.sol
pragma solidity ^0.8.0;
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 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 from,
address to,
uint256 amount
) external returns (bool);
}
文件 14 的 17:IERC20Metadata.sol
pragma solidity ^0.8.0;
import "../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);
}
文件 15 的 17:Math.sol
pragma solidity >=0.8.19;
import "../Common.sol" as Common;
import "./Errors.sol" as Errors;
import { wrap } from "./Casting.sol";
import {
uEXP_MAX_INPUT,
uEXP2_MAX_INPUT,
uHALF_UNIT,
uLOG2_10,
uLOG2_E,
uMAX_UD60x18,
uMAX_WHOLE_UD60x18,
UNIT,
uUNIT,
uUNIT_SQUARED,
ZERO
} from "./Constants.sol";
import { UD60x18 } from "./ValueType.sol";
function avg(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {
uint256 xUint = x.unwrap();
uint256 yUint = y.unwrap();
unchecked {
result = wrap((xUint & yUint) + ((xUint ^ yUint) >> 1));
}
}
function ceil(UD60x18 x) pure returns (UD60x18 result) {
uint256 xUint = x.unwrap();
if (xUint > uMAX_WHOLE_UD60x18) {
revert Errors.PRBMath_UD60x18_Ceil_Overflow(x);
}
assembly ("memory-safe") {
let remainder := mod(x, uUNIT)
let delta := sub(uUNIT, remainder)
result := add(x, mul(delta, gt(remainder, 0)))
}
}
function div(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {
result = wrap(Common.mulDiv(x.unwrap(), uUNIT, y.unwrap()));
}
function exp(UD60x18 x) pure returns (UD60x18 result) {
uint256 xUint = x.unwrap();
if (xUint > uEXP_MAX_INPUT) {
revert Errors.PRBMath_UD60x18_Exp_InputTooBig(x);
}
unchecked {
uint256 doubleUnitProduct = xUint * uLOG2_E;
result = exp2(wrap(doubleUnitProduct / uUNIT));
}
}
function exp2(UD60x18 x) pure returns (UD60x18 result) {
uint256 xUint = x.unwrap();
if (xUint > uEXP2_MAX_INPUT) {
revert Errors.PRBMath_UD60x18_Exp2_InputTooBig(x);
}
uint256 x_192x64 = (xUint << 64) / uUNIT;
result = wrap(Common.exp2(x_192x64));
}
function floor(UD60x18 x) pure returns (UD60x18 result) {
assembly ("memory-safe") {
let remainder := mod(x, uUNIT)
result := sub(x, mul(remainder, gt(remainder, 0)))
}
}
function frac(UD60x18 x) pure returns (UD60x18 result) {
assembly ("memory-safe") {
result := mod(x, uUNIT)
}
}
function gm(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {
uint256 xUint = x.unwrap();
uint256 yUint = y.unwrap();
if (xUint == 0 || yUint == 0) {
return ZERO;
}
unchecked {
uint256 xyUint = xUint * yUint;
if (xyUint / xUint != yUint) {
revert Errors.PRBMath_UD60x18_Gm_Overflow(x, y);
}
result = wrap(Common.sqrt(xyUint));
}
}
function inv(UD60x18 x) pure returns (UD60x18 result) {
unchecked {
result = wrap(uUNIT_SQUARED / x.unwrap());
}
}
function ln(UD60x18 x) pure returns (UD60x18 result) {
unchecked {
result = wrap(log2(x).unwrap() * uUNIT / uLOG2_E);
}
}
function log10(UD60x18 x) pure returns (UD60x18 result) {
uint256 xUint = x.unwrap();
if (xUint < uUNIT) {
revert Errors.PRBMath_UD60x18_Log_InputTooSmall(x);
}
assembly ("memory-safe") {
switch x
case 1 { result := mul(uUNIT, sub(0, 18)) }
case 10 { result := mul(uUNIT, sub(1, 18)) }
case 100 { result := mul(uUNIT, sub(2, 18)) }
case 1000 { result := mul(uUNIT, sub(3, 18)) }
case 10000 { result := mul(uUNIT, sub(4, 18)) }
case 100000 { result := mul(uUNIT, sub(5, 18)) }
case 1000000 { result := mul(uUNIT, sub(6, 18)) }
case 10000000 { result := mul(uUNIT, sub(7, 18)) }
case 100000000 { result := mul(uUNIT, sub(8, 18)) }
case 1000000000 { result := mul(uUNIT, sub(9, 18)) }
case 10000000000 { result := mul(uUNIT, sub(10, 18)) }
case 100000000000 { result := mul(uUNIT, sub(11, 18)) }
case 1000000000000 { result := mul(uUNIT, sub(12, 18)) }
case 10000000000000 { result := mul(uUNIT, sub(13, 18)) }
case 100000000000000 { result := mul(uUNIT, sub(14, 18)) }
case 1000000000000000 { result := mul(uUNIT, sub(15, 18)) }
case 10000000000000000 { result := mul(uUNIT, sub(16, 18)) }
case 100000000000000000 { result := mul(uUNIT, sub(17, 18)) }
case 1000000000000000000 { result := 0 }
case 10000000000000000000 { result := uUNIT }
case 100000000000000000000 { result := mul(uUNIT, 2) }
case 1000000000000000000000 { result := mul(uUNIT, 3) }
case 10000000000000000000000 { result := mul(uUNIT, 4) }
case 100000000000000000000000 { result := mul(uUNIT, 5) }
case 1000000000000000000000000 { result := mul(uUNIT, 6) }
case 10000000000000000000000000 { result := mul(uUNIT, 7) }
case 100000000000000000000000000 { result := mul(uUNIT, 8) }
case 1000000000000000000000000000 { result := mul(uUNIT, 9) }
case 10000000000000000000000000000 { result := mul(uUNIT, 10) }
case 100000000000000000000000000000 { result := mul(uUNIT, 11) }
case 1000000000000000000000000000000 { result := mul(uUNIT, 12) }
case 10000000000000000000000000000000 { result := mul(uUNIT, 13) }
case 100000000000000000000000000000000 { result := mul(uUNIT, 14) }
case 1000000000000000000000000000000000 { result := mul(uUNIT, 15) }
case 10000000000000000000000000000000000 { result := mul(uUNIT, 16) }
case 100000000000000000000000000000000000 { result := mul(uUNIT, 17) }
case 1000000000000000000000000000000000000 { result := mul(uUNIT, 18) }
case 10000000000000000000000000000000000000 { result := mul(uUNIT, 19) }
case 100000000000000000000000000000000000000 { result := mul(uUNIT, 20) }
case 1000000000000000000000000000000000000000 { result := mul(uUNIT, 21) }
case 10000000000000000000000000000000000000000 { result := mul(uUNIT, 22) }
case 100000000000000000000000000000000000000000 { result := mul(uUNIT, 23) }
case 1000000000000000000000000000000000000000000 { result := mul(uUNIT, 24) }
case 10000000000000000000000000000000000000000000 { result := mul(uUNIT, 25) }
case 100000000000000000000000000000000000000000000 { result := mul(uUNIT, 26) }
case 1000000000000000000000000000000000000000000000 { result := mul(uUNIT, 27) }
case 10000000000000000000000000000000000000000000000 { result := mul(uUNIT, 28) }
case 100000000000000000000000000000000000000000000000 { result := mul(uUNIT, 29) }
case 1000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 30) }
case 10000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 31) }
case 100000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 32) }
case 1000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 33) }
case 10000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 34) }
case 100000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 35) }
case 1000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 36) }
case 10000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 37) }
case 100000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 38) }
case 1000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 39) }
case 10000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 40) }
case 100000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 41) }
case 1000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 42) }
case 10000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 43) }
case 100000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 44) }
case 1000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 45) }
case 10000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 46) }
case 100000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 47) }
case 1000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 48) }
case 10000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 49) }
case 100000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 50) }
case 1000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 51) }
case 10000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 52) }
case 100000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 53) }
case 1000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 54) }
case 10000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 55) }
case 100000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 56) }
case 1000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 57) }
case 10000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 58) }
case 100000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 59) }
default { result := uMAX_UD60x18 }
}
if (result.unwrap() == uMAX_UD60x18) {
unchecked {
result = wrap(log2(x).unwrap() * uUNIT / uLOG2_10);
}
}
}
function log2(UD60x18 x) pure returns (UD60x18 result) {
uint256 xUint = x.unwrap();
if (xUint < uUNIT) {
revert Errors.PRBMath_UD60x18_Log_InputTooSmall(x);
}
unchecked {
uint256 n = Common.msb(xUint / uUNIT);
uint256 resultUint = n * uUNIT;
uint256 y = xUint >> n;
if (y == uUNIT) {
return wrap(resultUint);
}
uint256 DOUBLE_UNIT = 2e18;
for (uint256 delta = uHALF_UNIT; delta > 0; delta >>= 1) {
y = (y * y) / uUNIT;
if (y >= DOUBLE_UNIT) {
resultUint += delta;
y >>= 1;
}
}
result = wrap(resultUint);
}
}
function mul(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {
result = wrap(Common.mulDiv18(x.unwrap(), y.unwrap()));
}
function pow(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {
uint256 xUint = x.unwrap();
uint256 yUint = y.unwrap();
if (xUint == 0) {
return yUint == 0 ? UNIT : ZERO;
}
else if (xUint == uUNIT) {
return UNIT;
}
if (yUint == 0) {
return UNIT;
}
else if (yUint == uUNIT) {
return x;
}
if (xUint > uUNIT) {
result = exp2(mul(log2(x), y));
}
else {
UD60x18 i = wrap(uUNIT_SQUARED / xUint);
UD60x18 w = exp2(mul(log2(i), y));
result = wrap(uUNIT_SQUARED / w.unwrap());
}
}
function powu(UD60x18 x, uint256 y) pure returns (UD60x18 result) {
uint256 xUint = x.unwrap();
uint256 resultUint = y & 1 > 0 ? xUint : uUNIT;
for (y >>= 1; y > 0; y >>= 1) {
xUint = Common.mulDiv18(xUint, xUint);
if (y & 1 > 0) {
resultUint = Common.mulDiv18(resultUint, xUint);
}
}
result = wrap(resultUint);
}
function sqrt(UD60x18 x) pure returns (UD60x18 result) {
uint256 xUint = x.unwrap();
unchecked {
if (xUint > uMAX_UD60x18 / uUNIT) {
revert Errors.PRBMath_UD60x18_Sqrt_Overflow(x);
}
result = wrap(Common.sqrt(xUint * uUNIT));
}
}
文件 16 的 17:UD60x18.sol
pragma solidity >=0.8.19;
import "./ud60x18/Casting.sol";
import "./ud60x18/Constants.sol";
import "./ud60x18/Conversions.sol";
import "./ud60x18/Errors.sol";
import "./ud60x18/Helpers.sol";
import "./ud60x18/Math.sol";
import "./ud60x18/ValueType.sol";
文件 17 的 17:ValueType.sol
pragma solidity >=0.8.19;
import "./Casting.sol" as Casting;
type UD2x18 is uint64;
using {
Casting.intoSD1x18,
Casting.intoSD59x18,
Casting.intoUD60x18,
Casting.intoUint256,
Casting.intoUint128,
Casting.intoUint40,
Casting.unwrap
} for UD2x18 global;
{
"compilationTarget": {
"src/Fenix.sol": "Fenix"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "none"
},
"optimizer": {
"enabled": true,
"runs": 10000
},
"remappings": [
":@atomize/=src/",
":@openzeppelin/=lib/openzeppelin-contracts/",
":@prb/math/=lib/prb-math/src/",
":@prb/test/=lib/prb-test/src/",
":XEN-crypto/=lib/XEN-crypto/contracts/",
":abdk-libraries-solidity/=lib/abdk-libraries-solidity/",
":ds-test/=lib/forge-std/lib/ds-test/src/",
":forge-std/=lib/forge-std/src/",
":prb-math/=lib/prb-math/src/",
":prb-test/=lib/prb-test/src/",
":xen-crypto/=lib/XEN-crypto/contracts/"
]
}
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AddressZero","type":"error"},{"inputs":[],"name":"BalanceZero","type":"error"},{"inputs":[],"name":"CooldownActive","type":"error"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"name":"PRBMath_MulDiv18_Overflow","type":"error"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"},{"internalType":"uint256","name":"denominator","type":"uint256"}],"name":"PRBMath_MulDiv_Overflow","type":"error"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"}],"name":"PRBMath_UD60x18_Convert_Overflow","type":"error"},{"inputs":[{"internalType":"UD60x18","name":"x","type":"uint256"}],"name":"PRBMath_UD60x18_Exp2_InputTooBig","type":"error"},{"inputs":[{"internalType":"UD60x18","name":"x","type":"uint256"}],"name":"PRBMath_UD60x18_Log_InputTooSmall","type":"error"},{"inputs":[],"name":"SizeGreaterThanMax","type":"error"},{"inputs":[],"name":"StakeLate","type":"error"},{"inputs":[],"name":"StakeNotActive","type":"error"},{"inputs":[],"name":"StakeNotEnded","type":"error"},{"inputs":[{"internalType":"enum Status","name":"status","type":"uint8"}],"name":"StakeStatusAlreadySet","type":"error"},{"inputs":[],"name":"TermGreaterThanMax","type":"error"},{"inputs":[],"name":"TermZero","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"WrongCaller","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":[{"components":[{"internalType":"enum Status","name":"status","type":"uint8"},{"internalType":"uint40","name":"startTs","type":"uint40"},{"internalType":"uint40","name":"deferralTs","type":"uint40"},{"internalType":"uint40","name":"endTs","type":"uint40"},{"internalType":"uint16","name":"term","type":"uint16"},{"internalType":"uint256","name":"fenix","type":"uint256"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"uint256","name":"payout","type":"uint256"}],"indexed":true,"internalType":"struct Stake","name":"_stake","type":"tuple"}],"name":"DeferStake","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"enum Status","name":"status","type":"uint8"},{"internalType":"uint40","name":"startTs","type":"uint40"},{"internalType":"uint40","name":"deferralTs","type":"uint40"},{"internalType":"uint40","name":"endTs","type":"uint40"},{"internalType":"uint16","name":"term","type":"uint16"},{"internalType":"uint256","name":"fenix","type":"uint256"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"uint256","name":"payout","type":"uint256"}],"indexed":true,"internalType":"struct Stake","name":"_stake","type":"tuple"}],"name":"EndStake","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint40","name":"id","type":"uint40"},{"internalType":"uint40","name":"rewardTs","type":"uint40"},{"internalType":"uint256","name":"fenix","type":"uint256"},{"internalType":"address","name":"caller","type":"address"}],"indexed":true,"internalType":"struct Reward","name":"reward","type":"tuple"}],"name":"FlushRewardPool","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"xenContract","type":"address"},{"indexed":true,"internalType":"address","name":"tokenContract","type":"address"},{"indexed":false,"internalType":"uint256","name":"xenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"name":"Redeemed","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"enum Status","name":"status","type":"uint8"},{"internalType":"uint40","name":"startTs","type":"uint40"},{"internalType":"uint40","name":"deferralTs","type":"uint40"},{"internalType":"uint40","name":"endTs","type":"uint40"},{"internalType":"uint16","name":"term","type":"uint16"},{"internalType":"uint256","name":"fenix","type":"uint256"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"uint256","name":"payout","type":"uint256"}],"indexed":true,"internalType":"struct Stake","name":"_stake","type":"tuple"}],"name":"StartStake","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":"uint256","name":"_shareRate","type":"uint256"}],"name":"UpdateShareRate","type":"event"},{"inputs":[],"name":"ANNUAL_INFLATION_RATE","outputs":[{"internalType":"UD60x18","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_STAKE_LENGTH_DAYS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"XEN_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"XEN_BURN_RATIO","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":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"xen","type":"uint256"}],"name":"burnXEN","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"fenix","type":"uint256"},{"internalType":"uint256","name":"term","type":"uint256"}],"name":"calculateBonus","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"enum Status","name":"status","type":"uint8"},{"internalType":"uint40","name":"startTs","type":"uint40"},{"internalType":"uint40","name":"deferralTs","type":"uint40"},{"internalType":"uint40","name":"endTs","type":"uint40"},{"internalType":"uint16","name":"term","type":"uint16"},{"internalType":"uint256","name":"fenix","type":"uint256"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"uint256","name":"payout","type":"uint256"}],"internalType":"struct Stake","name":"stake","type":"tuple"}],"name":"calculateEarlyPayout","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"enum Status","name":"status","type":"uint8"},{"internalType":"uint40","name":"startTs","type":"uint40"},{"internalType":"uint40","name":"deferralTs","type":"uint40"},{"internalType":"uint40","name":"endTs","type":"uint40"},{"internalType":"uint16","name":"term","type":"uint16"},{"internalType":"uint256","name":"fenix","type":"uint256"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"uint256","name":"payout","type":"uint256"}],"internalType":"struct Stake","name":"stake","type":"tuple"}],"name":"calculateLatePayout","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"bonus","type":"uint256"}],"name":"calculateShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"fenix","type":"uint256"}],"name":"calculateSizeBonus","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"term","type":"uint256"}],"name":"calculateTimeBonus","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"cooldownUnlockTs","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"stakeIndex","type":"uint256"},{"internalType":"address","name":"stakerAddress","type":"address"}],"name":"deferStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"stakeIndex","type":"uint256"}],"name":"endStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"equityPoolSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"equityPoolTotalShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"flushRewardPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"genesisTs","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"onTokenBurned","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"rewardFor","outputs":[{"components":[{"internalType":"uint40","name":"id","type":"uint40"},{"internalType":"uint40","name":"rewardTs","type":"uint40"},{"internalType":"uint256","name":"fenix","type":"uint256"},{"internalType":"address","name":"caller","type":"address"}],"internalType":"struct Reward","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardPoolSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"shareRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"stakerAddress","type":"address"}],"name":"stakeCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"stakerAddress","type":"address"},{"internalType":"uint256","name":"stakeIndex","type":"uint256"}],"name":"stakeFor","outputs":[{"components":[{"internalType":"enum Status","name":"status","type":"uint8"},{"internalType":"uint40","name":"startTs","type":"uint40"},{"internalType":"uint40","name":"deferralTs","type":"uint40"},{"internalType":"uint40","name":"endTs","type":"uint40"},{"internalType":"uint16","name":"term","type":"uint16"},{"internalType":"uint256","name":"fenix","type":"uint256"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"uint256","name":"payout","type":"uint256"}],"internalType":"struct Stake","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"fenix","type":"uint256"},{"internalType":"uint256","name":"term","type":"uint256"}],"name":"startStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"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":"amount","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":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]