Overview
S Balance
S Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Initialize | 4060061 | 69 days ago | IN | 0 S | 0.00696613 |
Loading...
Loading
Contract Name:
OffchainExchange
Compiler Version
v0.8.13+commit.abaa5c0e
Optimization Enabled:
Yes with 800 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts-upgradeable/utils/cryptography/draft-EIP712Upgradeable.sol"; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import "./interfaces/engine/IProductEngine.sol"; import "./libraries/MathSD21x18.sol"; import "./common/Constants.sol"; import "./libraries/MathHelper.sol"; import "./libraries/RiskHelper.sol"; import "./libraries/Logger.sol"; import "./interfaces/IOffchainExchange.sol"; import "./EndpointGated.sol"; import "./common/Errors.sol"; import "./interfaces/engine/ISpotEngine.sol"; import "./interfaces/engine/IPerpEngine.sol"; contract OffchainExchange is IOffchainExchange, EndpointGated, EIP712Upgradeable { using MathSD21x18 for int128; IClearinghouse internal clearinghouse; mapping(uint32 => MarketInfoStore) internal marketInfo; mapping(uint32 => address) internal virtualBookContract; mapping(uint32 => LpParams) internal lpParams; mapping(bytes32 => int128) public filledAmounts; ISpotEngine internal spotEngine; IPerpEngine internal perpEngine; mapping(address => mapping(uint32 => FeeRates)) internal feeRates; mapping(address => bool) internal addressTouched; address[] internal customFeeAddresses; mapping(uint32 => uint32) internal quoteIds; // adding following two useless mappings to not break storage layout by FOffchainExchange. mapping(uint32 => int128) internal uselessMapping1; mapping(uint32 => int128) internal uselessMapping2; // address -> mask (if the i-th bit is 1, it means the i-th iso subacc is being used) mapping(address => uint256) internal isolatedSubaccountsMask; // isolated subaccount -> subaccount mapping(bytes32 => bytes32) internal parentSubaccounts; // (subaccount, id) -> isolated subaccount mapping(bytes32 => mapping(uint256 => bytes32)) internal isolatedSubaccounts; // which isolated subaccount does an isolated order create mapping(bytes32 => bytes32) internal digestToSubaccount; // how much margin does an isolated order require mapping(bytes32 => int128) internal digestToMargin; function getAllFeeRates(address[] memory users, uint32[] memory productIds) external view returns (FeeRates[] memory) { FeeRates[] memory rates = new FeeRates[]( users.length * productIds.length ); for (uint256 i = 0; i < users.length; i++) { for (uint256 j = 0; j < productIds.length; j++) { rates[i * productIds.length + j] = feeRates[users[i]][ productIds[j] ]; } } return rates; } function getCustomFeeAddresses(uint32 startAt, uint32 limit) external view returns (address[] memory) { uint32 endAt = startAt + limit; uint32 total = uint32(customFeeAddresses.length); if (endAt > total) { endAt = total; } if (startAt > total) { startAt = total; } address[] memory addresses = new address[](endAt - startAt); for (uint32 i = startAt; i < endAt; i++) { addresses[i - startAt] = customFeeAddresses[i]; } return addresses; } // copied from EIP712Upgradeable bytes32 private constant _TYPE_HASH = keccak256( "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" ); function getMarketInfo(uint32 productId) public view returns (MarketInfo memory m) { MarketInfoStore memory market = marketInfo[productId]; m.quoteId = quoteIds[productId]; m.collectedFees = market.collectedFees; m.minSize = int128(market.minSize) * 1e9; m.sizeIncrement = int128(market.sizeIncrement) * 1e9; return m; } struct CallState { IPerpEngine perp; ISpotEngine spot; bool isPerp; uint32 productId; } function _getCallState(uint32 productId) internal view returns (CallState memory) { address engineAddr = clearinghouse.getEngineByProduct(productId); IPerpEngine perp = perpEngine; // don't read the spot engine from storage if its a perp engine if (engineAddr == address(perp)) { return CallState({ perp: IPerpEngine(engineAddr), spot: ISpotEngine(address(0)), isPerp: true, productId: productId }); } else { return CallState({ perp: IPerpEngine(address(0)), spot: spotEngine, isPerp: false, productId: productId }); } } function tryCloseIsolatedSubaccount(bytes32 subaccount) external virtual { require(msg.sender == address(clearinghouse), ERR_UNAUTHORIZED); _tryCloseIsolatedSubaccount(subaccount); } function _tryCloseIsolatedSubaccount(bytes32 subaccount) internal { uint32 productId = RiskHelper.getIsolatedProductId(subaccount); if (productId == 0) { return; } IPerpEngine.Balance memory balance = perpEngine.getBalance( productId, subaccount ); if (balance.amount == 0) { uint8 id = RiskHelper.getIsolatedId(subaccount); address addr = address(uint160(bytes20(subaccount))); bytes32 parent = parentSubaccounts[subaccount]; if (balance.vQuoteBalance != 0) { perpEngine.updateBalance( productId, subaccount, 0, -balance.vQuoteBalance ); perpEngine.updateBalance( productId, parent, 0, balance.vQuoteBalance ); } int128 quoteBalance = spotEngine .getBalance(QUOTE_PRODUCT_ID, subaccount) .amount; if (quoteBalance != 0) { spotEngine.updateBalance( QUOTE_PRODUCT_ID, subaccount, -quoteBalance ); spotEngine.updateBalance( QUOTE_PRODUCT_ID, parent, quoteBalance ); } isolatedSubaccountsMask[addr] &= ~uint256(0) ^ (1 << id); isolatedSubaccounts[parent][id] = bytes32(0); parentSubaccounts[subaccount] = bytes32(0); emit CloseIsolatedSubaccount(subaccount, parent); } } function _updateBalances( CallState memory callState, uint32 quoteId, bytes32 subaccount, int128 baseDelta, int128 quoteDelta ) internal { if (callState.isPerp) { callState.perp.updateBalance( callState.productId, subaccount, baseDelta, quoteDelta ); } else { if (quoteId == QUOTE_PRODUCT_ID) { callState.spot.updateBalance( callState.productId, subaccount, baseDelta, quoteDelta ); } else { callState.spot.updateBalance( callState.productId, subaccount, baseDelta ); callState.spot.updateBalance(quoteId, subaccount, quoteDelta); } } } function initialize(address _clearinghouse, address _endpoint) external initializer { __Ownable_init(); setEndpoint(_endpoint); __EIP712_init("Vertex", "0.0.1"); clearinghouse = IClearinghouse(_clearinghouse); spotEngine = ISpotEngine( clearinghouse.getEngineByType(IProductEngine.EngineType.SPOT) ); perpEngine = IPerpEngine( clearinghouse.getEngineByType(IProductEngine.EngineType.PERP) ); } function requireEngine() internal virtual { require( msg.sender == address(spotEngine) || msg.sender == address(perpEngine), "only engine can modify config" ); } function updateMarket( uint32 productId, uint32 quoteId, address virtualBook, int128 sizeIncrement, int128 minSize, int128 lpSpreadX18 ) external { requireEngine(); if (virtualBook != address(0)) { require( virtualBookContract[productId] == address(0), "virtual book already set" ); virtualBookContract[productId] = virtualBook; } if (quoteId != type(uint32).max) { quoteIds[productId] = quoteId; } marketInfo[productId].minSize = int64(minSize / 1e9); marketInfo[productId].sizeIncrement = int64(sizeIncrement / 1e9); lpParams[productId] = LpParams(lpSpreadX18); } function getLpParams(uint32 productId) external view returns (LpParams memory) { return lpParams[productId]; } function getSizeIncrement(uint32 productId) external view returns (int128) { return int128(marketInfo[productId].sizeIncrement) * 1e9; } function getMinSize(uint32 productId) external view returns (int128) { return int128(marketInfo[productId].minSize) * 1e9; } function getDigest(uint32 productId, IEndpoint.Order memory order) public view returns (bytes32) { string memory structType = "Order(bytes32 sender,int128 priceX18,int128 amount,uint64 expiration,uint64 nonce)"; bytes32 structHash = keccak256( abi.encode( keccak256(bytes(structType)), order.sender, order.priceX18, order.amount, order.expiration, order.nonce ) ); bytes32 domainSeparator = keccak256( abi.encode( _TYPE_HASH, _EIP712NameHash(), _EIP712VersionHash(), block.chainid, address(virtualBookContract[productId]) ) ); return ECDSAUpgradeable.toTypedDataHash(domainSeparator, structHash); } function _isPerp(IPerpEngine engine, uint32 productId) internal view returns (bool) { return clearinghouse.getEngineByProduct(productId) == address(engine); } function _checkSignature( bytes32 subaccount, bytes32 digest, address linkedSigner, bytes memory signature ) internal view virtual returns (bool) { address signer = ECDSA.recover(digest, signature); return (signer != address(0)) && (subaccount == FEES_ACCOUNT || signer == address(uint160(bytes20(subaccount))) || signer == linkedSigner); } function _expired(uint64 expiration) internal view returns (bool) { return expiration & ((1 << 58) - 1) <= getOracleTime(); } function _isReduceOnly(uint64 expiration) internal pure returns (bool) { return ((expiration >> 61) & 1) == 1; } function _validateOrder( CallState memory callState, MarketInfo memory, IEndpoint.SignedOrder memory signedOrder, bytes32 orderDigest, address /* linkedSigner */ ) internal view returns (bool) { if (signedOrder.order.sender == X_ACCOUNT) { return true; } IEndpoint.Order memory order = signedOrder.order; uint32 isolatedProductId = RiskHelper.getIsolatedProductId( order.sender ); if (isolatedProductId != 0) { require(callState.productId == isolatedProductId, ERR_UNAUTHORIZED); } int128 filledAmount = filledAmounts[orderDigest]; order.amount -= filledAmount; if (_isReduceOnly(order.expiration)) { int128 amount = callState.isPerp ? callState .perp .getBalance(callState.productId, order.sender) .amount : callState .spot .getBalance(callState.productId, order.sender) .amount; if ((order.amount > 0) == (amount > 0)) { order.amount = 0; } else if (order.amount > 0) { order.amount = MathHelper.min(order.amount, -amount); } else if (order.amount < 0) { order.amount = MathHelper.max(order.amount, -amount); } } return (order.priceX18 > 0) && // _checkSignature( // order.sender, // orderDigest, // linkedSigner, // signedOrder.signature // ) && // valid amount (order.amount != 0) && !_expired(order.expiration); } function _feeAmount( uint32 productId, bytes32 subaccount, MarketInfo memory market, int128 matchBase, int128 matchQuote, int128 alreadyMatched, int128 orderPriceX18, bool taker ) internal view returns (int128, int128) { // X account is passthrough for trading and incurs // no fees if (subaccount == X_ACCOUNT) { return (0, matchQuote); } int128 meteredQuote = 0; if (taker) { // flat minimum fee if (alreadyMatched == 0) { meteredQuote += market.minSize.mul(orderPriceX18); if (matchQuote < 0) { meteredQuote = -meteredQuote; } } // exclude the portion on [0, self.min_size) for match_quote and // add to metered_quote int128 matchBaseAbs = matchBase.abs(); // fee is only applied on [minSize, amount) int128 feeApplied = MathHelper.abs(alreadyMatched + matchBase) - market.minSize; feeApplied = MathHelper.min(feeApplied, matchBaseAbs); if (feeApplied > 0) { meteredQuote += matchQuote.mulDiv(feeApplied, matchBaseAbs); } } else { // for maker rebates things stay the same meteredQuote += matchQuote; } int128 keepRateX18 = ONE - getFeeFractionX18(subaccount, productId, taker); int128 newMeteredQuote = (meteredQuote > 0) ? meteredQuote.mul(keepRateX18) : meteredQuote.div(keepRateX18); int128 fee = meteredQuote - newMeteredQuote; market.collectedFees += fee; return (fee, matchQuote - fee); } function feeAmount( uint32 productId, bytes32 subaccount, MarketInfo memory market, int128 matchBase, int128 matchQuote, int128 alreadyMatched, int128 orderPriceX18, bool taker ) internal virtual returns (int128, int128) { return _feeAmount( productId, subaccount, market, matchBase, matchQuote, alreadyMatched, orderPriceX18, taker ); } struct OrdersInfo { bytes32 takerDigest; bytes32 makerDigest; int128 makerAmount; } function _matchOrderAMM( CallState memory callState, int128 baseDelta, // change in the LP's base position int128 quoteDelta, // change in the LP's quote position IEndpoint.SignedOrder memory taker ) internal returns (int128, int128) { // 1. assert that the price is better than the limit price int128 impliedPriceX18 = quoteDelta.div(baseDelta).abs(); if (taker.order.amount > 0) { // if buying, the implied price must be lower than the limit price require( impliedPriceX18 <= taker.order.priceX18, ERR_ORDERS_CANNOT_BE_MATCHED ); // AMM must be selling // magnitude of what AMM is selling must be less than or equal to what the taker is buying require( baseDelta < 0 && taker.order.amount >= -baseDelta, ERR_ORDERS_CANNOT_BE_MATCHED ); } else { // if selling, the implied price must be higher than the limit price require( impliedPriceX18 >= taker.order.priceX18, ERR_ORDERS_CANNOT_BE_MATCHED ); // AMM must be buying // magnitude of what AMM is buying must be less than or equal to what the taker is selling require( baseDelta > 0 && taker.order.amount <= -baseDelta, ERR_ORDERS_CANNOT_BE_MATCHED ); } IProductEngine engine = callState.isPerp ? IProductEngine(callState.perp) : IProductEngine(callState.spot); (int128 baseSwapped, int128 quoteSwapped) = engine.swapLp( callState.productId, baseDelta, quoteDelta ); taker.order.amount += baseSwapped; return (-baseSwapped, -quoteSwapped); } function _matchOrderOrder( CallState memory callState, MarketInfo memory market, IEndpoint.Order memory taker, IEndpoint.Order memory maker, OrdersInfo memory ordersInfo ) internal returns (int128 takerAmountDelta, int128 takerQuoteDelta) { // execution happens at the maker's price if (taker.amount < 0) { takerAmountDelta = MathHelper.max(taker.amount, -maker.amount); } else if (taker.amount > 0) { takerAmountDelta = MathHelper.min(taker.amount, -maker.amount); } else { return (0, 0); } takerAmountDelta -= takerAmountDelta % market.sizeIncrement; int128 makerQuoteDelta = takerAmountDelta.mul(maker.priceX18); takerQuoteDelta = -makerQuoteDelta; // apply the maker fee int128 makerFee; (makerFee, makerQuoteDelta) = feeAmount( callState.productId, maker.sender, market, -takerAmountDelta, makerQuoteDelta, 0, // alreadyMatched doesn't matter for a maker order 0, // price doesn't matter for a maker order false ); taker.amount -= takerAmountDelta; maker.amount += takerAmountDelta; _updateBalances( callState, market.quoteId, maker.sender, -takerAmountDelta, makerQuoteDelta ); emit FillOrder( callState.productId, ordersInfo.makerDigest, maker.sender, maker.priceX18, ordersInfo.makerAmount, maker.expiration, maker.nonce, false, makerFee, -takerAmountDelta, makerQuoteDelta ); } function matchOrderAMM( IEndpoint.MatchOrderAMM calldata txn, address takerLinkedSigner ) external onlyEndpoint { CallState memory callState = _getCallState(txn.productId); MarketInfo memory market = getMarketInfo(txn.productId); bytes32 takerDigest = getDigest(txn.productId, txn.taker.order); int128 takerAmount = txn.taker.order.amount; // need to convert the taker order from calldata into memory // otherwise modifications we make to the order's amounts // don't persist IEndpoint.SignedOrder memory taker = txn.taker; require( !RiskHelper.isIsolatedSubaccount(taker.order.sender), ERR_UNAUTHORIZED ); require( _validateOrder( callState, market, taker, takerDigest, takerLinkedSigner ), ERR_INVALID_TAKER ); (int128 takerAmountDelta, int128 takerQuoteDelta) = _matchOrderAMM( callState, txn.baseDelta, txn.quoteDelta, taker ); // apply the taker fee int128 takerFee; (takerFee, takerQuoteDelta) = feeAmount( txn.productId, taker.order.sender, market, takerAmountDelta, takerQuoteDelta, takerAmount - taker.order.amount - takerAmountDelta, -takerQuoteDelta.div(takerAmountDelta), true ); _updateBalances( callState, market.quoteId, taker.order.sender, takerAmountDelta, takerQuoteDelta ); require(isHealthy(taker.order.sender), ERR_INVALID_TAKER); emit FillOrder( txn.productId, takerDigest, taker.order.sender, taker.order.priceX18, takerAmount, taker.order.expiration, taker.order.nonce, true, takerFee, takerAmountDelta, takerQuoteDelta ); marketInfo[txn.productId].collectedFees = market.collectedFees; filledAmounts[takerDigest] = takerAmount - taker.order.amount; } function isHealthy( bytes32 /* subaccount */ ) internal view virtual returns (bool) { return true; } function matchOrders(IEndpoint.MatchOrdersWithSigner calldata txn) external onlyEndpoint { CallState memory callState = _getCallState(txn.matchOrders.productId); int128 takerAmount; int128 takerFee; int128 takerAmountDelta; int128 takerQuoteDelta; OrdersInfo memory ordersInfo; MarketInfo memory market = getMarketInfo(callState.productId); IEndpoint.SignedOrder memory taker = txn.matchOrders.taker; IEndpoint.SignedOrder memory maker = txn.matchOrders.maker; ordersInfo = OrdersInfo({ takerDigest: getDigest(callState.productId, taker.order), makerDigest: getDigest(callState.productId, maker.order), makerAmount: maker.order.amount }); if (digestToSubaccount[ordersInfo.takerDigest] != bytes32(0)) { taker.order.sender = digestToSubaccount[ordersInfo.takerDigest]; } if (digestToSubaccount[ordersInfo.makerDigest] != bytes32(0)) { maker.order.sender = digestToSubaccount[ordersInfo.makerDigest]; } takerAmount = taker.order.amount; require( _validateOrder( callState, market, taker, ordersInfo.takerDigest, txn.takerLinkedSigner ), ERR_INVALID_TAKER ); require( _validateOrder( callState, market, maker, ordersInfo.makerDigest, txn.makerLinkedSigner ), ERR_INVALID_MAKER ); // ensure orders are crossing require( (maker.order.amount > 0) != (taker.order.amount > 0), ERR_ORDERS_CANNOT_BE_MATCHED ); if (maker.order.amount > 0) { require( maker.order.priceX18 >= taker.order.priceX18, ERR_ORDERS_CANNOT_BE_MATCHED ); } else { require( maker.order.priceX18 <= taker.order.priceX18, ERR_ORDERS_CANNOT_BE_MATCHED ); } (takerAmountDelta, takerQuoteDelta) = _matchOrderOrder( callState, market, taker.order, maker.order, ordersInfo ); // apply the taker fee (takerFee, takerQuoteDelta) = feeAmount( callState.productId, taker.order.sender, market, takerAmountDelta, takerQuoteDelta, takerAmount - taker.order.amount - takerAmountDelta, maker.order.priceX18, true ); _updateBalances( callState, market.quoteId, taker.order.sender, takerAmountDelta, takerQuoteDelta ); require(isHealthy(taker.order.sender), ERR_INVALID_TAKER); require(isHealthy(maker.order.sender), ERR_INVALID_MAKER); marketInfo[callState.productId].collectedFees = market.collectedFees; if (taker.order.sender != X_ACCOUNT) { filledAmounts[ordersInfo.takerDigest] = takerAmount - taker.order.amount; } if (maker.order.sender != X_ACCOUNT) { filledAmounts[ordersInfo.makerDigest] = ordersInfo.makerAmount - maker.order.amount; } _tryCloseIsolatedSubaccount(taker.order.sender); _tryCloseIsolatedSubaccount(maker.order.sender); emit FillOrder( callState.productId, ordersInfo.takerDigest, taker.order.sender, taker.order.priceX18, takerAmount, taker.order.expiration, taker.order.nonce, true, takerFee, takerAmountDelta, takerQuoteDelta ); } function swapAMM(IEndpoint.SwapAMM calldata txn) external onlyEndpoint { require(!RiskHelper.isIsolatedSubaccount(txn.sender), ERR_UNAUTHORIZED); MarketInfo memory market = getMarketInfo(txn.productId); CallState memory callState = _getCallState(txn.productId); require(txn.priceX18 > 0, ERR_INVALID_PRICE); if (callState.isPerp) { require( txn.amount % market.sizeIncrement == 0, ERR_INVALID_SWAP_PARAMS ); } IProductEngine engine = callState.isPerp ? IProductEngine(callState.perp) : IProductEngine(callState.spot); (int128 takerAmountDelta, int128 takerQuoteDelta) = engine.swapLp( txn.productId, txn.amount, -txn.amount.mul(txn.priceX18) ); takerAmountDelta = -takerAmountDelta; takerQuoteDelta = -takerQuoteDelta; int128 takerFee; (takerFee, takerQuoteDelta) = feeAmount( txn.productId, txn.sender, market, takerAmountDelta, takerQuoteDelta, (takerAmountDelta > 0) ? market.minSize : -market.minSize, // just charge the protocol fee without any flat stuff 0, true ); _updateBalances( callState, market.quoteId, txn.sender, takerAmountDelta, takerQuoteDelta ); require( clearinghouse.getHealth( txn.sender, IProductEngine.HealthType.INITIAL ) >= 0, ERR_INVALID_TAKER ); marketInfo[txn.productId].collectedFees = market.collectedFees; } function dumpFees() external onlyEndpoint { // loop over all spot and perp product ids uint32[] memory productIds = spotEngine.getProductIds(); for (uint32 i = 1; i < productIds.length; i++) { uint32 productId = productIds[i]; MarketInfoStore memory market = marketInfo[productId]; // its possible for fees to be <= 0 if there is a cross-chain trade // and the maker rebate is exclusively coming from one chain if (market.collectedFees <= 0) { continue; } spotEngine.updateBalance( quoteIds[productId], FEES_ACCOUNT, market.collectedFees ); market.collectedFees = 0; marketInfo[productId] = market; } productIds = perpEngine.getProductIds(); for (uint32 i = 0; i < productIds.length; i++) { uint32 productId = productIds[i]; MarketInfoStore memory market = marketInfo[productId]; if (market.collectedFees == 0) { continue; } perpEngine.updateBalance( productId, FEES_ACCOUNT, 0, market.collectedFees ); market.collectedFees = 0; marketInfo[productId] = market; } } function getFeeFractionX18( bytes32 subaccount, uint32 productId, bool taker ) public view returns (int128) { FeeRates memory userFeeRates = feeRates[ address(uint160(bytes20(subaccount))) ][productId]; if (userFeeRates.isNonDefault == 0) { // use the default fee rates. userFeeRates = FeeRates(0, 200_000_000_000_000, 1); } return taker ? userFeeRates.takerRateX18 : userFeeRates.makerRateX18; } function getFeeRatesX18(bytes32 subaccount, uint32 productId) public view returns (int128, int128) { FeeRates memory userFeeRates = feeRates[ address(uint160(bytes20(subaccount))) ][productId]; if (userFeeRates.isNonDefault == 0) { // use the default fee rates. userFeeRates = FeeRates(0, 200_000_000_000_000, 1); } return (userFeeRates.takerRateX18, userFeeRates.makerRateX18); } function updateFeeRates( address user, uint32 productId, int64 makerRateX18, int64 takerRateX18 ) external onlyEndpoint { if (!addressTouched[user]) { addressTouched[user] = true; customFeeAddresses.push(user); } if (productId == QUOTE_PRODUCT_ID) { uint32[] memory spotProductIds = spotEngine.getProductIds(); uint32[] memory perpProductIds = perpEngine.getProductIds(); for (uint32 i = 0; i < spotProductIds.length; i++) { if (spotProductIds[i] == QUOTE_PRODUCT_ID) { continue; } feeRates[user][spotProductIds[i]] = FeeRates( makerRateX18, takerRateX18, 1 ); } for (uint32 i = 0; i < perpProductIds.length; i++) { feeRates[user][perpProductIds[i]] = FeeRates( makerRateX18, takerRateX18, 1 ); } } else { feeRates[user][productId] = FeeRates(makerRateX18, takerRateX18, 1); } } function getVirtualBook(uint32 productId) external view returns (address) { return virtualBookContract[productId]; } function getAllVirtualBooks() external view returns (address[] memory) { uint32[] memory spotProductIds = spotEngine.getProductIds(); uint32[] memory perpProductIds = perpEngine.getProductIds(); uint32 maxProductId = 0; for (uint32 i = 0; i < spotProductIds.length; i++) { if (spotProductIds[i] > maxProductId) { maxProductId = spotProductIds[i]; } } for (uint32 i = 0; i < perpProductIds.length; i++) { if (perpProductIds[i] > maxProductId) { maxProductId = perpProductIds[i]; } } address[] memory virtualBooks = new address[](maxProductId + 1); for (uint32 i = 0; i <= maxProductId; i++) { virtualBooks[i] = virtualBookContract[i]; } return virtualBooks; } function getIsolatedDigest( uint32 productId, IEndpoint.IsolatedOrder memory order ) public view returns (bytes32) { string memory structType = "IsolatedOrder(bytes32 sender,int128 priceX18,int128 amount,uint64 expiration,uint64 nonce,int128 margin)"; bytes32 structHash = keccak256( abi.encode( keccak256(bytes(structType)), order.sender, order.priceX18, order.amount, order.expiration, order.nonce, order.margin ) ); bytes32 domainSeparator = keccak256( abi.encode( _TYPE_HASH, _EIP712NameHash(), _EIP712VersionHash(), block.chainid, address(virtualBookContract[productId]) ) ); return ECDSAUpgradeable.toTypedDataHash(domainSeparator, structHash); } function createIsolatedSubaccount( IEndpoint.CreateIsolatedSubaccount memory txn, address linkedSigner ) external onlyEndpoint returns (bytes32) { require( !RiskHelper.isIsolatedSubaccount(txn.order.sender), ERR_UNAUTHORIZED ); bytes32 isolatedDigest = getIsolatedDigest(txn.productId, txn.order); require( _checkSignature( txn.order.sender, isolatedDigest, linkedSigner, txn.signature ), ERR_INVALID_SIGNATURE ); address senderAddress = address(uint160(bytes20(txn.order.sender))); uint256 mask = isolatedSubaccountsMask[senderAddress]; bytes32 newIsolatedSubaccount = bytes32(0); for (uint256 id = 0; (1 << id) <= mask; id += 1) { if (mask & (1 << id) != 0) { bytes32 subaccount = isolatedSubaccounts[txn.order.sender][id]; if (subaccount != bytes32(0)) { uint32 productId = RiskHelper.getIsolatedProductId( subaccount ); if (productId == txn.productId) { newIsolatedSubaccount = subaccount; break; } } } } if (newIsolatedSubaccount == bytes32(0)) { require( mask != (1 << MAX_ISOLATED_SUBACCOUNTS_PER_ADDRESS) - 1, "Too many isolated subaccounts" ); uint8 id = 0; while (mask & 1 != 0) { mask >>= 1; id += 1; } // | address | reserved | productId | id | 'iso' | // | 20 bytes | 6 bytes | 2 bytes | 1 byte | 3 bytes | newIsolatedSubaccount = bytes32( (uint256(uint160(senderAddress)) << 96) | (uint256(txn.productId) << 32) | (uint256(id) << 24) | 6910831 ); isolatedSubaccountsMask[senderAddress] |= 1 << id; parentSubaccounts[newIsolatedSubaccount] = txn.order.sender; isolatedSubaccounts[txn.order.sender][id] = newIsolatedSubaccount; } bytes32 digest = getDigest( txn.productId, IEndpoint.Order({ sender: txn.order.sender, priceX18: txn.order.priceX18, amount: txn.order.amount, expiration: txn.order.expiration, nonce: txn.order.nonce }) ); digestToSubaccount[digest] = newIsolatedSubaccount; if (txn.order.margin > 0) { digestToMargin[digest] = txn.order.margin; spotEngine.updateBalance( QUOTE_PRODUCT_ID, txn.order.sender, -txn.order.margin ); spotEngine.updateBalance( QUOTE_PRODUCT_ID, newIsolatedSubaccount, txn.order.margin ); } return newIsolatedSubaccount; } function getIsolatedSubaccounts(bytes32 subaccount) external view returns (bytes32[] memory) { uint256 nIsolatedSubaccounts = 0; for (uint256 id = 0; id < MAX_ISOLATED_SUBACCOUNTS_PER_ADDRESS; id++) { bytes32 isolatedSubaccount = isolatedSubaccounts[subaccount][id]; if (isolatedSubaccount != bytes32(0)) { nIsolatedSubaccounts += 1; } } bytes32[] memory isolatedsubaccountsResponse = new bytes32[]( nIsolatedSubaccounts ); for (uint256 id = 0; id < MAX_ISOLATED_SUBACCOUNTS_PER_ADDRESS; id++) { bytes32 isolatedSubaccount = isolatedSubaccounts[subaccount][id]; if (isolatedSubaccount != bytes32(0)) { isolatedsubaccountsResponse[ --nIsolatedSubaccounts ] = isolatedSubaccount; } } return isolatedsubaccountsResponse; } function isIsolatedSubaccountActive(bytes32 parent, bytes32 subaccount) external view returns (bool) { for (uint256 id = 0; id < MAX_ISOLATED_SUBACCOUNTS_PER_ADDRESS; id++) { if (subaccount == isolatedSubaccounts[parent][id]) { return true; } } return false; } function getParentSubaccount(bytes32 subaccount) external view returns (bytes32) { return parentSubaccounts[subaccount]; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal onlyInitializing { __Ownable_init_unchained(); } function __Ownable_init_unchained() internal onlyInitializing { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0-rc.2) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ``` * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: setting the version to 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized < type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Internal function that returns the initialized version. Returns `_initialized` */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Internal function that returns the initialized version. Returns `_initializing` */ function _isInitializing() internal view returns (bool) { return _initializing; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0-rc.2) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0-rc.2) (utils/cryptography/draft-EIP712.sol) pragma solidity ^0.8.0; // EIP-712 is Final as of 2022-08-11. This file is deprecated. import "./EIP712Upgradeable.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0-rc.2) (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.0; import "../StringsUpgradeable.sol"; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSAUpgradeable { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS, InvalidSignatureV // Deprecated in v4.8 } function _throwError(RecoverError error) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert("ECDSA: invalid signature"); } else if (error == RecoverError.InvalidSignatureLength) { revert("ECDSA: invalid signature length"); } else if (error == RecoverError.InvalidSignatureS) { revert("ECDSA: invalid signature 's' value"); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature` or error string. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. /// @solidity memory-safe-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else { return (address(0), RecoverError.InvalidSignatureLength); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, signature); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] * * _Available since v4.3._ */ function tryRecover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address, RecoverError) { bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); uint8 v = uint8((uint256(vs) >> 255) + 27); return tryRecover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. * * _Available since v4.2._ */ function recover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, r, vs); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. * * _Available since v4.3._ */ function tryRecover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address, RecoverError) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature); } return (signer, RecoverError.NoError); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, v, r, s); _throwError(error); return recovered; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { // 32 is the length in bytes of hash, // enforced by the type signature above return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); } /** * @dev Returns an Ethereum Signed Message, created from `s`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", StringsUpgradeable.toString(s.length), s)); } /** * @dev Returns an Ethereum Signed Typed Data, created from a * `domainSeparator` and a `structHash`. This produces hash corresponding * to the one signed with the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] * JSON-RPC method as part of EIP-712. * * See {recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0-rc.2) (utils/cryptography/EIP712.sol) pragma solidity ^0.8.0; import "./ECDSAUpgradeable.sol"; import "../../proxy/utils/Initializable.sol"; /** * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data. * * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible, * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding * they need in their contracts using a combination of `abi.encode` and `keccak256`. * * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA * ({_hashTypedDataV4}). * * The implementation of the domain separator was designed to be as efficient as possible while still properly updating * the chain id to protect against replay attacks on an eventual fork of the chain. * * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask]. * * _Available since v3.4._ * * @custom:storage-size 52 */ abstract contract EIP712Upgradeable is Initializable { /* solhint-disable var-name-mixedcase */ bytes32 private _HASHED_NAME; bytes32 private _HASHED_VERSION; bytes32 private constant _TYPE_HASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); /* solhint-enable var-name-mixedcase */ /** * @dev Initializes the domain separator and parameter caches. * * The meaning of `name` and `version` is specified in * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]: * * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol. * - `version`: the current major version of the signing domain. * * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart * contract upgrade]. */ function __EIP712_init(string memory name, string memory version) internal onlyInitializing { __EIP712_init_unchained(name, version); } function __EIP712_init_unchained(string memory name, string memory version) internal onlyInitializing { bytes32 hashedName = keccak256(bytes(name)); bytes32 hashedVersion = keccak256(bytes(version)); _HASHED_NAME = hashedName; _HASHED_VERSION = hashedVersion; } /** * @dev Returns the domain separator for the current chain. */ function _domainSeparatorV4() internal view returns (bytes32) { return _buildDomainSeparator(_TYPE_HASH, _EIP712NameHash(), _EIP712VersionHash()); } function _buildDomainSeparator( bytes32 typeHash, bytes32 nameHash, bytes32 versionHash ) private view returns (bytes32) { return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this))); } /** * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this * function returns the hash of the fully encoded EIP712 message for this domain. * * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: * * ```solidity * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( * keccak256("Mail(address to,string contents)"), * mailTo, * keccak256(bytes(mailContents)) * ))); * address signer = ECDSA.recover(digest, signature); * ``` */ function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) { return ECDSAUpgradeable.toTypedDataHash(_domainSeparatorV4(), structHash); } /** * @dev The hash of the name parameter for the EIP712 domain. * * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs * are a concern. */ function _EIP712NameHash() internal virtual view returns (bytes32) { return _HASHED_NAME; } /** * @dev The hash of the version parameter for the EIP712 domain. * * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs * are a concern. */ function _EIP712VersionHash() internal virtual view returns (bytes32) { return _HASHED_VERSION; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0-rc.2) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library MathUpgradeable { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 result) { unchecked { // 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 { 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) { return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // 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; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv( uint256 x, uint256 y, uint256 denominator, Rounding rounding ) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // 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 + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10**64) { value /= 10**64; result += 64; } if (value >= 10**32) { value /= 10**32; result += 32; } if (value >= 10**16) { value /= 10**16; result += 16; } if (value >= 10**8) { value /= 10**8; result += 8; } if (value >= 10**4) { value /= 10**4; result += 4; } if (value >= 10**2) { value /= 10**2; result += 2; } if (value >= 10**1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0-rc.2) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/MathUpgradeable.sol"; /** * @dev String operations. */ library StringsUpgradeable { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = MathUpgradeable.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, MathUpgradeable.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ 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 amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0-rc.2) (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.0; import "../Strings.sol"; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS, InvalidSignatureV // Deprecated in v4.8 } function _throwError(RecoverError error) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert("ECDSA: invalid signature"); } else if (error == RecoverError.InvalidSignatureLength) { revert("ECDSA: invalid signature length"); } else if (error == RecoverError.InvalidSignatureS) { revert("ECDSA: invalid signature 's' value"); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature` or error string. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. /// @solidity memory-safe-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else { return (address(0), RecoverError.InvalidSignatureLength); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, signature); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] * * _Available since v4.3._ */ function tryRecover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address, RecoverError) { bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); uint8 v = uint8((uint256(vs) >> 255) + 27); return tryRecover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. * * _Available since v4.2._ */ function recover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, r, vs); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. * * _Available since v4.3._ */ function tryRecover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address, RecoverError) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature); } return (signer, RecoverError.NoError); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, v, r, s); _throwError(error); return recovered; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { // 32 is the length in bytes of hash, // enforced by the type signature above return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); } /** * @dev Returns an Ethereum Signed Message, created from `s`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s)); } /** * @dev Returns an Ethereum Signed Typed Data, created from a * `domainSeparator` and a `structHash`. This produces hash corresponding * to the one signed with the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] * JSON-RPC method as part of EIP-712. * * See {recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0-rc.2) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 result) { unchecked { // 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 { 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) { return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // 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; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv( uint256 x, uint256 y, uint256 denominator, Rounding rounding ) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // 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 + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10**64) { value /= 10**64; result += 64; } if (value >= 10**32) { value /= 10**32; result += 32; } if (value >= 10**16) { value /= 10**16; result += 16; } if (value >= 10**8) { value /= 10**8; result += 8; } if (value >= 10**4) { value /= 10**4; result += 4; } if (value >= 10**2) { value /= 10**2; result += 2; } if (value >= 10**1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0-rc.2) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/Math.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; /// @dev Each clearinghouse has a unique quote product uint32 constant QUOTE_PRODUCT_ID = 0; /// @dev Fees account bytes32 constant FEES_ACCOUNT = bytes32(0); bytes32 constant X_ACCOUNT = 0x0000000000000000000000000000000000000000000000000000000000000001; string constant DEFAULT_REFERRAL_CODE = "-1"; uint128 constant MINIMUM_LIQUIDITY = 10**3; int128 constant ONE = 10**18; uint8 constant MAX_DECIMALS = 18; int128 constant TAKER_SEQUENCER_FEE = 0; // $0.00 int128 constant SLOW_MODE_FEE = 1000000; // $1 int128 constant FAST_WITHDRAWAL_FEE_RATE = 1_000_000_000_000_000; // 0.1% int128 constant LIQUIDATION_FEE = 1e18; // $1 int128 constant HEALTHCHECK_FEE = 1e18; // $1 uint128 constant INT128_MAX = uint128(type(int128).max); uint64 constant SECONDS_PER_DAY = 3600 * 24; uint32 constant VRTX_PRODUCT_ID = 41; int128 constant LIQUIDATION_FEE_FRACTION = 500_000_000_000_000_000; // 50% int128 constant INTEREST_FEE_FRACTION = 200_000_000_000_000_000; // 20% int256 constant MIN_DEPOSIT_AMOUNT = 5 * ONE; uint32 constant MAX_ISOLATED_SUBACCOUNTS_PER_ADDRESS = 10;
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; // Trying to take an action on vertex when string constant ERR_REQUIRES_DEPOSIT = "RS"; // ERC20 Transfer failed string constant ERR_TRANSFER_FAILED = "TF"; // Unauthorized string constant ERR_UNAUTHORIZED = "U"; // Invalid product string constant ERR_INVALID_PRODUCT = "IP"; // Subaccount health too low string constant ERR_SUBACCT_HEALTH = "SH"; // Not liquidatable string constant ERR_NOT_LIQUIDATABLE = "NL"; // Liquidator health too low string constant ERR_NOT_LIQUIDATABLE_INITIAL = "NLI"; // Liquidatee has positive initial health string constant ERR_LIQUIDATED_TOO_MUCH = "LTM"; // Trying to liquidate quote, or string constant ERR_INVALID_LIQUIDATION_PARAMS = "NILP"; // Trying to liquidate perp but the amount is not divisible by sizeIncrement string constant ERR_INVALID_LIQUIDATION_AMOUNT = "NILA"; // Tried to liquidate too little, too much or signs are different string constant ERR_NOT_LIQUIDATABLE_AMT = "NLA"; // Tried to liquidate liabilities before perps string constant ERR_NOT_LIQUIDATABLE_LIABILITIES = "NLL"; // Tried to finalize subaccount that cannot be finalized string constant ERR_NOT_FINALIZABLE_SUBACCOUNT = "NFS"; // Not enough quote to settle string constant ERR_CANNOT_SETTLE = "CS"; // Not enough insurance to settle string constant ERR_NO_INSURANCE = "NI"; // Above reserve ratio string constant ERR_RESERVE_RATIO = "RR"; // Invalid socialize amount string constant ERR_INVALID_SOCIALIZE_AMT = "ISA"; // Socializing product with no open interest string constant ERR_NO_OPEN_INTEREST = "NOI"; // FOK not filled, this isn't rly an error so this is jank string constant ERR_FOK_NOT_FILLED = "ENF"; // bad product config via weights string constant ERR_BAD_PRODUCT_CONFIG = "BPC"; // subacct name too long string constant ERR_LONG_NAME = "LN"; // already registered in health group string constant ERR_ALREADY_REGISTERED = "AR"; // invalid health group provided string constant ERR_INVALID_HEALTH_GROUP = "IHG"; string constant ERR_GETTING_ZERO_HEALTH_GROUP = "GZHG"; // trying to burn more LP than owned string constant ERR_INSUFFICIENT_LP = "ILP"; // taker order subaccount fails risk or is invalid string constant ERR_INVALID_TAKER = "IT"; // maker order subaccount fails risk or is invalid string constant ERR_INVALID_MAKER = "IM"; string constant ERR_INVALID_SIGNATURE = "IS"; string constant ERR_ORDERS_CANNOT_BE_MATCHED = "OCBM"; string constant ERR_INVALID_LP_AMOUNT = "ILA"; string constant ERR_SLIPPAGE_TOO_HIGH = "STH"; string constant ERR_SUBACCOUNT_NOT_FOUND = "SNF"; string constant ERR_INVALID_PRICE = "IPR"; string constant ERR_INVALID_TIME = "ITI"; // states on node and engine are not same string constant ERR_DSYNC = "DSYNC"; string constant ERR_INVALID_SWAP_PARAMS = "ISP"; string constant ERR_CONVERSION_OVERFLOW = "CO"; string constant ERR_ONLY_CLEARINGHOUSE_CAN_SET_BOOK = "OCCSB"; // we match on containing these strings in sequencer string constant ERR_INVALID_SUBMISSION_INDEX = "IX"; string constant ERR_NO_SLOW_MODE_TXS_REMAINING = "no slow mode transactions remaining"; string constant ERR_INVALID_COUNT = "IC"; string constant ERR_SLOW_TX_TOO_RECENT = "STTR"; string constant ERR_WALLET_NOT_TRANSFERABLE = "WNT"; string constant ERR_WALLET_SANCTIONED = "WS"; string constant ERR_SLOW_MODE_WRONG_SENDER = "SMWS"; string constant ERR_WRONG_NONCE = "WN"; // initially wanted to call this // ERR_FULL_UTILIZATION but the shortened // error string may make people mad on the frontend string constant ERR_MAX_UTILIZATION = "MU"; string constant ERR_INVALID_RISK_GROUP = "IRG"; string constant ERR_VERIFY_SCHNORR = "VSR"; string constant ERR_DEPOSIT_TOO_SMALL = "DTS"; string constant ERR_CODE_NOT_MATCH = "CNM";
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "./interfaces/IEndpoint.sol"; import "./interfaces/IEndpointGated.sol"; import "./libraries/MathSD21x18.sol"; import "./common/Constants.sol"; import "hardhat/console.sol"; abstract contract EndpointGated is OwnableUpgradeable, IEndpointGated { address private endpoint; function setEndpoint(address _endpoint) internal onlyOwner { endpoint = _endpoint; } function getEndpoint() public view returns (address) { return endpoint; } function getOracleTime() internal view returns (uint128) { return IEndpoint(endpoint).getTime(); } modifier onlyEndpoint() { require( msg.sender == endpoint, "SequencerGated: caller is not the endpoint" ); _; } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; import "./IClearinghouseEventEmitter.sol"; import "../engine/IProductEngine.sol"; import "../IEndpoint.sol"; import "../IEndpointGated.sol"; import "../../libraries/RiskHelper.sol"; interface IClearinghouse is IClearinghouseEventEmitter, IEndpointGated { function addEngine( address engine, address offchainExchange, IProductEngine.EngineType engineType ) external; function registerProduct(uint32 productId) external; function transferQuote(IEndpoint.TransferQuote calldata tx) external; function depositCollateral(IEndpoint.DepositCollateral calldata tx) external; function withdrawCollateral( bytes32 sender, uint32 productId, uint128 amount, address sendTo, uint64 idx ) external; function mintLp(IEndpoint.MintLp calldata tx) external; function burnLp(IEndpoint.BurnLp calldata tx) external; function liquidateSubaccount(IEndpoint.LiquidateSubaccount calldata tx) external; function depositInsurance(bytes calldata transaction) external; function withdrawInsurance(bytes calldata transaction, uint64 idx) external; function settlePnl(bytes calldata transaction) external; function claimSequencerFees( IEndpoint.ClaimSequencerFees calldata tx, int128[] calldata fees ) external; /// @notice Retrieve quote ERC20 address function getQuote() external view returns (address); /// @notice Returns the registered engine address by type function getEngineByType(IProductEngine.EngineType engineType) external view returns (address); /// @notice Returns the engine associated with a product ID function getEngineByProduct(uint32 productId) external view returns (address); /// @notice Returns health for the subaccount across all engines function getHealth(bytes32 subaccount, IProductEngine.HealthType healthType) external view returns (int128); /// @notice Returns the amount of insurance remaining in this clearinghouse function getInsurance() external view returns (int128); function getSpreads() external view returns (uint256); function upgradeClearinghouseLiq(address _clearinghouseLiq) external; function getClearinghouseLiq() external view returns (address); function burnLpAndTransfer(IEndpoint.BurnLpAndTransfer calldata txn) external; function requireMinDeposit(uint32 productId, uint128 amount) external; function assertCode(bytes calldata tx) external; function manualAssert(bytes calldata tx) external; function getWithdrawPool() external view returns (address); function getSlowModeFee() external view returns (uint256); function setWithdrawPool(address _withdrawPool) external; }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; interface IClearinghouseEventEmitter { /// @notice Emitted during initialization event ClearinghouseInitialized(address endpoint, address quote); /// @notice Emitted when collateral is modified for a subaccount event ModifyCollateral( int128 amount, bytes32 indexed subaccount, uint32 productId ); event Liquidation( bytes32 indexed liquidatorSubaccount, bytes32 indexed liquidateeSubaccount, uint32 productId, bool isEncodedSpread, int128 amount, int128 amountQuote ); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; import "./IProductEngine.sol"; import "../../libraries/RiskHelper.sol"; interface IPerpEngine is IProductEngine { event FundingPayment( uint32 productId, uint128 dt, int128 openInterest, int128 payment ); struct State { int128 cumulativeFundingLongX18; int128 cumulativeFundingShortX18; int128 availableSettle; int128 openInterest; } struct Balance { int128 amount; int128 vQuoteBalance; int128 lastCumulativeFundingX18; } struct LpState { int128 supply; // TODO: this should be removed; we can just get it from State.cumulativeFundingLongX18 int128 lastCumulativeFundingX18; int128 cumulativeFundingPerLpX18; int128 base; int128 quote; } struct LpBalance { int128 amount; // NOTE: funding payments should be rolled // into Balance.vQuoteBalance; int128 lastCumulativeFundingX18; } struct UpdateProductTx { uint32 productId; int128 sizeIncrement; int128 minSize; int128 lpSpreadX18; RiskHelper.RiskStore riskStore; } function getStateAndBalance(uint32 productId, bytes32 subaccount) external view returns (State memory, Balance memory); function getBalance(uint32 productId, bytes32 subaccount) external view returns (Balance memory); function getStatesAndBalances(uint32 productId, bytes32 subaccount) external view returns ( LpState memory, LpBalance memory, State memory, Balance memory ); /// @dev Returns amount settled and emits SettlePnl events for each product function settlePnl(bytes32 subaccount, uint256 productIds) external returns (int128); function getSettlementState(uint32 productId, bytes32 subaccount) external view returns ( int128 availableSettle, LpState memory lpState, LpBalance memory lpBalance, State memory state, Balance memory balance ); function updateBalance( uint32 productId, bytes32 subaccount, int128 amountDelta, int128 vQuoteDelta ) external; function updateStates(uint128 dt, int128[] calldata avgPriceDiffs) external; function manualAssert(int128[] calldata openInterests) external view; function getPositionPnl(uint32 productId, bytes32 subaccount) external view returns (int128); function socializeSubaccount(bytes32 subaccount, int128 insurance) external returns (int128); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "../clearinghouse/IClearinghouse.sol"; import "../../libraries/RiskHelper.sol"; interface IProductEngine { event AddProduct(uint32 productId); enum EngineType { SPOT, PERP } enum HealthType { INITIAL, MAINTENANCE, PNL } struct ProductDelta { uint32 productId; bytes32 subaccount; int128 amountDelta; int128 vQuoteDelta; } struct CoreRisk { int128 amount; int128 price; int128 longWeight; } /// @notice Initializes the engine function initialize( address _clearinghouse, address _offchainExchange, address _quote, address _endpoint, address _admin ) external; function getHealthContribution( bytes32 subaccount, IProductEngine.HealthType healthType ) external view returns (int128); function getCoreRisk( bytes32 subaccount, uint32 productId, IProductEngine.HealthType healthType ) external view returns (IProductEngine.CoreRisk memory); function updateProduct(bytes calldata txn) external; function swapLp( uint32 productId, int128 baseDelta, int128 quoteDelta ) external returns (int128, int128); function mintLp( uint32 productId, bytes32 subaccount, int128 amountBase, int128 quoteAmountLow, int128 quoteAmountHigh ) external; function burnLp( uint32 productId, bytes32 subaccount, // passing 0 here means to burn all int128 amountLp ) external returns (int128, int128); function decomposeLps(bytes32 liquidatee, bytes32 liquidator) external returns (int128); /// @notice return clearinghouse addr function getClearinghouse() external view returns (address); /// @notice return productIds associated with engine function getProductIds() external view returns (uint32[] memory); function getRisk(uint32 productId) external view returns (RiskHelper.Risk memory); /// @notice return the type of engine function getEngineType() external pure returns (IProductEngine.EngineType); function updatePrice(uint32 productId, int128 priceX18) external; }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; import "./IProductEngine.sol"; import "../../libraries/RiskHelper.sol"; interface ISpotEngine is IProductEngine { event InterestPayment( uint32 productId, uint128 dt, int128 depositRateMultiplierX18, int128 borrowRateMultiplierX18, int128 feeAmount ); struct Config { address token; int128 interestInflectionUtilX18; int128 interestFloorX18; int128 interestSmallCapX18; int128 interestLargeCapX18; } struct State { int128 cumulativeDepositsMultiplierX18; int128 cumulativeBorrowsMultiplierX18; int128 totalDepositsNormalized; int128 totalBorrowsNormalized; } struct Balance { int128 amount; int128 lastCumulativeMultiplierX18; } struct BalanceNormalized { int128 amountNormalized; } struct LpState { int128 supply; Balance quote; Balance base; } struct LpBalance { int128 amount; } struct Balances { BalanceNormalized balance; LpBalance lpBalance; } struct UpdateProductTx { uint32 productId; int128 sizeIncrement; int128 minSize; int128 lpSpreadX18; Config config; RiskHelper.RiskStore riskStore; } function getStateAndBalance(uint32 productId, bytes32 subaccount) external view returns (State memory, Balance memory); function getBalance(uint32 productId, bytes32 subaccount) external view returns (Balance memory); function getStatesAndBalances(uint32 productId, bytes32 subaccount) external view returns ( LpState memory, LpBalance memory, State memory, Balance memory ); function getConfig(uint32 productId) external view returns (Config memory); function getWithdrawFee(uint32 productId) external view returns (int128); function getToken(uint32 productId) external view returns (address); function updateBalance( uint32 productId, bytes32 subaccount, int128 amountDelta ) external; function updateBalance( uint32 productId, bytes32 subaccount, int128 amountDelta, int128 quoteDelta ) external; function updateQuoteFromInsurance(bytes32 subaccount, int128 insurance) external returns (int128); function updateStates(uint128 dt) external; function updateMinDepositRate(uint32 productId, int128 minDepositRateX18) external; function manualAssert( int128[] calldata totalDeposits, int128[] calldata totalBorrows ) external view; function socializeSubaccount(bytes32 subaccount) external; function assertUtilization(uint32 productId) external view; }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; import "./clearinghouse/IClearinghouse.sol"; interface IEndpoint { event SubmitTransactions(); // events that we parse transactions into enum TransactionType { LiquidateSubaccount, DepositCollateral, WithdrawCollateral, SpotTick, UpdatePrice, SettlePnl, MatchOrders, DepositInsurance, ExecuteSlowMode, MintLp, BurnLp, SwapAMM, MatchOrderAMM, DumpFees, ClaimSequencerFees, PerpTick, ManualAssert, Rebate, // deprecated UpdateProduct, LinkSigner, UpdateFeeRates, BurnLpAndTransfer, MatchOrdersRFQ, TransferQuote, RebalanceXWithdraw, UpdateMinDepositRate, AssertCode, WithdrawInsurance, CreateIsolatedSubaccount } struct UpdateProduct { address engine; bytes tx; } /// requires signature from sender enum LiquidationMode { SPREAD, SPOT, PERP } struct LegacyLiquidateSubaccount { bytes32 sender; bytes32 liquidatee; uint8 mode; uint32 healthGroup; int128 amount; uint64 nonce; } struct LiquidateSubaccount { bytes32 sender; bytes32 liquidatee; uint32 productId; bool isEncodedSpread; int128 amount; uint64 nonce; } struct LegacySignedLiquidateSubaccount { LegacyLiquidateSubaccount tx; bytes signature; } struct SignedLiquidateSubaccount { LiquidateSubaccount tx; bytes signature; } struct DepositCollateral { bytes32 sender; uint32 productId; uint128 amount; } struct SignedDepositCollateral { DepositCollateral tx; bytes signature; } struct WithdrawCollateral { bytes32 sender; uint32 productId; uint128 amount; uint64 nonce; } struct SignedWithdrawCollateral { WithdrawCollateral tx; bytes signature; } struct MintLp { bytes32 sender; uint32 productId; uint128 amountBase; uint128 quoteAmountLow; uint128 quoteAmountHigh; uint64 nonce; } struct SignedMintLp { MintLp tx; bytes signature; } struct BurnLp { bytes32 sender; uint32 productId; uint128 amount; uint64 nonce; } struct SignedBurnLp { BurnLp tx; bytes signature; } struct LinkSigner { bytes32 sender; bytes32 signer; uint64 nonce; } struct SignedLinkSigner { LinkSigner tx; bytes signature; } /// callable by endpoint; no signature verifications needed struct PerpTick { uint128 time; int128[] avgPriceDiffs; } struct LegacySpotTick { uint128 time; } struct SpotTick { uint128 time; // utilization ratio across all chains int128[] utilizationRatiosX18; } struct ManualAssert { int128[] openInterests; int128[] totalDeposits; int128[] totalBorrows; } struct AssertCode { string[] contractNames; bytes32[] codeHashes; } struct WithdrawInsurance { uint128 amount; address sendTo; } struct Rebate { bytes32[] subaccounts; int128[] amounts; } struct UpdateFeeRates { address user; uint32 productId; // the absolute value of fee rates can't be larger than 100%, // so their X18 values are in the range [-1e18, 1e18], which // can be stored by using int64. int64 makerRateX18; int64 takerRateX18; } struct ClaimSequencerFees { bytes32 subaccount; } struct RebalanceXWithdraw { uint32 productId; uint128 amount; address sendTo; } struct UpdateMinDepositRate { uint32 productId; int128 minDepositRateX18; } struct UpdatePrice { uint32 productId; int128 priceX18; } struct SettlePnl { bytes32[] subaccounts; uint256[] productIds; } /// matching struct Order { bytes32 sender; int128 priceX18; int128 amount; uint64 expiration; uint64 nonce; } struct SignedOrder { Order order; bytes signature; } struct LegacyMatchOrders { uint32 productId; bool amm; SignedOrder taker; SignedOrder maker; } struct MatchOrders { uint32 productId; SignedOrder taker; SignedOrder maker; } struct MatchOrdersWithSigner { MatchOrders matchOrders; address takerLinkedSigner; address makerLinkedSigner; } // just swap against AMM -- theres no maker order struct MatchOrderAMM { uint32 productId; int128 baseDelta; int128 quoteDelta; SignedOrder taker; } struct SwapAMM { bytes32 sender; uint32 productId; int128 amount; int128 priceX18; } struct DepositInsurance { uint128 amount; } struct SlowModeTx { uint64 executableAt; address sender; bytes tx; } struct SlowModeConfig { uint64 timeout; uint64 txCount; uint64 txUpTo; } // legacy :( struct Prices { int128 spotPriceX18; int128 perpPriceX18; } struct BurnLpAndTransfer { bytes32 sender; uint32 productId; uint128 amount; bytes32 recipient; } struct TransferQuote { bytes32 sender; bytes32 recipient; uint128 amount; uint64 nonce; } struct SignedTransferQuote { TransferQuote tx; bytes signature; } struct IsolatedOrder { bytes32 sender; int128 priceX18; int128 amount; uint64 expiration; uint64 nonce; int128 margin; } struct CreateIsolatedSubaccount { IsolatedOrder order; uint32 productId; bytes signature; } function depositCollateral( bytes12 subaccountName, uint32 productId, uint128 amount ) external; function depositCollateralWithReferral( bytes12 subaccountName, uint32 productId, uint128 amount, string calldata referralCode ) external; function depositCollateralWithReferral( bytes32 subaccount, uint32 productId, uint128 amount, string calldata referralCode ) external; function submitSlowModeTransaction(bytes calldata transaction) external; function getTime() external view returns (uint128); function getSequencer() external view returns (address); function getNonce(address sender) external view returns (uint64); function getOffchainExchange() external view returns (address); function getPriceX18(uint32 productId) external view returns (int128); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.13; import "./IEndpoint.sol"; interface IEndpointGated { function getEndpoint() external view returns (address endpoint); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; import "./clearinghouse/IClearinghouse.sol"; interface IOffchainExchange { event FillOrder( uint32 indexed productId, // original order information bytes32 indexed digest, bytes32 indexed subaccount, int128 priceX18, int128 amount, uint64 expiration, uint64 nonce, // whether this order is taking or making bool isTaker, // amount paid in fees (in quote) int128 feeAmount, // change in this subaccount's base balance from this fill int128 baseDelta, // change in this subaccount's quote balance from this fill int128 quoteDelta ); event CloseIsolatedSubaccount( bytes32 indexed isolatedSubaccount, bytes32 indexed parentSubaccount ); struct FeeRates { int64 makerRateX18; int64 takerRateX18; uint8 isNonDefault; // 1: non-default, 0: default } struct LpParams { int128 lpSpreadX18; } struct MarketInfoStore { int64 minSize; int64 sizeIncrement; int128 collectedFees; } struct MarketInfo { uint32 quoteId; int128 minSize; int128 sizeIncrement; int128 collectedFees; } function initialize(address _clearinghouse, address _endpoint) external; function updateFeeRates( address user, uint32 productId, int64 makerRateX18, int64 takerRateX18 ) external; function updateMarket( uint32 productId, uint32 quoteId, address virtualBook, int128 sizeIncrement, int128 minSize, int128 lpSpreadX18 ) external; function getMinSize(uint32 productId) external view returns (int128); function getDigest(uint32 productId, IEndpoint.Order memory order) external view returns (bytes32); function getSizeIncrement(uint32 productId) external view returns (int128); function getMarketInfo(uint32 productId) external view returns (MarketInfo memory); function getLpParams(uint32 productId) external view returns (LpParams memory); function swapAMM(IEndpoint.SwapAMM calldata tx) external; function matchOrderAMM( IEndpoint.MatchOrderAMM calldata tx, address takerLinkedSigner ) external; function matchOrders(IEndpoint.MatchOrdersWithSigner calldata tx) external; function dumpFees() external; function createIsolatedSubaccount( IEndpoint.CreateIsolatedSubaccount memory tx, address linkedSigner ) external returns (bytes32); function isIsolatedSubaccountActive(bytes32 parent, bytes32 subaccount) external view returns (bool); function getParentSubaccount(bytes32 subaccount) external view returns (bytes32); function tryCloseIsolatedSubaccount(bytes32 subaccount) external; }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; import "@openzeppelin/contracts/utils/Strings.sol"; import "./MathHelper.sol"; library Logger { event VertexEVMLog(string message); function log(string memory message) internal { emit VertexEVMLog(message); } function log(int128 value) internal { log(MathHelper.int2str(value)); } function log(string memory message, int128 value) internal { log(string.concat(message, " ", MathHelper.int2str(value))); } function log(string memory message, uint128 value) internal { log(string.concat(message, " ", MathHelper.uint2str(value))); } // function log(string memory message, uint32 value) internal { // log(message, uint128(value)); // } function log(string memory message, address value) internal { log( string.concat(message, " ", Strings.toHexString(uint160(value), 20)) ); } function log(string memory messages, bytes32 value) internal { log(string.concat(messages, " ", string(abi.encodePacked(value)))); } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; import "./MathSD21x18.sol"; /// @title MathHelper /// @dev Provides basic math functions library MathHelper { using MathSD21x18 for int128; /// @notice Returns market id for two given product ids function max(int128 a, int128 b) internal pure returns (int128) { return a > b ? a : b; } function min(int128 a, int128 b) internal pure returns (int128) { return a < b ? a : b; } function abs(int128 val) internal pure returns (int128) { return val < 0 ? -val : val; } // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method) function sqrt(int128 y) internal pure returns (int128 z) { require(y >= 0, "ds-math-sqrt-non-positive"); if (y > 3) { z = y; int128 x = y / 2 + 1; while (x < z) { z = x; x = (y / x + x) / 2; } } else if (y != 0) { z = 1; } } function sqrt256(int256 y) internal pure returns (int256 z) { require(y >= 0, "ds-math-sqrt-non-positive"); if (y > 3) { z = y; int256 x = y / 2 + 1; while (x < z) { z = x; x = (y / x + x) / 2; } } else if (y != 0) { z = 1; } } function int2str(int128 value) internal pure returns (string memory) { if (value == 0) { return "0"; } bool negative = value < 0; uint128 absval = uint128(negative ? -value : value); string memory out = uint2str(absval); if (negative) { out = string.concat("-", out); } return out; } function uint2str(uint128 value) internal pure returns (string memory) { if (value == 0) { return "0"; } uint128 temp = value; uint128 digits; while (temp != 0) { digits++; temp /= 10; } bytes memory buffer = new bytes(digits); while (value != 0) { digits -= 1; buffer[digits] = bytes1(uint8(48 + uint128(value % 10))); value /= 10; } return string(buffer); } // https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.1.0/contracts/math/SignedSafeMath.sol#L86 function add(int128 x, int128 y) internal pure returns (int128) { int128 z = x + y; require((y >= 0 && z >= x) || (y < 0 && z < x), "ds-math-add-overflow"); return z; } // https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.1.0/contracts/math/SignedSafeMath.sol#L69 function sub(int128 x, int128 y) internal pure returns (int128) { int128 z = x - y; require( (y >= 0 && z <= x) || (y < 0 && z > x), "ds-math-sub-underflow" ); return z; } function mul(int128 x, int128 y) internal pure returns (int128 z) { require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow"); } function floor(int128 x, int128 y) internal pure returns (int128 z) { require(y > 0, "ds-math-floor-neg-mod"); int128 r = x % y; if (r == 0) { z = x; } else { z = (x >= 0 ? x - r : x - r - y); } } function ceil(int128 x, int128 y) internal pure returns (int128 z) { require(y > 0, "ds-math-ceil-neg-mod"); int128 r = x % y; if (r == 0) { z = x; } else { z = (x >= 0 ? x + y - r : x - r); } } // we don't need to floor base with sizeIncrement in this function // because this function is only used by `view` functions, which means // the returned values will not be written into storage. function ammEquilibrium( int128 base, int128 quote, int128 priceX18 ) internal pure returns (int128, int128) { if (base == 0 || quote == 0) { return (0, 0); } int256 k = int256(base) * quote; // base * price * base == k // base = sqrt(k / price); base = int128(MathHelper.sqrt256((k * 1e18) / priceX18)); quote = (base == 0) ? int128(0) : int128(k / base); return (base, quote); } function isSwapValid( int128 baseDelta, int128 quoteDelta, int128 base, int128 quote ) internal pure returns (bool) { if ( base == 0 || quote == 0 || base + baseDelta <= 0 || quote + quoteDelta <= 0 ) { return false; } int256 kPrev = int256(base) * quote; int256 kNew = int256(base + baseDelta) * (quote + quoteDelta); return kNew > kPrev; } function swap( int128 amountSwap, int128 base, int128 quote, int128 priceX18, int128 sizeIncrement, int128 lpSpreadX18 ) internal pure returns (int128, int128) { // (amountSwap % sizeIncrement) is guaranteed to be 0 if (base == 0 || quote == 0) { return (0, 0); } int128 currentPriceX18 = quote.div(base); int128 keepRateX18 = 1e18 - lpSpreadX18; // selling if (amountSwap > 0) { priceX18 = priceX18.div(keepRateX18); if (priceX18 >= currentPriceX18) { return (0, 0); } } else { priceX18 = priceX18.mul(keepRateX18); if (priceX18 <= currentPriceX18) { return (0, 0); } } int256 k = int256(base) * quote; int128 baseAtPrice = int128( (MathHelper.sqrt256(k) * 1e9) / MathHelper.sqrt(priceX18) ); // base -> base + amountSwap int128 baseSwapped; if ( (amountSwap > 0 && base + amountSwap > baseAtPrice) || (amountSwap < 0 && base + amountSwap < baseAtPrice) ) { // we hit price limits before we exhaust amountSwap if (baseAtPrice >= base) { baseSwapped = MathHelper.floor( baseAtPrice - base, sizeIncrement ); } else { baseSwapped = MathHelper.ceil( baseAtPrice - base, sizeIncrement ); } } else { // just swap it all // amountSwap is already guaranteed to adhere to sizeIncrement baseSwapped = amountSwap; } int128 quoteSwapped = int128(k / (base + baseSwapped) - quote); if (amountSwap > 0) { quoteSwapped = quoteSwapped.mul(keepRateX18); } else { quoteSwapped = quoteSwapped.div(keepRateX18); } return (baseSwapped, quoteSwapped); } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; import "prb-math/contracts/PRBMathSD59x18.sol"; library MathSD21x18 { using PRBMathSD59x18 for int256; int128 private constant ONE_X18 = 1000000000000000000; int128 private constant MIN_X18 = -0x80000000000000000000000000000000; int128 private constant MAX_X18 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; string private constant ERR_OVERFLOW = "OF"; string private constant ERR_DIV_BY_ZERO = "DBZ"; function fromInt(int128 x) internal pure returns (int128) { unchecked { int256 result = int256(x) * ONE_X18; require(result >= MIN_X18 && result <= MAX_X18, ERR_OVERFLOW); return int128(result); } } function mulDiv( int128 x, int128 y, int128 z ) internal pure returns (int128) { unchecked { require(z != 0, ERR_DIV_BY_ZERO); int256 result = (int256(x) * y) / z; require(result >= MIN_X18 && result <= MAX_X18, ERR_OVERFLOW); return int128(result); } } function toInt(int128 x) internal pure returns (int128) { unchecked { return int128(x / ONE_X18); } } function add(int128 x, int128 y) internal pure returns (int128) { unchecked { int256 result = int256(x) + y; require(result >= MIN_X18 && result <= MAX_X18, ERR_OVERFLOW); return int128(result); } } function sub(int128 x, int128 y) internal pure returns (int128) { unchecked { int256 result = int256(x) - y; require(result >= MIN_X18 && result <= MAX_X18, ERR_OVERFLOW); return int128(result); } } function mul(int128 x, int128 y) internal pure returns (int128) { unchecked { int256 result = (int256(x) * y) / ONE_X18; require(result >= MIN_X18 && result <= MAX_X18, ERR_OVERFLOW); return int128(result); } } function div(int128 x, int128 y) internal pure returns (int128) { unchecked { require(y != 0, ERR_DIV_BY_ZERO); int256 result = (int256(x) * ONE_X18) / y; require(result >= MIN_X18 && result <= MAX_X18, ERR_OVERFLOW); return int128(result); } } function abs(int128 x) internal pure returns (int128) { unchecked { require(x != MIN_X18, ERR_OVERFLOW); return x < 0 ? -x : x; } } function sqrt(int128 x) internal pure returns (int128) { unchecked { int256 result = int256(x).sqrt(); require(result >= MIN_X18 && result <= MAX_X18, ERR_OVERFLOW); return int128(result); } } // note that y is not X18 function pow(int128 x, int128 y) internal pure returns (int128) { unchecked { require(y >= 0, ERR_OVERFLOW); int128 result = ONE_X18; for (int128 i = 1; i <= y; i *= 2) { if (i & y != 0) { result = mul(result, x); } x = mul(x, x); } return result; } } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; import "./MathSD21x18.sol"; import "../interfaces/engine/IProductEngine.sol"; import "../common/Constants.sol"; import "../common/Errors.sol"; import "./MathHelper.sol"; /// @title RiskHelper /// @dev Provides basic math functions library RiskHelper { using MathSD21x18 for int128; struct RiskStore { // these weights are all // between 0 and 2 // these integers are the real // weights times 1e9 int32 longWeightInitial; int32 shortWeightInitial; int32 longWeightMaintenance; int32 shortWeightMaintenance; int128 priceX18; } struct Risk { int128 longWeightInitialX18; int128 shortWeightInitialX18; int128 longWeightMaintenanceX18; int128 shortWeightMaintenanceX18; int128 priceX18; } function _getSpreadHealthRebateAmount( Risk memory perpRisk, int128 basisAmount, int128 priceSumX18, IProductEngine.HealthType healthType ) internal pure returns (int128) { // 5x more leverage than the standard perp // by refunding 4/5 of the health penalty int128 rebateRateX18 = ((ONE - _getWeightX18(perpRisk, 1, healthType)) * 4) / 5; return rebateRateX18.mul(priceSumX18).mul(basisAmount); } function _getLpRawValue( int128 baseAmount, int128 quoteAmount, int128 priceX18 ) internal pure returns (int128) { // naive way: value an LP token by value of the raw components 2 * arithmetic mean of base value and quote value // price manipulation proof way: use the geometric mean return 2 * int128( MathHelper.sqrt256( int256(baseAmount.mul(priceX18)) * quoteAmount ) ); } function _getWeightX18( Risk memory risk, int128 amount, IProductEngine.HealthType healthType ) internal pure returns (int128) { // (1 + imf * sqrt(amount)) if (healthType == IProductEngine.HealthType.PNL) { return ONE; } int128 weight; if (amount >= 0) { weight = healthType == IProductEngine.HealthType.INITIAL ? risk.longWeightInitialX18 : risk.longWeightMaintenanceX18; } else { weight = healthType == IProductEngine.HealthType.INITIAL ? risk.shortWeightInitialX18 : risk.shortWeightMaintenanceX18; } return weight; } function isIsolatedSubaccount(bytes32 subaccount) internal pure returns (bool) { return uint256(subaccount) & 0xFFFFFF == 6910831; } function getIsolatedProductId(bytes32 subaccount) internal pure returns (uint32) { if (!isIsolatedSubaccount(subaccount)) { return 0; } return uint32((uint256(subaccount) >> 32) & 0xFFFF); } function getIsolatedId(bytes32 subaccount) internal pure returns (uint8) { if (!isIsolatedSubaccount(subaccount)) { return 0; } return uint8((uint256(subaccount) >> 24) & 0xFF); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.4.22 <0.9.0; library console { address constant CONSOLE_ADDRESS = 0x000000000000000000636F6e736F6c652e6c6f67; function _sendLogPayloadImplementation(bytes memory payload) internal view { address consoleAddress = CONSOLE_ADDRESS; /// @solidity memory-safe-assembly assembly { pop( staticcall( gas(), consoleAddress, add(payload, 32), mload(payload), 0, 0 ) ) } } function _castToPure( function(bytes memory) internal view fnIn ) internal pure returns (function(bytes memory) pure fnOut) { assembly { fnOut := fnIn } } function _sendLogPayload(bytes memory payload) internal pure { _castToPure(_sendLogPayloadImplementation)(payload); } function log() internal pure { _sendLogPayload(abi.encodeWithSignature("log()")); } function logInt(int256 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(int256)", p0)); } function logUint(uint256 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256)", p0)); } function logString(string memory p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); } function logBool(bool p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); } function logAddress(address p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); } function logBytes(bytes memory p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0)); } function logBytes1(bytes1 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0)); } function logBytes2(bytes2 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0)); } function logBytes3(bytes3 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0)); } function logBytes4(bytes4 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0)); } function logBytes5(bytes5 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0)); } function logBytes6(bytes6 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0)); } function logBytes7(bytes7 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0)); } function logBytes8(bytes8 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0)); } function logBytes9(bytes9 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0)); } function logBytes10(bytes10 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0)); } function logBytes11(bytes11 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0)); } function logBytes12(bytes12 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0)); } function logBytes13(bytes13 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0)); } function logBytes14(bytes14 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0)); } function logBytes15(bytes15 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0)); } function logBytes16(bytes16 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0)); } function logBytes17(bytes17 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0)); } function logBytes18(bytes18 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0)); } function logBytes19(bytes19 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0)); } function logBytes20(bytes20 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0)); } function logBytes21(bytes21 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0)); } function logBytes22(bytes22 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0)); } function logBytes23(bytes23 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0)); } function logBytes24(bytes24 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0)); } function logBytes25(bytes25 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0)); } function logBytes26(bytes26 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0)); } function logBytes27(bytes27 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0)); } function logBytes28(bytes28 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0)); } function logBytes29(bytes29 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0)); } function logBytes30(bytes30 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0)); } function logBytes31(bytes31 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0)); } function logBytes32(bytes32 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0)); } function log(uint256 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256)", p0)); } function log(string memory p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); } function log(bool p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); } function log(address p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); } function log(uint256 p0, uint256 p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256)", p0, p1)); } function log(uint256 p0, string memory p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string)", p0, p1)); } function log(uint256 p0, bool p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool)", p0, p1)); } function log(uint256 p0, address p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address)", p0, p1)); } function log(string memory p0, uint256 p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256)", p0, p1)); } function log(string memory p0, string memory p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1)); } function log(string memory p0, bool p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1)); } function log(string memory p0, address p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1)); } function log(bool p0, uint256 p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256)", p0, p1)); } function log(bool p0, string memory p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1)); } function log(bool p0, bool p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1)); } function log(bool p0, address p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1)); } function log(address p0, uint256 p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256)", p0, p1)); } function log(address p0, string memory p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1)); } function log(address p0, bool p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1)); } function log(address p0, address p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1)); } function log(uint256 p0, uint256 p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256)", p0, p1, p2)); } function log(uint256 p0, uint256 p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string)", p0, p1, p2)); } function log(uint256 p0, uint256 p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool)", p0, p1, p2)); } function log(uint256 p0, uint256 p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address)", p0, p1, p2)); } function log(uint256 p0, string memory p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256)", p0, p1, p2)); } function log(uint256 p0, string memory p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string)", p0, p1, p2)); } function log(uint256 p0, string memory p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool)", p0, p1, p2)); } function log(uint256 p0, string memory p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address)", p0, p1, p2)); } function log(uint256 p0, bool p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256)", p0, p1, p2)); } function log(uint256 p0, bool p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string)", p0, p1, p2)); } function log(uint256 p0, bool p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool)", p0, p1, p2)); } function log(uint256 p0, bool p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address)", p0, p1, p2)); } function log(uint256 p0, address p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256)", p0, p1, p2)); } function log(uint256 p0, address p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string)", p0, p1, p2)); } function log(uint256 p0, address p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool)", p0, p1, p2)); } function log(uint256 p0, address p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address)", p0, p1, p2)); } function log(string memory p0, uint256 p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256)", p0, p1, p2)); } function log(string memory p0, uint256 p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string)", p0, p1, p2)); } function log(string memory p0, uint256 p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool)", p0, p1, p2)); } function log(string memory p0, uint256 p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address)", p0, p1, p2)); } function log(string memory p0, string memory p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256)", p0, p1, p2)); } function log(string memory p0, string memory p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2)); } function log(string memory p0, string memory p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2)); } function log(string memory p0, string memory p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2)); } function log(string memory p0, bool p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256)", p0, p1, p2)); } function log(string memory p0, bool p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2)); } function log(string memory p0, bool p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2)); } function log(string memory p0, bool p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2)); } function log(string memory p0, address p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256)", p0, p1, p2)); } function log(string memory p0, address p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2)); } function log(string memory p0, address p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2)); } function log(string memory p0, address p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2)); } function log(bool p0, uint256 p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256)", p0, p1, p2)); } function log(bool p0, uint256 p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string)", p0, p1, p2)); } function log(bool p0, uint256 p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool)", p0, p1, p2)); } function log(bool p0, uint256 p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address)", p0, p1, p2)); } function log(bool p0, string memory p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256)", p0, p1, p2)); } function log(bool p0, string memory p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2)); } function log(bool p0, string memory p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2)); } function log(bool p0, string memory p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2)); } function log(bool p0, bool p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256)", p0, p1, p2)); } function log(bool p0, bool p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2)); } function log(bool p0, bool p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2)); } function log(bool p0, bool p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2)); } function log(bool p0, address p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256)", p0, p1, p2)); } function log(bool p0, address p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2)); } function log(bool p0, address p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2)); } function log(bool p0, address p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2)); } function log(address p0, uint256 p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256)", p0, p1, p2)); } function log(address p0, uint256 p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string)", p0, p1, p2)); } function log(address p0, uint256 p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool)", p0, p1, p2)); } function log(address p0, uint256 p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address)", p0, p1, p2)); } function log(address p0, string memory p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256)", p0, p1, p2)); } function log(address p0, string memory p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2)); } function log(address p0, string memory p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2)); } function log(address p0, string memory p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2)); } function log(address p0, bool p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256)", p0, p1, p2)); } function log(address p0, bool p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2)); } function log(address p0, bool p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2)); } function log(address p0, bool p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2)); } function log(address p0, address p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256)", p0, p1, p2)); } function log(address p0, address p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2)); } function log(address p0, address p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2)); } function log(address p0, address p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2)); } function log(uint256 p0, uint256 p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,string)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,bool)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,address)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,string)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,bool)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,address)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,string)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,bool)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,address)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,string)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,bool)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,address)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,string)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,bool)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,address)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,string)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,bool)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,address)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,string)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,bool)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,address)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,string)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,bool)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,address)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,string)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,bool)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,address)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,string)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,bool)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,address)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,string)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,bool)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,address)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,string)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,bool)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,address)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,string)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,bool)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,address)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,string)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,bool)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,address)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,string)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,bool)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,address)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,string)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,bool)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,address)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,uint256)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,string)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,bool)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,address)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,uint256)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,string)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,bool)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,address)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,uint256)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,string)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,bool)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,address)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,uint256)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,string)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,bool)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,address)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,uint256)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,string)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,bool)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,address)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint256)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint256)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint256)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,uint256)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,string)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,bool)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,address)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint256)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint256)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint256)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3)); } function log(string memory p0, address p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,uint256)", p0, p1, p2, p3)); } function log(string memory p0, address p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,string)", p0, p1, p2, p3)); } function log(string memory p0, address p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,bool)", p0, p1, p2, p3)); } function log(string memory p0, address p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,address)", p0, p1, p2, p3)); } function log(string memory p0, address p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint256)", p0, p1, p2, p3)); } function log(string memory p0, address p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3)); } function log(string memory p0, address p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3)); } function log(string memory p0, address p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3)); } function log(string memory p0, address p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint256)", p0, p1, p2, p3)); } function log(string memory p0, address p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3)); } function log(string memory p0, address p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3)); } function log(string memory p0, address p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3)); } function log(string memory p0, address p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint256)", p0, p1, p2, p3)); } function log(string memory p0, address p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3)); } function log(string memory p0, address p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3)); } function log(string memory p0, address p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,uint256)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,string)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,bool)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,address)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,uint256)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,string)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,bool)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,address)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,uint256)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,string)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,bool)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,address)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,uint256)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,string)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,bool)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,address)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,uint256)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,string)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,bool)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,address)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint256)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint256)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint256)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3)); } function log(bool p0, bool p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,uint256)", p0, p1, p2, p3)); } function log(bool p0, bool p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,string)", p0, p1, p2, p3)); } function log(bool p0, bool p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,bool)", p0, p1, p2, p3)); } function log(bool p0, bool p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,address)", p0, p1, p2, p3)); } function log(bool p0, bool p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint256)", p0, p1, p2, p3)); } function log(bool p0, bool p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3)); } function log(bool p0, bool p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3)); } function log(bool p0, bool p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3)); } function log(bool p0, bool p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint256)", p0, p1, p2, p3)); } function log(bool p0, bool p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3)); } function log(bool p0, bool p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3)); } function log(bool p0, bool p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3)); } function log(bool p0, bool p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint256)", p0, p1, p2, p3)); } function log(bool p0, bool p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3)); } function log(bool p0, bool p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3)); } function log(bool p0, bool p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3)); } function log(bool p0, address p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,uint256)", p0, p1, p2, p3)); } function log(bool p0, address p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,string)", p0, p1, p2, p3)); } function log(bool p0, address p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,bool)", p0, p1, p2, p3)); } function log(bool p0, address p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,address)", p0, p1, p2, p3)); } function log(bool p0, address p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint256)", p0, p1, p2, p3)); } function log(bool p0, address p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3)); } function log(bool p0, address p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3)); } function log(bool p0, address p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3)); } function log(bool p0, address p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint256)", p0, p1, p2, p3)); } function log(bool p0, address p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3)); } function log(bool p0, address p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3)); } function log(bool p0, address p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3)); } function log(bool p0, address p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint256)", p0, p1, p2, p3)); } function log(bool p0, address p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3)); } function log(bool p0, address p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3)); } function log(bool p0, address p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,uint256)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,string)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,bool)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,address)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,uint256)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,string)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,bool)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,address)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,uint256)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,string)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,bool)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,address)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,uint256)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,string)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,bool)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,address)", p0, p1, p2, p3)); } function log(address p0, string memory p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,uint256)", p0, p1, p2, p3)); } function log(address p0, string memory p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,string)", p0, p1, p2, p3)); } function log(address p0, string memory p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,bool)", p0, p1, p2, p3)); } function log(address p0, string memory p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,address)", p0, p1, p2, p3)); } function log(address p0, string memory p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint256)", p0, p1, p2, p3)); } function log(address p0, string memory p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3)); } function log(address p0, string memory p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3)); } function log(address p0, string memory p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3)); } function log(address p0, string memory p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint256)", p0, p1, p2, p3)); } function log(address p0, string memory p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3)); } function log(address p0, string memory p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3)); } function log(address p0, string memory p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3)); } function log(address p0, string memory p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint256)", p0, p1, p2, p3)); } function log(address p0, string memory p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3)); } function log(address p0, string memory p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3)); } function log(address p0, string memory p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3)); } function log(address p0, bool p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,uint256)", p0, p1, p2, p3)); } function log(address p0, bool p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,string)", p0, p1, p2, p3)); } function log(address p0, bool p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,bool)", p0, p1, p2, p3)); } function log(address p0, bool p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,address)", p0, p1, p2, p3)); } function log(address p0, bool p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint256)", p0, p1, p2, p3)); } function log(address p0, bool p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3)); } function log(address p0, bool p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3)); } function log(address p0, bool p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3)); } function log(address p0, bool p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint256)", p0, p1, p2, p3)); } function log(address p0, bool p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3)); } function log(address p0, bool p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3)); } function log(address p0, bool p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3)); } function log(address p0, bool p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint256)", p0, p1, p2, p3)); } function log(address p0, bool p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3)); } function log(address p0, bool p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3)); } function log(address p0, bool p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3)); } function log(address p0, address p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,uint256)", p0, p1, p2, p3)); } function log(address p0, address p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,string)", p0, p1, p2, p3)); } function log(address p0, address p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,bool)", p0, p1, p2, p3)); } function log(address p0, address p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,address)", p0, p1, p2, p3)); } function log(address p0, address p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint256)", p0, p1, p2, p3)); } function log(address p0, address p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3)); } function log(address p0, address p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3)); } function log(address p0, address p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3)); } function log(address p0, address p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint256)", p0, p1, p2, p3)); } function log(address p0, address p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3)); } function log(address p0, address p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3)); } function log(address p0, address p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3)); } function log(address p0, address p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint256)", p0, p1, p2, p3)); } function log(address p0, address p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3)); } function log(address p0, address p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3)); } function log(address p0, address p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3)); } }
// SPDX-License-Identifier: Unlicense pragma solidity >=0.8.4; /// @notice Emitted when the result overflows uint256. error PRBMath__MulDivFixedPointOverflow(uint256 prod1); /// @notice Emitted when the result overflows uint256. error PRBMath__MulDivOverflow(uint256 prod1, uint256 denominator); /// @notice Emitted when one of the inputs is type(int256).min. error PRBMath__MulDivSignedInputTooSmall(); /// @notice Emitted when the intermediary absolute result overflows int256. error PRBMath__MulDivSignedOverflow(uint256 rAbs); /// @notice Emitted when the input is MIN_SD59x18. error PRBMathSD59x18__AbsInputTooSmall(); /// @notice Emitted when ceiling a number overflows SD59x18. error PRBMathSD59x18__CeilOverflow(int256 x); /// @notice Emitted when one of the inputs is MIN_SD59x18. error PRBMathSD59x18__DivInputTooSmall(); /// @notice Emitted when one of the intermediary unsigned results overflows SD59x18. error PRBMathSD59x18__DivOverflow(uint256 rAbs); /// @notice Emitted when the input is greater than 133.084258667509499441. error PRBMathSD59x18__ExpInputTooBig(int256 x); /// @notice Emitted when the input is greater than 192. error PRBMathSD59x18__Exp2InputTooBig(int256 x); /// @notice Emitted when flooring a number underflows SD59x18. error PRBMathSD59x18__FloorUnderflow(int256 x); /// @notice Emitted when converting a basic integer to the fixed-point format overflows SD59x18. error PRBMathSD59x18__FromIntOverflow(int256 x); /// @notice Emitted when converting a basic integer to the fixed-point format underflows SD59x18. error PRBMathSD59x18__FromIntUnderflow(int256 x); /// @notice Emitted when the product of the inputs is negative. error PRBMathSD59x18__GmNegativeProduct(int256 x, int256 y); /// @notice Emitted when multiplying the inputs overflows SD59x18. error PRBMathSD59x18__GmOverflow(int256 x, int256 y); /// @notice Emitted when the input is less than or equal to zero. error PRBMathSD59x18__LogInputTooSmall(int256 x); /// @notice Emitted when one of the inputs is MIN_SD59x18. error PRBMathSD59x18__MulInputTooSmall(); /// @notice Emitted when the intermediary absolute result overflows SD59x18. error PRBMathSD59x18__MulOverflow(uint256 rAbs); /// @notice Emitted when the intermediary absolute result overflows SD59x18. error PRBMathSD59x18__PowuOverflow(uint256 rAbs); /// @notice Emitted when the input is negative. error PRBMathSD59x18__SqrtNegativeInput(int256 x); /// @notice Emitted when the calculating the square root overflows SD59x18. error PRBMathSD59x18__SqrtOverflow(int256 x); /// @notice Emitted when addition overflows UD60x18. error PRBMathUD60x18__AddOverflow(uint256 x, uint256 y); /// @notice Emitted when ceiling a number overflows UD60x18. error PRBMathUD60x18__CeilOverflow(uint256 x); /// @notice Emitted when the input is greater than 133.084258667509499441. error PRBMathUD60x18__ExpInputTooBig(uint256 x); /// @notice Emitted when the input is greater than 192. error PRBMathUD60x18__Exp2InputTooBig(uint256 x); /// @notice Emitted when converting a basic integer to the fixed-point format format overflows UD60x18. error PRBMathUD60x18__FromUintOverflow(uint256 x); /// @notice Emitted when multiplying the inputs overflows UD60x18. error PRBMathUD60x18__GmOverflow(uint256 x, uint256 y); /// @notice Emitted when the input is less than 1. error PRBMathUD60x18__LogInputTooSmall(uint256 x); /// @notice Emitted when the calculating the square root overflows UD60x18. error PRBMathUD60x18__SqrtOverflow(uint256 x); /// @notice Emitted when subtraction underflows UD60x18. error PRBMathUD60x18__SubUnderflow(uint256 x, uint256 y); /// @dev Common mathematical functions used in both PRBMathSD59x18 and PRBMathUD60x18. Note that this shared library /// does not always assume the signed 59.18-decimal fixed-point or the unsigned 60.18-decimal fixed-point /// representation. When it does not, it is explicitly mentioned in the NatSpec documentation. library PRBMath { /// STRUCTS /// struct SD59x18 { int256 value; } struct UD60x18 { uint256 value; } /// STORAGE /// /// @dev How many trailing decimals can be represented. uint256 internal constant SCALE = 1e18; /// @dev Largest power of two divisor of SCALE. uint256 internal constant SCALE_LPOTD = 262144; /// @dev SCALE inverted mod 2^256. uint256 internal constant SCALE_INVERSE = 78156646155174841979727994598816262306175212592076161876661_508869554232690281; /// 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. function exp2(uint256 x) internal pure returns (uint256 result) { unchecked { // Start from 0.5 in the 192.64-bit fixed-point format. result = 0x800000000000000000000000000000000000000000000000; // Multiply the result by root(2, 2^-i) when the bit at position i is 1. None of the intermediary results overflows // because the initial result is 2^191 and all magic factors are less than 2^65. 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 & 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 & 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 & 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 & 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 & 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 & 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 & 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; } // We're doing two things at the same time: // // 1. Multiply the result by 2^n + 1, where "2^n" is the integer part and the one is added to account for // the fact that we initially set the result to 0.5. This is accomplished by subtracting from 191 // rather than 192. // 2. Convert the result to the unsigned 60.18-decimal fixed-point format. // // This works because 2^(191-ip) = 2^ip / 2^191, where "ip" is the integer part "2^n". result *= SCALE; result >>= (191 - (x >> 64)); } } /// @notice Finds the zero-based index of the first one in the binary representation of x. /// @dev See the note on msb in the "Find First Set" Wikipedia article https://en.wikipedia.org/wiki/Find_first_set /// @param x The uint256 number for which to find the index of the most significant bit. /// @return msb The index of the most significant bit as an uint256. function mostSignificantBit(uint256 x) internal pure returns (uint256 msb) { if (x >= 2**128) { x >>= 128; msb += 128; } if (x >= 2**64) { x >>= 64; msb += 64; } if (x >= 2**32) { x >>= 32; msb += 32; } if (x >= 2**16) { x >>= 16; msb += 16; } if (x >= 2**8) { x >>= 8; msb += 8; } if (x >= 2**4) { x >>= 4; msb += 4; } if (x >= 2**2) { x >>= 2; msb += 2; } if (x >= 2**1) { // No need to shift x any more. msb += 1; } } /// @notice Calculates floor(x*y÷denominator) with full precision. /// /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv. /// /// Requirements: /// - The denominator cannot be zero. /// - The result must fit within uint256. /// /// Caveats: /// - This function does not work with fixed-point numbers. /// /// @param x The multiplicand as an uint256. /// @param y The multiplier as an uint256. /// @param denominator The divisor as an uint256. /// @return result The result as an uint256. function mulDiv( uint256 x, uint256 y, uint256 denominator ) internal 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 { 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 { result = prod0 / denominator; } return result; } // Make sure the result is less than 2^256. Also prevents denominator == 0. if (prod1 >= denominator) { revert PRBMath__MulDivOverflow(prod1, denominator); } /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. unchecked { // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 lpotdod = denominator & (~denominator + 1); assembly { // Divide denominator by lpotdod. denominator := div(denominator, lpotdod) // Divide [prod1 prod0] by lpotdod. prod0 := div(prod0, lpotdod) // Flip lpotdod such that it is 2^256 / lpotdod. If lpotdod is zero, then it becomes one. lpotdod := add(div(sub(0, lpotdod), lpotdod), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * lpotdod; // 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; return result; } } /// @notice Calculates floor(x*y÷1e18) with full precision. /// /// @dev Variant of "mulDiv" with constant folding, i.e. in which the denominator is always 1e18. Before returning the /// final result, we add 1 if (x * y) % SCALE >= HALF_SCALE. Without this, 6.6e-19 would be truncated to 0 instead of /// being rounded to 1e-18. See "Listing 6" and text above it at https://accu.org/index.php/journals/1717. /// /// Requirements: /// - The result must fit within uint256. /// /// Caveats: /// - The body is purposely left uncommented; see the NatSpec comments in "PRBMath.mulDiv" to understand how this works. /// - It is assumed that the result can never be type(uint256).max when x and y solve the following two equations: /// 1. x * y = type(uint256).max * SCALE /// 2. (x * y) % SCALE >= SCALE / 2 /// /// @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. function mulDivFixedPoint(uint256 x, uint256 y) internal pure returns (uint256 result) { uint256 prod0; uint256 prod1; assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } if (prod1 >= SCALE) { revert PRBMath__MulDivFixedPointOverflow(prod1); } uint256 remainder; uint256 roundUpUnit; assembly { remainder := mulmod(x, y, SCALE) roundUpUnit := gt(remainder, 499999999999999999) } if (prod1 == 0) { unchecked { result = (prod0 / SCALE) + roundUpUnit; return result; } } assembly { result := add( mul( or( div(sub(prod0, remainder), SCALE_LPOTD), mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, SCALE_LPOTD), SCALE_LPOTD), 1)) ), SCALE_INVERSE ), roundUpUnit ) } } /// @notice Calculates floor(x*y÷denominator) with full precision. /// /// @dev An extension of "mulDiv" for signed numbers. Works by computing the signs and the absolute values separately. /// /// Requirements: /// - None of the inputs can be type(int256).min. /// - The result must fit within 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. function mulDivSigned( int256 x, int256 y, int256 denominator ) internal pure returns (int256 result) { if (x == type(int256).min || y == type(int256).min || denominator == type(int256).min) { revert PRBMath__MulDivSignedInputTooSmall(); } // Get hold of the absolute values of x, y and the denominator. uint256 ax; uint256 ay; uint256 ad; unchecked { ax = x < 0 ? uint256(-x) : uint256(x); ay = y < 0 ? uint256(-y) : uint256(y); ad = denominator < 0 ? uint256(-denominator) : uint256(denominator); } // Compute the absolute value of (x*y)÷denominator. The result must fit within int256. uint256 rAbs = mulDiv(ax, ay, ad); if (rAbs > uint256(type(int256).max)) { revert PRBMath__MulDivSignedOverflow(rAbs); } // Get the signs of x, y and the denominator. uint256 sx; uint256 sy; uint256 sd; assembly { sx := sgt(x, sub(0, 1)) sy := sgt(y, sub(0, 1)) sd := sgt(denominator, sub(0, 1)) } // XOR over sx, sy and sd. This is checking whether there are one or three negative signs in the inputs. // If yes, the result should be negative. result = sx ^ sy ^ sd == 0 ? -int256(rAbs) : int256(rAbs); } /// @notice Calculates the square root of x, rounding down. /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method. /// /// Caveats: /// - This function does not work with fixed-point numbers. /// /// @param x The uint256 number for which to calculate the square root. /// @return result The result as an uint256. function sqrt(uint256 x) internal pure returns (uint256 result) { if (x == 0) { return 0; } // Set the initial guess to the least power of two that is greater than or equal to sqrt(x). uint256 xAux = uint256(x); result = 1; if (xAux >= 0x100000000000000000000000000000000) { xAux >>= 128; result <<= 64; } if (xAux >= 0x10000000000000000) { xAux >>= 64; result <<= 32; } if (xAux >= 0x100000000) { xAux >>= 32; result <<= 16; } if (xAux >= 0x10000) { xAux >>= 16; result <<= 8; } if (xAux >= 0x100) { xAux >>= 8; result <<= 4; } if (xAux >= 0x10) { xAux >>= 4; result <<= 2; } if (xAux >= 0x8) { result <<= 1; } // The operations can never overflow because the result is max 2^127 when it enters this block. 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; // Seven iterations should be enough uint256 roundedDownResult = x / result; return result >= roundedDownResult ? roundedDownResult : result; } } }
// SPDX-License-Identifier: Unlicense pragma solidity >=0.8.4; import "./PRBMath.sol"; /// @title PRBMathSD59x18 /// @author Paul Razvan Berg /// @notice Smart contract library for advanced fixed-point math that works with int256 numbers considered to have 18 /// trailing decimals. We call this number representation signed 59.18-decimal fixed-point, since the numbers can have /// a sign and there can be up to 59 digits in the integer part and up to 18 decimals in the fractional part. The numbers /// are bound by the minimum and the maximum values permitted by the Solidity type int256. library PRBMathSD59x18 { /// @dev log2(e) as a signed 59.18-decimal fixed-point number. int256 internal constant LOG2_E = 1_442695040888963407; /// @dev Half the SCALE number. int256 internal constant HALF_SCALE = 5e17; /// @dev The maximum value a signed 59.18-decimal fixed-point number can have. int256 internal constant MAX_SD59x18 = 57896044618658097711785492504343953926634992332820282019728_792003956564819967; /// @dev The maximum whole value a signed 59.18-decimal fixed-point number can have. int256 internal constant MAX_WHOLE_SD59x18 = 57896044618658097711785492504343953926634992332820282019728_000000000000000000; /// @dev The minimum value a signed 59.18-decimal fixed-point number can have. int256 internal constant MIN_SD59x18 = -57896044618658097711785492504343953926634992332820282019728_792003956564819968; /// @dev The minimum whole value a signed 59.18-decimal fixed-point number can have. int256 internal constant MIN_WHOLE_SD59x18 = -57896044618658097711785492504343953926634992332820282019728_000000000000000000; /// @dev How many trailing decimals can be represented. int256 internal constant SCALE = 1e18; /// INTERNAL FUNCTIONS /// /// @notice Calculate the absolute value of x. /// /// @dev Requirements: /// - x must be greater than MIN_SD59x18. /// /// @param x The number to calculate the absolute value for. /// @param result The absolute value of x. function abs(int256 x) internal pure returns (int256 result) { unchecked { if (x == MIN_SD59x18) { revert PRBMathSD59x18__AbsInputTooSmall(); } result = x < 0 ? -x : x; } } /// @notice Calculates the arithmetic average of x and y, rounding down. /// @param x The first operand as a signed 59.18-decimal fixed-point number. /// @param y The second operand as a signed 59.18-decimal fixed-point number. /// @return result The arithmetic average as a signed 59.18-decimal fixed-point number. function avg(int256 x, int256 y) internal pure returns (int256 result) { // The operations can never overflow. unchecked { int256 sum = (x >> 1) + (y >> 1); if (sum < 0) { // If at least one of x and y is odd, we add 1 to the result. This is because shifting negative numbers to the // right rounds down to infinity. assembly { result := add(sum, and(or(x, y), 1)) } } else { // If both x and y are odd, we add 1 to the result. This is because if both numbers are odd, the 0.5 // remainder gets truncated twice. result = sum + (x & y & 1); } } } /// @notice Yields the least greatest signed 59.18 decimal fixed-point number greater 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 must be less than or equal to MAX_WHOLE_SD59x18. /// /// @param x The signed 59.18-decimal fixed-point number to ceil. /// @param result The least integer greater than or equal to x, as a signed 58.18-decimal fixed-point number. function ceil(int256 x) internal pure returns (int256 result) { if (x > MAX_WHOLE_SD59x18) { revert PRBMathSD59x18__CeilOverflow(x); } unchecked { int256 remainder = x % SCALE; if (remainder == 0) { result = x; } else { // Solidity uses C fmod style, which returns a modulus with the same sign as x. result = x - remainder; if (x > 0) { result += SCALE; } } } } /// @notice Divides two signed 59.18-decimal fixed-point numbers, returning a new signed 59.18-decimal fixed-point number. /// /// @dev Variant of "mulDiv" that works with signed numbers. Works by computing the signs and the absolute values separately. /// /// Requirements: /// - All from "PRBMath.mulDiv". /// - None of the inputs can be MIN_SD59x18. /// - The denominator cannot be zero. /// - The result must fit within int256. /// /// Caveats: /// - All from "PRBMath.mulDiv". /// /// @param x The numerator as a signed 59.18-decimal fixed-point number. /// @param y The denominator as a signed 59.18-decimal fixed-point number. /// @param result The quotient as a signed 59.18-decimal fixed-point number. function div(int256 x, int256 y) internal pure returns (int256 result) { if (x == MIN_SD59x18 || y == MIN_SD59x18) { revert PRBMathSD59x18__DivInputTooSmall(); } // Get hold of the absolute values of x and y. uint256 ax; uint256 ay; unchecked { ax = x < 0 ? uint256(-x) : uint256(x); ay = y < 0 ? uint256(-y) : uint256(y); } // Compute the absolute value of (x*SCALE)÷y. The result must fit within int256. uint256 rAbs = PRBMath.mulDiv(ax, uint256(SCALE), ay); if (rAbs > uint256(MAX_SD59x18)) { revert PRBMathSD59x18__DivOverflow(rAbs); } // Get the signs of x and y. uint256 sx; uint256 sy; assembly { sx := sgt(x, sub(0, 1)) sy := sgt(y, sub(0, 1)) } // XOR over sx and sy. This is basically checking whether the inputs have the same sign. If yes, the result // should be positive. Otherwise, it should be negative. result = sx ^ sy == 1 ? -int256(rAbs) : int256(rAbs); } /// @notice Returns Euler's number as a signed 59.18-decimal fixed-point number. /// @dev See https://en.wikipedia.org/wiki/E_(mathematical_constant). function e() internal pure returns (int256 result) { result = 2_718281828459045235; } /// @notice Calculates the natural exponent of x. /// /// @dev Based on the insight that e^x = 2^(x * log2(e)). /// /// Requirements: /// - All from "log2". /// - x must be less than 133.084258667509499441. /// /// Caveats: /// - All from "exp2". /// - For any x less than -41.446531673892822322, the result is zero. /// /// @param x The exponent as a signed 59.18-decimal fixed-point number. /// @return result The result as a signed 59.18-decimal fixed-point number. function exp(int256 x) internal pure returns (int256 result) { // Without this check, the value passed to "exp2" would be less than -59.794705707972522261. if (x < -41_446531673892822322) { return 0; } // Without this check, the value passed to "exp2" would be greater than 192. if (x >= 133_084258667509499441) { revert PRBMathSD59x18__ExpInputTooBig(x); } // Do the fixed-point multiplication inline to save gas. unchecked { int256 doubleScaleProduct = x * LOG2_E; result = exp2((doubleScaleProduct + HALF_SCALE) / SCALE); } } /// @notice Calculates the binary exponent of x using the binary fraction method. /// /// @dev See https://ethereum.stackexchange.com/q/79903/24693. /// /// Requirements: /// - x must be 192 or less. /// - The result must fit within MAX_SD59x18. /// /// Caveats: /// - For any x less than -59.794705707972522261, the result is zero. /// /// @param x The exponent as a signed 59.18-decimal fixed-point number. /// @return result The result as a signed 59.18-decimal fixed-point number. function exp2(int256 x) internal pure returns (int256 result) { // This works because 2^(-x) = 1/2^x. if (x < 0) { // 2^59.794705707972522262 is the maximum number whose inverse does not truncate down to zero. if (x < -59_794705707972522261) { return 0; } // Do the fixed-point inversion inline to save gas. The numerator is SCALE * SCALE. unchecked { result = 1e36 / exp2(-x); } } else { // 2^192 doesn't fit within the 192.64-bit format used internally in this function. if (x >= 192e18) { revert PRBMathSD59x18__Exp2InputTooBig(x); } unchecked { // Convert x to the 192.64-bit fixed-point format. uint256 x192x64 = (uint256(x) << 64) / uint256(SCALE); // Safe to convert the result to int256 directly because the maximum input allowed is 192. result = int256(PRBMath.exp2(x192x64)); } } } /// @notice Yields the greatest signed 59.18 decimal fixed-point 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 must be greater than or equal to MIN_WHOLE_SD59x18. /// /// @param x The signed 59.18-decimal fixed-point number to floor. /// @param result The greatest integer less than or equal to x, as a signed 58.18-decimal fixed-point number. function floor(int256 x) internal pure returns (int256 result) { if (x < MIN_WHOLE_SD59x18) { revert PRBMathSD59x18__FloorUnderflow(x); } unchecked { int256 remainder = x % SCALE; if (remainder == 0) { result = x; } else { // Solidity uses C fmod style, which returns a modulus with the same sign as x. result = x - remainder; if (x < 0) { result -= SCALE; } } } } /// @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 signed 59.18-decimal fixed-point number to get the fractional part of. /// @param result The fractional part of x as a signed 59.18-decimal fixed-point number. function frac(int256 x) internal pure returns (int256 result) { unchecked { result = x % SCALE; } } /// @notice Converts a number from basic integer form to signed 59.18-decimal fixed-point representation. /// /// @dev Requirements: /// - x must be greater than or equal to MIN_SD59x18 divided by SCALE. /// - x must be less than or equal to MAX_SD59x18 divided by SCALE. /// /// @param x The basic integer to convert. /// @param result The same number in signed 59.18-decimal fixed-point representation. function fromInt(int256 x) internal pure returns (int256 result) { unchecked { if (x < MIN_SD59x18 / SCALE) { revert PRBMathSD59x18__FromIntUnderflow(x); } if (x > MAX_SD59x18 / SCALE) { revert PRBMathSD59x18__FromIntOverflow(x); } result = x * SCALE; } } /// @notice Calculates geometric mean of x and y, i.e. sqrt(x * y), rounding down. /// /// @dev Requirements: /// - x * y must fit within MAX_SD59x18, lest it overflows. /// - x * y cannot be negative. /// /// @param x The first operand as a signed 59.18-decimal fixed-point number. /// @param y The second operand as a signed 59.18-decimal fixed-point number. /// @return result The result as a signed 59.18-decimal fixed-point number. function gm(int256 x, int256 y) internal pure returns (int256 result) { if (x == 0) { return 0; } unchecked { // Checking for overflow this way is faster than letting Solidity do it. int256 xy = x * y; if (xy / x != y) { revert PRBMathSD59x18__GmOverflow(x, y); } // The product cannot be negative. if (xy < 0) { revert PRBMathSD59x18__GmNegativeProduct(x, y); } // We don't need to multiply by the SCALE here because the x*y product had already picked up a factor of SCALE // during multiplication. See the comments within the "sqrt" function. result = int256(PRBMath.sqrt(uint256(xy))); } } /// @notice Calculates 1 / x, rounding toward zero. /// /// @dev Requirements: /// - x cannot be zero. /// /// @param x The signed 59.18-decimal fixed-point number for which to calculate the inverse. /// @return result The inverse as a signed 59.18-decimal fixed-point number. function inv(int256 x) internal pure returns (int256 result) { unchecked { // 1e36 is SCALE * SCALE. result = 1e36 / x; } } /// @notice Calculates the natural logarithm of x. /// /// @dev Based on the insight that ln(x) = log2(x) / log2(e). /// /// Requirements: /// - All from "log2". /// /// Caveats: /// - All from "log2". /// - This doesn't return exactly 1 for 2718281828459045235, for that we would need more fine-grained precision. /// /// @param x The signed 59.18-decimal fixed-point number for which to calculate the natural logarithm. /// @return result The natural logarithm as a signed 59.18-decimal fixed-point number. function ln(int256 x) internal pure returns (int256 result) { // Do the fixed-point multiplication inline to save gas. This is overflow-safe because the maximum value that log2(x) // can return is 195205294292027477728. unchecked { result = (log2(x) * SCALE) / LOG2_E; } } /// @notice Calculates the common logarithm of x. /// /// @dev First checks if x is an exact power of ten and it stops if yes. If it's not, calculates the common /// logarithm based on the insight that log10(x) = log2(x) / log2(10). /// /// Requirements: /// - All from "log2". /// /// Caveats: /// - All from "log2". /// /// @param x The signed 59.18-decimal fixed-point number for which to calculate the common logarithm. /// @return result The common logarithm as a signed 59.18-decimal fixed-point number. function log10(int256 x) internal pure returns (int256 result) { if (x <= 0) { revert PRBMathSD59x18__LogInputTooSmall(x); } // Note that the "mul" in this block is the assembly mul operation, not the "mul" function defined in this contract. // prettier-ignore assembly { switch x case 1 { result := mul(SCALE, sub(0, 18)) } case 10 { result := mul(SCALE, sub(1, 18)) } case 100 { result := mul(SCALE, sub(2, 18)) } case 1000 { result := mul(SCALE, sub(3, 18)) } case 10000 { result := mul(SCALE, sub(4, 18)) } case 100000 { result := mul(SCALE, sub(5, 18)) } case 1000000 { result := mul(SCALE, sub(6, 18)) } case 10000000 { result := mul(SCALE, sub(7, 18)) } case 100000000 { result := mul(SCALE, sub(8, 18)) } case 1000000000 { result := mul(SCALE, sub(9, 18)) } case 10000000000 { result := mul(SCALE, sub(10, 18)) } case 100000000000 { result := mul(SCALE, sub(11, 18)) } case 1000000000000 { result := mul(SCALE, sub(12, 18)) } case 10000000000000 { result := mul(SCALE, sub(13, 18)) } case 100000000000000 { result := mul(SCALE, sub(14, 18)) } case 1000000000000000 { result := mul(SCALE, sub(15, 18)) } case 10000000000000000 { result := mul(SCALE, sub(16, 18)) } case 100000000000000000 { result := mul(SCALE, sub(17, 18)) } case 1000000000000000000 { result := 0 } case 10000000000000000000 { result := SCALE } case 100000000000000000000 { result := mul(SCALE, 2) } case 1000000000000000000000 { result := mul(SCALE, 3) } case 10000000000000000000000 { result := mul(SCALE, 4) } case 100000000000000000000000 { result := mul(SCALE, 5) } case 1000000000000000000000000 { result := mul(SCALE, 6) } case 10000000000000000000000000 { result := mul(SCALE, 7) } case 100000000000000000000000000 { result := mul(SCALE, 8) } case 1000000000000000000000000000 { result := mul(SCALE, 9) } case 10000000000000000000000000000 { result := mul(SCALE, 10) } case 100000000000000000000000000000 { result := mul(SCALE, 11) } case 1000000000000000000000000000000 { result := mul(SCALE, 12) } case 10000000000000000000000000000000 { result := mul(SCALE, 13) } case 100000000000000000000000000000000 { result := mul(SCALE, 14) } case 1000000000000000000000000000000000 { result := mul(SCALE, 15) } case 10000000000000000000000000000000000 { result := mul(SCALE, 16) } case 100000000000000000000000000000000000 { result := mul(SCALE, 17) } case 1000000000000000000000000000000000000 { result := mul(SCALE, 18) } case 10000000000000000000000000000000000000 { result := mul(SCALE, 19) } case 100000000000000000000000000000000000000 { result := mul(SCALE, 20) } case 1000000000000000000000000000000000000000 { result := mul(SCALE, 21) } case 10000000000000000000000000000000000000000 { result := mul(SCALE, 22) } case 100000000000000000000000000000000000000000 { result := mul(SCALE, 23) } case 1000000000000000000000000000000000000000000 { result := mul(SCALE, 24) } case 10000000000000000000000000000000000000000000 { result := mul(SCALE, 25) } case 100000000000000000000000000000000000000000000 { result := mul(SCALE, 26) } case 1000000000000000000000000000000000000000000000 { result := mul(SCALE, 27) } case 10000000000000000000000000000000000000000000000 { result := mul(SCALE, 28) } case 100000000000000000000000000000000000000000000000 { result := mul(SCALE, 29) } case 1000000000000000000000000000000000000000000000000 { result := mul(SCALE, 30) } case 10000000000000000000000000000000000000000000000000 { result := mul(SCALE, 31) } case 100000000000000000000000000000000000000000000000000 { result := mul(SCALE, 32) } case 1000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 33) } case 10000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 34) } case 100000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 35) } case 1000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 36) } case 10000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 37) } case 100000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 38) } case 1000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 39) } case 10000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 40) } case 100000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 41) } case 1000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 42) } case 10000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 43) } case 100000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 44) } case 1000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 45) } case 10000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 46) } case 100000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 47) } case 1000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 48) } case 10000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 49) } case 100000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 50) } case 1000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 51) } case 10000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 52) } case 100000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 53) } case 1000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 54) } case 10000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 55) } case 100000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 56) } case 1000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 57) } case 10000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 58) } default { result := MAX_SD59x18 } } if (result == MAX_SD59x18) { // Do the fixed-point division inline to save gas. The denominator is log2(10). unchecked { result = (log2(x) * SCALE) / 3_321928094887362347; } } } /// @notice Calculates the binary logarithm of x. /// /// @dev Based on the iterative approximation algorithm. /// https://en.wikipedia.org/wiki/Binary_logarithm#Iterative_approximation /// /// Requirements: /// - x must be greater than zero. /// /// Caveats: /// - The results are not perfectly accurate to the last decimal, due to the lossy precision of the iterative approximation. /// /// @param x The signed 59.18-decimal fixed-point number for which to calculate the binary logarithm. /// @return result The binary logarithm as a signed 59.18-decimal fixed-point number. function log2(int256 x) internal pure returns (int256 result) { if (x <= 0) { revert PRBMathSD59x18__LogInputTooSmall(x); } unchecked { // This works because log2(x) = -log2(1/x). int256 sign; if (x >= SCALE) { sign = 1; } else { sign = -1; // Do the fixed-point inversion inline to save gas. The numerator is SCALE * SCALE. assembly { x := div(1000000000000000000000000000000000000, x) } } // Calculate the integer part of the logarithm and add it to the result and finally calculate y = x * 2^(-n). uint256 n = PRBMath.mostSignificantBit(uint256(x / SCALE)); // The integer part of the logarithm as a signed 59.18-decimal fixed-point number. The operation can't overflow // because n is maximum 255, SCALE is 1e18 and sign is either 1 or -1. result = int256(n) * SCALE; // This is y = x * 2^(-n). int256 y = x >> n; // If y = 1, the fractional part is zero. if (y == SCALE) { return result * sign; } // Calculate the fractional part via the iterative approximation. // The "delta >>= 1" part is equivalent to "delta /= 2", but shifting bits is faster. for (int256 delta = int256(HALF_SCALE); delta > 0; delta >>= 1) { y = (y * y) / SCALE; // Is y^2 > 2 and so in the range [2,4)? if (y >= 2 * SCALE) { // Add the 2^(-m) factor to the logarithm. result += delta; // Corresponds to z/2 on Wikipedia. y >>= 1; } } result *= sign; } } /// @notice Multiplies two signed 59.18-decimal fixed-point numbers together, returning a new signed 59.18-decimal /// fixed-point number. /// /// @dev Variant of "mulDiv" that works with signed numbers and employs constant folding, i.e. the denominator is /// always 1e18. /// /// Requirements: /// - All from "PRBMath.mulDivFixedPoint". /// - None of the inputs can be MIN_SD59x18 /// - The result must fit within MAX_SD59x18. /// /// Caveats: /// - The body is purposely left uncommented; see the NatSpec comments in "PRBMath.mulDiv" to understand how this works. /// /// @param x The multiplicand as a signed 59.18-decimal fixed-point number. /// @param y The multiplier as a signed 59.18-decimal fixed-point number. /// @return result The product as a signed 59.18-decimal fixed-point number. function mul(int256 x, int256 y) internal pure returns (int256 result) { if (x == MIN_SD59x18 || y == MIN_SD59x18) { revert PRBMathSD59x18__MulInputTooSmall(); } unchecked { uint256 ax; uint256 ay; ax = x < 0 ? uint256(-x) : uint256(x); ay = y < 0 ? uint256(-y) : uint256(y); uint256 rAbs = PRBMath.mulDivFixedPoint(ax, ay); if (rAbs > uint256(MAX_SD59x18)) { revert PRBMathSD59x18__MulOverflow(rAbs); } uint256 sx; uint256 sy; assembly { sx := sgt(x, sub(0, 1)) sy := sgt(y, sub(0, 1)) } result = sx ^ sy == 1 ? -int256(rAbs) : int256(rAbs); } } /// @notice Returns PI as a signed 59.18-decimal fixed-point number. function pi() internal pure returns (int256 result) { result = 3_141592653589793238; } /// @notice Raises x to the power of y. /// /// @dev Based on the insight that x^y = 2^(log2(x) * y). /// /// Requirements: /// - All from "exp2", "log2" and "mul". /// - z cannot be zero. /// /// Caveats: /// - All from "exp2", "log2" and "mul". /// - Assumes 0^0 is 1. /// /// @param x Number to raise to given power y, as a signed 59.18-decimal fixed-point number. /// @param y Exponent to raise x to, as a signed 59.18-decimal fixed-point number. /// @return result x raised to power y, as a signed 59.18-decimal fixed-point number. function pow(int256 x, int256 y) internal pure returns (int256 result) { if (x == 0) { result = y == 0 ? SCALE : int256(0); } else { result = exp2(mul(log2(x), y)); } } /// @notice Raises x (signed 59.18-decimal fixed-point number) to the power of y (basic unsigned integer) using the /// famous algorithm "exponentiation by squaring". /// /// @dev See https://en.wikipedia.org/wiki/Exponentiation_by_squaring /// /// Requirements: /// - All from "abs" and "PRBMath.mulDivFixedPoint". /// - The result must fit within MAX_SD59x18. /// /// Caveats: /// - All from "PRBMath.mulDivFixedPoint". /// - Assumes 0^0 is 1. /// /// @param x The base as a signed 59.18-decimal fixed-point number. /// @param y The exponent as an uint256. /// @return result The result as a signed 59.18-decimal fixed-point number. function powu(int256 x, uint256 y) internal pure returns (int256 result) { uint256 xAbs = uint256(abs(x)); // Calculate the first iteration of the loop in advance. uint256 rAbs = y & 1 > 0 ? xAbs : uint256(SCALE); // Equivalent to "for(y /= 2; y > 0; y /= 2)" but faster. uint256 yAux = y; for (yAux >>= 1; yAux > 0; yAux >>= 1) { xAbs = PRBMath.mulDivFixedPoint(xAbs, xAbs); // Equivalent to "y % 2 == 1" but faster. if (yAux & 1 > 0) { rAbs = PRBMath.mulDivFixedPoint(rAbs, xAbs); } } // The result must fit within the 59.18-decimal fixed-point representation. if (rAbs > uint256(MAX_SD59x18)) { revert PRBMathSD59x18__PowuOverflow(rAbs); } // Is the base negative and the exponent an odd number? bool isNegative = x < 0 && y & 1 == 1; result = isNegative ? -int256(rAbs) : int256(rAbs); } /// @notice Returns 1 as a signed 59.18-decimal fixed-point number. function scale() internal pure returns (int256 result) { result = SCALE; } /// @notice Calculates the square root of x, rounding down. /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method. /// /// Requirements: /// - x cannot be negative. /// - x must be less than MAX_SD59x18 / SCALE. /// /// @param x The signed 59.18-decimal fixed-point number for which to calculate the square root. /// @return result The result as a signed 59.18-decimal fixed-point . function sqrt(int256 x) internal pure returns (int256 result) { unchecked { if (x < 0) { revert PRBMathSD59x18__SqrtNegativeInput(x); } if (x > MAX_SD59x18 / SCALE) { revert PRBMathSD59x18__SqrtOverflow(x); } // Multiply x by the SCALE to account for the factor of SCALE that is picked up when multiplying two signed // 59.18-decimal fixed-point numbers together (in this case, those two numbers are both the square root). result = int256(PRBMath.sqrt(uint256(x * SCALE))); } } /// @notice Converts a signed 59.18-decimal fixed-point number to basic integer form, rounding down in the process. /// @param x The signed 59.18-decimal fixed-point number to convert. /// @return result The same number in basic integer form. function toInt(int256 x) internal pure returns (int256 result) { unchecked { result = x / SCALE; } } }
{ "optimizer": { "enabled": true, "runs": 800 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"isolatedSubaccount","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"parentSubaccount","type":"bytes32"}],"name":"CloseIsolatedSubaccount","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"productId","type":"uint32"},{"indexed":true,"internalType":"bytes32","name":"digest","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"subaccount","type":"bytes32"},{"indexed":false,"internalType":"int128","name":"priceX18","type":"int128"},{"indexed":false,"internalType":"int128","name":"amount","type":"int128"},{"indexed":false,"internalType":"uint64","name":"expiration","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"nonce","type":"uint64"},{"indexed":false,"internalType":"bool","name":"isTaker","type":"bool"},{"indexed":false,"internalType":"int128","name":"feeAmount","type":"int128"},{"indexed":false,"internalType":"int128","name":"baseDelta","type":"int128"},{"indexed":false,"internalType":"int128","name":"quoteDelta","type":"int128"}],"name":"FillOrder","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"components":[{"components":[{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"int128","name":"priceX18","type":"int128"},{"internalType":"int128","name":"amount","type":"int128"},{"internalType":"uint64","name":"expiration","type":"uint64"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"int128","name":"margin","type":"int128"}],"internalType":"struct IEndpoint.IsolatedOrder","name":"order","type":"tuple"},{"internalType":"uint32","name":"productId","type":"uint32"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct IEndpoint.CreateIsolatedSubaccount","name":"txn","type":"tuple"},{"internalType":"address","name":"linkedSigner","type":"address"}],"name":"createIsolatedSubaccount","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"dumpFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"filledAmounts","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"users","type":"address[]"},{"internalType":"uint32[]","name":"productIds","type":"uint32[]"}],"name":"getAllFeeRates","outputs":[{"components":[{"internalType":"int64","name":"makerRateX18","type":"int64"},{"internalType":"int64","name":"takerRateX18","type":"int64"},{"internalType":"uint8","name":"isNonDefault","type":"uint8"}],"internalType":"struct IOffchainExchange.FeeRates[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllVirtualBooks","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"startAt","type":"uint32"},{"internalType":"uint32","name":"limit","type":"uint32"}],"name":"getCustomFeeAddresses","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"productId","type":"uint32"},{"components":[{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"int128","name":"priceX18","type":"int128"},{"internalType":"int128","name":"amount","type":"int128"},{"internalType":"uint64","name":"expiration","type":"uint64"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"internalType":"struct IEndpoint.Order","name":"order","type":"tuple"}],"name":"getDigest","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getEndpoint","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"subaccount","type":"bytes32"},{"internalType":"uint32","name":"productId","type":"uint32"},{"internalType":"bool","name":"taker","type":"bool"}],"name":"getFeeFractionX18","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"subaccount","type":"bytes32"},{"internalType":"uint32","name":"productId","type":"uint32"}],"name":"getFeeRatesX18","outputs":[{"internalType":"int128","name":"","type":"int128"},{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"productId","type":"uint32"},{"components":[{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"int128","name":"priceX18","type":"int128"},{"internalType":"int128","name":"amount","type":"int128"},{"internalType":"uint64","name":"expiration","type":"uint64"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"int128","name":"margin","type":"int128"}],"internalType":"struct IEndpoint.IsolatedOrder","name":"order","type":"tuple"}],"name":"getIsolatedDigest","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"subaccount","type":"bytes32"}],"name":"getIsolatedSubaccounts","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"productId","type":"uint32"}],"name":"getLpParams","outputs":[{"components":[{"internalType":"int128","name":"lpSpreadX18","type":"int128"}],"internalType":"struct IOffchainExchange.LpParams","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"productId","type":"uint32"}],"name":"getMarketInfo","outputs":[{"components":[{"internalType":"uint32","name":"quoteId","type":"uint32"},{"internalType":"int128","name":"minSize","type":"int128"},{"internalType":"int128","name":"sizeIncrement","type":"int128"},{"internalType":"int128","name":"collectedFees","type":"int128"}],"internalType":"struct IOffchainExchange.MarketInfo","name":"m","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"productId","type":"uint32"}],"name":"getMinSize","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"subaccount","type":"bytes32"}],"name":"getParentSubaccount","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"productId","type":"uint32"}],"name":"getSizeIncrement","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"productId","type":"uint32"}],"name":"getVirtualBook","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_clearinghouse","type":"address"},{"internalType":"address","name":"_endpoint","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"parent","type":"bytes32"},{"internalType":"bytes32","name":"subaccount","type":"bytes32"}],"name":"isIsolatedSubaccountActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"productId","type":"uint32"},{"internalType":"int128","name":"baseDelta","type":"int128"},{"internalType":"int128","name":"quoteDelta","type":"int128"},{"components":[{"components":[{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"int128","name":"priceX18","type":"int128"},{"internalType":"int128","name":"amount","type":"int128"},{"internalType":"uint64","name":"expiration","type":"uint64"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"internalType":"struct IEndpoint.Order","name":"order","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct IEndpoint.SignedOrder","name":"taker","type":"tuple"}],"internalType":"struct IEndpoint.MatchOrderAMM","name":"txn","type":"tuple"},{"internalType":"address","name":"takerLinkedSigner","type":"address"}],"name":"matchOrderAMM","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"uint32","name":"productId","type":"uint32"},{"components":[{"components":[{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"int128","name":"priceX18","type":"int128"},{"internalType":"int128","name":"amount","type":"int128"},{"internalType":"uint64","name":"expiration","type":"uint64"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"internalType":"struct IEndpoint.Order","name":"order","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct IEndpoint.SignedOrder","name":"taker","type":"tuple"},{"components":[{"components":[{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"int128","name":"priceX18","type":"int128"},{"internalType":"int128","name":"amount","type":"int128"},{"internalType":"uint64","name":"expiration","type":"uint64"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"internalType":"struct IEndpoint.Order","name":"order","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct IEndpoint.SignedOrder","name":"maker","type":"tuple"}],"internalType":"struct IEndpoint.MatchOrders","name":"matchOrders","type":"tuple"},{"internalType":"address","name":"takerLinkedSigner","type":"address"},{"internalType":"address","name":"makerLinkedSigner","type":"address"}],"internalType":"struct IEndpoint.MatchOrdersWithSigner","name":"txn","type":"tuple"}],"name":"matchOrders","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"uint32","name":"productId","type":"uint32"},{"internalType":"int128","name":"amount","type":"int128"},{"internalType":"int128","name":"priceX18","type":"int128"}],"internalType":"struct IEndpoint.SwapAMM","name":"txn","type":"tuple"}],"name":"swapAMM","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"subaccount","type":"bytes32"}],"name":"tryCloseIsolatedSubaccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint32","name":"productId","type":"uint32"},{"internalType":"int64","name":"makerRateX18","type":"int64"},{"internalType":"int64","name":"takerRateX18","type":"int64"}],"name":"updateFeeRates","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"productId","type":"uint32"},{"internalType":"uint32","name":"quoteId","type":"uint32"},{"internalType":"address","name":"virtualBook","type":"address"},{"internalType":"int128","name":"sizeIncrement","type":"int128"},{"internalType":"int128","name":"minSize","type":"int128"},{"internalType":"int128","name":"lpSpreadX18","type":"int128"}],"name":"updateMarket","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b50615a5c80620000216000396000f3fe608060405234801561001057600080fd5b50600436106101cf5760003560e01c806388bc796811610104578063b60aaa7c116100a2578063edc6d37b11610071578063edc6d37b146104cf578063f2b26331146104ef578063f2fde38b14610502578063f6ee7b4b1461051557600080fd5b8063b60aaa7c14610481578063b76d78e314610494578063ce933e59146104a7578063d895202a146104af57600080fd5b8063a27a250a116100de578063a27a250a14610437578063a5ae218b1461044a578063aed8e9671461045d578063b5cbd70e1461046e57600080fd5b806388bc7968146104005780638da5cb5b1461041357806395ee60711461042457600080fd5b806340f1a34d1161017157806366f87bd11161014b57806366f87bd114610396578063707c8b58146103dd578063715018a6146103e557806378f0d3ce146103ed57600080fd5b806340f1a34d146102f95780634821c8b51461032f578063485cc9551461038357600080fd5b80631a2b2d16116101ad5780631a2b2d16146102495780631d029b4d1461026c5780632da1c59b146102c65780633fceea28146102d957600080fd5b80630f2c878e146101d45780630f4b509d1461020657806313b56ddb1461021b575b600080fd5b6101e76101e2366004614a5a565b610528565b60408051600f93840b81529190920b6020820152015b60405180910390f35b610219610214366004614aa2565b6105c5565b005b61023b610229366004614abe565b600090815260a8602052604090205490565b6040519081526020016101fd565b61025c610257366004614ad7565b6109e1565b60405190151581526020016101fd565b61027f61027a366004614af9565b610a36565b6040516101fd9190600060808201905063ffffffff83511682526020830151600f0b60208301526040830151600f0b60408301526060830151600f0b606083015292915050565b6102196102d4366004614b4a565b610af7565b6102ec6102e7366004614bcc565b610cb9565b6040516101fd9190614bfa565b61031c610307366004614abe565b609e60205260009081526040902054600f0b81565b604051600f9190910b81526020016101fd565b61037161033d366004614af9565b604080516020808201835260009182905263ffffffff939093168152609d8352819020815192830190915254600f0b815290565b6040519051600f0b81526020016101fd565b610219610391366004614c47565b610de9565b6103c56103a4366004614af9565b63ffffffff166000908152609c60205260409020546001600160a01b031690565b6040516001600160a01b0390911681526020016101fd565b6102196110ae565b610219611538565b6102196103fb366004614c75565b61154c565b61021961040e366004614cbc565b6118d0565b6033546001600160a01b03166103c5565b61023b610432366004614de4565b611ec0565b61023b610445366004614f2c565b612040565b61023b610458366004614fde565b6124e9565b6065546001600160a01b03166103c5565b61031c61047c36600461500b565b612580565b61031c61048f366004614af9565b612620565b6102196104a2366004615064565b612647565b6102ec612afd565b6104c26104bd366004615149565b612dc8565b6040516101fd919061520b565b6104e26104dd366004614abe565b612f60565b6040516101fd919061526e565b61031c6104fd366004614af9565b613062565b6102196105103660046152a6565b613090565b610219610523366004614abe565b613120565b606082811c600090815260a16020908152604080832063ffffffff8616845282528083208151948501825254600781810b8652600160401b8204900b92850192909252600160801b90910460ff169083018190529091829182036105ab5750604080516060810182526000815265b5e620f4800060208201526001918101919091525b60208101519051600791820b9350900b90505b9250929050565b6065546001600160a01b031633146106375760405162461bcd60e51b815260206004820152602a60248201527f53657175656e63657247617465643a2063616c6c6572206973206e6f742074686044820152691948195b991c1bda5b9d60b21b60648201526084015b60405180910390fd5b6040805180820190915260018152605560f81b60208201526269736f823562ffffff16036106785760405162461bcd60e51b815260040161062e91906152c3565b50600061068e61027a6040840160208501614af9565b905060006106aa6106a56040850160208601614af9565b61316e565b905060006106be6080850160608601615318565b600f0b136040518060400160405280600381526020016224a82960e91b815250906106fc5760405162461bcd60e51b815260040161062e91906152c3565b5080604001511561076757816040015183604001602081019061071f9190615318565b610729919061534b565b60408051808201909152600381526204953560ec1b602082015290600f0b156107655760405162461bcd60e51b815260040161062e91906152c3565b505b6000816040015161077c57816020015161077f565b81515b90506000806001600160a01b03831663c7167cf56107a36040890160208a01614af9565b6107b360608a0160408b01615318565b6107df6107c660808c0160608d01615318565b6107d660608d0160408e01615318565b600f0b90613290565b6107e890615383565b6040516001600160e01b031960e086901b16815263ffffffff939093166004840152600f91820b6024840152900b604482015260640160408051808303816000875af115801561083c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061086091906153a9565b915091508161086e90615383565b915061087981615383565b905060006108c36108906040890160208a01614af9565b88358886866000600f83900b136108b4578b602001516108af90615383565b6108ba565b8b602001515b6000600161330b565b87519093509091506108da90869089358686613330565b609a546040516388b6496f60e01b81526000916001600160a01b0316906388b6496f9061090e908b359085906004016153ee565b602060405180830381865afa15801561092b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061094f9190615412565b600f0b121560405180604001604052806002815260200161125560f21b8152509061098d5760405162461bcd60e51b815260040161062e91906152c3565b506060860151609b60006109a760408b0160208c01614af9565b63ffffffff168152602081019190915260400160002080546001600160801b03928316600160801b02921691909117905550505050505050565b6000805b600a811015610a2a57600084815260a9602090815260408083208484529091529020548303610a18576001915050610a30565b80610a228161542f565b9150506109e5565b50600090505b92915050565b6040805160808101825260008082526020808301829052828401829052606080840183815263ffffffff878116808652609b85528786208851948501895254600781810b8652600160401b8204810b86880152600160801b909104600f90810b868b0190815292885260a49096529790952054168552925190910b909152805191929091610ac9910b633b9aca00615448565b600f0b602080840191909152810151610ae99060070b633b9aca00615448565b600f0b604083015250919050565b610aff61351d565b6001600160a01b03841615610ba95763ffffffff86166000908152609c60205260409020546001600160a01b031615610b7a5760405162461bcd60e51b815260206004820152601860248201527f7669727475616c20626f6f6b20616c7265616479207365740000000000000000604482015260640161062e565b63ffffffff86166000908152609c6020526040902080546001600160a01b0319166001600160a01b0386161790555b63ffffffff85811614610bdf5763ffffffff868116600090815260a460205260409020805463ffffffff19169187169190911790555b610bed633b9aca00836154e6565b63ffffffff87166000908152609b60205260409020805467ffffffffffffffff191667ffffffffffffffff92909216919091179055610c30633b9aca00846154e6565b63ffffffff969096166000818152609b6020908152604080832080546fffffffffffffffff00000000000000001916600160401b67ffffffffffffffff909c169b909b029a909a1790995588518082018a52600f9490940b8452918152609d90915295909520945185546001600160801b0319166001600160801b039091161790945550505050565b60606000610cc7838561552d565b60a35490915063ffffffff8082169083161115610ce2578091505b8063ffffffff168563ffffffff161115610cfa578094505b6000610d068684615555565b63ffffffff1667ffffffffffffffff811115610d2457610d24614cf7565b604051908082528060200260200182016040528015610d4d578160200160208202803683370190505b509050855b8363ffffffff168163ffffffff161015610ddf5760a38163ffffffff1681548110610d7f57610d7f61557a565b6000918252602090912001546001600160a01b031682610d9f8984615555565b63ffffffff1681518110610db557610db561557a565b6001600160a01b039092166020928302919091019091015280610dd781615590565b915050610d52565b5095945050505050565b600054610100900460ff1615808015610e095750600054600160ff909116105b80610e235750303b158015610e23575060005460ff166001145b610e955760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840161062e565b6000805460ff191660011790558015610eb8576000805461ff0019166101001790555b610ec061358c565b610ec9826135ff565b610f3d6040518060400160405280600681526020017f56657274657800000000000000000000000000000000000000000000000000008152506040518060400160405280600581526020017f302e302e31000000000000000000000000000000000000000000000000000000815250613629565b609a80546001600160a01b0319166001600160a01b038516908117909155604051635d2e9ad160e01b8152635d2e9ad190610f7d906000906004016155b3565b602060405180830381865afa158015610f9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fbe91906155cd565b609f80546001600160a01b0319166001600160a01b03928316179055609a54604051635d2e9ad160e01b8152911690635d2e9ad190611002906001906004016155b3565b602060405180830381865afa15801561101f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061104391906155cd565b60a080546001600160a01b0319166001600160a01b039290921691909117905580156110a9576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b6065546001600160a01b0316331461111b5760405162461bcd60e51b815260206004820152602a60248201527f53657175656e63657247617465643a2063616c6c6572206973206e6f742074686044820152691948195b991c1bda5b9d60b21b606482015260840161062e565b609f54604080516347428e7b60e01b815290516000926001600160a01b0316916347428e7b91600480830192869291908290030181865afa158015611164573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261118c91908101906155ea565b905060015b81518163ffffffff161015611326576000828263ffffffff16815181106111ba576111ba61557a565b60209081029190910181015163ffffffff81166000908152609b8352604080822081516060810183529054600781810b8352600160401b8204900b95820195909552600160801b909404600f0b9084018190529193501261121c575050611314565b609f5463ffffffff838116600090815260a460205260408082205485820151915163e0b0621f60e01b8152931660048401526024830191909152600f0b60448201526001600160a01b039091169063e0b0621f90606401600060405180830381600087803b15801561128d57600080fd5b505af11580156112a1573d6000803e3d6000fd5b50506000604080850182815263ffffffff9096168252609b6020908152912084518154929095015195516001600160801b03908116600160801b0267ffffffffffffffff978816600160401b026001600160801b0319909416979096169690961791909117949094169290921790925550505b8061131e81615590565b915050611191565b5060a060009054906101000a90046001600160a01b03166001600160a01b03166347428e7b6040518163ffffffff1660e01b8152600401600060405180830381865afa15801561137a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526113a291908101906155ea565b905060005b81518163ffffffff161015611534576000828263ffffffff16815181106113d0576113d061557a565b60209081029190910181015163ffffffff81166000908152609b8352604080822081516060810183529054600781810b8352600160401b8204900b95820195909552600160801b909404600f0b90840181905291935003611432575050611522565b60a054604082810151905163f8a42e5160e01b815263ffffffff851660048201526000602482018190526044820152600f9190910b60648201526001600160a01b039091169063f8a42e5190608401600060405180830381600087803b15801561149b57600080fd5b505af11580156114af573d6000803e3d6000fd5b50506000604080850182815263ffffffff9096168252609b6020908152912084518154929095015195516001600160801b03908116600160801b0267ffffffffffffffff978816600160401b026001600160801b0319909416979096169690961791909117949094169290921790925550505b8061152c81615590565b9150506113a7565b5050565b61154061369e565b61154a60006136f8565b565b6065546001600160a01b031633146115b95760405162461bcd60e51b815260206004820152602a60248201527f53657175656e63657247617465643a2063616c6c6572206973206e6f742074686044820152691948195b991c1bda5b9d60b21b606482015260840161062e565b60006115cb6106a56020850185614af9565b905060006115df61027a6020860186614af9565b905060006116106115f36020870187614af9565b6116006060880188615684565b61043290368190038101906156a4565b905060006116216060870187615684565b611632906060810190604001615318565b905060006116436060880188615684565b61164c906156c0565b80515190915062ffffff166269736f1415604051806040016040528060018152602001605560f81b815250906116955760405162461bcd60e51b815260040161062e91906152c3565b506116a3858583868a61374a565b60405180604001604052806002815260200161125560f21b815250906116dc5760405162461bcd60e51b815260040161062e91906152c3565b5060008061170a876116f460408c0160208d01615318565b61170460608d0160408e01615318565b866139f0565b9092509050600061176561172160208c018c614af9565b855180516040909101518a9087908790829061173d908d615733565b6117479190615733565b611755600f8a900b8b613c7a565b61175e90615383565b600161330b565b885186515191945091925061177d918a918686613330565b604080518082019091526002815261125560f21b602082015250835151866117a860208d018d614af9565b865160208082015160608084015160809485015160408051600f95860b81528f860b9681019690965267ffffffffffffffff92831690860152169083015260019282019290925285820b60a082015287820b60c08201529086900b60e082015263ffffffff91909116907f7c57459d6f4f0fb2fc5b1e298c8c0eb238422944964aa1e249eaa78747f0cca9906101000160405180910390a46060870151609b600061185660208e018e614af9565b63ffffffff1681526020810191909152604090810160002080546001600160801b03938416600160801b02931692909217909155845101516118989086615733565b6000968752609e602052604090962080546001600160801b0319166001600160801b0390971696909617909555505050505050505050565b6065546001600160a01b0316331461193d5760405162461bcd60e51b815260206004820152602a60248201527f53657175656e63657247617465643a2063616c6c6572206973206e6f742074686044820152691948195b991c1bda5b9d60b21b606482015260840161062e565b600061195a61194c8380615783565b6106a5906020810190614af9565b6040805160608101825260008082526020820181905291810182905291925090819081908190600061198f8760600151610a36565b9050600061199d8980615783565b6119ab906020810190615684565b6119b4906156c0565b905060006119c28a80615783565b6119d0906040810190615684565b6119d9906156c0565b905060405180606001604052806119f88b606001518560000151611ec0565b8152602001611a0f8b606001518460000151611ec0565b81528251604090810151600f0b6020928301528251600090815260aa90925290205490945015611a4e578351600090815260aa60205260409020548251525b602080850151600090815260aa909152604090205415611a8157602080850151600090815260aa90915260409020548151525b8160000151604001519750611aaf89848487600001518e6020016020810190611aaa91906152a6565b61374a565b60405180604001604052806002815260200161125560f21b81525090611ae85760405162461bcd60e51b815260040161062e91906152c3565b50611b0789848387602001518e6040016020810190611aaa91906152a6565b60405180604001604052806002815260200161494d60f01b81525090611b405760405162461bcd60e51b815260040161062e91906152c3565b5081516040908101518251820151825180840190935260048352634f43424d60e01b60208401526000600f91820b81129290910b1303611b935760405162461bcd60e51b815260040161062e91906152c3565b506000816000015160400151600f0b1315611c0357816000015160200151600f0b816000015160200151600f0b1215604051806040016040528060048152602001634f43424d60e01b81525090611bfd5760405162461bcd60e51b815260040161062e91906152c3565b50611c5a565b816000015160200151600f0b816000015160200151600f0b1315604051806040016040528060048152602001634f43424d60e01b81525090611c585760405162461bcd60e51b815260040161062e91906152c3565b505b611c6f89848460000151846000015188613ce3565b8096508197505050611cb789606001518360000151600001518589898b8860000151604001518f611ca09190615733565b611caa9190615733565b875160200151600161330b565b8451845151929950909650611cd0918b91908989613330565b604080518082019091526002815261125560f21b602082015250604080518082019091526002815261494d60f01b602082015250606080840151908a015163ffffffff166000908152609b6020526040902080546001600160801b03928316600160801b029216919091179055815151600114611d8657815160400151611d579089615733565b84516000908152609e6020526040902080546001600160801b0319166001600160801b03929092169190911790555b805151600114611ddb578060000151604001518460400151611da89190615733565b6020858101516000908152609e9091526040902080546001600160801b0319166001600160801b03929092169190911790555b815151611de790613eba565b805151611df390613eba565b81600001516000015184600001518a6060015163ffffffff167f7c57459d6f4f0fb2fc5b1e298c8c0eb238422944964aa1e249eaa78747f0cca98560000151602001518c87600001516060015188600001516080015160018f8f8f604051611eac989796959493929190600f98890b815296880b602088015267ffffffffffffffff95861660408801529390941660608601529015156080850152840b60a084015290830b60c083015290910b60e08201526101000190565b60405180910390a450505050505050505050565b60008060405180608001604052806052815260200161596d6052913990506000818051906020012084600001518560200151866040015187606001518860800151604051602001611f4a969594939291909586526020860194909452600f92830b6040860152910b606084015267ffffffffffffffff90811660808401521660a082015260c00190565b60405160208183030381529060405280519060200120905060007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f611f8e60665490565b60675463ffffffff89166000908152609c6020908152604091829020548251918201959095529081019290925260608201524660808201526001600160a01b0390911660a082015260c001604051602081830303815290604052805190602001209050612036818360405161190160f01b6020820152602281018390526042810182905260009060620160405160208183030381529060405280519060200120905092915050565b9695505050505050565b6065546000906001600160a01b031633146120b05760405162461bcd60e51b815260206004820152602a60248201527f53657175656e63657247617465643a2063616c6c6572206973206e6f742074686044820152691948195b991c1bda5b9d60b21b606482015260840161062e565b82515162ffffff166269736f1415604051806040016040528060018152602001605560f81b815250906120f65760405162461bcd60e51b815260040161062e91906152c3565b50600061210b846020015185600001516124e9565b9050612125846000015160000151828587604001516142a9565b60405180604001604052806002815260200161495360f01b8152509061215e5760405162461bcd60e51b815260040161062e91906152c3565b5083515160601c600081815260a7602052604081205490805b82816001901b116121f2576001811b8316156121e057875151600090815260a96020908152604080832084845290915290205480156121de5760006121bb82614309565b9050896020015163ffffffff168163ffffffff16036121dc575091506121f2565b505b505b6121eb600182615799565b9050612177565b50806123085761220560016104006157b1565b82036122535760405162461bcd60e51b815260206004820152601d60248201527f546f6f206d616e792069736f6c61746564207375626163636f756e7473000000604482015260640161062e565b60005b600183161561227657600192831c9261226f90826157c8565b9050612256565b6020888101516001600160a01b038616600090815260a7835260408082208054600160ff881690811b9091179091558c515160189690961b63ff0000001693851b67ffffffff000000001660608a901b6bffffffffffffffffffffffff191617939093176269736f1780835260a88552818320959095558b5151825260a9845280822092825291909252902081905590505b600061238088602001516040518060a001604052808b600001516000015181526020018b6000015160200151600f0b81526020018b6000015160400151600f0b81526020018b600001516060015167ffffffffffffffff1681526020018b600001516080015167ffffffffffffffff16815250611ec0565b600081815260aa60205260408120849055895160a00151919250600f9190910b13156124de57875160a090810151600083815260ab6020526040812080546001600160801b0319166001600160801b0390931692909217909155609f548a5180519301516001600160a01b039091169263e0b0621f929161240090615383565b6040516001600160e01b031960e086901b16815263ffffffff9390931660048401526024830191909152600f0b6044820152606401600060405180830381600087803b15801561244f57600080fd5b505af1158015612463573d6000803e3d6000fd5b5050609f548a5160a0015160405163e0b0621f60e01b81526000600482015260248101879052600f9190910b60448201526001600160a01b03909116925063e0b0621f9150606401600060405180830381600087803b1580156124c557600080fd5b505af11580156124d9573d6000803e3d6000fd5b505050505b509695505050505050565b6000806040518060a00160405280606881526020016159bf60689139905060008180519060200120846000015185602001518660400151876060015188608001518960a00151604051602001611f4a97969594939291909687526020870195909552600f93840b604087015291830b606086015267ffffffffffffffff90811660808601521660a08401520b60c082015260e00190565b606083811c600090815260a16020908152604080832063ffffffff8716845282528083208151948501825254600781810b8652600160401b8204900b92850192909252600160801b90910460ff1690830181905290919082036126025750604080516060810182526000815265b5e620f4800060208201526001918101919091525b8261260e578051612614565b80602001515b60070b95945050505050565b63ffffffff81166000908152609b6020526040812054610a309060070b633b9aca00615448565b6065546001600160a01b031633146126b45760405162461bcd60e51b815260206004820152602a60248201527f53657175656e63657247617465643a2063616c6c6572206973206e6f742074686044820152691948195b991c1bda5b9d60b21b606482015260840161062e565b6001600160a01b038416600090815260a2602052604090205460ff1661273a576001600160a01b038416600081815260a260205260408120805460ff1916600190811790915560a3805491820181559091527f60859188cffe297f44dde29f2d2865634621f26215049caeb304ccba566a8b170180546001600160a01b03191690911790555b63ffffffff8316612a6557609f54604080516347428e7b60e01b815290516000926001600160a01b0316916347428e7b91600480830192869291908290030181865afa15801561278e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526127b691908101906155ea565b9050600060a060009054906101000a90046001600160a01b03166001600160a01b03166347428e7b6040518163ffffffff1660e01b8152600401600060405180830381865afa15801561280d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261283591908101906155ea565b905060005b82518163ffffffff16101561296457600063ffffffff16838263ffffffff16815181106128695761286961557a565b602002602001015163ffffffff1603156129525760405180606001604052808660070b81526020018560070b8152602001600160ff1681525060a16000896001600160a01b03166001600160a01b031681526020019081526020016000206000858463ffffffff16815181106128e1576128e161557a565b60209081029190910181015163ffffffff1682528181019290925260409081016000208351815493850151949092015160ff16600160801b0260ff60801b1967ffffffffffffffff958616600160401b026001600160801b0319909516959093169490941792909217169190911790555b8061295c81615590565b91505061283a565b5060005b81518163ffffffff161015612a5d5760405180606001604052808660070b81526020018560070b8152602001600160ff1681525060a16000896001600160a01b03166001600160a01b031681526020019081526020016000206000848463ffffffff16815181106129db576129db61557a565b60209081029190910181015163ffffffff1682528181019290925260409081016000208351815493850151949092015160ff16600160801b0260ff60801b1967ffffffffffffffff958616600160401b026001600160801b03199095169590931694909417929092171691909117905580612a5581615590565b915050612968565b505050612af7565b60408051606081018252600784810b825283900b602080830191825260018385019081526001600160a01b038916600090815260a1835285812063ffffffff8a168252909252939020915182549151935160ff16600160801b0260ff60801b1967ffffffffffffffff958616600160401b026001600160801b0319909416959092169490941791909117169190911790555b50505050565b60606000609f60009054906101000a90046001600160a01b03166001600160a01b03166347428e7b6040518163ffffffff1660e01b8152600401600060405180830381865afa158015612b54573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612b7c91908101906155ea565b9050600060a060009054906101000a90046001600160a01b03166001600160a01b03166347428e7b6040518163ffffffff1660e01b8152600401600060405180830381865afa158015612bd3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612bfb91908101906155ea565b90506000805b83518163ffffffff161015612c78578163ffffffff16848263ffffffff1681518110612c2f57612c2f61557a565b602002602001015163ffffffff161115612c6657838163ffffffff1681518110612c5b57612c5b61557a565b602002602001015191505b80612c7081615590565b915050612c01565b5060005b82518163ffffffff161015612cf3578163ffffffff16838263ffffffff1681518110612caa57612caa61557a565b602002602001015163ffffffff161115612ce157828163ffffffff1681518110612cd657612cd661557a565b602002602001015191505b80612ceb81615590565b915050612c7c565b506000612d0182600161552d565b63ffffffff1667ffffffffffffffff811115612d1f57612d1f614cf7565b604051908082528060200260200182016040528015612d48578160200160208202803683370190505b50905060005b8263ffffffff168163ffffffff1611612dbf5763ffffffff81166000818152609c602052604090205483516001600160a01b039091169184918110612d9557612d9561557a565b6001600160a01b039092166020928302919091019091015280612db781615590565b915050612d4e565b50949350505050565b6060600082518451612dda91906157ed565b67ffffffffffffffff811115612df257612df2614cf7565b604051908082528060200260200182016040528015612e3d57816020015b6040805160608101825260008082526020808301829052928201528252600019909201910181612e105790505b50905060005b8451811015612f585760005b8451811015612f455760a16000878481518110612e6e57612e6e61557a565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000206000868381518110612eaa57612eaa61557a565b60209081029190910181015163ffffffff16825281810192909252604090810160002081516060810183529054600781810b8352600160401b8204900b93820193909352600160801b90920460ff1690820152855184908390612f0d90866157ed565b612f179190615799565b81518110612f2757612f2761557a565b60200260200101819052508080612f3d9061542f565b915050612e4f565b5080612f508161542f565b915050612e43565b509392505050565b60606000805b600a811015612fb057600084815260a9602090815260408083208484529091529020548015612f9d57612f9a600184615799565b92505b5080612fa88161542f565b915050612f66565b5060008167ffffffffffffffff811115612fcc57612fcc614cf7565b604051908082528060200260200182016040528015612ff5578160200160208202803683370190505b50905060005b600a811015612f5857600085815260a960209081526040808320848452909152902054801561304f57808361302f8661580c565b955085815181106130425761304261557a565b6020026020010181815250505b508061305a8161542f565b915050612ffb565b63ffffffff81166000908152609b6020526040812054610a3090600160401b900460070b633b9aca00615448565b61309861369e565b6001600160a01b0381166131145760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161062e565b61311d816136f8565b50565b609a546040805180820190915260018152605560f81b6020820152906001600160a01b031633146131645760405162461bcd60e51b815260040161062e91906152c3565b5061311d81613eba565b604080516080810182526000808252602082018190529181018290526060810191909152609a5460405163deb14ec360e01b815263ffffffff841660048201526000916001600160a01b03169063deb14ec390602401602060405180830381865afa1580156131e1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061320591906155cd565b60a0549091506001600160a01b039081169082168190036132565750604080516080810182526001600160a01b0390921682526000602083015260019082015263ffffffff90921660608301525090565b5050604080516080810182526000808252609f546001600160a01b031660208301529181019190915263ffffffff90921660608301525090565b600080670de0b6b3a7640000600f85810b9085900b025b0590506f7fffffffffffffffffffffffffffffff1981128015906132d2575060016001607f1b038113155b6040518060400160405280600281526020016127a360f11b81525090612f585760405162461bcd60e51b815260040161062e91906152c3565b60008061331e8a8a8a8a8a8a8a8a61432d565b915091505b9850989650505050505050565b8460400151156133c1578451606086015160405163f8a42e5160e01b815263ffffffff909116600482015260248101859052600f84810b604483015283900b60648201526001600160a01b039091169063f8a42e51906084015b600060405180830381600087803b1580156133a457600080fd5b505af11580156133b8573d6000803e3d6000fd5b50505050613516565b63ffffffff8416613423576020850151606086015160405163f8a42e5160e01b815263ffffffff909116600482015260248101859052600f84810b604483015283900b60648201526001600160a01b039091169063f8a42e519060840161338a565b6020850151606086015160405163e0b0621f60e01b815263ffffffff909116600482015260248101859052600f84900b60448201526001600160a01b039091169063e0b0621f90606401600060405180830381600087803b15801561348757600080fd5b505af115801561349b573d6000803e3d6000fd5b505050602086015160405163e0b0621f60e01b815263ffffffff8716600482015260248101869052600f84900b60448201526001600160a01b03909116915063e0b0621f90606401600060405180830381600087803b1580156134fd57600080fd5b505af1158015613511573d6000803e3d6000fd5b505050505b5050505050565b609f546001600160a01b0316331480613540575060a0546001600160a01b031633145b61154a5760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c7920656e67696e652063616e206d6f6469667920636f6e666967000000604482015260640161062e565b600054610100900460ff166135f75760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b606482015260840161062e565b61154a6144a2565b61360761369e565b606580546001600160a01b0319166001600160a01b0392909216919091179055565b600054610100900460ff166136945760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b606482015260840161062e565b6115348282614516565b6033546001600160a01b0316331461154a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161062e565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b82515160009060001901613760575060016139e7565b8351805160009061377090614309565b905063ffffffff8116156137cb578063ffffffff16886060015163ffffffff1614604051806040016040528060018152602001605560f81b815250906137c95760405162461bcd60e51b815260040161062e91906152c3565b505b6000858152609e602052604090819020549083018051600f9290920b918291906137f6908390615733565b600f0b9052506060830151603d1c6001908116036139ae576000896040015161389f5760208a015160608b01518551604051637c1e148760e01b815263ffffffff909216600483015260248201526001600160a01b0390911690637c1e1487906044016040805180830381865afa158015613875573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138999190615823565b5161391f565b895160608b01518551604051637c1e148760e01b815263ffffffff909216600483015260248201526001600160a01b0390911690637c1e148790604401606060405180830381865afa1580156138f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061391d9190615882565b515b9050600081600f0b13151560008560400151600f0b1315150361394857600060408501526139ac565b60008460400151600f0b131561397c5761396f84604001518261396a90615383565b61459b565b600f0b60408501526139ac565b60008460400151600f0b12156139ac576139a384604001518261399e90615383565b6145b9565b600f0b60408501525b505b60008360200151600f0b1380156139cb57506040830151600f0b15155b80156139e157506139df83606001516145ce565b155b93505050505b95945050505050565b60008080613a0d613a05600f87900b88613c7a565b600f0b6145ff565b90506000846000015160400151600f0b1315613adb57836000015160200151600f0b81600f0b1315604051806040016040528060048152602001634f43424d60e01b81525090613a705760405162461bcd60e51b815260040161062e91906152c3565b50600086600f0b128015613a9a5750613a8886615383565b600f0b846000015160400151600f0b12155b604051806040016040528060048152602001634f43424d60e01b81525090613ad55760405162461bcd60e51b815260040161062e91906152c3565b50613b8f565b836000015160200151600f0b81600f0b1215604051806040016040528060048152602001634f43424d60e01b81525090613b285760405162461bcd60e51b815260040161062e91906152c3565b50600086600f0b138015613b525750613b4086615383565b600f0b846000015160400151600f0b13155b604051806040016040528060048152602001634f43424d60e01b81525090613b8d5760405162461bcd60e51b815260040161062e91906152c3565b505b60008760400151613ba4578760200151613ba7565b87515b606089015160405163c7167cf560e01b815263ffffffff9091166004820152600f89810b602483015288900b604482015290915060009081906001600160a01b0384169063c7167cf59060640160408051808303816000875af1158015613c12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c3691906153a9565b91509150818760000151604001818151613c5091906158f4565b600f0b905250613c5f82615383565b613c6882615383565b95509550505050505b94509492505050565b600081600f0b600014156040518060400160405280600381526020016222212d60e91b81525090613cbe5760405162461bcd60e51b815260040161062e91906152c3565b50600082600f0b670de0b6b3a7640000600f0b85600f0b02816132a7576132a7615335565b60008060008560400151600f0b1215613d1357613d0c8560400151856040015161399e90615383565b9150613d44565b60008560400151600f0b1315613d3957613d0c8560400151856040015161396a90615383565b506000905080613eb0565b6040860151613d53908361534b565b613d5d9083615733565b91506000613d7b856020015184600f0b61329090919063ffffffff16565b9050613d8681615383565b91506000613dad896060015187600001518a87613da290615383565b86600080600061330b565b80935081925050508387604001818151613dc79190615733565b600f0b905250604086018051859190613de19083906158f4565b600f0b90525087518651613e00918b91613dfa88615383565b86613330565b856000015185602001518a6060015163ffffffff167f7c57459d6f4f0fb2fc5b1e298c8c0eb238422944964aa1e249eaa78747f0cca9896020015189604001518b606001518c608001516000898d613e5790615383565b60408051600f98890b815296880b602088015267ffffffffffffffff9586169087015293909216606085015215156080840152830b60a0830152820b60c08201529087900b60e08201526101000160405180910390a450505b9550959350505050565b6000613ec582614309565b90508063ffffffff16600003613ed9575050565b60a054604051637c1e148760e01b815263ffffffff83166004820152602481018490526000916001600160a01b031690637c1e148790604401606060405180830381865afa158015613f2f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f539190615882565b8051909150600f0b6000036110a9576000613f6d84614669565b600085815260a8602090815260409091205490840151919250606086901c91600f0b156140af5760a05460208501516001600160a01b039091169063f8a42e519087908990600090613fbe90615383565b6040516001600160e01b031960e087901b16815263ffffffff9490941660048501526024840192909252600f90810b60448401520b6064820152608401600060405180830381600087803b15801561401557600080fd5b505af1158015614029573d6000803e3d6000fd5b505060a054602087015160405163f8a42e5160e01b815263ffffffff8a1660048201526024810186905260006044820152600f9190910b60648201526001600160a01b03909116925063f8a42e519150608401600060405180830381600087803b15801561409657600080fd5b505af11580156140aa573d6000803e3d6000fd5b505050505b609f54604051637c1e148760e01b815260006004820181905260248201899052916001600160a01b031690637c1e1487906044016040805180830381865afa1580156140ff573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141239190615823565b519050600f81900b1561422457609f546001600160a01b031663e0b0621f60008961414d85615383565b6040516001600160e01b031960e086901b16815263ffffffff9390931660048401526024830191909152600f0b6044820152606401600060405180830381600087803b15801561419c57600080fd5b505af11580156141b0573d6000803e3d6000fd5b5050609f5460405163e0b0621f60e01b81526000600482015260248101869052600f85900b60448201526001600160a01b03909116925063e0b0621f9150606401600060405180830381600087803b15801561420b57600080fd5b505af115801561421f573d6000803e3d6000fd5b505050505b6001600160a01b038316600090815260a7602090815260408083208054600160ff8a1690811b6000191890911690915585845260a98352818420908452825280832083905589835260a890915280822082905551839189917f027ce6fbfb5b4d17a0ee36b592ef0db77b060df7e023bc84e68c5f0664c9b83a9190a350505050505050565b6000806142b6858461468c565b90506001600160a01b0381161580159061203657508515806142e457506001600160a01b038116606087901c145b806120365750836001600160a01b0316816001600160a01b0316149695505050505050565b600062ffffff82166269736f1461432257506000919050565b5060201c61ffff1690565b600080600019890161434457506000905084613323565b600083156143ff5785600f0b60000361438d57602089015161436990600f0b86613290565b61437390826158f4565b9050600087600f0b121561438d5761438a81615383565b90505b600061439b89600f0b6145ff565b905060008a602001516143b88b8a6143b391906158f4565b6146a8565b6143c29190615733565b90506143ce818361459b565b9050600081600f0b13156143f8576143eb600f8a900b82846146c3565b6143f590846158f4565b92505b505061440c565b61440987826158f4565b90505b60006144198b8d87612580565b61442b90670de0b6b3a7640000615733565b905060008083600f0b1361444c57614447600f84900b83613c7a565b61445a565b61445a600f84900b83613290565b905060006144688285615733565b9050808c60600181815161447c91906158f4565b600f0b9052508061448d818c615733565b95509550505050509850989650505050505050565b600054610100900460ff1661450d5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b606482015260840161062e565b61154a336136f8565b600054610100900460ff166145815760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b606482015260840161062e565b815160209283012081519190920120606691909155606755565b600081600f0b83600f0b126145b057816145b2565b825b9392505050565b600081600f0b83600f0b136145b057816145b2565b60006145d8614788565b6001600160801b0316826703ffffffffffffff1667ffffffffffffffff1611159050919050565b60408051808201909152600281526127a360f11b6020820152600090600f83900b6f7fffffffffffffffffffffffffffffff19036146505760405162461bcd60e51b815260040161062e91906152c3565b50600082600f0b126146625781610a30565b5060000390565b600062ffffff82166269736f1461468257506000919050565b5060181c60ff1690565b600080600061469b85856147fb565b91509150612f588161483d565b60008082600f0b126146ba5781610a30565b610a3082615383565b600081600f0b600014156040518060400160405280600381526020016222212d60e91b815250906147075760405162461bcd60e51b815260040161062e91906152c3565b50600082600f0b84600f0b86600f0b028161472457614724615335565b0590506f7fffffffffffffffffffffffffffffff19811280159061474f575060016001607f1b038113155b6040518060400160405280600281526020016127a360f11b81525090612dbf5760405162461bcd60e51b815260040161062e91906152c3565b60655460408051632abf68dd60e11b815290516000926001600160a01b03169163557ed1ba9160048083019260209291908290030181865afa1580156147d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147f69190615943565b905090565b60008082516041036148315760208301516040840151606085015160001a61482587828585614987565b945094505050506105be565b506000905060026105be565b6000816004811115614851576148516153d8565b036148595750565b600181600481111561486d5761486d6153d8565b036148ba5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015260640161062e565b60028160048111156148ce576148ce6153d8565b0361491b5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015260640161062e565b600381600481111561492f5761492f6153d8565b0361311d5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b606482015260840161062e565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156149be5750600090506003613c71565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015614a12573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116614a3b57600060019250925050613c71565b9660009650945050505050565b63ffffffff8116811461311d57600080fd5b60008060408385031215614a6d57600080fd5b823591506020830135614a7f81614a48565b809150509250929050565b600060808284031215614a9c57600080fd5b50919050565b600060808284031215614ab457600080fd5b6145b28383614a8a565b600060208284031215614ad057600080fd5b5035919050565b60008060408385031215614aea57600080fd5b50508035926020909101359150565b600060208284031215614b0b57600080fd5b81356145b281614a48565b6001600160a01b038116811461311d57600080fd5b8035614b3681614b16565b919050565b80600f0b811461311d57600080fd5b60008060008060008060c08789031215614b6357600080fd5b8635614b6e81614a48565b95506020870135614b7e81614a48565b94506040870135614b8e81614b16565b93506060870135614b9e81614b3b565b92506080870135614bae81614b3b565b915060a0870135614bbe81614b3b565b809150509295509295509295565b60008060408385031215614bdf57600080fd5b8235614bea81614a48565b91506020830135614a7f81614a48565b6020808252825182820181905260009190848201906040850190845b81811015614c3b5783516001600160a01b031683529284019291840191600101614c16565b50909695505050505050565b60008060408385031215614c5a57600080fd5b8235614c6581614b16565b91506020830135614a7f81614b16565b60008060408385031215614c8857600080fd5b823567ffffffffffffffff811115614c9f57600080fd5b614cab85828601614a8a565b9250506020830135614a7f81614b16565b600060208284031215614cce57600080fd5b813567ffffffffffffffff811115614ce557600080fd5b8201606081850312156145b257600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715614d3657614d36614cf7565b604052919050565b803567ffffffffffffffff81168114614b3657600080fd5b600060a08284031215614d6857600080fd5b60405160a0810181811067ffffffffffffffff82111715614d8b57614d8b614cf7565b604052823581529050806020830135614da381614b3b565b60208201526040830135614db681614b3b565b6040820152614dc760608401614d3e565b6060820152614dd860808401614d3e565b60808201525092915050565b60008060c08385031215614df757600080fd5b8235614e0281614a48565b9150614e118460208501614d56565b90509250929050565b600060c08284031215614e2c57600080fd5b60405160c0810181811067ffffffffffffffff82111715614e4f57614e4f614cf7565b604052823581529050806020830135614e6781614b3b565b60208201526040830135614e7a81614b3b565b6040820152614e8b60608401614d3e565b6060820152614e9c60808401614d3e565b608082015260a0830135614eaf81614b3b565b60a0919091015292915050565b600082601f830112614ecd57600080fd5b813567ffffffffffffffff811115614ee757614ee7614cf7565b614efa601f8201601f1916602001614d0d565b818152846020838601011115614f0f57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060408385031215614f3f57600080fd5b823567ffffffffffffffff80821115614f5757600080fd5b908401906101008287031215614f6c57600080fd5b604051606081018181108382111715614f8757614f87614cf7565b604052614f948784614e1a565b815260c0830135614fa481614a48565b602082015260e083013582811115614fbb57600080fd5b614fc788828601614ebc565b6040830152509350614e1191505060208401614b2b565b60008060e08385031215614ff157600080fd5b8235614ffc81614a48565b9150614e118460208501614e1a565b60008060006060848603121561502057600080fd5b83359250602084013561503281614a48565b91506040840135801515811461504757600080fd5b809150509250925092565b8035600781900b8114614b3657600080fd5b6000806000806080858703121561507a57600080fd5b843561508581614b16565b9350602085013561509581614a48565b92506150a360408601615052565b91506150b160608601615052565b905092959194509250565b600067ffffffffffffffff8211156150d6576150d6614cf7565b5060051b60200190565b600082601f8301126150f157600080fd5b81356020615106615101836150bc565b614d0d565b82815260059290921b8401810191818101908684111561512557600080fd5b8286015b848110156124de57803561513c81614a48565b8352918301918301615129565b6000806040838503121561515c57600080fd5b823567ffffffffffffffff8082111561517457600080fd5b818501915085601f83011261518857600080fd5b81356020615198615101836150bc565b82815260059290921b840181019181810190898411156151b757600080fd5b948201945b838610156151de5785356151cf81614b16565b825294820194908201906151bc565b965050860135925050808211156151f457600080fd5b50615201858286016150e0565b9150509250929050565b602080825282518282018190526000919060409081850190868401855b828110156152615781518051600790810b865287820151900b8786015285015160ff168585015260609093019290850190600101615228565b5091979650505050505050565b6020808252825182820181905260009190848201906040850190845b81811015614c3b5783518352928401929184019160010161528a565b6000602082840312156152b857600080fd5b81356145b281614b16565b600060208083528351808285015260005b818110156152f0578581018301518582016040015282016152d4565b81811115615302576000604083870101525b50601f01601f1916929092016040019392505050565b60006020828403121561532a57600080fd5b81356145b281614b3b565b634e487b7160e01b600052601260045260246000fd5b600082600f0b8061535e5761535e615335565b8083600f0b0791505092915050565b634e487b7160e01b600052601160045260246000fd5b600081600f0b60016001607f1b031981036153a0576153a061536d565b60000392915050565b600080604083850312156153bc57600080fd5b82516153c781614b3b565b6020840151909250614a7f81614b3b565b634e487b7160e01b600052602160045260246000fd5b8281526040810160038310615405576154056153d8565b8260208301529392505050565b60006020828403121561542457600080fd5b81516145b281614b3b565b6000600182016154415761544161536d565b5060010190565b600081600f0b83600f0b60016001607f1b036000821360008413838304851182821616156154785761547861536d565b6f7fffffffffffffffffffffffffffffff1960008512828116878305871216156154a4576154a461536d565b600087129250858205871284841616156154c0576154c061536d565b858505871281841616156154d6576154d661536d565b5050509290910295945050505050565b600081600f0b83600f0b806154fd576154fd615335565b6f7fffffffffffffffffffffffffffffff198214600019821416156155245761552461536d565b90059392505050565b600063ffffffff80831681851680830382111561554c5761554c61536d565b01949350505050565b600063ffffffff838116908316818110156155725761557261536d565b039392505050565b634e487b7160e01b600052603260045260246000fd5b600063ffffffff8083168181036155a9576155a961536d565b6001019392505050565b60208101600283106155c7576155c76153d8565b91905290565b6000602082840312156155df57600080fd5b81516145b281614b16565b600060208083850312156155fd57600080fd5b825167ffffffffffffffff81111561561457600080fd5b8301601f8101851361562557600080fd5b8051615633615101826150bc565b81815260059190911b8201830190838101908783111561565257600080fd5b928401925b8284101561567957835161566a81614a48565b82529284019290840190615657565b979650505050505050565b6000823560be1983360301811261569a57600080fd5b9190910192915050565b600060a082840312156156b657600080fd5b6145b28383614d56565b600060c082360312156156d257600080fd5b6040516040810167ffffffffffffffff82821081831117156156f6576156f6614cf7565b816040526157043686614d56565b835260a085013591508082111561571a57600080fd5b5061572736828601614ebc565b60208301525092915050565b600081600f0b83600f0b600081128160016001607f1b03190183128115161561575e5761575e61536d565b8160016001607f1b030183138116156157795761577961536d565b5090039392505050565b60008235605e1983360301811261569a57600080fd5b600082198211156157ac576157ac61536d565b500190565b6000828210156157c3576157c361536d565b500390565b600060ff821660ff84168060ff038211156157e5576157e561536d565b019392505050565b60008160001904831182151516156158075761580761536d565b500290565b60008161581b5761581b61536d565b506000190190565b60006040828403121561583557600080fd5b6040516040810181811067ffffffffffffffff8211171561585857615858614cf7565b604052825161586681614b3b565b8152602083015161587681614b3b565b60208201529392505050565b60006060828403121561589457600080fd5b6040516060810181811067ffffffffffffffff821117156158b7576158b7614cf7565b60405282516158c581614b3b565b815260208301516158d581614b3b565b602082015260408301516158e881614b3b565b60408201529392505050565b600081600f0b83600f0b600082128260016001607f1b030382138115161561591e5761591e61536d565b8260016001607f1b031903821281161561593a5761593a61536d565b50019392505050565b60006020828403121561595557600080fd5b81516001600160801b03811681146145b257600080fdfe4f7264657228627974657333322073656e6465722c696e743132382070726963655831382c696e7431323820616d6f756e742c75696e7436342065787069726174696f6e2c75696e743634206e6f6e63652949736f6c617465644f7264657228627974657333322073656e6465722c696e743132382070726963655831382c696e7431323820616d6f756e742c75696e7436342065787069726174696f6e2c75696e743634206e6f6e63652c696e74313238206d617267696e29a264697066735822122055c1dfd41aeaf7f141d3d7b30860c91f7ebb6fee2e9c1b75721d1a687cc8dbcf64736f6c634300080d0033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101cf5760003560e01c806388bc796811610104578063b60aaa7c116100a2578063edc6d37b11610071578063edc6d37b146104cf578063f2b26331146104ef578063f2fde38b14610502578063f6ee7b4b1461051557600080fd5b8063b60aaa7c14610481578063b76d78e314610494578063ce933e59146104a7578063d895202a146104af57600080fd5b8063a27a250a116100de578063a27a250a14610437578063a5ae218b1461044a578063aed8e9671461045d578063b5cbd70e1461046e57600080fd5b806388bc7968146104005780638da5cb5b1461041357806395ee60711461042457600080fd5b806340f1a34d1161017157806366f87bd11161014b57806366f87bd114610396578063707c8b58146103dd578063715018a6146103e557806378f0d3ce146103ed57600080fd5b806340f1a34d146102f95780634821c8b51461032f578063485cc9551461038357600080fd5b80631a2b2d16116101ad5780631a2b2d16146102495780631d029b4d1461026c5780632da1c59b146102c65780633fceea28146102d957600080fd5b80630f2c878e146101d45780630f4b509d1461020657806313b56ddb1461021b575b600080fd5b6101e76101e2366004614a5a565b610528565b60408051600f93840b81529190920b6020820152015b60405180910390f35b610219610214366004614aa2565b6105c5565b005b61023b610229366004614abe565b600090815260a8602052604090205490565b6040519081526020016101fd565b61025c610257366004614ad7565b6109e1565b60405190151581526020016101fd565b61027f61027a366004614af9565b610a36565b6040516101fd9190600060808201905063ffffffff83511682526020830151600f0b60208301526040830151600f0b60408301526060830151600f0b606083015292915050565b6102196102d4366004614b4a565b610af7565b6102ec6102e7366004614bcc565b610cb9565b6040516101fd9190614bfa565b61031c610307366004614abe565b609e60205260009081526040902054600f0b81565b604051600f9190910b81526020016101fd565b61037161033d366004614af9565b604080516020808201835260009182905263ffffffff939093168152609d8352819020815192830190915254600f0b815290565b6040519051600f0b81526020016101fd565b610219610391366004614c47565b610de9565b6103c56103a4366004614af9565b63ffffffff166000908152609c60205260409020546001600160a01b031690565b6040516001600160a01b0390911681526020016101fd565b6102196110ae565b610219611538565b6102196103fb366004614c75565b61154c565b61021961040e366004614cbc565b6118d0565b6033546001600160a01b03166103c5565b61023b610432366004614de4565b611ec0565b61023b610445366004614f2c565b612040565b61023b610458366004614fde565b6124e9565b6065546001600160a01b03166103c5565b61031c61047c36600461500b565b612580565b61031c61048f366004614af9565b612620565b6102196104a2366004615064565b612647565b6102ec612afd565b6104c26104bd366004615149565b612dc8565b6040516101fd919061520b565b6104e26104dd366004614abe565b612f60565b6040516101fd919061526e565b61031c6104fd366004614af9565b613062565b6102196105103660046152a6565b613090565b610219610523366004614abe565b613120565b606082811c600090815260a16020908152604080832063ffffffff8616845282528083208151948501825254600781810b8652600160401b8204900b92850192909252600160801b90910460ff169083018190529091829182036105ab5750604080516060810182526000815265b5e620f4800060208201526001918101919091525b60208101519051600791820b9350900b90505b9250929050565b6065546001600160a01b031633146106375760405162461bcd60e51b815260206004820152602a60248201527f53657175656e63657247617465643a2063616c6c6572206973206e6f742074686044820152691948195b991c1bda5b9d60b21b60648201526084015b60405180910390fd5b6040805180820190915260018152605560f81b60208201526269736f823562ffffff16036106785760405162461bcd60e51b815260040161062e91906152c3565b50600061068e61027a6040840160208501614af9565b905060006106aa6106a56040850160208601614af9565b61316e565b905060006106be6080850160608601615318565b600f0b136040518060400160405280600381526020016224a82960e91b815250906106fc5760405162461bcd60e51b815260040161062e91906152c3565b5080604001511561076757816040015183604001602081019061071f9190615318565b610729919061534b565b60408051808201909152600381526204953560ec1b602082015290600f0b156107655760405162461bcd60e51b815260040161062e91906152c3565b505b6000816040015161077c57816020015161077f565b81515b90506000806001600160a01b03831663c7167cf56107a36040890160208a01614af9565b6107b360608a0160408b01615318565b6107df6107c660808c0160608d01615318565b6107d660608d0160408e01615318565b600f0b90613290565b6107e890615383565b6040516001600160e01b031960e086901b16815263ffffffff939093166004840152600f91820b6024840152900b604482015260640160408051808303816000875af115801561083c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061086091906153a9565b915091508161086e90615383565b915061087981615383565b905060006108c36108906040890160208a01614af9565b88358886866000600f83900b136108b4578b602001516108af90615383565b6108ba565b8b602001515b6000600161330b565b87519093509091506108da90869089358686613330565b609a546040516388b6496f60e01b81526000916001600160a01b0316906388b6496f9061090e908b359085906004016153ee565b602060405180830381865afa15801561092b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061094f9190615412565b600f0b121560405180604001604052806002815260200161125560f21b8152509061098d5760405162461bcd60e51b815260040161062e91906152c3565b506060860151609b60006109a760408b0160208c01614af9565b63ffffffff168152602081019190915260400160002080546001600160801b03928316600160801b02921691909117905550505050505050565b6000805b600a811015610a2a57600084815260a9602090815260408083208484529091529020548303610a18576001915050610a30565b80610a228161542f565b9150506109e5565b50600090505b92915050565b6040805160808101825260008082526020808301829052828401829052606080840183815263ffffffff878116808652609b85528786208851948501895254600781810b8652600160401b8204810b86880152600160801b909104600f90810b868b0190815292885260a49096529790952054168552925190910b909152805191929091610ac9910b633b9aca00615448565b600f0b602080840191909152810151610ae99060070b633b9aca00615448565b600f0b604083015250919050565b610aff61351d565b6001600160a01b03841615610ba95763ffffffff86166000908152609c60205260409020546001600160a01b031615610b7a5760405162461bcd60e51b815260206004820152601860248201527f7669727475616c20626f6f6b20616c7265616479207365740000000000000000604482015260640161062e565b63ffffffff86166000908152609c6020526040902080546001600160a01b0319166001600160a01b0386161790555b63ffffffff85811614610bdf5763ffffffff868116600090815260a460205260409020805463ffffffff19169187169190911790555b610bed633b9aca00836154e6565b63ffffffff87166000908152609b60205260409020805467ffffffffffffffff191667ffffffffffffffff92909216919091179055610c30633b9aca00846154e6565b63ffffffff969096166000818152609b6020908152604080832080546fffffffffffffffff00000000000000001916600160401b67ffffffffffffffff909c169b909b029a909a1790995588518082018a52600f9490940b8452918152609d90915295909520945185546001600160801b0319166001600160801b039091161790945550505050565b60606000610cc7838561552d565b60a35490915063ffffffff8082169083161115610ce2578091505b8063ffffffff168563ffffffff161115610cfa578094505b6000610d068684615555565b63ffffffff1667ffffffffffffffff811115610d2457610d24614cf7565b604051908082528060200260200182016040528015610d4d578160200160208202803683370190505b509050855b8363ffffffff168163ffffffff161015610ddf5760a38163ffffffff1681548110610d7f57610d7f61557a565b6000918252602090912001546001600160a01b031682610d9f8984615555565b63ffffffff1681518110610db557610db561557a565b6001600160a01b039092166020928302919091019091015280610dd781615590565b915050610d52565b5095945050505050565b600054610100900460ff1615808015610e095750600054600160ff909116105b80610e235750303b158015610e23575060005460ff166001145b610e955760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840161062e565b6000805460ff191660011790558015610eb8576000805461ff0019166101001790555b610ec061358c565b610ec9826135ff565b610f3d6040518060400160405280600681526020017f56657274657800000000000000000000000000000000000000000000000000008152506040518060400160405280600581526020017f302e302e31000000000000000000000000000000000000000000000000000000815250613629565b609a80546001600160a01b0319166001600160a01b038516908117909155604051635d2e9ad160e01b8152635d2e9ad190610f7d906000906004016155b3565b602060405180830381865afa158015610f9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fbe91906155cd565b609f80546001600160a01b0319166001600160a01b03928316179055609a54604051635d2e9ad160e01b8152911690635d2e9ad190611002906001906004016155b3565b602060405180830381865afa15801561101f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061104391906155cd565b60a080546001600160a01b0319166001600160a01b039290921691909117905580156110a9576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b6065546001600160a01b0316331461111b5760405162461bcd60e51b815260206004820152602a60248201527f53657175656e63657247617465643a2063616c6c6572206973206e6f742074686044820152691948195b991c1bda5b9d60b21b606482015260840161062e565b609f54604080516347428e7b60e01b815290516000926001600160a01b0316916347428e7b91600480830192869291908290030181865afa158015611164573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261118c91908101906155ea565b905060015b81518163ffffffff161015611326576000828263ffffffff16815181106111ba576111ba61557a565b60209081029190910181015163ffffffff81166000908152609b8352604080822081516060810183529054600781810b8352600160401b8204900b95820195909552600160801b909404600f0b9084018190529193501261121c575050611314565b609f5463ffffffff838116600090815260a460205260408082205485820151915163e0b0621f60e01b8152931660048401526024830191909152600f0b60448201526001600160a01b039091169063e0b0621f90606401600060405180830381600087803b15801561128d57600080fd5b505af11580156112a1573d6000803e3d6000fd5b50506000604080850182815263ffffffff9096168252609b6020908152912084518154929095015195516001600160801b03908116600160801b0267ffffffffffffffff978816600160401b026001600160801b0319909416979096169690961791909117949094169290921790925550505b8061131e81615590565b915050611191565b5060a060009054906101000a90046001600160a01b03166001600160a01b03166347428e7b6040518163ffffffff1660e01b8152600401600060405180830381865afa15801561137a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526113a291908101906155ea565b905060005b81518163ffffffff161015611534576000828263ffffffff16815181106113d0576113d061557a565b60209081029190910181015163ffffffff81166000908152609b8352604080822081516060810183529054600781810b8352600160401b8204900b95820195909552600160801b909404600f0b90840181905291935003611432575050611522565b60a054604082810151905163f8a42e5160e01b815263ffffffff851660048201526000602482018190526044820152600f9190910b60648201526001600160a01b039091169063f8a42e5190608401600060405180830381600087803b15801561149b57600080fd5b505af11580156114af573d6000803e3d6000fd5b50506000604080850182815263ffffffff9096168252609b6020908152912084518154929095015195516001600160801b03908116600160801b0267ffffffffffffffff978816600160401b026001600160801b0319909416979096169690961791909117949094169290921790925550505b8061152c81615590565b9150506113a7565b5050565b61154061369e565b61154a60006136f8565b565b6065546001600160a01b031633146115b95760405162461bcd60e51b815260206004820152602a60248201527f53657175656e63657247617465643a2063616c6c6572206973206e6f742074686044820152691948195b991c1bda5b9d60b21b606482015260840161062e565b60006115cb6106a56020850185614af9565b905060006115df61027a6020860186614af9565b905060006116106115f36020870187614af9565b6116006060880188615684565b61043290368190038101906156a4565b905060006116216060870187615684565b611632906060810190604001615318565b905060006116436060880188615684565b61164c906156c0565b80515190915062ffffff166269736f1415604051806040016040528060018152602001605560f81b815250906116955760405162461bcd60e51b815260040161062e91906152c3565b506116a3858583868a61374a565b60405180604001604052806002815260200161125560f21b815250906116dc5760405162461bcd60e51b815260040161062e91906152c3565b5060008061170a876116f460408c0160208d01615318565b61170460608d0160408e01615318565b866139f0565b9092509050600061176561172160208c018c614af9565b855180516040909101518a9087908790829061173d908d615733565b6117479190615733565b611755600f8a900b8b613c7a565b61175e90615383565b600161330b565b885186515191945091925061177d918a918686613330565b604080518082019091526002815261125560f21b602082015250835151866117a860208d018d614af9565b865160208082015160608084015160809485015160408051600f95860b81528f860b9681019690965267ffffffffffffffff92831690860152169083015260019282019290925285820b60a082015287820b60c08201529086900b60e082015263ffffffff91909116907f7c57459d6f4f0fb2fc5b1e298c8c0eb238422944964aa1e249eaa78747f0cca9906101000160405180910390a46060870151609b600061185660208e018e614af9565b63ffffffff1681526020810191909152604090810160002080546001600160801b03938416600160801b02931692909217909155845101516118989086615733565b6000968752609e602052604090962080546001600160801b0319166001600160801b0390971696909617909555505050505050505050565b6065546001600160a01b0316331461193d5760405162461bcd60e51b815260206004820152602a60248201527f53657175656e63657247617465643a2063616c6c6572206973206e6f742074686044820152691948195b991c1bda5b9d60b21b606482015260840161062e565b600061195a61194c8380615783565b6106a5906020810190614af9565b6040805160608101825260008082526020820181905291810182905291925090819081908190600061198f8760600151610a36565b9050600061199d8980615783565b6119ab906020810190615684565b6119b4906156c0565b905060006119c28a80615783565b6119d0906040810190615684565b6119d9906156c0565b905060405180606001604052806119f88b606001518560000151611ec0565b8152602001611a0f8b606001518460000151611ec0565b81528251604090810151600f0b6020928301528251600090815260aa90925290205490945015611a4e578351600090815260aa60205260409020548251525b602080850151600090815260aa909152604090205415611a8157602080850151600090815260aa90915260409020548151525b8160000151604001519750611aaf89848487600001518e6020016020810190611aaa91906152a6565b61374a565b60405180604001604052806002815260200161125560f21b81525090611ae85760405162461bcd60e51b815260040161062e91906152c3565b50611b0789848387602001518e6040016020810190611aaa91906152a6565b60405180604001604052806002815260200161494d60f01b81525090611b405760405162461bcd60e51b815260040161062e91906152c3565b5081516040908101518251820151825180840190935260048352634f43424d60e01b60208401526000600f91820b81129290910b1303611b935760405162461bcd60e51b815260040161062e91906152c3565b506000816000015160400151600f0b1315611c0357816000015160200151600f0b816000015160200151600f0b1215604051806040016040528060048152602001634f43424d60e01b81525090611bfd5760405162461bcd60e51b815260040161062e91906152c3565b50611c5a565b816000015160200151600f0b816000015160200151600f0b1315604051806040016040528060048152602001634f43424d60e01b81525090611c585760405162461bcd60e51b815260040161062e91906152c3565b505b611c6f89848460000151846000015188613ce3565b8096508197505050611cb789606001518360000151600001518589898b8860000151604001518f611ca09190615733565b611caa9190615733565b875160200151600161330b565b8451845151929950909650611cd0918b91908989613330565b604080518082019091526002815261125560f21b602082015250604080518082019091526002815261494d60f01b602082015250606080840151908a015163ffffffff166000908152609b6020526040902080546001600160801b03928316600160801b029216919091179055815151600114611d8657815160400151611d579089615733565b84516000908152609e6020526040902080546001600160801b0319166001600160801b03929092169190911790555b805151600114611ddb578060000151604001518460400151611da89190615733565b6020858101516000908152609e9091526040902080546001600160801b0319166001600160801b03929092169190911790555b815151611de790613eba565b805151611df390613eba565b81600001516000015184600001518a6060015163ffffffff167f7c57459d6f4f0fb2fc5b1e298c8c0eb238422944964aa1e249eaa78747f0cca98560000151602001518c87600001516060015188600001516080015160018f8f8f604051611eac989796959493929190600f98890b815296880b602088015267ffffffffffffffff95861660408801529390941660608601529015156080850152840b60a084015290830b60c083015290910b60e08201526101000190565b60405180910390a450505050505050505050565b60008060405180608001604052806052815260200161596d6052913990506000818051906020012084600001518560200151866040015187606001518860800151604051602001611f4a969594939291909586526020860194909452600f92830b6040860152910b606084015267ffffffffffffffff90811660808401521660a082015260c00190565b60405160208183030381529060405280519060200120905060007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f611f8e60665490565b60675463ffffffff89166000908152609c6020908152604091829020548251918201959095529081019290925260608201524660808201526001600160a01b0390911660a082015260c001604051602081830303815290604052805190602001209050612036818360405161190160f01b6020820152602281018390526042810182905260009060620160405160208183030381529060405280519060200120905092915050565b9695505050505050565b6065546000906001600160a01b031633146120b05760405162461bcd60e51b815260206004820152602a60248201527f53657175656e63657247617465643a2063616c6c6572206973206e6f742074686044820152691948195b991c1bda5b9d60b21b606482015260840161062e565b82515162ffffff166269736f1415604051806040016040528060018152602001605560f81b815250906120f65760405162461bcd60e51b815260040161062e91906152c3565b50600061210b846020015185600001516124e9565b9050612125846000015160000151828587604001516142a9565b60405180604001604052806002815260200161495360f01b8152509061215e5760405162461bcd60e51b815260040161062e91906152c3565b5083515160601c600081815260a7602052604081205490805b82816001901b116121f2576001811b8316156121e057875151600090815260a96020908152604080832084845290915290205480156121de5760006121bb82614309565b9050896020015163ffffffff168163ffffffff16036121dc575091506121f2565b505b505b6121eb600182615799565b9050612177565b50806123085761220560016104006157b1565b82036122535760405162461bcd60e51b815260206004820152601d60248201527f546f6f206d616e792069736f6c61746564207375626163636f756e7473000000604482015260640161062e565b60005b600183161561227657600192831c9261226f90826157c8565b9050612256565b6020888101516001600160a01b038616600090815260a7835260408082208054600160ff881690811b9091179091558c515160189690961b63ff0000001693851b67ffffffff000000001660608a901b6bffffffffffffffffffffffff191617939093176269736f1780835260a88552818320959095558b5151825260a9845280822092825291909252902081905590505b600061238088602001516040518060a001604052808b600001516000015181526020018b6000015160200151600f0b81526020018b6000015160400151600f0b81526020018b600001516060015167ffffffffffffffff1681526020018b600001516080015167ffffffffffffffff16815250611ec0565b600081815260aa60205260408120849055895160a00151919250600f9190910b13156124de57875160a090810151600083815260ab6020526040812080546001600160801b0319166001600160801b0390931692909217909155609f548a5180519301516001600160a01b039091169263e0b0621f929161240090615383565b6040516001600160e01b031960e086901b16815263ffffffff9390931660048401526024830191909152600f0b6044820152606401600060405180830381600087803b15801561244f57600080fd5b505af1158015612463573d6000803e3d6000fd5b5050609f548a5160a0015160405163e0b0621f60e01b81526000600482015260248101879052600f9190910b60448201526001600160a01b03909116925063e0b0621f9150606401600060405180830381600087803b1580156124c557600080fd5b505af11580156124d9573d6000803e3d6000fd5b505050505b509695505050505050565b6000806040518060a00160405280606881526020016159bf60689139905060008180519060200120846000015185602001518660400151876060015188608001518960a00151604051602001611f4a97969594939291909687526020870195909552600f93840b604087015291830b606086015267ffffffffffffffff90811660808601521660a08401520b60c082015260e00190565b606083811c600090815260a16020908152604080832063ffffffff8716845282528083208151948501825254600781810b8652600160401b8204900b92850192909252600160801b90910460ff1690830181905290919082036126025750604080516060810182526000815265b5e620f4800060208201526001918101919091525b8261260e578051612614565b80602001515b60070b95945050505050565b63ffffffff81166000908152609b6020526040812054610a309060070b633b9aca00615448565b6065546001600160a01b031633146126b45760405162461bcd60e51b815260206004820152602a60248201527f53657175656e63657247617465643a2063616c6c6572206973206e6f742074686044820152691948195b991c1bda5b9d60b21b606482015260840161062e565b6001600160a01b038416600090815260a2602052604090205460ff1661273a576001600160a01b038416600081815260a260205260408120805460ff1916600190811790915560a3805491820181559091527f60859188cffe297f44dde29f2d2865634621f26215049caeb304ccba566a8b170180546001600160a01b03191690911790555b63ffffffff8316612a6557609f54604080516347428e7b60e01b815290516000926001600160a01b0316916347428e7b91600480830192869291908290030181865afa15801561278e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526127b691908101906155ea565b9050600060a060009054906101000a90046001600160a01b03166001600160a01b03166347428e7b6040518163ffffffff1660e01b8152600401600060405180830381865afa15801561280d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261283591908101906155ea565b905060005b82518163ffffffff16101561296457600063ffffffff16838263ffffffff16815181106128695761286961557a565b602002602001015163ffffffff1603156129525760405180606001604052808660070b81526020018560070b8152602001600160ff1681525060a16000896001600160a01b03166001600160a01b031681526020019081526020016000206000858463ffffffff16815181106128e1576128e161557a565b60209081029190910181015163ffffffff1682528181019290925260409081016000208351815493850151949092015160ff16600160801b0260ff60801b1967ffffffffffffffff958616600160401b026001600160801b0319909516959093169490941792909217169190911790555b8061295c81615590565b91505061283a565b5060005b81518163ffffffff161015612a5d5760405180606001604052808660070b81526020018560070b8152602001600160ff1681525060a16000896001600160a01b03166001600160a01b031681526020019081526020016000206000848463ffffffff16815181106129db576129db61557a565b60209081029190910181015163ffffffff1682528181019290925260409081016000208351815493850151949092015160ff16600160801b0260ff60801b1967ffffffffffffffff958616600160401b026001600160801b03199095169590931694909417929092171691909117905580612a5581615590565b915050612968565b505050612af7565b60408051606081018252600784810b825283900b602080830191825260018385019081526001600160a01b038916600090815260a1835285812063ffffffff8a168252909252939020915182549151935160ff16600160801b0260ff60801b1967ffffffffffffffff958616600160401b026001600160801b0319909416959092169490941791909117169190911790555b50505050565b60606000609f60009054906101000a90046001600160a01b03166001600160a01b03166347428e7b6040518163ffffffff1660e01b8152600401600060405180830381865afa158015612b54573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612b7c91908101906155ea565b9050600060a060009054906101000a90046001600160a01b03166001600160a01b03166347428e7b6040518163ffffffff1660e01b8152600401600060405180830381865afa158015612bd3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612bfb91908101906155ea565b90506000805b83518163ffffffff161015612c78578163ffffffff16848263ffffffff1681518110612c2f57612c2f61557a565b602002602001015163ffffffff161115612c6657838163ffffffff1681518110612c5b57612c5b61557a565b602002602001015191505b80612c7081615590565b915050612c01565b5060005b82518163ffffffff161015612cf3578163ffffffff16838263ffffffff1681518110612caa57612caa61557a565b602002602001015163ffffffff161115612ce157828163ffffffff1681518110612cd657612cd661557a565b602002602001015191505b80612ceb81615590565b915050612c7c565b506000612d0182600161552d565b63ffffffff1667ffffffffffffffff811115612d1f57612d1f614cf7565b604051908082528060200260200182016040528015612d48578160200160208202803683370190505b50905060005b8263ffffffff168163ffffffff1611612dbf5763ffffffff81166000818152609c602052604090205483516001600160a01b039091169184918110612d9557612d9561557a565b6001600160a01b039092166020928302919091019091015280612db781615590565b915050612d4e565b50949350505050565b6060600082518451612dda91906157ed565b67ffffffffffffffff811115612df257612df2614cf7565b604051908082528060200260200182016040528015612e3d57816020015b6040805160608101825260008082526020808301829052928201528252600019909201910181612e105790505b50905060005b8451811015612f585760005b8451811015612f455760a16000878481518110612e6e57612e6e61557a565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000206000868381518110612eaa57612eaa61557a565b60209081029190910181015163ffffffff16825281810192909252604090810160002081516060810183529054600781810b8352600160401b8204900b93820193909352600160801b90920460ff1690820152855184908390612f0d90866157ed565b612f179190615799565b81518110612f2757612f2761557a565b60200260200101819052508080612f3d9061542f565b915050612e4f565b5080612f508161542f565b915050612e43565b509392505050565b60606000805b600a811015612fb057600084815260a9602090815260408083208484529091529020548015612f9d57612f9a600184615799565b92505b5080612fa88161542f565b915050612f66565b5060008167ffffffffffffffff811115612fcc57612fcc614cf7565b604051908082528060200260200182016040528015612ff5578160200160208202803683370190505b50905060005b600a811015612f5857600085815260a960209081526040808320848452909152902054801561304f57808361302f8661580c565b955085815181106130425761304261557a565b6020026020010181815250505b508061305a8161542f565b915050612ffb565b63ffffffff81166000908152609b6020526040812054610a3090600160401b900460070b633b9aca00615448565b61309861369e565b6001600160a01b0381166131145760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161062e565b61311d816136f8565b50565b609a546040805180820190915260018152605560f81b6020820152906001600160a01b031633146131645760405162461bcd60e51b815260040161062e91906152c3565b5061311d81613eba565b604080516080810182526000808252602082018190529181018290526060810191909152609a5460405163deb14ec360e01b815263ffffffff841660048201526000916001600160a01b03169063deb14ec390602401602060405180830381865afa1580156131e1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061320591906155cd565b60a0549091506001600160a01b039081169082168190036132565750604080516080810182526001600160a01b0390921682526000602083015260019082015263ffffffff90921660608301525090565b5050604080516080810182526000808252609f546001600160a01b031660208301529181019190915263ffffffff90921660608301525090565b600080670de0b6b3a7640000600f85810b9085900b025b0590506f7fffffffffffffffffffffffffffffff1981128015906132d2575060016001607f1b038113155b6040518060400160405280600281526020016127a360f11b81525090612f585760405162461bcd60e51b815260040161062e91906152c3565b60008061331e8a8a8a8a8a8a8a8a61432d565b915091505b9850989650505050505050565b8460400151156133c1578451606086015160405163f8a42e5160e01b815263ffffffff909116600482015260248101859052600f84810b604483015283900b60648201526001600160a01b039091169063f8a42e51906084015b600060405180830381600087803b1580156133a457600080fd5b505af11580156133b8573d6000803e3d6000fd5b50505050613516565b63ffffffff8416613423576020850151606086015160405163f8a42e5160e01b815263ffffffff909116600482015260248101859052600f84810b604483015283900b60648201526001600160a01b039091169063f8a42e519060840161338a565b6020850151606086015160405163e0b0621f60e01b815263ffffffff909116600482015260248101859052600f84900b60448201526001600160a01b039091169063e0b0621f90606401600060405180830381600087803b15801561348757600080fd5b505af115801561349b573d6000803e3d6000fd5b505050602086015160405163e0b0621f60e01b815263ffffffff8716600482015260248101869052600f84900b60448201526001600160a01b03909116915063e0b0621f90606401600060405180830381600087803b1580156134fd57600080fd5b505af1158015613511573d6000803e3d6000fd5b505050505b5050505050565b609f546001600160a01b0316331480613540575060a0546001600160a01b031633145b61154a5760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c7920656e67696e652063616e206d6f6469667920636f6e666967000000604482015260640161062e565b600054610100900460ff166135f75760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b606482015260840161062e565b61154a6144a2565b61360761369e565b606580546001600160a01b0319166001600160a01b0392909216919091179055565b600054610100900460ff166136945760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b606482015260840161062e565b6115348282614516565b6033546001600160a01b0316331461154a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161062e565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b82515160009060001901613760575060016139e7565b8351805160009061377090614309565b905063ffffffff8116156137cb578063ffffffff16886060015163ffffffff1614604051806040016040528060018152602001605560f81b815250906137c95760405162461bcd60e51b815260040161062e91906152c3565b505b6000858152609e602052604090819020549083018051600f9290920b918291906137f6908390615733565b600f0b9052506060830151603d1c6001908116036139ae576000896040015161389f5760208a015160608b01518551604051637c1e148760e01b815263ffffffff909216600483015260248201526001600160a01b0390911690637c1e1487906044016040805180830381865afa158015613875573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138999190615823565b5161391f565b895160608b01518551604051637c1e148760e01b815263ffffffff909216600483015260248201526001600160a01b0390911690637c1e148790604401606060405180830381865afa1580156138f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061391d9190615882565b515b9050600081600f0b13151560008560400151600f0b1315150361394857600060408501526139ac565b60008460400151600f0b131561397c5761396f84604001518261396a90615383565b61459b565b600f0b60408501526139ac565b60008460400151600f0b12156139ac576139a384604001518261399e90615383565b6145b9565b600f0b60408501525b505b60008360200151600f0b1380156139cb57506040830151600f0b15155b80156139e157506139df83606001516145ce565b155b93505050505b95945050505050565b60008080613a0d613a05600f87900b88613c7a565b600f0b6145ff565b90506000846000015160400151600f0b1315613adb57836000015160200151600f0b81600f0b1315604051806040016040528060048152602001634f43424d60e01b81525090613a705760405162461bcd60e51b815260040161062e91906152c3565b50600086600f0b128015613a9a5750613a8886615383565b600f0b846000015160400151600f0b12155b604051806040016040528060048152602001634f43424d60e01b81525090613ad55760405162461bcd60e51b815260040161062e91906152c3565b50613b8f565b836000015160200151600f0b81600f0b1215604051806040016040528060048152602001634f43424d60e01b81525090613b285760405162461bcd60e51b815260040161062e91906152c3565b50600086600f0b138015613b525750613b4086615383565b600f0b846000015160400151600f0b13155b604051806040016040528060048152602001634f43424d60e01b81525090613b8d5760405162461bcd60e51b815260040161062e91906152c3565b505b60008760400151613ba4578760200151613ba7565b87515b606089015160405163c7167cf560e01b815263ffffffff9091166004820152600f89810b602483015288900b604482015290915060009081906001600160a01b0384169063c7167cf59060640160408051808303816000875af1158015613c12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c3691906153a9565b91509150818760000151604001818151613c5091906158f4565b600f0b905250613c5f82615383565b613c6882615383565b95509550505050505b94509492505050565b600081600f0b600014156040518060400160405280600381526020016222212d60e91b81525090613cbe5760405162461bcd60e51b815260040161062e91906152c3565b50600082600f0b670de0b6b3a7640000600f0b85600f0b02816132a7576132a7615335565b60008060008560400151600f0b1215613d1357613d0c8560400151856040015161399e90615383565b9150613d44565b60008560400151600f0b1315613d3957613d0c8560400151856040015161396a90615383565b506000905080613eb0565b6040860151613d53908361534b565b613d5d9083615733565b91506000613d7b856020015184600f0b61329090919063ffffffff16565b9050613d8681615383565b91506000613dad896060015187600001518a87613da290615383565b86600080600061330b565b80935081925050508387604001818151613dc79190615733565b600f0b905250604086018051859190613de19083906158f4565b600f0b90525087518651613e00918b91613dfa88615383565b86613330565b856000015185602001518a6060015163ffffffff167f7c57459d6f4f0fb2fc5b1e298c8c0eb238422944964aa1e249eaa78747f0cca9896020015189604001518b606001518c608001516000898d613e5790615383565b60408051600f98890b815296880b602088015267ffffffffffffffff9586169087015293909216606085015215156080840152830b60a0830152820b60c08201529087900b60e08201526101000160405180910390a450505b9550959350505050565b6000613ec582614309565b90508063ffffffff16600003613ed9575050565b60a054604051637c1e148760e01b815263ffffffff83166004820152602481018490526000916001600160a01b031690637c1e148790604401606060405180830381865afa158015613f2f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f539190615882565b8051909150600f0b6000036110a9576000613f6d84614669565b600085815260a8602090815260409091205490840151919250606086901c91600f0b156140af5760a05460208501516001600160a01b039091169063f8a42e519087908990600090613fbe90615383565b6040516001600160e01b031960e087901b16815263ffffffff9490941660048501526024840192909252600f90810b60448401520b6064820152608401600060405180830381600087803b15801561401557600080fd5b505af1158015614029573d6000803e3d6000fd5b505060a054602087015160405163f8a42e5160e01b815263ffffffff8a1660048201526024810186905260006044820152600f9190910b60648201526001600160a01b03909116925063f8a42e519150608401600060405180830381600087803b15801561409657600080fd5b505af11580156140aa573d6000803e3d6000fd5b505050505b609f54604051637c1e148760e01b815260006004820181905260248201899052916001600160a01b031690637c1e1487906044016040805180830381865afa1580156140ff573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141239190615823565b519050600f81900b1561422457609f546001600160a01b031663e0b0621f60008961414d85615383565b6040516001600160e01b031960e086901b16815263ffffffff9390931660048401526024830191909152600f0b6044820152606401600060405180830381600087803b15801561419c57600080fd5b505af11580156141b0573d6000803e3d6000fd5b5050609f5460405163e0b0621f60e01b81526000600482015260248101869052600f85900b60448201526001600160a01b03909116925063e0b0621f9150606401600060405180830381600087803b15801561420b57600080fd5b505af115801561421f573d6000803e3d6000fd5b505050505b6001600160a01b038316600090815260a7602090815260408083208054600160ff8a1690811b6000191890911690915585845260a98352818420908452825280832083905589835260a890915280822082905551839189917f027ce6fbfb5b4d17a0ee36b592ef0db77b060df7e023bc84e68c5f0664c9b83a9190a350505050505050565b6000806142b6858461468c565b90506001600160a01b0381161580159061203657508515806142e457506001600160a01b038116606087901c145b806120365750836001600160a01b0316816001600160a01b0316149695505050505050565b600062ffffff82166269736f1461432257506000919050565b5060201c61ffff1690565b600080600019890161434457506000905084613323565b600083156143ff5785600f0b60000361438d57602089015161436990600f0b86613290565b61437390826158f4565b9050600087600f0b121561438d5761438a81615383565b90505b600061439b89600f0b6145ff565b905060008a602001516143b88b8a6143b391906158f4565b6146a8565b6143c29190615733565b90506143ce818361459b565b9050600081600f0b13156143f8576143eb600f8a900b82846146c3565b6143f590846158f4565b92505b505061440c565b61440987826158f4565b90505b60006144198b8d87612580565b61442b90670de0b6b3a7640000615733565b905060008083600f0b1361444c57614447600f84900b83613c7a565b61445a565b61445a600f84900b83613290565b905060006144688285615733565b9050808c60600181815161447c91906158f4565b600f0b9052508061448d818c615733565b95509550505050509850989650505050505050565b600054610100900460ff1661450d5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b606482015260840161062e565b61154a336136f8565b600054610100900460ff166145815760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b606482015260840161062e565b815160209283012081519190920120606691909155606755565b600081600f0b83600f0b126145b057816145b2565b825b9392505050565b600081600f0b83600f0b136145b057816145b2565b60006145d8614788565b6001600160801b0316826703ffffffffffffff1667ffffffffffffffff1611159050919050565b60408051808201909152600281526127a360f11b6020820152600090600f83900b6f7fffffffffffffffffffffffffffffff19036146505760405162461bcd60e51b815260040161062e91906152c3565b50600082600f0b126146625781610a30565b5060000390565b600062ffffff82166269736f1461468257506000919050565b5060181c60ff1690565b600080600061469b85856147fb565b91509150612f588161483d565b60008082600f0b126146ba5781610a30565b610a3082615383565b600081600f0b600014156040518060400160405280600381526020016222212d60e91b815250906147075760405162461bcd60e51b815260040161062e91906152c3565b50600082600f0b84600f0b86600f0b028161472457614724615335565b0590506f7fffffffffffffffffffffffffffffff19811280159061474f575060016001607f1b038113155b6040518060400160405280600281526020016127a360f11b81525090612dbf5760405162461bcd60e51b815260040161062e91906152c3565b60655460408051632abf68dd60e11b815290516000926001600160a01b03169163557ed1ba9160048083019260209291908290030181865afa1580156147d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147f69190615943565b905090565b60008082516041036148315760208301516040840151606085015160001a61482587828585614987565b945094505050506105be565b506000905060026105be565b6000816004811115614851576148516153d8565b036148595750565b600181600481111561486d5761486d6153d8565b036148ba5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015260640161062e565b60028160048111156148ce576148ce6153d8565b0361491b5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015260640161062e565b600381600481111561492f5761492f6153d8565b0361311d5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b606482015260840161062e565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156149be5750600090506003613c71565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015614a12573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116614a3b57600060019250925050613c71565b9660009650945050505050565b63ffffffff8116811461311d57600080fd5b60008060408385031215614a6d57600080fd5b823591506020830135614a7f81614a48565b809150509250929050565b600060808284031215614a9c57600080fd5b50919050565b600060808284031215614ab457600080fd5b6145b28383614a8a565b600060208284031215614ad057600080fd5b5035919050565b60008060408385031215614aea57600080fd5b50508035926020909101359150565b600060208284031215614b0b57600080fd5b81356145b281614a48565b6001600160a01b038116811461311d57600080fd5b8035614b3681614b16565b919050565b80600f0b811461311d57600080fd5b60008060008060008060c08789031215614b6357600080fd5b8635614b6e81614a48565b95506020870135614b7e81614a48565b94506040870135614b8e81614b16565b93506060870135614b9e81614b3b565b92506080870135614bae81614b3b565b915060a0870135614bbe81614b3b565b809150509295509295509295565b60008060408385031215614bdf57600080fd5b8235614bea81614a48565b91506020830135614a7f81614a48565b6020808252825182820181905260009190848201906040850190845b81811015614c3b5783516001600160a01b031683529284019291840191600101614c16565b50909695505050505050565b60008060408385031215614c5a57600080fd5b8235614c6581614b16565b91506020830135614a7f81614b16565b60008060408385031215614c8857600080fd5b823567ffffffffffffffff811115614c9f57600080fd5b614cab85828601614a8a565b9250506020830135614a7f81614b16565b600060208284031215614cce57600080fd5b813567ffffffffffffffff811115614ce557600080fd5b8201606081850312156145b257600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715614d3657614d36614cf7565b604052919050565b803567ffffffffffffffff81168114614b3657600080fd5b600060a08284031215614d6857600080fd5b60405160a0810181811067ffffffffffffffff82111715614d8b57614d8b614cf7565b604052823581529050806020830135614da381614b3b565b60208201526040830135614db681614b3b565b6040820152614dc760608401614d3e565b6060820152614dd860808401614d3e565b60808201525092915050565b60008060c08385031215614df757600080fd5b8235614e0281614a48565b9150614e118460208501614d56565b90509250929050565b600060c08284031215614e2c57600080fd5b60405160c0810181811067ffffffffffffffff82111715614e4f57614e4f614cf7565b604052823581529050806020830135614e6781614b3b565b60208201526040830135614e7a81614b3b565b6040820152614e8b60608401614d3e565b6060820152614e9c60808401614d3e565b608082015260a0830135614eaf81614b3b565b60a0919091015292915050565b600082601f830112614ecd57600080fd5b813567ffffffffffffffff811115614ee757614ee7614cf7565b614efa601f8201601f1916602001614d0d565b818152846020838601011115614f0f57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060408385031215614f3f57600080fd5b823567ffffffffffffffff80821115614f5757600080fd5b908401906101008287031215614f6c57600080fd5b604051606081018181108382111715614f8757614f87614cf7565b604052614f948784614e1a565b815260c0830135614fa481614a48565b602082015260e083013582811115614fbb57600080fd5b614fc788828601614ebc565b6040830152509350614e1191505060208401614b2b565b60008060e08385031215614ff157600080fd5b8235614ffc81614a48565b9150614e118460208501614e1a565b60008060006060848603121561502057600080fd5b83359250602084013561503281614a48565b91506040840135801515811461504757600080fd5b809150509250925092565b8035600781900b8114614b3657600080fd5b6000806000806080858703121561507a57600080fd5b843561508581614b16565b9350602085013561509581614a48565b92506150a360408601615052565b91506150b160608601615052565b905092959194509250565b600067ffffffffffffffff8211156150d6576150d6614cf7565b5060051b60200190565b600082601f8301126150f157600080fd5b81356020615106615101836150bc565b614d0d565b82815260059290921b8401810191818101908684111561512557600080fd5b8286015b848110156124de57803561513c81614a48565b8352918301918301615129565b6000806040838503121561515c57600080fd5b823567ffffffffffffffff8082111561517457600080fd5b818501915085601f83011261518857600080fd5b81356020615198615101836150bc565b82815260059290921b840181019181810190898411156151b757600080fd5b948201945b838610156151de5785356151cf81614b16565b825294820194908201906151bc565b965050860135925050808211156151f457600080fd5b50615201858286016150e0565b9150509250929050565b602080825282518282018190526000919060409081850190868401855b828110156152615781518051600790810b865287820151900b8786015285015160ff168585015260609093019290850190600101615228565b5091979650505050505050565b6020808252825182820181905260009190848201906040850190845b81811015614c3b5783518352928401929184019160010161528a565b6000602082840312156152b857600080fd5b81356145b281614b16565b600060208083528351808285015260005b818110156152f0578581018301518582016040015282016152d4565b81811115615302576000604083870101525b50601f01601f1916929092016040019392505050565b60006020828403121561532a57600080fd5b81356145b281614b3b565b634e487b7160e01b600052601260045260246000fd5b600082600f0b8061535e5761535e615335565b8083600f0b0791505092915050565b634e487b7160e01b600052601160045260246000fd5b600081600f0b60016001607f1b031981036153a0576153a061536d565b60000392915050565b600080604083850312156153bc57600080fd5b82516153c781614b3b565b6020840151909250614a7f81614b3b565b634e487b7160e01b600052602160045260246000fd5b8281526040810160038310615405576154056153d8565b8260208301529392505050565b60006020828403121561542457600080fd5b81516145b281614b3b565b6000600182016154415761544161536d565b5060010190565b600081600f0b83600f0b60016001607f1b036000821360008413838304851182821616156154785761547861536d565b6f7fffffffffffffffffffffffffffffff1960008512828116878305871216156154a4576154a461536d565b600087129250858205871284841616156154c0576154c061536d565b858505871281841616156154d6576154d661536d565b5050509290910295945050505050565b600081600f0b83600f0b806154fd576154fd615335565b6f7fffffffffffffffffffffffffffffff198214600019821416156155245761552461536d565b90059392505050565b600063ffffffff80831681851680830382111561554c5761554c61536d565b01949350505050565b600063ffffffff838116908316818110156155725761557261536d565b039392505050565b634e487b7160e01b600052603260045260246000fd5b600063ffffffff8083168181036155a9576155a961536d565b6001019392505050565b60208101600283106155c7576155c76153d8565b91905290565b6000602082840312156155df57600080fd5b81516145b281614b16565b600060208083850312156155fd57600080fd5b825167ffffffffffffffff81111561561457600080fd5b8301601f8101851361562557600080fd5b8051615633615101826150bc565b81815260059190911b8201830190838101908783111561565257600080fd5b928401925b8284101561567957835161566a81614a48565b82529284019290840190615657565b979650505050505050565b6000823560be1983360301811261569a57600080fd5b9190910192915050565b600060a082840312156156b657600080fd5b6145b28383614d56565b600060c082360312156156d257600080fd5b6040516040810167ffffffffffffffff82821081831117156156f6576156f6614cf7565b816040526157043686614d56565b835260a085013591508082111561571a57600080fd5b5061572736828601614ebc565b60208301525092915050565b600081600f0b83600f0b600081128160016001607f1b03190183128115161561575e5761575e61536d565b8160016001607f1b030183138116156157795761577961536d565b5090039392505050565b60008235605e1983360301811261569a57600080fd5b600082198211156157ac576157ac61536d565b500190565b6000828210156157c3576157c361536d565b500390565b600060ff821660ff84168060ff038211156157e5576157e561536d565b019392505050565b60008160001904831182151516156158075761580761536d565b500290565b60008161581b5761581b61536d565b506000190190565b60006040828403121561583557600080fd5b6040516040810181811067ffffffffffffffff8211171561585857615858614cf7565b604052825161586681614b3b565b8152602083015161587681614b3b565b60208201529392505050565b60006060828403121561589457600080fd5b6040516060810181811067ffffffffffffffff821117156158b7576158b7614cf7565b60405282516158c581614b3b565b815260208301516158d581614b3b565b602082015260408301516158e881614b3b565b60408201529392505050565b600081600f0b83600f0b600082128260016001607f1b030382138115161561591e5761591e61536d565b8260016001607f1b031903821281161561593a5761593a61536d565b50019392505050565b60006020828403121561595557600080fd5b81516001600160801b03811681146145b257600080fdfe4f7264657228627974657333322073656e6465722c696e743132382070726963655831382c696e7431323820616d6f756e742c75696e7436342065787069726174696f6e2c75696e743634206e6f6e63652949736f6c617465644f7264657228627974657333322073656e6465722c696e743132382070726963655831382c696e7431323820616d6f756e742c75696e7436342065787069726174696f6e2c75696e743634206e6f6e63652c696e74313238206d617267696e29a264697066735822122055c1dfd41aeaf7f141d3d7b30860c91f7ebb6fee2e9c1b75721d1a687cc8dbcf64736f6c634300080d0033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 35 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.