Source Code
Latest 25 from a total of 4,938 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Sell Shares | 37842525 | 10 mins ago | IN | 0 ETH | 0.00000087 | ||||
| Claim Winnings | 37842336 | 16 mins ago | IN | 0 ETH | 0.00000043 | ||||
| Buy Shares | 37842059 | 25 mins ago | IN | 0 ETH | 0.00000023 | ||||
| Buy Shares | 37842019 | 27 mins ago | IN | 0 ETH | 0.00000032 | ||||
| Buy Shares | 37841953 | 29 mins ago | IN | 0 ETH | 0.00000032 | ||||
| Sell Shares | 37841732 | 36 mins ago | IN | 0 ETH | 0.00000035 | ||||
| Sell Shares | 37841667 | 38 mins ago | IN | 0 ETH | 0.00000036 | ||||
| Buy Shares | 37841155 | 56 mins ago | IN | 0 ETH | 0.00000041 | ||||
| Buy Shares | 37841095 | 58 mins ago | IN | 0 ETH | 0.00000033 | ||||
| Claim Winnings | 37839779 | 1 hr ago | IN | 0 ETH | 0.00000017 | ||||
| Claim Winnings | 37839560 | 1 hr ago | IN | 0 ETH | 0.0000004 | ||||
| Claim Winnings | 37839220 | 2 hrs ago | IN | 0 ETH | 0.00000017 | ||||
| Resolve Market | 37839204 | 2 hrs ago | IN | 0 ETH | 0.00000038 | ||||
| Buy Shares | 37839154 | 2 hrs ago | IN | 0 ETH | 0.00000054 | ||||
| Sell Shares | 37839045 | 2 hrs ago | IN | 0 ETH | 0.00000056 | ||||
| Buy Shares | 37838997 | 2 hrs ago | IN | 0 ETH | 0.00000051 | ||||
| Sell Shares | 37837754 | 2 hrs ago | IN | 0 ETH | 0.00000054 | ||||
| Sell Shares | 37837434 | 3 hrs ago | IN | 0 ETH | 0.00000055 | ||||
| Sell Shares | 37837391 | 3 hrs ago | IN | 0 ETH | 0.00000048 | ||||
| Buy Shares | 37837179 | 3 hrs ago | IN | 0 ETH | 0.00000038 | ||||
| Sell Shares | 37836859 | 3 hrs ago | IN | 0 ETH | 0.00000033 | ||||
| Buy Shares | 37836741 | 3 hrs ago | IN | 0 ETH | 0.00000042 | ||||
| Sell Shares | 37836589 | 3 hrs ago | IN | 0 ETH | 0.0000004 | ||||
| Claim Winnings | 37836310 | 3 hrs ago | IN | 0 ETH | 0.00000036 | ||||
| Claim Winnings | 37836301 | 3 hrs ago | IN | 0 ETH | 0.0000003 |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
PredictBaseUniswapCPMM
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 50 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {UD60x18, ud, unwrap, exp, ln, div, mul, add} from "@prb/math/src/UD60x18.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
contract PredictBaseUniswapCPMM is ReentrancyGuard {
IERC20 public usdcToken;
address public superAdmin;
uint256 public creatorFeePercent = 1; // percent (0-100)
uint256 public protocolFeePercent = 1; // percent (0-100)
uint256 public createMarketFee = 500_000; // USDC (1e6)
// ---------- Errors ----------
error NotSuperAdmin();
error NotAdmin();
error MarketNotActive();
error MarketDoesNotExist();
error ContractPaused();
error InvalidOption();
error ZeroAmount();
error EndDateInPast();
error Closed();
error TransferFailed();
error NotEnoughShares();
error TallyUnderflow();
error InsufficientCollateral();
error NetZeroAfterFees();
error NotResolved();
error NotWinningOption();
error NoWinnings();
error PayoutDepleted();
error BadAddress();
error SlippageExceeded();
bool public paused;
mapping(address => bool) public admins;
enum MarketStatus {Active, Resolved, Canceled}
uint64 private constant UNRESOLVED = type(uint64).max;
struct Market {
// Meta
address creator;
string question;
string[] categories;
string details;
string image;
uint64 endDate;
MarketStatus status;
uint64 winningOption; // 0..N-1, or UNRESOLVED
// LMSR state
uint256 b; // UD60x18 raw (1e18)
uint256 optionCount; // N
uint256[] shares; // per outcome (1e6)
uint256[] totalUser; // per outcome (1e6)
// NOTE: This now stores PRIORS (π_i), 1e18-scaled, sum ≈ 1e18.
uint256[] weights1e18; // (kept name for compatibility; semantics = priors)
// Payout/fees
uint256 userPayoutLeft; // remaining winner shares to pay
uint256 creatorFeeAccrued; // USDC 1e6
uint256 protocolFeeAccrued; // USDC 1e6
// Liquidity/compat
uint256 initialLiquidity; // LP amount (USDC 1e6)
uint256 adminLiquidity; // USDC added by admins
uint256 totalPayout;
// Per-market pool and cancel accounting
uint256 poolBalance; // USDC attributed to THIS market
uint256 cashInTotal; // sum of usdcIn from buys
uint256 cashOutTotal; // sum of netOut from sells
uint256 userRefundedTotal; // amount refunded to users after cancel
}
uint256 public marketCounter;
mapping(uint256 => Market) private markets;
mapping(uint256 => bool) public marketExistsFlag;
// marketId => user => option => shares (1e6)
mapping(uint256 => mapping(address => mapping(uint256 => uint256))) public userShares;
// marketId => user => net USDC (buys - sells), can be negative
mapping(uint256 => mapping(address => int256)) private _userNetCash;
mapping(uint256 => string[]) private optionTitles;
// ---------- Modifiers ----------
modifier onlySuperAdmin() {
if (msg.sender != superAdmin) revert NotSuperAdmin();
_;
}
modifier onlyAdmin() {
if (!(admins[msg.sender] || msg.sender == superAdmin)) revert NotAdmin();
_;
}
modifier marketActive(uint256 marketId) {
if (markets[marketId].status != MarketStatus.Active) revert MarketNotActive();
_;
}
modifier marketExists(uint256 marketId) {
if (!marketExistsFlag[marketId]) revert MarketDoesNotExist();
_;
}
modifier notPaused() {
if (paused) revert ContractPaused();
_;
}
// ---------- Events ----------
event MarketCreated(
uint256 indexed marketId,
address indexed creator,
string question,
string details,
string[] categories,
string image,
uint64 endDate,
string[] optionTitles,
uint256[] shares,
uint256 initialLiquidity,
uint256[] weightRatios,
uint64 winningOption,
MarketStatus status,
uint256 poolBalance,
uint256 b
);
event SharesBought(
uint256 indexed marketId,
address indexed user,
uint256 option,
uint256 usdcIn,
uint256 sharesOut,
uint256[] shares,
uint256 poolBalance,
uint256 creatorFee,
address indexed sender,
bool isGift
);
event SharesSold(
uint256 indexed marketId,
address indexed user,
uint256 option,
uint256 sharesIn,
uint256 usdcOut,
uint256[] shares,
uint256 poolBalance,
uint256 creatorFee,
address indexed sender
);
event MarketResolved(
uint256 indexed marketId,
uint256 winningOption,
MarketStatus status,
uint256 creatorLiquidityReturn,
uint256 adminLiquidityReturn
);
event MarketCanceled(uint256 indexed marketId, address indexed canceledBy, uint256 creatorlpRefund, uint256 adminlpRefund);
event WinningsClaimed(uint256 indexed marketId, address indexed user, uint256 optionIndex, bool isRefund, uint256 amount);
event SuperAdminUpdated(address indexed newSuperAdmin);
event AdminUpdated(address indexed admin, bool isAuthorized);
event Paused(bool status);
event FeesPaid(uint256 indexed marketId, uint256 creatorFee, uint256 protocolFee, address creator, address protocol);
event OptionTitlesUpdated(uint256 indexed marketId, uint256 optionCount);
event MarketEndDateUpdated(uint256 indexed marketId, uint256 newEndDate);
event CreatorFeePercentUpdated(uint256 oldFee, uint256 newFee);
event ProtocolFeePercentUpdated(uint256 oldFee, uint256 newFee);
event CreateMarketFeeUpdated(uint256 oldFee, uint256 newFee);
event LiquidityAdded(uint256 indexed marketId, address indexed admin, uint256 poolBalance, uint256 b, uint256 adminLiquidity);
event MarketInfoUpdated(
uint256 indexed marketId,
string question,
string[] categories,
string details,
string image
);
// ---------- Constructor / Admin ----------
constructor(address _usdc) {
usdcToken = IERC20(_usdc);
superAdmin = msg.sender;
admins[msg.sender] = true;
emit AdminUpdated(msg.sender, true);
}
function setSuperAdmin(address newAdmin) external onlySuperAdmin {
if (newAdmin == address(0)) revert BadAddress();
superAdmin = newAdmin;
emit SuperAdminUpdated(newAdmin);
}
function setAdmin(address admin, bool isAuthorized) external onlySuperAdmin {
if (admin == address(0)) revert BadAddress();
admins[admin] = isAuthorized;
emit AdminUpdated(admin, isAuthorized);
}
function setPaused(bool _paused) external onlySuperAdmin {
paused = _paused;
emit Paused(_paused);
}
function setCreatorFeePercent(uint256 newPercent) external onlyAdmin {
require(newPercent <= 100, "Fee too high");
uint256 old = creatorFeePercent;
creatorFeePercent = newPercent;
emit CreatorFeePercentUpdated(old, newPercent);
}
function setProtocolFeePercent(uint256 newPercent) external onlyAdmin {
require(newPercent <= 100, "Fee too high");
uint256 old = protocolFeePercent;
protocolFeePercent = newPercent;
emit ProtocolFeePercentUpdated(old, newPercent);
}
function setCreateMarketFee(uint256 newFee) external onlyAdmin {
uint256 old = createMarketFee;
createMarketFee = newFee;
emit CreateMarketFeeUpdated(old, newFee);
}
// ---------- Market Lifecycle ----------
function createMarket(
string calldata question,
string[] calldata categories,
string calldata details,
string calldata image,
uint64 endDate,
uint256 initialLiquidity,
string[] calldata _optionTitles,
uint256[] calldata weightRatios // if empty -> equal priors
) external notPaused {
uint256 n = _optionTitles.length;
if (n < 2) revert ZeroAmount();
if (initialLiquidity == 0) revert ZeroAmount();
if (!usdcToken.transferFrom(msg.sender, address(this), initialLiquidity)) revert TransferFailed();
uint256 id = ++marketCounter;
marketExistsFlag[id] = true;
Market storage m = markets[id];
m.creator = msg.sender;
m.question = question;
// Store categories array
delete m.categories;
for (uint256 i = 0; i < categories.length; i++) {
m.categories.push(categories[i]);
}
m.details = details;
m.image = image;
m.endDate = endDate;
m.initialLiquidity = initialLiquidity;
m.adminLiquidity = 0;
m.totalPayout = 0;
m.status = MarketStatus.Active;
m.winningOption = UNRESOLVED;
m.userPayoutLeft = 0;
m.creatorFeeAccrued = 0;
m.poolBalance += initialLiquidity;
_initLmsrWeighted(id, initialLiquidity, _optionTitles, weightRatios);
emit MarketCreated(
id,
m.creator,
m.question,
m.details,
m.categories,
m.image,
m.endDate,
_optionTitles,
m.shares,
m.initialLiquidity,
weightRatios,
m.winningOption,
m.status,
m.poolBalance,
m.b
);
}
// ---------- LMSR Core (PRIOR-weighted) ----------
// C(q) = b * ln( Σ_i π_i * exp(q_i / b) ), with Σ_i π_i ≈ 1 (1e18 scale)
function _initLmsrWeighted(
uint256 marketId,
uint256 totalInit,
string[] calldata titles,
uint256[] calldata ratios // if empty -> equal priors
) internal {
uint256 n = titles.length;
if (n < 2) revert ZeroAmount();
Market storage m = markets[marketId];
// Titles
delete optionTitles[marketId];
for (uint256 i = 0; i < n; i++) optionTitles[marketId].push(titles[i]);
// Arrays
m.optionCount = n;
delete m.shares;
delete m.totalUser;
delete m.weights1e18; // stores priors 1e18-scaled
m.shares = new uint256[](n);
m.totalUser = new uint256[](n);
m.weights1e18 = new uint256[](n);
// ---- Build priors π_i (1e18 scale), sum ≈ 1e18 ----
uint256 minPrior = type(uint256).max;
if (ratios.length == 0) {
// equal priors
uint256 eq = 1e18 / n;
uint256 sum = 0;
for (uint256 i = 0; i < n - 1; i++) {
m.weights1e18[i] = eq;
sum += eq;
if (eq < minPrior) minPrior = eq;
}
// last one: fill to 1e18 to avoid rounding drift
uint256 last = 1e18 - sum;
m.weights1e18[n - 1] = last;
if (last < minPrior) minPrior = last;
} else {
require(ratios.length == n, "ratios length mismatch");
uint256 sumRatios = 0;
for (uint256 i = 0; i < n; i++) sumRatios += ratios[i];
require(sumRatios > 0, "ratios sum zero");
uint256 acc = 0;
for (uint256 i = 0; i < n - 1; i++) {
// π_i = ratios[i] / sumRatios (1e18 scale)
uint256 pi = (ratios[i] * 1e18) / sumRatios;
if (pi == 0) pi = 1; // keep strictly positive
m.weights1e18[i] = pi;
acc += pi;
if (pi < minPrior) minPrior = pi;
}
// last prior = 1e18 - accumulated to ensure exact sum
uint256 last = 1e18 - acc;
if (last == 0) last = 1; // keep positive
m.weights1e18[n - 1] = last;
if (last < minPrior) minPrior = last;
}
// ---- Set b so worst-case loss equals totalInit ----
// loss_bound = b * ln(1 / minPrior), where minPrior is 1e18-scaled.
// Solve b = totalInit / ln(1/minPrior).
// Convert totalInit (1e6) -> UD60x18 by *1e12 to get 1e18 scale.
UD60x18 num = ud(totalInit * 1e12); // 1e18 scale
UD60x18 one = ud(1e18);
UD60x18 minPiUD = ud(minPrior);
// denom = ln(1 / minPrior)
UD60x18 denom = ln(div(one, minPiUD));
// Fallback safety: if denom ≈ 0 (shouldn't happen), use ln(n)
if (unwrap(denom) == 0) {
UD60x18 nUD = ud(n * 1e18);
UD60x18 lnN = ln(nUD);
denom = lnN;
}
UD60x18 bUD = div(num, denom);
m.b = unwrap(bUD);
emit OptionTitlesUpdated(marketId, n);
}
function _cost(uint256 bRaw, uint256[] memory q, uint256[] memory pri1e18)
internal
pure
returns (uint256 cRaw)
{
UD60x18 b = ud(bRaw);
UD60x18 sumExp = ud(0);
for (uint256 i = 0; i < q.length; i++) {
UD60x18 qi = ud(q[i] * 1e12); // 1e6 -> 1e18
UD60x18 prior = ud(pri1e18[i]); // 1e18-scale, Σ prior ≈ 1e18
// term = prior * exp(q_i / b)
UD60x18 term = mul(prior, exp(div(qi, b)));
sumExp = add(sumExp, term);
}
cRaw = unwrap(mul(b, ln(sumExp))); // 1e18
}
function _costToBuy(uint256 bRaw, uint256[] memory q, uint256[] memory pri, uint256 k, uint256 xShares)
internal
pure
returns (uint256 usdc)
{
uint256[] memory qp = new uint256[](q.length);
for (uint256 i = 0; i < q.length; i++) qp[i] = q[i];
qp[k] += xShares;
uint256 beforeRaw = _cost(bRaw, q, pri);
uint256 afterRaw = _cost(bRaw, qp, pri);
uint256 diffRaw = afterRaw - beforeRaw; // 1e18
usdc = diffRaw / 1e12; // 1e6
}
function _refundToSell(uint256 bRaw, uint256[] memory q, uint256[] memory pri, uint256 k, uint256 xShares)
internal
pure
returns (uint256 usdc)
{
uint256[] memory qp = new uint256[](q.length);
for (uint256 i = 0; i < q.length; i++) qp[i] = q[i];
qp[k] -= xShares;
uint256 beforeRaw = _cost(bRaw, q, pri);
uint256 afterRaw = _cost(bRaw, qp, pri);
uint256 diffRaw = beforeRaw - afterRaw; // 1e18
usdc = diffRaw / 1e12; // 1e6
}
function _priceUD(uint256 bRaw, uint256[] memory q, uint256[] memory pri, uint256 k)
internal
pure
returns (uint256 pRaw)
{
UD60x18 b = ud(bRaw);
UD60x18 den = ud(0);
UD60x18 num = ud(0);
for (uint256 i = 0; i < q.length; i++) {
UD60x18 term = mul(ud(pri[i]), exp(div(ud(q[i] * 1e12), b)));
den = add(den, term);
if (i == k) num = term;
}
pRaw = unwrap(div(num, den)); // 0..1 in 1e18
}
function buyShares(uint256 marketId, uint256 option, uint256 sharesOut, uint256 maxUsdcIn)
external
notPaused
marketActive(marketId)
nonReentrant
{
Market storage m = markets[marketId];
if (option >= m.optionCount) revert InvalidOption();
if (sharesOut == 0) revert ZeroAmount();
uint256 cost = _costToBuy(m.b, m.shares, m.weights1e18, option, sharesOut);
if (cost == 0) revert ZeroAmount();
uint256 creatorFee = (cost * creatorFeePercent) / 100;
uint256 protocolFee = (cost * protocolFeePercent) / 100;
uint256 totalFee = creatorFee + protocolFee;
uint256 totalIn = cost + totalFee;
if (totalIn > maxUsdcIn) revert SlippageExceeded();
if (!usdcToken.transferFrom(msg.sender, address(this), totalIn)) revert TransferFailed();
m.creatorFeeAccrued += creatorFee;
m.protocolFeeAccrued += protocolFee;
m.poolBalance += totalIn;
m.cashInTotal += totalIn;
_userNetCash[marketId][msg.sender] += int256(totalIn);
m.shares[option] += sharesOut;
userShares[marketId][msg.sender][option] += sharesOut;
m.totalUser[option] += sharesOut;
emit SharesBought(marketId, msg.sender, option, totalIn, sharesOut, m.shares, m.poolBalance, creatorFee, msg.sender, false);
}
function BuySharesForUser(uint256 marketId, uint256 option, uint256 sharesOut, uint256 maxUsdcIn, address user)
external
notPaused
marketActive(marketId)
nonReentrant
{
Market storage m = markets[marketId];
if (option >= m.optionCount) revert InvalidOption();
if (sharesOut == 0) revert ZeroAmount();
uint256 cost = _costToBuy(m.b, m.shares, m.weights1e18, option, sharesOut);
if (cost == 0) revert ZeroAmount();
uint256 creatorFee = (cost * creatorFeePercent) / 100;
uint256 protocolFee = (cost * protocolFeePercent) / 100;
uint256 totalFee = creatorFee + protocolFee;
uint256 totalIn = cost + totalFee;
if (totalIn > maxUsdcIn) revert SlippageExceeded();
if (!usdcToken.transferFrom(msg.sender, address(this), totalIn)) revert TransferFailed();
m.creatorFeeAccrued += creatorFee;
m.protocolFeeAccrued += protocolFee;
m.poolBalance += totalIn;
m.cashInTotal += totalIn;
_userNetCash[marketId][user] += int256(totalIn);
m.shares[option] += sharesOut;
userShares[marketId][user][option] += sharesOut;
m.totalUser[option] += sharesOut;
emit SharesBought(marketId, user, option, totalIn, sharesOut, m.shares, m.poolBalance, creatorFee, msg.sender, true);
}
function sellShares(uint256 marketId, uint256 option, uint256 sharesIn, uint256 minUsdcOut)
external
notPaused
marketActive(marketId)
nonReentrant
{
Market storage m = markets[marketId];
if (option >= m.optionCount) revert InvalidOption();
if (sharesIn == 0) revert ZeroAmount();
uint256 bal = userShares[marketId][msg.sender][option];
if (bal < sharesIn) revert NotEnoughShares();
uint256 gross = _refundToSell(m.b, m.shares, m.weights1e18, option, sharesIn);
if (gross == 0) revert ZeroAmount();
uint256 creatorFee = (gross * creatorFeePercent) / 100;
uint256 protocolFee = (gross * protocolFeePercent) / 100;
uint256 totalFee = creatorFee + protocolFee;
uint256 netOut = gross - totalFee;
if (netOut < minUsdcOut) revert SlippageExceeded();
m.creatorFeeAccrued += creatorFee;
m.protocolFeeAccrued += protocolFee;
m.shares[option] -= sharesIn;
userShares[marketId][msg.sender][option] = bal - sharesIn;
uint256 tu = m.totalUser[option];
if (tu < sharesIn) revert TallyUnderflow();
m.totalUser[option] = tu - sharesIn;
if (m.poolBalance < netOut) revert InsufficientCollateral();
m.poolBalance -= netOut;
m.cashOutTotal += netOut;
_userNetCash[marketId][msg.sender] -= int256(netOut);
if (!usdcToken.transfer(msg.sender, netOut)) revert TransferFailed();
emit SharesSold(marketId, msg.sender, option, sharesIn, netOut, m.shares, m.poolBalance,creatorFee, msg.sender);
}
// ---------- Resolve ----------
function resolveMarket(uint256 marketId, uint64 winningOption)
external
onlyAdmin
marketActive(marketId)
{
Market storage m = markets[marketId];
if (winningOption >= m.optionCount) revert InvalidOption();
m.status = MarketStatus.Resolved;
m.winningOption = winningOption;
uint256 userWinningSupply = m.totalUser[winningOption]; // 1e6
uint256 feesDue = m.creatorFeeAccrued + m.protocolFeeAccrued;
if (m.poolBalance < userWinningSupply + feesDue) revert InsufficientCollateral();
if (m.creatorFeeAccrued > 0) {
if (!usdcToken.transfer(m.creator, m.creatorFeeAccrued)) revert TransferFailed();
}
if (m.protocolFeeAccrued > 0) {
if (!usdcToken.transfer(superAdmin, m.protocolFeeAccrued)) revert TransferFailed();
}
emit FeesPaid(marketId, m.creatorFeeAccrued, m.protocolFeeAccrued, m.creator, superAdmin);
m.poolBalance -= feesDue;
m.creatorFeeAccrued = 0;
m.protocolFeeAccrued = 0;
uint256 adminLiquidityReturn;
uint256 creatorLiquidityReturn;
uint256 refundable = 0;
if (m.poolBalance > userWinningSupply) {
refundable = m.poolBalance - userWinningSupply;
m.poolBalance -= refundable;
if (refundable > m.initialLiquidity) {
if (!usdcToken.transfer(m.creator, m.initialLiquidity)) revert TransferFailed();
refundable = refundable - m.initialLiquidity;
// return amounts
creatorLiquidityReturn = m.initialLiquidity;
adminLiquidityReturn = refundable;
m.initialLiquidity = 0;
if (refundable > 0) {
if (!usdcToken.transfer(superAdmin, refundable)) revert TransferFailed();
}
} else {
if (!usdcToken.transfer(m.creator, refundable)) revert TransferFailed();
creatorLiquidityReturn = refundable;
adminLiquidityReturn = 0;
}
}
m.userPayoutLeft = userWinningSupply;
emit MarketResolved(marketId, winningOption, m.status, creatorLiquidityReturn, adminLiquidityReturn);
}
// ---------- Cancel ----------
function cancelMarket(uint256 marketId)
external
onlyAdmin
marketExists(marketId)
nonReentrant
{
Market storage m = markets[marketId];
require(
m.status == MarketStatus.Active,
"Only active markets can be cancelled"
);
// Users' still-unclaimed net deposits
uint256 grossUserOwed = (m.cashInTotal > m.cashOutTotal)
? (m.cashInTotal - m.cashOutTotal)
: 0;
uint256 remainingUserOwed = (grossUserOwed > m.userRefundedTotal)
? (grossUserOwed - m.userRefundedTotal)
: 0;
// What the canceller can take for LP right now
uint256 availableForLP = (m.poolBalance > remainingUserOwed)
? (m.poolBalance - remainingUserOwed)
: 0;
uint256 creatorLiquidityRefund = 0;
uint256 adminLiquidityRefund = 0;
// Refund creator's initial liquidity first
if (availableForLP > 0 && m.initialLiquidity > 0) {
creatorLiquidityRefund = availableForLP < m.initialLiquidity ? availableForLP : m.initialLiquidity;
m.initialLiquidity -= creatorLiquidityRefund;
m.poolBalance -= creatorLiquidityRefund;
availableForLP -= creatorLiquidityRefund;
if (!usdcToken.transfer(m.creator, creatorLiquidityRefund)) revert TransferFailed();
}
// Refund admin-added liquidity next
if (availableForLP > 0 && m.adminLiquidity > 0) {
adminLiquidityRefund = availableForLP < m.adminLiquidity ? availableForLP : m.adminLiquidity;
m.adminLiquidity -= adminLiquidityRefund;
m.poolBalance -= adminLiquidityRefund;
if (!usdcToken.transfer(superAdmin, adminLiquidityRefund)) revert TransferFailed();
}
m.status = MarketStatus.Canceled;
m.winningOption = UNRESOLVED;
emit MarketCanceled(marketId, msg.sender, m.initialLiquidity, m.adminLiquidity);
}
function addLiquidity(uint256 marketId, uint256 amount)
external
onlyAdmin
marketActive(marketId)
nonReentrant
{
if (amount == 0) revert ZeroAmount();
Market storage m = markets[marketId];
if (!usdcToken.transferFrom(msg.sender, address(this), amount)) revert TransferFailed();
// Update market pool (trading liquidity)
m.poolBalance += amount;
uint256 oldPool = m.poolBalance - amount;
m.adminLiquidity += amount;
// Scale b: new_b = old_b * (poolBalance + amount) / poolBalance
uint256 oldB = m.b;
m.b = (oldB * m.poolBalance) / oldPool;
emit LiquidityAdded(marketId, msg.sender, m.poolBalance, m.b, m.adminLiquidity);
}
// ---------- Unified Claims ----------
function claimWinnings(uint256 marketId, uint256 option)
external
nonReentrant
{
Market storage m = markets[marketId];
if (m.status == MarketStatus.Resolved) {
if (option != m.winningOption) revert NotWinningOption();
uint256 bal = userShares[marketId][msg.sender][option];
if (bal == 0) revert NoWinnings();
if (m.userPayoutLeft < bal) revert PayoutDepleted();
userShares[marketId][msg.sender][option] = 0;
uint256 tu = m.totalUser[option];
if (tu < bal) revert TallyUnderflow();
m.totalUser[option] = tu - bal;
m.userPayoutLeft -= bal;
if (m.poolBalance < bal) revert InsufficientCollateral();
m.poolBalance -= bal;
if (!usdcToken.transfer(msg.sender, bal)) revert TransferFailed();
emit WinningsClaimed(marketId, msg.sender, option, false,bal);
return;
}
if (m.status == MarketStatus.Canceled) {
int256 net = _userNetCash[marketId][msg.sender];
if (net <= 0) revert NoWinnings();
uint256 refund = uint256(net);
if (m.poolBalance < refund) revert InsufficientCollateral();
_userNetCash[marketId][msg.sender] = 0;
m.poolBalance -= refund;
m.userRefundedTotal += refund;
if (!usdcToken.transfer(msg.sender, refund)) revert TransferFailed();
emit WinningsClaimed(marketId, msg.sender, option, true, refund);
return;
}
revert NotResolved();
}
// ---------- Updates ----------
function updateMarketEndDate(uint256 marketId, uint64 newEndDate)
external
onlyAdmin
marketExists(marketId)
{
Market storage market = markets[marketId];
require(market.status == MarketStatus.Active, "Can only update date for active markets");
market.endDate = newEndDate;
emit MarketEndDateUpdated(marketId, newEndDate);
}
function updateMarketInfo(
uint256 marketId,
string calldata question,
string[] calldata categories,
string calldata details,
string calldata image
)
external
onlyAdmin
marketExists(marketId)
notPaused
{
Market storage m = markets[marketId];
require(m.status == MarketStatus.Active, "Only active markets can be updated");
m.question = question;
delete m.categories;
for (uint256 i = 0; i < categories.length; i++) {
m.categories.push(categories[i]);
}
m.details = details;
m.image = image;
emit MarketInfoUpdated(marketId, question, categories, details, image);
}
// ---------- Views ----------
function getUserNetCash(uint256 marketId, address user) external view returns (int256) {
return _userNetCash[marketId][user];
}
function getOptionCount(uint256 marketId) external view returns (uint256) {
return markets[marketId].optionCount;
}
function getOptionTitles(uint256 marketId) external view returns (string[] memory) {
return optionTitles[marketId];
}
function getOptionPrice(uint256 marketId, uint256 option) external view returns (uint256 price1e6) {
Market storage m = markets[marketId];
if (option >= m.optionCount) revert InvalidOption();
uint256 pUD = _priceUD(m.b, m.shares, m.weights1e18, option); // 1e18
price1e6 = (pUD * 1_000_000) / 1e18; // 1e6
}
function quoteBuyShares(uint256 marketId, uint256 option, uint256 usdcIn)
external
view
returns (uint256 sharesOut)
{
Market storage m = markets[marketId];
if (m.status != MarketStatus.Active) revert MarketNotActive();
if (option >= m.optionCount) revert InvalidOption();
if (usdcIn == 0) revert ZeroAmount();
uint256 creatorFee = (usdcIn * creatorFeePercent) / 100;
uint256 protocolFee = (usdcIn * protocolFeePercent) / 100;
uint256 netSpend = usdcIn - (creatorFee + protocolFee);
if (netSpend == 0) return 0;
uint256[] memory q = new uint256[](m.optionCount);
for (uint256 i = 0; i < m.optionCount; i++) q[i] = m.shares[i];
uint256 lo = 0;
uint256 hi = netSpend * 2;
while (_costToBuy(m.b, q, m.weights1e18, option, hi) < netSpend) {
hi <<= 1;
if (hi > 1e24) break;
}
while (lo < hi) {
uint256 mid = (lo + hi + 1) >> 1;
uint256 cost = _costToBuy(m.b, q, m.weights1e18, option, mid);
if (cost <= netSpend) lo = mid; else hi = mid - 1;
}
sharesOut = lo;
}
function quoteSellShares(uint256 marketId, uint256 option, uint256 sharesIn)
external
view
returns (uint256 usdcOut)
{
Market storage m = markets[marketId];
if (m.status != MarketStatus.Active) revert MarketNotActive();
if (option >= m.optionCount) revert InvalidOption();
if (sharesIn == 0) revert ZeroAmount();
uint256[] memory q = new uint256[](m.optionCount);
for (uint256 i = 0; i < m.optionCount; i++) q[i] = m.shares[i];
uint256 gross = _refundToSell(m.b, q, m.weights1e18, option, sharesIn);
uint256 creatorFee = (gross * creatorFeePercent) / 100;
uint256 protocolFee = (gross * protocolFeePercent) / 100; // NOTE: original had protocol; keep consistent if intended
usdcOut = gross - (creatorFee + protocolFee);
}
function getClaimableWinnings(uint256 marketId, address user) external view returns (uint256) {
Market storage m = markets[marketId];
if (m.status != MarketStatus.Resolved || m.winningOption == UNRESOLVED) return 0;
return userShares[marketId][user][m.winningOption];
}
function getMarketMeta(uint256 marketId)
external
view
returns (
address creator,
string memory question,
string[] memory categories,
string memory details,
string memory image,
uint256 endDate,
MarketStatus status,
uint256 winningOption
)
{
Market storage m = markets[marketId];
uint256 win = (m.winningOption == UNRESOLVED) ? type(uint256).max : uint256(m.winningOption);
return (m.creator, m.question, m.categories, m.details, m.image, m.endDate, m.status, win);
}
function getMarketAccounting(uint256 marketId)
external
view
returns (
uint256 initialLiquidity,
uint256 userPayoutLeft,
uint256[] memory shares,
uint256 creatorFeeAccrued,
uint256 protocolFeeAccrued,
uint256 poolBalance,
uint256 cashInTotal,
uint256 cashOutTotal,
uint256 userRefundedTotal,
uint256[] memory weights1e18 // (priors)
)
{
Market storage m = markets[marketId];
return (
m.initialLiquidity,
m.userPayoutLeft,
m.shares,
m.creatorFeeAccrued,
m.protocolFeeAccrued,
m.poolBalance,
m.cashInTotal,
m.cashOutTotal,
m.userRefundedTotal,
m.weights1e18
);
}
function getUserShares(uint256 marketId, address user, uint256 option) external view returns (uint256) {
return userShares[marketId][user][option];
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol)
pragma solidity >=0.4.16;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,
* consider using {ReentrancyGuardTransient} instead.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
uint256 private _status;
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
constructor() {
_status = NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be NOT_ENTERED
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
_status = ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == ENTERED;
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;
// Common.sol
//
// Common mathematical functions used in both SD59x18 and UD60x18. Note that these global functions do not
// always operate with SD59x18 and UD60x18 numbers.
/*//////////////////////////////////////////////////////////////////////////
CUSTOM ERRORS
//////////////////////////////////////////////////////////////////////////*/
/// @notice Thrown when the resultant value in {mulDiv} overflows uint256.
error PRBMath_MulDiv_Overflow(uint256 x, uint256 y, uint256 denominator);
/// @notice Thrown when the resultant value in {mulDiv18} overflows uint256.
error PRBMath_MulDiv18_Overflow(uint256 x, uint256 y);
/// @notice Thrown when one of the inputs passed to {mulDivSigned} is `type(int256).min`.
error PRBMath_MulDivSigned_InputTooSmall();
/// @notice Thrown when the resultant value in {mulDivSigned} overflows int256.
error PRBMath_MulDivSigned_Overflow(int256 x, int256 y);
/*//////////////////////////////////////////////////////////////////////////
CONSTANTS
//////////////////////////////////////////////////////////////////////////*/
/// @dev The maximum value a uint128 number can have.
uint128 constant MAX_UINT128 = type(uint128).max;
/// @dev The maximum value a uint40 number can have.
uint40 constant MAX_UINT40 = type(uint40).max;
/// @dev The maximum value a uint64 number can have.
uint64 constant MAX_UINT64 = type(uint64).max;
/// @dev The unit number, which the decimal precision of the fixed-point types.
uint256 constant UNIT = 1e18;
/// @dev The unit number inverted mod 2^256.
uint256 constant UNIT_INVERSE = 78156646155174841979727994598816262306175212592076161876661_508869554232690281;
/// @dev The the largest power of two that divides the decimal value of `UNIT`. The logarithm of this value is the least significant
/// bit in the binary representation of `UNIT`.
uint256 constant UNIT_LPOTD = 262144;
/*//////////////////////////////////////////////////////////////////////////
FUNCTIONS
//////////////////////////////////////////////////////////////////////////*/
/// @notice Calculates the binary exponent of x using the binary fraction method.
/// @dev Has to use 192.64-bit fixed-point numbers. See https://ethereum.stackexchange.com/a/96594/24693.
/// @param x The exponent as an unsigned 192.64-bit fixed-point number.
/// @return result The result as an unsigned 60.18-decimal fixed-point number.
/// @custom:smtchecker abstract-function-nondet
function exp2(uint256 x) pure returns (uint256 result) {
unchecked {
// Start from 0.5 in the 192.64-bit fixed-point format.
result = 0x800000000000000000000000000000000000000000000000;
// The following logic multiplies the result by $\sqrt{2^{-i}}$ when the bit at position i is 1. Key points:
//
// 1. Intermediate results will not overflow, as the starting point is 2^191 and all magic factors are under 2^65.
// 2. The rationale for organizing the if statements into groups of 8 is gas savings. If the result of performing
// a bitwise AND operation between x and any value in the array [0x80; 0x40; 0x20; 0x10; 0x08; 0x04; 0x02; 0x01] is 1,
// we know that `x & 0xFF` is also 1.
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;
}
}
// In the code snippet below, two operations are executed simultaneously:
//
// 1. The result is multiplied by $(2^n + 1)$, where $2^n$ represents the integer part, and the additional 1
// accounts for the initial guess of 0.5. This is achieved by subtracting from 191 instead of 192.
// 2. The result is then converted to an unsigned 60.18-decimal fixed-point format.
//
// The underlying logic is based on the relationship $2^{191-ip} = 2^{ip} / 2^{191}$, where $ip$ denotes the,
// integer part, $2^n$.
result *= UNIT;
result >>= (191 - (x >> 64));
}
}
/// @notice Finds the zero-based index of the first 1 in the binary representation of x.
///
/// @dev See the note on "msb" in this Wikipedia article: https://en.wikipedia.org/wiki/Find_first_set
///
/// Each step in this implementation is equivalent to this high-level code:
///
/// ```solidity
/// if (x >= 2 ** 128) {
/// x >>= 128;
/// result += 128;
/// }
/// ```
///
/// Where 128 is replaced with each respective power of two factor. See the full high-level implementation here:
/// https://gist.github.com/PaulRBerg/f932f8693f2733e30c4d479e8e980948
///
/// The Yul instructions used below are:
///
/// - "gt" is "greater than"
/// - "or" is the OR bitwise operator
/// - "shl" is "shift left"
/// - "shr" is "shift right"
///
/// @param x The uint256 number for which to find the index of the most significant bit.
/// @return result The index of the most significant bit as a uint256.
/// @custom:smtchecker abstract-function-nondet
function msb(uint256 x) pure returns (uint256 result) {
// 2^128
assembly ("memory-safe") {
let factor := shl(7, gt(x, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))
x := shr(factor, x)
result := or(result, factor)
}
// 2^64
assembly ("memory-safe") {
let factor := shl(6, gt(x, 0xFFFFFFFFFFFFFFFF))
x := shr(factor, x)
result := or(result, factor)
}
// 2^32
assembly ("memory-safe") {
let factor := shl(5, gt(x, 0xFFFFFFFF))
x := shr(factor, x)
result := or(result, factor)
}
// 2^16
assembly ("memory-safe") {
let factor := shl(4, gt(x, 0xFFFF))
x := shr(factor, x)
result := or(result, factor)
}
// 2^8
assembly ("memory-safe") {
let factor := shl(3, gt(x, 0xFF))
x := shr(factor, x)
result := or(result, factor)
}
// 2^4
assembly ("memory-safe") {
let factor := shl(2, gt(x, 0xF))
x := shr(factor, x)
result := or(result, factor)
}
// 2^2
assembly ("memory-safe") {
let factor := shl(1, gt(x, 0x3))
x := shr(factor, x)
result := or(result, factor)
}
// 2^1
// No need to shift x any more.
assembly ("memory-safe") {
let factor := gt(x, 0x1)
result := or(result, factor)
}
}
/// @notice Calculates x*y÷denominator with 512-bit precision.
///
/// @dev Credits to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv.
///
/// Notes:
/// - The result is rounded toward zero.
///
/// Requirements:
/// - The denominator must not be zero.
/// - The result must fit in uint256.
///
/// @param x The multiplicand as a uint256.
/// @param y The multiplier as a uint256.
/// @param denominator The divisor as a uint256.
/// @return result The result as a uint256.
/// @custom:smtchecker abstract-function-nondet
function mulDiv(uint256 x, uint256 y, uint256 denominator) pure returns (uint256 result) {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512-bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly ("memory-safe") {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
unchecked {
return prod0 / denominator;
}
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
if (prod1 >= denominator) {
revert PRBMath_MulDiv_Overflow(x, y, denominator);
}
////////////////////////////////////////////////////////////////////////////
// 512 by 256 division
////////////////////////////////////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly ("memory-safe") {
// Compute remainder using the mulmod Yul instruction.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512-bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
unchecked {
// Calculate the largest power of two divisor of the denominator using the unary operator ~. This operation cannot overflow
// because the denominator cannot be zero at this point in the function execution. The result is always >= 1.
// For more detail, see https://cs.stackexchange.com/q/138556/92363.
uint256 lpotdod = denominator & (~denominator + 1);
uint256 flippedLpotdod;
assembly ("memory-safe") {
// Factor powers of two out of denominator.
denominator := div(denominator, lpotdod)
// Divide [prod1 prod0] by lpotdod.
prod0 := div(prod0, lpotdod)
// Get the flipped value `2^256 / lpotdod`. If the `lpotdod` is zero, the flipped value is one.
// `sub(0, lpotdod)` produces the two's complement version of `lpotdod`, which is equivalent to flipping all the bits.
// However, `div` interprets this value as an unsigned value: https://ethereum.stackexchange.com/q/147168/24693
flippedLpotdod := add(div(sub(0, lpotdod), lpotdod), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * flippedLpotdod;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
}
}
/// @notice Calculates x*y÷1e18 with 512-bit precision.
///
/// @dev A variant of {mulDiv} with constant folding, i.e. in which the denominator is hard coded to 1e18.
///
/// Notes:
/// - The body is purposely left uncommented; to understand how this works, see the documentation in {mulDiv}.
/// - The result is rounded toward zero.
/// - We take as an axiom that the result cannot be `MAX_UINT256` when x and y solve the following system of equations:
///
/// $$
/// \begin{cases}
/// x * y = MAX\_UINT256 * UNIT \\
/// (x * y) \% UNIT \geq \frac{UNIT}{2}
/// \end{cases}
/// $$
///
/// Requirements:
/// - Refer to the requirements in {mulDiv}.
/// - The result must fit in uint256.
///
/// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number.
/// @param y The multiplier as an unsigned 60.18-decimal fixed-point number.
/// @return result The result as an unsigned 60.18-decimal fixed-point number.
/// @custom:smtchecker abstract-function-nondet
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
)
}
}
/// @notice Calculates x*y÷denominator with 512-bit precision.
///
/// @dev This is an extension of {mulDiv} for signed numbers, which works by computing the signs and the absolute values separately.
///
/// Notes:
/// - The result is rounded toward zero.
///
/// Requirements:
/// - Refer to the requirements in {mulDiv}.
/// - None of the inputs can be `type(int256).min`.
/// - The result must fit in int256.
///
/// @param x The multiplicand as an int256.
/// @param y The multiplier as an int256.
/// @param denominator The divisor as an int256.
/// @return result The result as an int256.
/// @custom:smtchecker abstract-function-nondet
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();
}
// Get hold of the absolute values of x, y and the denominator.
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);
}
// Compute the absolute value of x*y÷denominator. The result must fit in int256.
uint256 resultAbs = mulDiv(xAbs, yAbs, dAbs);
if (resultAbs > uint256(type(int256).max)) {
revert PRBMath_MulDivSigned_Overflow(x, y);
}
// Get the signs of x, y and the denominator.
uint256 sx;
uint256 sy;
uint256 sd;
assembly ("memory-safe") {
// "sgt" is the "signed greater than" assembly instruction and "sub(0,1)" is -1 in two's complement.
sx := sgt(x, sub(0, 1))
sy := sgt(y, sub(0, 1))
sd := sgt(denominator, sub(0, 1))
}
// XOR over sx, sy and sd. What this does is to check whether there are 1 or 3 negative signs in the inputs.
// If there are, the result should be negative. Otherwise, it should be positive.
unchecked {
result = sx ^ sy ^ sd == 0 ? -int256(resultAbs) : int256(resultAbs);
}
}
/// @notice Calculates the square root of x using the Babylonian method.
///
/// @dev See https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.
///
/// Notes:
/// - If x is not a perfect square, the result is rounded down.
/// - Credits to OpenZeppelin for the explanations in comments below.
///
/// @param x The uint256 number for which to calculate the square root.
/// @return result The result as a uint256.
/// @custom:smtchecker abstract-function-nondet
function sqrt(uint256 x) pure returns (uint256 result) {
if (x == 0) {
return 0;
}
// For our first guess, we calculate the biggest power of 2 which is smaller than the square root of x.
//
// We know that the "msb" (most significant bit) of x is a power of 2 such that we have:
//
// $$
// msb(x) <= x <= 2*msb(x)$
// $$
//
// We write $msb(x)$ as $2^k$, and we get:
//
// $$
// k = log_2(x)
// $$
//
// Thus, we can write the initial inequality as:
//
// $$
// 2^{log_2(x)} <= x <= 2*2^{log_2(x)+1} \\
// sqrt(2^k) <= sqrt(x) < sqrt(2^{k+1}) \\
// 2^{k/2} <= sqrt(x) < 2^{(k+1)/2} <= 2^{(k/2)+1}
// $$
//
// Consequently, $2^{log_2(x) /2} is a good first approximation of sqrt(x) with at least one correct bit.
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;
}
// At this point, `result` is an estimation with at least one bit of precision. We know the true value has at
// most 128 bits, since it is the square root of a uint256. Newton's method converges quadratically (precision
// doubles at every iteration). We thus need at most 7 iteration to turn our partial result with one bit of
// precision into the expected uint128 result.
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;
// If x is not a perfect square, round the result toward zero.
uint256 roundedResult = x / result;
if (result >= roundedResult) {
result = roundedResult;
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;
import "../Common.sol" as Common;
import "./Errors.sol" as CastingErrors;
import { SD59x18 } from "../sd59x18/ValueType.sol";
import { UD60x18 } from "../ud60x18/ValueType.sol";
import { SD1x18 } from "./ValueType.sol";
/// @notice Casts an SD1x18 number into SD59x18.
/// @dev There is no overflow check because SD1x18 ⊆ SD59x18.
function intoSD59x18(SD1x18 x) pure returns (SD59x18 result) {
result = SD59x18.wrap(int256(SD1x18.unwrap(x)));
}
/// @notice Casts an SD1x18 number into UD60x18.
/// @dev Requirements:
/// - x ≥ 0
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));
}
/// @notice Casts an SD1x18 number into uint128.
/// @dev Requirements:
/// - x ≥ 0
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));
}
/// @notice Casts an SD1x18 number into uint256.
/// @dev Requirements:
/// - x ≥ 0
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));
}
/// @notice Casts an SD1x18 number into uint40.
/// @dev Requirements:
/// - x ≥ 0
/// - x ≤ MAX_UINT40
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));
}
/// @notice Alias for {wrap}.
function sd1x18(int64 x) pure returns (SD1x18 result) {
result = SD1x18.wrap(x);
}
/// @notice Unwraps an SD1x18 number into int64.
function unwrap(SD1x18 x) pure returns (int64 result) {
result = SD1x18.unwrap(x);
}
/// @notice Wraps an int64 number into SD1x18.
function wrap(int64 x) pure returns (SD1x18 result) {
result = SD1x18.wrap(x);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;
import { SD1x18 } from "./ValueType.sol";
/// @dev Euler's number as an SD1x18 number.
SD1x18 constant E = SD1x18.wrap(2_718281828459045235);
/// @dev The maximum value an SD1x18 number can have.
int64 constant uMAX_SD1x18 = 9_223372036854775807;
SD1x18 constant MAX_SD1x18 = SD1x18.wrap(uMAX_SD1x18);
/// @dev The minimum value an SD1x18 number can have.
int64 constant uMIN_SD1x18 = -9_223372036854775808;
SD1x18 constant MIN_SD1x18 = SD1x18.wrap(uMIN_SD1x18);
/// @dev PI as an SD1x18 number.
SD1x18 constant PI = SD1x18.wrap(3_141592653589793238);
/// @dev The unit number, which gives the decimal precision of SD1x18.
SD1x18 constant UNIT = SD1x18.wrap(1e18);
int64 constant uUNIT = 1e18;// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;
import { SD1x18 } from "./ValueType.sol";
/// @notice Thrown when trying to cast an SD1x18 number that doesn't fit in UD60x18.
error PRBMath_SD1x18_ToUD60x18_Underflow(SD1x18 x);
/// @notice Thrown when trying to cast an SD1x18 number that doesn't fit in uint128.
error PRBMath_SD1x18_ToUint128_Underflow(SD1x18 x);
/// @notice Thrown when trying to cast an SD1x18 number that doesn't fit in uint256.
error PRBMath_SD1x18_ToUint256_Underflow(SD1x18 x);
/// @notice Thrown when trying to cast an SD1x18 number that doesn't fit in uint40.
error PRBMath_SD1x18_ToUint40_Overflow(SD1x18 x);
/// @notice Thrown when trying to cast an SD1x18 number that doesn't fit in uint40.
error PRBMath_SD1x18_ToUint40_Underflow(SD1x18 x);// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;
import "./Casting.sol" as Casting;
/// @notice The signed 1.18-decimal fixed-point number representation, which can have up to 1 digit and up to 18
/// decimals. The values of this are bound by the minimum and the maximum values permitted by the underlying Solidity
/// type int64. This is useful when end users want to use int64 to save gas, e.g. with tight variable packing in contract
/// storage.
type SD1x18 is int64;
/*//////////////////////////////////////////////////////////////////////////
CASTING
//////////////////////////////////////////////////////////////////////////*/
using {
Casting.intoSD59x18,
Casting.intoUD60x18,
Casting.intoUint128,
Casting.intoUint256,
Casting.intoUint40,
Casting.unwrap
} for SD1x18 global;// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;
import "../Common.sol" as Common;
import "./Errors.sol" as CastingErrors;
import { SD59x18 } from "../sd59x18/ValueType.sol";
import { UD60x18 } from "../ud60x18/ValueType.sol";
import { SD21x18 } from "./ValueType.sol";
/// @notice Casts an SD21x18 number into SD59x18.
/// @dev There is no overflow check because SD21x18 ⊆ SD59x18.
function intoSD59x18(SD21x18 x) pure returns (SD59x18 result) {
result = SD59x18.wrap(int256(SD21x18.unwrap(x)));
}
/// @notice Casts an SD21x18 number into UD60x18.
/// @dev Requirements:
/// - x ≥ 0
function intoUD60x18(SD21x18 x) pure returns (UD60x18 result) {
int128 xInt = SD21x18.unwrap(x);
if (xInt < 0) {
revert CastingErrors.PRBMath_SD21x18_ToUD60x18_Underflow(x);
}
result = UD60x18.wrap(uint128(xInt));
}
/// @notice Casts an SD21x18 number into uint128.
/// @dev Requirements:
/// - x ≥ 0
function intoUint128(SD21x18 x) pure returns (uint128 result) {
int128 xInt = SD21x18.unwrap(x);
if (xInt < 0) {
revert CastingErrors.PRBMath_SD21x18_ToUint128_Underflow(x);
}
result = uint128(xInt);
}
/// @notice Casts an SD21x18 number into uint256.
/// @dev Requirements:
/// - x ≥ 0
function intoUint256(SD21x18 x) pure returns (uint256 result) {
int128 xInt = SD21x18.unwrap(x);
if (xInt < 0) {
revert CastingErrors.PRBMath_SD21x18_ToUint256_Underflow(x);
}
result = uint256(uint128(xInt));
}
/// @notice Casts an SD21x18 number into uint40.
/// @dev Requirements:
/// - x ≥ 0
/// - x ≤ MAX_UINT40
function intoUint40(SD21x18 x) pure returns (uint40 result) {
int128 xInt = SD21x18.unwrap(x);
if (xInt < 0) {
revert CastingErrors.PRBMath_SD21x18_ToUint40_Underflow(x);
}
if (xInt > int128(uint128(Common.MAX_UINT40))) {
revert CastingErrors.PRBMath_SD21x18_ToUint40_Overflow(x);
}
result = uint40(uint128(xInt));
}
/// @notice Alias for {wrap}.
function sd21x18(int128 x) pure returns (SD21x18 result) {
result = SD21x18.wrap(x);
}
/// @notice Unwraps an SD21x18 number into int128.
function unwrap(SD21x18 x) pure returns (int128 result) {
result = SD21x18.unwrap(x);
}
/// @notice Wraps an int128 number into SD21x18.
function wrap(int128 x) pure returns (SD21x18 result) {
result = SD21x18.wrap(x);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;
import { SD21x18 } from "./ValueType.sol";
/// @dev Euler's number as an SD21x18 number.
SD21x18 constant E = SD21x18.wrap(2_718281828459045235);
/// @dev The maximum value an SD21x18 number can have.
int128 constant uMAX_SD21x18 = 170141183460469231731_687303715884105727;
SD21x18 constant MAX_SD21x18 = SD21x18.wrap(uMAX_SD21x18);
/// @dev The minimum value an SD21x18 number can have.
int128 constant uMIN_SD21x18 = -170141183460469231731_687303715884105728;
SD21x18 constant MIN_SD21x18 = SD21x18.wrap(uMIN_SD21x18);
/// @dev PI as an SD21x18 number.
SD21x18 constant PI = SD21x18.wrap(3_141592653589793238);
/// @dev The unit number, which gives the decimal precision of SD21x18.
SD21x18 constant UNIT = SD21x18.wrap(1e18);
int128 constant uUNIT = 1e18;// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;
import { SD21x18 } from "./ValueType.sol";
/// @notice Thrown when trying to cast an SD21x18 number that doesn't fit in uint128.
error PRBMath_SD21x18_ToUint128_Underflow(SD21x18 x);
/// @notice Thrown when trying to cast an SD21x18 number that doesn't fit in UD60x18.
error PRBMath_SD21x18_ToUD60x18_Underflow(SD21x18 x);
/// @notice Thrown when trying to cast an SD21x18 number that doesn't fit in uint256.
error PRBMath_SD21x18_ToUint256_Underflow(SD21x18 x);
/// @notice Thrown when trying to cast an SD21x18 number that doesn't fit in uint40.
error PRBMath_SD21x18_ToUint40_Overflow(SD21x18 x);
/// @notice Thrown when trying to cast an SD21x18 number that doesn't fit in uint40.
error PRBMath_SD21x18_ToUint40_Underflow(SD21x18 x);// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;
import "./Casting.sol" as Casting;
/// @notice The signed 21.18-decimal fixed-point number representation, which can have up to 21 digits and up to 18
/// decimals. The values of this are bound by the minimum and the maximum values permitted by the underlying Solidity
/// type int128. This is useful when end users want to use int128 to save gas, e.g. with tight variable packing in contract
/// storage.
type SD21x18 is int128;
/*//////////////////////////////////////////////////////////////////////////
CASTING
//////////////////////////////////////////////////////////////////////////*/
using {
Casting.intoSD59x18,
Casting.intoUD60x18,
Casting.intoUint128,
Casting.intoUint256,
Casting.intoUint40,
Casting.unwrap
} for SD21x18 global;// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;
import "./Errors.sol" as CastingErrors;
import { MAX_UINT128, MAX_UINT40 } from "../Common.sol";
import { uMAX_SD1x18, uMIN_SD1x18 } from "../sd1x18/Constants.sol";
import { SD1x18 } from "../sd1x18/ValueType.sol";
import { uMAX_SD21x18, uMIN_SD21x18 } from "../sd21x18/Constants.sol";
import { SD21x18 } from "../sd21x18/ValueType.sol";
import { uMAX_UD2x18 } from "../ud2x18/Constants.sol";
import { UD2x18 } from "../ud2x18/ValueType.sol";
import { uMAX_UD21x18 } from "../ud21x18/Constants.sol";
import { UD21x18 } from "../ud21x18/ValueType.sol";
import { UD60x18 } from "../ud60x18/ValueType.sol";
import { SD59x18 } from "./ValueType.sol";
/// @notice Casts an SD59x18 number into int256.
/// @dev This is basically a functional alias for {unwrap}.
function intoInt256(SD59x18 x) pure returns (int256 result) {
result = SD59x18.unwrap(x);
}
/// @notice Casts an SD59x18 number into SD1x18.
/// @dev Requirements:
/// - x ≥ uMIN_SD1x18
/// - x ≤ uMAX_SD1x18
function intoSD1x18(SD59x18 x) pure returns (SD1x18 result) {
int256 xInt = SD59x18.unwrap(x);
if (xInt < uMIN_SD1x18) {
revert CastingErrors.PRBMath_SD59x18_IntoSD1x18_Underflow(x);
}
if (xInt > uMAX_SD1x18) {
revert CastingErrors.PRBMath_SD59x18_IntoSD1x18_Overflow(x);
}
result = SD1x18.wrap(int64(xInt));
}
/// @notice Casts an SD59x18 number into SD21x18.
/// @dev Requirements:
/// - x ≥ uMIN_SD21x18
/// - x ≤ uMAX_SD21x18
function intoSD21x18(SD59x18 x) pure returns (SD21x18 result) {
int256 xInt = SD59x18.unwrap(x);
if (xInt < uMIN_SD21x18) {
revert CastingErrors.PRBMath_SD59x18_IntoSD21x18_Underflow(x);
}
if (xInt > uMAX_SD21x18) {
revert CastingErrors.PRBMath_SD59x18_IntoSD21x18_Overflow(x);
}
result = SD21x18.wrap(int128(xInt));
}
/// @notice Casts an SD59x18 number into UD2x18.
/// @dev Requirements:
/// - x ≥ 0
/// - x ≤ uMAX_UD2x18
function intoUD2x18(SD59x18 x) pure returns (UD2x18 result) {
int256 xInt = SD59x18.unwrap(x);
if (xInt < 0) {
revert CastingErrors.PRBMath_SD59x18_IntoUD2x18_Underflow(x);
}
if (xInt > int256(uint256(uMAX_UD2x18))) {
revert CastingErrors.PRBMath_SD59x18_IntoUD2x18_Overflow(x);
}
result = UD2x18.wrap(uint64(uint256(xInt)));
}
/// @notice Casts an SD59x18 number into UD21x18.
/// @dev Requirements:
/// - x ≥ 0
/// - x ≤ uMAX_UD21x18
function intoUD21x18(SD59x18 x) pure returns (UD21x18 result) {
int256 xInt = SD59x18.unwrap(x);
if (xInt < 0) {
revert CastingErrors.PRBMath_SD59x18_IntoUD21x18_Underflow(x);
}
if (xInt > int256(uint256(uMAX_UD21x18))) {
revert CastingErrors.PRBMath_SD59x18_IntoUD21x18_Overflow(x);
}
result = UD21x18.wrap(uint128(uint256(xInt)));
}
/// @notice Casts an SD59x18 number into UD60x18.
/// @dev Requirements:
/// - x ≥ 0
function intoUD60x18(SD59x18 x) pure returns (UD60x18 result) {
int256 xInt = SD59x18.unwrap(x);
if (xInt < 0) {
revert CastingErrors.PRBMath_SD59x18_IntoUD60x18_Underflow(x);
}
result = UD60x18.wrap(uint256(xInt));
}
/// @notice Casts an SD59x18 number into uint256.
/// @dev Requirements:
/// - x ≥ 0
function intoUint256(SD59x18 x) pure returns (uint256 result) {
int256 xInt = SD59x18.unwrap(x);
if (xInt < 0) {
revert CastingErrors.PRBMath_SD59x18_IntoUint256_Underflow(x);
}
result = uint256(xInt);
}
/// @notice Casts an SD59x18 number into uint128.
/// @dev Requirements:
/// - x ≥ 0
/// - x ≤ uMAX_UINT128
function intoUint128(SD59x18 x) pure returns (uint128 result) {
int256 xInt = SD59x18.unwrap(x);
if (xInt < 0) {
revert CastingErrors.PRBMath_SD59x18_IntoUint128_Underflow(x);
}
if (xInt > int256(uint256(MAX_UINT128))) {
revert CastingErrors.PRBMath_SD59x18_IntoUint128_Overflow(x);
}
result = uint128(uint256(xInt));
}
/// @notice Casts an SD59x18 number into uint40.
/// @dev Requirements:
/// - x ≥ 0
/// - x ≤ MAX_UINT40
function intoUint40(SD59x18 x) pure returns (uint40 result) {
int256 xInt = SD59x18.unwrap(x);
if (xInt < 0) {
revert CastingErrors.PRBMath_SD59x18_IntoUint40_Underflow(x);
}
if (xInt > int256(uint256(MAX_UINT40))) {
revert CastingErrors.PRBMath_SD59x18_IntoUint40_Overflow(x);
}
result = uint40(uint256(xInt));
}
/// @notice Alias for {wrap}.
function sd(int256 x) pure returns (SD59x18 result) {
result = SD59x18.wrap(x);
}
/// @notice Alias for {wrap}.
function sd59x18(int256 x) pure returns (SD59x18 result) {
result = SD59x18.wrap(x);
}
/// @notice Unwraps an SD59x18 number into int256.
function unwrap(SD59x18 x) pure returns (int256 result) {
result = SD59x18.unwrap(x);
}
/// @notice Wraps an int256 number into SD59x18.
function wrap(int256 x) pure returns (SD59x18 result) {
result = SD59x18.wrap(x);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;
import { SD59x18 } from "./ValueType.sol";
// NOTICE: the "u" prefix stands for "unwrapped".
/// @dev Euler's number as an SD59x18 number.
SD59x18 constant E = SD59x18.wrap(2_718281828459045235);
/// @dev The maximum input permitted in {exp}.
int256 constant uEXP_MAX_INPUT = 133_084258667509499440;
SD59x18 constant EXP_MAX_INPUT = SD59x18.wrap(uEXP_MAX_INPUT);
/// @dev Any value less than this returns 0 in {exp}.
int256 constant uEXP_MIN_THRESHOLD = -41_446531673892822322;
SD59x18 constant EXP_MIN_THRESHOLD = SD59x18.wrap(uEXP_MIN_THRESHOLD);
/// @dev The maximum input permitted in {exp2}.
int256 constant uEXP2_MAX_INPUT = 192e18 - 1;
SD59x18 constant EXP2_MAX_INPUT = SD59x18.wrap(uEXP2_MAX_INPUT);
/// @dev Any value less than this returns 0 in {exp2}.
int256 constant uEXP2_MIN_THRESHOLD = -59_794705707972522261;
SD59x18 constant EXP2_MIN_THRESHOLD = SD59x18.wrap(uEXP2_MIN_THRESHOLD);
/// @dev Half the UNIT number.
int256 constant uHALF_UNIT = 0.5e18;
SD59x18 constant HALF_UNIT = SD59x18.wrap(uHALF_UNIT);
/// @dev $log_2(10)$ as an SD59x18 number.
int256 constant uLOG2_10 = 3_321928094887362347;
SD59x18 constant LOG2_10 = SD59x18.wrap(uLOG2_10);
/// @dev $log_2(e)$ as an SD59x18 number.
int256 constant uLOG2_E = 1_442695040888963407;
SD59x18 constant LOG2_E = SD59x18.wrap(uLOG2_E);
/// @dev The maximum value an SD59x18 number can have.
int256 constant uMAX_SD59x18 = 57896044618658097711785492504343953926634992332820282019728_792003956564819967;
SD59x18 constant MAX_SD59x18 = SD59x18.wrap(uMAX_SD59x18);
/// @dev The maximum whole value an SD59x18 number can have.
int256 constant uMAX_WHOLE_SD59x18 = 57896044618658097711785492504343953926634992332820282019728_000000000000000000;
SD59x18 constant MAX_WHOLE_SD59x18 = SD59x18.wrap(uMAX_WHOLE_SD59x18);
/// @dev The minimum value an SD59x18 number can have.
int256 constant uMIN_SD59x18 = -57896044618658097711785492504343953926634992332820282019728_792003956564819968;
SD59x18 constant MIN_SD59x18 = SD59x18.wrap(uMIN_SD59x18);
/// @dev The minimum whole value an SD59x18 number can have.
int256 constant uMIN_WHOLE_SD59x18 = -57896044618658097711785492504343953926634992332820282019728_000000000000000000;
SD59x18 constant MIN_WHOLE_SD59x18 = SD59x18.wrap(uMIN_WHOLE_SD59x18);
/// @dev PI as an SD59x18 number.
SD59x18 constant PI = SD59x18.wrap(3_141592653589793238);
/// @dev The unit number, which gives the decimal precision of SD59x18.
int256 constant uUNIT = 1e18;
SD59x18 constant UNIT = SD59x18.wrap(1e18);
/// @dev The unit number squared.
int256 constant uUNIT_SQUARED = 1e36;
SD59x18 constant UNIT_SQUARED = SD59x18.wrap(uUNIT_SQUARED);
/// @dev Zero as an SD59x18 number.
SD59x18 constant ZERO = SD59x18.wrap(0);// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;
import { SD59x18 } from "./ValueType.sol";
/// @notice Thrown when taking the absolute value of `MIN_SD59x18`.
error PRBMath_SD59x18_Abs_MinSD59x18();
/// @notice Thrown when ceiling a number overflows SD59x18.
error PRBMath_SD59x18_Ceil_Overflow(SD59x18 x);
/// @notice Thrown when converting a basic integer to the fixed-point format overflows SD59x18.
error PRBMath_SD59x18_Convert_Overflow(int256 x);
/// @notice Thrown when converting a basic integer to the fixed-point format underflows SD59x18.
error PRBMath_SD59x18_Convert_Underflow(int256 x);
/// @notice Thrown when dividing two numbers and one of them is `MIN_SD59x18`.
error PRBMath_SD59x18_Div_InputTooSmall();
/// @notice Thrown when dividing two numbers and one of the intermediary unsigned results overflows SD59x18.
error PRBMath_SD59x18_Div_Overflow(SD59x18 x, SD59x18 y);
/// @notice Thrown when taking the natural exponent of a base greater than 133_084258667509499441.
error PRBMath_SD59x18_Exp_InputTooBig(SD59x18 x);
/// @notice Thrown when taking the binary exponent of a base greater than 192e18.
error PRBMath_SD59x18_Exp2_InputTooBig(SD59x18 x);
/// @notice Thrown when flooring a number underflows SD59x18.
error PRBMath_SD59x18_Floor_Underflow(SD59x18 x);
/// @notice Thrown when taking the geometric mean of two numbers and their product is negative.
error PRBMath_SD59x18_Gm_NegativeProduct(SD59x18 x, SD59x18 y);
/// @notice Thrown when taking the geometric mean of two numbers and multiplying them overflows SD59x18.
error PRBMath_SD59x18_Gm_Overflow(SD59x18 x, SD59x18 y);
/// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in SD1x18.
error PRBMath_SD59x18_IntoSD1x18_Overflow(SD59x18 x);
/// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in SD1x18.
error PRBMath_SD59x18_IntoSD1x18_Underflow(SD59x18 x);
/// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in SD21x18.
error PRBMath_SD59x18_IntoSD21x18_Overflow(SD59x18 x);
/// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in SD21x18.
error PRBMath_SD59x18_IntoSD21x18_Underflow(SD59x18 x);
/// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in UD2x18.
error PRBMath_SD59x18_IntoUD2x18_Overflow(SD59x18 x);
/// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in UD2x18.
error PRBMath_SD59x18_IntoUD2x18_Underflow(SD59x18 x);
/// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in UD21x18.
error PRBMath_SD59x18_IntoUD21x18_Overflow(SD59x18 x);
/// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in UD21x18.
error PRBMath_SD59x18_IntoUD21x18_Underflow(SD59x18 x);
/// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in UD60x18.
error PRBMath_SD59x18_IntoUD60x18_Underflow(SD59x18 x);
/// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in uint128.
error PRBMath_SD59x18_IntoUint128_Overflow(SD59x18 x);
/// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in uint128.
error PRBMath_SD59x18_IntoUint128_Underflow(SD59x18 x);
/// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in uint256.
error PRBMath_SD59x18_IntoUint256_Underflow(SD59x18 x);
/// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in uint40.
error PRBMath_SD59x18_IntoUint40_Overflow(SD59x18 x);
/// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in uint40.
error PRBMath_SD59x18_IntoUint40_Underflow(SD59x18 x);
/// @notice Thrown when taking the logarithm of a number less than or equal to zero.
error PRBMath_SD59x18_Log_InputTooSmall(SD59x18 x);
/// @notice Thrown when multiplying two numbers and one of the inputs is `MIN_SD59x18`.
error PRBMath_SD59x18_Mul_InputTooSmall();
/// @notice Thrown when multiplying two numbers and the intermediary absolute result overflows SD59x18.
error PRBMath_SD59x18_Mul_Overflow(SD59x18 x, SD59x18 y);
/// @notice Thrown when raising a number to a power and the intermediary absolute result overflows SD59x18.
error PRBMath_SD59x18_Powu_Overflow(SD59x18 x, uint256 y);
/// @notice Thrown when taking the square root of a negative number.
error PRBMath_SD59x18_Sqrt_NegativeInput(SD59x18 x);
/// @notice Thrown when the calculating the square root overflows SD59x18.
error PRBMath_SD59x18_Sqrt_Overflow(SD59x18 x);// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;
import { wrap } from "./Casting.sol";
import { SD59x18 } from "./ValueType.sol";
/// @notice Implements the checked addition operation (+) in the SD59x18 type.
function add(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
return wrap(x.unwrap() + y.unwrap());
}
/// @notice Implements the AND (&) bitwise operation in the SD59x18 type.
function and(SD59x18 x, int256 bits) pure returns (SD59x18 result) {
return wrap(x.unwrap() & bits);
}
/// @notice Implements the AND (&) bitwise operation in the SD59x18 type.
function and2(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
return wrap(x.unwrap() & y.unwrap());
}
/// @notice Implements the equal (=) operation in the SD59x18 type.
function eq(SD59x18 x, SD59x18 y) pure returns (bool result) {
result = x.unwrap() == y.unwrap();
}
/// @notice Implements the greater than operation (>) in the SD59x18 type.
function gt(SD59x18 x, SD59x18 y) pure returns (bool result) {
result = x.unwrap() > y.unwrap();
}
/// @notice Implements the greater than or equal to operation (>=) in the SD59x18 type.
function gte(SD59x18 x, SD59x18 y) pure returns (bool result) {
result = x.unwrap() >= y.unwrap();
}
/// @notice Implements a zero comparison check function in the SD59x18 type.
function isZero(SD59x18 x) pure returns (bool result) {
result = x.unwrap() == 0;
}
/// @notice Implements the left shift operation (<<) in the SD59x18 type.
function lshift(SD59x18 x, uint256 bits) pure returns (SD59x18 result) {
result = wrap(x.unwrap() << bits);
}
/// @notice Implements the lower than operation (<) in the SD59x18 type.
function lt(SD59x18 x, SD59x18 y) pure returns (bool result) {
result = x.unwrap() < y.unwrap();
}
/// @notice Implements the lower than or equal to operation (<=) in the SD59x18 type.
function lte(SD59x18 x, SD59x18 y) pure returns (bool result) {
result = x.unwrap() <= y.unwrap();
}
/// @notice Implements the unchecked modulo operation (%) in the SD59x18 type.
function mod(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
result = wrap(x.unwrap() % y.unwrap());
}
/// @notice Implements the not equal operation (!=) in the SD59x18 type.
function neq(SD59x18 x, SD59x18 y) pure returns (bool result) {
result = x.unwrap() != y.unwrap();
}
/// @notice Implements the NOT (~) bitwise operation in the SD59x18 type.
function not(SD59x18 x) pure returns (SD59x18 result) {
result = wrap(~x.unwrap());
}
/// @notice Implements the OR (|) bitwise operation in the SD59x18 type.
function or(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
result = wrap(x.unwrap() | y.unwrap());
}
/// @notice Implements the right shift operation (>>) in the SD59x18 type.
function rshift(SD59x18 x, uint256 bits) pure returns (SD59x18 result) {
result = wrap(x.unwrap() >> bits);
}
/// @notice Implements the checked subtraction operation (-) in the SD59x18 type.
function sub(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
result = wrap(x.unwrap() - y.unwrap());
}
/// @notice Implements the checked unary minus operation (-) in the SD59x18 type.
function unary(SD59x18 x) pure returns (SD59x18 result) {
result = wrap(-x.unwrap());
}
/// @notice Implements the unchecked addition operation (+) in the SD59x18 type.
function uncheckedAdd(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
unchecked {
result = wrap(x.unwrap() + y.unwrap());
}
}
/// @notice Implements the unchecked subtraction operation (-) in the SD59x18 type.
function uncheckedSub(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
unchecked {
result = wrap(x.unwrap() - y.unwrap());
}
}
/// @notice Implements the unchecked unary minus operation (-) in the SD59x18 type.
function uncheckedUnary(SD59x18 x) pure returns (SD59x18 result) {
unchecked {
result = wrap(-x.unwrap());
}
}
/// @notice Implements the XOR (^) bitwise operation in the SD59x18 type.
function xor(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
result = wrap(x.unwrap() ^ y.unwrap());
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;
import "../Common.sol" as Common;
import "./Errors.sol" as Errors;
import {
uEXP_MAX_INPUT,
uEXP2_MAX_INPUT,
uEXP_MIN_THRESHOLD,
uEXP2_MIN_THRESHOLD,
uHALF_UNIT,
uLOG2_10,
uLOG2_E,
uMAX_SD59x18,
uMAX_WHOLE_SD59x18,
uMIN_SD59x18,
uMIN_WHOLE_SD59x18,
UNIT,
uUNIT,
uUNIT_SQUARED,
ZERO
} from "./Constants.sol";
import { wrap } from "./Helpers.sol";
import { SD59x18 } from "./ValueType.sol";
/// @notice Calculates the absolute value of x.
///
/// @dev Requirements:
/// - x > MIN_SD59x18.
///
/// @param x The SD59x18 number for which to calculate the absolute value.
/// @return result The absolute value of x as an SD59x18 number.
/// @custom:smtchecker abstract-function-nondet
function abs(SD59x18 x) pure returns (SD59x18 result) {
int256 xInt = x.unwrap();
if (xInt == uMIN_SD59x18) {
revert Errors.PRBMath_SD59x18_Abs_MinSD59x18();
}
result = xInt < 0 ? wrap(-xInt) : x;
}
/// @notice Calculates the arithmetic average of x and y.
///
/// @dev Notes:
/// - The result is rounded toward zero.
///
/// @param x The first operand as an SD59x18 number.
/// @param y The second operand as an SD59x18 number.
/// @return result The arithmetic average as an SD59x18 number.
/// @custom:smtchecker abstract-function-nondet
function avg(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
int256 xInt = x.unwrap();
int256 yInt = y.unwrap();
unchecked {
// This operation is equivalent to `x / 2 + y / 2`, and it can never overflow.
int256 sum = (xInt >> 1) + (yInt >> 1);
if (sum < 0) {
// If at least one of x and y is odd, add 1 to the result, because shifting negative numbers to the right
// rounds toward negative infinity. The right part is equivalent to `sum + (x % 2 == 1 || y % 2 == 1)`.
assembly ("memory-safe") {
result := add(sum, and(or(xInt, yInt), 1))
}
} else {
// Add 1 if both x and y are odd to account for the double 0.5 remainder truncated after shifting.
result = wrap(sum + (xInt & yInt & 1));
}
}
}
/// @notice Yields the smallest whole number greater than or equal to x.
///
/// @dev Optimized for fractional value inputs, because every whole value has (1e18 - 1) fractional counterparts.
/// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions.
///
/// Requirements:
/// - x ≤ MAX_WHOLE_SD59x18
///
/// @param x The SD59x18 number to ceil.
/// @return result The smallest whole number greater than or equal to x, as an SD59x18 number.
/// @custom:smtchecker abstract-function-nondet
function ceil(SD59x18 x) pure returns (SD59x18 result) {
int256 xInt = x.unwrap();
if (xInt > uMAX_WHOLE_SD59x18) {
revert Errors.PRBMath_SD59x18_Ceil_Overflow(x);
}
int256 remainder = xInt % uUNIT;
if (remainder == 0) {
result = x;
} else {
unchecked {
// Solidity uses C fmod style, which returns a modulus with the same sign as x.
int256 resultInt = xInt - remainder;
if (xInt > 0) {
resultInt += uUNIT;
}
result = wrap(resultInt);
}
}
}
/// @notice Divides two SD59x18 numbers, returning a new SD59x18 number.
///
/// @dev This is an extension of {Common.mulDiv} for signed numbers, which works by computing the signs and the absolute
/// values separately.
///
/// Notes:
/// - Refer to the notes in {Common.mulDiv}.
/// - The result is rounded toward zero.
///
/// Requirements:
/// - Refer to the requirements in {Common.mulDiv}.
/// - None of the inputs can be `MIN_SD59x18`.
/// - The denominator must not be zero.
/// - The result must fit in SD59x18.
///
/// @param x The numerator as an SD59x18 number.
/// @param y The denominator as an SD59x18 number.
/// @return result The quotient as an SD59x18 number.
/// @custom:smtchecker abstract-function-nondet
function div(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
int256 xInt = x.unwrap();
int256 yInt = y.unwrap();
if (xInt == uMIN_SD59x18 || yInt == uMIN_SD59x18) {
revert Errors.PRBMath_SD59x18_Div_InputTooSmall();
}
// Get hold of the absolute values of x and y.
uint256 xAbs;
uint256 yAbs;
unchecked {
xAbs = xInt < 0 ? uint256(-xInt) : uint256(xInt);
yAbs = yInt < 0 ? uint256(-yInt) : uint256(yInt);
}
// Compute the absolute value (x*UNIT÷y). The resulting value must fit in SD59x18.
uint256 resultAbs = Common.mulDiv(xAbs, uint256(uUNIT), yAbs);
if (resultAbs > uint256(uMAX_SD59x18)) {
revert Errors.PRBMath_SD59x18_Div_Overflow(x, y);
}
// Check if x and y have the same sign using two's complement representation. The left-most bit represents the sign (1 for
// negative, 0 for positive or zero).
bool sameSign = (xInt ^ yInt) > -1;
// If the inputs have the same sign, the result should be positive. Otherwise, it should be negative.
unchecked {
result = wrap(sameSign ? int256(resultAbs) : -int256(resultAbs));
}
}
/// @notice Calculates the natural exponent of x using the following formula:
///
/// $$
/// e^x = 2^{x * log_2{e}}
/// $$
///
/// @dev Notes:
/// - Refer to the notes in {exp2}.
///
/// Requirements:
/// - Refer to the requirements in {exp2}.
/// - x < 133_084258667509499441.
///
/// @param x The exponent as an SD59x18 number.
/// @return result The result as an SD59x18 number.
/// @custom:smtchecker abstract-function-nondet
function exp(SD59x18 x) pure returns (SD59x18 result) {
int256 xInt = x.unwrap();
// Any input less than the threshold returns zero.
// This check also prevents an overflow for very small numbers.
if (xInt < uEXP_MIN_THRESHOLD) {
return ZERO;
}
// This check prevents values greater than 192e18 from being passed to {exp2}.
if (xInt > uEXP_MAX_INPUT) {
revert Errors.PRBMath_SD59x18_Exp_InputTooBig(x);
}
unchecked {
// Inline the fixed-point multiplication to save gas.
int256 doubleUnitProduct = xInt * uLOG2_E;
result = exp2(wrap(doubleUnitProduct / uUNIT));
}
}
/// @notice Calculates the binary exponent of x using the binary fraction method using the following formula:
///
/// $$
/// 2^{-x} = \frac{1}{2^x}
/// $$
///
/// @dev See https://ethereum.stackexchange.com/q/79903/24693.
///
/// Notes:
/// - If x < -59_794705707972522261, the result is zero.
///
/// Requirements:
/// - x < 192e18.
/// - The result must fit in SD59x18.
///
/// @param x The exponent as an SD59x18 number.
/// @return result The result as an SD59x18 number.
/// @custom:smtchecker abstract-function-nondet
function exp2(SD59x18 x) pure returns (SD59x18 result) {
int256 xInt = x.unwrap();
if (xInt < 0) {
// The inverse of any number less than the threshold is truncated to zero.
if (xInt < uEXP2_MIN_THRESHOLD) {
return ZERO;
}
unchecked {
// Inline the fixed-point inversion to save gas.
result = wrap(uUNIT_SQUARED / exp2(wrap(-xInt)).unwrap());
}
} else {
// Numbers greater than or equal to 192e18 don't fit in the 192.64-bit format.
if (xInt > uEXP2_MAX_INPUT) {
revert Errors.PRBMath_SD59x18_Exp2_InputTooBig(x);
}
unchecked {
// Convert x to the 192.64-bit fixed-point format.
uint256 x_192x64 = uint256((xInt << 64) / uUNIT);
// It is safe to cast the result to int256 due to the checks above.
result = wrap(int256(Common.exp2(x_192x64)));
}
}
}
/// @notice Yields the greatest whole number less than or equal to x.
///
/// @dev Optimized for fractional value inputs, because for every whole value there are (1e18 - 1) fractional
/// counterparts. See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions.
///
/// Requirements:
/// - x ≥ MIN_WHOLE_SD59x18
///
/// @param x The SD59x18 number to floor.
/// @return result The greatest whole number less than or equal to x, as an SD59x18 number.
/// @custom:smtchecker abstract-function-nondet
function floor(SD59x18 x) pure returns (SD59x18 result) {
int256 xInt = x.unwrap();
if (xInt < uMIN_WHOLE_SD59x18) {
revert Errors.PRBMath_SD59x18_Floor_Underflow(x);
}
int256 remainder = xInt % uUNIT;
if (remainder == 0) {
result = x;
} else {
unchecked {
// Solidity uses C fmod style, which returns a modulus with the same sign as x.
int256 resultInt = xInt - remainder;
if (xInt < 0) {
resultInt -= uUNIT;
}
result = wrap(resultInt);
}
}
}
/// @notice Yields the excess beyond the floor of x for positive numbers and the part of the number to the right.
/// of the radix point for negative numbers.
/// @dev Based on the odd function definition. https://en.wikipedia.org/wiki/Fractional_part
/// @param x The SD59x18 number to get the fractional part of.
/// @return result The fractional part of x as an SD59x18 number.
function frac(SD59x18 x) pure returns (SD59x18 result) {
result = wrap(x.unwrap() % uUNIT);
}
/// @notice Calculates the geometric mean of x and y, i.e. $\sqrt{x * y}$.
///
/// @dev Notes:
/// - The result is rounded toward zero.
///
/// Requirements:
/// - x * y must fit in SD59x18.
/// - x * y must not be negative, since complex numbers are not supported.
///
/// @param x The first operand as an SD59x18 number.
/// @param y The second operand as an SD59x18 number.
/// @return result The result as an SD59x18 number.
/// @custom:smtchecker abstract-function-nondet
function gm(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
int256 xInt = x.unwrap();
int256 yInt = y.unwrap();
if (xInt == 0 || yInt == 0) {
return ZERO;
}
unchecked {
// Equivalent to `xy / x != y`. Checking for overflow this way is faster than letting Solidity do it.
int256 xyInt = xInt * yInt;
if (xyInt / xInt != yInt) {
revert Errors.PRBMath_SD59x18_Gm_Overflow(x, y);
}
// The product must not be negative, since complex numbers are not supported.
if (xyInt < 0) {
revert Errors.PRBMath_SD59x18_Gm_NegativeProduct(x, y);
}
// We don't need to multiply the result by `UNIT` here because the x*y product picked up a factor of `UNIT`
// during multiplication. See the comments in {Common.sqrt}.
uint256 resultUint = Common.sqrt(uint256(xyInt));
result = wrap(int256(resultUint));
}
}
/// @notice Calculates the inverse of x.
///
/// @dev Notes:
/// - The result is rounded toward zero.
///
/// Requirements:
/// - x must not be zero.
///
/// @param x The SD59x18 number for which to calculate the inverse.
/// @return result The inverse as an SD59x18 number.
/// @custom:smtchecker abstract-function-nondet
function inv(SD59x18 x) pure returns (SD59x18 result) {
result = wrap(uUNIT_SQUARED / x.unwrap());
}
/// @notice Calculates the natural logarithm of x using the following formula:
///
/// $$
/// ln{x} = log_2{x} / log_2{e}
/// $$
///
/// @dev Notes:
/// - Refer to the notes in {log2}.
/// - The precision isn't sufficiently fine-grained to return exactly `UNIT` when the input is `E`.
///
/// Requirements:
/// - Refer to the requirements in {log2}.
///
/// @param x The SD59x18 number for which to calculate the natural logarithm.
/// @return result The natural logarithm as an SD59x18 number.
/// @custom:smtchecker abstract-function-nondet
function ln(SD59x18 x) pure returns (SD59x18 result) {
// Inline the fixed-point multiplication to save gas. This is overflow-safe because the maximum value that
// {log2} can return is ~195_205294292027477728.
result = wrap(log2(x).unwrap() * uUNIT / uLOG2_E);
}
/// @notice Calculates the common logarithm of x using the following formula:
///
/// $$
/// log_{10}{x} = log_2{x} / log_2{10}
/// $$
///
/// However, if x is an exact power of ten, a hard coded value is returned.
///
/// @dev Notes:
/// - Refer to the notes in {log2}.
///
/// Requirements:
/// - Refer to the requirements in {log2}.
///
/// @param x The SD59x18 number for which to calculate the common logarithm.
/// @return result The common logarithm as an SD59x18 number.
/// @custom:smtchecker abstract-function-nondet
function log10(SD59x18 x) pure returns (SD59x18 result) {
int256 xInt = x.unwrap();
if (xInt < 0) {
revert Errors.PRBMath_SD59x18_Log_InputTooSmall(x);
}
// Note that the `mul` in this block is the standard multiplication operation, not {SD59x18.mul}.
// prettier-ignore
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) }
default { result := uMAX_SD59x18 }
}
if (result.unwrap() == uMAX_SD59x18) {
unchecked {
// Inline the fixed-point division to save gas.
result = wrap(log2(x).unwrap() * uUNIT / uLOG2_10);
}
}
}
/// @notice Calculates the binary logarithm of x using the iterative approximation algorithm:
///
/// $$
/// log_2{x} = n + log_2{y}, \text{ where } y = x*2^{-n}, \ y \in [1, 2)
/// $$
///
/// For $0 \leq x \lt 1$, the input is inverted:
///
/// $$
/// log_2{x} = -log_2{\frac{1}{x}}
/// $$
///
/// @dev See https://en.wikipedia.org/wiki/Binary_logarithm#Iterative_approximation.
///
/// Notes:
/// - Due to the lossy precision of the iterative approximation, the results are not perfectly accurate to the last decimal.
///
/// Requirements:
/// - x > 0
///
/// @param x The SD59x18 number for which to calculate the binary logarithm.
/// @return result The binary logarithm as an SD59x18 number.
/// @custom:smtchecker abstract-function-nondet
function log2(SD59x18 x) pure returns (SD59x18 result) {
int256 xInt = x.unwrap();
if (xInt <= 0) {
revert Errors.PRBMath_SD59x18_Log_InputTooSmall(x);
}
unchecked {
int256 sign;
if (xInt >= uUNIT) {
sign = 1;
} else {
sign = -1;
// Inline the fixed-point inversion to save gas.
xInt = uUNIT_SQUARED / xInt;
}
// Calculate the integer part of the logarithm.
uint256 n = Common.msb(uint256(xInt / uUNIT));
// This is the integer part of the logarithm as an SD59x18 number. The operation can't overflow
// because n is at most 255, `UNIT` is 1e18, and the sign is either 1 or -1.
int256 resultInt = int256(n) * uUNIT;
// Calculate $y = x * 2^{-n}$.
int256 y = xInt >> n;
// If y is the unit number, the fractional part is zero.
if (y == uUNIT) {
return wrap(resultInt * sign);
}
// Calculate the fractional part via the iterative approximation.
// The `delta >>= 1` part is equivalent to `delta /= 2`, but shifting bits is more gas efficient.
int256 DOUBLE_UNIT = 2e18;
for (int256 delta = uHALF_UNIT; delta > 0; delta >>= 1) {
y = (y * y) / uUNIT;
// Is y^2 >= 2e18 and so in the range [2e18, 4e18)?
if (y >= DOUBLE_UNIT) {
// Add the 2^{-m} factor to the logarithm.
resultInt = resultInt + delta;
// Halve y, which corresponds to z/2 in the Wikipedia article.
y >>= 1;
}
}
resultInt *= sign;
result = wrap(resultInt);
}
}
/// @notice Multiplies two SD59x18 numbers together, returning a new SD59x18 number.
///
/// @dev Notes:
/// - Refer to the notes in {Common.mulDiv18}.
///
/// Requirements:
/// - Refer to the requirements in {Common.mulDiv18}.
/// - None of the inputs can be `MIN_SD59x18`.
/// - The result must fit in SD59x18.
///
/// @param x The multiplicand as an SD59x18 number.
/// @param y The multiplier as an SD59x18 number.
/// @return result The product as an SD59x18 number.
/// @custom:smtchecker abstract-function-nondet
function mul(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
int256 xInt = x.unwrap();
int256 yInt = y.unwrap();
if (xInt == uMIN_SD59x18 || yInt == uMIN_SD59x18) {
revert Errors.PRBMath_SD59x18_Mul_InputTooSmall();
}
// Get hold of the absolute values of x and y.
uint256 xAbs;
uint256 yAbs;
unchecked {
xAbs = xInt < 0 ? uint256(-xInt) : uint256(xInt);
yAbs = yInt < 0 ? uint256(-yInt) : uint256(yInt);
}
// Compute the absolute value (x*y÷UNIT). The resulting value must fit in SD59x18.
uint256 resultAbs = Common.mulDiv18(xAbs, yAbs);
if (resultAbs > uint256(uMAX_SD59x18)) {
revert Errors.PRBMath_SD59x18_Mul_Overflow(x, y);
}
// Check if x and y have the same sign using two's complement representation. The left-most bit represents the sign (1 for
// negative, 0 for positive or zero).
bool sameSign = (xInt ^ yInt) > -1;
// If the inputs have the same sign, the result should be positive. Otherwise, it should be negative.
unchecked {
result = wrap(sameSign ? int256(resultAbs) : -int256(resultAbs));
}
}
/// @notice Raises x to the power of y using the following formula:
///
/// $$
/// x^y = 2^{log_2{x} * y}
/// $$
///
/// @dev Notes:
/// - Refer to the notes in {exp2}, {log2}, and {mul}.
/// - Returns `UNIT` for 0^0.
///
/// Requirements:
/// - Refer to the requirements in {exp2}, {log2}, and {mul}.
///
/// @param x The base as an SD59x18 number.
/// @param y Exponent to raise x to, as an SD59x18 number
/// @return result x raised to power y, as an SD59x18 number.
/// @custom:smtchecker abstract-function-nondet
function pow(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
int256 xInt = x.unwrap();
int256 yInt = y.unwrap();
// If both x and y are zero, the result is `UNIT`. If just x is zero, the result is always zero.
if (xInt == 0) {
return yInt == 0 ? UNIT : ZERO;
}
// If x is `UNIT`, the result is always `UNIT`.
else if (xInt == uUNIT) {
return UNIT;
}
// If y is zero, the result is always `UNIT`.
if (yInt == 0) {
return UNIT;
}
// If y is `UNIT`, the result is always x.
else if (yInt == uUNIT) {
return x;
}
// Calculate the result using the formula.
result = exp2(mul(log2(x), y));
}
/// @notice Raises x (an SD59x18 number) to the power y (an unsigned basic integer) using the well-known
/// algorithm "exponentiation by squaring".
///
/// @dev See https://en.wikipedia.org/wiki/Exponentiation_by_squaring.
///
/// Notes:
/// - Refer to the notes in {Common.mulDiv18}.
/// - Returns `UNIT` for 0^0.
///
/// Requirements:
/// - Refer to the requirements in {abs} and {Common.mulDiv18}.
/// - The result must fit in SD59x18.
///
/// @param x The base as an SD59x18 number.
/// @param y The exponent as a uint256.
/// @return result The result as an SD59x18 number.
/// @custom:smtchecker abstract-function-nondet
function powu(SD59x18 x, uint256 y) pure returns (SD59x18 result) {
uint256 xAbs = uint256(abs(x).unwrap());
// Calculate the first iteration of the loop in advance.
uint256 resultAbs = y & 1 > 0 ? xAbs : uint256(uUNIT);
// Equivalent to `for(y /= 2; y > 0; y /= 2)`.
uint256 yAux = y;
for (yAux >>= 1; yAux > 0; yAux >>= 1) {
xAbs = Common.mulDiv18(xAbs, xAbs);
// Equivalent to `y % 2 == 1`.
if (yAux & 1 > 0) {
resultAbs = Common.mulDiv18(resultAbs, xAbs);
}
}
// The result must fit in SD59x18.
if (resultAbs > uint256(uMAX_SD59x18)) {
revert Errors.PRBMath_SD59x18_Powu_Overflow(x, y);
}
unchecked {
// Is the base negative and the exponent odd? If yes, the result should be negative.
int256 resultInt = int256(resultAbs);
bool isNegative = x.unwrap() < 0 && y & 1 == 1;
if (isNegative) {
resultInt = -resultInt;
}
result = wrap(resultInt);
}
}
/// @notice Calculates the square root of x using the Babylonian method.
///
/// @dev See https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.
///
/// Notes:
/// - Only the positive root is returned.
/// - The result is rounded toward zero.
///
/// Requirements:
/// - x ≥ 0, since complex numbers are not supported.
/// - x ≤ MAX_SD59x18 / UNIT
///
/// @param x The SD59x18 number for which to calculate the square root.
/// @return result The result as an SD59x18 number.
/// @custom:smtchecker abstract-function-nondet
function sqrt(SD59x18 x) pure returns (SD59x18 result) {
int256 xInt = x.unwrap();
if (xInt < 0) {
revert Errors.PRBMath_SD59x18_Sqrt_NegativeInput(x);
}
if (xInt > uMAX_SD59x18 / uUNIT) {
revert Errors.PRBMath_SD59x18_Sqrt_Overflow(x);
}
unchecked {
// Multiply x by `UNIT` to account for the factor of `UNIT` picked up when multiplying two SD59x18 numbers.
// In this case, the two numbers are both the square root.
uint256 resultUint = Common.sqrt(uint256(xInt * uUNIT));
result = wrap(int256(resultUint));
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;
import "./Casting.sol" as Casting;
import "./Helpers.sol" as Helpers;
import "./Math.sol" as Math;
/// @notice The signed 59.18-decimal fixed-point number representation, which can have up to 59 digits and up to 18
/// decimals. The values of this are bound by the minimum and the maximum values permitted by the underlying Solidity
/// type int256.
type SD59x18 is int256;
/*//////////////////////////////////////////////////////////////////////////
CASTING
//////////////////////////////////////////////////////////////////////////*/
using {
Casting.intoInt256,
Casting.intoSD1x18,
Casting.intoSD21x18,
Casting.intoUD2x18,
Casting.intoUD21x18,
Casting.intoUD60x18,
Casting.intoUint256,
Casting.intoUint128,
Casting.intoUint40,
Casting.unwrap
} for SD59x18 global;
/*//////////////////////////////////////////////////////////////////////////
MATHEMATICAL FUNCTIONS
//////////////////////////////////////////////////////////////////////////*/
using {
Math.abs,
Math.avg,
Math.ceil,
Math.div,
Math.exp,
Math.exp2,
Math.floor,
Math.frac,
Math.gm,
Math.inv,
Math.log10,
Math.log2,
Math.ln,
Math.mul,
Math.pow,
Math.powu,
Math.sqrt
} for SD59x18 global;
/*//////////////////////////////////////////////////////////////////////////
HELPER FUNCTIONS
//////////////////////////////////////////////////////////////////////////*/
using {
Helpers.add,
Helpers.and,
Helpers.eq,
Helpers.gt,
Helpers.gte,
Helpers.isZero,
Helpers.lshift,
Helpers.lt,
Helpers.lte,
Helpers.mod,
Helpers.neq,
Helpers.not,
Helpers.or,
Helpers.rshift,
Helpers.sub,
Helpers.uncheckedAdd,
Helpers.uncheckedSub,
Helpers.uncheckedUnary,
Helpers.xor
} for SD59x18 global;
/*//////////////////////////////////////////////////////////////////////////
OPERATORS
//////////////////////////////////////////////////////////////////////////*/
// The global "using for" directive makes it possible to use these operators on the SD59x18 type.
using {
Helpers.add as +,
Helpers.and2 as &,
Math.div as /,
Helpers.eq as ==,
Helpers.gt as >,
Helpers.gte as >=,
Helpers.lt as <,
Helpers.lte as <=,
Helpers.mod as %,
Math.mul as *,
Helpers.neq as !=,
Helpers.not as ~,
Helpers.or as |,
Helpers.sub as -,
Helpers.unary as -,
Helpers.xor as ^
} for SD59x18 global;// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;
import "../Common.sol" as Common;
import "./Errors.sol" as Errors;
import { SD59x18 } from "../sd59x18/ValueType.sol";
import { UD60x18 } from "../ud60x18/ValueType.sol";
import { UD21x18 } from "./ValueType.sol";
/// @notice Casts a UD21x18 number into SD59x18.
/// @dev There is no overflow check because UD21x18 ⊆ SD59x18.
function intoSD59x18(UD21x18 x) pure returns (SD59x18 result) {
result = SD59x18.wrap(int256(uint256(UD21x18.unwrap(x))));
}
/// @notice Casts a UD21x18 number into UD60x18.
/// @dev There is no overflow check because UD21x18 ⊆ UD60x18.
function intoUD60x18(UD21x18 x) pure returns (UD60x18 result) {
result = UD60x18.wrap(UD21x18.unwrap(x));
}
/// @notice Casts a UD21x18 number into uint128.
/// @dev This is basically an alias for {unwrap}.
function intoUint128(UD21x18 x) pure returns (uint128 result) {
result = UD21x18.unwrap(x);
}
/// @notice Casts a UD21x18 number into uint256.
/// @dev There is no overflow check because UD21x18 ⊆ uint256.
function intoUint256(UD21x18 x) pure returns (uint256 result) {
result = uint256(UD21x18.unwrap(x));
}
/// @notice Casts a UD21x18 number into uint40.
/// @dev Requirements:
/// - x ≤ MAX_UINT40
function intoUint40(UD21x18 x) pure returns (uint40 result) {
uint128 xUint = UD21x18.unwrap(x);
if (xUint > uint128(Common.MAX_UINT40)) {
revert Errors.PRBMath_UD21x18_IntoUint40_Overflow(x);
}
result = uint40(xUint);
}
/// @notice Alias for {wrap}.
function ud21x18(uint128 x) pure returns (UD21x18 result) {
result = UD21x18.wrap(x);
}
/// @notice Unwrap a UD21x18 number into uint128.
function unwrap(UD21x18 x) pure returns (uint128 result) {
result = UD21x18.unwrap(x);
}
/// @notice Wraps a uint128 number into UD21x18.
function wrap(uint128 x) pure returns (UD21x18 result) {
result = UD21x18.wrap(x);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;
import { UD21x18 } from "./ValueType.sol";
/// @dev Euler's number as a UD21x18 number.
UD21x18 constant E = UD21x18.wrap(2_718281828459045235);
/// @dev The maximum value a UD21x18 number can have.
uint128 constant uMAX_UD21x18 = 340282366920938463463_374607431768211455;
UD21x18 constant MAX_UD21x18 = UD21x18.wrap(uMAX_UD21x18);
/// @dev PI as a UD21x18 number.
UD21x18 constant PI = UD21x18.wrap(3_141592653589793238);
/// @dev The unit number, which gives the decimal precision of UD21x18.
uint256 constant uUNIT = 1e18;
UD21x18 constant UNIT = UD21x18.wrap(1e18);// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;
import { UD21x18 } from "./ValueType.sol";
/// @notice Thrown when trying to cast a UD21x18 number that doesn't fit in uint40.
error PRBMath_UD21x18_IntoUint40_Overflow(UD21x18 x);// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;
import "./Casting.sol" as Casting;
/// @notice The unsigned 21.18-decimal fixed-point number representation, which can have up to 21 digits and up to 18
/// decimals. The values of this are bound by the minimum and the maximum values permitted by the underlying Solidity
/// type uint128. This is useful when end users want to use uint128 to save gas, e.g. with tight variable packing in contract
/// storage.
type UD21x18 is uint128;
/*//////////////////////////////////////////////////////////////////////////
CASTING
//////////////////////////////////////////////////////////////////////////*/
using {
Casting.intoSD59x18,
Casting.intoUD60x18,
Casting.intoUint128,
Casting.intoUint256,
Casting.intoUint40,
Casting.unwrap
} for UD21x18 global;// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;
import "../Common.sol" as Common;
import "./Errors.sol" as Errors;
import { SD59x18 } from "../sd59x18/ValueType.sol";
import { UD60x18 } from "../ud60x18/ValueType.sol";
import { UD2x18 } from "./ValueType.sol";
/// @notice Casts a UD2x18 number into SD59x18.
/// @dev There is no overflow check because UD2x18 ⊆ SD59x18.
function intoSD59x18(UD2x18 x) pure returns (SD59x18 result) {
result = SD59x18.wrap(int256(uint256(UD2x18.unwrap(x))));
}
/// @notice Casts a UD2x18 number into UD60x18.
/// @dev There is no overflow check because UD2x18 ⊆ UD60x18.
function intoUD60x18(UD2x18 x) pure returns (UD60x18 result) {
result = UD60x18.wrap(UD2x18.unwrap(x));
}
/// @notice Casts a UD2x18 number into uint128.
/// @dev There is no overflow check because UD2x18 ⊆ uint128.
function intoUint128(UD2x18 x) pure returns (uint128 result) {
result = uint128(UD2x18.unwrap(x));
}
/// @notice Casts a UD2x18 number into uint256.
/// @dev There is no overflow check because UD2x18 ⊆ uint256.
function intoUint256(UD2x18 x) pure returns (uint256 result) {
result = uint256(UD2x18.unwrap(x));
}
/// @notice Casts a UD2x18 number into uint40.
/// @dev Requirements:
/// - x ≤ MAX_UINT40
function intoUint40(UD2x18 x) pure returns (uint40 result) {
uint64 xUint = UD2x18.unwrap(x);
if (xUint > uint64(Common.MAX_UINT40)) {
revert Errors.PRBMath_UD2x18_IntoUint40_Overflow(x);
}
result = uint40(xUint);
}
/// @notice Alias for {wrap}.
function ud2x18(uint64 x) pure returns (UD2x18 result) {
result = UD2x18.wrap(x);
}
/// @notice Unwrap a UD2x18 number into uint64.
function unwrap(UD2x18 x) pure returns (uint64 result) {
result = UD2x18.unwrap(x);
}
/// @notice Wraps a uint64 number into UD2x18.
function wrap(uint64 x) pure returns (UD2x18 result) {
result = UD2x18.wrap(x);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;
import { UD2x18 } from "./ValueType.sol";
/// @dev Euler's number as a UD2x18 number.
UD2x18 constant E = UD2x18.wrap(2_718281828459045235);
/// @dev The maximum value a UD2x18 number can have.
uint64 constant uMAX_UD2x18 = 18_446744073709551615;
UD2x18 constant MAX_UD2x18 = UD2x18.wrap(uMAX_UD2x18);
/// @dev PI as a UD2x18 number.
UD2x18 constant PI = UD2x18.wrap(3_141592653589793238);
/// @dev The unit number, which gives the decimal precision of UD2x18.
UD2x18 constant UNIT = UD2x18.wrap(1e18);
uint64 constant uUNIT = 1e18;// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;
import { UD2x18 } from "./ValueType.sol";
/// @notice Thrown when trying to cast a UD2x18 number that doesn't fit in uint40.
error PRBMath_UD2x18_IntoUint40_Overflow(UD2x18 x);// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;
import "./Casting.sol" as Casting;
/// @notice The unsigned 2.18-decimal fixed-point number representation, which can have up to 2 digits and up to 18
/// decimals. The values of this are bound by the minimum and the maximum values permitted by the underlying Solidity
/// type uint64. This is useful when end users want to use uint64 to save gas, e.g. with tight variable packing in contract
/// storage.
type UD2x18 is uint64;
/*//////////////////////////////////////////////////////////////////////////
CASTING
//////////////////////////////////////////////////////////////////////////*/
using {
Casting.intoSD59x18,
Casting.intoUD60x18,
Casting.intoUint128,
Casting.intoUint256,
Casting.intoUint40,
Casting.unwrap
} for UD2x18 global;// SPDX-License-Identifier: MIT 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";
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;
import "./Errors.sol" as CastingErrors;
import { MAX_UINT128, MAX_UINT40 } from "../Common.sol";
import { uMAX_SD1x18 } from "../sd1x18/Constants.sol";
import { SD1x18 } from "../sd1x18/ValueType.sol";
import { uMAX_SD21x18 } from "../sd21x18/Constants.sol";
import { SD21x18 } from "../sd21x18/ValueType.sol";
import { uMAX_SD59x18 } from "../sd59x18/Constants.sol";
import { SD59x18 } from "../sd59x18/ValueType.sol";
import { uMAX_UD2x18 } from "../ud2x18/Constants.sol";
import { uMAX_UD21x18 } from "../ud21x18/Constants.sol";
import { UD2x18 } from "../ud2x18/ValueType.sol";
import { UD21x18 } from "../ud21x18/ValueType.sol";
import { UD60x18 } from "./ValueType.sol";
/// @notice Casts a UD60x18 number into SD1x18.
/// @dev Requirements:
/// - x ≤ uMAX_SD1x18
function intoSD1x18(UD60x18 x) pure returns (SD1x18 result) {
uint256 xUint = UD60x18.unwrap(x);
if (xUint > uint256(int256(uMAX_SD1x18))) {
revert CastingErrors.PRBMath_UD60x18_IntoSD1x18_Overflow(x);
}
result = SD1x18.wrap(int64(uint64(xUint)));
}
/// @notice Casts a UD60x18 number into SD21x18.
/// @dev Requirements:
/// - x ≤ uMAX_SD21x18
function intoSD21x18(UD60x18 x) pure returns (SD21x18 result) {
uint256 xUint = UD60x18.unwrap(x);
if (xUint > uint256(int256(uMAX_SD21x18))) {
revert CastingErrors.PRBMath_UD60x18_IntoSD21x18_Overflow(x);
}
result = SD21x18.wrap(int128(uint128(xUint)));
}
/// @notice Casts a UD60x18 number into UD2x18.
/// @dev Requirements:
/// - x ≤ uMAX_UD2x18
function intoUD2x18(UD60x18 x) pure returns (UD2x18 result) {
uint256 xUint = UD60x18.unwrap(x);
if (xUint > uMAX_UD2x18) {
revert CastingErrors.PRBMath_UD60x18_IntoUD2x18_Overflow(x);
}
result = UD2x18.wrap(uint64(xUint));
}
/// @notice Casts a UD60x18 number into UD21x18.
/// @dev Requirements:
/// - x ≤ uMAX_UD21x18
function intoUD21x18(UD60x18 x) pure returns (UD21x18 result) {
uint256 xUint = UD60x18.unwrap(x);
if (xUint > uMAX_UD21x18) {
revert CastingErrors.PRBMath_UD60x18_IntoUD21x18_Overflow(x);
}
result = UD21x18.wrap(uint128(xUint));
}
/// @notice Casts a UD60x18 number into SD59x18.
/// @dev Requirements:
/// - x ≤ uMAX_SD59x18
function intoSD59x18(UD60x18 x) pure returns (SD59x18 result) {
uint256 xUint = UD60x18.unwrap(x);
if (xUint > uint256(uMAX_SD59x18)) {
revert CastingErrors.PRBMath_UD60x18_IntoSD59x18_Overflow(x);
}
result = SD59x18.wrap(int256(xUint));
}
/// @notice Casts a UD60x18 number into uint128.
/// @dev This is basically an alias for {unwrap}.
function intoUint256(UD60x18 x) pure returns (uint256 result) {
result = UD60x18.unwrap(x);
}
/// @notice Casts a UD60x18 number into uint128.
/// @dev Requirements:
/// - x ≤ MAX_UINT128
function intoUint128(UD60x18 x) pure returns (uint128 result) {
uint256 xUint = UD60x18.unwrap(x);
if (xUint > MAX_UINT128) {
revert CastingErrors.PRBMath_UD60x18_IntoUint128_Overflow(x);
}
result = uint128(xUint);
}
/// @notice Casts a UD60x18 number into uint40.
/// @dev Requirements:
/// - x ≤ MAX_UINT40
function intoUint40(UD60x18 x) pure returns (uint40 result) {
uint256 xUint = UD60x18.unwrap(x);
if (xUint > MAX_UINT40) {
revert CastingErrors.PRBMath_UD60x18_IntoUint40_Overflow(x);
}
result = uint40(xUint);
}
/// @notice Alias for {wrap}.
function ud(uint256 x) pure returns (UD60x18 result) {
result = UD60x18.wrap(x);
}
/// @notice Alias for {wrap}.
function ud60x18(uint256 x) pure returns (UD60x18 result) {
result = UD60x18.wrap(x);
}
/// @notice Unwraps a UD60x18 number into uint256.
function unwrap(UD60x18 x) pure returns (uint256 result) {
result = UD60x18.unwrap(x);
}
/// @notice Wraps a uint256 number into the UD60x18 value type.
function wrap(uint256 x) pure returns (UD60x18 result) {
result = UD60x18.wrap(x);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;
import { UD60x18 } from "./ValueType.sol";
// NOTICE: the "u" prefix stands for "unwrapped".
/// @dev Euler's number as a UD60x18 number.
UD60x18 constant E = UD60x18.wrap(2_718281828459045235);
/// @dev The maximum input permitted in {exp}.
uint256 constant uEXP_MAX_INPUT = 133_084258667509499440;
UD60x18 constant EXP_MAX_INPUT = UD60x18.wrap(uEXP_MAX_INPUT);
/// @dev The maximum input permitted in {exp2}.
uint256 constant uEXP2_MAX_INPUT = 192e18 - 1;
UD60x18 constant EXP2_MAX_INPUT = UD60x18.wrap(uEXP2_MAX_INPUT);
/// @dev Half the UNIT number.
uint256 constant uHALF_UNIT = 0.5e18;
UD60x18 constant HALF_UNIT = UD60x18.wrap(uHALF_UNIT);
/// @dev $log_2(10)$ as a UD60x18 number.
uint256 constant uLOG2_10 = 3_321928094887362347;
UD60x18 constant LOG2_10 = UD60x18.wrap(uLOG2_10);
/// @dev $log_2(e)$ as a UD60x18 number.
uint256 constant uLOG2_E = 1_442695040888963407;
UD60x18 constant LOG2_E = UD60x18.wrap(uLOG2_E);
/// @dev The maximum value a UD60x18 number can have.
uint256 constant uMAX_UD60x18 = 115792089237316195423570985008687907853269984665640564039457_584007913129639935;
UD60x18 constant MAX_UD60x18 = UD60x18.wrap(uMAX_UD60x18);
/// @dev The maximum whole value a UD60x18 number can have.
uint256 constant uMAX_WHOLE_UD60x18 = 115792089237316195423570985008687907853269984665640564039457_000000000000000000;
UD60x18 constant MAX_WHOLE_UD60x18 = UD60x18.wrap(uMAX_WHOLE_UD60x18);
/// @dev PI as a UD60x18 number.
UD60x18 constant PI = UD60x18.wrap(3_141592653589793238);
/// @dev The unit number, which gives the decimal precision of UD60x18.
uint256 constant uUNIT = 1e18;
UD60x18 constant UNIT = UD60x18.wrap(uUNIT);
/// @dev The unit number squared.
uint256 constant uUNIT_SQUARED = 1e36;
UD60x18 constant UNIT_SQUARED = UD60x18.wrap(uUNIT_SQUARED);
/// @dev Zero as a UD60x18 number.
UD60x18 constant ZERO = UD60x18.wrap(0);// SPDX-License-Identifier: MIT
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";
/// @notice Converts a UD60x18 number to a simple integer by dividing it by `UNIT`.
/// @dev The result is rounded toward zero.
/// @param x The UD60x18 number to convert.
/// @return result The same number in basic integer form.
function convert(UD60x18 x) pure returns (uint256 result) {
result = UD60x18.unwrap(x) / uUNIT;
}
/// @notice Converts a simple integer to UD60x18 by multiplying it by `UNIT`.
///
/// @dev Requirements:
/// - x ≤ MAX_UD60x18 / UNIT
///
/// @param x The basic integer to convert.
/// @return result The same number converted to UD60x18.
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);
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;
import { UD60x18 } from "./ValueType.sol";
/// @notice Thrown when ceiling a number overflows UD60x18.
error PRBMath_UD60x18_Ceil_Overflow(UD60x18 x);
/// @notice Thrown when converting a basic integer to the fixed-point format overflows UD60x18.
error PRBMath_UD60x18_Convert_Overflow(uint256 x);
/// @notice Thrown when taking the natural exponent of a base greater than 133_084258667509499441.
error PRBMath_UD60x18_Exp_InputTooBig(UD60x18 x);
/// @notice Thrown when taking the binary exponent of a base greater than 192e18.
error PRBMath_UD60x18_Exp2_InputTooBig(UD60x18 x);
/// @notice Thrown when taking the geometric mean of two numbers and multiplying them overflows UD60x18.
error PRBMath_UD60x18_Gm_Overflow(UD60x18 x, UD60x18 y);
/// @notice Thrown when trying to cast a UD60x18 number that doesn't fit in SD1x18.
error PRBMath_UD60x18_IntoSD1x18_Overflow(UD60x18 x);
/// @notice Thrown when trying to cast a UD60x18 number that doesn't fit in SD21x18.
error PRBMath_UD60x18_IntoSD21x18_Overflow(UD60x18 x);
/// @notice Thrown when trying to cast a UD60x18 number that doesn't fit in SD59x18.
error PRBMath_UD60x18_IntoSD59x18_Overflow(UD60x18 x);
/// @notice Thrown when trying to cast a UD60x18 number that doesn't fit in UD2x18.
error PRBMath_UD60x18_IntoUD2x18_Overflow(UD60x18 x);
/// @notice Thrown when trying to cast a UD60x18 number that doesn't fit in UD21x18.
error PRBMath_UD60x18_IntoUD21x18_Overflow(UD60x18 x);
/// @notice Thrown when trying to cast a UD60x18 number that doesn't fit in uint128.
error PRBMath_UD60x18_IntoUint128_Overflow(UD60x18 x);
/// @notice Thrown when trying to cast a UD60x18 number that doesn't fit in uint40.
error PRBMath_UD60x18_IntoUint40_Overflow(UD60x18 x);
/// @notice Thrown when taking the logarithm of a number less than UNIT.
error PRBMath_UD60x18_Log_InputTooSmall(UD60x18 x);
/// @notice Thrown when calculating the square root overflows UD60x18.
error PRBMath_UD60x18_Sqrt_Overflow(UD60x18 x);// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;
import { wrap } from "./Casting.sol";
import { UD60x18 } from "./ValueType.sol";
/// @notice Implements the checked addition operation (+) in the UD60x18 type.
function add(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {
result = wrap(x.unwrap() + y.unwrap());
}
/// @notice Implements the AND (&) bitwise operation in the UD60x18 type.
function and(UD60x18 x, uint256 bits) pure returns (UD60x18 result) {
result = wrap(x.unwrap() & bits);
}
/// @notice Implements the AND (&) bitwise operation in the UD60x18 type.
function and2(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {
result = wrap(x.unwrap() & y.unwrap());
}
/// @notice Implements the equal operation (==) in the UD60x18 type.
function eq(UD60x18 x, UD60x18 y) pure returns (bool result) {
result = x.unwrap() == y.unwrap();
}
/// @notice Implements the greater than operation (>) in the UD60x18 type.
function gt(UD60x18 x, UD60x18 y) pure returns (bool result) {
result = x.unwrap() > y.unwrap();
}
/// @notice Implements the greater than or equal to operation (>=) in the UD60x18 type.
function gte(UD60x18 x, UD60x18 y) pure returns (bool result) {
result = x.unwrap() >= y.unwrap();
}
/// @notice Implements a zero comparison check function in the UD60x18 type.
function isZero(UD60x18 x) pure returns (bool result) {
// This wouldn't work if x could be negative.
result = x.unwrap() == 0;
}
/// @notice Implements the left shift operation (<<) in the UD60x18 type.
function lshift(UD60x18 x, uint256 bits) pure returns (UD60x18 result) {
result = wrap(x.unwrap() << bits);
}
/// @notice Implements the lower than operation (<) in the UD60x18 type.
function lt(UD60x18 x, UD60x18 y) pure returns (bool result) {
result = x.unwrap() < y.unwrap();
}
/// @notice Implements the lower than or equal to operation (<=) in the UD60x18 type.
function lte(UD60x18 x, UD60x18 y) pure returns (bool result) {
result = x.unwrap() <= y.unwrap();
}
/// @notice Implements the checked modulo operation (%) in the UD60x18 type.
function mod(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {
result = wrap(x.unwrap() % y.unwrap());
}
/// @notice Implements the not equal operation (!=) in the UD60x18 type.
function neq(UD60x18 x, UD60x18 y) pure returns (bool result) {
result = x.unwrap() != y.unwrap();
}
/// @notice Implements the NOT (~) bitwise operation in the UD60x18 type.
function not(UD60x18 x) pure returns (UD60x18 result) {
result = wrap(~x.unwrap());
}
/// @notice Implements the OR (|) bitwise operation in the UD60x18 type.
function or(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {
result = wrap(x.unwrap() | y.unwrap());
}
/// @notice Implements the right shift operation (>>) in the UD60x18 type.
function rshift(UD60x18 x, uint256 bits) pure returns (UD60x18 result) {
result = wrap(x.unwrap() >> bits);
}
/// @notice Implements the checked subtraction operation (-) in the UD60x18 type.
function sub(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {
result = wrap(x.unwrap() - y.unwrap());
}
/// @notice Implements the unchecked addition operation (+) in the UD60x18 type.
function uncheckedAdd(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {
unchecked {
result = wrap(x.unwrap() + y.unwrap());
}
}
/// @notice Implements the unchecked subtraction operation (-) in the UD60x18 type.
function uncheckedSub(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {
unchecked {
result = wrap(x.unwrap() - y.unwrap());
}
}
/// @notice Implements the XOR (^) bitwise operation in the UD60x18 type.
function xor(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {
result = wrap(x.unwrap() ^ y.unwrap());
}// SPDX-License-Identifier: MIT
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";
/*//////////////////////////////////////////////////////////////////////////
MATHEMATICAL FUNCTIONS
//////////////////////////////////////////////////////////////////////////*/
/// @notice Calculates the arithmetic average of x and y using the following formula:
///
/// $$
/// avg(x, y) = (x & y) + ((xUint ^ yUint) / 2)
/// $$
///
/// In English, this is what this formula does:
///
/// 1. AND x and y.
/// 2. Calculate half of XOR x and y.
/// 3. Add the two results together.
///
/// This technique is known as SWAR, which stands for "SIMD within a register". You can read more about it here:
/// https://devblogs.microsoft.com/oldnewthing/20220207-00/?p=106223
///
/// @dev Notes:
/// - The result is rounded toward zero.
///
/// @param x The first operand as a UD60x18 number.
/// @param y The second operand as a UD60x18 number.
/// @return result The arithmetic average as a UD60x18 number.
/// @custom:smtchecker abstract-function-nondet
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));
}
}
/// @notice Yields the smallest whole number greater than or equal to x.
///
/// @dev This is optimized for fractional value inputs, because for every whole value there are (1e18 - 1) fractional
/// counterparts. See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions.
///
/// Requirements:
/// - x ≤ MAX_WHOLE_UD60x18
///
/// @param x The UD60x18 number to ceil.
/// @return result The smallest whole number greater than or equal to x, as a UD60x18 number.
/// @custom:smtchecker abstract-function-nondet
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") {
// Equivalent to `x % UNIT`.
let remainder := mod(x, uUNIT)
// Equivalent to `UNIT - remainder`.
let delta := sub(uUNIT, remainder)
// Equivalent to `x + remainder > 0 ? delta : 0`.
result := add(x, mul(delta, gt(remainder, 0)))
}
}
/// @notice Divides two UD60x18 numbers, returning a new UD60x18 number.
///
/// @dev Uses {Common.mulDiv} to enable overflow-safe multiplication and division.
///
/// Notes:
/// - Refer to the notes in {Common.mulDiv}.
///
/// Requirements:
/// - Refer to the requirements in {Common.mulDiv}.
///
/// @param x The numerator as a UD60x18 number.
/// @param y The denominator as a UD60x18 number.
/// @return result The quotient as a UD60x18 number.
/// @custom:smtchecker abstract-function-nondet
function div(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {
result = wrap(Common.mulDiv(x.unwrap(), uUNIT, y.unwrap()));
}
/// @notice Calculates the natural exponent of x using the following formula:
///
/// $$
/// e^x = 2^{x * log_2{e}}
/// $$
///
/// @dev Requirements:
/// - x ≤ 133_084258667509499440
///
/// @param x The exponent as a UD60x18 number.
/// @return result The result as a UD60x18 number.
/// @custom:smtchecker abstract-function-nondet
function exp(UD60x18 x) pure returns (UD60x18 result) {
uint256 xUint = x.unwrap();
// This check prevents values greater than 192e18 from being passed to {exp2}.
if (xUint > uEXP_MAX_INPUT) {
revert Errors.PRBMath_UD60x18_Exp_InputTooBig(x);
}
unchecked {
// Inline the fixed-point multiplication to save gas.
uint256 doubleUnitProduct = xUint * uLOG2_E;
result = exp2(wrap(doubleUnitProduct / uUNIT));
}
}
/// @notice Calculates the binary exponent of x using the binary fraction method.
///
/// @dev See https://ethereum.stackexchange.com/q/79903/24693
///
/// Requirements:
/// - x < 192e18
/// - The result must fit in UD60x18.
///
/// @param x The exponent as a UD60x18 number.
/// @return result The result as a UD60x18 number.
/// @custom:smtchecker abstract-function-nondet
function exp2(UD60x18 x) pure returns (UD60x18 result) {
uint256 xUint = x.unwrap();
// Numbers greater than or equal to 192e18 don't fit in the 192.64-bit format.
if (xUint > uEXP2_MAX_INPUT) {
revert Errors.PRBMath_UD60x18_Exp2_InputTooBig(x);
}
// Convert x to the 192.64-bit fixed-point format.
uint256 x_192x64 = (xUint << 64) / uUNIT;
// Pass x to the {Common.exp2} function, which uses the 192.64-bit fixed-point number representation.
result = wrap(Common.exp2(x_192x64));
}
/// @notice Yields the greatest whole number less than or equal to x.
/// @dev Optimized for fractional value inputs, because every whole value has (1e18 - 1) fractional counterparts.
/// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions.
/// @param x The UD60x18 number to floor.
/// @return result The greatest whole number less than or equal to x, as a UD60x18 number.
/// @custom:smtchecker abstract-function-nondet
function floor(UD60x18 x) pure returns (UD60x18 result) {
assembly ("memory-safe") {
// Equivalent to `x % UNIT`.
let remainder := mod(x, uUNIT)
// Equivalent to `x - remainder > 0 ? remainder : 0)`.
result := sub(x, mul(remainder, gt(remainder, 0)))
}
}
/// @notice Yields the excess beyond the floor of x using the odd function definition.
/// @dev See https://en.wikipedia.org/wiki/Fractional_part.
/// @param x The UD60x18 number to get the fractional part of.
/// @return result The fractional part of x as a UD60x18 number.
/// @custom:smtchecker abstract-function-nondet
function frac(UD60x18 x) pure returns (UD60x18 result) {
assembly ("memory-safe") {
result := mod(x, uUNIT)
}
}
/// @notice Calculates the geometric mean of x and y, i.e. $\sqrt{x * y}$, rounding down.
///
/// @dev Requirements:
/// - x * y must fit in UD60x18.
///
/// @param x The first operand as a UD60x18 number.
/// @param y The second operand as a UD60x18 number.
/// @return result The result as a UD60x18 number.
/// @custom:smtchecker abstract-function-nondet
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 {
// Checking for overflow this way is faster than letting Solidity do it.
uint256 xyUint = xUint * yUint;
if (xyUint / xUint != yUint) {
revert Errors.PRBMath_UD60x18_Gm_Overflow(x, y);
}
// We don't need to multiply the result by `UNIT` here because the x*y product picked up a factor of `UNIT`
// during multiplication. See the comments in {Common.sqrt}.
result = wrap(Common.sqrt(xyUint));
}
}
/// @notice Calculates the inverse of x.
///
/// @dev Notes:
/// - The result is rounded toward zero.
///
/// Requirements:
/// - x must not be zero.
///
/// @param x The UD60x18 number for which to calculate the inverse.
/// @return result The inverse as a UD60x18 number.
/// @custom:smtchecker abstract-function-nondet
function inv(UD60x18 x) pure returns (UD60x18 result) {
unchecked {
result = wrap(uUNIT_SQUARED / x.unwrap());
}
}
/// @notice Calculates the natural logarithm of x using the following formula:
///
/// $$
/// ln{x} = log_2{x} / log_2{e}
/// $$
///
/// @dev Notes:
/// - Refer to the notes in {log2}.
/// - The precision isn't sufficiently fine-grained to return exactly `UNIT` when the input is `E`.
///
/// Requirements:
/// - Refer to the requirements in {log2}.
///
/// @param x The UD60x18 number for which to calculate the natural logarithm.
/// @return result The natural logarithm as a UD60x18 number.
/// @custom:smtchecker abstract-function-nondet
function ln(UD60x18 x) pure returns (UD60x18 result) {
unchecked {
// Inline the fixed-point multiplication to save gas. This is overflow-safe because the maximum value that
// {log2} can return is ~196_205294292027477728.
result = wrap(log2(x).unwrap() * uUNIT / uLOG2_E);
}
}
/// @notice Calculates the common logarithm of x using the following formula:
///
/// $$
/// log_{10}{x} = log_2{x} / log_2{10}
/// $$
///
/// However, if x is an exact power of ten, a hard coded value is returned.
///
/// @dev Notes:
/// - Refer to the notes in {log2}.
///
/// Requirements:
/// - Refer to the requirements in {log2}.
///
/// @param x The UD60x18 number for which to calculate the common logarithm.
/// @return result The common logarithm as a UD60x18 number.
/// @custom:smtchecker abstract-function-nondet
function log10(UD60x18 x) pure returns (UD60x18 result) {
uint256 xUint = x.unwrap();
if (xUint < uUNIT) {
revert Errors.PRBMath_UD60x18_Log_InputTooSmall(x);
}
// Note that the `mul` in this assembly block is the standard multiplication operation, not {UD60x18.mul}.
// prettier-ignore
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 {
// Inline the fixed-point division to save gas.
result = wrap(log2(x).unwrap() * uUNIT / uLOG2_10);
}
}
}
/// @notice Calculates the binary logarithm of x using the iterative approximation algorithm:
///
/// $$
/// log_2{x} = n + log_2{y}, \text{ where } y = x*2^{-n}, \ y \in [1, 2)
/// $$
///
/// For $0 \leq x \lt 1$, the input is inverted:
///
/// $$
/// log_2{x} = -log_2{\frac{1}{x}}
/// $$
///
/// @dev See https://en.wikipedia.org/wiki/Binary_logarithm#Iterative_approximation
///
/// Notes:
/// - Due to the lossy precision of the iterative approximation, the results are not perfectly accurate to the last decimal.
///
/// Requirements:
/// - x ≥ UNIT
///
/// @param x The UD60x18 number for which to calculate the binary logarithm.
/// @return result The binary logarithm as a UD60x18 number.
/// @custom:smtchecker abstract-function-nondet
function log2(UD60x18 x) pure returns (UD60x18 result) {
uint256 xUint = x.unwrap();
if (xUint < uUNIT) {
revert Errors.PRBMath_UD60x18_Log_InputTooSmall(x);
}
unchecked {
// Calculate the integer part of the logarithm.
uint256 n = Common.msb(xUint / uUNIT);
// This is the integer part of the logarithm as a UD60x18 number. The operation can't overflow because n
// n is at most 255 and UNIT is 1e18.
uint256 resultUint = n * uUNIT;
// Calculate $y = x * 2^{-n}$.
uint256 y = xUint >> n;
// If y is the unit number, the fractional part is zero.
if (y == uUNIT) {
return wrap(resultUint);
}
// Calculate the fractional part via the iterative approximation.
// The `delta >>= 1` part is equivalent to `delta /= 2`, but shifting bits is more gas efficient.
uint256 DOUBLE_UNIT = 2e18;
for (uint256 delta = uHALF_UNIT; delta > 0; delta >>= 1) {
y = (y * y) / uUNIT;
// Is y^2 >= 2e18 and so in the range [2e18, 4e18)?
if (y >= DOUBLE_UNIT) {
// Add the 2^{-m} factor to the logarithm.
resultUint += delta;
// Halve y, which corresponds to z/2 in the Wikipedia article.
y >>= 1;
}
}
result = wrap(resultUint);
}
}
/// @notice Multiplies two UD60x18 numbers together, returning a new UD60x18 number.
///
/// @dev Uses {Common.mulDiv} to enable overflow-safe multiplication and division.
///
/// Notes:
/// - Refer to the notes in {Common.mulDiv}.
///
/// Requirements:
/// - Refer to the requirements in {Common.mulDiv}.
///
/// @dev See the documentation in {Common.mulDiv18}.
/// @param x The multiplicand as a UD60x18 number.
/// @param y The multiplier as a UD60x18 number.
/// @return result The product as a UD60x18 number.
/// @custom:smtchecker abstract-function-nondet
function mul(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {
result = wrap(Common.mulDiv18(x.unwrap(), y.unwrap()));
}
/// @notice Raises x to the power of y.
///
/// For $1 \leq x \leq \infty$, the following standard formula is used:
///
/// $$
/// x^y = 2^{log_2{x} * y}
/// $$
///
/// For $0 \leq x \lt 1$, since the unsigned {log2} is undefined, an equivalent formula is used:
///
/// $$
/// i = \frac{1}{x}
/// w = 2^{log_2{i} * y}
/// x^y = \frac{1}{w}
/// $$
///
/// @dev Notes:
/// - Refer to the notes in {log2} and {mul}.
/// - Returns `UNIT` for 0^0.
/// - It may not perform well with very small values of x. Consider using SD59x18 as an alternative.
///
/// Requirements:
/// - Refer to the requirements in {exp2}, {log2}, and {mul}.
///
/// @param x The base as a UD60x18 number.
/// @param y The exponent as a UD60x18 number.
/// @return result The result as a UD60x18 number.
/// @custom:smtchecker abstract-function-nondet
function pow(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {
uint256 xUint = x.unwrap();
uint256 yUint = y.unwrap();
// If both x and y are zero, the result is `UNIT`. If just x is zero, the result is always zero.
if (xUint == 0) {
return yUint == 0 ? UNIT : ZERO;
}
// If x is `UNIT`, the result is always `UNIT`.
else if (xUint == uUNIT) {
return UNIT;
}
// If y is zero, the result is always `UNIT`.
if (yUint == 0) {
return UNIT;
}
// If y is `UNIT`, the result is always x.
else if (yUint == uUNIT) {
return x;
}
// If x is > UNIT, use the standard formula.
if (xUint > uUNIT) {
result = exp2(mul(log2(x), y));
}
// Conversely, if x < UNIT, use the equivalent formula.
else {
UD60x18 i = wrap(uUNIT_SQUARED / xUint);
UD60x18 w = exp2(mul(log2(i), y));
result = wrap(uUNIT_SQUARED / w.unwrap());
}
}
/// @notice Raises x (a UD60x18 number) to the power y (an unsigned basic integer) using the well-known
/// algorithm "exponentiation by squaring".
///
/// @dev See https://en.wikipedia.org/wiki/Exponentiation_by_squaring.
///
/// Notes:
/// - Refer to the notes in {Common.mulDiv18}.
/// - Returns `UNIT` for 0^0.
///
/// Requirements:
/// - The result must fit in UD60x18.
///
/// @param x The base as a UD60x18 number.
/// @param y The exponent as a uint256.
/// @return result The result as a UD60x18 number.
/// @custom:smtchecker abstract-function-nondet
function powu(UD60x18 x, uint256 y) pure returns (UD60x18 result) {
// Calculate the first iteration of the loop in advance.
uint256 xUint = x.unwrap();
uint256 resultUint = y & 1 > 0 ? xUint : uUNIT;
// Equivalent to `for(y /= 2; y > 0; y /= 2)`.
for (y >>= 1; y > 0; y >>= 1) {
xUint = Common.mulDiv18(xUint, xUint);
// Equivalent to `y % 2 == 1`.
if (y & 1 > 0) {
resultUint = Common.mulDiv18(resultUint, xUint);
}
}
result = wrap(resultUint);
}
/// @notice Calculates the square root of x using the Babylonian method.
///
/// @dev See https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.
///
/// Notes:
/// - The result is rounded toward zero.
///
/// Requirements:
/// - x ≤ MAX_UD60x18 / UNIT
///
/// @param x The UD60x18 number for which to calculate the square root.
/// @return result The result as a UD60x18 number.
/// @custom:smtchecker abstract-function-nondet
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);
}
// Multiply x by `UNIT` to account for the factor of `UNIT` picked up when multiplying two UD60x18 numbers.
// In this case, the two numbers are both the square root.
result = wrap(Common.sqrt(xUint * uUNIT));
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;
import "./Casting.sol" as Casting;
import "./Helpers.sol" as Helpers;
import "./Math.sol" as Math;
/// @notice The unsigned 60.18-decimal fixed-point number representation, which can have up to 60 digits and up to 18
/// decimals. The values of this are bound by the minimum and the maximum values permitted by the Solidity type uint256.
/// @dev The value type is defined here so it can be imported in all other files.
type UD60x18 is uint256;
/*//////////////////////////////////////////////////////////////////////////
CASTING
//////////////////////////////////////////////////////////////////////////*/
using {
Casting.intoSD1x18,
Casting.intoSD21x18,
Casting.intoSD59x18,
Casting.intoUD2x18,
Casting.intoUD21x18,
Casting.intoUint128,
Casting.intoUint256,
Casting.intoUint40,
Casting.unwrap
} for UD60x18 global;
/*//////////////////////////////////////////////////////////////////////////
MATHEMATICAL FUNCTIONS
//////////////////////////////////////////////////////////////////////////*/
// The global "using for" directive makes the functions in this library callable on the UD60x18 type.
using {
Math.avg,
Math.ceil,
Math.div,
Math.exp,
Math.exp2,
Math.floor,
Math.frac,
Math.gm,
Math.inv,
Math.ln,
Math.log10,
Math.log2,
Math.mul,
Math.pow,
Math.powu,
Math.sqrt
} for UD60x18 global;
/*//////////////////////////////////////////////////////////////////////////
HELPER FUNCTIONS
//////////////////////////////////////////////////////////////////////////*/
// The global "using for" directive makes the functions in this library callable on the UD60x18 type.
using {
Helpers.add,
Helpers.and,
Helpers.eq,
Helpers.gt,
Helpers.gte,
Helpers.isZero,
Helpers.lshift,
Helpers.lt,
Helpers.lte,
Helpers.mod,
Helpers.neq,
Helpers.not,
Helpers.or,
Helpers.rshift,
Helpers.sub,
Helpers.uncheckedAdd,
Helpers.uncheckedSub,
Helpers.xor
} for UD60x18 global;
/*//////////////////////////////////////////////////////////////////////////
OPERATORS
//////////////////////////////////////////////////////////////////////////*/
// The global "using for" directive makes it possible to use these operators on the UD60x18 type.
using {
Helpers.add as +,
Helpers.and2 as &,
Math.div as /,
Helpers.eq as ==,
Helpers.gt as >,
Helpers.gte as >=,
Helpers.lt as <,
Helpers.lte as <=,
Helpers.or as |,
Helpers.mod as %,
Math.mul as *,
Helpers.neq as !=,
Helpers.not as ~,
Helpers.sub as -,
Helpers.xor as ^
} for UD60x18 global;{
"optimizer": {
"enabled": true,
"runs": 50
},
"viaIR": true,
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_usdc","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"BadAddress","type":"error"},{"inputs":[],"name":"Closed","type":"error"},{"inputs":[],"name":"ContractPaused","type":"error"},{"inputs":[],"name":"EndDateInPast","type":"error"},{"inputs":[],"name":"InsufficientCollateral","type":"error"},{"inputs":[],"name":"InvalidOption","type":"error"},{"inputs":[],"name":"MarketDoesNotExist","type":"error"},{"inputs":[],"name":"MarketNotActive","type":"error"},{"inputs":[],"name":"NetZeroAfterFees","type":"error"},{"inputs":[],"name":"NoWinnings","type":"error"},{"inputs":[],"name":"NotAdmin","type":"error"},{"inputs":[],"name":"NotEnoughShares","type":"error"},{"inputs":[],"name":"NotResolved","type":"error"},{"inputs":[],"name":"NotSuperAdmin","type":"error"},{"inputs":[],"name":"NotWinningOption","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":"UD60x18","name":"x","type":"uint256"}],"name":"PRBMath_UD60x18_Exp2_InputTooBig","type":"error"},{"inputs":[{"internalType":"UD60x18","name":"x","type":"uint256"}],"name":"PRBMath_UD60x18_Exp_InputTooBig","type":"error"},{"inputs":[{"internalType":"UD60x18","name":"x","type":"uint256"}],"name":"PRBMath_UD60x18_Log_InputTooSmall","type":"error"},{"inputs":[],"name":"PayoutDepleted","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[],"name":"SlippageExceeded","type":"error"},{"inputs":[],"name":"TallyUnderflow","type":"error"},{"inputs":[],"name":"TransferFailed","type":"error"},{"inputs":[],"name":"ZeroAmount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"admin","type":"address"},{"indexed":false,"internalType":"bool","name":"isAuthorized","type":"bool"}],"name":"AdminUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFee","type":"uint256"}],"name":"CreateMarketFeeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFee","type":"uint256"}],"name":"CreatorFeePercentUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"marketId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"creatorFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"protocolFee","type":"uint256"},{"indexed":false,"internalType":"address","name":"creator","type":"address"},{"indexed":false,"internalType":"address","name":"protocol","type":"address"}],"name":"FeesPaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"marketId","type":"uint256"},{"indexed":true,"internalType":"address","name":"admin","type":"address"},{"indexed":false,"internalType":"uint256","name":"poolBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"b","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"adminLiquidity","type":"uint256"}],"name":"LiquidityAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"marketId","type":"uint256"},{"indexed":true,"internalType":"address","name":"canceledBy","type":"address"},{"indexed":false,"internalType":"uint256","name":"creatorlpRefund","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"adminlpRefund","type":"uint256"}],"name":"MarketCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"marketId","type":"uint256"},{"indexed":true,"internalType":"address","name":"creator","type":"address"},{"indexed":false,"internalType":"string","name":"question","type":"string"},{"indexed":false,"internalType":"string","name":"details","type":"string"},{"indexed":false,"internalType":"string[]","name":"categories","type":"string[]"},{"indexed":false,"internalType":"string","name":"image","type":"string"},{"indexed":false,"internalType":"uint64","name":"endDate","type":"uint64"},{"indexed":false,"internalType":"string[]","name":"optionTitles","type":"string[]"},{"indexed":false,"internalType":"uint256[]","name":"shares","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"initialLiquidity","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"weightRatios","type":"uint256[]"},{"indexed":false,"internalType":"uint64","name":"winningOption","type":"uint64"},{"indexed":false,"internalType":"enum PredictBaseUniswapCPMM.MarketStatus","name":"status","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"poolBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"b","type":"uint256"}],"name":"MarketCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"marketId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newEndDate","type":"uint256"}],"name":"MarketEndDateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"marketId","type":"uint256"},{"indexed":false,"internalType":"string","name":"question","type":"string"},{"indexed":false,"internalType":"string[]","name":"categories","type":"string[]"},{"indexed":false,"internalType":"string","name":"details","type":"string"},{"indexed":false,"internalType":"string","name":"image","type":"string"}],"name":"MarketInfoUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"marketId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"winningOption","type":"uint256"},{"indexed":false,"internalType":"enum PredictBaseUniswapCPMM.MarketStatus","name":"status","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"creatorLiquidityReturn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"adminLiquidityReturn","type":"uint256"}],"name":"MarketResolved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"marketId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"optionCount","type":"uint256"}],"name":"OptionTitlesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"status","type":"bool"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFee","type":"uint256"}],"name":"ProtocolFeePercentUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"marketId","type":"uint256"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"option","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"usdcIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesOut","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"shares","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"poolBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"creatorFee","type":"uint256"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bool","name":"isGift","type":"bool"}],"name":"SharesBought","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"marketId","type":"uint256"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"option","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"usdcOut","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"shares","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"poolBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"creatorFee","type":"uint256"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"SharesSold","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newSuperAdmin","type":"address"}],"name":"SuperAdminUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"marketId","type":"uint256"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"optionIndex","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isRefund","type":"bool"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"WinningsClaimed","type":"event"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"},{"internalType":"uint256","name":"option","type":"uint256"},{"internalType":"uint256","name":"sharesOut","type":"uint256"},{"internalType":"uint256","name":"maxUsdcIn","type":"uint256"},{"internalType":"address","name":"user","type":"address"}],"name":"BuySharesForUser","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"addLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"admins","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"},{"internalType":"uint256","name":"option","type":"uint256"},{"internalType":"uint256","name":"sharesOut","type":"uint256"},{"internalType":"uint256","name":"maxUsdcIn","type":"uint256"}],"name":"buyShares","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"}],"name":"cancelMarket","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"},{"internalType":"uint256","name":"option","type":"uint256"}],"name":"claimWinnings","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"question","type":"string"},{"internalType":"string[]","name":"categories","type":"string[]"},{"internalType":"string","name":"details","type":"string"},{"internalType":"string","name":"image","type":"string"},{"internalType":"uint64","name":"endDate","type":"uint64"},{"internalType":"uint256","name":"initialLiquidity","type":"uint256"},{"internalType":"string[]","name":"_optionTitles","type":"string[]"},{"internalType":"uint256[]","name":"weightRatios","type":"uint256[]"}],"name":"createMarket","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"createMarketFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"creatorFeePercent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"},{"internalType":"address","name":"user","type":"address"}],"name":"getClaimableWinnings","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"}],"name":"getMarketAccounting","outputs":[{"internalType":"uint256","name":"initialLiquidity","type":"uint256"},{"internalType":"uint256","name":"userPayoutLeft","type":"uint256"},{"internalType":"uint256[]","name":"shares","type":"uint256[]"},{"internalType":"uint256","name":"creatorFeeAccrued","type":"uint256"},{"internalType":"uint256","name":"protocolFeeAccrued","type":"uint256"},{"internalType":"uint256","name":"poolBalance","type":"uint256"},{"internalType":"uint256","name":"cashInTotal","type":"uint256"},{"internalType":"uint256","name":"cashOutTotal","type":"uint256"},{"internalType":"uint256","name":"userRefundedTotal","type":"uint256"},{"internalType":"uint256[]","name":"weights1e18","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"}],"name":"getMarketMeta","outputs":[{"internalType":"address","name":"creator","type":"address"},{"internalType":"string","name":"question","type":"string"},{"internalType":"string[]","name":"categories","type":"string[]"},{"internalType":"string","name":"details","type":"string"},{"internalType":"string","name":"image","type":"string"},{"internalType":"uint256","name":"endDate","type":"uint256"},{"internalType":"enum PredictBaseUniswapCPMM.MarketStatus","name":"status","type":"uint8"},{"internalType":"uint256","name":"winningOption","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"}],"name":"getOptionCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"},{"internalType":"uint256","name":"option","type":"uint256"}],"name":"getOptionPrice","outputs":[{"internalType":"uint256","name":"price1e6","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"}],"name":"getOptionTitles","outputs":[{"internalType":"string[]","name":"","type":"string[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"},{"internalType":"address","name":"user","type":"address"}],"name":"getUserNetCash","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"option","type":"uint256"}],"name":"getUserShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"marketCounter","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"marketExistsFlag","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeePercent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"},{"internalType":"uint256","name":"option","type":"uint256"},{"internalType":"uint256","name":"usdcIn","type":"uint256"}],"name":"quoteBuyShares","outputs":[{"internalType":"uint256","name":"sharesOut","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"},{"internalType":"uint256","name":"option","type":"uint256"},{"internalType":"uint256","name":"sharesIn","type":"uint256"}],"name":"quoteSellShares","outputs":[{"internalType":"uint256","name":"usdcOut","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"},{"internalType":"uint64","name":"winningOption","type":"uint64"}],"name":"resolveMarket","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"},{"internalType":"uint256","name":"option","type":"uint256"},{"internalType":"uint256","name":"sharesIn","type":"uint256"},{"internalType":"uint256","name":"minUsdcOut","type":"uint256"}],"name":"sellShares","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"bool","name":"isAuthorized","type":"bool"}],"name":"setAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFee","type":"uint256"}],"name":"setCreateMarketFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newPercent","type":"uint256"}],"name":"setCreatorFeePercent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_paused","type":"bool"}],"name":"setPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newPercent","type":"uint256"}],"name":"setProtocolFeePercent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAdmin","type":"address"}],"name":"setSuperAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"superAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"},{"internalType":"uint64","name":"newEndDate","type":"uint64"}],"name":"updateMarketEndDate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"},{"internalType":"string","name":"question","type":"string"},{"internalType":"string[]","name":"categories","type":"string[]"},{"internalType":"string","name":"details","type":"string"},{"internalType":"string","name":"image","type":"string"}],"name":"updateMarketInfo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"usdcToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"userShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]Contract Creation Code
608034620000da57601f6200457738819003918201601f19168301916001600160401b03831184841017620000df57808492602094604052833981010312620000da57516001600160a01b03811690819003620000da576001908160005581600355816004556207a12060055560018060a01b031990818354161782553390600254161760025533600052600760205260406000208160ff198254161790556040519081527f235bc17e7930760029e9f4d860a2a8089976de5b381cf8380fc11c1d88a1113360203392a26040516144819081620000f68239f35b600080fd5b634e487b7160e01b600052604160045260246000fdfe608080604052600436101561001357600080fd5b60003560e01c90816301e421e0146127b35750806311e3c03e1461279557806311eac8551461276c57806313f1031d1461051b57806315700052146126ff57806316c38b3c146126935780631a095c6e146121fa57806324760807146121dc578063286db5c2146121b65780632882224f1461209557806329575f6a1461206c5780632dbdaf5b1461202c57806336b4c64d14611fe45780633a4d6d38146116b9578063429b62e51461167a5780634b0bddd2146115cb57806353613dd3146115ad57806357c8db97146115945780635a2db6fb146112a15780635c975abb1461127e578063625a7ee5146112585780636af48db9146112275780636d76ee57146111425780636f609ad014610ec85780636ff6c4b814610e3c5780637c16cd9e14610af85780639cd441da1461098d578063a498342114610901578063a573a8f814610882578063aaf49176146107c6578063ae165ff9146106ae578063cfe26c4414610562578063d27ff2fc1461051b578063d6e6eb9f146104fd578063e1adaf58146104ce5763ed881230146101ab57600080fd5b346104c9576101b936612b8e565b91929060ff600654166104b757816000526020926009845260ff60056040600020015460401c1660038110156104a15761048f576101f561338e565b8260005260098452604060002091600783015486101561047d57801561046b576006830154906102408188600887019461022e86613323565b61023a600a8a01613323565b916133c5565b92831561046b57606461025560035486612dee565b049461027a606461026860045488612dee565b04956102748789612f39565b90612f39565b918211610459576001546040516323b872dd60e01b815290899082906001600160a01b0316816000816102b289303360048501612c54565b03925af190811561044d57600091610420575b501561040e576103cc94600c82016102de888254612f39565b90556102ef600d8301918254612f39565b90556103ab61039b8a6009601185019461030a878754612f39565b86556012810161031b888254612f39565b90558b600052600c8d526040600020336000528d526040600020610340888254613372565b905561036561034f848b612ed9565b61035f8b83548360031b1c612f39565b91612cbf565b8b600052600b8d526040600020336000528d526040600020836000528d526040600020610393898254612f39565b905501612ed9565b61035f8683548360031b1c612f39565b5496604051988952880152604087015260e0606087015260e0860190613080565b92608085015260a0840152600060c08401527fd1626256062296eb2a74401b9149db9ce59bd7c024a01ffc261bfc3eded28eb633938033940390a46001600055005b6040516312171d8360e31b8152600490fd5b6104409150893d8b11610446575b6104388183612c1b565b810190612c3c565b386102c5565b503d61042e565b6040513d6000823e3d90fd5b604051638199f5f360e01b8152600490fd5b604051631f2a200560e01b8152600490fd5b604051632a71953160e01b8152600490fd5b604051635a90bb8d60e11b8152600490fd5b634e487b7160e01b600052602160045260246000fd5b60405163ab35696f60e01b8152600490fd5b600080fd5b346104c95760203660031901126104c95760043560005260096020526020600760406000200154604051908152f35b346104c95760003660031901126104c9576020600454604051908152f35b346104c95761052936612a75565b91600052600b60205260406000209060018060a01b03166000526020526040600020906000526020526020604060002054604051908152f35b346104c95760403660031901126104c95760043561057e612a9f565b33600052600760205260ff60406000205416801561069a575b156106885781600052600a60205260ff604060002054161561067657816000526009602052600560406000200190815460ff8160401c1660038110156104a157610621577f42440d1cfc9a52f9b6908f4a9b38357bc25b5510aa0ce725f3c15261071f5e6e926001600160401b036020931680926001600160401b031916179055604051908152a2005b60405162461bcd60e51b815260206004820152602760248201527f43616e206f6e6c7920757064617465206461746520666f7220616374697665206044820152666d61726b65747360c81b6064820152608490fd5b60405163b0cfa44760e01b8152600490fd5b604051637bfa4b9f60e01b8152600490fd5b506002546001600160a01b03163314610597565b346104c9576106bc36612ab5565b906000526009602052604060002090600782015481101561047d5760068201546106f4600a6106ed60088601613323565b9401613323565b9160009160009360005b86518110156107925761071181836133b1565b5161071c82896133b1565b5164e8d4a510009081810291818304149015171561077c5761075a9161074d6107488761075394613185565b6134d2565b90613d03565b8096612f39565b94848214610772575b5061076d90612c76565b6106fe565b955061076d610763565b634e487b7160e01b600052601160045260246000fd5b61079c8587613185565b620f42409081810291818304149015171561077c57602090670de0b6b3a764000060405191048152f35b346104c95760203660031901126104c95760043560005260096020526040600020600e81015461087e600b83015492600c81015490600d81015460118201546012830154601384015491601485015493610850610831600a61082a60088a01613323565b9801613323565b966040519b8c9b8c5260208c01526101408060408d01528b0190612bac565b9660608a0152608089015260a088015260c087015260e0860152610100850152838203610120850152612bac565b0390f35b346104c95760203660031901126104c95760043533600052600760205260ff6040600020541680156108ed575b156106885760407fa844e22c978ec45272a79c9dba58e154cf753922066ea12cba345f49dd3f4a4a91600554908060055582519182526020820152a1005b506002546001600160a01b031633146108af565b346104c95760203660031901126104c95760043533600052600760205260ff604060002054168015610979575b156106885760408161096460647f219d87b3822c2cd9103f559e66b1fa6683e5a41c1dde2e43ee26577e40f637be941115612be0565b600454908060045582519182526020820152a1005b506002546001600160a01b0316331461092e565b346104c95761099b36612ab5565b90336000526020916007835260ff604060002054168015610ae4575b1561068857816000526009835260ff60056040600020015460401c1660038110156104a15761048f576109e861338e565b801561046b578160005260098352604060002060018060a01b03600154168460405180926323b872dd60e01b825281600081610a2989303360048501612c54565b03925af190811561044d57600091610ac7575b501561040e576011810193610a52838654612f39565b809555610a896006610a64858861316e565b93610a74600f8201968754612f39565b8096550192610a84878554612dee565b61317b565b80925560405194855284015260408301527f089607a52cca0d390ff7d0ad4e97545804dcc41418e1daee9ec3948596fec94460603393a36001600055005b610ade9150853d8711610446576104388183612c1b565b85610a3c565b506002546001600160a01b031633146109b7565b346104c9576020806003193601126104c957600435336000526007825260ff604060002054168015610e28575b156106885780600052600a825260ff604060002054161561067657610b4861338e565b80600052600982526040600020916005830160ff815460401c1660038110156104a157610dd7576012840154601385015480821115610dce57610b8a9161316e565b601485015480821115610dc557610ba09161316e565b826011860191825490808211600014610dbc57610bbd908261316e565b905b8180151580610daf575b610cf7575b505080151580610cea575b610c43575b505050687fffffffffffffff8160411b68ffffffffffffffffff60401b19825416179055600f600e840154930154906040519384528301527f013609c5ed98f635a390501845e1c3fd8ed26be21ca23b95abecc781f6a90a4760403393a36001600055005b610ca192600f8801805492838110600014610cdf57610c6390809461316e565b9055610c7082825461316e565b905560018060a01b0380600154169060025416600060405180968195829463a9059cbb60e01b845260048401613d99565b03925af190811561044d57600091610cc2575b501561040e57848281610bde565b610cd99150833d8511610446576104388183612c1b565b85610cb4565b50610c63838061316e565b50600f8701541515610bd9565b610d649250610d27610d3591610d2e600e8c9795970196875490818410600014610da3578398899586809461316e565b905561316e565b875561316e565b9260018060a01b038060015416908a5416600060405180968195829463a9059cbb60e01b845260048401613d99565b03925af190811561044d57600091610d86575b501561040e5783908780610bce565b610d9d9150853d8711610446576104388183612c1b565b87610d77565b8198899586809461316e565b50600e8901541515610bc9565b50600090610bbf565b50506000610ba0565b50506000610b8a565b60405162461bcd60e51b8152600481018390526024808201527f4f6e6c7920616374697665206d61726b6574732063616e2062652063616e63656044820152631b1b195960e21b6064820152608490fd5b506002546001600160a01b03163314610b25565b346104c95760203660031901126104c95760043533600052600760205260ff604060002054168015610eb4575b1561068857604081610e9f60647f1f440356ff29d242b1f0e2afdae6b4be38d5cce2db5fbb241d3fdc363b942100941115612be0565b600354908060035582519182526020820152a1005b506002546001600160a01b03163314610e69565b346104c95760a03660031901126104c9576001600160a01b03608435818116906004359060443590602435908490036104c95760ff600654166104b757826000526020946009865260ff60056040600020015460401c1660038110156104a15761048f57610f3461338e565b83600052600986526040600020600781015483101561047d57831561046b576006810154610f7785856008850193610f6b85613323565b61023a600a8801613323565b94851561046b576064610f8c60035488612dee565b0493610fab6064610f9f6004548a612dee565b04976102748988612f39565b90606435821161045957600154168a60405180926323b872dd60e01b825281600081610fdc88303360048501612c54565b03925af190811561044d57600091611125575b501561040e57806110e561039b886009888f8f8f7fd1626256062296eb2a74401b9149db9ce59bd7c024a01ffc261bfc3eded28eb69f8b8f6111069f8f8a906110b89561035f94611048600c6110a99601918254612f39565b9055611059600d8c01918254612f39565b905560118a019e8f61106c828254612f39565b905560128b0161107d828254612f39565b905587600052600c8a526040600020896000528a526110a26040600020918254613372565b9055612ed9565b91909283548360031b1c612f39565b600052600b8252604060002090600052815260406000209084600052526040600020610393898254612f39565b5499604051968752860152604085015260e0606085015260e0840190613080565b95608083015260a0820152600160c08201528033950390a46001600055005b61113c91508b3d8d11610446576104388183612c1b565b8b610fef565b346104c95761115036612b74565b9091600052600960205260406000209160ff600584015460401c1692600393848110156104a15761048f5760078101548083101561047d57831561046b576111978161312c565b906008830160005b8281106111fe5760206111f6896111f060646111da6111d28d8d8d8d6111cc600a60068401549301613323565b91613db4565b935484612dee565b0460646111e960045485612dee565b0490612f39565b9061316e565b604051908152f35b8061120c6112229284612ed9565b9054908a1b1c61121c82876133b1565b52612c76565b61119f565b346104c95760203660031901126104c957600435600052600a602052602060ff604060002054166040519015158152f35b346104c95760403660031901126104c95760206111f6611276612a5f565b6004356143a6565b346104c95760003660031901126104c957602060ff600654166040519015158152f35b346104c9576112af36612b8e565b60ff60069492939454166104b757816000526020926009845260ff60056040600020015460401c1660038110156104a15761048f576112ec61338e565b8260005260098452604060002090600782015486101561047d57801561046b5783600052600b855260406000203360005285526040600020866000528552604060002054928184106115825760068301549161135d8189600887019561135187613323565b6111cc600a8a01613323565b94851561046b57606461137260035488612dee565b0495611391606461138560045484612dee565b04916111f0838a612f39565b938410610459576113e2918391600c88016113ad8a8254612f39565b90556113be600d8901918254612f39565b90556113dd6113cd8c88612ed9565b61035f8583548360031b1c61316e565b61316e565b86600052600b885260406000203360005288526040600020896000528852604060002055600984016114148982612ed9565b90549060031b1c908282106115705761143a8a611434856114409561316e565b92612ed9565b90612cbf565b601184019384549083821061155e5761145b8460139361316e565b865501611469838254612f39565b90556000868152600c88526040808220338352895281208054848103928512801582851316918412161761077c575560015460405163a9059cbb60e01b815290889082906001600160a01b0316816000816114c8893360048401613d99565b03925af190811561044d57600091611541575b501561040e57611506935496604051988952880152604087015260c0606087015260c0860190613080565b92608085015260a08401527fd23c082e07b3f3b32efe0f4971136900e9a67130775cd95e8dae76fb1d685f5733938033940390a46001600055005b6115589150883d8a11610446576104388183612c1b565b896114db565b604051633a23d82560e01b8152600490fd5b604051633a9a6bf560e11b8152600490fd5b604051633c57b48560e21b8152600490fd5b346104c95760206111f66115a736612b74565b916141d0565b346104c95760003660031901126104c9576020600354604051908152f35b346104c95760403660031901126104c9576115e4612a49565b602435908115158092036104c9576002546001600160a01b0391908216330361166857169081156116565760207f235bc17e7930760029e9f4d860a2a8089976de5b381cf8380fc11c1d88a11133918360005260078252604060002060ff1981541660ff8316179055604051908152a2005b6040516332691b5760e01b8152600490fd5b6040516316c726b160e01b8152600490fd5b346104c95760203660031901126104c9576001600160a01b0361169b612a49565b166000526007602052602060ff604060002054166040519015158152f35b346104c9576101003660031901126104c9576004356001600160401b0381116104c9576116ea9036906004016129ec565b6024356001600160401b0381116104c957611709903690600401612a19565b91906044356001600160401b0381116104c95761172a9036906004016129ec565b9190936064356001600160401b0381116104c95761174c9036906004016129ec565b608435916001600160401b03831683036104c95760c4356001600160401b0381116104c95761177f903690600401612a19565b96909860e4356001600160401b0381116104c9576117a1903690600401612a19565b97909660ff600654166104b75760028a1061046b5760a4351561046b576001546040516323b872dd60e01b81529060209082906001600160a01b0316816000816117f260a435303360048501612c54565b03925af190811561044d57600091611fc5575b501561040e5761185960019b61181c600854612c76565b9e8f80600855600052600a60205260406000208e60ff19825416179055600960205260406000209d8e33828060a01b031982541617815501612cee565b61186560028c01612e01565b60005b8b828210611fa25761189197969593506118889492506003915001612cee565b60048801612cee565b600585015460a435600e8701556000600f870155600060108701556001600160401b038060481b92169060018060881b031916171760058501556000600b8501556000600c8501556118e960a4356011860154612f39565b6011850155856000526009602052604060002095600d60205261190f6040600020612e01565b60005b848110611f72575083600788015561192c600888016130bd565b611938600988016130bd565b611944600a88016130bd565b61194d8461312c565b8051906001600160401b038211611f345760209061196e8360088c016130e1565b0160088901600052602060002060005b838110611f5e57505050506119928461312c565b8051906001600160401b038211611f34576020906119b38360098c016130e1565b0160098901600052602060002060005b838110611f4a57505050506119d78461312c565b8051906001600160401b038211611f34576020906119f883600a8c016130e1565b01600a8901600052602060002060005b838110611f205750600019979250505083611d5c578415611d3e5760009360005b8660001981011161077c576000198701811015611a8f57611a6d611a5082600a8d01612ed9565b97611a688a670de0b6b3a764000004809a8194612cbf565b612f39565b95888110611a85575b50611a8090612c76565b611a29565b9750611a80611a76565b50939791969297959095670de0b6b3a764000090810390811161077c57600019860186811161077c578161143a611ac992600a8701612ed9565b818110611d54575b505b64e8d4a510009060a43580830204820361077c578015611d3e57670de0b6b3a7640000611b196714057b7ef767814f926ec097ce7bc90715b34b9f100000000004613238565b02048015611cf0575b611b329060069260a43502613185565b910155847fc0d32b9d984118432cfd761f0df84468fa95b636e95b0e71b573176d6e3aa9546020604051868152a260018060a01b0384541695600585015491600e8601549060118701549660068101549160405197611baf611b9e6101a0808c528b0160018601612f46565b8a810360208c015260038501612f46565b89810360408b01526002840154808252602082019060208160051b84010192600287016000526020600020926000915b838310611cc4575050505050611c389392600892611c0c838d606081611c29970391015260048701612f46565b6001600160401b038b1660808e01528c810360a08e015291612ffd565b9189830360c08b015201613080565b60e08701929092528582036101008701528482526001600160fb1b0385116104c9577fb5c5b574da8421c61fe28d327f1a8fe774a3798fd039550927fbda6ef8125b2696611cb1879560209760051b8096898701376001600160401b038160481c1661012088015260ff61014088019160401c16612b67565b61016085015261018084015201030190a3005b909192939460206001611ce18193601f1986820301875289612f46565b97019301930191939290611bdf565b5084670de0b6b3a7640000810204670de0b6b3a7640000148515171561077c57611b326006916714057b7ef767814f670de0b6b3a7640000611d33818a02613238565b020491509150611b22565b634e487b7160e01b600052601260045260246000fd5b905088611ad1565b969493929190838303611ee25760009760005b858110611ebd57508815611e865760009460005b8160001981011161077c576000198201811015611e1457611da581878761315e565b35670de0b6b3a76400009081810291818304149015171561077c578b611dca9161317b565b96898815611e0b575b611de991611a688a61143a86600a839601612ed9565b96888110611e01575b50611dfc90612c76565b611d83565b9750611dfc611df2565b60019850611dd3565b5095919793949096929850670de0b6b3a76400008181031161077c5780670de0b6b3a76400000390670de0b6b3a764000014611e7e575b600019860186811161077c578161143a611e6892600a8701612ed9565b818110611e76575b50611ad3565b905088611e70565b506001611e4b565b60405162461bcd60e51b815260206004820152600f60248201526e726174696f732073756d207a65726f60881b6044820152606490fd5b98611ed7611edd91611ed08c888861315e565b3590612f39565b99612c76565b611d6f565b60405162461bcd60e51b81526020600482015260166024820152750e4c2e8d2dee640d8cadccee8d040dad2e6dac2e8c6d60531b6044820152606490fd5b600190602084519401938184015501611a08565b634e487b7160e01b600052604160045260246000fd5b6001906020845194019381840155016119c3565b60019060208451940193818401550161197e565b611f9d9082600052600d602052611f986040600020611f9283898c612e82565b91612ef1565b612c76565b611912565b90611f986002611fc093611fb7848789612e82565b92909101612ef1565b611868565b611fde915060203d602011610446576104388183612c1b565b8e611805565b346104c95760403660031901126104c957611ffd612a5f565b600435600052600c60205260406000209060018060a01b03166000526020526020604060002054604051908152f35b346104c95760203660031901126104c957600435600052600d60205261087e6120586040600020614164565b604051918291602083526020830190612b0b565b346104c95760003660031901126104c9576002546040516001600160a01b039091168152602090f35b346104c95760203660031901126104c9576004356000526009602052604060002060058101546001600160401b03808260481c168181146000146121b157506000195b6121a860018060a01b038554169361219060046121826040519861210a8a6121038160018501612f46565b038b612c1b565b61217461211960028301614164565b61214860405193612138856121318160038501612f46565b0386612c1b565b6121316040518098819301612f46565b6121666040519c8d9c8d5260208d61010091829101528d0190612acb565b908b820360408d0152612b0b565b9089820360608b0152612acb565b908782036080890152612acb565b93811660a086015260ff60c086019160401c16612b67565b60e08301520390f35b6120d8565b346104c9576121d56121c736612ab5565b906121d061338e565b613e0e565b6001600055005b346104c95760003660031901126104c9576020600854604051908152f35b346104c95760403660031901126104c957600435612216612a9f565b33600052600760205260ff60406000205416801561267f575b156106885781600052600960205260ff60056040600020015460401c1660038110156104a15761048f578160005260096020526040600020906007820154906001600160401b0381169182101561047d5760058301805468ffffffffffffffffff60401b1916604883901b67ffffffffffffffff60481b1617600160401b1790556122bd9060098401612ed9565b90549060031b1c91600c810190815490600d81016122dc815484612f39565b90601183019384546122ee848a612f39565b1161155e578061260d575b5080548061259a575b506000855491816123648254958c7f5811038d8089f26da5521abe80702dd405dd320106f5e92b954891ea28cea3fe608060018060a01b0398898c54169a8a600254169060405192835260208301528b60408301526060820152a2885461316e565b9788885555556000946000948882116123bf575b8960008051602061442c83398151915260808a8a8a6123b28f60058d60ff92600b820155015460401c166040519485526020850190612b67565b60408301526060820152a2005b9194509194506123d96123d2888461316e565b809361316e565b9055600e8201938454821160001461250e575061241c602084600154168585541690875491600060405180968195829463a9059cbb60e01b845260048401613d99565b03925af190811561044d576000916124ef575b501561040e576124418454809261316e565b9092600082955581612479575b5050906123b260ff6005608096959460008051602061442c833981519152985b985093949596612378565b6124ad91816020926001989796959854169060025416600060405180968195829463a9059cbb60e01b845260048401613d99565b03925af190811561044d576000916124d0575b501561040e57909192868061244e565b6124e9915060203d602011610446576104388183612c1b565b876124c0565b612508915060203d602011610446576104388183612c1b565b8861242f565b819594509060209161253f9397946001541690600060405180968195829463a9059cbb60e01b845260048401613d99565b03925af190811561044d5760009161257b575b501561040e5760008051602061442c833981519152936123b260ff60056080969360009561246e565b612594915060203d602011610446576104388183612c1b565b86612552565b60206125cf9160018060a01b0380600154169060025416600060405180968195829463a9059cbb60e01b845260048401613d99565b03925af190811561044d576000916125ee575b501561040e5788612302565b612607915060203d602011610446576104388183612c1b565b896125e2565b60206126419160018060a01b03806001541690875416600060405180968195829463a9059cbb60e01b845260048401613d99565b03925af190811561044d57600091612660575b501561040e57886122f9565b612679915060203d602011610446576104388183612c1b565b89612654565b506002546001600160a01b0316331461222f565b346104c95760203660031901126104c9576004358015158091036104c9576002546001600160a01b031633036116685760207f0e2fb031ee032dc02d8011dc50b816eb450cf856abd8261680dac74f72165bd29160ff196006541660ff821617600655604051908152a1005b346104c95760203660031901126104c957612718612a49565b600254906001600160a01b039081831633036116685716908115611656576001600160a01b03191681176002557f928a2375aa6302033471f791936c2eb8a3c97170505e7519fb73cd615b805bce600080a2005b346104c95760003660031901126104c9576001546040516001600160a01b039091168152602090f35b346104c95760003660031901126104c9576020600554604051908152f35b346104c95760a03660031901126104c9576004356001600160401b036024358181116104c9576127e79036906004016129ec565b90916044358181116104c957612801903690600401612a19565b91906064358281116104c95761281b9036906004016129ec565b9190926084359081116104c9576128369036906004016129ec565b94909833600052600760205260ff6040600020541680156129d8575b156129c9575087600052600a60205260ff60406000205416156106765760ff600654166104b757876000526009602052604060002060ff600582015460401c1660038110156104a157612979576128ad878960018401612cee565b600281016128ba81612e01565b60005b83811061295b5750509261293a612948938693612915898e7fa79644652b69872a47a010039d682853ffc3293654efde61f74e2d88702e8cf79e9f9a8a61290f896129569f9d93600360049501612cee565b01612cee565b61292c6040519b8c9b60808d5260808d0191612fdc565b918a830360208c0152612ffd565b918783036040890152612fdc565b918483036060860152612fdc565b0390a2005b80611f9861296d612974938789612e82565b9085612ef1565b6128bd565b60405162461bcd60e51b815260206004820152602260248201527f4f6e6c7920616374697665206d61726b6574732063616e206265207570646174604482015261195960f21b6064820152608490fd5b637bfa4b9f60e01b8152600490fd5b506002546001600160a01b03163314612852565b9181601f840112156104c9578235916001600160401b0383116104c957602083818601950101116104c957565b9181601f840112156104c9578235916001600160401b0383116104c9576020808501948460051b0101116104c957565b600435906001600160a01b03821682036104c957565b602435906001600160a01b03821682036104c957565b60609060031901126104c957600435906024356001600160a01b03811681036104c9579060443590565b602435906001600160401b03821682036104c957565b60409060031901126104c9576004359060243590565b919082519283825260005b848110612af7575050826000602080949584010152601f8019910116010190565b602081830181015184830182015201612ad6565b908082519081815260208091019281808460051b8301019501936000915b848310612b395750505050505090565b9091929394958480612b57600193601f198682030187528a51612acb565b9801930193019194939290612b29565b9060038210156104a15752565b60609060031901126104c957600435906024359060443590565b60809060031901126104c95760043590602435906044359060643590565b90815180825260208080930193019160005b828110612bcc575050505090565b835185529381019392810192600101612bbe565b15612be757565b60405162461bcd60e51b815260206004820152600c60248201526b08ccaca40e8dede40d0d2ced60a31b6044820152606490fd5b90601f801991011681019081106001600160401b03821117611f3457604052565b908160209103126104c9575180151581036104c95790565b6001600160a01b03918216815291166020820152604081019190915260600190565b600019811461077c5760010190565b90600182811c92168015612cb5575b6020831014612c9f57565b634e487b7160e01b600052602260045260246000fd5b91607f1691612c94565b919082549060031b91821b91600019901b1916179055565b818110612ce2575050565b60008155600101612cd7565b9092916001600160401b038111611f3457612d098254612c85565b601f8111612db1575b506000601f8211600114612d4d5781929394600092612d42575b50508160011b916000199060031b1c1916179055565b013590503880612d2c565b601f198216948382526020918281209281905b888210612d9957505083600195969710612d7f575b505050811b019055565b0135600019600384901b60f8161c19169055388080612d75565b80600184968294958701358155019501920190612d60565b612dde90836000526020600020601f840160051c81019160208510612de4575b601f0160051c0190612cd7565b38612d12565b9091508190612dd1565b8181029291811591840414171561077c57565b80549060009081815582612e1457505050565b81526020808220928301925b838110612e2d5750505050565b8083612e3b60019354612c85565b80612e49575b505001612e20565b601f8082118514612e6057505081555b8338612e41565b612e7990848452868420920160051c8201858301612cd7565b81835555612e59565b9190811015612ec35760051b81013590601e19813603018212156104c95701908135916001600160401b0383116104c95760200182360381136104c9579190565b634e487b7160e01b600052603260045260246000fd5b8054821015612ec35760005260206000200190600090565b8054919291600160401b811015611f3457612f1191600182018155612ed9565b929092612f2357612f2192612cee565b565b634e487b7160e01b600052600060045260246000fd5b9190820180921161077c57565b9060009291805491612f5783612c85565b918282526001938481169081600014612fb95750600114612f79575b50505050565b90919394506000526020928360002092846000945b838610612fa5575050505001019038808080612f73565b805485870183015294019385908201612f8e565b9294505050602093945060ff191683830152151560051b01019038808080612f73565b908060209392818452848401376000828201840152601f01601f1916010190565b90808352602080930192838260051b810194846000925b858410613025575050505050505090565b9091929394959681810384528735601e19843603018112156104c95783018681019190356001600160401b0381116104c95780360383136104c95761306f88928392600195612fdc565b990194019401929594939190613014565b90815480825260208092019260005281600020916000905b8282106130a6575050505090565b835485529384019360019384019390910190613098565b805460008255806130cc575050565b612f2191600052602060002090810190612cd7565b90600160401b8111611f34578154908083558181106130ff57505050565b612f219260005260206000209182019101612cd7565b6001600160401b038111611f345760051b60200190565b9061313682613115565b6131436040519182612c1b565b8281528092613154601f1991613115565b0190602036910137565b9190811015612ec35760051b0190565b9190820391821161077c57565b8115611d3e570490565b670de0b6b3a7640000916000198383099280830292838086109503948086039514613228578285101561320557908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b8260649260405192630c740aef60e31b8452600484015260248301526044820152fd5b505090613235925061317b565b90565b90670de0b6b3a76400009182811061330b5782810460018060801b03811160071b90811c906001600160401b03821160061b91821c63ffffffff811160051b90811c61ffff811160041b90811c60ff811160031b90811c91600f831160021b92831c936001968760038711811b96871c11961717171717171791848302921c93808514613304576706f05b59d3b2000094855b6132d757509193505050565b808291020494671bc16d674ec800008610156132f7575b821c94856132cb565b8095930192821c946132ee565b5090925050565b6024906040519063036d32ef60e41b82526004820152fd5b9060405191828154918282526020928383019160005283600020936000905b82821061335857505050612f2192500383612c1b565b855484526001958601958895509381019390910190613342565b9190916000838201938412911290801582169115161761077c57565b60026000541461339f576002600055565b604051633ee5aeb560e01b8152600490fd5b8051821015612ec35760209160051b010190565b9094916133d2865161312c565b9360005b87518110156133fd57806133ed6133f8928a6133b1565b5161121c82896133b1565b6133d6565b5093613438826113dd94959861343e9761343161342a64e8d4a510009b61342484896133b1565b51612f39565b91866133b1565b5286613442565b93613442565b0490565b90929192600090815b81518310156134a55761345e83836133b1565b5164e8d4a510009081810291818304149015171561077c5761349f916102746134999261074d610748896134928a8e6133b1565b5193613185565b92612c76565b9161344b565b6132359495506714057b7ef767814f9250670de0b6b3a764000091506134ca90613238565b020490613d03565b680736ea4425c11ac6308111613ceb576714057b7ef767814f90670de0b6b3a7640000918291020490680a688906bd8affffff8211613cd257604091821b81900490600160bf1b60ff60381b8316613be1575b60ff60301b8316613af1575b60ff60281b8316613a01575b64ff000000008316613909575b63ff0000008316613819575b62ff00008316613731575b61ff008316613651575b60ff831661357e575b02911c60bf031c90565b6080831661363f575b83831661362d575b6020831661361b575b60108316613609575b600883166135f7575b600483166135e5575b600283166135d5575b6001831615613574576001600160401b0102831c613574565b6001600160401b0102831c6135bc565b6801000000000000000302831c6135b3565b6801000000000000000602831c6135aa565b6801000000000000000b02831c6135a1565b6801000000000000001602831c613598565b6801000000000000002c02831c61358f565b6801000000000000005902831c613587565b618000831661371f575b614000831661370d575b61200083166136fb575b61100083166136e9575b61080083166136d7575b61040083166136c5575b61020083166136b3575b61010083161561356b57680100000000000000b102831c61356b565b6801000000000000016302831c613697565b680100000000000002c602831c61368d565b6801000000000000058c02831c613683565b68010000000000000b1702831c613679565b6801000000000000162e02831c61366f565b68010000000000002c5d02831c613665565b680100000000000058b902831c61365b565b628000008316613807575b6240000083166137f5575b6220000083166137e3575b6210000083166137d1575b6208000083166137bf575b6204000083166137ad575b62020000831661379b575b62010000831615613561576801000000000000b17202831c613561565b680100000000000162e402831c61377e565b6801000000000002c5c802831c613773565b68010000000000058b9102831c613768565b680100000000000b172102831c61375d565b68010000000000162e4302831c613752565b680100000000002c5c8602831c613747565b6801000000000058b90c02831c61373c565b638000000083166138f7575b634000000083166138e5575b632000000083166138d3575b631000000083166138c1575b630800000083166138af575b6304000000831661389d575b6302000000831661388b575b63010000008316156135565768010000000000b1721802831c613556565b6801000000000162e43002831c61386d565b68010000000002c5c86002831c613861565b680100000000058b90c002831c613855565b6801000000000b17217f02831c613849565b680100000000162e42ff02831c61383d565b6801000000002c5c85fe02831c613831565b68010000000058b90bfc02831c613825565b64800000000083166139ef575b64400000000083166139dd575b64200000000083166139cb575b64100000000083166139b9575b64080000000083166139a7575b6404000000008316613995575b6402000000008316613983575b64010000000083161561354a57680100000000b17217f802831c61354a565b68010000000162e42ff102831c613964565b680100000002c5c85fe302831c613957565b6801000000058b90bfce02831c61394a565b68010000000b17217fbb02831c61393d565b6801000000162e42fff002831c613930565b68010000002c5c8601cc02831c613923565b680100000058b90c0b4902831c613916565b6001602f1b8316613adf575b6001602e1b8316613acd575b6001602d1b8316613abb575b6001602c1b8316613aa9575b6001602b1b8316613a97575b6001602a1b8316613a85575b600160291b8316613a73575b600160281b83161561353d576801000000b17218355102831c61353d565b680100000162e430e5a202831c613a55565b6801000002c5c863b73f02831c613a49565b68010000058b90cf1e6e02831c613a3d565b680100000b1721bcfc9a02831c613a31565b68010000162e43f4f83102831c613a25565b680100002c5c89d5ec6d02831c613a19565b6801000058b91b5bc9ae02831c613a0d565b600160371b8316613bcf575b600160361b8316613bbd575b600160351b8316613bab575b600160341b8316613b99575b600160331b8316613b87575b600160321b8316613b75575b600160311b8316613b63575b600160301b8316156135315768010000b17255775c0402831c613531565b6801000162e525ee054702831c613b45565b68010002c5cc37da949202831c613b39565b680100058ba01fb9f96d02831c613b2d565b6801000b175effdc76ba02831c613b21565b680100162f3904051fa102831c613b15565b6801002c605e2e8cec5002831c613b09565b68010058c86da1c09ea202831c613afd565b6001603f1b8316613cbf575b6001603e1b8316613cad575b6001603d1b8316613c9b575b6001603c1b8316613c89575b6001603b1b8316613c77575b6001603a1b8316613c65575b600160391b8316613c53575b600160381b83161561352557680100b1afa5abcbed6102831c613525565b68010163da9fb33356d802831c613c35565b680102c9a3e778060ee702831c613c29565b6801059b0d31585743ae02831c613c1d565b68010b5586cf9890f62a02831c613c11565b6801172b83c7d517adce02831c613c05565b6801306fe0a31b7152df02831c613bf9565b5068016a09e667f3bcc909607f1b613bed565b60405163b3b6ba1f60e01b815260048101839052602490fd5b60249060405190630d7b1d6560e11b82526004820152fd5b90919060001983820983820291828083109203918083039214613d8857670de0b6b3a76400009081831015613d6a57947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b6044908660405191635173648d60e01b835260048301526024820152fd5b5050670de0b6b3a764000090049150565b6001600160a01b039091168152602081019190915260400190565b909491613dc1865161312c565b9360005b8751811015613de157806133ed613ddc928a6133b1565b613dc5565b5093613438826111f094959861343e9761343161342a64e8d4a510009b613e0884896133b1565b5161316e565b90600091808352602092600984526040938482209160058301805460ff81891c16600381101561415057600114613fb1575054861c60ff166003811015613f9d57600214613e67578551639f4a648960e01b8152600490fd5b8381969394959652600c82528281203382528252828120549381851315613f8c576011810185815410613f7b5790601491878452600c855285842033855285528386812055613eb787825461316e565b905501613ec5858254612f39565b9055600154835163a9059cbb60e01b815290839082906001600160a01b0316818581613ef58b3360048401613d99565b03925af1918215613f705791613f53575b5015613f425760019082519586528501528301527f09289ec34f62d6f895af933338b7a7edcc6fdb552e8f76337f33e6ccaaf1843b60603393a3565b81516312171d8360e31b8152600490fd5b613f6a9150823d8411610446576104388183612c1b565b38613f06565b8451903d90823e3d90fd5b8451633a23d82560e01b8152600490fd5b83516330a748d360e11b8152600490fd5b634e487b7160e01b82526021600452602482fd5b6001600160401b039150604897949596979392931c16860361413f57848252600b81528282203383528152828220868352815282822054938415613f8c57600b81018581541061412e57868452600b8352848420338552835284842088855283528385812055600982016140258982612ed9565b90549060031b1c87811061411d57601193929161143a8b6114348b6140499561316e565b61405487825461316e565b9055018054858110613f7b578561406a9161316e565b9055600154835163a9059cbb60e01b815290829082906001600160a01b031681868161409a8b3360048401613d99565b03925af19081156141135783916140f6575b50156140e55782519586528501528301527f09289ec34f62d6f895af933338b7a7edcc6fdb552e8f76337f33e6ccaaf1843b60603393a3565b82516312171d8360e31b8152600490fd5b61410d9150823d8411610446576104388183612c1b565b386140ac565b84513d85823e3d90fd5b8651633a9a6bf560e11b8152600490fd5b8451636e21e8cb60e01b8152600490fd5b8251630e5b822760e11b8152600490fd5b634e487b7160e01b84526021600452602484fd5b90815461417081613115565b9260409361418085519182612c1b565b828152809460208092019260005281600020906000935b8585106141a657505050505050565b600184819284516141c2816141bb818a612f46565b0382612c1b565b815201930194019391614197565b60009081526009602052604081209260ff600585015460401c1692600393848110156141505761048f576007850154908181101561047d57821561046b57614233606461421e875486612dee565b04936111f060049560646111e9885485612dee565b91821561439c576142438161312c565b9560088801865b8381106143795750505050839560019583871b848104600203614366579695949392919086600a60068401549301975b614312575b888a106142925750505050505050505090565b9091929394959697986142a58a82612f39565b8281018091116142ff57821c90866142c883886142c18e613323565b888a6133c5565b116142dd5750985b979695949392919061427f565b99506000198101908111156142d057634e487b7160e01b885260118752602488fd5b634e487b7160e01b895260118852602489fd5b90919293949596978561433082876143298d613323565b87896133c5565b10156142d057811b8169d3c21bcecceda100000082116143585790989796959493929161427a565b50979695949392919061427f565b634e487b7160e01b875260118652602487fd5b806143876143979284612ed9565b905490851b1c61121c828c6133b1565b61424a565b5050505091505090565b90600090828252600960205260056040832001549060ff8260401c16600381101561415057600114801590614416575b61440f576040938352600b6020528383209060018060a01b031683526020526001600160401b038383209160481c168252602052205490565b5050905090565b506001600160401b03808360481c16146143d656fed26a37ea32f0be10c131818ca4c38930b6917f34fd57e18abf0cd21dd418c88da2646970667358221220670a0012d434857466b49ddbfd0ed4005bbdca03b81b9cf7960747a7f8d7f6eb64736f6c63430008140033000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda02913
Deployed Bytecode
0x608080604052600436101561001357600080fd5b60003560e01c90816301e421e0146127b35750806311e3c03e1461279557806311eac8551461276c57806313f1031d1461051b57806315700052146126ff57806316c38b3c146126935780631a095c6e146121fa57806324760807146121dc578063286db5c2146121b65780632882224f1461209557806329575f6a1461206c5780632dbdaf5b1461202c57806336b4c64d14611fe45780633a4d6d38146116b9578063429b62e51461167a5780634b0bddd2146115cb57806353613dd3146115ad57806357c8db97146115945780635a2db6fb146112a15780635c975abb1461127e578063625a7ee5146112585780636af48db9146112275780636d76ee57146111425780636f609ad014610ec85780636ff6c4b814610e3c5780637c16cd9e14610af85780639cd441da1461098d578063a498342114610901578063a573a8f814610882578063aaf49176146107c6578063ae165ff9146106ae578063cfe26c4414610562578063d27ff2fc1461051b578063d6e6eb9f146104fd578063e1adaf58146104ce5763ed881230146101ab57600080fd5b346104c9576101b936612b8e565b91929060ff600654166104b757816000526020926009845260ff60056040600020015460401c1660038110156104a15761048f576101f561338e565b8260005260098452604060002091600783015486101561047d57801561046b576006830154906102408188600887019461022e86613323565b61023a600a8a01613323565b916133c5565b92831561046b57606461025560035486612dee565b049461027a606461026860045488612dee565b04956102748789612f39565b90612f39565b918211610459576001546040516323b872dd60e01b815290899082906001600160a01b0316816000816102b289303360048501612c54565b03925af190811561044d57600091610420575b501561040e576103cc94600c82016102de888254612f39565b90556102ef600d8301918254612f39565b90556103ab61039b8a6009601185019461030a878754612f39565b86556012810161031b888254612f39565b90558b600052600c8d526040600020336000528d526040600020610340888254613372565b905561036561034f848b612ed9565b61035f8b83548360031b1c612f39565b91612cbf565b8b600052600b8d526040600020336000528d526040600020836000528d526040600020610393898254612f39565b905501612ed9565b61035f8683548360031b1c612f39565b5496604051988952880152604087015260e0606087015260e0860190613080565b92608085015260a0840152600060c08401527fd1626256062296eb2a74401b9149db9ce59bd7c024a01ffc261bfc3eded28eb633938033940390a46001600055005b6040516312171d8360e31b8152600490fd5b6104409150893d8b11610446575b6104388183612c1b565b810190612c3c565b386102c5565b503d61042e565b6040513d6000823e3d90fd5b604051638199f5f360e01b8152600490fd5b604051631f2a200560e01b8152600490fd5b604051632a71953160e01b8152600490fd5b604051635a90bb8d60e11b8152600490fd5b634e487b7160e01b600052602160045260246000fd5b60405163ab35696f60e01b8152600490fd5b600080fd5b346104c95760203660031901126104c95760043560005260096020526020600760406000200154604051908152f35b346104c95760003660031901126104c9576020600454604051908152f35b346104c95761052936612a75565b91600052600b60205260406000209060018060a01b03166000526020526040600020906000526020526020604060002054604051908152f35b346104c95760403660031901126104c95760043561057e612a9f565b33600052600760205260ff60406000205416801561069a575b156106885781600052600a60205260ff604060002054161561067657816000526009602052600560406000200190815460ff8160401c1660038110156104a157610621577f42440d1cfc9a52f9b6908f4a9b38357bc25b5510aa0ce725f3c15261071f5e6e926001600160401b036020931680926001600160401b031916179055604051908152a2005b60405162461bcd60e51b815260206004820152602760248201527f43616e206f6e6c7920757064617465206461746520666f7220616374697665206044820152666d61726b65747360c81b6064820152608490fd5b60405163b0cfa44760e01b8152600490fd5b604051637bfa4b9f60e01b8152600490fd5b506002546001600160a01b03163314610597565b346104c9576106bc36612ab5565b906000526009602052604060002090600782015481101561047d5760068201546106f4600a6106ed60088601613323565b9401613323565b9160009160009360005b86518110156107925761071181836133b1565b5161071c82896133b1565b5164e8d4a510009081810291818304149015171561077c5761075a9161074d6107488761075394613185565b6134d2565b90613d03565b8096612f39565b94848214610772575b5061076d90612c76565b6106fe565b955061076d610763565b634e487b7160e01b600052601160045260246000fd5b61079c8587613185565b620f42409081810291818304149015171561077c57602090670de0b6b3a764000060405191048152f35b346104c95760203660031901126104c95760043560005260096020526040600020600e81015461087e600b83015492600c81015490600d81015460118201546012830154601384015491601485015493610850610831600a61082a60088a01613323565b9801613323565b966040519b8c9b8c5260208c01526101408060408d01528b0190612bac565b9660608a0152608089015260a088015260c087015260e0860152610100850152838203610120850152612bac565b0390f35b346104c95760203660031901126104c95760043533600052600760205260ff6040600020541680156108ed575b156106885760407fa844e22c978ec45272a79c9dba58e154cf753922066ea12cba345f49dd3f4a4a91600554908060055582519182526020820152a1005b506002546001600160a01b031633146108af565b346104c95760203660031901126104c95760043533600052600760205260ff604060002054168015610979575b156106885760408161096460647f219d87b3822c2cd9103f559e66b1fa6683e5a41c1dde2e43ee26577e40f637be941115612be0565b600454908060045582519182526020820152a1005b506002546001600160a01b0316331461092e565b346104c95761099b36612ab5565b90336000526020916007835260ff604060002054168015610ae4575b1561068857816000526009835260ff60056040600020015460401c1660038110156104a15761048f576109e861338e565b801561046b578160005260098352604060002060018060a01b03600154168460405180926323b872dd60e01b825281600081610a2989303360048501612c54565b03925af190811561044d57600091610ac7575b501561040e576011810193610a52838654612f39565b809555610a896006610a64858861316e565b93610a74600f8201968754612f39565b8096550192610a84878554612dee565b61317b565b80925560405194855284015260408301527f089607a52cca0d390ff7d0ad4e97545804dcc41418e1daee9ec3948596fec94460603393a36001600055005b610ade9150853d8711610446576104388183612c1b565b85610a3c565b506002546001600160a01b031633146109b7565b346104c9576020806003193601126104c957600435336000526007825260ff604060002054168015610e28575b156106885780600052600a825260ff604060002054161561067657610b4861338e565b80600052600982526040600020916005830160ff815460401c1660038110156104a157610dd7576012840154601385015480821115610dce57610b8a9161316e565b601485015480821115610dc557610ba09161316e565b826011860191825490808211600014610dbc57610bbd908261316e565b905b8180151580610daf575b610cf7575b505080151580610cea575b610c43575b505050687fffffffffffffff8160411b68ffffffffffffffffff60401b19825416179055600f600e840154930154906040519384528301527f013609c5ed98f635a390501845e1c3fd8ed26be21ca23b95abecc781f6a90a4760403393a36001600055005b610ca192600f8801805492838110600014610cdf57610c6390809461316e565b9055610c7082825461316e565b905560018060a01b0380600154169060025416600060405180968195829463a9059cbb60e01b845260048401613d99565b03925af190811561044d57600091610cc2575b501561040e57848281610bde565b610cd99150833d8511610446576104388183612c1b565b85610cb4565b50610c63838061316e565b50600f8701541515610bd9565b610d649250610d27610d3591610d2e600e8c9795970196875490818410600014610da3578398899586809461316e565b905561316e565b875561316e565b9260018060a01b038060015416908a5416600060405180968195829463a9059cbb60e01b845260048401613d99565b03925af190811561044d57600091610d86575b501561040e5783908780610bce565b610d9d9150853d8711610446576104388183612c1b565b87610d77565b8198899586809461316e565b50600e8901541515610bc9565b50600090610bbf565b50506000610ba0565b50506000610b8a565b60405162461bcd60e51b8152600481018390526024808201527f4f6e6c7920616374697665206d61726b6574732063616e2062652063616e63656044820152631b1b195960e21b6064820152608490fd5b506002546001600160a01b03163314610b25565b346104c95760203660031901126104c95760043533600052600760205260ff604060002054168015610eb4575b1561068857604081610e9f60647f1f440356ff29d242b1f0e2afdae6b4be38d5cce2db5fbb241d3fdc363b942100941115612be0565b600354908060035582519182526020820152a1005b506002546001600160a01b03163314610e69565b346104c95760a03660031901126104c9576001600160a01b03608435818116906004359060443590602435908490036104c95760ff600654166104b757826000526020946009865260ff60056040600020015460401c1660038110156104a15761048f57610f3461338e565b83600052600986526040600020600781015483101561047d57831561046b576006810154610f7785856008850193610f6b85613323565b61023a600a8801613323565b94851561046b576064610f8c60035488612dee565b0493610fab6064610f9f6004548a612dee565b04976102748988612f39565b90606435821161045957600154168a60405180926323b872dd60e01b825281600081610fdc88303360048501612c54565b03925af190811561044d57600091611125575b501561040e57806110e561039b886009888f8f8f7fd1626256062296eb2a74401b9149db9ce59bd7c024a01ffc261bfc3eded28eb69f8b8f6111069f8f8a906110b89561035f94611048600c6110a99601918254612f39565b9055611059600d8c01918254612f39565b905560118a019e8f61106c828254612f39565b905560128b0161107d828254612f39565b905587600052600c8a526040600020896000528a526110a26040600020918254613372565b9055612ed9565b91909283548360031b1c612f39565b600052600b8252604060002090600052815260406000209084600052526040600020610393898254612f39565b5499604051968752860152604085015260e0606085015260e0840190613080565b95608083015260a0820152600160c08201528033950390a46001600055005b61113c91508b3d8d11610446576104388183612c1b565b8b610fef565b346104c95761115036612b74565b9091600052600960205260406000209160ff600584015460401c1692600393848110156104a15761048f5760078101548083101561047d57831561046b576111978161312c565b906008830160005b8281106111fe5760206111f6896111f060646111da6111d28d8d8d8d6111cc600a60068401549301613323565b91613db4565b935484612dee565b0460646111e960045485612dee565b0490612f39565b9061316e565b604051908152f35b8061120c6112229284612ed9565b9054908a1b1c61121c82876133b1565b52612c76565b61119f565b346104c95760203660031901126104c957600435600052600a602052602060ff604060002054166040519015158152f35b346104c95760403660031901126104c95760206111f6611276612a5f565b6004356143a6565b346104c95760003660031901126104c957602060ff600654166040519015158152f35b346104c9576112af36612b8e565b60ff60069492939454166104b757816000526020926009845260ff60056040600020015460401c1660038110156104a15761048f576112ec61338e565b8260005260098452604060002090600782015486101561047d57801561046b5783600052600b855260406000203360005285526040600020866000528552604060002054928184106115825760068301549161135d8189600887019561135187613323565b6111cc600a8a01613323565b94851561046b57606461137260035488612dee565b0495611391606461138560045484612dee565b04916111f0838a612f39565b938410610459576113e2918391600c88016113ad8a8254612f39565b90556113be600d8901918254612f39565b90556113dd6113cd8c88612ed9565b61035f8583548360031b1c61316e565b61316e565b86600052600b885260406000203360005288526040600020896000528852604060002055600984016114148982612ed9565b90549060031b1c908282106115705761143a8a611434856114409561316e565b92612ed9565b90612cbf565b601184019384549083821061155e5761145b8460139361316e565b865501611469838254612f39565b90556000868152600c88526040808220338352895281208054848103928512801582851316918412161761077c575560015460405163a9059cbb60e01b815290889082906001600160a01b0316816000816114c8893360048401613d99565b03925af190811561044d57600091611541575b501561040e57611506935496604051988952880152604087015260c0606087015260c0860190613080565b92608085015260a08401527fd23c082e07b3f3b32efe0f4971136900e9a67130775cd95e8dae76fb1d685f5733938033940390a46001600055005b6115589150883d8a11610446576104388183612c1b565b896114db565b604051633a23d82560e01b8152600490fd5b604051633a9a6bf560e11b8152600490fd5b604051633c57b48560e21b8152600490fd5b346104c95760206111f66115a736612b74565b916141d0565b346104c95760003660031901126104c9576020600354604051908152f35b346104c95760403660031901126104c9576115e4612a49565b602435908115158092036104c9576002546001600160a01b0391908216330361166857169081156116565760207f235bc17e7930760029e9f4d860a2a8089976de5b381cf8380fc11c1d88a11133918360005260078252604060002060ff1981541660ff8316179055604051908152a2005b6040516332691b5760e01b8152600490fd5b6040516316c726b160e01b8152600490fd5b346104c95760203660031901126104c9576001600160a01b0361169b612a49565b166000526007602052602060ff604060002054166040519015158152f35b346104c9576101003660031901126104c9576004356001600160401b0381116104c9576116ea9036906004016129ec565b6024356001600160401b0381116104c957611709903690600401612a19565b91906044356001600160401b0381116104c95761172a9036906004016129ec565b9190936064356001600160401b0381116104c95761174c9036906004016129ec565b608435916001600160401b03831683036104c95760c4356001600160401b0381116104c95761177f903690600401612a19565b96909860e4356001600160401b0381116104c9576117a1903690600401612a19565b97909660ff600654166104b75760028a1061046b5760a4351561046b576001546040516323b872dd60e01b81529060209082906001600160a01b0316816000816117f260a435303360048501612c54565b03925af190811561044d57600091611fc5575b501561040e5761185960019b61181c600854612c76565b9e8f80600855600052600a60205260406000208e60ff19825416179055600960205260406000209d8e33828060a01b031982541617815501612cee565b61186560028c01612e01565b60005b8b828210611fa25761189197969593506118889492506003915001612cee565b60048801612cee565b600585015460a435600e8701556000600f870155600060108701556001600160401b038060481b92169060018060881b031916171760058501556000600b8501556000600c8501556118e960a4356011860154612f39565b6011850155856000526009602052604060002095600d60205261190f6040600020612e01565b60005b848110611f72575083600788015561192c600888016130bd565b611938600988016130bd565b611944600a88016130bd565b61194d8461312c565b8051906001600160401b038211611f345760209061196e8360088c016130e1565b0160088901600052602060002060005b838110611f5e57505050506119928461312c565b8051906001600160401b038211611f34576020906119b38360098c016130e1565b0160098901600052602060002060005b838110611f4a57505050506119d78461312c565b8051906001600160401b038211611f34576020906119f883600a8c016130e1565b01600a8901600052602060002060005b838110611f205750600019979250505083611d5c578415611d3e5760009360005b8660001981011161077c576000198701811015611a8f57611a6d611a5082600a8d01612ed9565b97611a688a670de0b6b3a764000004809a8194612cbf565b612f39565b95888110611a85575b50611a8090612c76565b611a29565b9750611a80611a76565b50939791969297959095670de0b6b3a764000090810390811161077c57600019860186811161077c578161143a611ac992600a8701612ed9565b818110611d54575b505b64e8d4a510009060a43580830204820361077c578015611d3e57670de0b6b3a7640000611b196714057b7ef767814f926ec097ce7bc90715b34b9f100000000004613238565b02048015611cf0575b611b329060069260a43502613185565b910155847fc0d32b9d984118432cfd761f0df84468fa95b636e95b0e71b573176d6e3aa9546020604051868152a260018060a01b0384541695600585015491600e8601549060118701549660068101549160405197611baf611b9e6101a0808c528b0160018601612f46565b8a810360208c015260038501612f46565b89810360408b01526002840154808252602082019060208160051b84010192600287016000526020600020926000915b838310611cc4575050505050611c389392600892611c0c838d606081611c29970391015260048701612f46565b6001600160401b038b1660808e01528c810360a08e015291612ffd565b9189830360c08b015201613080565b60e08701929092528582036101008701528482526001600160fb1b0385116104c9577fb5c5b574da8421c61fe28d327f1a8fe774a3798fd039550927fbda6ef8125b2696611cb1879560209760051b8096898701376001600160401b038160481c1661012088015260ff61014088019160401c16612b67565b61016085015261018084015201030190a3005b909192939460206001611ce18193601f1986820301875289612f46565b97019301930191939290611bdf565b5084670de0b6b3a7640000810204670de0b6b3a7640000148515171561077c57611b326006916714057b7ef767814f670de0b6b3a7640000611d33818a02613238565b020491509150611b22565b634e487b7160e01b600052601260045260246000fd5b905088611ad1565b969493929190838303611ee25760009760005b858110611ebd57508815611e865760009460005b8160001981011161077c576000198201811015611e1457611da581878761315e565b35670de0b6b3a76400009081810291818304149015171561077c578b611dca9161317b565b96898815611e0b575b611de991611a688a61143a86600a839601612ed9565b96888110611e01575b50611dfc90612c76565b611d83565b9750611dfc611df2565b60019850611dd3565b5095919793949096929850670de0b6b3a76400008181031161077c5780670de0b6b3a76400000390670de0b6b3a764000014611e7e575b600019860186811161077c578161143a611e6892600a8701612ed9565b818110611e76575b50611ad3565b905088611e70565b506001611e4b565b60405162461bcd60e51b815260206004820152600f60248201526e726174696f732073756d207a65726f60881b6044820152606490fd5b98611ed7611edd91611ed08c888861315e565b3590612f39565b99612c76565b611d6f565b60405162461bcd60e51b81526020600482015260166024820152750e4c2e8d2dee640d8cadccee8d040dad2e6dac2e8c6d60531b6044820152606490fd5b600190602084519401938184015501611a08565b634e487b7160e01b600052604160045260246000fd5b6001906020845194019381840155016119c3565b60019060208451940193818401550161197e565b611f9d9082600052600d602052611f986040600020611f9283898c612e82565b91612ef1565b612c76565b611912565b90611f986002611fc093611fb7848789612e82565b92909101612ef1565b611868565b611fde915060203d602011610446576104388183612c1b565b8e611805565b346104c95760403660031901126104c957611ffd612a5f565b600435600052600c60205260406000209060018060a01b03166000526020526020604060002054604051908152f35b346104c95760203660031901126104c957600435600052600d60205261087e6120586040600020614164565b604051918291602083526020830190612b0b565b346104c95760003660031901126104c9576002546040516001600160a01b039091168152602090f35b346104c95760203660031901126104c9576004356000526009602052604060002060058101546001600160401b03808260481c168181146000146121b157506000195b6121a860018060a01b038554169361219060046121826040519861210a8a6121038160018501612f46565b038b612c1b565b61217461211960028301614164565b61214860405193612138856121318160038501612f46565b0386612c1b565b6121316040518098819301612f46565b6121666040519c8d9c8d5260208d61010091829101528d0190612acb565b908b820360408d0152612b0b565b9089820360608b0152612acb565b908782036080890152612acb565b93811660a086015260ff60c086019160401c16612b67565b60e08301520390f35b6120d8565b346104c9576121d56121c736612ab5565b906121d061338e565b613e0e565b6001600055005b346104c95760003660031901126104c9576020600854604051908152f35b346104c95760403660031901126104c957600435612216612a9f565b33600052600760205260ff60406000205416801561267f575b156106885781600052600960205260ff60056040600020015460401c1660038110156104a15761048f578160005260096020526040600020906007820154906001600160401b0381169182101561047d5760058301805468ffffffffffffffffff60401b1916604883901b67ffffffffffffffff60481b1617600160401b1790556122bd9060098401612ed9565b90549060031b1c91600c810190815490600d81016122dc815484612f39565b90601183019384546122ee848a612f39565b1161155e578061260d575b5080548061259a575b506000855491816123648254958c7f5811038d8089f26da5521abe80702dd405dd320106f5e92b954891ea28cea3fe608060018060a01b0398898c54169a8a600254169060405192835260208301528b60408301526060820152a2885461316e565b9788885555556000946000948882116123bf575b8960008051602061442c83398151915260808a8a8a6123b28f60058d60ff92600b820155015460401c166040519485526020850190612b67565b60408301526060820152a2005b9194509194506123d96123d2888461316e565b809361316e565b9055600e8201938454821160001461250e575061241c602084600154168585541690875491600060405180968195829463a9059cbb60e01b845260048401613d99565b03925af190811561044d576000916124ef575b501561040e576124418454809261316e565b9092600082955581612479575b5050906123b260ff6005608096959460008051602061442c833981519152985b985093949596612378565b6124ad91816020926001989796959854169060025416600060405180968195829463a9059cbb60e01b845260048401613d99565b03925af190811561044d576000916124d0575b501561040e57909192868061244e565b6124e9915060203d602011610446576104388183612c1b565b876124c0565b612508915060203d602011610446576104388183612c1b565b8861242f565b819594509060209161253f9397946001541690600060405180968195829463a9059cbb60e01b845260048401613d99565b03925af190811561044d5760009161257b575b501561040e5760008051602061442c833981519152936123b260ff60056080969360009561246e565b612594915060203d602011610446576104388183612c1b565b86612552565b60206125cf9160018060a01b0380600154169060025416600060405180968195829463a9059cbb60e01b845260048401613d99565b03925af190811561044d576000916125ee575b501561040e5788612302565b612607915060203d602011610446576104388183612c1b565b896125e2565b60206126419160018060a01b03806001541690875416600060405180968195829463a9059cbb60e01b845260048401613d99565b03925af190811561044d57600091612660575b501561040e57886122f9565b612679915060203d602011610446576104388183612c1b565b89612654565b506002546001600160a01b0316331461222f565b346104c95760203660031901126104c9576004358015158091036104c9576002546001600160a01b031633036116685760207f0e2fb031ee032dc02d8011dc50b816eb450cf856abd8261680dac74f72165bd29160ff196006541660ff821617600655604051908152a1005b346104c95760203660031901126104c957612718612a49565b600254906001600160a01b039081831633036116685716908115611656576001600160a01b03191681176002557f928a2375aa6302033471f791936c2eb8a3c97170505e7519fb73cd615b805bce600080a2005b346104c95760003660031901126104c9576001546040516001600160a01b039091168152602090f35b346104c95760003660031901126104c9576020600554604051908152f35b346104c95760a03660031901126104c9576004356001600160401b036024358181116104c9576127e79036906004016129ec565b90916044358181116104c957612801903690600401612a19565b91906064358281116104c95761281b9036906004016129ec565b9190926084359081116104c9576128369036906004016129ec565b94909833600052600760205260ff6040600020541680156129d8575b156129c9575087600052600a60205260ff60406000205416156106765760ff600654166104b757876000526009602052604060002060ff600582015460401c1660038110156104a157612979576128ad878960018401612cee565b600281016128ba81612e01565b60005b83811061295b5750509261293a612948938693612915898e7fa79644652b69872a47a010039d682853ffc3293654efde61f74e2d88702e8cf79e9f9a8a61290f896129569f9d93600360049501612cee565b01612cee565b61292c6040519b8c9b60808d5260808d0191612fdc565b918a830360208c0152612ffd565b918783036040890152612fdc565b918483036060860152612fdc565b0390a2005b80611f9861296d612974938789612e82565b9085612ef1565b6128bd565b60405162461bcd60e51b815260206004820152602260248201527f4f6e6c7920616374697665206d61726b6574732063616e206265207570646174604482015261195960f21b6064820152608490fd5b637bfa4b9f60e01b8152600490fd5b506002546001600160a01b03163314612852565b9181601f840112156104c9578235916001600160401b0383116104c957602083818601950101116104c957565b9181601f840112156104c9578235916001600160401b0383116104c9576020808501948460051b0101116104c957565b600435906001600160a01b03821682036104c957565b602435906001600160a01b03821682036104c957565b60609060031901126104c957600435906024356001600160a01b03811681036104c9579060443590565b602435906001600160401b03821682036104c957565b60409060031901126104c9576004359060243590565b919082519283825260005b848110612af7575050826000602080949584010152601f8019910116010190565b602081830181015184830182015201612ad6565b908082519081815260208091019281808460051b8301019501936000915b848310612b395750505050505090565b9091929394958480612b57600193601f198682030187528a51612acb565b9801930193019194939290612b29565b9060038210156104a15752565b60609060031901126104c957600435906024359060443590565b60809060031901126104c95760043590602435906044359060643590565b90815180825260208080930193019160005b828110612bcc575050505090565b835185529381019392810192600101612bbe565b15612be757565b60405162461bcd60e51b815260206004820152600c60248201526b08ccaca40e8dede40d0d2ced60a31b6044820152606490fd5b90601f801991011681019081106001600160401b03821117611f3457604052565b908160209103126104c9575180151581036104c95790565b6001600160a01b03918216815291166020820152604081019190915260600190565b600019811461077c5760010190565b90600182811c92168015612cb5575b6020831014612c9f57565b634e487b7160e01b600052602260045260246000fd5b91607f1691612c94565b919082549060031b91821b91600019901b1916179055565b818110612ce2575050565b60008155600101612cd7565b9092916001600160401b038111611f3457612d098254612c85565b601f8111612db1575b506000601f8211600114612d4d5781929394600092612d42575b50508160011b916000199060031b1c1916179055565b013590503880612d2c565b601f198216948382526020918281209281905b888210612d9957505083600195969710612d7f575b505050811b019055565b0135600019600384901b60f8161c19169055388080612d75565b80600184968294958701358155019501920190612d60565b612dde90836000526020600020601f840160051c81019160208510612de4575b601f0160051c0190612cd7565b38612d12565b9091508190612dd1565b8181029291811591840414171561077c57565b80549060009081815582612e1457505050565b81526020808220928301925b838110612e2d5750505050565b8083612e3b60019354612c85565b80612e49575b505001612e20565b601f8082118514612e6057505081555b8338612e41565b612e7990848452868420920160051c8201858301612cd7565b81835555612e59565b9190811015612ec35760051b81013590601e19813603018212156104c95701908135916001600160401b0383116104c95760200182360381136104c9579190565b634e487b7160e01b600052603260045260246000fd5b8054821015612ec35760005260206000200190600090565b8054919291600160401b811015611f3457612f1191600182018155612ed9565b929092612f2357612f2192612cee565b565b634e487b7160e01b600052600060045260246000fd5b9190820180921161077c57565b9060009291805491612f5783612c85565b918282526001938481169081600014612fb95750600114612f79575b50505050565b90919394506000526020928360002092846000945b838610612fa5575050505001019038808080612f73565b805485870183015294019385908201612f8e565b9294505050602093945060ff191683830152151560051b01019038808080612f73565b908060209392818452848401376000828201840152601f01601f1916010190565b90808352602080930192838260051b810194846000925b858410613025575050505050505090565b9091929394959681810384528735601e19843603018112156104c95783018681019190356001600160401b0381116104c95780360383136104c95761306f88928392600195612fdc565b990194019401929594939190613014565b90815480825260208092019260005281600020916000905b8282106130a6575050505090565b835485529384019360019384019390910190613098565b805460008255806130cc575050565b612f2191600052602060002090810190612cd7565b90600160401b8111611f34578154908083558181106130ff57505050565b612f219260005260206000209182019101612cd7565b6001600160401b038111611f345760051b60200190565b9061313682613115565b6131436040519182612c1b565b8281528092613154601f1991613115565b0190602036910137565b9190811015612ec35760051b0190565b9190820391821161077c57565b8115611d3e570490565b670de0b6b3a7640000916000198383099280830292838086109503948086039514613228578285101561320557908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b8260649260405192630c740aef60e31b8452600484015260248301526044820152fd5b505090613235925061317b565b90565b90670de0b6b3a76400009182811061330b5782810460018060801b03811160071b90811c906001600160401b03821160061b91821c63ffffffff811160051b90811c61ffff811160041b90811c60ff811160031b90811c91600f831160021b92831c936001968760038711811b96871c11961717171717171791848302921c93808514613304576706f05b59d3b2000094855b6132d757509193505050565b808291020494671bc16d674ec800008610156132f7575b821c94856132cb565b8095930192821c946132ee565b5090925050565b6024906040519063036d32ef60e41b82526004820152fd5b9060405191828154918282526020928383019160005283600020936000905b82821061335857505050612f2192500383612c1b565b855484526001958601958895509381019390910190613342565b9190916000838201938412911290801582169115161761077c57565b60026000541461339f576002600055565b604051633ee5aeb560e01b8152600490fd5b8051821015612ec35760209160051b010190565b9094916133d2865161312c565b9360005b87518110156133fd57806133ed6133f8928a6133b1565b5161121c82896133b1565b6133d6565b5093613438826113dd94959861343e9761343161342a64e8d4a510009b61342484896133b1565b51612f39565b91866133b1565b5286613442565b93613442565b0490565b90929192600090815b81518310156134a55761345e83836133b1565b5164e8d4a510009081810291818304149015171561077c5761349f916102746134999261074d610748896134928a8e6133b1565b5193613185565b92612c76565b9161344b565b6132359495506714057b7ef767814f9250670de0b6b3a764000091506134ca90613238565b020490613d03565b680736ea4425c11ac6308111613ceb576714057b7ef767814f90670de0b6b3a7640000918291020490680a688906bd8affffff8211613cd257604091821b81900490600160bf1b60ff60381b8316613be1575b60ff60301b8316613af1575b60ff60281b8316613a01575b64ff000000008316613909575b63ff0000008316613819575b62ff00008316613731575b61ff008316613651575b60ff831661357e575b02911c60bf031c90565b6080831661363f575b83831661362d575b6020831661361b575b60108316613609575b600883166135f7575b600483166135e5575b600283166135d5575b6001831615613574576001600160401b0102831c613574565b6001600160401b0102831c6135bc565b6801000000000000000302831c6135b3565b6801000000000000000602831c6135aa565b6801000000000000000b02831c6135a1565b6801000000000000001602831c613598565b6801000000000000002c02831c61358f565b6801000000000000005902831c613587565b618000831661371f575b614000831661370d575b61200083166136fb575b61100083166136e9575b61080083166136d7575b61040083166136c5575b61020083166136b3575b61010083161561356b57680100000000000000b102831c61356b565b6801000000000000016302831c613697565b680100000000000002c602831c61368d565b6801000000000000058c02831c613683565b68010000000000000b1702831c613679565b6801000000000000162e02831c61366f565b68010000000000002c5d02831c613665565b680100000000000058b902831c61365b565b628000008316613807575b6240000083166137f5575b6220000083166137e3575b6210000083166137d1575b6208000083166137bf575b6204000083166137ad575b62020000831661379b575b62010000831615613561576801000000000000b17202831c613561565b680100000000000162e402831c61377e565b6801000000000002c5c802831c613773565b68010000000000058b9102831c613768565b680100000000000b172102831c61375d565b68010000000000162e4302831c613752565b680100000000002c5c8602831c613747565b6801000000000058b90c02831c61373c565b638000000083166138f7575b634000000083166138e5575b632000000083166138d3575b631000000083166138c1575b630800000083166138af575b6304000000831661389d575b6302000000831661388b575b63010000008316156135565768010000000000b1721802831c613556565b6801000000000162e43002831c61386d565b68010000000002c5c86002831c613861565b680100000000058b90c002831c613855565b6801000000000b17217f02831c613849565b680100000000162e42ff02831c61383d565b6801000000002c5c85fe02831c613831565b68010000000058b90bfc02831c613825565b64800000000083166139ef575b64400000000083166139dd575b64200000000083166139cb575b64100000000083166139b9575b64080000000083166139a7575b6404000000008316613995575b6402000000008316613983575b64010000000083161561354a57680100000000b17217f802831c61354a565b68010000000162e42ff102831c613964565b680100000002c5c85fe302831c613957565b6801000000058b90bfce02831c61394a565b68010000000b17217fbb02831c61393d565b6801000000162e42fff002831c613930565b68010000002c5c8601cc02831c613923565b680100000058b90c0b4902831c613916565b6001602f1b8316613adf575b6001602e1b8316613acd575b6001602d1b8316613abb575b6001602c1b8316613aa9575b6001602b1b8316613a97575b6001602a1b8316613a85575b600160291b8316613a73575b600160281b83161561353d576801000000b17218355102831c61353d565b680100000162e430e5a202831c613a55565b6801000002c5c863b73f02831c613a49565b68010000058b90cf1e6e02831c613a3d565b680100000b1721bcfc9a02831c613a31565b68010000162e43f4f83102831c613a25565b680100002c5c89d5ec6d02831c613a19565b6801000058b91b5bc9ae02831c613a0d565b600160371b8316613bcf575b600160361b8316613bbd575b600160351b8316613bab575b600160341b8316613b99575b600160331b8316613b87575b600160321b8316613b75575b600160311b8316613b63575b600160301b8316156135315768010000b17255775c0402831c613531565b6801000162e525ee054702831c613b45565b68010002c5cc37da949202831c613b39565b680100058ba01fb9f96d02831c613b2d565b6801000b175effdc76ba02831c613b21565b680100162f3904051fa102831c613b15565b6801002c605e2e8cec5002831c613b09565b68010058c86da1c09ea202831c613afd565b6001603f1b8316613cbf575b6001603e1b8316613cad575b6001603d1b8316613c9b575b6001603c1b8316613c89575b6001603b1b8316613c77575b6001603a1b8316613c65575b600160391b8316613c53575b600160381b83161561352557680100b1afa5abcbed6102831c613525565b68010163da9fb33356d802831c613c35565b680102c9a3e778060ee702831c613c29565b6801059b0d31585743ae02831c613c1d565b68010b5586cf9890f62a02831c613c11565b6801172b83c7d517adce02831c613c05565b6801306fe0a31b7152df02831c613bf9565b5068016a09e667f3bcc909607f1b613bed565b60405163b3b6ba1f60e01b815260048101839052602490fd5b60249060405190630d7b1d6560e11b82526004820152fd5b90919060001983820983820291828083109203918083039214613d8857670de0b6b3a76400009081831015613d6a57947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b6044908660405191635173648d60e01b835260048301526024820152fd5b5050670de0b6b3a764000090049150565b6001600160a01b039091168152602081019190915260400190565b909491613dc1865161312c565b9360005b8751811015613de157806133ed613ddc928a6133b1565b613dc5565b5093613438826111f094959861343e9761343161342a64e8d4a510009b613e0884896133b1565b5161316e565b90600091808352602092600984526040938482209160058301805460ff81891c16600381101561415057600114613fb1575054861c60ff166003811015613f9d57600214613e67578551639f4a648960e01b8152600490fd5b8381969394959652600c82528281203382528252828120549381851315613f8c576011810185815410613f7b5790601491878452600c855285842033855285528386812055613eb787825461316e565b905501613ec5858254612f39565b9055600154835163a9059cbb60e01b815290839082906001600160a01b0316818581613ef58b3360048401613d99565b03925af1918215613f705791613f53575b5015613f425760019082519586528501528301527f09289ec34f62d6f895af933338b7a7edcc6fdb552e8f76337f33e6ccaaf1843b60603393a3565b81516312171d8360e31b8152600490fd5b613f6a9150823d8411610446576104388183612c1b565b38613f06565b8451903d90823e3d90fd5b8451633a23d82560e01b8152600490fd5b83516330a748d360e11b8152600490fd5b634e487b7160e01b82526021600452602482fd5b6001600160401b039150604897949596979392931c16860361413f57848252600b81528282203383528152828220868352815282822054938415613f8c57600b81018581541061412e57868452600b8352848420338552835284842088855283528385812055600982016140258982612ed9565b90549060031b1c87811061411d57601193929161143a8b6114348b6140499561316e565b61405487825461316e565b9055018054858110613f7b578561406a9161316e565b9055600154835163a9059cbb60e01b815290829082906001600160a01b031681868161409a8b3360048401613d99565b03925af19081156141135783916140f6575b50156140e55782519586528501528301527f09289ec34f62d6f895af933338b7a7edcc6fdb552e8f76337f33e6ccaaf1843b60603393a3565b82516312171d8360e31b8152600490fd5b61410d9150823d8411610446576104388183612c1b565b386140ac565b84513d85823e3d90fd5b8651633a9a6bf560e11b8152600490fd5b8451636e21e8cb60e01b8152600490fd5b8251630e5b822760e11b8152600490fd5b634e487b7160e01b84526021600452602484fd5b90815461417081613115565b9260409361418085519182612c1b565b828152809460208092019260005281600020906000935b8585106141a657505050505050565b600184819284516141c2816141bb818a612f46565b0382612c1b565b815201930194019391614197565b60009081526009602052604081209260ff600585015460401c1692600393848110156141505761048f576007850154908181101561047d57821561046b57614233606461421e875486612dee565b04936111f060049560646111e9885485612dee565b91821561439c576142438161312c565b9560088801865b8381106143795750505050839560019583871b848104600203614366579695949392919086600a60068401549301975b614312575b888a106142925750505050505050505090565b9091929394959697986142a58a82612f39565b8281018091116142ff57821c90866142c883886142c18e613323565b888a6133c5565b116142dd5750985b979695949392919061427f565b99506000198101908111156142d057634e487b7160e01b885260118752602488fd5b634e487b7160e01b895260118852602489fd5b90919293949596978561433082876143298d613323565b87896133c5565b10156142d057811b8169d3c21bcecceda100000082116143585790989796959493929161427a565b50979695949392919061427f565b634e487b7160e01b875260118652602487fd5b806143876143979284612ed9565b905490851b1c61121c828c6133b1565b61424a565b5050505091505090565b90600090828252600960205260056040832001549060ff8260401c16600381101561415057600114801590614416575b61440f576040938352600b6020528383209060018060a01b031683526020526001600160401b038383209160481c168252602052205490565b5050905090565b506001600160401b03808360481c16146143d656fed26a37ea32f0be10c131818ca4c38930b6917f34fd57e18abf0cd21dd418c88da2646970667358221220670a0012d434857466b49ddbfd0ed4005bbdca03b81b9cf7960747a7f8d7f6eb64736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda02913
-----Decoded View---------------
Arg [0] : _usdc (address): 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda02913
Loading...
Loading
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| BASE | 100.00% | $0.999702 | 55,385.4749 | $55,368.97 |
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.