Source Code
More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 281 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Deposit | 22650649 | 3 hrs ago | IN | 0 ETH | 0.00015088 | ||||
Deposit | 22646804 | 16 hrs ago | IN | 0 ETH | 0.00045868 | ||||
Execute Withdraw... | 22646254 | 18 hrs ago | IN | 0 ETH | 0.00067632 | ||||
Borrow | 22644817 | 22 hrs ago | IN | 0 ETH | 0.00012425 | ||||
Deposit | 22644482 | 24 hrs ago | IN | 0 ETH | 0.00043634 | ||||
Deposit | 22644417 | 24 hrs ago | IN | 0 ETH | 0.00049884 | ||||
Deposit | 22641458 | 34 hrs ago | IN | 0 ETH | 0.00047669 | ||||
Queue Withdrawal | 22641310 | 34 hrs ago | IN | 0 ETH | 0.00086412 | ||||
Deposit | 22639868 | 39 hrs ago | IN | 0 ETH | 0.0015615 | ||||
Repay And Proces... | 22639214 | 41 hrs ago | IN | 0 ETH | 0.00036669 | ||||
Collect Fees | 22638426 | 44 hrs ago | IN | 0 ETH | 0.00027125 | ||||
Queue Withdrawal | 22637072 | 2 days ago | IN | 0 ETH | 0.00049177 | ||||
Borrow | 22636859 | 2 days ago | IN | 0 ETH | 0.00014516 | ||||
Deposit | 22636780 | 2 days ago | IN | 0 ETH | 0.00018257 | ||||
Deposit | 22636291 | 2 days ago | IN | 0 ETH | 0.00018468 | ||||
Execute Withdraw... | 22631369 | 2 days ago | IN | 0 ETH | 0.00068473 | ||||
Execute Withdraw... | 22630055 | 3 days ago | IN | 0 ETH | 0.00019555 | ||||
Borrow | 22628410 | 3 days ago | IN | 0 ETH | 0.0003981 | ||||
Deposit | 22628192 | 3 days ago | IN | 0 ETH | 0.00057848 | ||||
Deposit | 22625116 | 3 days ago | IN | 0 ETH | 0.00200295 | ||||
Collect Fees | 22624902 | 3 days ago | IN | 0 ETH | 0.00115702 | ||||
Execute Withdraw... | 22624510 | 3 days ago | IN | 0 ETH | 0.00063548 | ||||
Queue Withdrawal | 22623903 | 3 days ago | IN | 0 ETH | 0.00035367 | ||||
Deposit | 22622664 | 4 days ago | IN | 0 ETH | 0.00023659 | ||||
Deposit | 22622642 | 4 days ago | IN | 0 ETH | 0.00024404 |
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Method | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|---|
0x61026060 | 21989547 | 92 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Similar Match Source Code This contract matches the deployed Bytecode of the Source Code for Contract 0xFe7cf568...754876F94 The constructor portion of the code might be different and could alter the actual behaviour of the contract
Contract Name:
WildcatMarket
Compiler Version
v0.8.25+commit.b61c2a91
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: Apache-2.0 WITH LicenseRef-Commons-Clause-1.0 pragma solidity >=0.8.20; import './WildcatMarketBase.sol'; import './WildcatMarketConfig.sol'; import './WildcatMarketToken.sol'; import './WildcatMarketWithdrawals.sol'; import '../WildcatSanctionsSentinel.sol'; contract WildcatMarket is WildcatMarketBase, WildcatMarketConfig, WildcatMarketToken, WildcatMarketWithdrawals { using MathUtils for uint256; using SafeCastLib for uint256; using LibERC20 for address; using BoolUtils for bool; /** * @dev Apply pending interest, delinquency fees and protocol fees * to the state and process the pending withdrawal batch if * one exists and has expired, then update the market's * delinquency status. */ function updateState() external nonReentrant sphereXGuardExternal { MarketState memory state = _getUpdatedState(); _writeState(state); } /** * @dev Token rescue function for recovering tokens sent to the market * contract by mistake or otherwise outside of the normal course of * operation. */ function rescueTokens(address token) external nonReentrant onlyBorrower { if ((token == asset).or(token == address(this))) { revert_BadRescueAsset(); } token.safeTransferAll(msg.sender); } /** * @dev Deposit up to `amount` underlying assets and mint market tokens * for `msg.sender`. * * The actual deposit amount is limited by the market's maximum deposit * amount, which is the configured `maxTotalSupply` minus the current * total supply. * * Reverts if the market is closed or if the scaled token amount * that would be minted for the deposit is zero. */ function _depositUpTo( uint256 amount ) internal virtual nonReentrant returns (uint256 /* actualAmount */) { // Get current state MarketState memory state = _getUpdatedState(); if (state.isClosed) revert_DepositToClosedMarket(); // Reduce amount if it would exceed totalSupply amount = MathUtils.min(amount, state.maximumDeposit()); // Scale the mint amount uint104 scaledAmount = state.scaleAmount(amount).toUint104(); if (scaledAmount == 0) revert_NullMintAmount(); // Cache account data and revert if not authorized to deposit. Account memory account = _getAccount(msg.sender); hooks.onDeposit(msg.sender, scaledAmount, state); // Transfer deposit from caller asset.safeTransferFrom(msg.sender, address(this), amount); account.scaledBalance += scaledAmount; _accounts[msg.sender] = account; emit_Transfer(_runtimeConstant(address(0)), msg.sender, amount); emit_Deposit(msg.sender, amount, scaledAmount); // Increase supply state.scaledTotalSupply += scaledAmount; // Update stored state _writeState(state); return amount; } /** * @dev Deposit up to `amount` underlying assets and mint market tokens * for `msg.sender`. * * The actual deposit amount is limited by the market's maximum deposit * amount, which is the configured `maxTotalSupply` minus the current * total supply. * * Reverts if the market is closed or if the scaled token amount * that would be minted for the deposit is zero. */ function depositUpTo( uint256 amount ) external virtual sphereXGuardExternal returns (uint256 /* actualAmount */) { return _depositUpTo(amount); } /** * @dev Deposit exactly `amount` underlying assets and mint market tokens * for `msg.sender`. * * Reverts if the deposit amount would cause the market to exceed the * configured `maxTotalSupply`. */ function deposit(uint256 amount) external virtual sphereXGuardExternal { uint256 actualAmount = _depositUpTo(amount); if (amount != actualAmount) revert_MaxSupplyExceeded(); } /** * @dev Withdraw available protocol fees to the fee recipient. */ function collectFees() external nonReentrant sphereXGuardExternal { MarketState memory state = _getUpdatedState(); if (state.accruedProtocolFees == 0) revert_NullFeeAmount(); uint128 withdrawableFees = state.withdrawableProtocolFees(totalAssets()); if (withdrawableFees == 0) revert_InsufficientReservesForFeeWithdrawal(); state.accruedProtocolFees -= withdrawableFees; asset.safeTransfer(feeRecipient, withdrawableFees); _writeState(state); emit_FeesCollected(withdrawableFees); } /** * @dev Withdraw funds from the market to the borrower. * * Can only withdraw up to the assets that are not required * to meet the borrower's collateral obligations. * * Reverts if the market is closed. */ function borrow(uint256 amount) external onlyBorrower nonReentrant sphereXGuardExternal { // Check if the borrower is flagged as a sanctioned entity on Chainalysis. // Uses `isFlaggedByChainalysis` instead of `isSanctioned` to prevent the borrower // overriding their sanction status. if (_isFlaggedByChainalysis(borrower)) { revert_BorrowWhileSanctioned(); } MarketState memory state = _getUpdatedState(); if (state.isClosed) revert_BorrowFromClosedMarket(); uint256 borrowable = state.borrowableAssets(totalAssets()); if (amount > borrowable) revert_BorrowAmountTooHigh(); // Execute borrow hook if enabled hooks.onBorrow(amount, state); asset.safeTransfer(msg.sender, amount); _writeState(state); emit_Borrow(amount); } function _repay(MarketState memory state, uint256 amount, uint256 baseCalldataSize) internal { if (amount == 0) revert_NullRepayAmount(); if (state.isClosed) revert_RepayToClosedMarket(); asset.safeTransferFrom(msg.sender, address(this), amount); emit_DebtRepaid(msg.sender, amount); // Execute repay hook if enabled hooks.onRepay(amount, state, baseCalldataSize); } /** * @dev Transfers funds from the caller to the market. * * Any payments made through this function are considered * repayments from the borrower. Do *not* use this function * if you are a lender or an unrelated third party. * * Reverts if the market is closed or `amount` is 0. */ function repay(uint256 amount) external nonReentrant sphereXGuardExternal { if (amount == 0) revert_NullRepayAmount(); asset.safeTransferFrom(msg.sender, address(this), amount); emit_DebtRepaid(msg.sender, amount); MarketState memory state = _getUpdatedState(); if (state.isClosed) revert_RepayToClosedMarket(); // Execute repay hook if enabled hooks.onRepay(amount, state, _runtimeConstant(0x24)); _writeState(state); } /** * @dev Sets the market APR to 0% and marks market as closed. * * Can not be called if there are any unpaid withdrawal batches. * * Transfers remaining debts from borrower if market is not fully * collateralized; otherwise, transfers any assets in excess of * debts to the borrower. */ function closeMarket() external onlyBorrower nonReentrant sphereXGuardExternal { MarketState memory state = _getUpdatedState(); if (state.isClosed) revert_MarketAlreadyClosed(); uint256 currentlyHeld = totalAssets(); uint256 totalDebts = state.totalDebts(); if (currentlyHeld < totalDebts) { // Transfer remaining debts from borrower uint256 remainingDebt = totalDebts - currentlyHeld; _repay(state, remainingDebt, 0x04); currentlyHeld += remainingDebt; } else if (currentlyHeld > totalDebts) { uint256 excessDebt = currentlyHeld - totalDebts; // Transfer excess assets to borrower asset.safeTransfer(borrower, excessDebt); currentlyHeld -= excessDebt; } hooks.onCloseMarket(state); state.annualInterestBips = 0; state.isClosed = true; state.reserveRatioBips = 10000; // Ensures that delinquency fee doesn't increase scale factor further // as doing so would mean last lender in market couldn't fully redeem state.timeDelinquent = 0; // Still track available liquidity in case of a rounding error uint256 availableLiquidity = currentlyHeld - (state.normalizedUnclaimedWithdrawals + state.accruedProtocolFees); // If there is a pending withdrawal batch which is not fully paid off, set aside // up to the available liquidity for that batch. if (state.pendingWithdrawalExpiry != 0) { uint32 expiry = state.pendingWithdrawalExpiry; WithdrawalBatch memory batch = _withdrawalData.batches[expiry]; if (batch.scaledAmountBurned < batch.scaledTotalAmount) { (, uint128 normalizedAmountPaid) = _applyWithdrawalBatchPayment( batch, state, expiry, availableLiquidity ); availableLiquidity -= normalizedAmountPaid; _withdrawalData.batches[expiry] = batch; } // Remove the pending batch to ensure new withdrawals are not // added to it after the market is closed. state.pendingWithdrawalExpiry = 0; emit_WithdrawalBatchExpired( expiry, batch.scaledTotalAmount, batch.scaledAmountBurned, batch.normalizedAmountPaid ); emit_WithdrawalBatchClosed(expiry); // If the batch expiry is at the time of the market's closure, create // a new empty batch that expires in one second to ensure new batches // aren't created after the market is closed with the same expiry. if (expiry == block.timestamp) { uint32 newExpiry = expiry + 1; emit_WithdrawalBatchCreated(newExpiry); state.pendingWithdrawalExpiry = newExpiry; } } uint256 numBatches = _withdrawalData.unpaidBatches.length(); for (uint256 i; i < numBatches; i++) { // Process the next unpaid batch using available liquidity uint256 normalizedAmountPaid = _processUnpaidWithdrawalBatch(state, availableLiquidity); // Reduce liquidity available to next batch availableLiquidity -= normalizedAmountPaid; } if (state.scaledPendingWithdrawals != 0) { revert_CloseMarketWithUnpaidWithdrawals(); } _writeState(state); emit_MarketClosed(block.timestamp); } /** * @dev Queues a full withdrawal of a sanctioned account's assets. */ function _blockAccount(MarketState memory state, address accountAddress) internal override { Account memory account = _accounts[accountAddress]; if (account.scaledBalance > 0) { uint104 scaledAmount = account.scaledBalance; uint256 normalizedAmount = state.normalizeAmount(scaledAmount); uint32 expiry = _queueWithdrawal( state, account, accountAddress, scaledAmount, normalizedAmount, msg.data.length ); emit_SanctionedAccountAssetsQueuedForWithdrawal( accountAddress, expiry, scaledAmount, normalizedAmount ); } } }
// SPDX-License-Identifier: Apache-2.0 WITH LicenseRef-Commons-Clause-1.0 pragma solidity >=0.8.20; import '../ReentrancyGuard.sol'; import '../spherex/SphereXProtectedRegisteredBase.sol'; import '../interfaces/IMarketEventsAndErrors.sol'; import '../interfaces/IERC20.sol'; import '../IHooksFactory.sol'; import '../libraries/FeeMath.sol'; import '../libraries/MarketErrors.sol'; import '../libraries/MarketEvents.sol'; import '../libraries/Withdrawal.sol'; import '../libraries/FunctionTypeCasts.sol'; import '../libraries/LibERC20.sol'; import '../types/HooksConfig.sol'; contract WildcatMarketBase is SphereXProtectedRegisteredBase, ReentrancyGuard, IMarketEventsAndErrors { using SafeCastLib for uint256; using MathUtils for uint256; using FunctionTypeCasts for *; using LibERC20 for address; // ==================================================================== // // Market Config (immutable) // // ==================================================================== // /** * @dev Return the contract version string "2". */ function version() external pure returns (string memory) { assembly { mstore(0x40, 0) mstore(0x41, 0x0132) mstore(0x20, 0x20) return(0x20, 0x60) } } HooksConfig public immutable hooks; /// @dev Account with blacklist control, used for blocking sanctioned addresses. address public immutable sentinel; /// @dev Account with authority to borrow assets from the market. address public immutable borrower; /// @dev Factory that deployed the market. Has the ability to update the protocol fee. address public immutable factory; /// @dev Account that receives protocol fees. address public immutable feeRecipient; /// @dev Penalty fee added to interest earned by lenders, does not affect protocol fee. uint public immutable delinquencyFeeBips; /// @dev Time after which delinquency incurs penalty fee. uint public immutable delinquencyGracePeriod; /// @dev Time before withdrawal batches are processed. uint public immutable withdrawalBatchDuration; /// @dev Token decimals (same as underlying asset). uint8 public immutable decimals; /// @dev Address of the underlying asset. address public immutable asset; bytes32 internal immutable PACKED_NAME_WORD_0; bytes32 internal immutable PACKED_NAME_WORD_1; bytes32 internal immutable PACKED_SYMBOL_WORD_0; bytes32 internal immutable PACKED_SYMBOL_WORD_1; function symbol() external view returns (string memory) { bytes32 symbolWord0 = PACKED_SYMBOL_WORD_0; bytes32 symbolWord1 = PACKED_SYMBOL_WORD_1; assembly { // The layout here is: // 0x00: Offset to the string // 0x20: Length of the string // 0x40: First word of the string // 0x60: Second word of the string // The first word of the string that is kept in immutable storage also contains the // length byte, meaning the total size limit of the string is 63 bytes. mstore(0, 0x20) mstore(0x20, 0) mstore(0x3f, symbolWord0) mstore(0x5f, symbolWord1) return(0, 0x80) } } function name() external view returns (string memory) { bytes32 nameWord0 = PACKED_NAME_WORD_0; bytes32 nameWord1 = PACKED_NAME_WORD_1; assembly { // The layout here is: // 0x00: Offset to the string // 0x20: Length of the string // 0x40: First word of the string // 0x60: Second word of the string // The first word of the string that is kept in immutable storage also contains the // length byte, meaning the total size limit of the string is 63 bytes. mstore(0, 0x20) mstore(0x20, 0) mstore(0x3f, nameWord0) mstore(0x5f, nameWord1) return(0, 0x80) } } /// @dev Returns immutable arch-controller address. function archController() external view returns (address) { return _archController; } // ===================================================================== // // Market State // // ===================================================================== // MarketState internal _state; mapping(address => Account) internal _accounts; WithdrawalData internal _withdrawalData; // ===================================================================== // // Constructor // // ===================================================================== // function _getMarketParameters() internal view returns (uint256 marketParametersPointer) { assembly { marketParametersPointer := mload(0x40) mstore(0x40, add(marketParametersPointer, 0x260)) // Write the selector for IHooksFactory.getMarketParameters mstore(0x00, 0x04032dbb) // Call `getMarketParameters` and copy the returned struct to the allocated memory // buffer, reverting if the call fails or does not return the correct amount of bytes. // This overrides all the ABI decoding safety checks, as the call is always made to // the factory contract which will only ever return the prepared market parameters. if iszero( and( eq(returndatasize(), 0x260), staticcall(gas(), caller(), 0x1c, 0x04, marketParametersPointer, 0x260) ) ) { revert(0, 0) } } } constructor() { factory = msg.sender; // Cast the function signature of `_getMarketParameters` to get a valid reference to // a `MarketParameters` object without creating a duplicate allocation or unnecessarily // zeroing out the memory buffer. MarketParameters memory parameters = _getMarketParameters.asReturnsMarketParameters()(); // Set asset metadata asset = parameters.asset; decimals = parameters.decimals; PACKED_NAME_WORD_0 = parameters.packedNameWord0; PACKED_NAME_WORD_1 = parameters.packedNameWord1; PACKED_SYMBOL_WORD_0 = parameters.packedSymbolWord0; PACKED_SYMBOL_WORD_1 = parameters.packedSymbolWord1; { // Initialize the market state - all values in slots 1 and 2 of the struct are // initialized to zero, so they are skipped. uint maxTotalSupply = parameters.maxTotalSupply; uint reserveRatioBips = parameters.reserveRatioBips; uint annualInterestBips = parameters.annualInterestBips; uint protocolFeeBips = parameters.protocolFeeBips; assembly { // MarketState Slot 0 Storage Layout: // [15:31] | state.maxTotalSupply // [31:32] | state.isClosed = false let slot0 := shl(8, maxTotalSupply) sstore(_state.slot, slot0) // MarketState Slot 3 Storage Layout: // [4:8] | lastInterestAccruedTimestamp // [8:22] | scaleFactor = 1e27 // [22:24] | reserveRatioBips // [24:26] | annualInterestBips // [26:28] | protocolFeeBips // [28:32] | timeDelinquent = 0 let slot3 := or( or(or(shl(0xc0, timestamp()), shl(0x50, RAY)), shl(0x40, reserveRatioBips)), or(shl(0x30, annualInterestBips), shl(0x20, protocolFeeBips)) ) sstore(add(_state.slot, 3), slot3) } } hooks = parameters.hooks; sentinel = parameters.sentinel; borrower = parameters.borrower; feeRecipient = parameters.feeRecipient; delinquencyFeeBips = parameters.delinquencyFeeBips; delinquencyGracePeriod = parameters.delinquencyGracePeriod; withdrawalBatchDuration = parameters.withdrawalBatchDuration; _archController = parameters.archController; __SphereXProtectedRegisteredBase_init(parameters.sphereXEngine); } // ===================================================================== // // Modifiers // // ===================================================================== // modifier onlyBorrower() { address _borrower = borrower; assembly { // Equivalent to // if (msg.sender != borrower) revert NotApprovedBorrower(); if xor(caller(), _borrower) { mstore(0, 0x02171e6a) revert(0x1c, 0x04) } } _; } // ===================================================================== // // Internal State Getters // // ===================================================================== // /** * @dev Retrieve an account from storage. * * Reverts if account is sanctioned. */ function _getAccount(address accountAddress) internal view returns (Account memory account) { account = _accounts[accountAddress]; if (_isSanctioned(accountAddress)) revert_AccountBlocked(); } /** * @dev Checks if `account` is flagged as a sanctioned entity by Chainalysis. * If an account is flagged mistakenly, the borrower can override their * status on the sentinel and allow them to interact with the market. */ function _isSanctioned(address account) internal view returns (bool result) { address _borrower = borrower; address _sentinel = address(sentinel); assembly { let freeMemoryPointer := mload(0x40) mstore(0, 0x06e74444) mstore(0x20, _borrower) mstore(0x40, account) // Call `sentinel.isSanctioned(borrower, account)` and revert if the call fails // or does not return 32 bytes. if iszero( and(eq(returndatasize(), 0x20), staticcall(gas(), _sentinel, 0x1c, 0x44, 0, 0x20)) ) { returndatacopy(0, 0, returndatasize()) revert(0, returndatasize()) } result := mload(0) mstore(0x40, freeMemoryPointer) } } // ===================================================================== // // External State Getters // // ===================================================================== // /** * @dev Returns the amount of underlying assets the borrower is obligated * to maintain in the market to avoid delinquency. */ function coverageLiquidity() external view nonReentrantView returns (uint256) { return _calculateCurrentStatePointers.asReturnsMarketState()().liquidityRequired(); } /** * @dev Returns the scale factor (in ray) used to convert scaled balances * to normalized balances. */ function scaleFactor() external view nonReentrantView returns (uint256) { return _calculateCurrentStatePointers.asReturnsMarketState()().scaleFactor; } /** * @dev Total balance in underlying asset. */ function totalAssets() public view returns (uint256) { return asset.balanceOf(address(this)); } /** * @dev Returns the amount of underlying assets the borrower is allowed * to borrow. * * This is the balance of underlying assets minus: * - pending (unpaid) withdrawals * - paid withdrawals * - reserve ratio times the portion of the supply not pending withdrawal * - protocol fees */ function borrowableAssets() external view nonReentrantView returns (uint256) { return _calculateCurrentStatePointers.asReturnsMarketState()().borrowableAssets(totalAssets()); } /** * @dev Returns the amount of protocol fees (in underlying asset amount) * that have accrued and are pending withdrawal. */ function accruedProtocolFees() external view nonReentrantView returns (uint256) { return _calculateCurrentStatePointers.asReturnsMarketState()().accruedProtocolFees; } function totalDebts() external view nonReentrantView returns (uint256) { return _calculateCurrentStatePointers.asReturnsMarketState()().totalDebts(); } /** * @dev Returns the state of the market as of the last update. */ function previousState() external view returns (MarketState memory) { MarketState memory state = _state; assembly { return(state, 0x1c0) } } /** * @dev Return the state the market would have at the current block after applying * interest and fees accrued since the last update and processing the pending * withdrawal batch if it is expired. */ function currentState() external view nonReentrantView returns (MarketState memory state) { state = _calculateCurrentStatePointers.asReturnsMarketState()(); assembly { return(state, 0x1c0) } } /** * @dev Call `_calculateCurrentState()` and return only the `state` parameter. * * Casting the function type prevents a duplicate declaration of the MarketState * return parameter, which would cause unnecessary zeroing and allocation of memory. * With `viaIR` enabled, the cast is a noop. */ function _calculateCurrentStatePointers() internal view returns (uint256 state) { (state, , ) = _calculateCurrentState.asReturnsPointers()(); } /** * @dev Returns the scaled total supply the vaut would have at the current block * after applying interest and fees accrued since the last update and burning * market tokens for the pending withdrawal batch if it is expired. */ function scaledTotalSupply() external view nonReentrantView returns (uint256) { return _calculateCurrentStatePointers.asReturnsMarketState()().scaledTotalSupply; } /** * @dev Returns the scaled balance of `account` */ function scaledBalanceOf(address account) external view nonReentrantView returns (uint256) { return _accounts[account].scaledBalance; } /** * @dev Returns the amount of protocol fees that are currently * withdrawable by the fee recipient. */ function withdrawableProtocolFees() external view returns (uint128) { return _calculateCurrentStatePointers.asReturnsMarketState()().withdrawableProtocolFees( totalAssets() ); } // /*////////////////////////////////////////////////////////////// // Internal State Handlers // //////////////////////////////////////////////////////////////*/ function _blockAccount(MarketState memory state, address accountAddress) internal virtual {} /** * @dev Returns cached MarketState after accruing interest and delinquency / protocol fees * and processing expired withdrawal batch, if any. * * Used by functions that make additional changes to `state`. * * NOTE: Returned `state` does not match `_state` if interest is accrued * Calling function must update `_state` or revert. * * @return state Market state after interest is accrued. */ function _getUpdatedState() internal returns (MarketState memory state) { state = _state; // Handle expired withdrawal batch if (state.hasPendingExpiredBatch()) { uint256 expiry = state.pendingWithdrawalExpiry; // Only accrue interest if time has passed since last update. // This will only be false if withdrawalBatchDuration is 0. uint32 lastInterestAccruedTimestamp = state.lastInterestAccruedTimestamp; if (expiry != lastInterestAccruedTimestamp) { (uint256 baseInterestRay, uint256 delinquencyFeeRay, uint256 protocolFee) = state .updateScaleFactorAndFees(delinquencyFeeBips, delinquencyGracePeriod, expiry); emit_InterestAndFeesAccrued( lastInterestAccruedTimestamp, expiry, state.scaleFactor, baseInterestRay, delinquencyFeeRay, protocolFee ); } _processExpiredWithdrawalBatch(state); } uint32 lastInterestAccruedTimestamp = state.lastInterestAccruedTimestamp; // Apply interest and fees accrued since last update (expiry or previous tx) if (block.timestamp != lastInterestAccruedTimestamp) { (uint256 baseInterestRay, uint256 delinquencyFeeRay, uint256 protocolFee) = state .updateScaleFactorAndFees(delinquencyFeeBips, delinquencyGracePeriod, block.timestamp); emit_InterestAndFeesAccrued( lastInterestAccruedTimestamp, block.timestamp, state.scaleFactor, baseInterestRay, delinquencyFeeRay, protocolFee ); } // If there is a pending withdrawal batch which is not fully paid off, set aside // up to the available liquidity for that batch. if (state.pendingWithdrawalExpiry != 0) { uint32 expiry = state.pendingWithdrawalExpiry; WithdrawalBatch memory batch = _withdrawalData.batches[expiry]; if (batch.scaledAmountBurned < batch.scaledTotalAmount) { // Burn as much of the withdrawal batch as possible with available liquidity. uint256 availableLiquidity = batch.availableLiquidityForPendingBatch(state, totalAssets()); if (availableLiquidity > 0) { _applyWithdrawalBatchPayment(batch, state, expiry, availableLiquidity); _withdrawalData.batches[expiry] = batch; } } } } /** * @dev Calculate the current state, applying fees and interest accrued since * the last state update as well as the effects of withdrawal batch expiry * on the market state. * Identical to _getUpdatedState() except it does not modify storage or * or emit events. * Returns expired batch data, if any, so queries against batches have * access to the most recent data. */ function _calculateCurrentState() internal view returns ( MarketState memory state, uint32 pendingBatchExpiry, WithdrawalBatch memory pendingBatch ) { state = _state; // Handle expired withdrawal batch if (state.hasPendingExpiredBatch()) { pendingBatchExpiry = state.pendingWithdrawalExpiry; // Only accrue interest if time has passed since last update. // This will only be false if withdrawalBatchDuration is 0. if (pendingBatchExpiry != state.lastInterestAccruedTimestamp) { state.updateScaleFactorAndFees( delinquencyFeeBips, delinquencyGracePeriod, pendingBatchExpiry ); } pendingBatch = _withdrawalData.batches[pendingBatchExpiry]; uint256 availableLiquidity = pendingBatch.availableLiquidityForPendingBatch( state, totalAssets() ); if (availableLiquidity > 0) { _applyWithdrawalBatchPaymentView(pendingBatch, state, availableLiquidity); } state.pendingWithdrawalExpiry = 0; } if (state.lastInterestAccruedTimestamp != block.timestamp) { state.updateScaleFactorAndFees(delinquencyFeeBips, delinquencyGracePeriod, block.timestamp); } // If there is a pending withdrawal batch which is not fully paid off, set aside // up to the available liquidity for that batch. if (state.pendingWithdrawalExpiry != 0) { pendingBatchExpiry = state.pendingWithdrawalExpiry; pendingBatch = _withdrawalData.batches[pendingBatchExpiry]; if (pendingBatch.scaledAmountBurned < pendingBatch.scaledTotalAmount) { // Burn as much of the withdrawal batch as possible with available liquidity. uint256 availableLiquidity = pendingBatch.availableLiquidityForPendingBatch( state, totalAssets() ); if (availableLiquidity > 0) { _applyWithdrawalBatchPaymentView(pendingBatch, state, availableLiquidity); } } } } /** * @dev Writes the cached MarketState to storage and emits an event. * Used at the end of all functions which modify `state`. */ function _writeState(MarketState memory state) internal { bool isDelinquent = state.liquidityRequired() > totalAssets(); state.isDelinquent = isDelinquent; { bool isClosed = state.isClosed; uint maxTotalSupply = state.maxTotalSupply; assembly { // Slot 0 Storage Layout: // [15:31] | state.maxTotalSupply // [31:32] | state.isClosed let slot0 := or(isClosed, shl(0x08, maxTotalSupply)) sstore(_state.slot, slot0) } } { uint accruedProtocolFees = state.accruedProtocolFees; uint normalizedUnclaimedWithdrawals = state.normalizedUnclaimedWithdrawals; assembly { // Slot 1 Storage Layout: // [0:16] | state.normalizedUnclaimedWithdrawals // [16:32] | state.accruedProtocolFees let slot1 := or(accruedProtocolFees, shl(0x80, normalizedUnclaimedWithdrawals)) sstore(add(_state.slot, 1), slot1) } } { uint scaledTotalSupply = state.scaledTotalSupply; uint scaledPendingWithdrawals = state.scaledPendingWithdrawals; uint pendingWithdrawalExpiry = state.pendingWithdrawalExpiry; assembly { // Slot 2 Storage Layout: // [1:2] | state.isDelinquent // [2:6] | state.pendingWithdrawalExpiry // [6:19] | state.scaledPendingWithdrawals // [19:32] | state.scaledTotalSupply let slot2 := or( or( or(shl(0xf0, isDelinquent), shl(0xd0, pendingWithdrawalExpiry)), shl(0x68, scaledPendingWithdrawals) ), scaledTotalSupply ) sstore(add(_state.slot, 2), slot2) } } { uint timeDelinquent = state.timeDelinquent; uint protocolFeeBips = state.protocolFeeBips; uint annualInterestBips = state.annualInterestBips; uint reserveRatioBips = state.reserveRatioBips; uint scaleFactor = state.scaleFactor; uint lastInterestAccruedTimestamp = state.lastInterestAccruedTimestamp; assembly { // Slot 3 Storage Layout: // [4:8] | state.lastInterestAccruedTimestamp // [8:22] | state.scaleFactor // [22:24] | state.reserveRatioBips // [24:26] | state.annualInterestBips // [26:28] | protocolFeeBips // [28:32] | state.timeDelinquent let slot3 := or( or( or( or(shl(0xc0, lastInterestAccruedTimestamp), shl(0x50, scaleFactor)), shl(0x40, reserveRatioBips) ), or(shl(0x30, annualInterestBips), shl(0x20, protocolFeeBips)) ), timeDelinquent ) sstore(add(_state.slot, 3), slot3) } } emit_StateUpdated(state.scaleFactor, isDelinquent); } /** * @dev Handles an expired withdrawal batch: * - Retrieves the amount of underlying assets that can be used to pay for the batch. * - If the amount is sufficient to pay the full amount owed to the batch, the batch * is closed and the total withdrawal amount is reserved. * - If the amount is insufficient to pay the full amount owed to the batch, the batch * is recorded as an unpaid batch and the available assets are reserved. * - The assets reserved for the batch are scaled by the current scale factor and that * amount of scaled tokens is burned, ensuring borrowers do not continue paying interest * on withdrawn assets. */ function _processExpiredWithdrawalBatch(MarketState memory state) internal { uint32 expiry = state.pendingWithdrawalExpiry; WithdrawalBatch memory batch = _withdrawalData.batches[expiry]; if (batch.scaledAmountBurned < batch.scaledTotalAmount) { // Burn as much of the withdrawal batch as possible with available liquidity. uint256 availableLiquidity = batch.availableLiquidityForPendingBatch(state, totalAssets()); if (availableLiquidity > 0) { _applyWithdrawalBatchPayment(batch, state, expiry, availableLiquidity); } } emit_WithdrawalBatchExpired( expiry, batch.scaledTotalAmount, batch.scaledAmountBurned, batch.normalizedAmountPaid ); if (batch.scaledAmountBurned < batch.scaledTotalAmount) { _withdrawalData.unpaidBatches.push(expiry); } else { emit_WithdrawalBatchClosed(expiry); } state.pendingWithdrawalExpiry = 0; _withdrawalData.batches[expiry] = batch; } /** * @dev Process withdrawal payment, burning market tokens and reserving * underlying assets so they are only available for withdrawals. */ function _applyWithdrawalBatchPayment( WithdrawalBatch memory batch, MarketState memory state, uint32 expiry, uint256 availableLiquidity ) internal returns (uint104 scaledAmountBurned, uint128 normalizedAmountPaid) { uint104 scaledAmountOwed = batch.scaledTotalAmount - batch.scaledAmountBurned; // Do nothing if batch is already paid if (scaledAmountOwed == 0) return (0, 0); uint256 scaledAvailableLiquidity = state.scaleAmount(availableLiquidity); scaledAmountBurned = MathUtils.min(scaledAvailableLiquidity, scaledAmountOwed).toUint104(); // Use mulDiv instead of normalizeAmount to round `normalizedAmountPaid` down, ensuring // it is always possible to finish withdrawal batches on closed markets. normalizedAmountPaid = MathUtils.mulDiv(scaledAmountBurned, state.scaleFactor, RAY).toUint128(); batch.scaledAmountBurned += scaledAmountBurned; batch.normalizedAmountPaid += normalizedAmountPaid; state.scaledPendingWithdrawals -= scaledAmountBurned; // Update normalizedUnclaimedWithdrawals so the tokens are only accessible for withdrawals. state.normalizedUnclaimedWithdrawals += normalizedAmountPaid; // Burn market tokens to stop interest accrual upon withdrawal payment. state.scaledTotalSupply -= scaledAmountBurned; // Emit transfer for external trackers to indicate burn. emit_Transfer(address(this), _runtimeConstant(address(0)), normalizedAmountPaid); emit_WithdrawalBatchPayment(expiry, scaledAmountBurned, normalizedAmountPaid); } function _applyWithdrawalBatchPaymentView( WithdrawalBatch memory batch, MarketState memory state, uint256 availableLiquidity ) internal pure { uint104 scaledAmountOwed = batch.scaledTotalAmount - batch.scaledAmountBurned; // Do nothing if batch is already paid if (scaledAmountOwed == 0) return; uint256 scaledAvailableLiquidity = state.scaleAmount(availableLiquidity); uint104 scaledAmountBurned = MathUtils .min(scaledAvailableLiquidity, scaledAmountOwed) .toUint104(); // Use mulDiv instead of normalizeAmount to round `normalizedAmountPaid` down, ensuring // it is always possible to finish withdrawal batches on closed markets. uint128 normalizedAmountPaid = MathUtils .mulDiv(scaledAmountBurned, state.scaleFactor, RAY) .toUint128(); batch.scaledAmountBurned += scaledAmountBurned; batch.normalizedAmountPaid += normalizedAmountPaid; state.scaledPendingWithdrawals -= scaledAmountBurned; // Update normalizedUnclaimedWithdrawals so the tokens are only accessible for withdrawals. state.normalizedUnclaimedWithdrawals += normalizedAmountPaid; // Burn market tokens to stop interest accrual upon withdrawal payment. state.scaledTotalSupply -= scaledAmountBurned; } /** * @dev Function to obfuscate the fact that a value is constant from solc's optimizer. * This prevents function specialization for calls with a constant input parameter, * which usually has very little benefit in terms of gas savings but can * drastically increase contract size. * * The value returned will always match the input value outside of the constructor, * fallback and receive functions. */ function _runtimeConstant( uint256 actualConstant ) internal pure returns (uint256 runtimeConstant) { assembly { mstore(0, actualConstant) runtimeConstant := mload(iszero(calldatasize())) } } function _runtimeConstant( address actualConstant ) internal pure returns (address runtimeConstant) { assembly { mstore(0, actualConstant) runtimeConstant := mload(iszero(calldatasize())) } } function _isFlaggedByChainalysis(address account) internal view returns (bool isFlagged) { address sentinelAddress = address(sentinel); assembly { mstore(0, 0x95c09839) mstore(0x20, account) if iszero( and(eq(returndatasize(), 0x20), staticcall(gas(), sentinelAddress, 0x1c, 0x24, 0, 0x20)) ) { returndatacopy(0, 0, returndatasize()) revert(0, returndatasize()) } isFlagged := mload(0) } } function _createEscrowForUnderlyingAsset( address accountAddress ) internal returns (address escrow) { address tokenAddress = address(asset); address borrowerAddress = borrower; address sentinelAddress = address(sentinel); assembly { let freeMemoryPointer := mload(0x40) mstore(0, 0xa1054f6b) mstore(0x20, borrowerAddress) mstore(0x40, accountAddress) mstore(0x60, tokenAddress) if iszero( and(eq(returndatasize(), 0x20), call(gas(), sentinelAddress, 0, 0x1c, 0x64, 0, 0x20)) ) { returndatacopy(0, 0, returndatasize()) revert(0, returndatasize()) } escrow := mload(0) mstore(0x40, freeMemoryPointer) mstore(0x60, 0) } } }
// SPDX-License-Identifier: Apache-2.0 WITH LicenseRef-Commons-Clause-1.0 pragma solidity >=0.8.20; import './WildcatMarketBase.sol'; import '../libraries/FeeMath.sol'; import '../libraries/SafeCastLib.sol'; contract WildcatMarketConfig is WildcatMarketBase { using SafeCastLib for uint256; using FunctionTypeCasts for *; // ===================================================================== // // External Config Getters // // ===================================================================== // /** * @dev Returns whether or not a market has been closed. */ function isClosed() external view returns (bool) { // Use stored state because the state update can not affect whether // the market is closed. return _state.isClosed; } /** * @dev Returns the maximum amount of underlying asset that can * currently be deposited to the market. */ function maximumDeposit() external view returns (uint256) { MarketState memory state = _calculateCurrentStatePointers.asReturnsMarketState()(); return state.maximumDeposit(); } /** * @dev Returns the maximum supply the market can reach via * deposits (does not apply to interest accrual). */ function maxTotalSupply() external view returns (uint256) { return _state.maxTotalSupply; } /** * @dev Returns the annual interest rate earned by lenders * in bips. */ function annualInterestBips() external view returns (uint256) { return _state.annualInterestBips; } function reserveRatioBips() external view returns (uint256) { return _state.reserveRatioBips; } // ========================================================================== // // Sanctions // // ========================================================================== // /// @dev Block a sanctioned account from interacting with the market /// and transfer its balance to an escrow contract. // ****************************************************************** // * |\**/| * * * // * \ == / * * * // * | b| * * * // * | y| * * * // * \ e/ * * * // * \/ * * * // * * * * // * * * * // * * |\**/| * * // * * \ == / * _.-^^---....,,-- * // * * | b| * _-- --_ * // * * | y| * < >) * // * * \ e/ * | O-FAC! | * // * * \/ * \._ _./ * // * * * ```--. . , ; .--''' * // * * * 💸 | | | * // * * * .-=|| | |=-. 💸 * // 💰🤑💰 * 😅 * 😐 * 💸 `-=#$%&%$#=-' * // \|/ * /|\ * /|\ * 🌪 | ; :| 🌪 * // /\ * 💰/\ 💰 * 💰/\ 💰 * _____.,-#%&$@%#&#~,._____ * // ****************************************************************** function nukeFromOrbit(address accountAddress) external nonReentrant sphereXGuardExternal { if (!_isSanctioned(accountAddress)) revert_BadLaunchCode(); MarketState memory state = _getUpdatedState(); hooks.onNukeFromOrbit(accountAddress, state); _blockAccount(state, accountAddress); _writeState(state); } // ========================================================================== // // External Config Setters // // ========================================================================== // /** * @dev Sets the maximum total supply - this only limits deposits and * does not affect interest accrual. * * The hooks contract may block the change but can not modify the * value being set. */ function setMaxTotalSupply( uint256 _maxTotalSupply ) external onlyBorrower nonReentrant sphereXGuardExternal { MarketState memory state = _getUpdatedState(); if (state.isClosed) revert_CapacityChangeOnClosedMarket(); hooks.onSetMaxTotalSupply(_maxTotalSupply, state); state.maxTotalSupply = _maxTotalSupply.toUint128(); _writeState(state); emit_MaxTotalSupplyUpdated(_maxTotalSupply); } /** * @dev Sets the annual interest rate earned by lenders in bips. * * If the new reserve ratio is lower than the old ratio, * asserts that the market is not currently delinquent. * * If the new reserve ratio is higher than the old ratio, * asserts that the market will not become delinquent * because of the change. */ function setAnnualInterestAndReserveRatioBips( uint16 _annualInterestBips, uint16 _reserveRatioBips ) external onlyBorrower nonReentrant sphereXGuardExternal { MarketState memory state = _getUpdatedState(); if (state.isClosed) revert_AprChangeOnClosedMarket(); uint256 initialReserveRatioBips = state.reserveRatioBips; (_annualInterestBips, _reserveRatioBips) = hooks.onSetAnnualInterestAndReserveRatioBips( _annualInterestBips, _reserveRatioBips, state ); if (_annualInterestBips > BIP) { revert_AnnualInterestBipsTooHigh(); } if (_reserveRatioBips > BIP) { revert_ReserveRatioBipsTooHigh(); } if (_reserveRatioBips <= initialReserveRatioBips) { if (state.liquidityRequired() > totalAssets()) { revert_InsufficientReservesForOldLiquidityRatio(); } } state.reserveRatioBips = _reserveRatioBips; state.annualInterestBips = _annualInterestBips; if (_reserveRatioBips > initialReserveRatioBips) { if (state.liquidityRequired() > totalAssets()) { revert_InsufficientReservesForNewLiquidityRatio(); } } _writeState(state); emit_AnnualInterestBipsUpdated(_annualInterestBips); emit_ReserveRatioBipsUpdated(_reserveRatioBips); } function setProtocolFeeBips(uint16 _protocolFeeBips) external nonReentrant sphereXGuardExternal { if (msg.sender != factory) revert_NotFactory(); if (_protocolFeeBips > 1_000) revert_ProtocolFeeTooHigh(); MarketState memory state = _getUpdatedState(); if (state.isClosed) revert_ProtocolFeeChangeOnClosedMarket(); if (_protocolFeeBips != state.protocolFeeBips) { hooks.onSetProtocolFeeBips(_protocolFeeBips, state); state.protocolFeeBips = _protocolFeeBips; emit ProtocolFeeBipsUpdated(_protocolFeeBips); } _writeState(state); } }
// SPDX-License-Identifier: Apache-2.0 WITH LicenseRef-Commons-Clause-1.0 pragma solidity >=0.8.20; import './WildcatMarketBase.sol'; contract WildcatMarketToken is WildcatMarketBase { using SafeCastLib for uint256; using FunctionTypeCasts for *; // ========================================================================== // // ERC20 Queries // // ========================================================================== // mapping(address => mapping(address => uint256)) public allowance; /// @notice Returns the normalized balance of `account` with interest. function balanceOf(address account) public view virtual nonReentrantView returns (uint256) { return _calculateCurrentStatePointers.asReturnsMarketState()().normalizeAmount( _accounts[account].scaledBalance ); } /// @notice Returns the normalized total supply with interest. function totalSupply() external view virtual nonReentrantView returns (uint256) { return _calculateCurrentStatePointers.asReturnsMarketState()().totalSupply(); } // ========================================================================== // // ERC20 Actions // // ========================================================================== // function approve( address spender, uint256 amount ) external virtual nonReentrant sphereXGuardExternal returns (bool) { _approve(msg.sender, spender, amount); return true; } function transfer( address to, uint256 amount ) external virtual nonReentrant sphereXGuardExternal returns (bool) { _transfer(msg.sender, to, amount, 0x44); return true; } function transferFrom( address from, address to, uint256 amount ) external virtual nonReentrant sphereXGuardExternal returns (bool) { uint256 allowed = allowance[from][msg.sender]; // Saves gas for unlimited approvals. if (allowed != type(uint256).max) { uint256 newAllowance = allowed - amount; _approve(from, msg.sender, newAllowance); } _transfer(from, to, amount, 0x64); return true; } function _approve(address approver, address spender, uint256 amount) internal virtual { allowance[approver][spender] = amount; emit_Approval(approver, spender, amount); } function _transfer( address from, address to, uint256 amount, uint baseCalldataSize ) internal virtual { MarketState memory state = _getUpdatedState(); uint104 scaledAmount = state.scaleAmount(amount).toUint104(); if (scaledAmount == 0) revert_NullTransferAmount(); hooks.onTransfer(from, to, scaledAmount, state, baseCalldataSize); Account memory fromAccount = _getAccount(from); fromAccount.scaledBalance -= scaledAmount; _accounts[from] = fromAccount; Account memory toAccount = _getAccount(to); toAccount.scaledBalance += scaledAmount; _accounts[to] = toAccount; _writeState(state); emit_Transfer(from, to, amount); } }
// SPDX-License-Identifier: Apache-2.0 WITH LicenseRef-Commons-Clause-1.0 pragma solidity >=0.8.20; import './WildcatMarketBase.sol'; import '../libraries/LibERC20.sol'; import '../libraries/BoolUtils.sol'; contract WildcatMarketWithdrawals is WildcatMarketBase { using LibERC20 for address; using MathUtils for uint256; using MathUtils for bool; using SafeCastLib for uint256; using BoolUtils for bool; // ========================================================================== // // Withdrawal Queries // // ========================================================================== // /** * @dev Returns the expiry timestamp of every unpaid withdrawal batch. */ function getUnpaidBatchExpiries() external view nonReentrantView returns (uint32[] memory) { return _withdrawalData.unpaidBatches.values(); } function getWithdrawalBatch( uint32 expiry ) external view nonReentrantView returns (WithdrawalBatch memory batch) { (, uint32 pendingBatchExpiry, WithdrawalBatch memory pendingBatch) = _calculateCurrentState(); if ((expiry == pendingBatchExpiry).and(expiry > 0)) { return pendingBatch; } WithdrawalBatch storage _batch = _withdrawalData.batches[expiry]; batch.scaledTotalAmount = _batch.scaledTotalAmount; batch.scaledAmountBurned = _batch.scaledAmountBurned; batch.normalizedAmountPaid = _batch.normalizedAmountPaid; } function getAccountWithdrawalStatus( address accountAddress, uint32 expiry ) external view nonReentrantView returns (AccountWithdrawalStatus memory status) { AccountWithdrawalStatus storage _status = _withdrawalData.accountStatuses[expiry][ accountAddress ]; status.scaledAmount = _status.scaledAmount; status.normalizedAmountWithdrawn = _status.normalizedAmountWithdrawn; } function getAvailableWithdrawalAmount( address accountAddress, uint32 expiry ) external view nonReentrantView returns (uint256) { if (expiry >= block.timestamp) { revert_WithdrawalBatchNotExpired(); } (, uint32 pendingBatchExpiry, WithdrawalBatch memory pendingBatch) = _calculateCurrentState(); WithdrawalBatch memory batch; if (expiry == pendingBatchExpiry) { batch = pendingBatch; } else { batch = _withdrawalData.batches[expiry]; } AccountWithdrawalStatus memory status = _withdrawalData.accountStatuses[expiry][accountAddress]; // Rounding errors will lead to some dust accumulating in the batch, but the cost of // executing a withdrawal will be lower for users. uint256 previousTotalWithdrawn = status.normalizedAmountWithdrawn; uint256 newTotalWithdrawn = uint256(batch.normalizedAmountPaid).mulDiv( status.scaledAmount, batch.scaledTotalAmount ); return newTotalWithdrawn - previousTotalWithdrawn; } // ========================================================================== // // Withdrawal Actions // // ========================================================================== // function _queueWithdrawal( MarketState memory state, Account memory account, address accountAddress, uint104 scaledAmount, uint normalizedAmount, uint baseCalldataSize ) internal returns (uint32 expiry) { // Cache batch expiry on the stack for gas savings expiry = state.pendingWithdrawalExpiry; // If there is no pending withdrawal batch, create a new one. if (state.pendingWithdrawalExpiry == 0) { // If the market is closed, use zero for withdrawal batch duration. uint duration = state.isClosed.ternary(0, withdrawalBatchDuration); expiry = uint32(block.timestamp + duration); emit_WithdrawalBatchCreated(expiry); state.pendingWithdrawalExpiry = expiry; } // Execute queueWithdrawal hook if enabled hooks.onQueueWithdrawal(accountAddress, expiry, scaledAmount, state, baseCalldataSize); // Reduce account's balance and emit transfer event account.scaledBalance -= scaledAmount; _accounts[accountAddress] = account; emit_Transfer(accountAddress, address(this), normalizedAmount); WithdrawalBatch memory batch = _withdrawalData.batches[expiry]; // Add scaled withdrawal amount to account withdrawal status, withdrawal batch and market state. _withdrawalData.accountStatuses[expiry][accountAddress].scaledAmount += scaledAmount; batch.scaledTotalAmount += scaledAmount; state.scaledPendingWithdrawals += scaledAmount; emit_WithdrawalQueued(expiry, accountAddress, scaledAmount, normalizedAmount); // Burn as much of the withdrawal batch as possible with available liquidity. uint256 availableLiquidity = batch.availableLiquidityForPendingBatch(state, totalAssets()); if (availableLiquidity > 0) { _applyWithdrawalBatchPayment(batch, state, expiry, availableLiquidity); } // Update stored batch data _withdrawalData.batches[expiry] = batch; // Update stored state _writeState(state); } /** * @dev Create a withdrawal request for a lender. */ function queueWithdrawal( uint256 amount ) external nonReentrant sphereXGuardExternal returns (uint32 expiry) { MarketState memory state = _getUpdatedState(); uint104 scaledAmount = state.scaleAmount(amount).toUint104(); if (scaledAmount == 0) revert_NullBurnAmount(); // Cache account data Account memory account = _getAccount(msg.sender); return _queueWithdrawal(state, account, msg.sender, scaledAmount, amount, _runtimeConstant(0x24)); } /** * @dev Queue a withdrawal for all of the caller's balance. */ function queueFullWithdrawal() external nonReentrant sphereXGuardExternal returns (uint32 expiry) { MarketState memory state = _getUpdatedState(); // Cache account data Account memory account = _getAccount(msg.sender); uint104 scaledAmount = account.scaledBalance; if (scaledAmount == 0) revert_NullBurnAmount(); uint256 normalizedAmount = state.normalizeAmount(scaledAmount); return _queueWithdrawal( state, account, msg.sender, scaledAmount, normalizedAmount, _runtimeConstant(0x04) ); } /** * @dev Execute a pending withdrawal request for a batch that has expired. * * Withdraws the proportional amount of the paid batch owed to * `accountAddress` which has not already been withdrawn. * * If `accountAddress` is sanctioned, transfers the owed amount to * an escrow contract specific to the account and blocks the account. * * Reverts if: * - `expiry >= block.timestamp` * - `expiry` does not correspond to an existing withdrawal batch * - `accountAddress` has already withdrawn the full amount owed */ function executeWithdrawal( address accountAddress, uint32 expiry ) public nonReentrant sphereXGuardExternal returns (uint256) { MarketState memory state = _getUpdatedState(); // Use an obfuscated constant for the base calldata size to prevent solc // function specialization. uint256 normalizedAmountWithdrawn = _executeWithdrawal( state, accountAddress, expiry, _runtimeConstant(0x44) ); // Update stored state _writeState(state); return normalizedAmountWithdrawn; } function executeWithdrawals( address[] calldata accountAddresses, uint32[] calldata expiries ) external nonReentrant sphereXGuardExternal returns (uint256[] memory amounts) { if (accountAddresses.length != expiries.length) revert_InvalidArrayLength(); amounts = new uint256[](accountAddresses.length); MarketState memory state = _getUpdatedState(); for (uint256 i = 0; i < accountAddresses.length; i++) { // Use calldatasize() for baseCalldataSize to indicate no data should be passed as `extraData` amounts[i] = _executeWithdrawal(state, accountAddresses[i], expiries[i], msg.data.length); } // Update stored state _writeState(state); return amounts; } function _executeWithdrawal( MarketState memory state, address accountAddress, uint32 expiry, uint baseCalldataSize ) internal returns (uint256) { WithdrawalBatch memory batch = _withdrawalData.batches[expiry]; if (expiry == state.pendingWithdrawalExpiry) revert_WithdrawalBatchNotExpired(); AccountWithdrawalStatus storage status = _withdrawalData.accountStatuses[expiry][ accountAddress ]; uint128 newTotalWithdrawn = uint128( MathUtils.mulDiv(batch.normalizedAmountPaid, status.scaledAmount, batch.scaledTotalAmount) ); uint128 normalizedAmountWithdrawn = newTotalWithdrawn - status.normalizedAmountWithdrawn; if (normalizedAmountWithdrawn == 0) revert_NullWithdrawalAmount(); hooks.onExecuteWithdrawal(accountAddress, normalizedAmountWithdrawn, state, baseCalldataSize); status.normalizedAmountWithdrawn = newTotalWithdrawn; state.normalizedUnclaimedWithdrawals -= normalizedAmountWithdrawn; if (_isSanctioned(accountAddress)) { // Get or create an escrow contract for the lender and transfer the owed amount to it. // They will be unable to withdraw from the escrow until their sanctioned // status is lifted on Chainalysis, or until the borrower overrides it. address escrow = _createEscrowForUnderlyingAsset(accountAddress); asset.safeTransfer(escrow, normalizedAmountWithdrawn); // Emit `SanctionedAccountWithdrawalSentToEscrow` event using a custom emitter. emit_SanctionedAccountWithdrawalSentToEscrow( accountAddress, escrow, expiry, normalizedAmountWithdrawn ); } else { asset.safeTransfer(accountAddress, normalizedAmountWithdrawn); } emit_WithdrawalExecuted(expiry, accountAddress, normalizedAmountWithdrawn); return normalizedAmountWithdrawn; } function repayAndProcessUnpaidWithdrawalBatches( uint256 repayAmount, uint256 maxBatches ) public nonReentrant sphereXGuardExternal { // Repay before updating state to ensure the paid amount is counted towards // any pending or unpaid withdrawals. if (repayAmount > 0) { asset.safeTransferFrom(msg.sender, address(this), repayAmount); emit_DebtRepaid(msg.sender, repayAmount); } MarketState memory state = _getUpdatedState(); if (state.isClosed) revert_RepayToClosedMarket(); // Use an obfuscated constant for the base calldata size to prevent solc // function specialization. if (repayAmount > 0) hooks.onRepay(repayAmount, state, _runtimeConstant(0x44)); // Calculate assets available to process the first batch - will be updated after each batch uint256 availableLiquidity = totalAssets() - (state.normalizedUnclaimedWithdrawals + state.accruedProtocolFees); // Get the maximum number of batches to process uint256 numBatches = MathUtils.min(maxBatches, _withdrawalData.unpaidBatches.length()); uint256 i; // Process up to `maxBatches` unpaid batches while there is available liquidity while (i++ < numBatches && availableLiquidity > 0) { // Process the next unpaid batch using available liquidity uint256 normalizedAmountPaid = _processUnpaidWithdrawalBatch(state, availableLiquidity); // Reduce liquidity available to next batch availableLiquidity = availableLiquidity.satSub(normalizedAmountPaid); } _writeState(state); } function _processUnpaidWithdrawalBatch( MarketState memory state, uint256 availableLiquidity ) internal returns (uint256 normalizedAmountPaid) { // Get the next unpaid batch timestamp from storage (reverts if none) uint32 expiry = _withdrawalData.unpaidBatches.first(); // Cache batch data in memory WithdrawalBatch memory batch = _withdrawalData.batches[expiry]; // Pay up to the available liquidity to the batch (, normalizedAmountPaid) = _applyWithdrawalBatchPayment( batch, state, expiry, availableLiquidity ); // Update stored batch _withdrawalData.batches[expiry] = batch; // Remove batch from unpaid set if fully paid if (batch.scaledTotalAmount == batch.scaledAmountBurned) { _withdrawalData.unpaidBatches.shift(); emit_WithdrawalBatchClosed(expiry); } } }
// SPDX-License-Identifier: Apache-2.0 WITH LicenseRef-Commons-Clause-1.0 pragma solidity >=0.8.20; import { IChainalysisSanctionsList } from './interfaces/IChainalysisSanctionsList.sol'; import { IWildcatSanctionsSentinel } from './interfaces/IWildcatSanctionsSentinel.sol'; import { WildcatSanctionsEscrow } from './WildcatSanctionsEscrow.sol'; contract WildcatSanctionsSentinel is IWildcatSanctionsSentinel { // ========================================================================== // // Constants // // ========================================================================== // bytes32 public constant override WildcatSanctionsEscrowInitcodeHash = keccak256(type(WildcatSanctionsEscrow).creationCode); address public immutable override chainalysisSanctionsList; address public immutable override archController; // ========================================================================== // // Storage // // ========================================================================== // TmpEscrowParams public override tmpEscrowParams; mapping(address borrower => mapping(address account => bool sanctionOverride)) public override sanctionOverrides; // ========================================================================== // // Constructor // // ========================================================================== // constructor(address _archController, address _chainalysisSanctionsList) { archController = _archController; chainalysisSanctionsList = _chainalysisSanctionsList; _resetTmpEscrowParams(); } // ========================================================================== // // Internal Helpers // // ========================================================================== // function _resetTmpEscrowParams() internal { tmpEscrowParams = TmpEscrowParams(address(1), address(1), address(1)); } /** * @dev Derive create2 salt for an escrow given the borrower, account and asset. * name prefix and symbol prefix. */ function _deriveSalt( address borrower, address account, address asset ) internal pure returns (bytes32 salt) { assembly { // Cache free memory pointer let freeMemoryPointer := mload(0x40) // `keccak256(abi.encode(borrower, account, asset))` mstore(0x00, borrower) mstore(0x20, account) mstore(0x40, asset) salt := keccak256(0, 0x60) // Restore free memory pointer mstore(0x40, freeMemoryPointer) } } // ========================================================================== // // Sanction Queries // // ========================================================================== // /** * @dev Returns boolean indicating whether `account` is sanctioned on Chainalysis. */ function isFlaggedByChainalysis(address account) public view override returns (bool) { return IChainalysisSanctionsList(chainalysisSanctionsList).isSanctioned(account); } /** * @dev Returns boolean indicating whether `account` is sanctioned on Chainalysis * and that status has not been overridden by `borrower`. */ function isSanctioned(address borrower, address account) public view override returns (bool) { return !sanctionOverrides[borrower][account] && isFlaggedByChainalysis(account); } // ========================================================================== // // Sanction Overrides // // ========================================================================== // /** * @dev Overrides the sanction status of `account` for `borrower`. */ function overrideSanction(address account) public override { sanctionOverrides[msg.sender][account] = true; emit SanctionOverride(msg.sender, account); } /** * @dev Removes the sanction override of `account` for `borrower`. */ function removeSanctionOverride(address account) public override { sanctionOverrides[msg.sender][account] = false; emit SanctionOverrideRemoved(msg.sender, account); } // ========================================================================== // // Escrow Deployment // // ========================================================================== // /** * @dev Creates a new WildcatSanctionsEscrow contract for `borrower`, * `account`, and `asset` or returns the existing escrow contract * if one already exists. * * The escrow contract is added to the set of sanction override * addresses for `borrower` so that it can not be blocked. */ function createEscrow( address borrower, address account, address asset ) public override returns (address escrowContract) { escrowContract = getEscrowAddress(borrower, account, asset); // Skip creation if the address code size is non-zero if (escrowContract.code.length != 0) return escrowContract; tmpEscrowParams = TmpEscrowParams(borrower, account, asset); new WildcatSanctionsEscrow{ salt: _deriveSalt(borrower, account, asset) }(); emit NewSanctionsEscrow(borrower, account, asset); sanctionOverrides[borrower][escrowContract] = true; emit SanctionOverride(borrower, escrowContract); _resetTmpEscrowParams(); } /** * @dev Calculate the create2 escrow address for the combination * of `borrower`, `account`, and `asset`. */ function getEscrowAddress( address borrower, address account, address asset ) public view override returns (address escrowAddress) { bytes32 salt = _deriveSalt(borrower, account, asset); bytes32 initCodeHash = WildcatSanctionsEscrowInitcodeHash; assembly { // Cache the free memory pointer so it can be restored at the end let freeMemoryPointer := mload(0x40) // Write 0xff + address(this) to bytes 11:32 mstore(0x00, or(0xff0000000000000000000000000000000000000000, address())) // Write salt to bytes 32:64 mstore(0x20, salt) // Write initcode hash to bytes 64:96 mstore(0x40, initCodeHash) // Calculate create2 hash escrowAddress := and(keccak256(0x0b, 0x55), 0xffffffffffffffffffffffffffffffffffffffff) // Restore the free memory pointer mstore(0x40, freeMemoryPointer) } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.20; /// @dev Selector for `error NoReentrantCalls()` uint256 constant NoReentrantCalls_ErrorSelector = 0x7fa8a987; uint256 constant _REENTRANCY_GUARD_SLOT = 0x929eee14; /** * @title ReentrancyGuard * @author d1ll0n * @notice Changes from original: * - Removed the checks for whether tstore is supported. * @author Modified from Seaport contract by 0age (https://github.com/ProjectOpenSea/seaport-1.6) * * @notice ReentrancyGuard contains a transient storage variable and related * functionality for protecting against reentrancy. */ contract ReentrancyGuard { /** * @dev Revert with an error when a caller attempts to reenter a protected function. * * Note: Only defined for the sake of the interface and readability - the * definition is not directly referenced in the contract code. */ error NoReentrantCalls(); uint256 private constant _NOT_ENTERED = 0; uint256 private constant _ENTERED = 1; /** * @dev Reentrancy guard for state-changing functions. * Reverts if the reentrancy guard is currently set; otherwise, sets * the reentrancy guard, executes the function body, then clears the * reentrancy guard. */ modifier nonReentrant() { _setReentrancyGuard(); _; _clearReentrancyGuard(); } /** * @dev Reentrancy guard for view functions. * Reverts if the reentrancy guard is currently set. */ modifier nonReentrantView() { _assertNonReentrant(); _; } /** * @dev Internal function to ensure that a sentinel value for the reentrancy * guard is not currently set and, if not, to set a sentinel value for * the reentrancy guard. */ function _setReentrancyGuard() internal { assembly { // Retrieve the current value of the reentrancy guard slot. let _reentrancyGuard := tload(_REENTRANCY_GUARD_SLOT) // Ensure that the reentrancy guard is not already set. // Equivalent to `if (_reentrancyGuard != _NOT_ENTERED) revert NoReentrantCalls();` if _reentrancyGuard { mstore(0, NoReentrantCalls_ErrorSelector) revert(0x1c, 0x04) } // Set the reentrancy guard. // Equivalent to `_reentrancyGuard = _ENTERED;` tstore(_REENTRANCY_GUARD_SLOT, _ENTERED) } } /** * @dev Internal function to unset the reentrancy guard sentinel value. */ function _clearReentrancyGuard() internal { assembly { // Equivalent to `_reentrancyGuard = _NOT_ENTERED;` tstore(_REENTRANCY_GUARD_SLOT, _NOT_ENTERED) } } /** * @dev Internal view function to ensure that a sentinel value for the * reentrancy guard is not currently set. */ function _assertNonReentrant() internal view { assembly { // Ensure that the reentrancy guard is not currently set. // Equivalent to `if (_reentrancyGuard != _NOT_ENTERED) revert NoReentrantCalls();` if tload(_REENTRANCY_GUARD_SLOT) { mstore(0, NoReentrantCalls_ErrorSelector) revert(0x1c, 0x04) } } } }
// SPDX-License-Identifier: UNLICENSED // (c) SphereX 2023 Terms&Conditions pragma solidity ^0.8.20; import { ISphereXEngine, ModifierLocals } from './ISphereXEngine.sol'; import './SphereXProtectedEvents.sol'; import './SphereXProtectedErrors.sol'; /** * @title Modified version of SphereXProtectedBase for contracts registered * on Wildcat's arch controller. * * @author Modified from https://github.com/spherex-xyz/spherex-protect-contracts/blob/main/src/SphereXProtectedBase.sol * * @dev In this version, the WildcatArchController deployment is the SphereX operator. * There is no admin because the arch controller address can not be modified. * * All admin functions/events/errors have been removed to reduce contract size. * * SphereX engine address validation is delegated to the arch controller. */ abstract contract SphereXProtectedRegisteredBase { // ========================================================================== // // Constants // // ========================================================================== // /// @dev Storage slot with the address of the SphereX engine contract. bytes32 private constant SPHEREX_ENGINE_STORAGE_SLOT = bytes32(uint256(keccak256('eip1967.spherex.spherex_engine')) - 1); /** * @dev Address of the WildcatArchController deployment. * The arch controller is able to set the SphereX engine address. * The inheriting contract must assign this in the constructor. */ address internal immutable _archController; // ========================================================================== // // Initializer // // ========================================================================== // /** * @dev Initializes the SphereXEngine and emits events for the initial * engine and operator (arch controller). */ function __SphereXProtectedRegisteredBase_init(address engine) internal virtual { emit_ChangedSpherexOperator(address(0), _archController); _setAddress(SPHEREX_ENGINE_STORAGE_SLOT, engine); emit_ChangedSpherexEngineAddress(address(0), engine); } // ========================================================================== // // Events and Errors // // ========================================================================== // error SphereXOperatorRequired(); event ChangedSpherexOperator(address oldSphereXAdmin, address newSphereXAdmin); event ChangedSpherexEngineAddress(address oldEngineAddress, address newEngineAddress); // ========================================================================== // // Local Modifiers // // ========================================================================== // modifier spherexOnlyOperator() { if (msg.sender != _archController) { revert_SphereXOperatorRequired(); } _; } modifier returnsIfNotActivatedPre(ModifierLocals memory locals) { locals.engine = sphereXEngine(); if (locals.engine == address(0)) { return; } _; } modifier returnsIfNotActivatedPost(ModifierLocals memory locals) { if (locals.engine == address(0)) { return; } _; } // ========================================================================== // // Management // // ========================================================================== // /// @dev Returns the current operator address. function sphereXOperator() public view returns (address) { return _archController; } /// @dev Returns the current engine address. function sphereXEngine() public view returns (address) { return _getAddress(SPHEREX_ENGINE_STORAGE_SLOT); } /** * @dev Change the address of the SphereX engine. * * This is also used to enable SphereX protection, which is disabled * when the engine address is 0. * * Note: The new engine is not validated as it would be in `SphereXProtectedBase` * because the operator is the arch controller, which validates the engine * address prior to updating it here. */ function changeSphereXEngine(address newSphereXEngine) external spherexOnlyOperator { address oldEngine = _getAddress(SPHEREX_ENGINE_STORAGE_SLOT); _setAddress(SPHEREX_ENGINE_STORAGE_SLOT, newSphereXEngine); emit_ChangedSpherexEngineAddress(oldEngine, newSphereXEngine); } // ========================================================================== // // Hooks // // ========================================================================== // /** * @dev Wrapper for `_getStorageSlotsAndPreparePostCalldata` that returns * a `uint256` pointer to `locals` rather than the struct itself. * * Declaring a return parameter for a struct will always zero and * allocate memory for every field in the struct. If the parameter * is always reassigned, the gas and memory used on this are wasted. * * Using a `uint256` pointer instead of a struct declaration avoids * this waste while being functionally identical. */ function _sphereXValidateExternalPre() internal returns (uint256 localsPointer) { return _castFunctionToPointerOutput(_getStorageSlotsAndPreparePostCalldata)(_getSelector()); } /** * @dev Internal function for engine communication. We use it to reduce contract size. * Should be called before the code of an external function. * * Queries `storageSlots` from `sphereXValidatePre` on the engine and writes * the result to `locals.storageSlots`, then caches the current storage values * for those slots in `locals.valuesBefore`. * * Also allocates memory for the calldata of the future call to `sphereXValidatePost` * and initializes every value in the calldata except for `gas` and `valuesAfter` data. * * @param num function identifier */ function _getStorageSlotsAndPreparePostCalldata( int256 num ) internal returnsIfNotActivatedPre(locals) returns (ModifierLocals memory locals) { assembly { // Read engine from `locals.engine` - this is filled by `returnsIfNotActivatedPre` let engineAddress := mload(add(locals, 0x60)) // Get free memory pointer - this will be used for the calldata // to `sphereXValidatePre` and then reused for both `storageSlots` // and the future calldata to `sphereXValidatePost` let pointer := mload(0x40) // Call `sphereXValidatePre(num, msg.sender, msg.data)` mstore(pointer, 0x8925ca5a) mstore(add(pointer, 0x20), num) mstore(add(pointer, 0x40), caller()) mstore(add(pointer, 0x60), 0x60) mstore(add(pointer, 0x80), calldatasize()) calldatacopy(add(pointer, 0xa0), 0, calldatasize()) let size := add(0xc4, calldatasize()) if iszero( and(eq(mload(0), 0x20), call(gas(), engineAddress, 0, add(pointer, 28), size, 0, 0x40)) ) { returndatacopy(0, 0, returndatasize()) revert(0, returndatasize()) } let length := mload(0x20) // Set up the memory after the allocation `locals` struct as: // [0x00:0x20]: `storageSlots.length` // [0x20:0x20+(length * 0x20)]: `storageSlots` data // [0x20+(length*0x20):]: calldata for `sphereXValidatePost` // The layout for the `sphereXValidatePost` calldata is: // [0x00:0x20]: num // [0x20:0x40]: gas // [0x40:0x60]: valuesBefore offset (0x80) // [0x60:0x80]: valuesAfter offset (0xa0 + (0x20 * length)) // [0x80:0xa0]: valuesBefore length (0xa0 + (0x20 * length)) // [0xa0:0xa0+(0x20*length)]: valuesBefore data // [0xa0+(0x20*length):0xc0+(0x20*length)] valuesAfter length // [0xc0+(0x20*length):0xc0+(0x40*length)]: valuesAfter data // // size of calldata: 0xc0 + (0x40 * length) // // size of allocation: 0xe0 + (0x60 * length) // Calculate size of array data (excluding length): 32 * length let arrayDataSize := shl(5, length) // Finalize memory allocation with space for `storageSlots` and // the calldata for `sphereXValidatePost`. mstore(0x40, add(pointer, add(0xe0, mul(arrayDataSize, 3)))) // Copy `storageSlots` from returndata to the start of the allocated // memory buffer and write the pointer to `locals.storageSlots` returndatacopy(pointer, 0x20, add(arrayDataSize, 0x20)) mstore(locals, pointer) // Get pointer to future calldata. // Add `32 + arrayDataSize` to skip the allocation for `locals.storageSlots` // @todo *could* put `valuesBefore` before `storageSlots` and reuse // the `storageSlots` buffer for `valuesAfter` let calldataPointer := add(pointer, add(arrayDataSize, 0x20)) // Write `-num` to calldata mstore(calldataPointer, sub(0, num)) // Write `valuesBefore` offset to calldata mstore(add(calldataPointer, 0x40), 0x80) // Write `locals.valuesBefore` pointer mstore(add(locals, 0x20), add(calldataPointer, 0x80)) // Write `valuesAfter` offset to calldata mstore(add(calldataPointer, 0x60), add(0xa0, arrayDataSize)) // Write `gasleft()` to `locals.gas` mstore(add(locals, 0x40), gas()) } _readStorageTo(locals.storageSlots, locals.valuesBefore); } /** * @dev Wrapper for `_callSphereXValidatePost` that takes a pointer * instead of a struct. */ function _sphereXValidateExternalPost(uint256 locals) internal { _castFunctionToPointerInput(_callSphereXValidatePost)(locals); } function _callSphereXValidatePost( ModifierLocals memory locals ) internal returnsIfNotActivatedPost(locals) { uint256 length; bytes32[] memory storageSlots; bytes32[] memory valuesAfter; assembly { storageSlots := mload(locals) length := mload(storageSlots) valuesAfter := add(storageSlots, add(0xc0, shl(6, length))) } _readStorageTo(storageSlots, valuesAfter); assembly { let sphereXEngineAddress := mload(add(locals, 0x60)) let arrayDataSize := shl(5, length) let calldataSize := add(0xc4, shl(1, arrayDataSize)) let calldataPointer := add(storageSlots, add(arrayDataSize, 0x20)) let gasDiff := sub(mload(add(locals, 0x40)), gas()) mstore(add(calldataPointer, 0x20), gasDiff) let slotBefore := sub(calldataPointer, 32) let slotBeforeCache := mload(slotBefore) mstore(slotBefore, 0xf0bd9468) if iszero(call(gas(), sphereXEngineAddress, 0, add(slotBefore, 28), calldataSize, 0, 0)) { returndatacopy(0, 0, returndatasize()) revert(0, returndatasize()) } mstore(slotBefore, slotBeforeCache) } } /// @dev Returns the function selector from the current calldata. function _getSelector() internal pure returns (int256 selector) { assembly { selector := shr(224, calldataload(0)) } } /// @dev Modifier to be incorporated in all external protected non-view functions modifier sphereXGuardExternal() { uint256 localsPointer = _sphereXValidateExternalPre(); _; _sphereXValidateExternalPost(localsPointer); } // ========================================================================== // // Internal Storage Helpers // // ========================================================================== // /// @dev Stores an address in an arbitrary slot function _setAddress(bytes32 slot, address newAddress) internal { assembly { sstore(slot, newAddress) } } /// @dev Returns an address from an arbitrary slot. function _getAddress(bytes32 slot) internal view returns (address addr) { assembly { addr := sload(slot) } } /** * @dev Internal function that reads values from given storage slots * and writes them to a particular memory location. * * @param storageSlots array of storage slots to read * @param values array of values to write values to */ function _readStorageTo(bytes32[] memory storageSlots, bytes32[] memory values) internal view { assembly { let length := mload(storageSlots) let arrayDataSize := shl(5, length) mstore(values, length) let nextSlotPointer := add(storageSlots, 0x20) let nextElementPointer := add(values, 0x20) let endPointer := add(nextElementPointer, shl(5, length)) for { } lt(nextElementPointer, endPointer) { } { mstore(nextElementPointer, sload(mload(nextSlotPointer))) nextElementPointer := add(nextElementPointer, 0x20) nextSlotPointer := add(nextSlotPointer, 0x20) } } } // ========================================================================== // // Function Type Casts // // ========================================================================== // function _castFunctionToPointerInput( function(ModifierLocals memory) internal fnIn ) internal pure returns (function(uint256) internal fnOut) { assembly { fnOut := fnIn } } function _castFunctionToPointerOutput( function(int256) internal returns (ModifierLocals memory) fnIn ) internal pure returns (function(int256) internal returns (uint256) fnOut) { assembly { fnOut := fnIn } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.20; import { MarketState } from '../libraries/MarketState.sol'; interface IMarketEventsAndErrors { /// @notice Error thrown when deposit exceeds maxTotalSupply error MaxSupplyExceeded(); /// @notice Error thrown when non-borrower tries accessing borrower-only actions error NotApprovedBorrower(); /// @notice Error thrown when non-approved lender tries lending to the market error NotApprovedLender(); /// @notice Error thrown when caller other than factory tries changing protocol fee error NotFactory(); /// @notice Error thrown when non-sentinel tries to use nukeFromOrbit error BadLaunchCode(); /// @notice Error thrown when transfer target is blacklisted error AccountBlocked(); error BadRescueAsset(); error BorrowAmountTooHigh(); error InsufficientReservesForFeeWithdrawal(); error WithdrawalBatchNotExpired(); error NullMintAmount(); error NullBurnAmount(); error NullFeeAmount(); error NullTransferAmount(); error NullWithdrawalAmount(); error NullRepayAmount(); error NullBuyBackAmount(); error MarketAlreadyClosed(); error DepositToClosedMarket(); error RepayToClosedMarket(); error BuyBackOnDelinquentMarket(); error BorrowWhileSanctioned(); error BorrowFromClosedMarket(); error AprChangeOnClosedMarket(); error CapacityChangeOnClosedMarket(); error ProtocolFeeChangeOnClosedMarket(); error CloseMarketWithUnpaidWithdrawals(); error AnnualInterestBipsTooHigh(); error ReserveRatioBipsTooHigh(); error ProtocolFeeTooHigh(); /// @dev Error thrown when reserve ratio is set to a value /// that would make the market delinquent. error InsufficientReservesForNewLiquidityRatio(); error InsufficientReservesForOldLiquidityRatio(); error InvalidArrayLength(); event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); event MaxTotalSupplyUpdated(uint256 assets); event ProtocolFeeBipsUpdated(uint256 protocolFeeBips); event AnnualInterestBipsUpdated(uint256 annualInterestBipsUpdated); event ReserveRatioBipsUpdated(uint256 reserveRatioBipsUpdated); event SanctionedAccountAssetsSentToEscrow( address indexed account, address escrow, uint256 amount ); event SanctionedAccountAssetsQueuedForWithdrawal( address indexed account, uint256 expiry, uint256 scaledAmount, uint256 normalizedAmount ); event Deposit(address indexed account, uint256 assetAmount, uint256 scaledAmount); event Borrow(uint256 assetAmount); event DebtRepaid(address indexed from, uint256 assetAmount); event MarketClosed(uint256 timestamp); event FeesCollected(uint256 assets); event StateUpdated(uint256 scaleFactor, bool isDelinquent); event InterestAndFeesAccrued( uint256 fromTimestamp, uint256 toTimestamp, uint256 scaleFactor, uint256 baseInterestRay, uint256 delinquencyFeeRay, uint256 protocolFees ); event AccountSanctioned(address indexed account); // =====================================================================// // Withdrawl Events // // =====================================================================// event WithdrawalBatchExpired( uint256 indexed expiry, uint256 scaledTotalAmount, uint256 scaledAmountBurned, uint256 normalizedAmountPaid ); /// @dev Emitted when a new withdrawal batch is created. event WithdrawalBatchCreated(uint256 indexed expiry); /// @dev Emitted when a withdrawal batch is paid off. event WithdrawalBatchClosed(uint256 indexed expiry); event WithdrawalBatchPayment( uint256 indexed expiry, uint256 scaledAmountBurned, uint256 normalizedAmountPaid ); event WithdrawalQueued( uint256 indexed expiry, address indexed account, uint256 scaledAmount, uint256 normalizedAmount ); event WithdrawalExecuted( uint256 indexed expiry, address indexed account, uint256 normalizedAmount ); event SanctionedAccountWithdrawalSentToEscrow( address indexed account, address escrow, uint32 expiry, uint256 amount ); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.20; interface IERC20 { event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); function totalSupply() external view returns (uint256); function balanceOf(address account) external view returns (uint256); function transfer(address recipient, uint256 amount) external returns (bool); function allowance(address owner, address spender) external view returns (uint256); function approve(address spender, uint256 amount) external returns (bool); function increaseAllowance(address spender, uint256 addedValue) external returns (bool); function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool); function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); function name() external view returns (string memory); function symbol() external view returns (string memory); function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import './access/IHooks.sol'; import './interfaces/WildcatStructsAndEnums.sol'; struct HooksTemplate { /// @dev Asset used to pay origination fee address originationFeeAsset; /// @dev Amount of `originationFeeAsset` paid to deploy a new market using /// an instance of this template. uint80 originationFeeAmount; /// @dev Basis points paid on interest for markets deployed using hooks /// based on this template uint16 protocolFeeBips; /// @dev Whether the template exists bool exists; /// @dev Whether the template is enabled bool enabled; /// @dev Index of the template address in the array of hooks templates uint24 index; /// @dev Address to pay origination and interest fees address feeRecipient; /// @dev Name of the template string name; } interface IHooksFactoryEventsAndErrors { error FeeMismatch(); error NotApprovedBorrower(); error HooksTemplateNotFound(); error HooksTemplateNotAvailable(); error HooksTemplateAlreadyExists(); error DeploymentFailed(); error HooksInstanceNotFound(); error CallerNotArchControllerOwner(); error InvalidFeeConfiguration(); error SaltDoesNotContainSender(); error MarketAlreadyExists(); error HooksInstanceAlreadyExists(); error NameOrSymbolTooLong(); error AssetBlacklisted(); error SetProtocolFeeBipsFailed(); event HooksInstanceDeployed(address hooksInstance, address hooksTemplate); event HooksTemplateAdded( address hooksTemplate, string name, address feeRecipient, address originationFeeAsset, uint80 originationFeeAmount, uint16 protocolFeeBips ); event HooksTemplateDisabled(address hooksTemplate); event HooksTemplateFeesUpdated( address hooksTemplate, address feeRecipient, address originationFeeAsset, uint80 originationFeeAmount, uint16 protocolFeeBips ); event MarketDeployed( address indexed hooksTemplate, address indexed market, string name, string symbol, address asset, uint256 maxTotalSupply, uint256 annualInterestBips, uint256 delinquencyFeeBips, uint256 withdrawalBatchDuration, uint256 reserveRatioBips, uint256 delinquencyGracePeriod, HooksConfig hooks ); } interface IHooksFactory is IHooksFactoryEventsAndErrors { function archController() external view returns (address); function sanctionsSentinel() external view returns (address); function marketInitCodeStorage() external view returns (address); function marketInitCodeHash() external view returns (uint256); /// @dev Set-up function to register the factory as a controller with the arch-controller. /// This enables the factory to register new markets. function registerWithArchController() external; function name() external view returns (string memory); // ========================================================================== // // Hooks Templates // // ========================================================================== // /// @dev Add a hooks template that stores the initcode for the template. /// /// On success: /// - Emits `HooksTemplateAdded` on success. /// - Adds the template to the list of templates. /// - Creates `HooksTemplate` struct with the given parameters mapped to the template address. /// /// Reverts if: /// - The caller is not the owner of the arch-controller. /// - The template already exists. /// - The fee settings are invalid. function addHooksTemplate( address hooksTemplate, string calldata name, address feeRecipient, address originationFeeAsset, uint80 originationFeeAmount, uint16 protocolFeeBips ) external; /// @dev Update the fees for a hooks template. /// /// On success: /// - Emits `HooksTemplateFeesUpdated` on success. /// - Updates the fees for the `HooksTemplate` struct mapped to the template address. /// /// Reverts if: /// - The caller is not the owner of the arch-controller. /// - The template does not exist. /// - The fee settings are invalid. function updateHooksTemplateFees( address hooksTemplate, address feeRecipient, address originationFeeAsset, uint80 originationFeeAmount, uint16 protocolFeeBips ) external; /// @dev Disable a hooks template. /// /// On success: /// - Emits `HooksTemplateDisabled` on success. /// - Disables the `HooksTemplate` struct mapped to the template address. /// /// Reverts if: /// - The caller is not the owner of the arch-controller. /// - The template does not exist. function disableHooksTemplate(address hooksTemplate) external; /// @dev Get the name and fee configuration for an approved hooks template. function getHooksTemplateDetails( address hooksTemplate ) external view returns (HooksTemplate memory); /// @dev Check if a hooks template is approved. function isHooksTemplate(address hooksTemplate) external view returns (bool); /// @dev Get the list of approved hooks templates. function getHooksTemplates() external view returns (address[] memory); function getHooksTemplates( uint256 start, uint256 end ) external view returns (address[] memory arr); function getHooksTemplatesCount() external view returns (uint256); function getMarketsForHooksTemplate( address hooksTemplate ) external view returns (address[] memory); function getMarketsForHooksTemplate( address hooksTemplate, uint256 start, uint256 end ) external view returns (address[] memory arr); function getMarketsForHooksTemplateCount(address hooksTemplate) external view returns (uint256); // ========================================================================== // // Hooks Instances // // ========================================================================== // /// @dev Deploy a hooks instance for an approved template with constructor args. /// /// On success: /// - Emits `HooksInstanceDeployed`. /// - Deploys a new hooks instance with the given templates and constructor args. /// - Maps the hooks instance to the template address. /// /// Reverts if: /// - The caller is not an approved borrower. /// - The template does not exist. /// - The template is not enabled. /// - The deployment fails. function deployHooksInstance( address hooksTemplate, bytes calldata constructorArgs ) external returns (address hooksDeployment); function getHooksInstancesForBorrower(address borrower) external view returns (address[] memory); function getHooksInstancesCountForBorrower(address borrower) external view returns (uint256); /// @dev Check if a hooks instance was deployed by the factory. function isHooksInstance(address hooks) external view returns (bool); /// @dev Get the template that was used to deploy a hooks instance. function getHooksTemplateForInstance(address hooks) external view returns (address); // ========================================================================== // // Markets // // ========================================================================== // function getMarketsForHooksInstance( address hooksInstance ) external view returns (address[] memory); function getMarketsForHooksInstance( address hooksInstance, uint256 start, uint256 len ) external view returns (address[] memory arr); function getMarketsForHooksInstanceCount(address hooksInstance) external view returns (uint256); /// @dev Get the temporarily stored market parameters for a market that is /// currently being deployed. function getMarketParameters() external view returns (MarketParameters memory parameters); /// @dev Deploy a market with an existing hooks deployment (in `parameters.hooks`) /// /// On success: /// - Pays the origination fee (if applicable). /// - Calls `onDeployMarket` on the hooks contract. /// - Deploys a new market with the given parameters. /// - Emits `MarketDeployed`. /// /// Reverts if: /// - The caller is not an approved borrower. /// - The hooks instance does not exist. /// - Payment of origination fee fails. /// - The deployment fails. /// - The call to `onDeployMarket` fails. /// - `originationFeeAsset` does not match the hook template's /// - `originationFeeAmount` does not match the hook template's function deployMarket( DeployMarketInputs calldata parameters, bytes calldata hooksData, bytes32 salt, address originationFeeAsset, uint256 originationFeeAmount ) external returns (address market); /// @dev Deploy a hooks instance for an approved template,then deploy a new market with that /// instance as its hooks contract. /// Will call `onCreateMarket` on `parameters.hooks`. function deployMarketAndHooks( address hooksTemplate, bytes calldata hooksConstructorArgs, DeployMarketInputs calldata parameters, bytes calldata hooksData, bytes32 salt, address originationFeeAsset, uint256 originationFeeAmount ) external returns (address market, address hooks); function computeMarketAddress(bytes32 salt) external view returns (address); function pushProtocolFeeBipsUpdates( address hooksTemplate, uint marketStartIndex, uint marketEndIndex ) external; function pushProtocolFeeBipsUpdates(address hooksTemplate) external; }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.20; import './MathUtils.sol'; import './SafeCastLib.sol'; import './MarketState.sol'; using SafeCastLib for uint256; using MathUtils for uint256; library FeeMath { /** * @dev Function to calculate the interest accumulated using a linear interest rate formula * * @param rateBip The interest rate, in bips * @param timeDelta The time elapsed since the last interest accrual * @return result The interest rate linearly accumulated during the timeDelta, in ray */ function calculateLinearInterestFromBips( uint256 rateBip, uint256 timeDelta ) internal pure returns (uint256 result) { uint256 rate = rateBip.bipToRay(); uint256 accumulatedInterestRay = rate * timeDelta; unchecked { return accumulatedInterestRay / SECONDS_IN_365_DAYS; } } function calculateBaseInterest( MarketState memory state, uint256 timestamp ) internal pure returns (uint256 baseInterestRay) { baseInterestRay = MathUtils.calculateLinearInterestFromBips( state.annualInterestBips, timestamp - state.lastInterestAccruedTimestamp ); } function applyProtocolFee( MarketState memory state, uint256 baseInterestRay ) internal pure returns (uint256 protocolFee) { // Protocol fee is charged in addition to the interest paid to lenders. uint256 protocolFeeRay = uint(state.protocolFeeBips).bipMul(baseInterestRay); protocolFee = uint256(state.scaledTotalSupply).rayMul( uint256(state.scaleFactor).rayMul(protocolFeeRay) ); state.accruedProtocolFees = (state.accruedProtocolFees + protocolFee).toUint128(); } function updateDelinquency( MarketState memory state, uint256 timestamp, uint256 delinquencyFeeBips, uint256 delinquencyGracePeriod ) internal pure returns (uint256 delinquencyFeeRay) { // Calculate the number of seconds the borrower spent in penalized // delinquency since the last update. uint256 timeWithPenalty = updateTimeDelinquentAndGetPenaltyTime( state, delinquencyGracePeriod, timestamp - state.lastInterestAccruedTimestamp ); if (timeWithPenalty > 0) { // Calculate penalty fees on the interest accrued. delinquencyFeeRay = calculateLinearInterestFromBips(delinquencyFeeBips, timeWithPenalty); } } /** * @notice Calculate the number of seconds that the market has been in * penalized delinquency since the last update, and update * `timeDelinquent` in state. * * @dev When `isDelinquent`, equivalent to: * max(0, timeDelta - max(0, delinquencyGracePeriod - previousTimeDelinquent)) * When `!isDelinquent`, equivalent to: * min(timeDelta, max(0, previousTimeDelinquent - delinquencyGracePeriod)) * * @param state Encoded state parameters * @param delinquencyGracePeriod Seconds in delinquency before penalties apply * @param timeDelta Seconds since the last update * @param `timeWithPenalty` Number of seconds since the last update where * the market was in delinquency outside of the grace period. */ function updateTimeDelinquentAndGetPenaltyTime( MarketState memory state, uint256 delinquencyGracePeriod, uint256 timeDelta ) internal pure returns (uint256 /* timeWithPenalty */) { // Seconds in delinquency at last update uint256 previousTimeDelinquent = state.timeDelinquent; if (state.isDelinquent) { // Since the borrower is still delinquent, increase the total // time in delinquency by the time elapsed. state.timeDelinquent = (previousTimeDelinquent + timeDelta).toUint32(); // Calculate the number of seconds the borrower had remaining // in the grace period. uint256 secondsRemainingWithoutPenalty = delinquencyGracePeriod.satSub( previousTimeDelinquent ); // Penalties apply for the number of seconds the market spent in // delinquency outside of the grace period since the last update. return timeDelta.satSub(secondsRemainingWithoutPenalty); } // Reduce the total time in delinquency by the time elapsed, stopping // when it reaches zero. state.timeDelinquent = previousTimeDelinquent.satSub(timeDelta).toUint32(); // Calculate the number of seconds the old timeDelinquent had remaining // outside the grace period, or zero if it was already in the grace period. uint256 secondsRemainingWithPenalty = previousTimeDelinquent.satSub(delinquencyGracePeriod); // Only apply penalties for the remaining time outside of the grace period. return MathUtils.min(secondsRemainingWithPenalty, timeDelta); } /** * @dev Calculates interest and delinquency/protocol fees accrued since last state update * and applies it to cached state, returning the rates for base interest and delinquency * fees and the normalized amount of protocol fees accrued. * * Takes `timestamp` as input to allow separate calculation of interest * before and after withdrawal batch expiry. * * @param state Market scale parameters * @param delinquencyFeeBips Delinquency fee rate (in bips) * @param delinquencyGracePeriod Grace period (in seconds) before delinquency fees apply * @param timestamp Time to calculate interest and fees accrued until * @return baseInterestRay Interest accrued to lenders (ray) * @return delinquencyFeeRay Penalty fee incurred by borrower for delinquency (ray). * @return protocolFee Protocol fee charged on interest (normalized token amount). */ function updateScaleFactorAndFees( MarketState memory state, uint256 delinquencyFeeBips, uint256 delinquencyGracePeriod, uint256 timestamp ) internal pure returns (uint256 baseInterestRay, uint256 delinquencyFeeRay, uint256 protocolFee) { baseInterestRay = state.calculateBaseInterest(timestamp); if (state.protocolFeeBips > 0) { protocolFee = state.applyProtocolFee(baseInterestRay); } if (delinquencyFeeBips > 0) { delinquencyFeeRay = state.updateDelinquency( timestamp, delinquencyFeeBips, delinquencyGracePeriod ); } // Calculate new scaleFactor uint256 prevScaleFactor = state.scaleFactor; uint256 scaleFactorDelta = prevScaleFactor.rayMul(baseInterestRay + delinquencyFeeRay); state.scaleFactor = (prevScaleFactor + scaleFactorDelta).toUint112(); state.lastInterestAccruedTimestamp = uint32(timestamp); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; uint256 constant MaxSupplyExceeded_ErrorSelector = 0x8a164f63; /// @dev Equivalent to `revert MaxSupplyExceeded()` function revert_MaxSupplyExceeded() pure { assembly { mstore(0, 0x8a164f63) revert(0x1c, 0x04) } } uint256 constant CapacityChangeOnClosedMarket_ErrorSelector = 0x81b21078; /// @dev Equivalent to `revert CapacityChangeOnClosedMarket()` function revert_CapacityChangeOnClosedMarket() pure { assembly { mstore(0, 0x81b21078) revert(0x1c, 0x04) } } uint256 constant AprChangeOnClosedMarket_ErrorSelector = 0xb9de88a2; /// @dev Equivalent to `revert AprChangeOnClosedMarket()` function revert_AprChangeOnClosedMarket() pure { assembly { mstore(0, 0xb9de88a2) revert(0x1c, 0x04) } } uint256 constant MarketAlreadyClosed_ErrorSelector = 0x449e5f50; /// @dev Equivalent to `revert MarketAlreadyClosed()` function revert_MarketAlreadyClosed() pure { assembly { mstore(0, 0x449e5f50) revert(0x1c, 0x04) } } uint256 constant NotApprovedBorrower_ErrorSelector = 0x02171e6a; /// @dev Equivalent to `revert NotApprovedBorrower()` function revert_NotApprovedBorrower() pure { assembly { mstore(0, 0x02171e6a) revert(0x1c, 0x04) } } uint256 constant NotApprovedLender_ErrorSelector = 0xe50a45ce; /// @dev Equivalent to `revert NotApprovedLender()` function revert_NotApprovedLender() pure { assembly { mstore(0, 0xe50a45ce) revert(0x1c, 0x04) } } uint256 constant BadLaunchCode_ErrorSelector = 0xa97ab167; /// @dev Equivalent to `revert BadLaunchCode()` function revert_BadLaunchCode() pure { assembly { mstore(0, 0xa97ab167) revert(0x1c, 0x04) } } uint256 constant ReserveRatioBipsTooHigh_ErrorSelector = 0x8ec83073; /// @dev Equivalent to `revert ReserveRatioBipsTooHigh()` function revert_ReserveRatioBipsTooHigh() pure { assembly { mstore(0, 0x8ec83073) revert(0x1c, 0x04) } } /* code size: 25634 initcode size: 28024 errors: -48 runtime, -48 initcode */ uint256 constant AnnualInterestBipsTooHigh_ErrorSelector = 0xcf1f916f; /// @dev Equivalent to `revert ReserveRatioBipsTooHigh()` function revert_AnnualInterestBipsTooHigh() pure { assembly { mstore(0, 0xcf1f916f) revert(0x1c, 0x04) } } uint256 constant AccountBlocked_ErrorSelector = 0x6bc671fd; /// @dev Equivalent to `revert AccountBlocked()` function revert_AccountBlocked() pure { assembly { mstore(0, 0x6bc671fd) revert(0x1c, 0x04) } } uint256 constant BorrowAmountTooHigh_ErrorSelector = 0x119fe6e3; /// @dev Equivalent to `revert BorrowAmountTooHigh()` function revert_BorrowAmountTooHigh() pure { assembly { mstore(0, 0x119fe6e3) revert(0x1c, 0x04) } } uint256 constant BadRescueAsset_ErrorSelector = 0x11530cde; /// @dev Equivalent to `revert BadRescueAsset()` function revert_BadRescueAsset() pure { assembly { mstore(0, 0x11530cde) revert(0x1c, 0x04) } } uint256 constant InsufficientReservesForFeeWithdrawal_ErrorSelector = 0xf784cfa4; /// @dev Equivalent to `revert InsufficientReservesForFeeWithdrawal()` function revert_InsufficientReservesForFeeWithdrawal() pure { assembly { mstore(0, 0xf784cfa4) revert(0x1c, 0x04) } } uint256 constant WithdrawalBatchNotExpired_ErrorSelector = 0x2561b880; /// @dev Equivalent to `revert WithdrawalBatchNotExpired()` function revert_WithdrawalBatchNotExpired() pure { assembly { mstore(0, 0x2561b880) revert(0x1c, 0x04) } } uint256 constant NullMintAmount_ErrorSelector = 0xe4aa5055; /// @dev Equivalent to `revert NullMintAmount()` function revert_NullMintAmount() pure { assembly { mstore(0, 0xe4aa5055) revert(0x1c, 0x04) } } uint256 constant NullBurnAmount_ErrorSelector = 0xd61c50f8; /// @dev Equivalent to `revert NullBurnAmount()` function revert_NullBurnAmount() pure { assembly { mstore(0, 0xd61c50f8) revert(0x1c, 0x04) } } uint256 constant NullFeeAmount_ErrorSelector = 0x45c835cb; /// @dev Equivalent to `revert NullFeeAmount()` function revert_NullFeeAmount() pure { assembly { mstore(0, 0x45c835cb) revert(0x1c, 0x04) } } uint256 constant NullTransferAmount_ErrorSelector = 0xddee9b30; /// @dev Equivalent to `revert NullTransferAmount()` function revert_NullTransferAmount() pure { assembly { mstore(0, 0xddee9b30) revert(0x1c, 0x04) } } uint256 constant NullWithdrawalAmount_ErrorSelector = 0x186334fe; /// @dev Equivalent to `revert NullWithdrawalAmount()` function revert_NullWithdrawalAmount() pure { assembly { mstore(0, 0x186334fe) revert(0x1c, 0x04) } } uint256 constant NullRepayAmount_ErrorSelector = 0x7e082088; /// @dev Equivalent to `revert NullRepayAmount()` function revert_NullRepayAmount() pure { assembly { mstore(0, 0x7e082088) revert(0x1c, 0x04) } } uint256 constant NullBuyBackAmount_ErrorSelector = 0x50394120; /// @dev Equivalent to `revert NullBuyBackAmount()` function revert_NullBuyBackAmount() pure { assembly { mstore(0, 0x50394120) revert(0x1c, 0x04) } } uint256 constant DepositToClosedMarket_ErrorSelector = 0x22d7c043; /// @dev Equivalent to `revert DepositToClosedMarket()` function revert_DepositToClosedMarket() pure { assembly { mstore(0, 0x22d7c043) revert(0x1c, 0x04) } } uint256 constant RepayToClosedMarket_ErrorSelector = 0x61d1bc8f; /// @dev Equivalent to `revert RepayToClosedMarket()` function revert_RepayToClosedMarket() pure { assembly { mstore(0, 0x61d1bc8f) revert(0x1c, 0x04) } } uint256 constant BuyBackOnDelinquentMarket_Selector = 0x1707a7b7; /// @dev Equivalent to `revert BuyBackOnDelinquentMarket()` function revert_BuyBackOnDelinquentMarket() pure { assembly { mstore(0, 0x1707a7b7) revert(0x1c, 0x04) } } uint256 constant BorrowWhileSanctioned_ErrorSelector = 0x4a1c13a9; /// @dev Equivalent to `revert BorrowWhileSanctioned()` function revert_BorrowWhileSanctioned() pure { assembly { mstore(0, 0x4a1c13a9) revert(0x1c, 0x04) } } uint256 constant BorrowFromClosedMarket_ErrorSelector = 0xd0242b28; /// @dev Equivalent to `revert BorrowFromClosedMarket()` function revert_BorrowFromClosedMarket() pure { assembly { mstore(0, 0xd0242b28) revert(0x1c, 0x04) } } uint256 constant CloseMarketWithUnpaidWithdrawals_ErrorSelector = 0x4d790997; /// @dev Equivalent to `revert CloseMarketWithUnpaidWithdrawals()` function revert_CloseMarketWithUnpaidWithdrawals() pure { assembly { mstore(0, 0x4d790997) revert(0x1c, 0x04) } } uint256 constant InsufficientReservesForNewLiquidityRatio_ErrorSelector = 0x253ecbb9; /// @dev Equivalent to `revert InsufficientReservesForNewLiquidityRatio()` function revert_InsufficientReservesForNewLiquidityRatio() pure { assembly { mstore(0, 0x253ecbb9) revert(0x1c, 0x04) } } uint256 constant InsufficientReservesForOldLiquidityRatio_ErrorSelector = 0x0a68e5bf; /// @dev Equivalent to `revert InsufficientReservesForOldLiquidityRatio()` function revert_InsufficientReservesForOldLiquidityRatio() pure { assembly { mstore(0, 0x0a68e5bf) revert(0x1c, 0x04) } } uint256 constant InvalidArrayLength_ErrorSelector = 0x9d89020a; /// @dev Equivalent to `revert InvalidArrayLength()` function revert_InvalidArrayLength() pure { assembly { mstore(0, 0x9d89020a) revert(0x1c, 0x04) } } uint256 constant ProtocolFeeTooHigh_ErrorSelector = 0x499fddb1; /// @dev Equivalent to `revert ProtocolFeeTooHigh()` function revert_ProtocolFeeTooHigh() pure { assembly { mstore(0, 0x499fddb1) revert(0x1c, 0x04) } } uint256 constant ProtocolFeeChangeOnClosedMarket_ErrorSelector = 0x37f1a75f; /// @dev Equivalent to `revert ProtocolFeeChangeOnClosedMarket()` function revert_ProtocolFeeChangeOnClosedMarket() pure { assembly { mstore(0, 0x37f1a75f) revert(0x1c, 0x04) } } uint256 constant NotFactory_ErrorSelector = 0x32cc7236; function revert_NotFactory() pure { assembly { mstore(0, 0x32cc7236) revert(0x1c, 0x04) } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; uint256 constant InterestAndFeesAccrued_abi_head_size = 0xc0; uint256 constant InterestAndFeesAccrued_toTimestamp_offset = 0x20; uint256 constant InterestAndFeesAccrued_scaleFactor_offset = 0x40; uint256 constant InterestAndFeesAccrued_baseInterestRay_offset = 0x60; uint256 constant InterestAndFeesAccrued_delinquencyFeeRay_offset = 0x80; uint256 constant InterestAndFeesAccrued_protocolFees_offset = 0xa0; function emit_Transfer(address from, address to, uint256 value) { assembly { mstore(0, value) log3(0, 0x20, 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, from, to) } } function emit_Approval(address owner, address spender, uint256 value) { assembly { mstore(0, value) log3( 0, 0x20, 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925, owner, spender ) } } function emit_MaxTotalSupplyUpdated(uint256 assets) { assembly { mstore(0, assets) log1(0, 0x20, 0xf2672935fc79f5237559e2e2999dbe743bf65430894ac2b37666890e7c69e1af) } } function emit_ProtocolFeeBipsUpdated(uint256 protocolFeeBips) { assembly { mstore(0, protocolFeeBips) log1(0, 0x20, 0x4b34705283cdb9398d0e50b216b8fb424c6d4def5db9bfadc661ee3adc6076ee) } } function emit_AnnualInterestBipsUpdated(uint256 annualInterestBipsUpdated) { assembly { mstore(0, annualInterestBipsUpdated) log1(0, 0x20, 0xff7b6c8be373823323d3c5d99f5d027dd409dce5db54eae511bbdd5546b75037) } } function emit_ReserveRatioBipsUpdated(uint256 reserveRatioBipsUpdated) { assembly { mstore(0, reserveRatioBipsUpdated) log1(0, 0x20, 0x72877a153052500f5edbb2f9da96a0f45d671d4b4555fdf8628a709dc4eab43a) } } function emit_SanctionedAccountAssetsSentToEscrow(address account, address escrow, uint256 amount) { assembly { mstore(0, escrow) mstore(0x20, amount) log2(0, 0x40, 0x571e706c2f09ae0632313e5f3ae89fffdedfc370a2ea59a07fb0d8091147645b, account) } } function emit_SanctionedAccountAssetsQueuedForWithdrawal( address account, uint32 expiry, uint256 scaledAmount, uint256 normalizedAmount ) { assembly { let freePointer := mload(0x40) mstore(0, expiry) mstore(0x20, scaledAmount) mstore(0x40, normalizedAmount) log2(0, 0x60, 0xe12b220b92469ae28fb0d79de531f94161431be9f073b96b8aad3effb88be6fa, account) mstore(0x40, freePointer) } } function emit_Deposit(address account, uint256 assetAmount, uint256 scaledAmount) { assembly { mstore(0, assetAmount) mstore(0x20, scaledAmount) log2(0, 0x40, 0x90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a15, account) } } function emit_Borrow(uint256 assetAmount) { assembly { mstore(0, assetAmount) log1(0, 0x20, 0xb848ae6b1253b6cb77e81464128ce8bd94d3d524fea54e801e0da869784dca33) } } function emit_DebtRepaid(address from, uint256 assetAmount) { assembly { mstore(0, assetAmount) log2(0, 0x20, 0xe8b606ac1e5df7657db58d297ca8f41c090fc94c5fd2d6958f043e41736e9fa6, from) } } function emit_MarketClosed(uint256 _timestamp) { assembly { mstore(0, _timestamp) log1(0, 0x20, 0x9dc30b8eda31a6a144e092e5de600955523a6a925cc15cc1d1b9b4872cfa6155) } } function emit_FeesCollected(uint256 assets) { assembly { mstore(0, assets) log1(0, 0x20, 0x860c0aa5520013080c2f65981705fcdea474d9f7c3daf954656ed5e65d692d1f) } } function emit_StateUpdated(uint256 scaleFactor, bool isDelinquent) { assembly { mstore(0, scaleFactor) mstore(0x20, isDelinquent) log1(0, 0x40, 0x9385f9ff65bcd2fb81cece54b27d4ec7376795fc4dcff686e370e347b0ed86c0) } } function emit_InterestAndFeesAccrued( uint256 fromTimestamp, uint256 toTimestamp, uint256 scaleFactor, uint256 baseInterestRay, uint256 delinquencyFeeRay, uint256 protocolFees ) { assembly { let dst := mload(0x40) /// Copy fromTimestamp mstore(dst, fromTimestamp) /// Copy toTimestamp mstore(add(dst, InterestAndFeesAccrued_toTimestamp_offset), toTimestamp) /// Copy scaleFactor mstore(add(dst, InterestAndFeesAccrued_scaleFactor_offset), scaleFactor) /// Copy baseInterestRay mstore(add(dst, InterestAndFeesAccrued_baseInterestRay_offset), baseInterestRay) /// Copy delinquencyFeeRay mstore(add(dst, InterestAndFeesAccrued_delinquencyFeeRay_offset), delinquencyFeeRay) /// Copy protocolFees mstore(add(dst, InterestAndFeesAccrued_protocolFees_offset), protocolFees) log1( dst, InterestAndFeesAccrued_abi_head_size, 0x18247a393d0531b65fbd94f5e78bc5639801a4efda62ae7b43533c4442116c3a ) } } function emit_WithdrawalBatchExpired( uint256 expiry, uint256 scaledTotalAmount, uint256 scaledAmountBurned, uint256 normalizedAmountPaid ) { assembly { let freePointer := mload(0x40) mstore(0, scaledTotalAmount) mstore(0x20, scaledAmountBurned) mstore(0x40, normalizedAmountPaid) log2(0, 0x60, 0x9262dc39b47cad3a0512e4c08dda248cb345e7163058f300bc63f56bda288b6e, expiry) mstore(0x40, freePointer) } } function emit_WithdrawalBatchCreated(uint256 expiry) { assembly { log2(0, 0x00, 0x5c9a946d3041134198ebefcd814de7748def6576efd3d1b48f48193e183e89ef, expiry) } } function emit_WithdrawalBatchClosed(uint256 expiry) { assembly { log2(0, 0x00, 0xcbdf25bf6e096dd9030d89bb2ba2e3e7adb82d25a233c3ca3d92e9f098b74e55, expiry) } } function emit_WithdrawalBatchPayment( uint256 expiry, uint256 scaledAmountBurned, uint256 normalizedAmountPaid ) { assembly { mstore(0, scaledAmountBurned) mstore(0x20, normalizedAmountPaid) log2(0, 0x40, 0x5272034725119f19d7236de4129fdb5093f0dcb80282ca5edbd587df91d2bd89, expiry) } } function emit_WithdrawalQueued( uint256 expiry, address account, uint256 scaledAmount, uint256 normalizedAmount ) { assembly { mstore(0, scaledAmount) mstore(0x20, normalizedAmount) log3( 0, 0x40, 0xecc966b282a372469fa4d3e497c2ac17983c3eaed03f3f17c9acf4b15591663e, expiry, account ) } } function emit_WithdrawalExecuted(uint256 expiry, address account, uint256 normalizedAmount) { assembly { mstore(0, normalizedAmount) log3( 0, 0x20, 0xd6cddb3d69146e96ebc2c87b1b3dd0b20ee2d3b0eadf134e011afb434a3e56e6, expiry, account ) } } function emit_SanctionedAccountWithdrawalSentToEscrow( address account, address escrow, uint32 expiry, uint256 amount ) { assembly { let freePointer := mload(0x40) mstore(0, escrow) mstore(0x20, expiry) mstore(0x40, amount) log2(0, 0x60, 0x0d0843a0fcb8b83f625aafb6e42f234ac48c6728b207d52d97cfa8fbd34d498f, account) mstore(0x40, freePointer) } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.20; import './MarketState.sol'; import './FIFOQueue.sol'; using MathUtils for uint256; using WithdrawalLib for WithdrawalBatch global; /** * Withdrawals are grouped together in batches with a fixed expiry. * Until a withdrawal is paid out, the tokens are not burned from the market * and continue to accumulate interest. */ struct WithdrawalBatch { // Total scaled amount of tokens to be withdrawn uint104 scaledTotalAmount; // Amount of scaled tokens that have been paid by borrower uint104 scaledAmountBurned; // Amount of normalized tokens that have been paid by borrower uint128 normalizedAmountPaid; } struct AccountWithdrawalStatus { uint104 scaledAmount; uint128 normalizedAmountWithdrawn; } struct WithdrawalData { FIFOQueue unpaidBatches; mapping(uint32 => WithdrawalBatch) batches; mapping(uint256 => mapping(address => AccountWithdrawalStatus)) accountStatuses; } library WithdrawalLib { function scaledOwedAmount(WithdrawalBatch memory batch) internal pure returns (uint104) { return batch.scaledTotalAmount - batch.scaledAmountBurned; } /** * @dev Get the amount of assets which are not already reserved * for prior withdrawal batches. This must only be used on * the latest withdrawal batch to expire. */ function availableLiquidityForPendingBatch( WithdrawalBatch memory batch, MarketState memory state, uint256 totalAssets ) internal pure returns (uint256) { // Subtract normalized value of pending scaled withdrawals, processed // withdrawals and protocol fees. uint256 priorScaledAmountPending = (state.scaledPendingWithdrawals - batch.scaledOwedAmount()); uint256 unavailableAssets = state.normalizedUnclaimedWithdrawals + state.normalizeAmount(priorScaledAmountPending) + state.accruedProtocolFees; return totalAssets.satSub(unavailableAssets); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.20; import { MarketParameters } from '../interfaces/WildcatStructsAndEnums.sol'; import { MarketState } from '../libraries/MarketState.sol'; import { WithdrawalBatch } from '../libraries/Withdrawal.sol'; /** * @dev Type-casts to convert functions returning raw (uint) pointers * to functions returning memory pointers of specific types. * * Used to get around solc's over-allocation of memory when * dynamic return parameters are re-assigned. * * With `viaIR` enabled, calling any of these functions is a noop. */ library FunctionTypeCasts { /** * @dev Function type cast to avoid duplicate declaration/allocation * of MarketState return parameter. */ function asReturnsMarketState( function() internal view returns (uint256) fnIn ) internal pure returns (function() internal view returns (MarketState memory) fnOut) { assembly { fnOut := fnIn } } /** * @dev Function type cast to avoid duplicate declaration/allocation * of MarketState and WithdrawalBatch return parameters. */ function asReturnsPointers( function() internal view returns (MarketState memory, uint32, WithdrawalBatch memory) fnIn ) internal pure returns (function() internal view returns (uint256, uint32, uint256) fnOut) { assembly { fnOut := fnIn } } /** * @dev Function type cast to avoid duplicate declaration/allocation * of manually allocated MarketParameters in market constructor. */ function asReturnsMarketParameters( function() internal view returns (uint256) fnIn ) internal pure returns (function() internal view returns (MarketParameters memory) fnOut) { assembly { fnOut := fnIn } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import './StringQuery.sol'; /// @notice Safe ERC20 library /// @author d1ll0n /// @notice Changes from solady: /// - Removed Permit2 and ETH functions /// - `balanceOf(address)` reverts if the call fails or does not return >=32 bytes /// - Added queries for `name`, `symbol`, `decimals` /// - Set name to LibERC20 as it has queries unrelated to transfers and ETH functions were removed /// @author Modified from Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibERC20.sol) /// @author Previously modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibERC20.sol) /// /// @dev Note: /// - For ERC20s, this implementation won't check that a token has code, /// responsibility is delegated to the caller. library LibERC20 { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The ERC20 `transferFrom` has failed. error TransferFromFailed(); /// @dev The ERC20 `transfer` has failed. error TransferFailed(); /// @dev The ERC20 `balanceOf` call has failed. error BalanceOfFailed(); /// @dev The ERC20 `name` call has failed. error NameFailed(); /// @dev The ERC20 `symbol` call has failed. error SymbolFailed(); /// @dev The ERC20 `decimals` call has failed. error DecimalsFailed(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC20 OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Sends `amount` of ERC20 `token` from `from` to `to`. /// Reverts upon failure. /// /// The `from` account must have at least `amount` approved for /// the current contract to manage. function safeTransferFrom(address token, address from, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, amount) // Store the `amount` argument. mstore(0x40, to) // Store the `to` argument. mstore(0x2c, shl(96, from)) // Store the `from` argument. mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`. // Perform the transfer, reverting upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20) ) ) { mstore(0x00, 0x7939f424) // `TransferFromFailed()`. revert(0x1c, 0x04) } mstore(0x60, 0) // Restore the zero slot to zero. mstore(0x40, m) // Restore the free memory pointer. } } /// @dev Sends `amount` of ERC20 `token` from the current contract to `to`. /// Reverts upon failure. function safeTransfer(address token, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { mstore(0x14, to) // Store the `to` argument. mstore(0x34, amount) // Store the `amount` argument. mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`. // Perform the transfer, reverting upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) ) ) { mstore(0x00, 0x90b8ec18) // `TransferFailed()`. revert(0x1c, 0x04) } mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten. } } /// @dev Sends all of ERC20 `token` from the current contract to `to`. /// Reverts upon failure. function safeTransferAll(address token, address to) internal returns (uint256 amount) { /// @solidity memory-safe-assembly assembly { mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`. mstore(0x20, address()) // Store the address of the current contract. // Read the balance, reverting upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. gt(returndatasize(), 0x1f), // At least 32 bytes returned. staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20) ) ) { mstore(0x00, 0x90b8ec18) // `TransferFailed()`. revert(0x1c, 0x04) } mstore(0x14, to) // Store the `to` argument. amount := mload(0x34) // The `amount` is already at 0x34. We'll need to return it. mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`. // Perform the transfer, reverting upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) ) ) { mstore(0x00, 0x90b8ec18) // `TransferFailed()`. revert(0x1c, 0x04) } mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten. } } /// @dev Returns the amount of ERC20 `token` owned by `account`. /// Reverts if the call to `balanceOf` reverts or returns less than 32 bytes. function balanceOf(address token, address account) internal view returns (uint256 amount) { /// @solidity memory-safe-assembly assembly { mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`. mstore(0x20, account) // Store the `account` argument. // Read the balance, reverting upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. gt(returndatasize(), 0x1f), // At least 32 bytes returned. staticcall(gas(), token, 0x1c, 0x24, 0x00, 0x20) ) ) { mstore(0x00, 0x4963f6d5) // `BalanceOfFailed()`. revert(0x1c, 0x04) } amount := mload(0x00) } } /// @dev Returns the `decimals` of ERC20 `token`. /// Reverts if the call to `decimals` reverts or returns less than 32 bytes. function decimals(address token) internal view returns (uint8 _decimals) { assembly { // Write selector for `decimals()` to the end of the first word // of scratch space. mstore(0, 0x313ce567) // Call `asset.decimals()`, writing up to 32 bytes of returndata // to scratch space, overwriting the calldata used for the call. // Reverts if the call fails, does not return exactly 32 bytes, or the returndata // exceeds 8 bits. if iszero( and( and(eq(returndatasize(), 0x20), lt(mload(0), 0x100)), staticcall(gas(), token, 0x1c, 0x04, 0, 0x20) ) ) { mstore(0x00, 0x3394d170) // `DecimalsFailed()`. revert(0x1c, 0x04) } // Read the return value from scratch space _decimals := mload(0) } } /// @dev Returns the `name` of ERC20 `token`. /// Reverts if the call to `name` reverts or returns a value which is neither /// a bytes32 string nor a valid ABI-encoded string. function name(address token) internal view returns (string memory) { // The `name` function selector is 0x06fdde03. // The `NameFailed` error selector is 0x2ed09f54. return queryStringOrBytes32AsString(token, 0x06fdde03, 0x2ed09f54); } /// @dev Returns the `symbol` of ERC20 `token`. /// Reverts if the call to `symbol` reverts or returns a value which is neither /// a bytes32 string nor a valid ABI-encoded string. function symbol(address token) internal view returns (string memory) { // The `symbol` function selector is 0x95d89b41. // The `SymbolFailed` error selector is 0x3ddcc60a. return queryStringOrBytes32AsString(token, 0x95d89b41, 0x3ddcc60a); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.20; import '../access/IHooks.sol'; import '../libraries/MarketState.sol'; type HooksConfig is uint256; HooksConfig constant EmptyHooksConfig = HooksConfig.wrap(0); using LibHooksConfig for HooksConfig global; using LibHooksConfig for HooksDeploymentConfig global; // Type that contains only the flags for a specific hooks contract, with one // set of flags for optional hooks and one set of flags for required hooks. type HooksDeploymentConfig is uint256; function encodeHooksDeploymentConfig( HooksConfig optionalFlags, HooksConfig requiredFlags ) pure returns (HooksDeploymentConfig flags) { assembly { let cleanedOptionalFlags := and(0xffff, shr(0x50, optionalFlags)) let cleanedRequiredFlags := and(0xffff0000, shr(0x40, requiredFlags)) flags := or(cleanedOptionalFlags, cleanedRequiredFlags) } } // --------------------- Bits after hook activation flag -------------------- // // Offsets are from the right uint256 constant Bit_Enabled_Deposit = 95; uint256 constant Bit_Enabled_QueueWithdrawal = 94; uint256 constant Bit_Enabled_ExecuteWithdrawal = 93; uint256 constant Bit_Enabled_Transfer = 92; uint256 constant Bit_Enabled_Borrow = 91; uint256 constant Bit_Enabled_Repay = 90; uint256 constant Bit_Enabled_CloseMarket = 89; uint256 constant Bit_Enabled_NukeFromOrbit = 88; uint256 constant Bit_Enabled_SetMaxTotalSupply = 87; uint256 constant Bit_Enabled_SetAnnualInterestAndReserveRatioBips = 86; uint256 constant Bit_Enabled_SetProtocolFeeBips = 85; uint256 constant MarketStateSize = 0x01c0; function encodeHooksConfig( address hooksAddress, bool useOnDeposit, bool useOnQueueWithdrawal, bool useOnExecuteWithdrawal, bool useOnTransfer, bool useOnBorrow, bool useOnRepay, bool useOnCloseMarket, bool useOnNukeFromOrbit, bool useOnSetMaxTotalSupply, bool useOnSetAnnualInterestAndReserveRatioBips, bool useOnSetProtocolFeeBips ) pure returns (HooksConfig hooks) { assembly { hooks := shl(96, hooksAddress) hooks := or(hooks, shl(Bit_Enabled_Deposit, useOnDeposit)) hooks := or(hooks, shl(Bit_Enabled_QueueWithdrawal, useOnQueueWithdrawal)) hooks := or(hooks, shl(Bit_Enabled_ExecuteWithdrawal, useOnExecuteWithdrawal)) hooks := or(hooks, shl(Bit_Enabled_Transfer, useOnTransfer)) hooks := or(hooks, shl(Bit_Enabled_Borrow, useOnBorrow)) hooks := or(hooks, shl(Bit_Enabled_Repay, useOnRepay)) hooks := or(hooks, shl(Bit_Enabled_CloseMarket, useOnCloseMarket)) hooks := or(hooks, shl(Bit_Enabled_NukeFromOrbit, useOnNukeFromOrbit)) hooks := or(hooks, shl(Bit_Enabled_SetMaxTotalSupply, useOnSetMaxTotalSupply)) hooks := or( hooks, shl( Bit_Enabled_SetAnnualInterestAndReserveRatioBips, useOnSetAnnualInterestAndReserveRatioBips ) ) hooks := or(hooks, shl(Bit_Enabled_SetProtocolFeeBips, useOnSetProtocolFeeBips)) } } library LibHooksConfig { function setHooksAddress( HooksConfig hooks, address _hooksAddress ) internal pure returns (HooksConfig updatedHooks) { assembly { // Shift twice to clear the address updatedHooks := shr(160, shl(160, hooks)) // Set the new address updatedHooks := or(updatedHooks, shl(96, _hooksAddress)) } } /** * @dev Create a merged HooksConfig with the shared flags of `a` and `b` * and the address of `a`. */ function mergeSharedFlags( HooksConfig a, HooksConfig b ) internal pure returns (HooksConfig merged) { assembly { let addressA := shl(0x60, shr(0x60, a)) let flagsA := shl(0xa0, a) let flagsB := shl(0xa0, b) let mergedFlags := shr(0xa0, and(flagsA, flagsB)) merged := or(addressA, mergedFlags) } } /** * @dev Create a merged HooksConfig with the shared flags of `a` and `b` * and the address of `a`. */ function mergeAllFlags(HooksConfig a, HooksConfig b) internal pure returns (HooksConfig merged) { assembly { let addressA := shl(0x60, shr(0x60, a)) let flagsA := shl(0xa0, a) let flagsB := shl(0xa0, b) let mergedFlags := shr(0xa0, or(flagsA, flagsB)) merged := or(addressA, mergedFlags) } } function mergeFlags( HooksConfig config, HooksDeploymentConfig flags ) internal pure returns (HooksConfig merged) { assembly { let _hooksAddress := shl(96, shr(96, config)) // Position flags at the end of the word let configFlags := shr(0x50, config) // Optional flags are already in the right position, required flags must be // shifted to align with the other flags. The leading and trailing bits for all 3 // words will be masked out at the end let _optionalFlags := flags let _requiredFlags := shr(0x10, flags) let mergedFlags := and(0xffff, or(and(configFlags, _optionalFlags), _requiredFlags)) merged := or(_hooksAddress, shl(0x50, mergedFlags)) } } function optionalFlags(HooksDeploymentConfig flags) internal pure returns (HooksConfig config) { assembly { config := shl(0x50, and(flags, 0xffff)) } } function requiredFlags(HooksDeploymentConfig flags) internal pure returns (HooksConfig config) { assembly { config := shl(0x40, and(flags, 0xffff0000)) } } // ========================================================================== // // Parameter Readers // // ========================================================================== // function readFlag(HooksConfig hooks, uint256 bitsAfter) internal pure returns (bool flagged) { assembly { flagged := and(shr(bitsAfter, hooks), 1) } } function setFlag( HooksConfig hooks, uint256 bitsAfter ) internal pure returns (HooksConfig updatedHooks) { assembly { updatedHooks := or(hooks, shl(bitsAfter, 1)) } } function clearFlag( HooksConfig hooks, uint256 bitsAfter ) internal pure returns (HooksConfig updatedHooks) { assembly { updatedHooks := and(hooks, not(shl(bitsAfter, 1))) } } /// @dev Address of the hooks contract function hooksAddress(HooksConfig hooks) internal pure returns (address _hooks) { assembly { _hooks := shr(96, hooks) } } /// @dev Whether to call hook contract for deposit function useOnDeposit(HooksConfig hooks) internal pure returns (bool) { return hooks.readFlag(Bit_Enabled_Deposit); } /// @dev Whether to call hook contract for queueWithdrawal function useOnQueueWithdrawal(HooksConfig hooks) internal pure returns (bool) { return hooks.readFlag(Bit_Enabled_QueueWithdrawal); } /// @dev Whether to call hook contract for executeWithdrawal function useOnExecuteWithdrawal(HooksConfig hooks) internal pure returns (bool) { return hooks.readFlag(Bit_Enabled_ExecuteWithdrawal); } /// @dev Whether to call hook contract for transfer function useOnTransfer(HooksConfig hooks) internal pure returns (bool) { return hooks.readFlag(Bit_Enabled_Transfer); } /// @dev Whether to call hook contract for borrow function useOnBorrow(HooksConfig hooks) internal pure returns (bool) { return hooks.readFlag(Bit_Enabled_Borrow); } /// @dev Whether to call hook contract for repay function useOnRepay(HooksConfig hooks) internal pure returns (bool) { return hooks.readFlag(Bit_Enabled_Repay); } /// @dev Whether to call hook contract for closeMarket function useOnCloseMarket(HooksConfig hooks) internal pure returns (bool) { return hooks.readFlag(Bit_Enabled_CloseMarket); } /// @dev Whether to call hook contract when account sanctioned function useOnNukeFromOrbit(HooksConfig hooks) internal pure returns (bool) { return hooks.readFlag(Bit_Enabled_NukeFromOrbit); } /// @dev Whether to call hook contract for setMaxTotalSupply function useOnSetMaxTotalSupply(HooksConfig hooks) internal pure returns (bool) { return hooks.readFlag(Bit_Enabled_SetMaxTotalSupply); } /// @dev Whether to call hook contract for setAnnualInterestAndReserveRatioBips function useOnSetAnnualInterestAndReserveRatioBips( HooksConfig hooks ) internal pure returns (bool) { return hooks.readFlag(Bit_Enabled_SetAnnualInterestAndReserveRatioBips); } /// @dev Whether to call hook contract for setProtocolFeeBips function useOnSetProtocolFeeBips(HooksConfig hooks) internal pure returns (bool) { return hooks.readFlag(Bit_Enabled_SetProtocolFeeBips); } // ========================================================================== // // Hook for deposit // // ========================================================================== // uint256 internal constant DepositCalldataSize = 0x24; // Size of lender + scaledAmount + state + extraData.offset + extraData.length uint256 internal constant DepositHook_Base_Size = 0x0244; uint256 internal constant DepositHook_ScaledAmount_Offset = 0x20; uint256 internal constant DepositHook_State_Offset = 0x40; uint256 internal constant DepositHook_ExtraData_Head_Offset = 0x200; uint256 internal constant DepositHook_ExtraData_Length_Offset = 0x0220; uint256 internal constant DepositHook_ExtraData_TailOffset = 0x0240; function onDeposit( HooksConfig self, address lender, uint256 scaledAmount, MarketState memory state ) internal { address target = self.hooksAddress(); uint32 onDepositSelector = uint32(IHooks.onDeposit.selector); if (self.useOnDeposit()) { assembly { let extraCalldataBytes := sub(calldatasize(), DepositCalldataSize) let cdPointer := mload(0x40) let headPointer := add(cdPointer, 0x20) // Write selector for `onDeposit` mstore(cdPointer, onDepositSelector) // Write `lender` to hook calldata mstore(headPointer, lender) // Write `scaledAmount` to hook calldata mstore(add(headPointer, DepositHook_ScaledAmount_Offset), scaledAmount) // Copy market state to hook calldata mcopy(add(headPointer, DepositHook_State_Offset), state, MarketStateSize) // Write bytes offset for `extraData` mstore( add(headPointer, DepositHook_ExtraData_Head_Offset), DepositHook_ExtraData_Length_Offset ) // Write length for `extraData` mstore(add(headPointer, DepositHook_ExtraData_Length_Offset), extraCalldataBytes) // Copy `extraData` from end of calldata to hook calldata calldatacopy( add(headPointer, DepositHook_ExtraData_TailOffset), DepositCalldataSize, extraCalldataBytes ) let size := add(DepositHook_Base_Size, extraCalldataBytes) if iszero(call(gas(), target, 0, add(cdPointer, 0x1c), size, 0, 0)) { returndatacopy(0, 0, returndatasize()) revert(0, returndatasize()) } } } } // ========================================================================== // // Hook for queueWithdrawal // // ========================================================================== // // Size of lender + scaledAmount + state + extraData.offset + extraData.length uint256 internal constant QueueWithdrawalHook_Base_Size = 0x0264; uint256 internal constant QueueWithdrawalHook_Expiry_Offset = 0x20; uint256 internal constant QueueWithdrawalHook_ScaledAmount_Offset = 0x40; uint256 internal constant QueueWithdrawalHook_State_Offset = 0x60; uint256 internal constant QueueWithdrawalHook_ExtraData_Head_Offset = 0x220; uint256 internal constant QueueWithdrawalHook_ExtraData_Length_Offset = 0x0240; uint256 internal constant QueueWithdrawalHook_ExtraData_TailOffset = 0x0260; function onQueueWithdrawal( HooksConfig self, address lender, uint32 expiry, uint256 scaledAmount, MarketState memory state, uint256 baseCalldataSize ) internal { address target = self.hooksAddress(); uint32 onQueueWithdrawalSelector = uint32(IHooks.onQueueWithdrawal.selector); if (self.useOnQueueWithdrawal()) { assembly { let extraCalldataBytes := sub(calldatasize(), baseCalldataSize) let cdPointer := mload(0x40) let headPointer := add(cdPointer, 0x20) // Write selector for `onQueueWithdrawal` mstore(cdPointer, onQueueWithdrawalSelector) // Write `lender` to hook calldata mstore(headPointer, lender) // Write `expiry` to hook calldata mstore(add(headPointer, QueueWithdrawalHook_Expiry_Offset), expiry) // Write `scaledAmount` to hook calldata mstore(add(headPointer, QueueWithdrawalHook_ScaledAmount_Offset), scaledAmount) // Copy market state to hook calldata mcopy(add(headPointer, QueueWithdrawalHook_State_Offset), state, MarketStateSize) // Write bytes offset for `extraData` mstore( add(headPointer, QueueWithdrawalHook_ExtraData_Head_Offset), QueueWithdrawalHook_ExtraData_Length_Offset ) // Write length for `extraData` mstore(add(headPointer, QueueWithdrawalHook_ExtraData_Length_Offset), extraCalldataBytes) // Copy `extraData` from end of calldata to hook calldata calldatacopy( add(headPointer, QueueWithdrawalHook_ExtraData_TailOffset), baseCalldataSize, extraCalldataBytes ) let size := add(QueueWithdrawalHook_Base_Size, extraCalldataBytes) if iszero(call(gas(), target, 0, add(cdPointer, 0x1c), size, 0, 0)) { returndatacopy(0, 0, returndatasize()) revert(0, returndatasize()) } } } } // ========================================================================== // // Hook for executeWithdrawal // // ========================================================================== // // Size of lender + scaledAmount + state + extraData.offset + extraData.length uint256 internal constant ExecuteWithdrawalHook_Base_Size = 0x0244; uint256 internal constant ExecuteWithdrawalHook_ScaledAmount_Offset = 0x20; uint256 internal constant ExecuteWithdrawalHook_State_Offset = 0x40; uint256 internal constant ExecuteWithdrawalHook_ExtraData_Head_Offset = 0x0200; uint256 internal constant ExecuteWithdrawalHook_ExtraData_Length_Offset = 0x0220; uint256 internal constant ExecuteWithdrawalHook_ExtraData_TailOffset = 0x0240; function onExecuteWithdrawal( HooksConfig self, address lender, uint256 scaledAmount, MarketState memory state, uint256 baseCalldataSize ) internal { address target = self.hooksAddress(); uint32 onExecuteWithdrawalSelector = uint32(IHooks.onExecuteWithdrawal.selector); if (self.useOnExecuteWithdrawal()) { assembly { let extraCalldataBytes := sub(calldatasize(), baseCalldataSize) let cdPointer := mload(0x40) let headPointer := add(cdPointer, 0x20) // Write selector for `onExecuteWithdrawal` mstore(cdPointer, onExecuteWithdrawalSelector) // Write `lender` to hook calldata mstore(headPointer, lender) // Write `scaledAmount` to hook calldata mstore(add(headPointer, ExecuteWithdrawalHook_ScaledAmount_Offset), scaledAmount) // Copy market state to hook calldata mcopy(add(headPointer, ExecuteWithdrawalHook_State_Offset), state, MarketStateSize) // Write bytes offset for `extraData` mstore( add(headPointer, ExecuteWithdrawalHook_ExtraData_Head_Offset), ExecuteWithdrawalHook_ExtraData_Length_Offset ) // Write length for `extraData` mstore(add(headPointer, ExecuteWithdrawalHook_ExtraData_Length_Offset), extraCalldataBytes) // Copy `extraData` from end of calldata to hook calldata calldatacopy( add(headPointer, ExecuteWithdrawalHook_ExtraData_TailOffset), baseCalldataSize, extraCalldataBytes ) let size := add(ExecuteWithdrawalHook_Base_Size, extraCalldataBytes) if iszero(call(gas(), target, 0, add(cdPointer, 0x1c), size, 0, 0)) { returndatacopy(0, 0, returndatasize()) revert(0, returndatasize()) } } } } // ========================================================================== // // Hook for transfer // // ========================================================================== // // Size of caller + from + to + scaledAmount + state + extraData.offset + extraData.length uint256 internal constant TransferHook_Base_Size = 0x0284; uint256 internal constant TransferHook_From_Offset = 0x20; uint256 internal constant TransferHook_To_Offset = 0x40; uint256 internal constant TransferHook_ScaledAmount_Offset = 0x60; uint256 internal constant TransferHook_State_Offset = 0x80; uint256 internal constant TransferHook_ExtraData_Head_Offset = 0x240; uint256 internal constant TransferHook_ExtraData_Length_Offset = 0x0260; uint256 internal constant TransferHook_ExtraData_TailOffset = 0x0280; function onTransfer( HooksConfig self, address from, address to, uint256 scaledAmount, MarketState memory state, uint256 baseCalldataSize ) internal { address target = self.hooksAddress(); uint32 onTransferSelector = uint32(IHooks.onTransfer.selector); if (self.useOnTransfer()) { assembly { let extraCalldataBytes := sub(calldatasize(), baseCalldataSize) let cdPointer := mload(0x40) let headPointer := add(cdPointer, 0x20) // Write selector for `onTransfer` mstore(cdPointer, onTransferSelector) // Write `caller` to hook calldata mstore(headPointer, caller()) // Write `from` to hook calldata mstore(add(headPointer, TransferHook_From_Offset), from) // Write `to` to hook calldata mstore(add(headPointer, TransferHook_To_Offset), to) // Write `scaledAmount` to hook calldata mstore(add(headPointer, TransferHook_ScaledAmount_Offset), scaledAmount) // Copy market state to hook calldata mcopy(add(headPointer, TransferHook_State_Offset), state, MarketStateSize) // Write bytes offset for `extraData` mstore( add(headPointer, TransferHook_ExtraData_Head_Offset), TransferHook_ExtraData_Length_Offset ) // Write length for `extraData` mstore(add(headPointer, TransferHook_ExtraData_Length_Offset), extraCalldataBytes) // Copy `extraData` from end of calldata to hook calldata calldatacopy( add(headPointer, TransferHook_ExtraData_TailOffset), baseCalldataSize, extraCalldataBytes ) let size := add(TransferHook_Base_Size, extraCalldataBytes) if iszero(call(gas(), target, 0, add(cdPointer, 0x1c), size, 0, 0)) { returndatacopy(0, 0, returndatasize()) revert(0, returndatasize()) } } } } // ========================================================================== // // Hook for borrow // // ========================================================================== // uint256 internal constant BorrowCalldataSize = 0x24; // Size of normalizedAmount + state + extraData.offset + extraData.length uint256 internal constant BorrowHook_Base_Size = 0x0224; uint256 internal constant BorrowHook_State_Offset = 0x20; uint256 internal constant BorrowHook_ExtraData_Head_Offset = 0x01e0; uint256 internal constant BorrowHook_ExtraData_Length_Offset = 0x0200; uint256 internal constant BorrowHook_ExtraData_TailOffset = 0x0220; function onBorrow(HooksConfig self, uint256 normalizedAmount, MarketState memory state) internal { address target = self.hooksAddress(); uint32 onBorrowSelector = uint32(IHooks.onBorrow.selector); if (self.useOnBorrow()) { assembly { let extraCalldataBytes := sub(calldatasize(), BorrowCalldataSize) let ptr := mload(0x40) let headPointer := add(ptr, 0x20) mstore(ptr, onBorrowSelector) // Copy `normalizedAmount` to hook calldata mstore(headPointer, normalizedAmount) // Copy market state to hook calldata mcopy(add(headPointer, BorrowHook_State_Offset), state, MarketStateSize) // Write bytes offset for `extraData` mstore( add(headPointer, BorrowHook_ExtraData_Head_Offset), BorrowHook_ExtraData_Length_Offset ) // Write length for `extraData` mstore(add(headPointer, BorrowHook_ExtraData_Length_Offset), extraCalldataBytes) // Copy `extraData` from end of calldata to hook calldata calldatacopy( add(headPointer, BorrowHook_ExtraData_TailOffset), BorrowCalldataSize, extraCalldataBytes ) let size := add(RepayHook_Base_Size, extraCalldataBytes) if iszero(call(gas(), target, 0, add(ptr, 0x1c), size, 0, 0)) { returndatacopy(0, 0, returndatasize()) revert(0, returndatasize()) } } } } // ========================================================================== // // Hook for repay // // ========================================================================== // // Size of normalizedAmount + state + extraData.offset + extraData.length uint256 internal constant RepayHook_Base_Size = 0x0224; uint256 internal constant RepayHook_State_Offset = 0x20; uint256 internal constant RepayHook_ExtraData_Head_Offset = 0x01e0; uint256 internal constant RepayHook_ExtraData_Length_Offset = 0x0200; uint256 internal constant RepayHook_ExtraData_TailOffset = 0x0220; function onRepay( HooksConfig self, uint256 normalizedAmount, MarketState memory state, uint256 baseCalldataSize ) internal { address target = self.hooksAddress(); uint32 onRepaySelector = uint32(IHooks.onRepay.selector); if (self.useOnRepay()) { assembly { let extraCalldataBytes := sub(calldatasize(), baseCalldataSize) let ptr := mload(0x40) let headPointer := add(ptr, 0x20) mstore(ptr, onRepaySelector) // Copy `normalizedAmount` to hook calldata mstore(headPointer, normalizedAmount) // Copy market state to hook calldata mcopy(add(headPointer, RepayHook_State_Offset), state, MarketStateSize) // Write bytes offset for `extraData` mstore(add(headPointer, RepayHook_ExtraData_Head_Offset), RepayHook_ExtraData_Length_Offset) // Write length for `extraData` mstore(add(headPointer, RepayHook_ExtraData_Length_Offset), extraCalldataBytes) // Copy `extraData` from end of calldata to hook calldata calldatacopy( add(headPointer, RepayHook_ExtraData_TailOffset), baseCalldataSize, extraCalldataBytes ) let size := add(RepayHook_Base_Size, extraCalldataBytes) if iszero(call(gas(), target, 0, add(ptr, 0x1c), size, 0, 0)) { returndatacopy(0, 0, returndatasize()) revert(0, returndatasize()) } } } } // ========================================================================== // // Hook for closeMarket // // ========================================================================== // // Size of calldata to `market.closeMarket` uint256 internal constant CloseMarketCalldataSize = 0x04; // Base size of calldata for `hooks.onCloseMarket()` uint256 internal constant CloseMarketHook_Base_Size = 0x0204; uint256 internal constant CloseMarketHook_ExtraData_Head_Offset = MarketStateSize; uint256 internal constant CloseMarketHook_ExtraData_Length_Offset = 0x01e0; uint256 internal constant CloseMarketHook_ExtraData_TailOffset = 0x0200; function onCloseMarket(HooksConfig self, MarketState memory state) internal { address target = self.hooksAddress(); uint32 onCloseMarketSelector = uint32(IHooks.onCloseMarket.selector); if (self.useOnCloseMarket()) { assembly { let extraCalldataBytes := sub(calldatasize(), CloseMarketCalldataSize) let cdPointer := mload(0x40) let headPointer := add(cdPointer, 0x20) // Write selector for `onCloseMarket` mstore(cdPointer, onCloseMarketSelector) // Copy market state to hook calldata mcopy(headPointer, state, MarketStateSize) // Write bytes offset for `extraData` mstore( add(headPointer, CloseMarketHook_ExtraData_Head_Offset), CloseMarketHook_ExtraData_Length_Offset ) // Write length for `extraData` mstore(add(headPointer, CloseMarketHook_ExtraData_Length_Offset), extraCalldataBytes) // Copy `extraData` from end of calldata to hook calldata calldatacopy( add(headPointer, CloseMarketHook_ExtraData_TailOffset), CloseMarketCalldataSize, extraCalldataBytes ) let size := add(CloseMarketHook_Base_Size, extraCalldataBytes) if iszero(call(gas(), target, 0, add(cdPointer, 0x1c), size, 0, 0)) { returndatacopy(0, 0, returndatasize()) revert(0, returndatasize()) } } } } // ========================================================================== // // Hook for setMaxTotalSupply // // ========================================================================== // uint256 internal constant SetMaxTotalSupplyCalldataSize = 0x24; // Size of maxTotalSupply + state + extraData.offset + extraData.length uint256 internal constant SetMaxTotalSupplyHook_Base_Size = 0x0224; uint256 internal constant SetMaxTotalSupplyHook_State_Offset = 0x20; uint256 internal constant SetMaxTotalSupplyHook_ExtraData_Head_Offset = 0x01e0; uint256 internal constant SetMaxTotalSupplyHook_ExtraData_Length_Offset = 0x0200; uint256 internal constant SetMaxTotalSupplyHook_ExtraData_TailOffset = 0x0220; function onSetMaxTotalSupply( HooksConfig self, uint256 maxTotalSupply, MarketState memory state ) internal { address target = self.hooksAddress(); uint32 onSetMaxTotalSupplySelector = uint32(IHooks.onSetMaxTotalSupply.selector); if (self.useOnSetMaxTotalSupply()) { assembly { let extraCalldataBytes := sub(calldatasize(), SetMaxTotalSupplyCalldataSize) let cdPointer := mload(0x40) let headPointer := add(cdPointer, 0x20) // Write selector for `onSetMaxTotalSupply` mstore(cdPointer, onSetMaxTotalSupplySelector) // Write `maxTotalSupply` to hook calldata mstore(headPointer, maxTotalSupply) // Copy market state to hook calldata mcopy(add(headPointer, SetMaxTotalSupplyHook_State_Offset), state, MarketStateSize) // Write bytes offset for `extraData` mstore( add(headPointer, SetMaxTotalSupplyHook_ExtraData_Head_Offset), SetMaxTotalSupplyHook_ExtraData_Length_Offset ) // Write length for `extraData` mstore(add(headPointer, SetMaxTotalSupplyHook_ExtraData_Length_Offset), extraCalldataBytes) // Copy `extraData` from end of calldata to hook calldata calldatacopy( add(headPointer, SetMaxTotalSupplyHook_ExtraData_TailOffset), SetMaxTotalSupplyCalldataSize, extraCalldataBytes ) let size := add(SetMaxTotalSupplyHook_Base_Size, extraCalldataBytes) if iszero(call(gas(), target, 0, add(cdPointer, 0x1c), size, 0, 0)) { returndatacopy(0, 0, returndatasize()) revert(0, returndatasize()) } } } } // ========================================================================== // // Hook for setAnnualInterestBips // // ========================================================================== // uint256 internal constant SetAnnualInterestAndReserveRatioBipsCalldataSize = 0x44; // Size of annualInterestBips + state + extraData.offset + extraData.length uint256 internal constant SetAnnualInterestAndReserveRatioBipsHook_Base_Size = 0x0244; uint256 internal constant SetAnnualInterestAndReserveRatioBipsHook_ReserveRatioBits_Offset = 0x20; uint256 internal constant SetAnnualInterestAndReserveRatioBipsHook_State_Offset = 0x40; uint256 internal constant SetAnnualInterestAndReserveRatioBipsHook_ExtraData_Head_Offset = 0x0200; uint256 internal constant SetAnnualInterestAndReserveRatioBipsHook_ExtraData_Length_Offset = 0x0220; uint256 internal constant SetAnnualInterestAndReserveRatioBipsHook_ExtraData_TailOffset = 0x0240; function onSetAnnualInterestAndReserveRatioBips( HooksConfig self, uint16 annualInterestBips, uint16 reserveRatioBips, MarketState memory state ) internal returns (uint16 newAnnualInterestBips, uint16 newReserveRatioBips) { address target = self.hooksAddress(); uint32 onSetAnnualInterestBipsSelector = uint32( IHooks.onSetAnnualInterestAndReserveRatioBips.selector ); if (self.useOnSetAnnualInterestAndReserveRatioBips()) { assembly { let extraCalldataBytes := sub( calldatasize(), SetAnnualInterestAndReserveRatioBipsCalldataSize ) let cdPointer := mload(0x40) let headPointer := add(cdPointer, 0x20) // Write selector for `onSetAnnualInterestBips` mstore(cdPointer, onSetAnnualInterestBipsSelector) // Write `annualInterestBips` to hook calldata mstore(headPointer, annualInterestBips) // Write `reserveRatioBips` to hook calldata mstore( add(headPointer, SetAnnualInterestAndReserveRatioBipsHook_ReserveRatioBits_Offset), reserveRatioBips ) // Copy market state to hook calldata mcopy( add(headPointer, SetAnnualInterestAndReserveRatioBipsHook_State_Offset), state, MarketStateSize ) // Write bytes offset for `extraData` mstore( add(headPointer, SetAnnualInterestAndReserveRatioBipsHook_ExtraData_Head_Offset), SetAnnualInterestAndReserveRatioBipsHook_ExtraData_Length_Offset ) // Write length for `extraData` mstore( add(headPointer, SetAnnualInterestAndReserveRatioBipsHook_ExtraData_Length_Offset), extraCalldataBytes ) // Copy `extraData` from end of calldata to hook calldata calldatacopy( add(headPointer, SetAnnualInterestAndReserveRatioBipsHook_ExtraData_TailOffset), SetAnnualInterestAndReserveRatioBipsCalldataSize, extraCalldataBytes ) let size := add(SetAnnualInterestAndReserveRatioBipsHook_Base_Size, extraCalldataBytes) // Returndata is expected to have the new values for `annualInterestBips` and `reserveRatioBips` if or( lt(returndatasize(), 0x40), iszero(call(gas(), target, 0, add(cdPointer, 0x1c), size, 0, 0x40)) ) { returndatacopy(0, 0, returndatasize()) revert(0, returndatasize()) } newAnnualInterestBips := and(mload(0), 0xffff) newReserveRatioBips := and(mload(0x20), 0xffff) } } else { (newAnnualInterestBips, newReserveRatioBips) = (annualInterestBips, reserveRatioBips); } } // ========================================================================== // // Hook for protocol fee bips updated // // ========================================================================== // uint256 internal constant SetProtocolFeeBipsCalldataSize = 0x24; // Size of protocolFeeBips + state + extraData.offset + extraData.length uint256 internal constant SetProtocolFeeBips_Base_Size = 0x0224; uint256 internal constant SetProtocolFeeBips_State_Offset = 0x20; uint256 internal constant SetProtocolFeeBips_ExtraData_Head_Offset = 0x01e0; uint256 internal constant SetProtocolFeeBips_ExtraData_Length_Offset = 0x0200; uint256 internal constant SetProtocolFeeBips_ExtraData_TailOffset = 0x0220; function onSetProtocolFeeBips( HooksConfig self, uint protocolFeeBips, MarketState memory state ) internal { address target = self.hooksAddress(); uint32 onSetProtocolFeeBipsSelector = uint32(IHooks.onSetProtocolFeeBips.selector); if (self.useOnSetProtocolFeeBips()) { assembly { let extraCalldataBytes := sub(calldatasize(), SetProtocolFeeBipsCalldataSize) let cdPointer := mload(0x40) let headPointer := add(cdPointer, 0x20) // Write selector for `onSetProtocolFeeBips` mstore(cdPointer, onSetProtocolFeeBipsSelector) // Write `protocolFeeBips` to hook calldata mstore(headPointer, protocolFeeBips) // Copy market state to hook calldata mcopy(add(headPointer, SetProtocolFeeBips_State_Offset), state, MarketStateSize) // Write bytes offset for `extraData` mstore( add(headPointer, SetProtocolFeeBips_ExtraData_Head_Offset), SetProtocolFeeBips_ExtraData_Length_Offset ) // Write length for `extraData` mstore(add(headPointer, SetProtocolFeeBips_ExtraData_Length_Offset), extraCalldataBytes) // Copy `extraData` from end of calldata to hook calldata calldatacopy( add(headPointer, SetProtocolFeeBips_ExtraData_TailOffset), SetProtocolFeeBipsCalldataSize, extraCalldataBytes ) let size := add(SetProtocolFeeBips_Base_Size, extraCalldataBytes) if iszero(call(gas(), target, 0, add(cdPointer, 0x1c), size, 0, 0)) { returndatacopy(0, 0, returndatasize()) revert(0, returndatasize()) } } } } // ========================================================================== // // Hook for assets sent to escrow // // ========================================================================== // uint256 internal constant NukeFromOrbitCalldataSize = 0x24; // Size of lender + state + extraData.offset + extraData.length uint256 internal constant NukeFromOrbit_Base_Size = 0x0224; uint256 internal constant NukeFromOrbit_State_Offset = 0x20; uint256 internal constant NukeFromOrbit_ExtraData_Head_Offset = 0x01e0; uint256 internal constant NukeFromOrbit_ExtraData_Length_Offset = 0x0200; uint256 internal constant NukeFromOrbit_ExtraData_TailOffset = 0x0220; function onNukeFromOrbit(HooksConfig self, address lender, MarketState memory state) internal { address target = self.hooksAddress(); uint32 onNukeFromOrbitSelector = uint32(IHooks.onNukeFromOrbit.selector); if (self.useOnNukeFromOrbit()) { assembly { let extraCalldataBytes := sub(calldatasize(), NukeFromOrbitCalldataSize) let cdPointer := mload(0x40) let headPointer := add(cdPointer, 0x20) // Write selector for `onNukeFromOrbit` mstore(cdPointer, onNukeFromOrbitSelector) // Write `lender` to hook calldata mstore(headPointer, lender) // Copy market state to hook calldata mcopy(add(headPointer, NukeFromOrbit_State_Offset), state, MarketStateSize) // Write bytes offset for `extraData` mstore( add(headPointer, NukeFromOrbit_ExtraData_Head_Offset), NukeFromOrbit_ExtraData_Length_Offset ) // Write length for `extraData` mstore(add(headPointer, NukeFromOrbit_ExtraData_Length_Offset), extraCalldataBytes) // Copy `extraData` from end of calldata to hook calldata calldatacopy( add(headPointer, NukeFromOrbit_ExtraData_TailOffset), NukeFromOrbitCalldataSize, extraCalldataBytes ) let size := add(NukeFromOrbit_Base_Size, extraCalldataBytes) if iszero(call(gas(), target, 0, add(cdPointer, 0x1c), size, 0, 0)) { returndatacopy(0, 0, returndatasize()) revert(0, returndatasize()) } } } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.20; import './Errors.sol'; library SafeCastLib { function _assertNonOverflow(bool didNotOverflow) private pure { assembly { if iszero(didNotOverflow) { mstore(0, Panic_ErrorSelector) mstore(Panic_ErrorCodePointer, Panic_Arithmetic) revert(Error_SelectorPointer, Panic_ErrorLength) } } } function toUint8(uint256 x) internal pure returns (uint8 y) { _assertNonOverflow(x == (y = uint8(x))); } function toUint16(uint256 x) internal pure returns (uint16 y) { _assertNonOverflow(x == (y = uint16(x))); } function toUint24(uint256 x) internal pure returns (uint24 y) { _assertNonOverflow(x == (y = uint24(x))); } function toUint32(uint256 x) internal pure returns (uint32 y) { _assertNonOverflow(x == (y = uint32(x))); } function toUint40(uint256 x) internal pure returns (uint40 y) { _assertNonOverflow(x == (y = uint40(x))); } function toUint48(uint256 x) internal pure returns (uint48 y) { _assertNonOverflow(x == (y = uint48(x))); } function toUint56(uint256 x) internal pure returns (uint56 y) { _assertNonOverflow(x == (y = uint56(x))); } function toUint64(uint256 x) internal pure returns (uint64 y) { _assertNonOverflow(x == (y = uint64(x))); } function toUint72(uint256 x) internal pure returns (uint72 y) { _assertNonOverflow(x == (y = uint72(x))); } function toUint80(uint256 x) internal pure returns (uint80 y) { _assertNonOverflow(x == (y = uint80(x))); } function toUint88(uint256 x) internal pure returns (uint88 y) { _assertNonOverflow(x == (y = uint88(x))); } function toUint96(uint256 x) internal pure returns (uint96 y) { _assertNonOverflow(x == (y = uint96(x))); } function toUint104(uint256 x) internal pure returns (uint104 y) { _assertNonOverflow(x == (y = uint104(x))); } function toUint112(uint256 x) internal pure returns (uint112 y) { _assertNonOverflow(x == (y = uint112(x))); } function toUint120(uint256 x) internal pure returns (uint120 y) { _assertNonOverflow(x == (y = uint120(x))); } function toUint128(uint256 x) internal pure returns (uint128 y) { _assertNonOverflow(x == (y = uint128(x))); } function toUint136(uint256 x) internal pure returns (uint136 y) { _assertNonOverflow(x == (y = uint136(x))); } function toUint144(uint256 x) internal pure returns (uint144 y) { _assertNonOverflow(x == (y = uint144(x))); } function toUint152(uint256 x) internal pure returns (uint152 y) { _assertNonOverflow(x == (y = uint152(x))); } function toUint160(uint256 x) internal pure returns (uint160 y) { _assertNonOverflow(x == (y = uint160(x))); } function toUint168(uint256 x) internal pure returns (uint168 y) { _assertNonOverflow(x == (y = uint168(x))); } function toUint176(uint256 x) internal pure returns (uint176 y) { _assertNonOverflow(x == (y = uint176(x))); } function toUint184(uint256 x) internal pure returns (uint184 y) { _assertNonOverflow(x == (y = uint184(x))); } function toUint192(uint256 x) internal pure returns (uint192 y) { _assertNonOverflow(x == (y = uint192(x))); } function toUint200(uint256 x) internal pure returns (uint200 y) { _assertNonOverflow(x == (y = uint200(x))); } function toUint208(uint256 x) internal pure returns (uint208 y) { _assertNonOverflow(x == (y = uint208(x))); } function toUint216(uint256 x) internal pure returns (uint216 y) { _assertNonOverflow(x == (y = uint216(x))); } function toUint224(uint256 x) internal pure returns (uint224 y) { _assertNonOverflow(x == (y = uint224(x))); } function toUint232(uint256 x) internal pure returns (uint232 y) { _assertNonOverflow(x == (y = uint232(x))); } function toUint240(uint256 x) internal pure returns (uint240 y) { _assertNonOverflow(x == (y = uint240(x))); } function toUint248(uint256 x) internal pure returns (uint248 y) { _assertNonOverflow(x == (y = uint248(x))); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.20; library BoolUtils { function and(bool a, bool b) internal pure returns (bool c) { assembly { c := and(a, b) } } function or(bool a, bool b) internal pure returns (bool c) { assembly { c := or(a, b) } } function xor(bool a, bool b) internal pure returns (bool c) { assembly { c := xor(a, b) } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.20; interface IChainalysisSanctionsList { function isSanctioned(address addr) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.20; interface IWildcatSanctionsSentinel { event NewSanctionsEscrow( address indexed borrower, address indexed account, address indexed asset ); event SanctionOverride(address indexed borrower, address indexed account); event SanctionOverrideRemoved(address indexed borrower, address indexed account); struct TmpEscrowParams { address borrower; address account; address asset; } function WildcatSanctionsEscrowInitcodeHash() external pure returns (bytes32); // Returns immutable sanctions list contract function chainalysisSanctionsList() external view returns (address); // Returns immutable arch-controller function archController() external view returns (address); // Returns temporary escrow params function tmpEscrowParams() external view returns (address borrower, address account, address asset); // Returns result of `chainalysisSanctionsList().isSanctioned(account)` function isFlaggedByChainalysis(address account) external view returns (bool); // Returns result of `chainalysisSanctionsList().isSanctioned(account)` // if borrower has not overridden the status of `account` function isSanctioned(address borrower, address account) external view returns (bool); // Returns boolean indicating whether `borrower` has overridden the // sanction status of `account` function sanctionOverrides(address borrower, address account) external view returns (bool); function overrideSanction(address account) external; function removeSanctionOverride(address account) external; // Returns create2 address of sanctions escrow contract for // combination of `borrower,account,asset` function getEscrowAddress( address borrower, address account, address asset ) external view returns (address escrowContract); /** * @dev Returns a create2 deployment of WildcatSanctionsEscrow unique to each * combination of `account,borrower,asset`. If the contract is already * deployed, returns the existing address. * * Emits `NewSanctionsEscrow(borrower, account, asset)` if a new contract * is deployed. * * The sanctions escrow contract is used to hold assets until either the * sanctioned status is lifted or the assets are released by the borrower. */ function createEscrow( address borrower, address account, address asset ) external returns (address escrowContract); }
// SPDX-License-Identifier: Apache-2.0 WITH LicenseRef-Commons-Clause-1.0 pragma solidity >=0.8.20; import './interfaces/IERC20.sol'; import './interfaces/IWildcatSanctionsEscrow.sol'; import './interfaces/IWildcatSanctionsSentinel.sol'; import './libraries/LibERC20.sol'; contract WildcatSanctionsEscrow is IWildcatSanctionsEscrow { using LibERC20 for address; address public immutable override sentinel; address public immutable override borrower; address public immutable override account; address internal immutable asset; constructor() { sentinel = msg.sender; (borrower, account, asset) = IWildcatSanctionsSentinel(sentinel).tmpEscrowParams(); } function balance() public view override returns (uint256) { return IERC20(asset).balanceOf(address(this)); } function canReleaseEscrow() public view override returns (bool) { return !IWildcatSanctionsSentinel(sentinel).isSanctioned(borrower, account); } function escrowedAsset() public view override returns (address, uint256) { return (asset, balance()); } function releaseEscrow() public override { if (!canReleaseEscrow()) revert CanNotReleaseEscrow(); uint256 amount = balance(); address _account = account; address _asset = asset; asset.safeTransfer(_account, amount); emit EscrowReleased(_account, _asset, amount); } }
// SPDX-License-Identifier: UNLICENSED // (c) SphereX 2023 Terms&Conditions pragma solidity ^0.8.20; /// @dev this struct is used to reduce the stack usage of the modifiers. struct ModifierLocals { bytes32[] storageSlots; bytes32[] valuesBefore; uint256 gas; address engine; } /// @title Interface for SphereXEngine - definitions of core functionality /// @author SphereX Technologies ltd /// @notice This interface is imported by SphereXProtected, so that SphereXProtected can call functions from SphereXEngine /// @dev Full docs of these functions can be found in SphereXEngine interface ISphereXEngine { function sphereXValidatePre( int256 num, address sender, bytes calldata data ) external returns (bytes32[] memory); function sphereXValidatePost( int256 num, uint256 gas, bytes32[] calldata valuesBefore, bytes32[] calldata valuesAfter ) external; function sphereXValidateInternalPre(int256 num) external returns (bytes32[] memory); function sphereXValidateInternalPost( int256 num, uint256 gas, bytes32[] calldata valuesBefore, bytes32[] calldata valuesAfter ) external; function addAllowedSenderOnChain(address sender) external; /// This function is taken as is from OZ IERC165, we don't inherit from OZ /// to avoid collisions with the customer OZ version. /// @dev Returns true if this contract implements the interface defined by /// `interfaceId`. See the corresponding /// https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] /// to learn more about how these ids are created. /// This function call must use less than 30 000 gas. function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; function emit_ChangedSpherexOperator(address oldSphereXAdmin, address newSphereXAdmin) { assembly { mstore(0, oldSphereXAdmin) mstore(0x20, newSphereXAdmin) log1(0, 0x40, 0x2ac55ae7ba47db34b5334622acafeb34a65daf143b47019273185d64c73a35a5) } } function emit_ChangedSpherexEngineAddress(address oldEngineAddress, address newEngineAddress) { assembly { mstore(0, oldEngineAddress) mstore(0x20, newEngineAddress) log1(0, 0x40, 0xf33499cccaa0611882086224cc48cd82ef54b66a4d2edf4ed67108dd516896d5) } } function emit_SpherexAdminTransferStarted(address currentAdmin, address pendingAdmin) { assembly { mstore(0, currentAdmin) mstore(0x20, pendingAdmin) log1(0, 0x40, 0x5778f1547abbbb86090a43c32aec38334b31df4beeb6f8f3fa063f593b53a526) } } function emit_SpherexAdminTransferCompleted(address oldAdmin, address newAdmin) { assembly { mstore(0, oldAdmin) mstore(0x20, newAdmin) log1(0, 0x40, 0x67ebaebcd2ca5a91a404e898110f221747e8d15567f2388a34794aab151cf3e6) } } function emit_NewAllowedSenderOnchain(address sender) { assembly { mstore(0, sender) log1(0, 0x20, 0x6de0a1fd3a59e5479e6480ba65ef28d4f3ab8143c2c631bbfd9969ab39074797) } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; function revert_SphereXOperatorRequired() pure { assembly { mstore(0, 0x4ee0b8f8) revert(0x1c, 0x04) } } function revert_SphereXAdminRequired() pure { assembly { mstore(0, 0x6222a550) revert(0x1c, 0x04) } } function revert_SphereXOperatorOrAdminRequired() pure { assembly { mstore(0, 0xb2dbeb59) revert(0x1c, 0x04) } } function revert_SphereXNotPendingAdmin() pure { assembly { mstore(0, 0x4d28a58e) revert(0x1c, 0x04) } } function revert_SphereXNotEngine() pure { assembly { mstore(0, 0x7dcb7ada) revert(0x1c, 0x04) } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.20; import './MathUtils.sol'; import './SafeCastLib.sol'; import './FeeMath.sol'; using MarketStateLib for MarketState global; using MarketStateLib for Account global; using FeeMath for MarketState global; struct MarketState { bool isClosed; uint128 maxTotalSupply; uint128 accruedProtocolFees; // Underlying assets reserved for withdrawals which have been paid // by the borrower but not yet executed. uint128 normalizedUnclaimedWithdrawals; // Scaled token supply (divided by scaleFactor) uint104 scaledTotalSupply; // Scaled token amount in withdrawal batches that have not been // paid by borrower yet. uint104 scaledPendingWithdrawals; uint32 pendingWithdrawalExpiry; // Whether market is currently delinquent (liquidity under requirement) bool isDelinquent; // Seconds borrower has been delinquent uint32 timeDelinquent; // Fee charged to borrowers as a fraction of the annual interest rate uint16 protocolFeeBips; // Annual interest rate accrued to lenders, in basis points uint16 annualInterestBips; // Percentage of outstanding balance that must be held in liquid reserves uint16 reserveRatioBips; // Ratio between internal balances and underlying token amounts uint112 scaleFactor; uint32 lastInterestAccruedTimestamp; } struct Account { uint104 scaledBalance; } library MarketStateLib { using MathUtils for uint256; using SafeCastLib for uint256; /** * @dev Returns the normalized total supply of the market. */ function totalSupply(MarketState memory state) internal pure returns (uint256) { return state.normalizeAmount(state.scaledTotalSupply); } /** * @dev Returns the maximum amount of tokens that can be deposited without * reaching the maximum total supply. */ function maximumDeposit(MarketState memory state) internal pure returns (uint256) { return uint256(state.maxTotalSupply).satSub(state.totalSupply()); } /** * @dev Normalize an amount of scaled tokens using the current scale factor. */ function normalizeAmount( MarketState memory state, uint256 amount ) internal pure returns (uint256) { return amount.rayMul(state.scaleFactor); } /** * @dev Scale an amount of normalized tokens using the current scale factor. */ function scaleAmount(MarketState memory state, uint256 amount) internal pure returns (uint256) { return amount.rayDiv(state.scaleFactor); } /** * @dev Collateralization requirement is: * - 100% of all pending (unpaid) withdrawals * - 100% of all unclaimed (paid) withdrawals * - reserve ratio times the outstanding debt (supply - pending withdrawals) * - accrued protocol fees */ function liquidityRequired( MarketState memory state ) internal pure returns (uint256 _liquidityRequired) { uint256 scaledWithdrawals = state.scaledPendingWithdrawals; uint256 scaledRequiredReserves = (state.scaledTotalSupply - scaledWithdrawals).bipMul( state.reserveRatioBips ) + scaledWithdrawals; return state.normalizeAmount(scaledRequiredReserves) + state.accruedProtocolFees + state.normalizedUnclaimedWithdrawals; } /** * @dev Returns the amount of underlying assets that can be withdrawn * for protocol fees. The only debts with higher priority are * processed withdrawals that have not been executed. */ function withdrawableProtocolFees( MarketState memory state, uint256 totalAssets ) internal pure returns (uint128) { uint256 totalAvailableAssets = totalAssets - state.normalizedUnclaimedWithdrawals; return uint128(MathUtils.min(totalAvailableAssets, state.accruedProtocolFees)); } /** * @dev Returns the amount of underlying assets that can be borrowed. * * The borrower must maintain sufficient assets in the market to * cover 100% of pending withdrawals, 100% of previously processed * withdrawals (before they are executed), and the reserve ratio * times the outstanding debt (deposits not pending withdrawal). * * Any underlying assets in the market above this amount can be borrowed. */ function borrowableAssets( MarketState memory state, uint256 totalAssets ) internal pure returns (uint256) { return totalAssets.satSub(state.liquidityRequired()); } function hasPendingExpiredBatch(MarketState memory state) internal view returns (bool result) { uint256 expiry = state.pendingWithdrawalExpiry; assembly { // Equivalent to expiry > 0 && expiry < block.timestamp result := and(gt(expiry, 0), gt(timestamp(), expiry)) } } function totalDebts(MarketState memory state) internal pure returns (uint256) { return state.normalizeAmount(state.scaledTotalSupply) + state.normalizedUnclaimedWithdrawals + state.accruedProtocolFees; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import '../types/HooksConfig.sol'; import '../libraries/MarketState.sol'; import '../interfaces/WildcatStructsAndEnums.sol'; abstract contract IHooks { error CallerNotFactory(); address public immutable factory; constructor() { factory = msg.sender; } /// @dev Returns the version string of the hooks contract. /// Used to determine what the contract does and how `extraData` is interpreted. function version() external view virtual returns (string memory); /// @dev Returns the HooksDeploymentConfig type which contains the sets /// of optional and required hooks that this contract implements. function config() external view virtual returns (HooksDeploymentConfig); function onCreateMarket( address deployer, address marketAddress, DeployMarketInputs calldata parameters, bytes calldata extraData ) external returns (HooksConfig) { if (msg.sender != factory) revert CallerNotFactory(); return _onCreateMarket(deployer, marketAddress, parameters, extraData); } function _onCreateMarket( address deployer, address marketAddress, DeployMarketInputs calldata parameters, bytes calldata extraData ) internal virtual returns (HooksConfig); function onDeposit( address lender, uint256 scaledAmount, MarketState calldata intermediateState, bytes calldata extraData ) external virtual; function onQueueWithdrawal( address lender, uint32 expiry, uint scaledAmount, MarketState calldata intermediateState, bytes calldata extraData ) external virtual; function onExecuteWithdrawal( address lender, uint128 normalizedAmountWithdrawn, MarketState calldata intermediateState, bytes calldata extraData ) external virtual; function onTransfer( address caller, address from, address to, uint scaledAmount, MarketState calldata intermediateState, bytes calldata extraData ) external virtual; function onBorrow( uint normalizedAmount, MarketState calldata intermediateState, bytes calldata extraData ) external virtual; function onRepay( uint normalizedAmount, MarketState calldata intermediateState, bytes calldata extraData ) external virtual; function onCloseMarket( MarketState calldata intermediateState, bytes calldata extraData ) external virtual; function onNukeFromOrbit( address lender, MarketState calldata intermediateState, bytes calldata extraData ) external virtual; function onSetMaxTotalSupply( uint256 maxTotalSupply, MarketState calldata intermediateState, bytes calldata extraData ) external virtual; function onSetAnnualInterestAndReserveRatioBips( uint16 annualInterestBips, uint16 reserveRatioBips, MarketState calldata intermediateState, bytes calldata extraData ) external virtual returns (uint16 updatedAnnualInterestBips, uint16 updatedReserveRatioBips); function onSetProtocolFeeBips( uint16 protocolFeeBips, MarketState memory intermediateState, bytes calldata extraData ) external virtual; }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.20; import { MarketState } from '../libraries/MarketState.sol'; import { HooksConfig } from '../types/HooksConfig.sol'; struct MarketParameters { address asset; uint8 decimals; bytes32 packedNameWord0; bytes32 packedNameWord1; bytes32 packedSymbolWord0; bytes32 packedSymbolWord1; address borrower; address feeRecipient; address sentinel; uint128 maxTotalSupply; uint16 protocolFeeBips; uint16 annualInterestBips; uint16 delinquencyFeeBips; uint32 withdrawalBatchDuration; uint16 reserveRatioBips; uint32 delinquencyGracePeriod; address archController; address sphereXEngine; HooksConfig hooks; } struct DeployMarketInputs { address asset; string namePrefix; string symbolPrefix; uint128 maxTotalSupply; uint16 annualInterestBips; uint16 delinquencyFeeBips; uint32 withdrawalBatchDuration; uint16 reserveRatioBips; uint32 delinquencyGracePeriod; HooksConfig hooks; } struct MarketControllerParameters { address archController; address borrower; address sentinel; address marketInitCodeStorage; uint256 marketInitCodeHash; uint32 minimumDelinquencyGracePeriod; uint32 maximumDelinquencyGracePeriod; uint16 minimumReserveRatioBips; uint16 maximumReserveRatioBips; uint16 minimumDelinquencyFeeBips; uint16 maximumDelinquencyFeeBips; uint32 minimumWithdrawalBatchDuration; uint32 maximumWithdrawalBatchDuration; uint16 minimumAnnualInterestBips; uint16 maximumAnnualInterestBips; address sphereXEngine; } struct ProtocolFeeConfiguration { address feeRecipient; address originationFeeAsset; uint80 originationFeeAmount; uint16 protocolFeeBips; } struct MarketParameterConstraints { uint32 minimumDelinquencyGracePeriod; uint32 maximumDelinquencyGracePeriod; uint16 minimumReserveRatioBips; uint16 maximumReserveRatioBips; uint16 minimumDelinquencyFeeBips; uint16 maximumDelinquencyFeeBips; uint32 minimumWithdrawalBatchDuration; uint32 maximumWithdrawalBatchDuration; uint16 minimumAnnualInterestBips; uint16 maximumAnnualInterestBips; }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.20; import './Errors.sol'; uint256 constant BIP = 1e4; uint256 constant HALF_BIP = 0.5e4; uint256 constant RAY = 1e27; uint256 constant HALF_RAY = 0.5e27; uint256 constant BIP_RAY_RATIO = 1e23; uint256 constant SECONDS_IN_365_DAYS = 365 days; library MathUtils { /// @dev The multiply-divide operation failed, either due to a /// multiplication overflow, or a division by a zero. error MulDivFailed(); using MathUtils for uint256; /** * @dev Function to calculate the interest accumulated using a linear interest rate formula * * @param rateBip The interest rate, in bips * @param timeDelta The time elapsed since the last interest accrual * @return result The interest rate linearly accumulated during the timeDelta, in ray */ function calculateLinearInterestFromBips( uint256 rateBip, uint256 timeDelta ) internal pure returns (uint256 result) { uint256 rate = rateBip.bipToRay(); uint256 accumulatedInterestRay = rate * timeDelta; unchecked { return accumulatedInterestRay / SECONDS_IN_365_DAYS; } } /** * @dev Return the smaller of `a` and `b` */ function min(uint256 a, uint256 b) internal pure returns (uint256 c) { c = ternary(a < b, a, b); } /** * @dev Return the larger of `a` and `b`. */ function max(uint256 a, uint256 b) internal pure returns (uint256 c) { c = ternary(a < b, b, a); } /** * @dev Saturation subtraction. Subtract `b` from `a` and return the result * if it is positive or zero if it underflows. */ function satSub(uint256 a, uint256 b) internal pure returns (uint256 c) { assembly { // (a > b) * (a - b) // If a-b underflows, the product will be zero c := mul(gt(a, b), sub(a, b)) } } /** * @dev Saturation addition. Add `a` to `b` and return the result * if it is less than `maxValue` or `maxValue` if it overflows. */ function satAdd(uint256 a, uint256 b, uint256 maxValue) internal pure returns (uint256 c) { unchecked { c = a + b; return ternary(c < maxValue, c, maxValue); } } /** * @dev Return `valueIfTrue` if `condition` is true and `valueIfFalse` if it is false. * Equivalent to `condition ? valueIfTrue : valueIfFalse` */ function ternary( bool condition, uint256 valueIfTrue, uint256 valueIfFalse ) internal pure returns (uint256 c) { assembly { c := add(valueIfFalse, mul(condition, sub(valueIfTrue, valueIfFalse))) } } /** * @dev Multiplies two bip, rounding half up to the nearest bip * see https://twitter.com/transmissions11/status/1451131036377571328 */ function bipMul(uint256 a, uint256 b) internal pure returns (uint256 c) { assembly { // equivalent to `require(b == 0 || a <= (type(uint256).max - HALF_BIP) / b)` if iszero(or(iszero(b), iszero(gt(a, div(sub(not(0), HALF_BIP), b))))) { // Store the Panic error signature. mstore(0, Panic_ErrorSelector) // Store the arithmetic (0x11) panic code. mstore(Panic_ErrorCodePointer, Panic_Arithmetic) // revert(abi.encodeWithSignature("Panic(uint256)", 0x11)) revert(Error_SelectorPointer, Panic_ErrorLength) } c := div(add(mul(a, b), HALF_BIP), BIP) } } /** * @dev Divides two bip, rounding half up to the nearest bip * see https://twitter.com/transmissions11/status/1451131036377571328 */ function bipDiv(uint256 a, uint256 b) internal pure returns (uint256 c) { assembly { // equivalent to `require(b != 0 && a <= (type(uint256).max - b/2) / BIP)` if or(iszero(b), gt(a, div(sub(not(0), div(b, 2)), BIP))) { mstore(0, Panic_ErrorSelector) mstore(Panic_ErrorCodePointer, Panic_Arithmetic) revert(Error_SelectorPointer, Panic_ErrorLength) } c := div(add(mul(a, BIP), div(b, 2)), b) } } /** * @dev Converts bip up to ray */ function bipToRay(uint256 a) internal pure returns (uint256 b) { // to avoid overflow, b/BIP_RAY_RATIO == a assembly { b := mul(a, BIP_RAY_RATIO) // equivalent to `require((b = a * BIP_RAY_RATIO) / BIP_RAY_RATIO == a ) if iszero(eq(div(b, BIP_RAY_RATIO), a)) { mstore(0, Panic_ErrorSelector) mstore(Panic_ErrorCodePointer, Panic_Arithmetic) revert(Error_SelectorPointer, Panic_ErrorLength) } } } /** * @dev Multiplies two ray, rounding half up to the nearest ray * see https://twitter.com/transmissions11/status/1451131036377571328 */ function rayMul(uint256 a, uint256 b) internal pure returns (uint256 c) { assembly { // equivalent to `require(b == 0 || a <= (type(uint256).max - HALF_RAY) / b)` if iszero(or(iszero(b), iszero(gt(a, div(sub(not(0), HALF_RAY), b))))) { mstore(0, Panic_ErrorSelector) mstore(Panic_ErrorCodePointer, Panic_Arithmetic) revert(Error_SelectorPointer, Panic_ErrorLength) } c := div(add(mul(a, b), HALF_RAY), RAY) } } /** * @dev Divide two ray, rounding half up to the nearest ray * see https://twitter.com/transmissions11/status/1451131036377571328 */ function rayDiv(uint256 a, uint256 b) internal pure returns (uint256 c) { assembly { // equivalent to `require(b != 0 && a <= (type(uint256).max - halfB) / RAY)` if or(iszero(b), gt(a, div(sub(not(0), div(b, 2)), RAY))) { mstore(0, Panic_ErrorSelector) mstore(Panic_ErrorCodePointer, Panic_Arithmetic) revert(Error_SelectorPointer, Panic_ErrorLength) } c := div(add(mul(a, RAY), div(b, 2)), b) } } /** * @dev Returns `floor(x * y / d)`. * Reverts if `x * y` overflows, or `d` is zero. * @custom:author solady/src/utils/FixedPointMathLib.sol */ function mulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { assembly { // Equivalent to require(d != 0 && (y == 0 || x <= type(uint256).max / y)) if iszero(mul(d, iszero(mul(y, gt(x, div(not(0), y)))))) { // Store the function selector of `MulDivFailed()`. mstore(0x00, 0xad251c27) // Revert with (offset, size). revert(0x1c, 0x04) } z := div(mul(x, y), d) } } /** * @dev Returns `ceil(x * y / d)`. * Reverts if `x * y` overflows, or `d` is zero. * @custom:author solady/src/utils/FixedPointMathLib.sol */ function mulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { assembly { // Equivalent to require(d != 0 && (y == 0 || x <= type(uint256).max / y)) if iszero(mul(d, iszero(mul(y, gt(x, div(not(0), y)))))) { // Store the function selector of `MulDivFailed()`. mstore(0x00, 0xad251c27) // Revert with (offset, size). revert(0x1c, 0x04) } z := add(iszero(iszero(mod(mul(x, y), d))), div(mul(x, y), d)) } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.20; struct FIFOQueue { uint128 startIndex; uint128 nextIndex; mapping(uint256 => uint32) data; } // @todo - make array tightly packed for gas efficiency with multiple reads/writes // also make a memory version of the array with (nextIndex, startIndex, storageSlot) // so that multiple storage reads aren't required for tx's using multiple functions using FIFOQueueLib for FIFOQueue global; library FIFOQueueLib { error FIFOQueueOutOfBounds(); function empty(FIFOQueue storage arr) internal view returns (bool) { return arr.nextIndex == arr.startIndex; } function first(FIFOQueue storage arr) internal view returns (uint32) { if (arr.startIndex == arr.nextIndex) { revert FIFOQueueOutOfBounds(); } return arr.data[arr.startIndex]; } function at(FIFOQueue storage arr, uint256 index) internal view returns (uint32) { index += arr.startIndex; if (index >= arr.nextIndex) { revert FIFOQueueOutOfBounds(); } return arr.data[index]; } function length(FIFOQueue storage arr) internal view returns (uint128) { return arr.nextIndex - arr.startIndex; } function values(FIFOQueue storage arr) internal view returns (uint32[] memory _values) { uint256 startIndex = arr.startIndex; uint256 nextIndex = arr.nextIndex; uint256 len = nextIndex - startIndex; _values = new uint32[](len); for (uint256 i = 0; i < len; i++) { _values[i] = arr.data[startIndex + i]; } return _values; } function push(FIFOQueue storage arr, uint32 value) internal { uint128 nextIndex = arr.nextIndex; arr.data[nextIndex] = value; arr.nextIndex = nextIndex + 1; } function shift(FIFOQueue storage arr) internal { uint128 startIndex = arr.startIndex; if (startIndex == arr.nextIndex) { revert FIFOQueueOutOfBounds(); } delete arr.data[startIndex]; arr.startIndex = startIndex + 1; } function shiftN(FIFOQueue storage arr, uint128 n) internal { uint128 startIndex = arr.startIndex; if (startIndex + n > arr.nextIndex) { revert FIFOQueueOutOfBounds(); } for (uint256 i = 0; i < n; i++) { delete arr.data[startIndex + i]; } arr.startIndex = startIndex + n; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.20; import { LibBit } from 'solady/utils/LibBit.sol'; using LibBit for uint256; uint256 constant OnlyFullWordMask = 0xffffffe0; function bytes32ToString(bytes32 value) pure returns (string memory str) { uint256 size; unchecked { uint256 sizeInBits = 255 - uint256(value).ffs(); size = (sizeInBits + 7) / 8; } assembly { str := mload(0x40) mstore(0x40, add(str, 0x40)) mstore(str, size) mstore(add(str, 0x20), value) } } function queryStringOrBytes32AsString( address target, uint256 leftPaddedFunctionSelector, uint256 leftPaddedGenericErrorSelector ) view returns (string memory str) { bool isBytes32; assembly { mstore(0, leftPaddedFunctionSelector) let status := staticcall(gas(), target, 0x1c, 0x04, 0, 0) isBytes32 := eq(returndatasize(), 0x20) // If call fails or function returns invalid data, revert. // Strings are always right padded to full words - if the returndata // is not 32 bytes (string encoded as bytes32) or >95 bytes (minimum abi // encoded string) it is an invalid string. if or(iszero(status), iszero(or(isBytes32, gt(returndatasize(), 0x5f)))) { // Check if call failed if iszero(status) { // Check if any revert data was given if returndatasize() { returndatacopy(0, 0, returndatasize()) revert(0, returndatasize()) } // If not, throw a generic error mstore(0, leftPaddedGenericErrorSelector) revert(0x1c, 0x04) } // If the returndata is the wrong size, `revert InvalidReturnDataString()` mstore(0, 0x4cb9c000) revert(0x1c, 0x04) } } if (isBytes32) { bytes32 value; assembly { returndatacopy(0x00, 0x00, 0x20) value := mload(0) } str = bytes32ToString(value); } else { // If returndata is a string, copy the length and value assembly { str := mload(0x40) // Get allocation size for the string including the length and data. // Rounding down returndatasize to nearest word because the returndata // has an extra offset word. let allocSize := and(sub(returndatasize(), 1), OnlyFullWordMask) mstore(0x40, add(str, allocSize)) // Copy returndata after the offset returndatacopy(str, 0x20, sub(returndatasize(), 0x20)) let length := mload(str) // Check if the length matches the returndatasize. // The encoded string should have the string length rounded up to the nearest word // as well as two words for length and offset. let expectedReturndataSize := add(allocSize, 0x20) if xor(returndatasize(), expectedReturndataSize) { mstore(0, 0x4cb9c000) revert(0x1c, 0x04) } } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.20; uint256 constant Panic_CompilerPanic = 0x00; uint256 constant Panic_AssertFalse = 0x01; uint256 constant Panic_Arithmetic = 0x11; uint256 constant Panic_DivideByZero = 0x12; uint256 constant Panic_InvalidEnumValue = 0x21; uint256 constant Panic_InvalidStorageByteArray = 0x22; uint256 constant Panic_EmptyArrayPop = 0x31; uint256 constant Panic_ArrayOutOfBounds = 0x32; uint256 constant Panic_MemoryTooLarge = 0x41; uint256 constant Panic_UninitializedFunctionPointer = 0x51; uint256 constant Panic_ErrorSelector = 0x4e487b71; uint256 constant Panic_ErrorCodePointer = 0x20; uint256 constant Panic_ErrorLength = 0x24; uint256 constant Error_SelectorPointer = 0x1c; /** * @dev Reverts with the given error selector. * @param errorSelector The left-aligned error selector. */ function revertWithSelector(bytes4 errorSelector) pure { assembly { mstore(0, errorSelector) revert(0, 4) } } /** * @dev Reverts with the given error selector. * @param errorSelector The left-padded error selector. */ function revertWithSelector(uint256 errorSelector) pure { assembly { mstore(0, errorSelector) revert(Error_SelectorPointer, 4) } } /** * @dev Reverts with the given error selector and argument. * @param errorSelector The left-aligned error selector. * @param argument The argument to the error. */ function revertWithSelectorAndArgument(bytes4 errorSelector, uint256 argument) pure { assembly { mstore(0, errorSelector) mstore(4, argument) revert(0, 0x24) } } /** * @dev Reverts with the given error selector and argument. * @param errorSelector The left-padded error selector. * @param argument The argument to the error. */ function revertWithSelectorAndArgument(uint256 errorSelector, uint256 argument) pure { assembly { mstore(0, errorSelector) mstore(0x20, argument) revert(Error_SelectorPointer, 0x24) } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.20; interface IWildcatSanctionsEscrow { event EscrowReleased(address indexed account, address indexed asset, uint256 amount); error CanNotReleaseEscrow(); function sentinel() external view returns (address); function borrower() external view returns (address); function account() external view returns (address); function balance() external view returns (uint256); function canReleaseEscrow() external view returns (bool); function escrowedAsset() external view returns (address token, uint256 amount); function releaseEscrow() external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Library for bit twiddling and boolean operations. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibBit.sol) /// @author Inspired by (https://graphics.stanford.edu/~seander/bithacks.html) library LibBit { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* BIT TWIDDLING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Find last set. /// Returns the index of the most significant bit of `x`, /// counting from the least significant bit position. /// If `x` is zero, returns 256. function fls(uint256 x) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { r := or(shl(8, iszero(x)), shl(7, lt(0xffffffffffffffffffffffffffffffff, x))) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) r := or(r, shl(2, lt(0xf, shr(r, x)))) r := or(r, byte(shr(r, x), hex"00000101020202020303030303030303")) } } /// @dev Count leading zeros. /// Returns the number of zeros preceding the most significant one bit. /// If `x` is zero, returns 256. function clz(uint256 x) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) r := or(r, shl(2, lt(0xf, shr(r, x)))) // forgefmt: disable-next-item r := add(iszero(x), xor(255, or(r, byte(shr(r, x), hex"00000101020202020303030303030303")))) } } /// @dev Find first set. /// Returns the index of the least significant bit of `x`, /// counting from the least significant bit position. /// If `x` is zero, returns 256. /// Equivalent to `ctz` (count trailing zeros), which gives /// the number of zeros following the least significant one bit. function ffs(uint256 x) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { // Isolate the least significant bit. let b := and(x, add(not(x), 1)) r := or(shl(8, iszero(x)), shl(7, lt(0xffffffffffffffffffffffffffffffff, b))) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, b)))) r := or(r, shl(5, lt(0xffffffff, shr(r, b)))) // For the remaining 32 bits, use a De Bruijn lookup. // forgefmt: disable-next-item r := or(r, byte(and(div(0xd76453e0, shr(r, b)), 0x1f), 0x001f0d1e100c1d070f090b19131c1706010e11080a1a141802121b1503160405)) } } /// @dev Returns the number of set bits in `x`. function popCount(uint256 x) internal pure returns (uint256 c) { /// @solidity memory-safe-assembly assembly { let max := not(0) let isMax := eq(x, max) x := sub(x, and(shr(1, x), div(max, 3))) x := add(and(x, div(max, 5)), and(shr(2, x), div(max, 5))) x := and(add(x, shr(4, x)), div(max, 17)) c := or(shl(8, isMax), shr(248, mul(x, div(max, 255)))) } } /// @dev Returns whether `x` is a power of 2. function isPo2(uint256 x) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { // Equivalent to `x && !(x & (x - 1))`. result := iszero(add(and(x, sub(x, 1)), iszero(x))) } } /// @dev Returns `x` reversed at the bit level. function reverseBits(uint256 x) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { // Computing masks on-the-fly reduces bytecode size by about 500 bytes. let m := not(0) r := x for { let s := 128 } 1 {} { m := xor(m, shl(s, m)) r := or(and(shr(s, r), m), and(shl(s, r), not(m))) s := shr(1, s) if iszero(s) { break } } } } /// @dev Returns `x` reversed at the byte level. function reverseBytes(uint256 x) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { // Computing masks on-the-fly reduces bytecode size by about 200 bytes. let m := not(0) r := x for { let s := 128 } 1 {} { m := xor(m, shl(s, m)) r := or(and(shr(s, r), m), and(shl(s, r), not(m))) s := shr(1, s) if eq(s, 4) { break } } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* BOOLEAN OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // A Solidity bool on the stack or memory is represented as a 256-bit word. // Non-zero values are true, zero is false. // A clean bool is either 0 (false) or 1 (true) under the hood. // Usually, if not always, the bool result of a regular Solidity expression, // or the argument of a public/external function will be a clean bool. // You can usually use the raw variants for more performance. // If uncertain, test (best with exact compiler settings). // Or use the non-raw variants (compiler can sometimes optimize out the double `iszero`s). /// @dev Returns `x & y`. Inputs must be clean. function rawAnd(bool x, bool y) internal pure returns (bool z) { /// @solidity memory-safe-assembly assembly { z := and(x, y) } } /// @dev Returns `x & y`. function and(bool x, bool y) internal pure returns (bool z) { /// @solidity memory-safe-assembly assembly { z := and(iszero(iszero(x)), iszero(iszero(y))) } } /// @dev Returns `x | y`. Inputs must be clean. function rawOr(bool x, bool y) internal pure returns (bool z) { /// @solidity memory-safe-assembly assembly { z := or(x, y) } } /// @dev Returns `x | y`. function or(bool x, bool y) internal pure returns (bool z) { /// @solidity memory-safe-assembly assembly { z := or(iszero(iszero(x)), iszero(iszero(y))) } } /// @dev Returns 1 if `b` is true, else 0. Input must be clean. function rawToUint(bool b) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := b } } /// @dev Returns 1 if `b` is true, else 0. function toUint(bool b) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := iszero(iszero(b)) } } }
{ "remappings": [ "src/=src/", "forge-std/=lib/forge-std/src/", "ds-test/=lib/ds-test/src/", "solmate/=lib/solmate/src/", "solady/=lib/solady/src/", "openzeppelin/=lib/openzeppelin-contracts/", "sol-utils/=lib/sol-utils/src/", "ethereum-access-token/=lib/ethereum-access-token/contracts/", "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "vulcan/=lib/vulcan/src/" ], "optimizer": { "enabled": true, "runs": 50000 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "none", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } }, "evmVersion": "cancun", "viaIR": true, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"name":"AccountBlocked","type":"error"},{"inputs":[],"name":"AnnualInterestBipsTooHigh","type":"error"},{"inputs":[],"name":"AprChangeOnClosedMarket","type":"error"},{"inputs":[],"name":"BadLaunchCode","type":"error"},{"inputs":[],"name":"BadRescueAsset","type":"error"},{"inputs":[],"name":"BorrowAmountTooHigh","type":"error"},{"inputs":[],"name":"BorrowFromClosedMarket","type":"error"},{"inputs":[],"name":"BorrowWhileSanctioned","type":"error"},{"inputs":[],"name":"BuyBackOnDelinquentMarket","type":"error"},{"inputs":[],"name":"CapacityChangeOnClosedMarket","type":"error"},{"inputs":[],"name":"CloseMarketWithUnpaidWithdrawals","type":"error"},{"inputs":[],"name":"DepositToClosedMarket","type":"error"},{"inputs":[],"name":"FIFOQueueOutOfBounds","type":"error"},{"inputs":[],"name":"InsufficientReservesForFeeWithdrawal","type":"error"},{"inputs":[],"name":"InsufficientReservesForNewLiquidityRatio","type":"error"},{"inputs":[],"name":"InsufficientReservesForOldLiquidityRatio","type":"error"},{"inputs":[],"name":"InvalidArrayLength","type":"error"},{"inputs":[],"name":"MarketAlreadyClosed","type":"error"},{"inputs":[],"name":"MaxSupplyExceeded","type":"error"},{"inputs":[],"name":"NoReentrantCalls","type":"error"},{"inputs":[],"name":"NotApprovedBorrower","type":"error"},{"inputs":[],"name":"NotApprovedLender","type":"error"},{"inputs":[],"name":"NotFactory","type":"error"},{"inputs":[],"name":"NullBurnAmount","type":"error"},{"inputs":[],"name":"NullBuyBackAmount","type":"error"},{"inputs":[],"name":"NullFeeAmount","type":"error"},{"inputs":[],"name":"NullMintAmount","type":"error"},{"inputs":[],"name":"NullRepayAmount","type":"error"},{"inputs":[],"name":"NullTransferAmount","type":"error"},{"inputs":[],"name":"NullWithdrawalAmount","type":"error"},{"inputs":[],"name":"ProtocolFeeChangeOnClosedMarket","type":"error"},{"inputs":[],"name":"ProtocolFeeTooHigh","type":"error"},{"inputs":[],"name":"RepayToClosedMarket","type":"error"},{"inputs":[],"name":"ReserveRatioBipsTooHigh","type":"error"},{"inputs":[],"name":"SphereXOperatorRequired","type":"error"},{"inputs":[],"name":"WithdrawalBatchNotExpired","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"AccountSanctioned","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"annualInterestBipsUpdated","type":"uint256"}],"name":"AnnualInterestBipsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"assetAmount","type":"uint256"}],"name":"Borrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldEngineAddress","type":"address"},{"indexed":false,"internalType":"address","name":"newEngineAddress","type":"address"}],"name":"ChangedSpherexEngineAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldSphereXAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newSphereXAdmin","type":"address"}],"name":"ChangedSpherexOperator","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"assetAmount","type":"uint256"}],"name":"DebtRepaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"assetAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"scaledAmount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"}],"name":"FeesCollected","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"scaleFactor","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"baseInterestRay","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"delinquencyFeeRay","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"protocolFees","type":"uint256"}],"name":"InterestAndFeesAccrued","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"MarketClosed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"}],"name":"MaxTotalSupplyUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"protocolFeeBips","type":"uint256"}],"name":"ProtocolFeeBipsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"reserveRatioBipsUpdated","type":"uint256"}],"name":"ReserveRatioBipsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"expiry","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"scaledAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"normalizedAmount","type":"uint256"}],"name":"SanctionedAccountAssetsQueuedForWithdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"address","name":"escrow","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"SanctionedAccountAssetsSentToEscrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"address","name":"escrow","type":"address"},{"indexed":false,"internalType":"uint32","name":"expiry","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"SanctionedAccountWithdrawalSentToEscrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"scaleFactor","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isDelinquent","type":"bool"}],"name":"StateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"expiry","type":"uint256"}],"name":"WithdrawalBatchClosed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"expiry","type":"uint256"}],"name":"WithdrawalBatchCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"expiry","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"scaledTotalAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"scaledAmountBurned","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"normalizedAmountPaid","type":"uint256"}],"name":"WithdrawalBatchExpired","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"expiry","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"scaledAmountBurned","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"normalizedAmountPaid","type":"uint256"}],"name":"WithdrawalBatchPayment","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"expiry","type":"uint256"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"normalizedAmount","type":"uint256"}],"name":"WithdrawalExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"expiry","type":"uint256"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"scaledAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"normalizedAmount","type":"uint256"}],"name":"WithdrawalQueued","type":"event"},{"inputs":[],"name":"accruedProtocolFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"annualInterestBips","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"archController","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"asset","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"borrow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"borrowableAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"borrower","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newSphereXEngine","type":"address"}],"name":"changeSphereXEngine","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"closeMarket","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"collectFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"coverageLiquidity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentState","outputs":[{"components":[{"internalType":"bool","name":"isClosed","type":"bool"},{"internalType":"uint128","name":"maxTotalSupply","type":"uint128"},{"internalType":"uint128","name":"accruedProtocolFees","type":"uint128"},{"internalType":"uint128","name":"normalizedUnclaimedWithdrawals","type":"uint128"},{"internalType":"uint104","name":"scaledTotalSupply","type":"uint104"},{"internalType":"uint104","name":"scaledPendingWithdrawals","type":"uint104"},{"internalType":"uint32","name":"pendingWithdrawalExpiry","type":"uint32"},{"internalType":"bool","name":"isDelinquent","type":"bool"},{"internalType":"uint32","name":"timeDelinquent","type":"uint32"},{"internalType":"uint16","name":"protocolFeeBips","type":"uint16"},{"internalType":"uint16","name":"annualInterestBips","type":"uint16"},{"internalType":"uint16","name":"reserveRatioBips","type":"uint16"},{"internalType":"uint112","name":"scaleFactor","type":"uint112"},{"internalType":"uint32","name":"lastInterestAccruedTimestamp","type":"uint32"}],"internalType":"struct MarketState","name":"state","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"delinquencyFeeBips","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"delinquencyGracePeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"depositUpTo","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"accountAddress","type":"address"},{"internalType":"uint32","name":"expiry","type":"uint32"}],"name":"executeWithdrawal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"accountAddresses","type":"address[]"},{"internalType":"uint32[]","name":"expiries","type":"uint32[]"}],"name":"executeWithdrawals","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"accountAddress","type":"address"},{"internalType":"uint32","name":"expiry","type":"uint32"}],"name":"getAccountWithdrawalStatus","outputs":[{"components":[{"internalType":"uint104","name":"scaledAmount","type":"uint104"},{"internalType":"uint128","name":"normalizedAmountWithdrawn","type":"uint128"}],"internalType":"struct AccountWithdrawalStatus","name":"status","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"accountAddress","type":"address"},{"internalType":"uint32","name":"expiry","type":"uint32"}],"name":"getAvailableWithdrawalAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getUnpaidBatchExpiries","outputs":[{"internalType":"uint32[]","name":"","type":"uint32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"expiry","type":"uint32"}],"name":"getWithdrawalBatch","outputs":[{"components":[{"internalType":"uint104","name":"scaledTotalAmount","type":"uint104"},{"internalType":"uint104","name":"scaledAmountBurned","type":"uint104"},{"internalType":"uint128","name":"normalizedAmountPaid","type":"uint128"}],"internalType":"struct WithdrawalBatch","name":"batch","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"hooks","outputs":[{"internalType":"HooksConfig","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isClosed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxTotalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maximumDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"accountAddress","type":"address"}],"name":"nukeFromOrbit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"previousState","outputs":[{"components":[{"internalType":"bool","name":"isClosed","type":"bool"},{"internalType":"uint128","name":"maxTotalSupply","type":"uint128"},{"internalType":"uint128","name":"accruedProtocolFees","type":"uint128"},{"internalType":"uint128","name":"normalizedUnclaimedWithdrawals","type":"uint128"},{"internalType":"uint104","name":"scaledTotalSupply","type":"uint104"},{"internalType":"uint104","name":"scaledPendingWithdrawals","type":"uint104"},{"internalType":"uint32","name":"pendingWithdrawalExpiry","type":"uint32"},{"internalType":"bool","name":"isDelinquent","type":"bool"},{"internalType":"uint32","name":"timeDelinquent","type":"uint32"},{"internalType":"uint16","name":"protocolFeeBips","type":"uint16"},{"internalType":"uint16","name":"annualInterestBips","type":"uint16"},{"internalType":"uint16","name":"reserveRatioBips","type":"uint16"},{"internalType":"uint112","name":"scaleFactor","type":"uint112"},{"internalType":"uint32","name":"lastInterestAccruedTimestamp","type":"uint32"}],"internalType":"struct MarketState","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"queueFullWithdrawal","outputs":[{"internalType":"uint32","name":"expiry","type":"uint32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"queueWithdrawal","outputs":[{"internalType":"uint32","name":"expiry","type":"uint32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"repay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"repayAmount","type":"uint256"},{"internalType":"uint256","name":"maxBatches","type":"uint256"}],"name":"repayAndProcessUnpaidWithdrawalBatches","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"rescueTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"reserveRatioBips","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"scaleFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"scaledBalanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"scaledTotalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sentinel","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_annualInterestBips","type":"uint16"},{"internalType":"uint16","name":"_reserveRatioBips","type":"uint16"}],"name":"setAnnualInterestAndReserveRatioBips","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTotalSupply","type":"uint256"}],"name":"setMaxTotalSupply","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_protocolFeeBips","type":"uint16"}],"name":"setProtocolFeeBips","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sphereXEngine","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sphereXOperator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalDebts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updateState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"withdrawableProtocolFees","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawalBatchDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
0x6102606040523461020357610012610207565b6040516155ef908161045b8239608051818181610f8f015261107a015260a051818181610ca701528181610de2015281816112000152818161190d01528181611b1e01528181611d33015281816120bb0152818161221e01528181612321015281816124db015281816134e50152818161372901528181613c020152818161401a015261418f015260c051818181612053015281816125df01528181614666015261511a015260e05181818161041c01528181610d9d0152818161169301528181611ca2015281816120090152818161247b0152818161463801526150c7015261010051818181611a770152611c6c015261012051818181610efd01526121a3015261014051818181610f3801528181612d4601528181612e2b0152818161311601526131eb01526101605181818161102b01528181612d2501528181612e0a015281816130f501526131ca0152610180518181816118510152613dbf01526101a05181610b8701526101c05181818161045f01528181610c3501528181610d110152818161123701528181611fc3015281816120e6015281816121c401528181612617015281816137f50152818161382c015281816140460152818161414001526150ee01526101e051816106160152610200518161063a015261022051816117ef015261024051816118130152f35b5f80fd5b6103ad6103a861010033815261021b610432565b8051610397906001600160a01b03166101c09081528261038661036f610245602084015160ff1690565b6101a09081526040840151946101e095865261037861036f6060870151976102009889528760808101519c6102209d8e5261032960a083015191610240928352610120926102c26102bb6102b06102a48789015160018060801b031690565b6001600160801b031690565b9a87015161ffff1690565b61ffff1690565b98610160996102d86102bb8c89015161ffff1690565b6102ec6102bb610140809a015161ffff1690565b9260081b5f55676765c793fa10079d606b1b9260201b9060301b179060401b4260c01b1717176003558c015160a0528b015160018060a01b031690565b60c09081528a01516001600160a01b031660e09081528a01516001600160a01b031690526103616102bb610180809b015161ffff1690565b90528a015163ffffffff1690565b63ffffffff1690565b905286015163ffffffff1690565b90528201516001600160a01b031690565b60805201516001600160a01b031690565b6103af565b565b60018060a01b03608051165f80526020527f2ac55ae7ba47db34b5334622acafeb34a65daf143b47019273185d64c73a35a560405fa1807f1777adabd324f814e2b0e28f6edf876dce01d7d66358c9acfe87b1b5f38338d5556020527ff33499cccaa0611882086224cc48cd82ef54b66a4d2edf4ed67108dd516896d560405fa1565b6040516102608082016040526304032dbb5f5280826004601c335afa903d141615610203579056fe60806040526004361015610011575f80fd5b5f3560e01c8062ae3bf8146103ce57806301e1d114146103c957806302372c4f146103c457806306fdde03146103bf578063088fee5e146103ba578063095ea7b3146103b55780630c1e3fea146103b05780630c3f6acf146103ab5780630cd1a5b6146103a657806311057cd0146103a157806314a1c32d1461039c57806318160ddd146103975780631d8557d7146103925780631da24f3e1461038d5780631e3cef531461038857806323b872dd146103835780632ab4d0521461037e578063313ce5671461037957806334bca29c14610374578063371fd8e61461036f57806338d52e0f1461036a5780633c231166146103655780633f3e4c1114610360578063469048401461035b5780634be687c6146103565780634c6c848f14610351578063514a4cd61461034c57806354635570146102b157806354b302c51461034757806354fd4d50146103425780636731ba6d1461033d578063683dd191146103385780636b174f351461033357806370a082311461032e5780637243d96c14610329578063739ccdd314610324578063740588591461031f578063766360171461031a5780637df1f1b914610315578063878eb9211461031057806395d89b411461030b5780639e6f980214610306578063a9059cbb14610301578063ae6ea191146102fc578063b1bf962d146102f7578063b68ce7a2146102f2578063b6b55f25146102ed578063c2b6b58c146102e8578063c45a0155146102e3578063c511ed5e146102de578063c5ebeaec146102d9578063c8796572146102d4578063cd7033c4146102cf578063d98e0fe8146102ca578063dbcd50b4146102c5578063dcd549d4146102c0578063dd62ed3e146102bb578063e5adc635146102b6578063e7e5db4f146102b15763f58c251c146102ac575f80fd5b6125b3565b61104e565b612457565b6123dc565b6122db565b612265565b612241565b612207565b61211e565b611ff3565b611c90565b611c40565b611c1f565b611bde565b611bb5565b611b83565b611a37565b611874565b61183a565b6117d5565b6116f8565b611667565b611623565b6114e9565b611451565b6113cc565b611361565b61129e565b61126a565b6110e6565b6110c2565b61109e565b611014565b610f5b565b610f21565b610ed1565b610d87565b610d35565b610ce5565b610c03565b610bab565b610b6e565b610b3d565b610a41565b6109fa565b61099a565b61095e565b61091d565b6108f1565b6108cd565b61088b565b61085b565b610835565b6107e0565b610661565b6105fc565b61055e565b610506565b6103f5565b73ffffffffffffffffffffffffffffffffffffffff8116036103f157565b5f80fd5b346103f15760206003193601126103f157600435610412816103d3565b61041a612bf8565b7f000000000000000000000000000000000000000000000000000000000000000033186104f95773ffffffffffffffffffffffffffffffffffffffff808216308114917f00000000000000000000000000000000000000000000000000000000000000001614176104ec576370a082315f5230602052602060346024601c845afa601f3d1116156104df575f6044601082602094336014526fa9059cbb00000000000000000000000082525af13d1560015f51141716156104df576104dd612c16565b005b6390b8ec185f526004601cfd5b6311530cde5f526004601cfd5b6302171e6a5f526004601cfd5b346103f1575f6003193601126103f1576020610520612603565b604051908152f35b63ffffffff8116036103f157565b60031960409101126103f15760043561054e816103d3565b9060243561055b81610528565b90565b346103f157604061056e36610536565b6105c0610579612681565b925f845263ffffffff60208501935f8552610592612c1f565b165f526008602052845f209073ffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b54906cffffffffffffffffffffffffff82168093526fffffffffffffffffffffffffffffffff809260681c168152835192835251166020820152f35b346103f1575f6003193601126103f15760205f525f6020527f0000000000000000000000000000000000000000000000000000000000000000603f527f0000000000000000000000000000000000000000000000000000000000000000605f5260805ff35b346103f15761066f36610536565b90610678612c1f565b63ffffffff9182811691428310156107d3576106f76106f26107819261079696610786966106a4612c2b565b9391506106af61274b565b50160361079a576106cf909563ffffffff165f52600860205260405f2090565b9073ffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b6127ab565b9161072d61071860208501516fffffffffffffffffffffffffffffffff1690565b6fffffffffffffffffffffffffffffffff1690565b9261076861075461075461071860408601516fffffffffffffffffffffffffffffffff1690565b92516cffffffffffffffffffffffffff1690565b6cffffffffffffffffffffffffff809116921690612ea7565b612811565b6040519081529081906020820190565b0390f35b506106cf6107be6107b98763ffffffff165f52600760205260405f2090565b612765565b9563ffffffff165f52600860205260405f2090565b632561b8805f526004601cfd5b346103f15760406003193601126103f157610823600435610800816103d3565b610808612bf8565b61081e610813612edb565b916024359033612f1f565b614d13565b5f63929eee145d602060405160018152f35b346103f1575f6003193601126103f15761084d61281e565b506101c0610859612880565bf35b346103f1575f6003193601126103f15761087361281e565b5061087c612c1f565b6101c0610887612c2b565b5050f35b346103f1575f6003193601126103f1576108a3612c1f565b60206fffffffffffffffffffffffffffffffff60406108c0612c2b565b5050015116604051908152f35b346103f1575f6003193601126103f157602061ffff60035460301c16604051908152f35b346103f1575f6003193601126103f157610909612c1f565b6020610520610916612c2b565b5050612f95565b346103f1575f6003193601126103f157610935612c1f565b6020610520610942612c2b565b50506cffffffffffffffffffffffffff60808201511690613e0d565b346103f1575f6003193601126103f157610976612bf8565b610991610981612edb565b61081e61098c612fe6565b61323f565b5f63929eee145d005b346103f15760206003193601126103f15773ffffffffffffffffffffffffffffffffffffffff6004356109cc816103d3565b6109d4612c1f565b165f52600460205260206cffffffffffffffffffffffffff60405f205416604051908152f35b346103f1575f6003193601126103f1576020610a27610a17612c2b565b5050610a21612603565b906133d4565b6fffffffffffffffffffffffffffffffff60405191168152f35b346103f15760606003193601126103f157600435610a5e816103d3565b602435610a6a816103d3565b604435610a75612bf8565b610a7d612edb565b9173ffffffffffffffffffffffffffffffffffffffff84165f526009602052610ac660405f203373ffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8103610b11575b509061081e91610afe94613497565b5f63929eee145d60405160018152602090f35b9190818303928311610b3857610afe94610b2f61081e943383612f1f565b94509091610aef565b6127e4565b346103f1575f6003193601126103f15760206fffffffffffffffffffffffffffffffff5f5460081c16604051908152f35b346103f1575f6003193601126103f157602060405160ff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346103f1576020610bf4610bbe36610536565b9190610bc8612bf8565b61081e610bee610bd6612edb565b92610bdf612fe6565b9560445f523615519187613627565b9361323f565b5f63929eee145d604051908152f35b346103f15760206003193601126103f157600435610c1f612bf8565b610c27612edb565b8115610cd857610c598230337f000000000000000000000000000000000000000000000000000000000000000061385a565b815f52337fe8b606ac1e5df7657db58d297ca8f41c090fc94c5fd2d6958f043e41736e9fa660205fa2610c8a612fe6565b918251610ccb576109919261098c61081e9260245f5282361551917f00000000000000000000000000000000000000000000000000000000000000006138d9565b6361d1bc8f5f526004601cfd5b637e0820885f526004601cfd5b346103f1575f6003193601126103f157602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346103f1575f6003193601126103f15760207f1777adabd324f814e2b0e28f6edf876dce01d7d66358c9acfe87b1b5f38338d55473ffffffffffffffffffffffffffffffffffffffff60405191168152f35b346103f15760206003193601126103f1576004357f000000000000000000000000000000000000000000000000000000000000000033186104f957610dca612bf8565b610dd2612edb565b610dda612fe6565b8051610ec4577f000000000000000000000000000000000000000000000000000000000000000060018160571c16610e4b575b5082610e3e61081e9261098c610e25610e439761393f565b6fffffffffffffffffffffffffffffffff166020830152565b61395e565b6104dd612c16565b5f80917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc36019082601c6040519363849da12985528960208601526101c088604087015e610200908180870152806102208701526024610240870137360193019160601c5af115610ebc575f610e0d565b3d5f803e3d5ffd5b6381b210785f526004601cfd5b346103f1575f6003193601126103f157602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346103f1575f6003193601126103f15760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346103f15760206003193601126103f157600435610f78816103d3565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163303611007577f1777adabd324f814e2b0e28f6edf876dce01d7d66358c9acfe87b1b5f38338d581815491555f526020527ff33499cccaa0611882086224cc48cd82ef54b66a4d2edf4ed67108dd516896d560405fa1005b634ee0b8f85f526004601cfd5b346103f1575f6003193601126103f15760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346103f1575f6003193601126103f157602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346103f1575f6003193601126103f15760206105206110bb612c2b565b5050613987565b346103f1575f6003193601126103f1575f6040526101326041526020805260606020f35b346103f15760406003193601126103f157600435611102612bf8565b61110a612edb565b811515918261122f575b61111c612fe6565b926111278451151590565b61122a576111eb575b5061118261113c612603565b61117c61071861115f60608701516fffffffffffffffffffffffffffffffff1690565b60408701516fffffffffffffffffffffffffffffffff16906129a8565b90612811565b9061119f6111916107186139bc565b602435818082039110020190565b5f925b816111ac856129cc565b9410806111e2575b156111d557806111c76111d092876139de565b80820391110290565b6111a2565b610e438361081e8761323f565b508015156111b4565b61122490836111fd60445f5236155190565b917f00000000000000000000000000000000000000000000000000000000000000006138d9565b5f611130565b610ccb565b61125b8130337f000000000000000000000000000000000000000000000000000000000000000061385a565b61126581336138af565b611114565b346103f1575f6003193601126103f157611282612c1f565b60206dffffffffffffffffffffffffffff6101806108c0612c2b565b346103f15760206003193601126103f1576004356112ba612bf8565b6112c2612edb565b6112ca612fe6565b916112ea6dffffffffffffffffffffffffffff61018085015116826151cf565b6113056cffffffffffffffffffffffffff82168092146151b6565b80156113545761079693611336926113309261132033613b42565b9260245f52361551933391613ba6565b91614d13565b5f63929eee145d60405163ffffffff90911681529081906020820190565b63d61c50f85f526004601cfd5b346103f15760206003193601126103f1576020610520600435611383816103d3565b61138b612c1f565b73ffffffffffffffffffffffffffffffffffffffff6113a8612c2b565b505091165f52600483526cffffffffffffffffffffffffff60405f20541690613e0d565b346103f1575f6003193601126103f1576113e4612bf8565b6113ec612edb565b6113f4612fe6565b906113fe33613b42565b916cffffffffffffffffffffffffff8351168015611354576107969382611330926114416dffffffffffffffffffffffffffff610180611336970151168261529f565b9160045f52361551933391613ba6565b346103f1575f6003193601126103f157611469612c1f565b6020610520611476612c2b565b5050613e2d565b9181601f840112156103f15782359167ffffffffffffffff83116103f1576020808501948460051b0101116103f157565b60209060206040818301928281528551809452019301915f5b8281106114d5575050505090565b8351855293810193928101926001016114c7565b346103f15760406003193601126103f15767ffffffffffffffff6004358181116103f15761151b90369060040161147d565b90916024359081116103f15761153590369060040161147d565b919092611540612bf8565b611548612edb565b938383036116165761156161155c846129f9565b612707565b938385527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061158f856129f9565b0136602087013761159e612fe6565b935f5b8181106115cd57610796876115b98a61081e8a61323f565b6115c1612c16565b604051918291826114ae565b806116056115de6001938589612a3e565b356115e8816103d3565b6115f3838789612a3e565b356115fd81610528565b36918a613627565b61160f828a612a53565b52016115a1565b639d89020a5f526004601cfd5b346103f1575f6003193601126103f15761163b612c1f565b6020611645612c2b565b5050611658611652612603565b91613e2d565b90604051918082039111028152f35b346103f1575f6003193601126103f157602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b60209060206040818301928281528551809452019301915f5b8281106116de575050505090565b835163ffffffff16855293810193928101926001016116d0565b346103f1575f6003193601126103f157611710612c1f565b6005546fffffffffffffffffffffffffffffffff81169060801c818103908111610b385761174061155c826129f9565b918183527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061176e836129f9565b013660208501375f5b82811061178c576040518061079686826116b7565b806117cf6117ba6117b06117a260019587612a67565b5f52600660205260405f2090565b5463ffffffff1690565b6117c48388612a53565b9063ffffffff169052565b01611777565b346103f1575f6003193601126103f15760205f525f6020527f0000000000000000000000000000000000000000000000000000000000000000603f527f0000000000000000000000000000000000000000000000000000000000000000605f5260805ff35b346103f1575f6003193601126103f15760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346103f15760406003193601126103f157600435611891816103d3565b6024359061189d612bf8565b6118a5612edb565b906118ae612fe6565b926118ce6dffffffffffffffffffffffffffff61018086015116826151cf565b916cffffffffffffffffffffffffff926118ec8482168092146151b6565b8015611a08578561098c8261199661081e976119316108239b611a029789337f0000000000000000000000000000000000000000000000000000000000000000614f73565b61193a33613b42565b9080611949858285511661340b565b168252335f9081526004602052604090205b9151166cffffffffffffffffffffffffff167fffffffffffffffffffffffffffffffffffffff00000000000000000000000000825416179055565b6119d56119c26119a587613b42565b926119bd84516cffffffffffffffffffffffffff1690565b613476565b6cffffffffffffffffffffffffff168252565b6119fd8573ffffffffffffffffffffffffffffffffffffffff165f52600460205260405f2090565b61342a565b33615011565b63ddee9b305f526004601cfd5b6004359061ffff821682036103f157565b6024359061ffff821682036103f157565b346103f15760206003193601126103f157611a50611a15565b611a58612bf8565b611a60612edb565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163303611b765761ffff82166103e88111611b7157611ab3612fe6565b8051611b6c578061081e92610e4395610120830191611ade611ad7845161ffff1690565b61ffff1690565b8103611aee575b5050505061323f565b81611b6093611b427f4b34705283cdb9398d0e50b216b8fb424c6d4def5db9bfadc661ee3adc6076ee96611b4b947f0000000000000000000000000000000000000000000000000000000000000000613efd565b9061ffff169052565b60405161ffff90911681529081906020820190565b0390a1805f8080611ae5565b613ef0565b613ee3565b6332cc72365f526004601cfd5b346103f1575f6003193601126103f157611b9b612c1f565b60206cffffffffffffffffffffffffff60806108c0612c2b565b346103f15760206003193601126103f1576020611bd0612edb565b610520611330600435613f7b565b346103f15760206003193601126103f157600435611bfa612edb565b90611c0481613f7b565b03611c12576104dd90614d13565b638a164f635f526004601cfd5b346103f1575f6003193601126103f157602060ff5f54166040519015158152f35b346103f1575f6003193601126103f157602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346103f1575f6003193601126103f1577f00000000000000000000000000000000000000000000000000000000000000008033186104f957611cd0612bf8565b611cd8612edb565b611ce0612fe6565b91611ceb8351151590565b611fee57611d9590611cfb612603565b90611d0585612f95565b9081831015611f9e575090611d1d81611d2d93612811565b90611d28828761412c565b612a67565b611d57847f000000000000000000000000000000000000000000000000000000000000000061420d565b5f610140850152600184526127106101608501525f61010085015261117c61071861115f60608701516fffffffffffffffffffffffffffffffff1690565b60c08301805163ffffffff908116918280611e27575b50505050611dba6107186139bc565b905f905b828210611e0f575050506cffffffffffffffffffffffffff611df060a08401516cffffffffffffffffffffffffff1690565b16611e0a57611e01610e439261323f565b61081e4261450a565b6144fd565b611e1f8161117c600193886139de565b910190611dbe565b611e426107b98563ffffffff165f52600760205260405f2090565b6020810180516cffffffffffffffffffffffffff1689611e84611e7285516cffffffffffffffffffffffffff1690565b6cffffffffffffffffffffffffff1690565b6cffffffffffffffffffffffffff80931610611f42575b5090611f0d92915f8652806fffffffffffffffffffffffffffffffff611f026040611eea611ed688516cffffffffffffffffffffffffff1690565b96516cffffffffffffffffffffffffff1690565b9601516fffffffffffffffffffffffffffffffff1690565b169316911684614477565b611f16816144b1565b4214611f23575b80611dab565b6117c4611f32611f3a94612b53565b9283166144d7565b5f8080611f1d565b886fffffffffffffffffffffffffffffffff611f698695949b8b611f7295611f0d99614264565b90501690612811565b97611f9483611f8f8a63ffffffff165f52600760205260405f2090565b612a74565b9091925089611e9b565b90808311611fae575b5050611d2d565b91610781611fbf611fe79483612811565b80937f00000000000000000000000000000000000000000000000000000000000000006140f2565b5f80611fa7565b6140e5565b346103f15760206003193601126103f1576004357f00000000000000000000000000000000000000000000000000000000000000008033186104f957612037612bf8565b61203f612edb565b906395c098395f5260205260205f6024601c7f00000000000000000000000000000000000000000000000000000000000000005afa60203d141615610ebc575f516121195761208c612fe6565b8051612114576120a361209d612603565b82613eda565b831161210f578261210a826120df61081e94610e43977f000000000000000000000000000000000000000000000000000000000000000061455a565b61098c83337f00000000000000000000000000000000000000000000000000000000000000006140f2565b6145d8565b61454d565b614540565b614533565b346103f1575f6003193601126103f157612136612bf8565b61213e612edb565b612146612fe6565b9060408201916fffffffffffffffffffffffffffffffff9081845116156121fa57612178612172612603565b826133d4565b8281169182156121ed57858461219a6121e89461081e97610e439a5116612b68565b16905261098c837f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000006140f2565b614601565b63f784cfa45f526004601cfd5b6345c835cb5f526004601cfd5b346103f1575f6003193601126103f15760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346103f1575f6003193601126103f157602060035461ffff6040519160401c168152f35b346103f15760206003193601126103f157606061229c60043561228781610528565b61228f61274b565b612297612c1f565b612b8a565b6fffffffffffffffffffffffffffffffff60408051926cffffffffffffffffffffffffff80825116855260208201511660208501520151166040820152f35b346103f15760206003193601126103f1576004356122f8816103d3565b612300612bf8565b612308612edb565b6123118261462a565b156123cf5761231e612fe6565b917f000000000000000000000000000000000000000000000000000000000000000060018160581c1661235e575b508261098c61081e92610e4395614699565b5f80917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc36019082601c60405193638b3ce9b385528760208601526101c08a604087015e610200908180870152806102208701526024610240870137360193019160601c5af115610ebc575f61234c565b63a97ab1675f526004601cfd5b346103f15760406003193601126103f157602061244e6004356123fe816103d3565b73ffffffffffffffffffffffffffffffffffffffff60243591612420836103d3565b165f526009835260405f209073ffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b54604051908152f35b346103f15760406003193601126103f157612470611a15565b612478611a26565b907f000000000000000000000000000000000000000000000000000000000000000033186104f9576124a8612bf8565b6124b0612edb565b906124b9612fe6565b80516125ae576124ff816101608101956124d8611ad7885161ffff1690565b947f0000000000000000000000000000000000000000000000000000000000000000614760565b61ffff959186811694612710978887116125a95783169788116125a4578711928315612588575b61254392612537919061ffff169052565b61ffff16610140840152565b612566575b9261256161081e9261255c610e439661323f565b614831565b61485a565b9261257084613e2d565b612578612603565b106125835792612548565b614824565b61259185613e2d565b612599612603565b101561252657614817565b61480a565b6147fd565b614753565b346103f1575f6003193601126103f157602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b6370a082315f523060205260205f6024601c7f00000000000000000000000000000000000000000000000000000000000000005afa601f3d111615612647575f5190565b634963f6d55f526004601cfd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051906040820182811067ffffffffffffffff8211176126a157604052565b612654565b604051906060820182811067ffffffffffffffff8211176126a157604052565b604051906101c0820182811067ffffffffffffffff8211176126a157604052565b604051906020820182811067ffffffffffffffff8211176126a157604052565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f604051930116820182811067ffffffffffffffff8211176126a157604052565b6127536126a6565b905f82525f60208301525f6040830152565b906fffffffffffffffffffffffffffffffff60016127816126a6565b9380546cffffffffffffffffffffffffff90818116875260681c1660208601520154166040830152565b906fffffffffffffffffffffffffffffffff6127c5612681565b92546cffffffffffffffffffffffffff8116845260681c166020830152565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b91908203918211610b3857565b6128266126c6565b905f82525f60208301525f60408301525f60608301525f60808301525f60a08301525f60c08301525f60e08301525f6101008301525f6101208301525f6101408301525f6101608301525f6101808301525f6101a0830152565b6128886126c6565b906128ce5f5461289d60ff8216859015159052565b60081c6fffffffffffffffffffffffffffffffff9081166020850152600154908116604085015260801c6060840152565b6002546cffffffffffffffffffffffffff8082166080850152606882901c1660a084015263ffffffff60d082901c811660c08501526129859161291b9060ff9060f01c16151560e0860152565b60035463ffffffff8282161661010086015261ffff602082901c8116610120870152603082901c8116610140870152604082901c16610160860152605081901c6dffffffffffffffffffffffffffff1661018086015260c01c166101a084019063ffffffff169052565b565b9060016fffffffffffffffffffffffffffffffff80931601918211610b3857565b9190916fffffffffffffffffffffffffffffffff80809416911601918211610b3857565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114610b385760010190565b67ffffffffffffffff81116126a15760051b60200190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b9190811015612a4e5760051b0190565b612a11565b8051821015612a4e5760209160051b010190565b91908201809211610b3857565b604060016fffffffffffffffffffffffffffffffff92612ad86cffffffffffffffffffffffffff86511682906cffffffffffffffffffffffffff167fffffffffffffffffffffffffffffffffffffff00000000000000000000000000825416179055565b60208501517fffffffffffff00000000000000000000000000ffffffffffffffffffffffffff79ffffffffffffffffffffffffff0000000000000000000000000083549260681b16911617815501920151167fffffffffffffffffffffffffffffffff00000000000000000000000000000000825416179055565b90600163ffffffff80931601918211610b3857565b6fffffffffffffffffffffffffffffffff9182169082160391908211610b3857565b9190612b94612c2b565b915063ffffffff809316928315159116831416612bf357505f5260076020526fffffffffffffffffffffffffffffffff600160405f2080546cffffffffffffffffffffffffff90818116875260681c1660208601520154166040830152565b925050565b63929eee14805c612c09576001905d565b637fa8a9875f526004601cfd5b5f63929eee145d565b63929eee145c612c0957565b612c3361281e565b505f612c3d61274b565b612c45612880565b92612c5f8460c063ffffffff910151168042119015151690565b612d73575b6101a084015163ffffffff904290821603612d1f575b60c085015163ffffffff16908116612c8f5750565b92509050612cae6107b98363ffffffff165f52600760205260405f2090565b90612cc960208301516cffffffffffffffffffffffffff1690565b6cffffffffffffffffffffffffff612cf1611e7285516cffffffffffffffffffffffffff1690565b911610612cfa57565b612d0c612d05612603565b85846149e2565b80612d145750565b612985908584614a6b565b612d6b427f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000088614883565b505050612c7a565b91505060c08201612d88815163ffffffff1690565b91612da7612d9e6101a086015163ffffffff1690565b63ffffffff1690565b63ffffffff8416908103612e04575b505f612dd36107b98563ffffffff165f52600760205260405f2090565b92612de6612ddf612603565b87866149e2565b80612df3575b5052612c64565b612dfe908786614a6b565b5f612dec565b612e50907f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000087614883565b5050612db6565b906b033b2e3c9fd0803ce800000091817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048111820215830215612e9a57020490565b63ad251c275f526004601cfd5b817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048111820215830215612e9a57020490565b604051608081019080821067ffffffffffffffff8311176126a15761055b9160405260608152606060208201525f60408201525f60608201525f3560e01c90614c2f565b909173ffffffffffffffffffffffffffffffffffffffff82165f52600960205280612f6b8460405f209073ffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b555f527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560205fa3565b612fb26cffffffffffffffffffffffffff60808301511682613e0d565b906fffffffffffffffffffffffffffffffff90816060820151168301809311610b385760400151168101809111610b385790565b612fee61281e565b50612ff7612880565b906130118260c063ffffffff910151168042119015151690565b61317f575b6101a082015163ffffffff908116428190036130eb575b5060c083015163ffffffff169081166130435750565b61305e6107b98263ffffffff165f52600760205260405f2090565b60208101516cffffffffffffffffffffffffff166cffffffffffffffffffffffffff61309a611e7284516cffffffffffffffffffffffffff1690565b9116106130a6575b5050565b6130b86130b1612603565b85836149e2565b806130c257505050565b826130d5611f8f92612985958886614264565b505063ffffffff165f52600760205260405f2090565b6131799061313b427f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000088614883565b9261317161315e6101808a95949501516dffffffffffffffffffffffffffff1690565b6dffffffffffffffffffffffffffff1690565b904290614d81565b5f61302d565b613193612d9e60c084015163ffffffff1690565b6131a8612d9e6101a085015163ffffffff1690565b8082036131c0575b50506131bb82614dcb565b613016565b81613210613238937f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000088614883565b93909261323261315e6101808a01516dffffffffffffffffffffffffffff1690565b91614d81565b5f806131b0565b6129859061324c81613e2d565b613254612603565b1060e08201819052908051151561328161071860208401516fffffffffffffffffffffffffffffffff1690565b60081b175f556132a761071860408301516fffffffffffffffffffffffffffffffff1690565b6132c761071860608401516fffffffffffffffffffffffffffffffff1690565b60801b176001556132eb611e7260808301516cffffffffffffffffffffffffff1690565b613308611e7260a08401516cffffffffffffffffffffffffff1690565b61331c612d9e60c085015163ffffffff1690565b9060681b9060d01b8460f01b171717600255613343612d9e61010083015163ffffffff1690565b613356611ad761012084015161ffff1690565b613369611ad761014085015161ffff1690565b9061337d611ad761016086015161ffff1690565b916133b2612d9e6101a06133a661315e6101808a01516dffffffffffffffffffffffffffff1690565b97015163ffffffff1690565b9160201b9060301b179160401b908460501b9060c01b17171717600355614f47565b906fffffffffffffffffffffffffffffffff91826060820151168203918211610b3857604083910151169081808203911002011690565b6cffffffffffffffffffffffffff9182169082160391908211610b3857565b6cffffffffffffffffffffffffff6129859251166cffffffffffffffffffffffffff167fffffffffffffffffffffffffffffffffffffff00000000000000000000000000825416179055565b9190916cffffffffffffffffffffffffff80809416911601918211610b3857565b91906134a1612fe6565b926134c16dffffffffffffffffffffffffffff61018086015116846151cf565b6cffffffffffffffffffffffffff6134dd8183168093146151b6565b8115611a08577f0000000000000000000000000000000000000000000000000000000000000000600181605c1c1661359f575b509461098c61359a926135636129859861352987613b42565b9080613538858285511661340b565b16825261195b8873ffffffffffffffffffffffffffffffffffffffff165f52600460205260405f2090565b6135726119c26119a588613b42565b6119fd8673ffffffffffffffffffffffffffffffffffffffff165f52600460205260405f2090565b615011565b5f80917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c9893983601906040519163a018f90e83523360208401528760408401528860608401528660808401526101c08660a085015e610260808401528061028084015260646102a084013782601c610220360193019160601c5af115610ebc57945f613510565b909291926136466107b98563ffffffff165f52600760205260405f2090565b9361365b612d9e60c085015163ffffffff1690565b9063ffffffff811691821461385557613686836106cf8363ffffffff165f52600860205260405f2090565b946136d96137046136aa60408a01516fffffffffffffffffffffffffffffffff1690565b986136f96107188a54809c6cffffffffffffffffffffffffff968795516cffffffffffffffffffffffffff1690565b6fffffffffffffffffffffffffffffffff97889687921693169116612ea7565b9960681c1689612b68565b9081169788156138505760608761379b6137bc9361055b9b61374d6137d2988f9d8e8e7f0000000000000000000000000000000000000000000000000000000000000000615049565b907fffffff00000000000000000000000000000000ffffffffffffffffffffffffff7cffffffffffffffffffffffffffffffff0000000000000000000000000083549260681b169116179055565b01916137b783516fffffffffffffffffffffffffffffffff1690565b612b68565b6fffffffffffffffffffffffffffffffff169052565b836137dc8461462a565b156138245761381f916137ee856150b9565b61381983827f00000000000000000000000000000000000000000000000000000000000000006140f2565b85615151565b61518b565b61381f9150837f00000000000000000000000000000000000000000000000000000000000000006140f2565b61503c565b6107d3565b601c5f60649281946020966040519860605260405260601b602c526f23b872dd000000000000000000000000600c525af13d1560015f51141716156138a2575f606052604052565b637939f4245f526004601cfd5b905f527fe8b606ac1e5df7657db58d297ca8f41c090fc94c5fd2d6958f043e41736e9fa660205fa2565b600181605a1c166138eb575b50505050565b5f601c6101c08296958684973603928392604051986383d9e1eb8a5260208a0152604089015e61020080880152816102208801526102408701376102240193019160601c5af115610ebc575f8080806138e5565b906129856fffffffffffffffffffffffffffffffff83168093146151b6565b5f527ff2672935fc79f5237559e2e2999dbe743bf65430894ac2b37666890e7c69e1af60205fa1565b6111c76fffffffffffffffffffffffffffffffff602083015116916cffffffffffffffffffffffffff60808201511690613e0d565b61055b6005546fffffffffffffffffffffffffffffffff81169060801c612b68565b9190600554906fffffffffffffffffffffffffffffffff918281169060801c8114613afc575f52600660205281613a3d63ffffffff60405f2054169283613a366107b98263ffffffff165f52600760205260405f2090565b9788614264565b90501693613a5d81611f8f8463ffffffff165f52600760205260405f2090565b6cffffffffffffffffffffffffff6020818351169201511614613a7e575050565b600554918083169260801c8314613afc57613acd83612985945f52600660205260405f207fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000008154169055612987565b167fffffffffffffffffffffffffffffffff0000000000000000000000000000000060055416176005556144b1565b60046040517f87274801000000000000000000000000000000000000000000000000000000008152fd5b906129856cffffffffffffffffffffffffff83168093146151b6565b905f613b4c6126e7565b5273ffffffffffffffffffffffffffffffffffffffff82165f526004602052613b9360405f206cffffffffffffffffffffffffff613b886126e7565b91541681529261462a565b613b9957565b636bc671fd5f526004601cfd5b9392959491909560c0850190613bc0825163ffffffff1690565b9763ffffffff92838a1615613d8e575b50938893613d4b93613d4484613c4961098c99613c266cffffffffffffffffffffffffff6129859e9d9916978d898d8a7f00000000000000000000000000000000000000000000000000000000000000006151f5565b6135726119c284613c4484516cffffffffffffffffffffffffff1690565b61340b565b613c54863086615011565b613ce1613c8e856106cf613c796107b98d63ffffffff165f52600760205260405f2090565b9b63ffffffff165f52600860205260405f2090565b613ca9836119bd83546cffffffffffffffffffffffffff1690565b6cffffffffffffffffffffffffff167fffffffffffffffffffffffffffffffffffffff00000000000000000000000000825416179055565b613d12613cff826119bd8b516cffffffffffffffffffffffffff1690565b6cffffffffffffffffffffffffff168952565b613d3160a08b01916119bd83516cffffffffffffffffffffffffff1690565b6cffffffffffffffffffffffffff169052565b8a1661526f565b613d5d613d56612603565b84836149e2565b80613d7c575b50611f8f8663ffffffff165f52600760205260405f2090565b613d8890878584614264565b50613d63565b93613dfc9950613d4b93613d44899894613c4961098c9995613ded612d9e613de76129859f613dbd9051151590565b7f000000000000000000000000000000000000000000000000000000000000000090815f03020190565b42612a67565b9e8f809b6117c48883166144d7565b959950509498995050935093613bd0565b906dffffffffffffffffffffffffffff61018061055b930151169061529f565b6cffffffffffffffffffffffffff8060a08301511690608083015116818103908111610b3857613e679061ffff61016085015116906152ee565b908101809111610b3857613e91906dffffffffffffffffffffffffffff610180840151169061529f565b6fffffffffffffffffffffffffffffffff6040830151168101809111610b3857613ed4610718606061055b9401516fffffffffffffffffffffffffffffffff1690565b90612a67565b6111c790613e2d565b63499fddb15f526004601cfd5b6337f1a75f5f526004601cfd5b919060018360551c16613f0f57505050565b5f9283601c81946101c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc360191604051966303473d8d88526020880152604087015e610200908180870152806102208701526024610240870137360193019160601c5af115610ebc57565b613f83612bf8565b613f8b612fe6565b90613f968251151590565b6140e057613fb390613fa783613987565b90818082039110020190565b90613fe4613fdf613fd961315e6101808501516dffffffffffffffffffffffffffff1690565b846151cf565b613b26565b906cffffffffffffffffffffffffff821680156140db576140d2926140b361098c9261409b61401233613b42565b61403e8784337f0000000000000000000000000000000000000000000000000000000000000000615343565b61406a8930337f000000000000000000000000000000000000000000000000000000000000000061385a565b6140886119c2866119bd84516cffffffffffffffffffffffffff1690565b335f90815260046020526040902061342a565b6140ac873361359a5f805236155190565b86336153cf565b613d3160808401916119bd83516cffffffffffffffffffffffffff1690565b90612985612c16565b615336565b615329565b63449e5f505f526004601cfd5b60105f60449260209582956014526034526fa9059cbb00000000000000000000000082525af13d1560015f51141716156104df575f603452565b8115610cd8578051610ccb576141648230337f000000000000000000000000000000000000000000000000000000000000000061385a565b815f52337fe8b606ac1e5df7657db58d297ca8f41c090fc94c5fd2d6958f043e41736e9fa660205fa27f000000000000000000000000000000000000000000000000000000000000000091600183605a1c166141bf57505050565b5f9283601c81946101c0600319360191604051966383d9e1eb88526020880152604087015e610200808601526102209080828701526004610240870137360193019160601c5af115610ebc57565b60018160591c1661421c575050565b5f91829182601c60031936016101c060405195639ecc64e68752602087015e6101e0808601526102009080828701526004610220870137360193019160601c5af115610ebc57565b9293916142b69161428285516cffffffffffffffffffffffffff1690565b9460208101956cffffffffffffffffffffffffff9485916142b089516cffffffffffffffffffffffffff1690565b9061340b565b16801561446a5761018083019788516142dc906dffffffffffffffffffffffffffff1690565b6dffffffffffffffffffffffffffff166142f5916151cf565b81811090829003020161430790613b26565b965193871693614327906dffffffffffffffffffffffffffff1685612e57565b6143309061393f565b9587815161434a906cffffffffffffffffffffffffff1690565b9061435491613476565b6cffffffffffffffffffffffffff16905260400180516143879087906fffffffffffffffffffffffffffffffff166129a8565b6fffffffffffffffffffffffffffffffff16905260a0810180516143bb9088906cffffffffffffffffffffffffff1661340b565b6cffffffffffffffffffffffffff1690526060810180516143ef9087906fffffffffffffffffffffffffffffffff166129a8565b6fffffffffffffffffffffffffffffffff16905260800180516144229087906cffffffffffffffffffffffffff1661340b565b6cffffffffffffffffffffffffff1690525f8052361551906fffffffffffffffffffffffffffffffff85169182309161445a92615011565b63ffffffff1691612985926153fd565b505f965086955050505050565b91929092604051935f526020526040527f9262dc39b47cad3a0512e4c08dda248cb345e7163058f300bc63f56bda288b6e60605fa2604052565b7fcbdf25bf6e096dd9030d89bb2ba2e3e7adb82d25a233c3ca3d92e9f098b74e555f80a2565b7f5c9a946d3041134198ebefcd814de7748def6576efd3d1b48f48193e183e89ef5f80a2565b634d7909975f526004601cfd5b5f527f9dc30b8eda31a6a144e092e5de600955523a6a925cc15cc1d1b9b4872cfa615560205fa1565b634a1c13a95f526004601cfd5b63d0242b285f526004601cfd5b63119fe6e35f526004601cfd5b9190600183605b1c1661456c57505050565b5f9283601c81946101c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc3601916040519663b1cfda0d88526020880152604087015e610200908180870152806102208701526024610240870137360193019160601c5af115610ebc57565b5f527fb848ae6b1253b6cb77e81464128ce8bd94d3d524fea54e801e0da869784dca3360205fa1565b5f527f860c0aa5520013080c2f65981705fcdea474d9f7c3daf954656ed5e65d692d1f60205fa1565b90604051916306e744445f527f000000000000000000000000000000000000000000000000000000000000000060205260405260205f6044601c7f00000000000000000000000000000000000000000000000000000000000000005afa60203d141615610ebc575f5191604052565b9073ffffffffffffffffffffffffffffffffffffffff81165f52600460205260405f20916cffffffffffffffffffffffffff6146d36126e7565b93541692838152836146e55750505050565b81614715918561470b6dffffffffffffffffffffffffffff61018088970151168261529f565b9485923694613ba6565b92604051935f526020526040527fe12b220b92469ae28fb0d79de531f94161431be9f073b96b8aad3effb88be6fa60605fa26040525f8080806138e5565b63b9de88a25f526004601cfd5b91909260018360561c165f146147f65791604093916101c05f947fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc36019287519563cc4526428752602087015287860152606085015e6102208084015280610240840152604461026084013782601c610200360193019160601c5af11560403d1017610ebc5761ffff90815f5116916020511690565b5090509091565b63cf1f916f5f526004601cfd5b638ec830735f526004601cfd5b630a68e5bf5f526004601cfd5b63253ecbb95f526004601cfd5b5f527fff7b6c8be373823323d3c5d99f5d027dd409dce5db54eae511bbdd5546b7503760205fa1565b5f527f72877a153052500f5edbb2f9da96a0f45d671d4b4555fdf8628a709dc4eab43a60205fa1565b92939190915f925f9261ffff968761014088015116916101a088019363ffffffff93848651168403848111610b38576148bb91615545565b809a6101208b0151168061495d575b50508061493b575b5050614930610180612985959697980161491c6149178b613ed46149118d61490b61315e88516dffffffffffffffffffffffffffff1690565b93612a67565b8261529f565b615464565b6dffffffffffffffffffffffffffff169052565b1663ffffffff169052565b612985959697506149546149309261018092858c61542b565b979695506148d2565b6149a69298509061496d916152ee565b6149a06cffffffffffffffffffffffffff60808c015116916dffffffffffffffffffffffffffff6101808d01511661529f565b9061529f565b604089016fffffffffffffffffffffffffffffffff908181511691838301809311610b38576149d99083168093146151b6565b5295895f6148ca565b614a106cffffffffffffffffffffffffff916142b08360a0860151169184602081835116920151169061340b565b16906fffffffffffffffffffffffffffffffff90614a4b82606083015116936dffffffffffffffffffffffffffff610180840151169061529f565b8301809311610b385760400151168101809111610b385780820391110290565b80516cffffffffffffffffffffffffff1690614aad60208201926cffffffffffffffffffffffffff9182916142b086516cffffffffffffffffffffffffff1690565b168015614c27576101808501958651614ad3906dffffffffffffffffffffffffffff1690565b6dffffffffffffffffffffffffffff16614aec916151cf565b818110908290030201614afe90613b26565b9451614b1e916dffffffffffffffffffffffffffff909116908616612e57565b614b279061393f565b91848151614b41906cffffffffffffffffffffffffff1690565b90614b4b91613476565b6cffffffffffffffffffffffffff1690526040018051614b7e9083906fffffffffffffffffffffffffffffffff166129a8565b6fffffffffffffffffffffffffffffffff16905260a082018051614bb29085906cffffffffffffffffffffffffff1661340b565b6cffffffffffffffffffffffffff16905260608201908151614be3906fffffffffffffffffffffffffffffffff1690565b90614bed916129a8565b6fffffffffffffffffffffffffffffffff169052608001908151614c1d906cffffffffffffffffffffffffff1690565b90613d319161340b565b505050505050565b90819073ffffffffffffffffffffffffffffffffffffffff7f1777adabd324f814e2b0e28f6edf876dce01d7d66358c9acfe87b1b5f38338d55416918260608501528215614d0c575060405190638925ca5a825260405f60209483868601523383860152606080860152366080860152368260a08701373660c4019082601c8701915af1835f51141615610ebc5760808361055b945160051b809460e06003830282010160405282820183823e80885201925f038184015281606084015285019260a08301845260a0019101525a60408401528251905190615481565b9392505050565b606081019073ffffffffffffffffffffffffffffffffffffffff825116156130a2575f8082518051908160061b95614d5060c08884010183615481565b519160051b019360405a91015103604085015283519463f0bd9468855260c4019082601c8601915af115610ebc5752565b927f18247a393d0531b65fbd94f5e78bc5639801a4efda62ae7b43533c4442116c3a959260c09592604051958652602086015260408501526060840152608083015260a0820152a1565b61298590611f8f60c082015f614de5825163ffffffff1690565b91614e016107b98463ffffffff165f52600760205260405f2090565b946020860190614e1e82516cffffffffffffffffffffffffff1690565b90614e39611e7289516cffffffffffffffffffffffffff1690565b6cffffffffffffffffffffffffff80931610614f17575b50614ec6614e6b88516cffffffffffffffffffffffffff1690565b92614eb3614e8682516cffffffffffffffffffffffffff1690565b60408b015163ffffffff8a16966fffffffffffffffffffffffffffffffff90911691861690861687614477565b516cffffffffffffffffffffffffff1690565b90614ee1611e7289516cffffffffffffffffffffffffff1690565b9116108314614f095750614ef4836154b9565b5263ffffffff165f52600760205260405f2090565b614f12906144b1565b614ef4565b614f29614f22612603565b828a6149e2565b8681614f37575b5050614e50565b614f41928a614264565b86614f30565b5f526020527f9385f9ff65bcd2fb81cece54b27d4ec7376795fc4dcff686e370e347b0ed86c060405fa1565b9091939293600182605c1c16614f8b575b5050505050565b6101c05f959486957fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc3601936040519663a018f90e885233602089015260408801526060870152608086015260a085015e610260808401528061028084015260446102a084013782601c610240360193019160601c5af115610ebc575f80808080614f84565b90915f527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60205fa3565b63186334fe5f526004601cfd5b9091600182605d1c1661505d575050505050565b601c5f9594869592836101c08895360393849360405199632970403d8b5260208b015260408a0152606089015e61022080880152816102408801526102608701376102440193019160601c5af115610ebc575f80808080614f84565b906040519163a1054f6b5f527f00000000000000000000000000000000000000000000000000000000000000006020526040527f000000000000000000000000000000000000000000000000000000000000000060605260205f6064601c827f00000000000000000000000000000000000000000000000000000000000000005af160203d141615610ebc575f51916040525f606052565b91929092604051935f526020526040527f0d0843a0fcb8b83f625aafb6e42f234ac48c6728b207d52d97cfa8fbd34d498f60605fa2604052565b90915f527fd6cddb3d69146e96ebc2c87b1b3dd0b20ee2d3b0eadf134e011afb434a3e56e660205fa3565b156151bd57565b634e487b715f5260116020526024601cfd5b8160011c906b033b2e3c9fd0803ce8000000908183190481118415176151bd5702010490565b919394909294600183605e1c1661520e57505050505050565b5f958695836101c0601c94899636039485946040519a633521cccc8c5260208c015260408b015260608a0152608089015e61024080880152816102608801526102808701376102640193019160601c5af115610ebc575f8080808080614c27565b919290925f526020527fecc966b282a372469fa4d3e497c2ac17983c3eaed03f3f17c9acf4b15591663e60405fa3565b817ffffffffffffffffffffffffffffffffffffffffffe6268e1b017bfe18bffffff04811115821517156151bd576b033b2e3c9fd0803ce800000091026b019d971e4fe8401e74000000010490565b817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec7704811115821517156151bd576127109102611388010490565b6322d7c0435f526004601cfd5b63e4aa50555f526004601cfd5b929192600181605f1c166153575750505050565b5f601c81956101c083967fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc36019260405197635aeb713f895260208901526040880152606087015e610220908180870152806102408701526024610260870137360193019160601c5af115610ebc575f8080806138e5565b91905f526020527f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a1560405fa2565b91905f526020527f5272034725119f19d7236de4129fdb5093f0dcb80282ca5edbd587df91d2bd8960405fa2565b909392935f9463ffffffff6101a0840151168203918211610b385761544f92615577565b9081615459575050565b61055b929350615545565b906129856dffffffffffffffffffffffffffff83168093146151b6565b9190825190818152602080809501918181019360051b0101915b8281106154a9575050509050565b815154815290840190840161549b565b6155039060055460801c90815f52600660205263ffffffff60405f2091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000825416179055612987565b6fffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffff000000000000000000000000000000006005549260801b16911617600555565b69152d02c7e14af68000008082029180828404036151bd57830202918183041490151715610b38576301e13380900490565b90610100820163ffffffff9060e0828251169401516155b7576155a5858503868611029283168093146151b6565b52808203911102818082039110020190565b848493940191828411610b38576155d29083168093146151b6565b528082039111028082039111029056fea164736f6c6343000819000a
Deployed Bytecode
0x60806040526004361015610011575f80fd5b5f3560e01c8062ae3bf8146103ce57806301e1d114146103c957806302372c4f146103c457806306fdde03146103bf578063088fee5e146103ba578063095ea7b3146103b55780630c1e3fea146103b05780630c3f6acf146103ab5780630cd1a5b6146103a657806311057cd0146103a157806314a1c32d1461039c57806318160ddd146103975780631d8557d7146103925780631da24f3e1461038d5780631e3cef531461038857806323b872dd146103835780632ab4d0521461037e578063313ce5671461037957806334bca29c14610374578063371fd8e61461036f57806338d52e0f1461036a5780633c231166146103655780633f3e4c1114610360578063469048401461035b5780634be687c6146103565780634c6c848f14610351578063514a4cd61461034c57806354635570146102b157806354b302c51461034757806354fd4d50146103425780636731ba6d1461033d578063683dd191146103385780636b174f351461033357806370a082311461032e5780637243d96c14610329578063739ccdd314610324578063740588591461031f578063766360171461031a5780637df1f1b914610315578063878eb9211461031057806395d89b411461030b5780639e6f980214610306578063a9059cbb14610301578063ae6ea191146102fc578063b1bf962d146102f7578063b68ce7a2146102f2578063b6b55f25146102ed578063c2b6b58c146102e8578063c45a0155146102e3578063c511ed5e146102de578063c5ebeaec146102d9578063c8796572146102d4578063cd7033c4146102cf578063d98e0fe8146102ca578063dbcd50b4146102c5578063dcd549d4146102c0578063dd62ed3e146102bb578063e5adc635146102b6578063e7e5db4f146102b15763f58c251c146102ac575f80fd5b6125b3565b61104e565b612457565b6123dc565b6122db565b612265565b612241565b612207565b61211e565b611ff3565b611c90565b611c40565b611c1f565b611bde565b611bb5565b611b83565b611a37565b611874565b61183a565b6117d5565b6116f8565b611667565b611623565b6114e9565b611451565b6113cc565b611361565b61129e565b61126a565b6110e6565b6110c2565b61109e565b611014565b610f5b565b610f21565b610ed1565b610d87565b610d35565b610ce5565b610c03565b610bab565b610b6e565b610b3d565b610a41565b6109fa565b61099a565b61095e565b61091d565b6108f1565b6108cd565b61088b565b61085b565b610835565b6107e0565b610661565b6105fc565b61055e565b610506565b6103f5565b73ffffffffffffffffffffffffffffffffffffffff8116036103f157565b5f80fd5b346103f15760206003193601126103f157600435610412816103d3565b61041a612bf8565b7f0000000000000000000000005b15f94efc3a6e2c82d7db8efd8d5ba55da11feb33186104f95773ffffffffffffffffffffffffffffffffffffffff808216308114917f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec71614176104ec576370a082315f5230602052602060346024601c845afa601f3d1116156104df575f6044601082602094336014526fa9059cbb00000000000000000000000082525af13d1560015f51141716156104df576104dd612c16565b005b6390b8ec185f526004601cfd5b6311530cde5f526004601cfd5b6302171e6a5f526004601cfd5b346103f1575f6003193601126103f1576020610520612603565b604051908152f35b63ffffffff8116036103f157565b60031960409101126103f15760043561054e816103d3565b9060243561055b81610528565b90565b346103f157604061056e36610536565b6105c0610579612681565b925f845263ffffffff60208501935f8552610592612c1f565b165f526008602052845f209073ffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b54906cffffffffffffffffffffffffff82168093526fffffffffffffffffffffffffffffffff809260681c168152835192835251166020820152f35b346103f1575f6003193601126103f15760205f525f6020527f1d57696e7465726d7574652054726164696e6720546574686572205553440000603f527f0000000000000000000000000000000000000000000000000000000000000000605f5260805ff35b346103f15761066f36610536565b90610678612c1f565b63ffffffff9182811691428310156107d3576106f76106f26107819261079696610786966106a4612c2b565b9391506106af61274b565b50160361079a576106cf909563ffffffff165f52600860205260405f2090565b9073ffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b6127ab565b9161072d61071860208501516fffffffffffffffffffffffffffffffff1690565b6fffffffffffffffffffffffffffffffff1690565b9261076861075461075461071860408601516fffffffffffffffffffffffffffffffff1690565b92516cffffffffffffffffffffffffff1690565b6cffffffffffffffffffffffffff809116921690612ea7565b612811565b6040519081529081906020820190565b0390f35b506106cf6107be6107b98763ffffffff165f52600760205260405f2090565b612765565b9563ffffffff165f52600860205260405f2090565b632561b8805f526004601cfd5b346103f15760406003193601126103f157610823600435610800816103d3565b610808612bf8565b61081e610813612edb565b916024359033612f1f565b614d13565b5f63929eee145d602060405160018152f35b346103f1575f6003193601126103f15761084d61281e565b506101c0610859612880565bf35b346103f1575f6003193601126103f15761087361281e565b5061087c612c1f565b6101c0610887612c2b565b5050f35b346103f1575f6003193601126103f1576108a3612c1f565b60206fffffffffffffffffffffffffffffffff60406108c0612c2b565b5050015116604051908152f35b346103f1575f6003193601126103f157602061ffff60035460301c16604051908152f35b346103f1575f6003193601126103f157610909612c1f565b6020610520610916612c2b565b5050612f95565b346103f1575f6003193601126103f157610935612c1f565b6020610520610942612c2b565b50506cffffffffffffffffffffffffff60808201511690613e0d565b346103f1575f6003193601126103f157610976612bf8565b610991610981612edb565b61081e61098c612fe6565b61323f565b5f63929eee145d005b346103f15760206003193601126103f15773ffffffffffffffffffffffffffffffffffffffff6004356109cc816103d3565b6109d4612c1f565b165f52600460205260206cffffffffffffffffffffffffff60405f205416604051908152f35b346103f1575f6003193601126103f1576020610a27610a17612c2b565b5050610a21612603565b906133d4565b6fffffffffffffffffffffffffffffffff60405191168152f35b346103f15760606003193601126103f157600435610a5e816103d3565b602435610a6a816103d3565b604435610a75612bf8565b610a7d612edb565b9173ffffffffffffffffffffffffffffffffffffffff84165f526009602052610ac660405f203373ffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8103610b11575b509061081e91610afe94613497565b5f63929eee145d60405160018152602090f35b9190818303928311610b3857610afe94610b2f61081e943383612f1f565b94509091610aef565b6127e4565b346103f1575f6003193601126103f15760206fffffffffffffffffffffffffffffffff5f5460081c16604051908152f35b346103f1575f6003193601126103f157602060405160ff7f0000000000000000000000000000000000000000000000000000000000000006168152f35b346103f1576020610bf4610bbe36610536565b9190610bc8612bf8565b61081e610bee610bd6612edb565b92610bdf612fe6565b9560445f523615519187613627565b9361323f565b5f63929eee145d604051908152f35b346103f15760206003193601126103f157600435610c1f612bf8565b610c27612edb565b8115610cd857610c598230337f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec761385a565b815f52337fe8b606ac1e5df7657db58d297ca8f41c090fc94c5fd2d6958f043e41736e9fa660205fa2610c8a612fe6565b918251610ccb576109919261098c61081e9260245f5282361551917fec6f30250269069b62d7b969a6af731214d20af9d040000000000000000000006138d9565b6361d1bc8f5f526004601cfd5b637e0820885f526004601cfd5b346103f1575f6003193601126103f157602060405173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7168152f35b346103f1575f6003193601126103f15760207f1777adabd324f814e2b0e28f6edf876dce01d7d66358c9acfe87b1b5f38338d55473ffffffffffffffffffffffffffffffffffffffff60405191168152f35b346103f15760206003193601126103f1576004357f0000000000000000000000005b15f94efc3a6e2c82d7db8efd8d5ba55da11feb33186104f957610dca612bf8565b610dd2612edb565b610dda612fe6565b8051610ec4577fec6f30250269069b62d7b969a6af731214d20af9d0400000000000000000000060018160571c16610e4b575b5082610e3e61081e9261098c610e25610e439761393f565b6fffffffffffffffffffffffffffffffff166020830152565b61395e565b6104dd612c16565b5f80917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc36019082601c6040519363849da12985528960208601526101c088604087015e610200908180870152806102208701526024610240870137360193019160601c5af115610ebc575f610e0d565b3d5f803e3d5ffd5b6381b210785f526004601cfd5b346103f1575f6003193601126103f157602060405173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000035a5d1bd68f3139971027b92c1ee9384a0708554168152f35b346103f1575f6003193601126103f15760206040517f00000000000000000000000000000000000000000000000000000000000001f48152f35b346103f15760206003193601126103f157600435610f78816103d3565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000feb516d9d946dd487a9346f6fee11f40c6945ee4163303611007577f1777adabd324f814e2b0e28f6edf876dce01d7d66358c9acfe87b1b5f38338d581815491555f526020527ff33499cccaa0611882086224cc48cd82ef54b66a4d2edf4ed67108dd516896d560405fa1005b634ee0b8f85f526004601cfd5b346103f1575f6003193601126103f15760206040517f000000000000000000000000000000000000000000000000000000000002a3008152f35b346103f1575f6003193601126103f157602060405173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000feb516d9d946dd487a9346f6fee11f40c6945ee4168152f35b346103f1575f6003193601126103f15760206105206110bb612c2b565b5050613987565b346103f1575f6003193601126103f1575f6040526101326041526020805260606020f35b346103f15760406003193601126103f157600435611102612bf8565b61110a612edb565b811515918261122f575b61111c612fe6565b926111278451151590565b61122a576111eb575b5061118261113c612603565b61117c61071861115f60608701516fffffffffffffffffffffffffffffffff1690565b60408701516fffffffffffffffffffffffffffffffff16906129a8565b90612811565b9061119f6111916107186139bc565b602435818082039110020190565b5f925b816111ac856129cc565b9410806111e2575b156111d557806111c76111d092876139de565b80820391110290565b6111a2565b610e438361081e8761323f565b508015156111b4565b61122490836111fd60445f5236155190565b917fec6f30250269069b62d7b969a6af731214d20af9d040000000000000000000006138d9565b5f611130565b610ccb565b61125b8130337f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec761385a565b61126581336138af565b611114565b346103f1575f6003193601126103f157611282612c1f565b60206dffffffffffffffffffffffffffff6101806108c0612c2b565b346103f15760206003193601126103f1576004356112ba612bf8565b6112c2612edb565b6112ca612fe6565b916112ea6dffffffffffffffffffffffffffff61018085015116826151cf565b6113056cffffffffffffffffffffffffff82168092146151b6565b80156113545761079693611336926113309261132033613b42565b9260245f52361551933391613ba6565b91614d13565b5f63929eee145d60405163ffffffff90911681529081906020820190565b63d61c50f85f526004601cfd5b346103f15760206003193601126103f1576020610520600435611383816103d3565b61138b612c1f565b73ffffffffffffffffffffffffffffffffffffffff6113a8612c2b565b505091165f52600483526cffffffffffffffffffffffffff60405f20541690613e0d565b346103f1575f6003193601126103f1576113e4612bf8565b6113ec612edb565b6113f4612fe6565b906113fe33613b42565b916cffffffffffffffffffffffffff8351168015611354576107969382611330926114416dffffffffffffffffffffffffffff610180611336970151168261529f565b9160045f52361551933391613ba6565b346103f1575f6003193601126103f157611469612c1f565b6020610520611476612c2b565b5050613e2d565b9181601f840112156103f15782359167ffffffffffffffff83116103f1576020808501948460051b0101116103f157565b60209060206040818301928281528551809452019301915f5b8281106114d5575050505090565b8351855293810193928101926001016114c7565b346103f15760406003193601126103f15767ffffffffffffffff6004358181116103f15761151b90369060040161147d565b90916024359081116103f15761153590369060040161147d565b919092611540612bf8565b611548612edb565b938383036116165761156161155c846129f9565b612707565b938385527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061158f856129f9565b0136602087013761159e612fe6565b935f5b8181106115cd57610796876115b98a61081e8a61323f565b6115c1612c16565b604051918291826114ae565b806116056115de6001938589612a3e565b356115e8816103d3565b6115f3838789612a3e565b356115fd81610528565b36918a613627565b61160f828a612a53565b52016115a1565b639d89020a5f526004601cfd5b346103f1575f6003193601126103f15761163b612c1f565b6020611645612c2b565b5050611658611652612603565b91613e2d565b90604051918082039111028152f35b346103f1575f6003193601126103f157602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000005b15f94efc3a6e2c82d7db8efd8d5ba55da11feb168152f35b60209060206040818301928281528551809452019301915f5b8281106116de575050505090565b835163ffffffff16855293810193928101926001016116d0565b346103f1575f6003193601126103f157611710612c1f565b6005546fffffffffffffffffffffffffffffffff81169060801c818103908111610b385761174061155c826129f9565b918183527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061176e836129f9565b013660208501375f5b82811061178c576040518061079686826116b7565b806117cf6117ba6117b06117a260019587612a67565b5f52600660205260405f2090565b5463ffffffff1690565b6117c48388612a53565b9063ffffffff169052565b01611777565b346103f1575f6003193601126103f15760205f525f6020527f07776d7455534454000000000000000000000000000000000000000000000000603f527f0000000000000000000000000000000000000000000000000000000000000000605f5260805ff35b346103f1575f6003193601126103f15760206040517f00000000000000000000000000000000000000000000000000000000000151808152f35b346103f15760406003193601126103f157600435611891816103d3565b6024359061189d612bf8565b6118a5612edb565b906118ae612fe6565b926118ce6dffffffffffffffffffffffffffff61018086015116826151cf565b916cffffffffffffffffffffffffff926118ec8482168092146151b6565b8015611a08578561098c8261199661081e976119316108239b611a029789337fec6f30250269069b62d7b969a6af731214d20af9d04000000000000000000000614f73565b61193a33613b42565b9080611949858285511661340b565b168252335f9081526004602052604090205b9151166cffffffffffffffffffffffffff167fffffffffffffffffffffffffffffffffffffff00000000000000000000000000825416179055565b6119d56119c26119a587613b42565b926119bd84516cffffffffffffffffffffffffff1690565b613476565b6cffffffffffffffffffffffffff168252565b6119fd8573ffffffffffffffffffffffffffffffffffffffff165f52600460205260405f2090565b61342a565b33615011565b63ddee9b305f526004601cfd5b6004359061ffff821682036103f157565b6024359061ffff821682036103f157565b346103f15760206003193601126103f157611a50611a15565b611a58612bf8565b611a60612edb565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000dd7dd3b5076cf89440d05585ff56d246386207be163303611b765761ffff82166103e88111611b7157611ab3612fe6565b8051611b6c578061081e92610e4395610120830191611ade611ad7845161ffff1690565b61ffff1690565b8103611aee575b5050505061323f565b81611b6093611b427f4b34705283cdb9398d0e50b216b8fb424c6d4def5db9bfadc661ee3adc6076ee96611b4b947fec6f30250269069b62d7b969a6af731214d20af9d04000000000000000000000613efd565b9061ffff169052565b60405161ffff90911681529081906020820190565b0390a1805f8080611ae5565b613ef0565b613ee3565b6332cc72365f526004601cfd5b346103f1575f6003193601126103f157611b9b612c1f565b60206cffffffffffffffffffffffffff60806108c0612c2b565b346103f15760206003193601126103f1576020611bd0612edb565b610520611330600435613f7b565b346103f15760206003193601126103f157600435611bfa612edb565b90611c0481613f7b565b03611c12576104dd90614d13565b638a164f635f526004601cfd5b346103f1575f6003193601126103f157602060ff5f54166040519015158152f35b346103f1575f6003193601126103f157602060405173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000dd7dd3b5076cf89440d05585ff56d246386207be168152f35b346103f1575f6003193601126103f1577f0000000000000000000000005b15f94efc3a6e2c82d7db8efd8d5ba55da11feb8033186104f957611cd0612bf8565b611cd8612edb565b611ce0612fe6565b91611ceb8351151590565b611fee57611d9590611cfb612603565b90611d0585612f95565b9081831015611f9e575090611d1d81611d2d93612811565b90611d28828761412c565b612a67565b611d57847fec6f30250269069b62d7b969a6af731214d20af9d0400000000000000000000061420d565b5f610140850152600184526127106101608501525f61010085015261117c61071861115f60608701516fffffffffffffffffffffffffffffffff1690565b60c08301805163ffffffff908116918280611e27575b50505050611dba6107186139bc565b905f905b828210611e0f575050506cffffffffffffffffffffffffff611df060a08401516cffffffffffffffffffffffffff1690565b16611e0a57611e01610e439261323f565b61081e4261450a565b6144fd565b611e1f8161117c600193886139de565b910190611dbe565b611e426107b98563ffffffff165f52600760205260405f2090565b6020810180516cffffffffffffffffffffffffff1689611e84611e7285516cffffffffffffffffffffffffff1690565b6cffffffffffffffffffffffffff1690565b6cffffffffffffffffffffffffff80931610611f42575b5090611f0d92915f8652806fffffffffffffffffffffffffffffffff611f026040611eea611ed688516cffffffffffffffffffffffffff1690565b96516cffffffffffffffffffffffffff1690565b9601516fffffffffffffffffffffffffffffffff1690565b169316911684614477565b611f16816144b1565b4214611f23575b80611dab565b6117c4611f32611f3a94612b53565b9283166144d7565b5f8080611f1d565b886fffffffffffffffffffffffffffffffff611f698695949b8b611f7295611f0d99614264565b90501690612811565b97611f9483611f8f8a63ffffffff165f52600760205260405f2090565b612a74565b9091925089611e9b565b90808311611fae575b5050611d2d565b91610781611fbf611fe79483612811565b80937f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec76140f2565b5f80611fa7565b6140e5565b346103f15760206003193601126103f1576004357f0000000000000000000000005b15f94efc3a6e2c82d7db8efd8d5ba55da11feb8033186104f957612037612bf8565b61203f612edb565b906395c098395f5260205260205f6024601c7f000000000000000000000000437e0551892c2c9b06d3ffd248fe60572e08cd1a5afa60203d141615610ebc575f516121195761208c612fe6565b8051612114576120a361209d612603565b82613eda565b831161210f578261210a826120df61081e94610e43977fec6f30250269069b62d7b969a6af731214d20af9d0400000000000000000000061455a565b61098c83337f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec76140f2565b6145d8565b61454d565b614540565b614533565b346103f1575f6003193601126103f157612136612bf8565b61213e612edb565b612146612fe6565b9060408201916fffffffffffffffffffffffffffffffff9081845116156121fa57612178612172612603565b826133d4565b8281169182156121ed57858461219a6121e89461081e97610e439a5116612b68565b16905261098c837f00000000000000000000000035a5d1bd68f3139971027b92c1ee9384a07085547f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec76140f2565b614601565b63f784cfa45f526004601cfd5b6345c835cb5f526004601cfd5b346103f1575f6003193601126103f15760206040517fec6f30250269069b62d7b969a6af731214d20af9d040000000000000000000008152f35b346103f1575f6003193601126103f157602060035461ffff6040519160401c168152f35b346103f15760206003193601126103f157606061229c60043561228781610528565b61228f61274b565b612297612c1f565b612b8a565b6fffffffffffffffffffffffffffffffff60408051926cffffffffffffffffffffffffff80825116855260208201511660208501520151166040820152f35b346103f15760206003193601126103f1576004356122f8816103d3565b612300612bf8565b612308612edb565b6123118261462a565b156123cf5761231e612fe6565b917fec6f30250269069b62d7b969a6af731214d20af9d0400000000000000000000060018160581c1661235e575b508261098c61081e92610e4395614699565b5f80917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc36019082601c60405193638b3ce9b385528760208601526101c08a604087015e610200908180870152806102208701526024610240870137360193019160601c5af115610ebc575f61234c565b63a97ab1675f526004601cfd5b346103f15760406003193601126103f157602061244e6004356123fe816103d3565b73ffffffffffffffffffffffffffffffffffffffff60243591612420836103d3565b165f526009835260405f209073ffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b54604051908152f35b346103f15760406003193601126103f157612470611a15565b612478611a26565b907f0000000000000000000000005b15f94efc3a6e2c82d7db8efd8d5ba55da11feb33186104f9576124a8612bf8565b6124b0612edb565b906124b9612fe6565b80516125ae576124ff816101608101956124d8611ad7885161ffff1690565b947fec6f30250269069b62d7b969a6af731214d20af9d04000000000000000000000614760565b61ffff959186811694612710978887116125a95783169788116125a4578711928315612588575b61254392612537919061ffff169052565b61ffff16610140840152565b612566575b9261256161081e9261255c610e439661323f565b614831565b61485a565b9261257084613e2d565b612578612603565b106125835792612548565b614824565b61259185613e2d565b612599612603565b101561252657614817565b61480a565b6147fd565b614753565b346103f1575f6003193601126103f157602060405173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000437e0551892c2c9b06d3ffd248fe60572e08cd1a168152f35b6370a082315f523060205260205f6024601c7f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec75afa601f3d111615612647575f5190565b634963f6d55f526004601cfd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051906040820182811067ffffffffffffffff8211176126a157604052565b612654565b604051906060820182811067ffffffffffffffff8211176126a157604052565b604051906101c0820182811067ffffffffffffffff8211176126a157604052565b604051906020820182811067ffffffffffffffff8211176126a157604052565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f604051930116820182811067ffffffffffffffff8211176126a157604052565b6127536126a6565b905f82525f60208301525f6040830152565b906fffffffffffffffffffffffffffffffff60016127816126a6565b9380546cffffffffffffffffffffffffff90818116875260681c1660208601520154166040830152565b906fffffffffffffffffffffffffffffffff6127c5612681565b92546cffffffffffffffffffffffffff8116845260681c166020830152565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b91908203918211610b3857565b6128266126c6565b905f82525f60208301525f60408301525f60608301525f60808301525f60a08301525f60c08301525f60e08301525f6101008301525f6101208301525f6101408301525f6101608301525f6101808301525f6101a0830152565b6128886126c6565b906128ce5f5461289d60ff8216859015159052565b60081c6fffffffffffffffffffffffffffffffff9081166020850152600154908116604085015260801c6060840152565b6002546cffffffffffffffffffffffffff8082166080850152606882901c1660a084015263ffffffff60d082901c811660c08501526129859161291b9060ff9060f01c16151560e0860152565b60035463ffffffff8282161661010086015261ffff602082901c8116610120870152603082901c8116610140870152604082901c16610160860152605081901c6dffffffffffffffffffffffffffff1661018086015260c01c166101a084019063ffffffff169052565b565b9060016fffffffffffffffffffffffffffffffff80931601918211610b3857565b9190916fffffffffffffffffffffffffffffffff80809416911601918211610b3857565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114610b385760010190565b67ffffffffffffffff81116126a15760051b60200190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b9190811015612a4e5760051b0190565b612a11565b8051821015612a4e5760209160051b010190565b91908201809211610b3857565b604060016fffffffffffffffffffffffffffffffff92612ad86cffffffffffffffffffffffffff86511682906cffffffffffffffffffffffffff167fffffffffffffffffffffffffffffffffffffff00000000000000000000000000825416179055565b60208501517fffffffffffff00000000000000000000000000ffffffffffffffffffffffffff79ffffffffffffffffffffffffff0000000000000000000000000083549260681b16911617815501920151167fffffffffffffffffffffffffffffffff00000000000000000000000000000000825416179055565b90600163ffffffff80931601918211610b3857565b6fffffffffffffffffffffffffffffffff9182169082160391908211610b3857565b9190612b94612c2b565b915063ffffffff809316928315159116831416612bf357505f5260076020526fffffffffffffffffffffffffffffffff600160405f2080546cffffffffffffffffffffffffff90818116875260681c1660208601520154166040830152565b925050565b63929eee14805c612c09576001905d565b637fa8a9875f526004601cfd5b5f63929eee145d565b63929eee145c612c0957565b612c3361281e565b505f612c3d61274b565b612c45612880565b92612c5f8460c063ffffffff910151168042119015151690565b612d73575b6101a084015163ffffffff904290821603612d1f575b60c085015163ffffffff16908116612c8f5750565b92509050612cae6107b98363ffffffff165f52600760205260405f2090565b90612cc960208301516cffffffffffffffffffffffffff1690565b6cffffffffffffffffffffffffff612cf1611e7285516cffffffffffffffffffffffffff1690565b911610612cfa57565b612d0c612d05612603565b85846149e2565b80612d145750565b612985908584614a6b565b612d6b427f000000000000000000000000000000000000000000000000000000000002a3007f00000000000000000000000000000000000000000000000000000000000001f488614883565b505050612c7a565b91505060c08201612d88815163ffffffff1690565b91612da7612d9e6101a086015163ffffffff1690565b63ffffffff1690565b63ffffffff8416908103612e04575b505f612dd36107b98563ffffffff165f52600760205260405f2090565b92612de6612ddf612603565b87866149e2565b80612df3575b5052612c64565b612dfe908786614a6b565b5f612dec565b612e50907f000000000000000000000000000000000000000000000000000000000002a3007f00000000000000000000000000000000000000000000000000000000000001f487614883565b5050612db6565b906b033b2e3c9fd0803ce800000091817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048111820215830215612e9a57020490565b63ad251c275f526004601cfd5b817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048111820215830215612e9a57020490565b604051608081019080821067ffffffffffffffff8311176126a15761055b9160405260608152606060208201525f60408201525f60608201525f3560e01c90614c2f565b909173ffffffffffffffffffffffffffffffffffffffff82165f52600960205280612f6b8460405f209073ffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b555f527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560205fa3565b612fb26cffffffffffffffffffffffffff60808301511682613e0d565b906fffffffffffffffffffffffffffffffff90816060820151168301809311610b385760400151168101809111610b385790565b612fee61281e565b50612ff7612880565b906130118260c063ffffffff910151168042119015151690565b61317f575b6101a082015163ffffffff908116428190036130eb575b5060c083015163ffffffff169081166130435750565b61305e6107b98263ffffffff165f52600760205260405f2090565b60208101516cffffffffffffffffffffffffff166cffffffffffffffffffffffffff61309a611e7284516cffffffffffffffffffffffffff1690565b9116106130a6575b5050565b6130b86130b1612603565b85836149e2565b806130c257505050565b826130d5611f8f92612985958886614264565b505063ffffffff165f52600760205260405f2090565b6131799061313b427f000000000000000000000000000000000000000000000000000000000002a3007f00000000000000000000000000000000000000000000000000000000000001f488614883565b9261317161315e6101808a95949501516dffffffffffffffffffffffffffff1690565b6dffffffffffffffffffffffffffff1690565b904290614d81565b5f61302d565b613193612d9e60c084015163ffffffff1690565b6131a8612d9e6101a085015163ffffffff1690565b8082036131c0575b50506131bb82614dcb565b613016565b81613210613238937f000000000000000000000000000000000000000000000000000000000002a3007f00000000000000000000000000000000000000000000000000000000000001f488614883565b93909261323261315e6101808a01516dffffffffffffffffffffffffffff1690565b91614d81565b5f806131b0565b6129859061324c81613e2d565b613254612603565b1060e08201819052908051151561328161071860208401516fffffffffffffffffffffffffffffffff1690565b60081b175f556132a761071860408301516fffffffffffffffffffffffffffffffff1690565b6132c761071860608401516fffffffffffffffffffffffffffffffff1690565b60801b176001556132eb611e7260808301516cffffffffffffffffffffffffff1690565b613308611e7260a08401516cffffffffffffffffffffffffff1690565b61331c612d9e60c085015163ffffffff1690565b9060681b9060d01b8460f01b171717600255613343612d9e61010083015163ffffffff1690565b613356611ad761012084015161ffff1690565b613369611ad761014085015161ffff1690565b9061337d611ad761016086015161ffff1690565b916133b2612d9e6101a06133a661315e6101808a01516dffffffffffffffffffffffffffff1690565b97015163ffffffff1690565b9160201b9060301b179160401b908460501b9060c01b17171717600355614f47565b906fffffffffffffffffffffffffffffffff91826060820151168203918211610b3857604083910151169081808203911002011690565b6cffffffffffffffffffffffffff9182169082160391908211610b3857565b6cffffffffffffffffffffffffff6129859251166cffffffffffffffffffffffffff167fffffffffffffffffffffffffffffffffffffff00000000000000000000000000825416179055565b9190916cffffffffffffffffffffffffff80809416911601918211610b3857565b91906134a1612fe6565b926134c16dffffffffffffffffffffffffffff61018086015116846151cf565b6cffffffffffffffffffffffffff6134dd8183168093146151b6565b8115611a08577fec6f30250269069b62d7b969a6af731214d20af9d04000000000000000000000600181605c1c1661359f575b509461098c61359a926135636129859861352987613b42565b9080613538858285511661340b565b16825261195b8873ffffffffffffffffffffffffffffffffffffffff165f52600460205260405f2090565b6135726119c26119a588613b42565b6119fd8673ffffffffffffffffffffffffffffffffffffffff165f52600460205260405f2090565b615011565b5f80917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c9893983601906040519163a018f90e83523360208401528760408401528860608401528660808401526101c08660a085015e610260808401528061028084015260646102a084013782601c610220360193019160601c5af115610ebc57945f613510565b909291926136466107b98563ffffffff165f52600760205260405f2090565b9361365b612d9e60c085015163ffffffff1690565b9063ffffffff811691821461385557613686836106cf8363ffffffff165f52600860205260405f2090565b946136d96137046136aa60408a01516fffffffffffffffffffffffffffffffff1690565b986136f96107188a54809c6cffffffffffffffffffffffffff968795516cffffffffffffffffffffffffff1690565b6fffffffffffffffffffffffffffffffff97889687921693169116612ea7565b9960681c1689612b68565b9081169788156138505760608761379b6137bc9361055b9b61374d6137d2988f9d8e8e7fec6f30250269069b62d7b969a6af731214d20af9d04000000000000000000000615049565b907fffffff00000000000000000000000000000000ffffffffffffffffffffffffff7cffffffffffffffffffffffffffffffff0000000000000000000000000083549260681b169116179055565b01916137b783516fffffffffffffffffffffffffffffffff1690565b612b68565b6fffffffffffffffffffffffffffffffff169052565b836137dc8461462a565b156138245761381f916137ee856150b9565b61381983827f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec76140f2565b85615151565b61518b565b61381f9150837f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec76140f2565b61503c565b6107d3565b601c5f60649281946020966040519860605260405260601b602c526f23b872dd000000000000000000000000600c525af13d1560015f51141716156138a2575f606052604052565b637939f4245f526004601cfd5b905f527fe8b606ac1e5df7657db58d297ca8f41c090fc94c5fd2d6958f043e41736e9fa660205fa2565b600181605a1c166138eb575b50505050565b5f601c6101c08296958684973603928392604051986383d9e1eb8a5260208a0152604089015e61020080880152816102208801526102408701376102240193019160601c5af115610ebc575f8080806138e5565b906129856fffffffffffffffffffffffffffffffff83168093146151b6565b5f527ff2672935fc79f5237559e2e2999dbe743bf65430894ac2b37666890e7c69e1af60205fa1565b6111c76fffffffffffffffffffffffffffffffff602083015116916cffffffffffffffffffffffffff60808201511690613e0d565b61055b6005546fffffffffffffffffffffffffffffffff81169060801c612b68565b9190600554906fffffffffffffffffffffffffffffffff918281169060801c8114613afc575f52600660205281613a3d63ffffffff60405f2054169283613a366107b98263ffffffff165f52600760205260405f2090565b9788614264565b90501693613a5d81611f8f8463ffffffff165f52600760205260405f2090565b6cffffffffffffffffffffffffff6020818351169201511614613a7e575050565b600554918083169260801c8314613afc57613acd83612985945f52600660205260405f207fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000008154169055612987565b167fffffffffffffffffffffffffffffffff0000000000000000000000000000000060055416176005556144b1565b60046040517f87274801000000000000000000000000000000000000000000000000000000008152fd5b906129856cffffffffffffffffffffffffff83168093146151b6565b905f613b4c6126e7565b5273ffffffffffffffffffffffffffffffffffffffff82165f526004602052613b9360405f206cffffffffffffffffffffffffff613b886126e7565b91541681529261462a565b613b9957565b636bc671fd5f526004601cfd5b9392959491909560c0850190613bc0825163ffffffff1690565b9763ffffffff92838a1615613d8e575b50938893613d4b93613d4484613c4961098c99613c266cffffffffffffffffffffffffff6129859e9d9916978d898d8a7fec6f30250269069b62d7b969a6af731214d20af9d040000000000000000000006151f5565b6135726119c284613c4484516cffffffffffffffffffffffffff1690565b61340b565b613c54863086615011565b613ce1613c8e856106cf613c796107b98d63ffffffff165f52600760205260405f2090565b9b63ffffffff165f52600860205260405f2090565b613ca9836119bd83546cffffffffffffffffffffffffff1690565b6cffffffffffffffffffffffffff167fffffffffffffffffffffffffffffffffffffff00000000000000000000000000825416179055565b613d12613cff826119bd8b516cffffffffffffffffffffffffff1690565b6cffffffffffffffffffffffffff168952565b613d3160a08b01916119bd83516cffffffffffffffffffffffffff1690565b6cffffffffffffffffffffffffff169052565b8a1661526f565b613d5d613d56612603565b84836149e2565b80613d7c575b50611f8f8663ffffffff165f52600760205260405f2090565b613d8890878584614264565b50613d63565b93613dfc9950613d4b93613d44899894613c4961098c9995613ded612d9e613de76129859f613dbd9051151590565b7f000000000000000000000000000000000000000000000000000000000001518090815f03020190565b42612a67565b9e8f809b6117c48883166144d7565b959950509498995050935093613bd0565b906dffffffffffffffffffffffffffff61018061055b930151169061529f565b6cffffffffffffffffffffffffff8060a08301511690608083015116818103908111610b3857613e679061ffff61016085015116906152ee565b908101809111610b3857613e91906dffffffffffffffffffffffffffff610180840151169061529f565b6fffffffffffffffffffffffffffffffff6040830151168101809111610b3857613ed4610718606061055b9401516fffffffffffffffffffffffffffffffff1690565b90612a67565b6111c790613e2d565b63499fddb15f526004601cfd5b6337f1a75f5f526004601cfd5b919060018360551c16613f0f57505050565b5f9283601c81946101c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc360191604051966303473d8d88526020880152604087015e610200908180870152806102208701526024610240870137360193019160601c5af115610ebc57565b613f83612bf8565b613f8b612fe6565b90613f968251151590565b6140e057613fb390613fa783613987565b90818082039110020190565b90613fe4613fdf613fd961315e6101808501516dffffffffffffffffffffffffffff1690565b846151cf565b613b26565b906cffffffffffffffffffffffffff821680156140db576140d2926140b361098c9261409b61401233613b42565b61403e8784337fec6f30250269069b62d7b969a6af731214d20af9d04000000000000000000000615343565b61406a8930337f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec761385a565b6140886119c2866119bd84516cffffffffffffffffffffffffff1690565b335f90815260046020526040902061342a565b6140ac873361359a5f805236155190565b86336153cf565b613d3160808401916119bd83516cffffffffffffffffffffffffff1690565b90612985612c16565b615336565b615329565b63449e5f505f526004601cfd5b60105f60449260209582956014526034526fa9059cbb00000000000000000000000082525af13d1560015f51141716156104df575f603452565b8115610cd8578051610ccb576141648230337f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec761385a565b815f52337fe8b606ac1e5df7657db58d297ca8f41c090fc94c5fd2d6958f043e41736e9fa660205fa27fec6f30250269069b62d7b969a6af731214d20af9d0400000000000000000000091600183605a1c166141bf57505050565b5f9283601c81946101c0600319360191604051966383d9e1eb88526020880152604087015e610200808601526102209080828701526004610240870137360193019160601c5af115610ebc57565b60018160591c1661421c575050565b5f91829182601c60031936016101c060405195639ecc64e68752602087015e6101e0808601526102009080828701526004610220870137360193019160601c5af115610ebc57565b9293916142b69161428285516cffffffffffffffffffffffffff1690565b9460208101956cffffffffffffffffffffffffff9485916142b089516cffffffffffffffffffffffffff1690565b9061340b565b16801561446a5761018083019788516142dc906dffffffffffffffffffffffffffff1690565b6dffffffffffffffffffffffffffff166142f5916151cf565b81811090829003020161430790613b26565b965193871693614327906dffffffffffffffffffffffffffff1685612e57565b6143309061393f565b9587815161434a906cffffffffffffffffffffffffff1690565b9061435491613476565b6cffffffffffffffffffffffffff16905260400180516143879087906fffffffffffffffffffffffffffffffff166129a8565b6fffffffffffffffffffffffffffffffff16905260a0810180516143bb9088906cffffffffffffffffffffffffff1661340b565b6cffffffffffffffffffffffffff1690526060810180516143ef9087906fffffffffffffffffffffffffffffffff166129a8565b6fffffffffffffffffffffffffffffffff16905260800180516144229087906cffffffffffffffffffffffffff1661340b565b6cffffffffffffffffffffffffff1690525f8052361551906fffffffffffffffffffffffffffffffff85169182309161445a92615011565b63ffffffff1691612985926153fd565b505f965086955050505050565b91929092604051935f526020526040527f9262dc39b47cad3a0512e4c08dda248cb345e7163058f300bc63f56bda288b6e60605fa2604052565b7fcbdf25bf6e096dd9030d89bb2ba2e3e7adb82d25a233c3ca3d92e9f098b74e555f80a2565b7f5c9a946d3041134198ebefcd814de7748def6576efd3d1b48f48193e183e89ef5f80a2565b634d7909975f526004601cfd5b5f527f9dc30b8eda31a6a144e092e5de600955523a6a925cc15cc1d1b9b4872cfa615560205fa1565b634a1c13a95f526004601cfd5b63d0242b285f526004601cfd5b63119fe6e35f526004601cfd5b9190600183605b1c1661456c57505050565b5f9283601c81946101c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc3601916040519663b1cfda0d88526020880152604087015e610200908180870152806102208701526024610240870137360193019160601c5af115610ebc57565b5f527fb848ae6b1253b6cb77e81464128ce8bd94d3d524fea54e801e0da869784dca3360205fa1565b5f527f860c0aa5520013080c2f65981705fcdea474d9f7c3daf954656ed5e65d692d1f60205fa1565b90604051916306e744445f527f0000000000000000000000005b15f94efc3a6e2c82d7db8efd8d5ba55da11feb60205260405260205f6044601c7f000000000000000000000000437e0551892c2c9b06d3ffd248fe60572e08cd1a5afa60203d141615610ebc575f5191604052565b9073ffffffffffffffffffffffffffffffffffffffff81165f52600460205260405f20916cffffffffffffffffffffffffff6146d36126e7565b93541692838152836146e55750505050565b81614715918561470b6dffffffffffffffffffffffffffff61018088970151168261529f565b9485923694613ba6565b92604051935f526020526040527fe12b220b92469ae28fb0d79de531f94161431be9f073b96b8aad3effb88be6fa60605fa26040525f8080806138e5565b63b9de88a25f526004601cfd5b91909260018360561c165f146147f65791604093916101c05f947fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc36019287519563cc4526428752602087015287860152606085015e6102208084015280610240840152604461026084013782601c610200360193019160601c5af11560403d1017610ebc5761ffff90815f5116916020511690565b5090509091565b63cf1f916f5f526004601cfd5b638ec830735f526004601cfd5b630a68e5bf5f526004601cfd5b63253ecbb95f526004601cfd5b5f527fff7b6c8be373823323d3c5d99f5d027dd409dce5db54eae511bbdd5546b7503760205fa1565b5f527f72877a153052500f5edbb2f9da96a0f45d671d4b4555fdf8628a709dc4eab43a60205fa1565b92939190915f925f9261ffff968761014088015116916101a088019363ffffffff93848651168403848111610b38576148bb91615545565b809a6101208b0151168061495d575b50508061493b575b5050614930610180612985959697980161491c6149178b613ed46149118d61490b61315e88516dffffffffffffffffffffffffffff1690565b93612a67565b8261529f565b615464565b6dffffffffffffffffffffffffffff169052565b1663ffffffff169052565b612985959697506149546149309261018092858c61542b565b979695506148d2565b6149a69298509061496d916152ee565b6149a06cffffffffffffffffffffffffff60808c015116916dffffffffffffffffffffffffffff6101808d01511661529f565b9061529f565b604089016fffffffffffffffffffffffffffffffff908181511691838301809311610b38576149d99083168093146151b6565b5295895f6148ca565b614a106cffffffffffffffffffffffffff916142b08360a0860151169184602081835116920151169061340b565b16906fffffffffffffffffffffffffffffffff90614a4b82606083015116936dffffffffffffffffffffffffffff610180840151169061529f565b8301809311610b385760400151168101809111610b385780820391110290565b80516cffffffffffffffffffffffffff1690614aad60208201926cffffffffffffffffffffffffff9182916142b086516cffffffffffffffffffffffffff1690565b168015614c27576101808501958651614ad3906dffffffffffffffffffffffffffff1690565b6dffffffffffffffffffffffffffff16614aec916151cf565b818110908290030201614afe90613b26565b9451614b1e916dffffffffffffffffffffffffffff909116908616612e57565b614b279061393f565b91848151614b41906cffffffffffffffffffffffffff1690565b90614b4b91613476565b6cffffffffffffffffffffffffff1690526040018051614b7e9083906fffffffffffffffffffffffffffffffff166129a8565b6fffffffffffffffffffffffffffffffff16905260a082018051614bb29085906cffffffffffffffffffffffffff1661340b565b6cffffffffffffffffffffffffff16905260608201908151614be3906fffffffffffffffffffffffffffffffff1690565b90614bed916129a8565b6fffffffffffffffffffffffffffffffff169052608001908151614c1d906cffffffffffffffffffffffffff1690565b90613d319161340b565b505050505050565b90819073ffffffffffffffffffffffffffffffffffffffff7f1777adabd324f814e2b0e28f6edf876dce01d7d66358c9acfe87b1b5f38338d55416918260608501528215614d0c575060405190638925ca5a825260405f60209483868601523383860152606080860152366080860152368260a08701373660c4019082601c8701915af1835f51141615610ebc5760808361055b945160051b809460e06003830282010160405282820183823e80885201925f038184015281606084015285019260a08301845260a0019101525a60408401528251905190615481565b9392505050565b606081019073ffffffffffffffffffffffffffffffffffffffff825116156130a2575f8082518051908160061b95614d5060c08884010183615481565b519160051b019360405a91015103604085015283519463f0bd9468855260c4019082601c8601915af115610ebc5752565b927f18247a393d0531b65fbd94f5e78bc5639801a4efda62ae7b43533c4442116c3a959260c09592604051958652602086015260408501526060840152608083015260a0820152a1565b61298590611f8f60c082015f614de5825163ffffffff1690565b91614e016107b98463ffffffff165f52600760205260405f2090565b946020860190614e1e82516cffffffffffffffffffffffffff1690565b90614e39611e7289516cffffffffffffffffffffffffff1690565b6cffffffffffffffffffffffffff80931610614f17575b50614ec6614e6b88516cffffffffffffffffffffffffff1690565b92614eb3614e8682516cffffffffffffffffffffffffff1690565b60408b015163ffffffff8a16966fffffffffffffffffffffffffffffffff90911691861690861687614477565b516cffffffffffffffffffffffffff1690565b90614ee1611e7289516cffffffffffffffffffffffffff1690565b9116108314614f095750614ef4836154b9565b5263ffffffff165f52600760205260405f2090565b614f12906144b1565b614ef4565b614f29614f22612603565b828a6149e2565b8681614f37575b5050614e50565b614f41928a614264565b86614f30565b5f526020527f9385f9ff65bcd2fb81cece54b27d4ec7376795fc4dcff686e370e347b0ed86c060405fa1565b9091939293600182605c1c16614f8b575b5050505050565b6101c05f959486957fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc3601936040519663a018f90e885233602089015260408801526060870152608086015260a085015e610260808401528061028084015260446102a084013782601c610240360193019160601c5af115610ebc575f80808080614f84565b90915f527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60205fa3565b63186334fe5f526004601cfd5b9091600182605d1c1661505d575050505050565b601c5f9594869592836101c08895360393849360405199632970403d8b5260208b015260408a0152606089015e61022080880152816102408801526102608701376102440193019160601c5af115610ebc575f80808080614f84565b906040519163a1054f6b5f527f0000000000000000000000005b15f94efc3a6e2c82d7db8efd8d5ba55da11feb6020526040527f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec760605260205f6064601c827f000000000000000000000000437e0551892c2c9b06d3ffd248fe60572e08cd1a5af160203d141615610ebc575f51916040525f606052565b91929092604051935f526020526040527f0d0843a0fcb8b83f625aafb6e42f234ac48c6728b207d52d97cfa8fbd34d498f60605fa2604052565b90915f527fd6cddb3d69146e96ebc2c87b1b3dd0b20ee2d3b0eadf134e011afb434a3e56e660205fa3565b156151bd57565b634e487b715f5260116020526024601cfd5b8160011c906b033b2e3c9fd0803ce8000000908183190481118415176151bd5702010490565b919394909294600183605e1c1661520e57505050505050565b5f958695836101c0601c94899636039485946040519a633521cccc8c5260208c015260408b015260608a0152608089015e61024080880152816102608801526102808701376102640193019160601c5af115610ebc575f8080808080614c27565b919290925f526020527fecc966b282a372469fa4d3e497c2ac17983c3eaed03f3f17c9acf4b15591663e60405fa3565b817ffffffffffffffffffffffffffffffffffffffffffe6268e1b017bfe18bffffff04811115821517156151bd576b033b2e3c9fd0803ce800000091026b019d971e4fe8401e74000000010490565b817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec7704811115821517156151bd576127109102611388010490565b6322d7c0435f526004601cfd5b63e4aa50555f526004601cfd5b929192600181605f1c166153575750505050565b5f601c81956101c083967fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc36019260405197635aeb713f895260208901526040880152606087015e610220908180870152806102408701526024610260870137360193019160601c5af115610ebc575f8080806138e5565b91905f526020527f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a1560405fa2565b91905f526020527f5272034725119f19d7236de4129fdb5093f0dcb80282ca5edbd587df91d2bd8960405fa2565b909392935f9463ffffffff6101a0840151168203918211610b385761544f92615577565b9081615459575050565b61055b929350615545565b906129856dffffffffffffffffffffffffffff83168093146151b6565b9190825190818152602080809501918181019360051b0101915b8281106154a9575050509050565b815154815290840190840161549b565b6155039060055460801c90815f52600660205263ffffffff60405f2091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000825416179055612987565b6fffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffff000000000000000000000000000000006005549260801b16911617600555565b69152d02c7e14af68000008082029180828404036151bd57830202918183041490151715610b38576301e13380900490565b90610100820163ffffffff9060e0828251169401516155b7576155a5858503868611029283168093146151b6565b52808203911102818082039110020190565b848493940191828411610b38576155d29083168093146151b6565b528082039111028082039111029056fea164736f6c6343000819000a
Deployed Bytecode Sourcemap
290:10719:25:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;;;;;;:::o;:::-;;;;;;;;;-1:-1:-1;;290:10719:25;;;;;;;;;;:::i;:::-;1258:92:2;;:::i;:::-;7999:8:26;8013:207;;;;290:10719:25;;;;1227:4;1210:22;;1200:5;;290:10719;1191:14;257:36:12;1186:87:25;;4240:1295:17;-1:-1:-1;4240:1295:17;1227:4:25;290:10719;4240:1295:17;290:10719:25;4240:1295:17;;;;;;;;;;;;;-1:-1:-1;4240:1295:17;;8013:207:26;290:10719:25;8013:207:26;;4240:1295:17;;;;;;;;;;-1:-1:-1;4240:1295:17;;;;;;;1315:1:2;;:::i;:::-;290:10719:25;4240:1295:17;;-1:-1:-1;4240:1295:17;290:10719:25;4240:1295:17;;1186:87:25;2886:63:18;-1:-1:-1;2886:63:18;290:10719:25;2886:63:18;;8013:207:26;;-1:-1:-1;8013:207:26;290:10719:25;8013:207:26;;290:10719:25;;;;;-1:-1:-1;;290:10719:25;;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::o;:::-;-1:-1:-1;;290:10719:25;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;:::o;:::-;;;;;;;;:::i;:::-;1686:67:29;290:10719:25;;:::i;:::-;;-1:-1:-1;290:10719:25;;;;;;;-1:-1:-1;290:10719:25;;1473:67:2;;:::i;:::-;290:10719:25;-1:-1:-1;290:10719:25;1686:31:29;290:10719:25;;;-1:-1:-1;290:10719:25;;;;;;;;;;;;;1686:67:29;290:10719:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;290:10719:25;;;;;3313:492:26;290:10719:25;3313:492:26;290:10719:25;3313:492:26;;3244:18;3313:492;;3288:18;3313:492;;;290:10719:25;3313:492:26;290:10719:25;;;;;;;:::i;:::-;1473:67:2;;;:::i;:::-;290:10719:25;;;;;2042:15:29;;2032:25;;;2028:80;;290:10719:25;2420:55:29;2724:106;2182:24;290:10719:25;2182:24:29;2843:42;2182:24;;;:::i;:::-;2212:28;;;290:10719:25;;:::i;:::-;-1:-1:-1;290:10719:25;2250:28:29;290:10719:25;;2420:39:29;2288:20;2246:129;290:10719:25;;;;2420:31:29;290:10719:25;;;;;;;2420:39:29;290:10719:25;;;;;;;;;;;;2420:55:29;290:10719:25;:::i;:::-;2658:32:29;2625:65;290:10719:25;2658:32:29;;;290:10719:25;;;;;;;;;;2625:65:29;2732:26;290:10719:25;;2724:35:29;290:10719:25;2732:26:29;;;290:10719:25;;;;;2724:35:29;290:10719:25;;;;;;;;;;;;;2724:106:29;;:::i;:::-;2843:42;:::i;:::-;2732:26;290:10719:25;;;;;;;;;;;;;;;;2246:129:29;2337:31;2420:39;290:10719:25;2337:31:29;;290:10719:25;;;;2337:23:29;290:10719:25;;;;;;;2337:31:29;290:10719:25;:::i;:::-;2246:129:29;290:10719:25;;;;2420:31:29;290:10719:25;;;;;;;2028:80:29;3423:63:18;-1:-1:-1;3423:63:18;290:10719:25;3423:63:18;;290:10719:25;;;;;-1:-1:-1;;290:10719:25;;;;;9929:1141:33;290:10719:25;;;;;:::i;:::-;1258:92:2;;:::i;:::-;1538:6:28;11426:29:33;;:::i;:::-;290:10719:25;;;1517:10:28;;1538:6;:::i;:::-;9929:1141:33;:::i;:::-;-1:-1:-1;2478:125:2;;290:10719:25;;;1558:4:28;290:10719:25;;;;;;;;-1:-1:-1;;290:10719:25;;;;;;;:::i;:::-;;11943:43:26;290:10719:25;;:::i;:::-;11943:43:26;290:10719:25;;;;;-1:-1:-1;;290:10719:25;;;;;;;:::i;:::-;;1473:67:2;;:::i;:::-;12386:43:26;290:10719:25;;:::i;:::-;12386:43:26;;;290:10719:25;;;;;-1:-1:-1;;290:10719:25;;;;;1473:67:2;;:::i;:::-;290:10719:25;;11507:75:26;290:10719:25;;:::i;:::-;11507:75:26;;;290:10719:25;;11507:75:26;290:10719:25;;;;;;;;;;-1:-1:-1;;290:10719:25;;;;;;;1539:25:27;290:10719:25;;;;;;;;;;;;;;;-1:-1:-1;;290:10719:25;;;;;1473:67:2;;:::i;:::-;290:10719:25;11675:68:26;290:10719:25;;:::i;:::-;11675:68:26;;;:::i;290:10719:25:-;;;;;-1:-1:-1;;290:10719:25;;;;;1473:67:2;;:::i;:::-;290:10719:25;1641:46:20;290:10719:25;;:::i;:::-;1663:23:20;;290:10719:25;1663:23:20;;;290:10719:25;;1641:46:20;;:::i;290:10719:25:-;;;;;-1:-1:-1;;290:10719:25;;;;;1258:92:2;;:::i;:::-;9929:1141:33;11426:29;;:::i;:::-;912:5:25;876:18;;:::i;:::-;912:5;:::i;9929:1141:33:-;290:10719:25;2478:125:2;;290:10719:25;;;;;;-1:-1:-1;;290:10719:25;;;;;;;;;;;:::i;:::-;1473:67:2;;:::i;:::-;290:10719:25;-1:-1:-1;290:10719:25;;;;;;;-1:-1:-1;290:10719:25;;;;;;;;;;;;;;-1:-1:-1;;290:10719:25;;;;;;13764:111:26;290:10719:25;;:::i;:::-;13854:13:26;;;;:::i;:::-;13764:111;;:::i;:::-;290:10719:25;;;;;;;;;;;;;-1:-1:-1;;290:10719:25;;;;;;;;;;:::i;:::-;;;;;;:::i;:::-;;;1258:92:2;;:::i;:::-;11426:29:33;;:::i;:::-;290:10719:25;;;;-1:-1:-1;290:10719:25;1936:9:28;290:10719:25;;1936:27:28;290:10719:25;-1:-1:-1;290:10719:25;1952:10:28;290:10719:25;;;;;;;;;;;1936:27:28;290:10719:25;2027:17:28;2016:28;;2012:136;;290:10719:25;2154:33:28;;;;9929:1141:33;2154:33:28;;:::i;9929:1141:33:-;-1:-1:-1;2478:125:2;;290:10719:25;;2201:4:28;290:10719:25;;;;;2012:136:28;290:10719:25;;;;;;;;;;9929:1141:33;1952:10:28;2128:12;2154:33;1952:10;;2128:12;;:::i;:::-;2012:136;;;;;;290:10719:25;;:::i;:::-;;;;;-1:-1:-1;;290:10719:25;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;290:10719:25;;;;;;;;;2185:31:26;290:10719:25;;;;;;;;;9929:1141:33;290:10719:25;;;:::i;:::-;1258:92:2;;;;:::i;:::-;7421:5:29;7273:103;11426:29:33;;:::i;:::-;7104:18:29;;;:::i;:::-;27523:103:26;7365:4:29;-1:-1:-1;27523:103:26;290:10719:25;27523:103:26;;7273::29;;;:::i;:::-;7421:5;;:::i;9929:1141:33:-;-1:-1:-1;2478:125:2;;290:10719:25;;;;;;;;;;;-1:-1:-1;;290:10719:25;;;;;;;1258:92:2;;:::i;:::-;11426:29:33;;:::i;:::-;6358:11:25;;6354:41;;6452:6;6445:4;;6425:10;6402:5;6452:6;:::i;:::-;2924:133:19;-1:-1:-1;2924:133:19;6425:10:25;2924:133:19;290:10719:25;-1:-1:-1;2924:133:19;6534:18:25;;:::i;:::-;290:10719;;;6558:48;;9929:1141:33;27523:103:26;6679:22:25;6721:5;27523:103:26;6696:4:25;-1:-1:-1;27523:103:26;290:10719:25;;27523:103:26;;6650:5:25;;6679:22;:::i;6558:48::-;5469:63:18;-1:-1:-1;5469:63:18;290:10719:25;5469:63:18;;6354:41:25;4767:63:18;-1:-1:-1;4767:63:18;290:10719:25;4767:63:18;;290:10719:25;;;;;-1:-1:-1;;290:10719:25;;;;;;;;;2265:30:26;290:10719:25;;;;;;;;;-1:-1:-1;;290:10719:25;;;;;;;12077:42:33;290:10719:25;;;;;;;;;;;;;-1:-1:-1;;290:10719:25;;;;;;;7999:8:26;8013:207;;;;1258:92:2;;:::i;:::-;11426:29:33;;:::i;:::-;4612:18:27;;:::i;:::-;290:10719:25;;4636:57:27;;4700:5;5656:63:34;;1414:2;5656:63;;26635:1412;;290:10719:25;4778:27:27;;4823:5;4862:15;4778:27;4755:50;4778:27;9929:1141:33;4778:27:27;;:::i;:::-;290:10719:25;;;4755:20:27;;290:10719:25;;4823:5:27;4862:15;:::i;9929:1141:33:-;1315:1:2;;:::i;26635:1412:34:-;-1:-1:-1;290:10719:25;;26678:1363:34;290:10719:25;26678:1363:34;;;;;;;290:10719:25;26678:1363:34;;;290:10719:25;26678:1363:34;;;;;;;;;;;;;;;;;;;;;;;;;;290:10719:25;26678:1363:34;;;6256:47;;;26678:1363;;;;;26635:1412;;;26678:1363;;-1:-1:-1;26678:1363:34;;;-1:-1:-1;26678:1363:34;4636:57:27;480:63:18;-1:-1:-1;480:63:18;290:10719:25;480:63:18;;290:10719:25;;;;;-1:-1:-1;;290:10719:25;;;;;;;;;1738:37:26;290:10719:25;;;;;;;;;-1:-1:-1;;290:10719:25;;;;;;;;1870:40:26;290:10719:25;;;;;;;;-1:-1:-1;;290:10719:25;;;;;;;;;;:::i;:::-;;3020:15:33;290:10719:25;3006:10:33;:29;3002:82;;290:10719:25;12077:42:33;;;11890:47;;-1:-1:-1;416:167:32;290:10719:25;416:167:32;;;-1:-1:-1;416:167:32;290:10719:25;3002:82:33;109:63:31;-1:-1:-1;109:63:31;290:10719:25;109:63:31;;290:10719:25;;;;;-1:-1:-1;;290:10719:25;;;;;;;;1975:44:26;290:10719:25;;;;;;;;-1:-1:-1;;290:10719:25;;;;;;;;;3938:15:26;290:10719:25;;;;;;;;;-1:-1:-1;;290:10719:25;;;;;;1109:22:27;290:10719:25;;:::i;:::-;1109:22:27;;;:::i;290:10719:25:-;;;;;-1:-1:-1;;290:10719:25;;;;;;1175:115:26;;;;;;;;;;;290:10719:25;;;;;-1:-1:-1;;290:10719:25;;;;;;;1258:92:2;;:::i;:::-;11426:29:33;;:::i;:::-;10319:15:29;;;10315:146;;;;290:10719:25;10494:18:29;;:::i;:::-;290:10719:25;;;;;;;;;10518:48:29;;10682:78;;290:10719:25;10892:13:29;:88;:13;;:::i;:::-;:88;10915:64;290:10719:25;10915:36:29;;;290:10719:25;;;;;;;10954:25:29;;290:10719:25;;;10915:64:29;;:::i;10892:88::-;;;:::i;:::-;11086:38;11060:65;;11086:38;;:::i;11060:65::-;290:10719:25;;2458:93:21;;;;1275:5;;2458:93;;1188:104;;11060:65:29;-1:-1:-1;11231:344:29;;11238:3;;;;:::i;:::-;:16;;:42;;;11231:344;11238:42;;;11386:56;;11521:47;11386:56;;;:::i;:::-;1682:132:21;;;;;;1604:214;;11521:47:29;11231:344;;11238:42;9929:1141:33;11238:42:29;11592:5;11238:42;11592:5;:::i;11238:42::-;11258:22;;;;11238:42;;10682:78;10737:22;;;;10754:4;27523:103:26;;;;;27411:219;;10737:22:29;10703:5;;10737:22;:::i;:::-;10682:78;;;10518:48;;:::i;10315:146::-;10394:11;10387:4;;10367:10;10344:5;10394:11;:::i;:::-;10442;10367:10;;10442:11;:::i;:::-;10315:146;;290:10719:25;;;;;-1:-1:-1;;290:10719:25;;;;;1473:67:2;;:::i;:::-;290:10719:25;;10500:67:26;290:10719:25;;:::i;:::-;;;;;-1:-1:-1;;290:10719:25;;;;;;;1258:92:2;;:::i;:::-;11426:29:33;;:::i;:::-;5320:18:29;;:::i;:::-;2460:17:20;2446:32;290:10719:25;2460:17:20;;;290:10719:25;;2446:32:20;;:::i;:::-;1884:21:22;290:10719:25;;;1884:21:22;;;;:::i;:::-;5415:17:29;;5411:46;;290:10719:25;5527:10:29;9929:1141:33;5527:10:29;5558:90;5527:10;5515:23;5527:10;5515:23;:::i;:::-;27523:103:26;5642:4:29;-1:-1:-1;27523:103:26;290:10719:25;27523:103:26;;5527:10:29;;5558:90;;:::i;:::-;9929:1141:33;;:::i;:::-;-1:-1:-1;2478:125:2;;290:10719:25;;;;;;;;;;;;;;;;5411:46:29;3861:63:18;-1:-1:-1;3861:63:18;290:10719:25;3861:63:18;;290:10719:25;;;;;-1:-1:-1;;290:10719:25;;;;;;758:121:28;290:10719:25;;;;;:::i;:::-;1473:67:2;;:::i;:::-;290:10719:25;;;:::i;:::-;;;;;-1:-1:-1;290:10719:25;;;;;;-1:-1:-1;290:10719:25;;;758:121:28;;:::i;290:10719:25:-;;;;;-1:-1:-1;;290:10719:25;;;;;1258:92:2;;:::i;:::-;11426:29:33;;:::i;:::-;5880:18:29;;:::i;:::-;5968:10;5956:23;5968:10;5956:23;:::i;:::-;290:10719:25;;;;;6040:17:29;;6036:46;;290:10719:25;2220:17:20;;6171:156:29;2220:17:20;2206:32;290:10719:25;2220:17:20;9929:1141:33;2220:17:20;;290:10719:25;;2206:32:20;;:::i;:::-;27523:103:26;290:10719:25;;27523:103:26;290:10719:25;27523:103:26;;5968:10:29;;6171:156;;:::i;290:10719:25:-;;;;;-1:-1:-1;;290:10719:25;;;;;1473:67:2;;:::i;:::-;290:10719:25;10209:75:26;290:10719:25;;:::i;:::-;10209:75:26;;;:::i;290:10719:25:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;290:10719:25;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;:::i;:::-;1258:92:2;;;;;:::i;:::-;11426:29:33;;:::i;:::-;7667:42:29;;;;7663:75;;290:10719:25;;;;:::i;:::-;;:::i;:::-;;;;;;;;;:::i;:::-;;;;;;;7827:18:29;;:::i;:::-;7857:13;-1:-1:-1;7872:27:29;;;;;;290:10719:25;8155:5:29;9929:1141:33;8155:5:29;;;;:::i;9929:1141:33:-;1315:1:2;;:::i;:::-;290:10719:25;;;;;;;:::i;7901:3:29:-;8054:19;8028:76;8054:19;290:10719:25;8054:19:29;;;;:::i;:::-;290:10719:25;;;;:::i;:::-;8075:11:29;;;;;:::i;:::-;290:10719:25;;;;:::i;:::-;;8028:76:29;;;:::i;:::-;8015:89;;;;:::i;:::-;290:10719:25;;7857:13:29;;7663:75;7297:63:18;-1:-1:-1;7297:63:18;290:10719:25;7297:63:18;;290:10719:25;;;;;-1:-1:-1;;290:10719:25;;;;;1473:67:2;;:::i;:::-;290:10719:25;;;:::i;:::-;11248:13:26;;4375:25:20;11248:13:26;;:::i;:::-;4375:25:20;;:::i;:::-;290:10719:25;;;1682:132:21;;;;;;;290:10719:25;;;;;;;;-1:-1:-1;;290:10719:25;;;;;;;;;1526:33:26;290:10719:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;290:10719:25;;;;;1473:67:2;;:::i;:::-;858:15:29;290:10719:25;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;:::i;:::-;;;;;;;;1465:7:14;;;;;;290:10719:25;;;;;;;:::i;1474:3:14:-;1509:14;1487:37;1500:24;;1509:14;290:10719:25;1509:14:14;;;:::i;:::-;290:10719:25;;1500:8:14;290:10719:25;;;;;;;1500:24:14;290:10719:25;;;;;1500:24:14;1487:37;;;;:::i;:::-;290:10719:25;;;;;;1487:37:14;290:10719:25;1450:13:14;;290:10719:25;;;;;-1:-1:-1;;290:10719:25;;;;;2660:496:26;290:10719:25;2660:496:26;290:10719:25;2660:496:26;;2585:20;2660:496;;2633:20;2660:496;;;290:10719:25;2660:496:26;290:10719:25;;;;;-1:-1:-1;;290:10719:25;;;;;;;;2081:45:26;290:10719:25;;;;;;;;-1:-1:-1;;290:10719:25;;;;;;;;;;:::i;:::-;;;1258:92:2;;;:::i;:::-;11426:29:33;;:::i;:::-;2552:18:28;;;:::i;:::-;2460:17:20;2446:32;290:10719:25;2460:17:20;;;290:10719:25;;2446:32:20;;:::i;:::-;290:10719:25;;;1884:21:22;290:10719:25;;;1884:21:22;;;;:::i;:::-;2647:17:28;;2643:50;;1711:10;290:10719:25;1711:10:28;290:10719:25;3080:6:28;1711:10;2700:65;9929:1141:33;1711:10:28;3044:5;1711:10;;;2700:5;:65;:::i;:::-;2801:17;1711:10;2801:17;:::i;:::-;290:10719:25;;2824:41:28;290:10719:25;;;;;2824:41:28;:::i;:::-;290:10719:25;;;1711:10:28;290:10719:25;;;;2871:9:28;290:10719:25;;;;;2871:15:28;290:10719:25;;;;;;;;;;;;;;2955:39:28;;2934:15;;;:::i;:::-;290:10719:25;;;;;;;;;2955:39:28;:::i;:::-;290:10719:25;;;;;2955:39:28;3000:13;;290:10719:25;;;;2871:9:28;290:10719:25;;;;;;;3000:13:28;290:10719:25;:::i;3044:5:28:-;1711:10;3080:6;:::i;2643:50::-;4308:63:18;-1:-1:-1;4308:63:18;290:10719:25;4308:63:18;;290:10719:25;;;;;;;;;;;:::o;:::-;;;;;;;;;;;:::o;:::-;;;;;-1:-1:-1;;290:10719:25;;;;;;;:::i;:::-;1258:92:2;;:::i;:::-;11426:29:33;;:::i;:::-;290:10719:25;6667:7:27;290:10719:25;6653:10:27;:21;6649:46;;290:10719:25;;;6724:5:27;6705:24;;6701:57;;6791:18;;:::i;:::-;290:10719:25;;6815:60:27;;6905:21;7112:5;6905:21;9929:1141:33;6905:21:27;;;;290:10719:25;6885:41:27;290:10719:25;;;;;;;;;;;;6885:41:27;;;6881:214;;290:10719:25;7112:5:27;;;;;:::i;6881:214::-;6936:5;7048:40;6936:5;:51;7048:40;6936:5;6995:40;6936:5;;:51;:::i;:::-;290:10719:25;;;;;;6995:40:27;290:10719:25;;;;;;;;;;;;;;;;7048:40:27;;;;6881:214;;;;;;6815:60;;:::i;6701:57::-;;:::i;6649:46::-;7960:63:18;-1:-1:-1;7960:63:18;290:10719:25;7960:63:18;;290:10719:25;;;;;-1:-1:-1;;290:10719:25;;;;;1473:67:2;;:::i;:::-;290:10719:25;;13266:73:26;290:10719:25;;:::i;:::-;;;;;-1:-1:-1;;290:10719:25;;;;;;11426:29:33;;:::i;:::-;9929:1141;1837:7:25;290:10719;;1837:7;:::i;290:10719::-;;;;;-1:-1:-1;;290:10719:25;;;;;;;11426:29:33;;:::i;:::-;1837:7:25;;;;:::i;:::-;3848:22;3844:54;;9929:1141:33;;;:::i;3844:54:25:-;219:63:18;-1:-1:-1;219:63:18;290:10719:25;219:63:18;;290:10719:25;;;;;-1:-1:-1;;290:10719:25;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;290:10719:25;;;;;;;;;1653:32:26;290:10719:25;;;;;;;;;-1:-1:-1;;290:10719:25;;;;;7999:8:26;8013:207;;;;;1258:92:2;;:::i;:::-;11426:29:33;;:::i;:::-;7183:18:25;;:::i;:::-;290:10719;;;;;;;;;7208:48;;8212:88;7287:13;;;:::i;:::-;7327:18;;;;:::i;:::-;7355:26;;;;;;;7463;;;;7539:30;7463:26;;:::i;:::-;7497:34;;;;;:::i;:::-;7539:30;:::i;:::-;7828:5;7808;;7828;:::i;:::-;290:10719;7840:24;;;290:10719;7891:4;290:10719;;;7901:22;;;290:10719;;8085:20;;;290:10719;8212:88;8235:64;290:10719;8235:36;;;290:10719;;;;;8212:88;8449:29;;;290:10719;;;;;;;;;8445:1282;;7351:452;9754:38;;;;9733:59;9754:38;;:::i;9733:59::-;9803:9;290:10719;9798:304;9814:14;;;;;;10112:30;;;290:10719;;10112:30;;;290:10719;;;;;;;10108:97;;10223:5;9929:1141:33;10223:5:25;;:::i;:::-;10253:15;;;:::i;10108:97::-;;:::i;9830:3::-;10053:42;9939:56;;7891:4;9939:56;;;:::i;10053:42::-;9830:3;290:10719;9803:9;;;8445:1282;290:10719;8577:31;;290:10719;;;;2337:23:29;290:10719:25;;;;;;;;8620:24;;;290:10719;;;;;8620:50;290:10719;;;;;;;;;;;;8620:50;290:10719;;;;8620:50;8616:331;;8445:1282;290:10719;;9113:154;290:10719;;;;;;;;8274:25;290:10719;;;;;;;;;;;;;;;;9233:26;;290:10719;;;;;;;;;;;9113:154;;:::i;:::-;9275:34;;;:::i;:::-;9557:15;9547:25;9543:178;;8445:1282;;;;9543:178;9623:38;9603:10;9671:41;9603:10;;:::i;:::-;290:10719;;;9623:38;:::i;9671:41::-;9543:178;;;;;8616:331;8717:120;290:10719;8717:120;;;;;;8847:42;8717:120;9113:154;8717:120;;:::i;:::-;290:10719;;;8847:42;;:::i;:::-;8899:31;290:10719;8899:31;;;290:10719;;;;2337:23:29;290:10719:25;;;;;;;8899:31;290:10719;:::i;:::-;8616:331;;;;;;;7351:452;7586:26;;;;7582:221;;7351:452;;;;;7582:221;7643:26;7750:10;7643:26;7769:27;7643:26;;;:::i;:::-;7721:5;;;7750:10;:::i;7769:27::-;7582:221;;;;7208:48;;:::i;290:10719::-;;;;;-1:-1:-1;;290:10719:25;;;;;;;7999:8:26;8013:207;;;;;1258:92:2;;:::i;:::-;11426:29:33;;:::i;:::-;28001:315:26;;-1:-1:-1;28001:315:26;290:10719:25;28001:315:26;290:10719:25;-1:-1:-1;28001:315:26;;27986:8;28001:315;;290:10719:25;28001:315:26;;;;;;-1:-1:-1;28001:315:26;5053:84:25;;5170:18;;:::i;:::-;290:10719;;5194:51;;5273:37;5296:13;;:::i;:::-;5273:37;;:::i;:::-;5320:19;;5316:53;;5414:5;5506;5414;5437;5530:6;5414:5;9929:1141:33;5414:5:25;;5437;:::i;:::-;5481:6;8013:207:26;;5450:5:25;5481:6;:::i;5506:5::-;5530:6;:::i;5316:53::-;;:::i;5194:51::-;;:::i;5053:84::-;;:::i;290:10719::-;;;;;-1:-1:-1;;290:10719:25;;;;;1258:92:2;;:::i;:::-;11426:29:33;;:::i;:::-;4083:18:25;;:::i;:::-;4111:25;;;;290:10719;;;;;;;4111:30;4107:58;;4199:45;4230:13;;:::i;:::-;4199:45;;:::i;:::-;290:10719;;;4254:21;;;4250:72;;290:10719;;4329:45;4448:5;290:10719;4460:36;290:10719;9929:1141:33;290:10719:25;;;4329:45;:::i;:::-;290:10719;;;4380:50;4399:12;;4380:5;:50;:::i;4448:5::-;4460:36;:::i;4250:72::-;3171:63:18;290:10719:25;3171:63:18;290:10719:25;3171:63:18;;4107:58:25;4077:63:18;290:10719:25;4077:63:18;290:10719:25;4077:63:18;;290:10719:25;;;;;-1:-1:-1;;290:10719:25;;;;;;;;1298:34:26;290:10719:25;;;;;;;;-1:-1:-1;;290:10719:25;;;;;;1646:23:27;290:10719:25;;;;;;;;;;;;;;;;-1:-1:-1;;290:10719:25;;;;;;1534:1:2;290:10719:25;;;;;:::i;:::-;;;:::i;:::-;1473:67:2;;:::i;:::-;1534:1;:::i;:::-;290:10719:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;290:10719:25;;;;;;;;;;:::i;:::-;1258:92:2;;:::i;:::-;11426:29:33;;:::i;:::-;3751::27;;;:::i;:::-;3750:30;3746:58;;3837:18;;:::i;:::-;3861:5;;5656:63:34;;1361:2;5656:63;;35140:1328;;290:10719:25;3932:14:27;;;3965:5;3932:14;9929:1141:33;3932:14:27;;:::i;35140:1328:34:-;-1:-1:-1;290:10719:25;;35179:1283:34;290:10719:25;35179:1283:34;;;;;;;290:10719:25;35179:1283:34;;;290:10719:25;35179:1283:34;;;;;;;;;;;;;;;;;;;;;;;;;;290:10719:25;35179:1283:34;;;6256:47;;;35179:1283;;;;;35140:1328;;;3746:58:27;1638:63:18;-1:-1:-1;1638:63:18;290:10719:25;1638:63:18;;290:10719:25;;;;;-1:-1:-1;;290:10719:25;;;;;;506:64:28;290:10719:25;;;;;:::i;:::-;;;;;;;;:::i;:::-;;-1:-1:-1;290:10719:25;506:64:28;290:10719:25;;;-1:-1:-1;290:10719:25;;;;;;;;;;;;;506:64:28;290:10719:25;;;;;;;;;;;;-1:-1:-1;;290:10719:25;;;;;;;:::i;:::-;;;:::i;:::-;7999:8:26;;8013:207;;;;1258:92:2;;:::i;:::-;11426:29:33;;:::i;:::-;5463:18:27;;;:::i;:::-;290:10719:25;;5487:52:27;;5652:115;5580:22;;;;290:10719:25;5546:56:27;290:10719:25;;;;;;;5546:56:27;5652:5;;:115;:::i;:::-;290:10719:25;;;;;;106:3:21;;5778:25:27;;;;5774:80;;290:10719:25;;5864:23:27;;;5860:76;;5946:44;;;;;5942:179;;290:10719:25;6174:46:27;6126:42;;;290:10719:25;;;;;;6126:42:27;290:10719:25;;6174:24:27;;;290:10719:25;;6174:46:27;6226:178;;290:10719:25;6422:5:27;6434:51;6491:47;6422:5;;9929:1141:33;6422:5:27;;:::i;:::-;6434:51;:::i;:::-;6491:47;:::i;6226:178::-;6287:25;;;;:::i;:::-;6315:13;;:::i;:::-;-1:-1:-1;6283:115:27;;6226:178;;;6283:115;;:::i;5942:179::-;6004:25;;;:::i;:::-;6032:13;;:::i;:::-;-1:-1:-1;6000:115:27;5942:179;6000:115;;:::i;5860:76::-;;:::i;5774:80::-;;:::i;5487:52::-;;:::i;290:10719:25:-;;;;;-1:-1:-1;;290:10719:25;;;;;;;;;1420:33:26;290:10719:25;;;;10633:101:26;5825:583:17;-1:-1:-1;5825:583:17;10723:4:26;5825:583:17;;;-1:-1:-1;5825:583:17;;10699:5:26;5825:583:17;;;;;;;;;-1:-1:-1;5825:583:17;10633:101:26;:::o;5825:583:17:-;;-1:-1:-1;5825:583:17;;;;290:10719:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;:::i;:::-;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;:::i;:::-;;;;;;;;;;;;;;;:::o;:::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;:::i;:::-;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;:::o;:::-;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;:::i;:::-;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;:::o;905:563:29:-;;;1101:24;;:::i;:::-;290:10719:25;;;;;;1170:10:29;;;;290:10719:25;;1136:28:29;;147:37:12;1131:86:29;;290:10719:25;1179:1:29;290:10719:25;1256:23:29;290:10719:25;;;1436:27:29;290:10719:25;1179:1:29;290:10719:25;;;;;;;;;;;;;;1349:24:29;;290:10719:25;1436:27:29;290:10719:25;;;1407:26:29;;290:10719:25;905:563:29:o;1131:86::-;1191:19;-1:-1:-1;;1191:19:29:o;1745:595:2:-;1791:545;;;;;;;;1745:595::o;1791:545::-;;;;;;;2430:177;2478:125;;;2430:177::o;2748:351::-;2799:296;;;;2748:351::o;17372:2003:26:-;290:10719:25;;:::i;:::-;;;;;:::i;:::-;;;:::i;:::-;17626:30:26;;;4527:29:20;290:10719:25;4410:294:20;4527:29;290:10719:25;;4562:138:20;;;;;;;4410:294;;17626:30:26;17622:821;;17372:2003;18453:34;;;290:10719:25;;;18491:15:26;290:10719:25;;;18453:53:26;18449:165;;17372:2003;18762:29;;;290:10719:25;;;;;;18758:613:26;;17372:2003;:::o;18758:613::-;18806:50;;;;290:10719:25;18879:43:26;18806:50;290:10719:25;;;;2337:23:29;290:10719:25;;;;;;;;18934:31:26;290:10719:25;18934:31:26;;;290:10719:25;;;;;;;18934:64:26;290:10719:25;;;;;;;18934:64:26;290:10719:25;;18934:64:26;18930:435;;17372:2003::o;18930:435::-;19125:98;19200:13;;:::i;:::-;19125:98;;;:::i;:::-;19237:22;19233:124;;18930:435;290:10719:25:o;19233:124:26:-;19327:18;;;;;:::i;18449:165::-;18516:91;18491:15;18567:22;18547:18;18516:91;;:::i;:::-;18449:165;;;;;17622:821;17687:29;;;;;;290:10719:25;;;;;;;;17884:34:26;17862:56;290:10719:25;17884:34:26;;;290:10719:25;;;;;;;;;;17862:56:26;290:10719:25;;;17862:56:26;;;17858:215;;17622:821;18096:43;290:10719:25;;18096:43:26;;290:10719:25;;;;2337:23:29;290:10719:25;;;;;;;;18247:13:26;18176:92;18247:13;;:::i;:::-;18176:92;;;:::i;:::-;18280:22;18276:120;;17622:821;290:10719:25;;17622:821:26;;18276:120;18368:18;;;;;:::i;:::-;18276:120;;;17858:215;17930:134;18002:22;;17972:18;17930:134;;:::i;:::-;17858:215;;;;5869:451:21;;170:4;5958:358;;;;;;;;;;;;;;;;5869:451;:::o;5958:358::-;;;;;;;5869:451;5958:358;;;;;;;;;;;;;;;5869:451;:::o;5446:182:33:-;290:10719:25;;;;;;;;;;;;;;;6381:28:33;290:10719:25;;;;;;;;;;;11212:60:33;290:10719:25;;;;11212:60:33;290:10719:25;;;;11212:60:33;;;;6381:28;;:::i;2214:180:28:-;;;290:10719:25;;;-1:-1:-1;290:10719:25;2306:9:28;290:10719:25;;;2306:28:28;290:10719:25;;-1:-1:-1;290:10719:25;;;;;;;;;;;;;2306:28:28;290:10719:25;-1:-1:-1;744:173:19;;290:10719:25;-1:-1:-1;744:173:19;2214:180:28:o;4708:227:20:-;4805:46;290:10719:25;4827:23:20;;;290:10719:25;;4805:46:20;;:::i;:::-;290:10719:25;;4860:36:20;;;;;290:10719:25;;;;;;;;;4905:25:20;;290:10719:25;;;;;;;;;4708:227:20;:::o;14622:2316:26:-;290:10719:25;;:::i;:::-;;;;:::i;:::-;14763:30:26;;;4527:29:20;290:10719:25;4410:294:20;4527:29;290:10719:25;;4562:138:20;;;;;;;4410:294;;14763:30:26;14759:808;;14622:2316;15610:34;;;290:10719:25;;;;;15735:15:26;:47;;;15731:450;;14622:2316;-1:-1:-1;16329:29:26;;;290:10719:25;;;;;;16325:609:26;;14622:2316;:::o;16325:609::-;290:10719:25;16457:31:26;;290:10719:25;;;;2337:23:29;290:10719:25;;;;;;;;16500:24:26;;;290:10719:25;;;;16500:50:26;290:10719:25;;;;;;;16500:50:26;290:10719:25;;16500:50:26;16496:432;;16325:609;;14622:2316;:::o;16496:432::-;16677:61;16724:13;;:::i;:::-;16677:61;;;:::i;:::-;16752:22;16748:172;;16496:432;16325:609;14622:2316;:::o;16748:172::-;16788:70;;16870:31;16788:70;290:10719:25;16788:70:26;;;;:::i;:::-;16870:31;;290:10719:25;;;;2337:23:29;290:10719:25;;;;;;;15731:450:26;15976:198;15735:15;15868:100;15735:15;15928:22;15908:18;15868:100;;:::i;:::-;16076:17;15976:198;290:10719:25;16076:17:26;;;;;;290:10719:25;;;;;;;;;;15976:198:26;15735:15;;15976:198;;:::i;:::-;15731:450;;;14759:808;14803:46;290:10719:25;14820:29:26;;;290:10719:25;;;;;14803:46:26;15075:38;290:10719:25;15029:34:26;;;290:10719:25;;;;;15075:38:26;;;;15071:445;;14759:808;15554:5;;;;;:::i;:::-;14759:808;;15071:445;15263:22;15201:93;15304:203;15263:22;;15243:18;15201:93;;:::i;:::-;15401:17;;;15304:203;290:10719:25;15401:17:26;;;290:10719:25;;;;;15304:203:26;;;:::i;:::-;15071:445;;;;19527:2739;22211:50;19527:2739;19609:25;;;:::i;:::-;19637:13;;:::i;:::-;-1:-1:-1;19656:18:26;;;290:10719:25;;;-1:-1:-1;290:10719:25;;;;19742:42:26;290:10719:25;19764:20:26;;;290:10719:25;;;;;19742:42:26;19792:226;;;-1:-1:-1;19792:226:26;20037:52;290:10719:25;20064:25:26;;;290:10719:25;;;;;20037:52:26;20097:74;290:10719:25;20135:36:26;;;290:10719:25;;;;;20097:74:26;20179:287;;;;;20485:48;290:10719:25;20179:287:26;20510:23;;290:10719:25;;;;;20485:48:26;20541:62;290:10719:25;20573:30:26;;;290:10719:25;;;;;20541:62:26;20611:60;290:10719:25;20642:29:26;;;290:10719:25;;;;;20611:60:26;20679:493;;;;;;;;;;;;;;21191:42;290:10719:25;21213:20:26;;;290:10719:25;;;;;21191:42:26;21241:44;290:10719:25;21264:21:26;;;290:10719:25;;;;;21241:44:26;21293:50;290:10719:25;21319:24:26;;;290:10719:25;;;;;21293:50:26;21375:22;21351:46;290:10719:25;21375:22:26;;;290:10719:25;;;;;21351:46:26;21424:17;21449:70;290:10719:25;21485:34:26;21405:36;290:10719:25;21424:17:26;;;290:10719:25;;;;;21405:36:26;21485:34;;290:10719:25;;;;;21449:70:26;21527:673;19764:20;21527:673;;;;;;20064:25;21527:673;;;;;;20642:29;21527:673;;;;;;;22211:50;:::i;3456:301:20:-;;290:10719:25;3632:36:20;;;;;290:10719:25;;;;;;;;;3725:25:20;;;;290:10719:25;;2458:93:21;;;;;1275:5;;2458:93;;290:10719:25;3456:301:20;:::o;290:10719:25:-;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;2398:694:28:-;;;2552:18;;:::i;:::-;2460:17:20;2446:32;290:10719:25;2460:17:20;;;290:10719:25;;2446:32:20;;:::i;:::-;290:10719:25;1884:21:22;290:10719:25;;;1884:21:22;;;;:::i;:::-;2647:17:28;;2643:50;;2700:5;5656:63:34;;1182:2;5656:63;;17566:1627;;2398:694:28;2801:17;;290:10719:25;3044:5:28;2801:17;290:10719:25;3080:6:28;2801:17;;;;:::i;:::-;290:10719:25;;2824:41:28;290:10719:25;;;;;2824:41:28;:::i;:::-;290:10719:25;;;2871:15:28;;290:10719:25;;;;2871:9:28;290:10719:25;;;;;;;;2955:39:28;;2934:15;;;:::i;2955:39::-;3000:13;;290:10719:25;;;;2871:9:28;290:10719:25;;;;;;;3044:5:28;3080:6;:::i;17566:1627:34:-;-1:-1:-1;17600:1587:34;;;;;;;;;;;;290:10719:25;17600:1587:34;;;;;;;;;;;;;6256:47;17600:1587;;;;;;;;;;;;;;;;;;;;;;;;2182:4:28;17600:1587:34;;;;;;;;;;;6256:47;;;17600:1587;;;;;17566:1627;;;;8190:1851:29;;;;;290:10719:25;8390:31:29;;290:10719:25;;;;2337:23:29;290:10719:25;;;;;;;;8441:29:29;8431:39;290:10719:25;8441:29:29;;;290:10719:25;;;;;8431:39:29;290:10719:25;;;;8431:39:29;;;8427:79;;8554:67;:39;;;290:10719:25;;;;2420:31:29;290:10719:25;;;;;;;8554:67:29;8688:26;290:10719:25;8810:52:29;290:10719:25;8688:26:29;;;290:10719:25;;;;;;;8656:111:29;8671:90;290:10719:25;;;;;;;;;;;;;;;;;;;;;;;;;8671:90:29;:::i;8656:111::-;290:10719:25;;;;8810:52:29;;:::i;:::-;290:10719:25;;;8873:30:29;;;8869:65;;9099:36;8941:5;9041:52;9099:65;8941:5;9923:74;8941:5;:93;9099:65;8941:5;;;;;;:93;:::i;:::-;290:10719:25;;;;;;;;;;;;;;;9041:52:29;9099:36;290:10719:25;;;;;;;;;9099:65:29;:::i;:::-;290:10719:25;;;;;9099:65:29;9175:29;;;;:::i;:::-;;;;9685:143;9482:47;;;;:::i;:::-;9537:53;:5;;;:53;:::i;:::-;9685:143;;:::i;:::-;9923:74;:::i;9171:746::-;9849:61;:5;;;;:61;:::i;8869:65::-;;:::i;8427:79::-;;:::i;2042:1017:17:-;2179:876;;;2042:1017;;;2179:876;2042:1017;2179:876;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2042:1017::o;2179:876::-;;;;;;;2860:199:19;;2924:133;;;;;;2860:199::o;22016:1443:34:-;5656:63;;1265:2;5656:63;;22268:1187;;22016:1443;;;;;:::o;22268:1187::-;-1:-1:-1;22299:1150:34;;;;;;;;;;;;;;;;290:10719:25;22299:1150:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;6256:47;;;22299:1150;;;;;22268:1187;;;;;;2155:116:22;;2244:21;290:10719:25;;;2244:21:22;;;;:::i;921:180:19:-;977:122;;;;;;921:180::o;1830:157:20:-;1641:46;290:10719:25;1933:20:20;;;290:10719:25;;1663:23:20;290:10719:25;1663:23:20;;;290:10719:25;;1641:46:20;;:::i;1073:119:14:-;1157:30;11086:15:29;290:10719:25;;;;;;;1157:30:14;:::i;11607:862:29:-;;;11856:15;290:10719:25;;;;;;;;;;727:31:14;;723:81;;-1:-1:-1;290:10719:25;816:8:14;290:10719:25;;;12084:100:29;290:10719:25;;-1:-1:-1;290:10719:25;;;11965:31:29;;290:10719:25;11965:31:29;;290:10719:25;;;;2337:23:29;290:10719:25;;;;;;;;12084:100:29;;;:::i;:::-;290:10719:25;;;12218:31:29;290:10719:25;12218:31:29;;;290:10719:25;;;;2337:23:29;290:10719:25;;;;;;;;;;;;;;12345:24:29;;290:10719:25;;12318:51:29;12314:151;;11607:862;;:::o;12314:151::-;11856:15;290:10719:25;;;;;;;;1834:27:14;;1830:77;;1962:14;290:10719:25;12424:34:29;290:10719:25;-1:-1:-1;290:10719:25;816:8:14;290:10719:25;;;-1:-1:-1;290:10719:25;;;;;;;1962:14:14;:::i;:::-;290:10719:25;;11856:15:29;290:10719:25;;;11856:15:29;290:10719:25;12424:34:29;:::i;1830:77:14:-;1878:22;290:10719:25;;1878:22:14;;;;1795:116:22;;1884:21;290:10719:25;;;1884:21:22;;;;:::i;8575:202:26:-;;-1:-1:-1;290:10719:25;;:::i;:::-;;;;;-1:-1:-1;290:10719:25;8683:9:26;290:10719:25;;8718:29:26;290:10719:25;-1:-1:-1;290:10719:25;;;;:::i;:::-;;;;;;8718:29:26;;:::i;:::-;8714:58;;8575:202::o;8714:58::-;2433:63:18;-1:-1:-1;2433:63:18;8683:9:26;2433:63:18;;3144:1959:29;;;;;;;;3443:29;;;290:10719:25;;;;;;;;;;;;;;;3549:34:29;3545:335;;3144:1959;290:10719:25;;;;4594:77:29;290:10719:25;4541:46:29;290:10719:25;;;;3933:86:29;290:10719:25;5092:5:29;290:10719:25;;;;3933:5:29;;;;;;:86;:::i;:::-;4082:37;;290:10719:25;;;;;;;;;4082:37:29;:::i;290:10719:25:-;4212:16:29;4205:4;;4212:16;;:::i;:::-;4406:84;:55;4267:31;4406:39;290:10719:25;4267:31:29;;290:10719:25;;;;2337:23:29;290:10719:25;;;;;;;;4406:39:29;290:10719:25;;;;2420:31:29;290:10719:25;;;;;;;4406:55:29;:84;290:10719:25;;;;;;;;4406:84:29;290:10719:25;;;;;;;;;;4406:84:29;4496:39;;290:10719:25;;;;;;;;4496:39:29;290:10719:25;;;;;4496:39:29;4541:46;:30;;;290:10719:25;;;;;;;;4541:46:29;290:10719:25;;;;;4541:46:29;290:10719:25;;4594:77:29;:::i;:::-;4789:61;4836:13;;:::i;:::-;4789:61;;;:::i;:::-;4860:22;4856:113;;3144:1959;5007:31;;;290:10719:25;;;;2337:23:29;290:10719:25;;;;;;;4856:113:29;4892:70;;;;;;:::i;:::-;4856:113;;;3545:335;290:10719:25;3835:38:29;290:10719:25;;4594:77:29;290:10719:25;4541:46:29;290:10719:25;;;;;;;3750:34:29;3757:26;3683:50;5092:5;290:10719:25;;;;;;;;;3709:23:29;3683:50;2458:93:21;3582:1:29;2458:93:21;;;2326:229;;3683:50:29;3757:15;:26;:::i;3750:34::-;290:10719:25;;;;3792:35:29;290:10719:25;;;3792:35:29;:::i;3835:38::-;3545:335;;;;;;;;;;;;;;2082:161:20;;290:10719:25;2220:17:20;2206:32;2082:161;2220:17;290:10719:25;;2206:32:20;;:::i;2767:471::-;290:10719:25;2913:30:20;;;;290:10719:25;;2983:23:20;;;;290:10719:25;;;;;;;;;;2982:88:20;3042:22;290:10719:25;3042:22:20;;;290:10719:25;;2982:88:20;;:::i;:::-;290:10719:25;;;;;;;;2206:32:20;2220:17;290:10719:25;2220:17:20;;;290:10719:25;;2206:32:20;;:::i;:::-;290:10719:25;3163:25:20;;;290:10719:25;;;;;;;;;3109:124:20;290:10719:25;3197:36:20;3109:124;3197:36;;290:10719:25;;;;;3109:124:20;;;:::i;4226:180::-;4375:25;4226:180;4375:25;:::i;7482:111:18:-;7528:63;;;;;;7739:124;7798:63;;;;;;32527:1662:34;;;5656:63;;1540:2;5656:63;;32784:1401;;32527:1662;;;:::o;32784:1401::-;-1:-1:-1;32828:1351:34;;;;;;;;;;;;;290:10719:25;32828:1351:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6256:47;;;32828:1351;;;;;32527:1662::o;1258:92:2:-;;;:::i;:::-;1923:18:25;;:::i;:::-;290:10719;;;;;;;;;1948:50;;2066:45;2088:22;;;;:::i;:::-;2066:45;2458:93:21;;;;1275:5;;2458:93;;1188:104;;2066:45:25;2460:17:20;2170:37:25;2446:32:20;;290:10719:25;2460:17:20;;;290:10719:25;;;;;2446:32:20;;;:::i;:::-;2170:37:25;:::i;:::-;290:10719;;;;2217:17;;2213:46;;2854:5;2370:10;2693:46;2769:39;2370:10;290:10719;2358:23;2370:10;2358:23;:::i;:::-;2388:48;2370:10;;;2388:5;:48;:::i;:::-;2529:6;2522:4;;2370:10;2479:5;2529:6;:::i;:::-;2543:37;;290:10719;;;;;;;;2543:37;2370:10;290:10719;;;;2871:9:28;290:10719:25;;;;;;:::i;:::-;2680:6;2370:10;;2638:28;290:10719;27523:103:26;;;;;27411:219;;2680:6:25;2370:10;;2693:46;:::i;:::-;2769:39;:23;;;290:10719;;;;;;;;2854:5;1315:1:2;;;:::i;2213:46:25:-;;:::i;1948:50::-;;:::i;913:112:18:-;960:63;;;;;;3169:835:17;3288:712;;;3169:835;3288:712;3169:835;;;3288:712;;;;;;;;;;;;;;;;;;;;;;;3169:835::o;5546:394:25:-;5649:11;;5645:41;;290:10719;;5692:48;;5797:6;5790:4;;5770:10;5747:5;5797:6;:::i;:::-;2924:133:19;5659:1:25;2924:133:19;5770:10:25;2924:133:19;;5659:1:25;2924:133:19;5889:5:25;5656:63:34;;;1265:2;5656:63;;22268:1187;;5546:394:25;;;:::o;22268:1187:34:-;5659:1:25;22299:1150:34;;;;;;-1:-1:-1;;22299:1150:34;;;;;;290:10719:25;22299:1150:34;;2924:133:19;22299:1150:34;;;;;;;;;;;;;;;;;;;290:10719:25;22299:1150:34;;;;;;;;6256:47;;;22299:1150;;;;;5546:394:25:o;24178:1418:34:-;5656:63;;1312:2;5656:63;;24376:1216;;24178:1418;;:::o;24376:1216::-;-1:-1:-1;24413:1173:34;;;;;-1:-1:-1;;24413:1173:34;;;;;;290:10719:25;24413:1173:34;;;;;;;;;;;;;;;;;;;;;;;;;;;6256:47;;;24413:1173;;;;;24178:1418::o;24129:1545:26:-;;;;24395:50;24129:1545;290:10719:25;;;;;;;;24421:24:26;;;;290:10719:25;;;;;;;;;;;;;24395:50:26;;:::i;:::-;290:10719:25;24499:21:26;;24495:40;;2460:17:20;;;290:10719:25;;;;;;;;;;;;2446:32:20;;;:::i;:::-;1275:5:21;;;2458:93;;;;;;24641:69:26;;;:::i;:::-;290:10719:25;;;;;;24908:60:26;;290:10719:25;;;24908:60:26;:::i;:::-;:72;;;:::i;:::-;290:10719:25;;;;;;;;;;;24987:46:26;;;;:::i;:::-;290:10719:25;;;;25039:26:26;;290:10719:25;;25039:50:26;;290:10719:25;;;;25039:50:26;:::i;:::-;290:10719:25;;;;25095:30:26;;;290:10719:25;;25095:52:26;;290:10719:25;;;;25095:52:26;:::i;:::-;290:10719:25;;;;25250:36:26;;;290:10719:25;;25250:60:26;;290:10719:25;;;;25250:60:26;:::i;:::-;290:10719:25;;;;25393:23:26;;290:10719:25;;25393:45:26;;290:10719:25;;;;25393:45:26;:::i;:::-;290:10719:25;;;;;27523:103:26;;;;;290:10719:25;;;;25528:4:26;;;25506:80;;;;:::i;:::-;290:10719:25;;25592:77:26;;;;:::i;24495:40::-;-1:-1:-1;24395:23:26;;-1:-1:-1;24395:23:26;;-1:-1:-1;;;;;24522:13:26:o;4633:436:19:-;;;;;4785:282;;;;;;;;;;;;;;;4633:436::o;5240:166::-;5296:108;;;;5240:166::o;5071:167::-;5128:108;;;;5071:167::o;6412:125:18:-;6472:63;;;;;;3061:179:19;3112:126;;;;;;3061:179::o;5907:114:18:-;5956:63;;;;;;6149:115;6199:63;;;;;;2620:112;2667:63;;;;;;19916:1441:34;;;5656:63;;1224:2;5656:63;;20125:1228;;19916:1441;;;:::o;20125:1228::-;-1:-1:-1;20157:1190:34;;;;;;;;;;;;;290:10719:25;20157:1190:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6256:47;;;20157:1190;;;;;19916:1441::o;2683:175:19:-;2729:127;;;;;;2683:175::o;3242:172::-;3290:122;;;;;;3242:172::o;9029:704:26:-;;9188:541;;;;;;9131:8;9188:541;;;;;;;;9173:8;9188:541;;;;;;;;;;;;;;9029:704::o;10359:648:25:-;;290:10719;;;-1:-1:-1;290:10719:25;10481:9;290:10719;;;-1:-1:-1;290:10719:25;;;;;:::i;:::-;;;;;;;;10516:25;10512:491;;10359:648;;;;:::o;10512:491::-;2220:17:20;10691:153:25;2220:17:20;;2206:32;290:10719:25;2220:17:20;;;;290:10719:25;;2206:32:20;;:::i;:::-;10821:8:25;;;;10691:153;;:::i;:::-;2160:262:19;290:10719:25;2160:262:19;;-1:-1:-1;2160:262:19;290:10719:25;2160:262:19;290:10719:25;2160:262:19;;;-1:-1:-1;2160:262:19;290:10719:25;2160:262:19;10512:491:25;;;;;;675:116:18;726:63;;;;;;29057:2700:34;;;;5656:63;;1486:2;5656:63;;29466:2287;5656:63;;;29528:2113;;;;;-1:-1:-1;29528:2113:34;;;;;;;;290:10719:25;29528:2113:34;;;;;;;;;;6256:47;29528:2113;;;;;;;;;;;;;;;;;;;;;;;;;6256:47;;;29528:2113;;;;;;;;;;;;-1:-1:-1;29528:2113:34;;;;;;29466:2287;29057:2700::o;29466:2287::-;31661:85;;;;29466:2287;29057:2700::o;2161:118:18:-;2214:63;;;;;;1833:116;1884:63;;;;;;6998:133;7066:63;;;;;;6701:133;6769:63;;;;;;1304:222:19;1383:141;;;;;;1304:222::o;1528:216::-;1603:139;;;;;;1528:216::o;5604:930:15:-;;;;;;290:10719:25;5850:19:15;290:10719:25;;;1061:24:15;;;;;290:10719:25;;1105:34:15;;;;290:10719:25;;;;;;;;;;;;;;1012:133:15;;;:::i;:::-;5946:21;;;;;290:10719:25;;5946:25:15;5942:99;;5604:930;6051:22;;;6047:173;;5604:930;6285:17;;6401:68;6285:17;6475:54;6285:17;;;;;6421:48;6422:34;290:10719:25;6335:59:15;6358:35;290:10719:25;6259:43:15;290:10719:25;;;;;;;6259:43:15;6358:35;;:::i;:::-;6335:59;;:::i;6422:34::-;6421:48;:::i;:::-;290:10719:25;;;;;6401:68:15;290:10719:25;;;;;;6047:173:15;6475:54;6103:110;;;;;6401:68;6103:110;6285:17;6103:110;;;;:::i;:::-;6047:173;;;;;;5942:99;1465:102;1394:51;;;;;;;:::i;:::-;1512:49;290:10719:25;1473:23:15;;;290:10719:25;;1520:17:15;290:10719:25;1520:17:15;;;290:10719:25;;1512:49:15;:::i;:::-;1465:102;;:::i;:::-;1602:25;;;290:10719:25;;;;;;;;;;;;;;;2244:21:22;290:10719:25;;;2244:21:22;;;;:::i;:::-;290:10719:25;5942:99:15;;;;;1340:595:24;1662:57;290:10719:25;1662:30:24;1088:50;1662:30;;;;290:10719:25;;;;1114:24:24;290:10719:25;;;;1114:24:24;;290:10719:25;;1088:50:24;;:::i;1662:57::-;290:10719:25;;;1754:36:24;2206:32:20;1754:36:24;;;;290:10719:25;;2220:17:20;290:10719:25;2220:17:20;;;290:10719:25;;2206:32:20;;:::i;:::-;290:10719:25;;;;;;;1855:25:24;;290:10719:25;;;;;;;;;1682:132:21;;;;;;1340:595:24;:::o;25678:1273:26:-;290:10719:25;;;;25893:24:26;25867:50;25893:24;;;290:10719:25;;;;;;;;;;;;25867:50:26;290:10719:25;25970:21:26;;25966:34;;2460:17:20;;;290:10719:25;;;;;;;;;;;;2446:32:20;;;:::i;:::-;1275:5:21;;;2458:93;;;;;;26113:83:26;;;:::i;:::-;290:10719:25;;26402:67:26;;290:10719:25;;;;;;;26402:67:26;:::i;:::-;:86;;;:::i;:::-;290:10719:25;;;;;;;;;;;26495:46:26;;;;:::i;:::-;290:10719:25;;;;26547:26:26;;290:10719:25;;26547:50:26;;290:10719:25;;;;26547:50:26;:::i;:::-;290:10719:25;;;;26603:30:26;;;290:10719:25;;26603:52:26;;290:10719:25;;;;26603:52:26;:::i;:::-;290:10719:25;;;;26758:36:26;;;290:10719:25;;;;;;;;;;26758:60:26;;;;:::i;:::-;290:10719:25;;;;26901:23:26;;290:10719:25;;;;;;;;;;26901:45:26;;;;:::i;25966:34::-;25993:7;;;;;;:::o;3099:173:33:-;;;12077:42;290:10719:25;;12077:42:33;290:10719:25;3169:13:33;;;;;290:10719:25;3210:27:33;;3206:54;;6417:3190;;;;;;;;-1:-1:-1;6417:3190:33;;;;;;;;;;;;3169:13;6417:3190;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;6417:3190:33;;;;;;;;9648:19;6417:3190;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;6417:3190:33;;;;;;3169:13;6417:3190;;;;;;;;;;;;;;;;;;;;;9627:19;;9648;;;;:::i;3206:54::-;3247:7;;;;;:::o;3276:137::-;3351:13;;;290:10719:25;;;;;3351:27:33;3347:54;;-1:-1:-1;10139:154:33;;;;;;;;;;10327:11;10139:154;;;;;10327:11;;:::i;:::-;10345:721;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3276:137::o;3649:982:19:-;;3843:786;3649:982;;3843:786;3649:982;;3843:786;;;;;;;;;;;;;;;;;;;;;;;;;;3649:982::o;22982:985:26:-;290:10719:25;22982:985:26;23923:31;23079:29;;;290:10719:25;;;;;;;;;23145:31:26;290:10719:25;23145:31:26;;290:10719:25;;;;2337:23:29;290:10719:25;;;;;;;;23187:24:26;;;;290:10719:25;;;;;;;;;;23187:50:26;290:10719:25;;;;;;;23187:50:26;290:10719:25;;;;23187:50:26;23183:369;;22982:985;290:10719:25;;;;;;;;;;;23558:144:26;290:10719:25;;;;;;;;23670:26:26;;;290:10719:25;;;;;;;;;;;;;;;;23558:144:26;:::i;:::-;290:10719:25;;;;;;;23713:50:26;290:10719:25;;;;;;;23713:50:26;290:10719:25;;23713:50:26;23740:23;;;;23808:6;;;;:::i;:::-;290:10719:25;;;;;2337:23:29;290:10719:25;;;;;;;23709:168:26;23836:34;;;:::i;:::-;23709:168;;23183:369;23360:61;23407:13;;:::i;:::-;23360:61;;;:::i;:::-;23433:22;;23429:117;;23183:369;;;;;23429:117;23467:70;;;;:::i;:::-;23429:117;;;3416:231:19;3487:158;;;;;;;;3416:231::o;17275:1922:34:-;;;;;;5656:63;;1182:2;5656:63;;17566:1627;;17275:1922;;;;;;:::o;17566:1627::-;17600:1587;-1:-1:-1;17600:1587:34;;;;;;;;;;;290:10719:25;17600:1587:34;;;;;;;;;;;6256:47;17600:1587;;;;;;;;;;;;;;;;;;;;;1735:4:28;17600:1587:34;;;;;;;;;;;6256:47;;;17600:1587;;;;;17566:1627;;;;;;;467:201:19;;;535:131;;;;;;467:201::o;4497:113:18:-;4545:63;;;;;;14579:1817:34;;;5656:63;;1138:2;5656:63;;14883:1509;;14579:1817;;;;;:::o;14883:1509::-;14926:1460;-1:-1:-1;14926:1460:34;;;;;;;;;;;;;;;;;290:10719:25;14926:1460:34;;;;;;;;;;6256:47;14926:1460;;;;;;;;;;;;;;;;;;;;;6256:47;;;14926:1460;;;;;14883:1509;;;;;;;28324:738:26;;28570:488;;;;;;28506:8;28570:488;;;;28468:5;28570:488;;;;;;28554:8;;28570:488;;;;;;;;;;;;;;;;;28324:738::o;6347:380:19:-;;;;;6479:246;;;;;;;;;;;;;;;6347:380::o;6062:283::-;;;6158:185;;;;;;6062:283::o;107::22:-;175:211;;;107:283::o;175:211::-;;;;;;;;;;5244:456:21;5322:374;;;;;;;;;;;;;;;;;;;;5244:456;:::o;11848:1929:34:-;;;;;;;5656:63;;1085:2;5656:63;;12165:1608;;11848:1929;;;;;;:::o;12165:1608::-;-1:-1:-1;12206:1561:34;;;;;;;;;;;;;;;;;290:10719:25;12206:1561:34;;;;;;;;;;6256:47;12206:1561;;;;;;;;;;;;;;;;;;;;;;;;;6256:47;;;12206:1561;;;;;12165:1608;;;;;;;;5716:344:19;;;;;5842:216;;;;;;;;5716:344::o;4620:469:21:-;4698:387;;;;;;;;;;;;;;;;;;;4620:469::o;2714:631::-;2792:549;;;;;;;;;;;;;;;;;;;2714:631::o;5186:114:18:-;5235:63;;;;;;3600:107;3642:63;;;;;;9326:1663:34;;;;5656:63;;1034:2;5656:63;;9570:1415;;9326:1663;;;;:::o;9570:1415::-;-1:-1:-1;9603:1376:34;;;;;;;;;;;;;290:10719:25;9603:1376:34;;;;;;;;;;6256:47;9603:1376;;;;;;;;;;;;;;;;;;;;;;;;6256:47;;;9603:1376;;;;;9570:1415;;;;;;2426:255:19;;;2512:167;;;;;;;;2426:255::o;5408:306::-;;;5531:181;;;;;;;;5408:306::o;1663:683:15:-;;;;;290:10719:25;2110:34:15;290:10719:25;2110:34:15;;;290:10719:25;;;;;;;;;2010:140:15;;;:::i;:::-;2161:19;;2157:185;;1663:683;;:::o;2157:185::-;2267:68;;;;;:::i;1915:116:22:-;;2004:21;290:10719:25;;;2004:21:22;;;;:::i;12384:655:33:-;;;12484:551;;;;;;;;;;;;;;;;;;;;;;;;;;;12384:655;;;;;:::o;12484:551::-;;;;;;;;;;;;;;1560:172:14;1714:13;1560:172;23145:15:26;290:10719:25;;;;;-1:-1:-1;290:10719:25;1665:8:14;290:10719:25;;;;-1:-1:-1;290:10719:25;;;;;;;;;;1714:13:14;:::i;:::-;290:10719:25;;23145:15:26;290:10719:25;;;;;;;;23145:15:26;290:10719:25;1560:172:14:o;820:308:21:-;4120:337;;;;;;;;;;;;290:10719:25;;;;;;;;;;;;;;292:8:21;;;820:308;:::o;3145:1545:15:-;;3423:20;;;290:10719:25;;3454:18:15;290:10719:25;;;;3454:18:15;;290:10719:25;3450:651:15;;829:20:22;1682:132:21;;;;;;;290:10719:25;;;829:20:22;;;;:::i;:::-;290:10719:25;1682:132:21;;;;;;2458:93;;;;1275:5;;2458:93;;3145:1545:15;:::o;3450:651::-;290:10719:25;;;;;;;;;;;829:20:22;290:10719:25;;;829:20:22;;;;:::i;:::-;290:10719:25;1682:132:21;;;;;;;;;;;;4039:55:15;:::o
Swarm Source
none://164736f6c6343000819000a
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
ETH | 100.00% | $1 | 623,927.1015 | $623,927.1 |
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ 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.