Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 18 from a total of 18 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Deploy Market An... | 22638973 | 2 days ago | IN | 0 ETH | 0.05373324 | ||||
Deploy Market An... | 22586073 | 9 days ago | IN | 0 ETH | 0.04175486 | ||||
Deploy Market | 22532288 | 17 days ago | IN | 0 ETH | 0.02682738 | ||||
Deploy Market An... | 22430622 | 31 days ago | IN | 0 ETH | 0.00401413 | ||||
Deploy Market An... | 22383208 | 38 days ago | IN | 0 ETH | 0.01210692 | ||||
Deploy Market | 22332630 | 45 days ago | IN | 0 ETH | 0.02313569 | ||||
Deploy Market An... | 22181288 | 66 days ago | IN | 0 ETH | 0.0103217 | ||||
Deploy Market | 22152328 | 70 days ago | IN | 0 ETH | 0.0050015 | ||||
Deploy Market An... | 22152303 | 70 days ago | IN | 0 ETH | 0.0091187 | ||||
Deploy Market An... | 22089954 | 78 days ago | IN | 0 ETH | 0.00413059 | ||||
Deploy Market An... | 22089305 | 79 days ago | IN | 0 ETH | 0.0176655 | ||||
Deploy Market | 22016397 | 89 days ago | IN | 0 ETH | 0.00451398 | ||||
Deploy Market | 21989700 | 92 days ago | IN | 0 ETH | 0.00445483 | ||||
Deploy Market | 21989547 | 92 days ago | IN | 0 ETH | 0.00697444 | ||||
Deploy Market An... | 21989438 | 92 days ago | IN | 0 ETH | 0.02440385 | ||||
Add Hooks Templa... | 21788204 | 121 days ago | IN | 0 ETH | 0.00038753 | ||||
Add Hooks Templa... | 21788203 | 121 days ago | IN | 0 ETH | 0.0004388 | ||||
Register With Ar... | 21788202 | 121 days ago | IN | 0 ETH | 0.00027177 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Method | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|---|
0x61026060 | 22638973 | 2 days ago | Contract Creation | 0 ETH | |||
0x60e06040 | 22638973 | 2 days ago | Contract Creation | 0 ETH | |||
0x61026060 | 22586073 | 9 days ago | Contract Creation | 0 ETH | |||
0x60e06040 | 22586073 | 9 days ago | Contract Creation | 0 ETH | |||
0x61026060 | 22578888 | 10 days ago | Contract Creation | 0 ETH | |||
0x61026060 | 22536567 | 16 days ago | Contract Creation | 0 ETH | |||
0x61026060 | 22536494 | 16 days ago | Contract Creation | 0 ETH | |||
0x61026060 | 22536455 | 16 days ago | Contract Creation | 0 ETH | |||
0x61026060 | 22536428 | 16 days ago | Contract Creation | 0 ETH | |||
0x61026060 | 22536250 | 16 days ago | Contract Creation | 0 ETH | |||
0x60e06040 | 22536250 | 16 days ago | Contract Creation | 0 ETH | |||
0x61026060 | 22532288 | 17 days ago | Contract Creation | 0 ETH | |||
0x61026060 | 22430622 | 31 days ago | Contract Creation | 0 ETH | |||
0x60e06040 | 22430622 | 31 days ago | Contract Creation | 0 ETH | |||
0x61026060 | 22383208 | 38 days ago | Contract Creation | 0 ETH | |||
0x60e06040 | 22383208 | 38 days ago | Contract Creation | 0 ETH | |||
0x61026060 | 22332630 | 45 days ago | Contract Creation | 0 ETH | |||
0x61026060 | 22225107 | 60 days ago | Contract Creation | 0 ETH | |||
0x60e06040 | 22225107 | 60 days ago | Contract Creation | 0 ETH | |||
0x61026060 | 22181288 | 66 days ago | Contract Creation | 0 ETH | |||
0x60e06040 | 22181288 | 66 days ago | Contract Creation | 0 ETH | |||
0x61026060 | 22152328 | 70 days ago | Contract Creation | 0 ETH | |||
0x61026060 | 22152303 | 70 days ago | Contract Creation | 0 ETH | |||
0x60e06040 | 22152303 | 70 days ago | Contract Creation | 0 ETH | |||
0x61026060 | 22089954 | 78 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
HooksFactory
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 './libraries/LibERC20.sol'; import './interfaces/IWildcatArchController.sol'; import './libraries/LibStoredInitCode.sol'; import './libraries/MathUtils.sol'; import './ReentrancyGuard.sol'; import './interfaces/WildcatStructsAndEnums.sol'; import './access/IHooks.sol'; import './IHooksFactory.sol'; import './types/TransientBytesArray.sol'; import './spherex/SphereXProtectedRegisteredBase.sol'; struct TmpMarketParameterStorage { address borrower; address asset; address feeRecipient; uint16 protocolFeeBips; uint128 maxTotalSupply; uint16 annualInterestBips; uint16 delinquencyFeeBips; uint32 withdrawalBatchDuration; uint16 reserveRatioBips; uint32 delinquencyGracePeriod; bytes32 packedNameWord0; bytes32 packedNameWord1; bytes32 packedSymbolWord0; bytes32 packedSymbolWord1; uint8 decimals; HooksConfig hooks; } contract HooksFactory is SphereXProtectedRegisteredBase, ReentrancyGuard, IHooksFactory { using LibERC20 for address; TransientBytesArray internal constant _tmpMarketParameters = TransientBytesArray.wrap(uint256(keccak256('Transient:TmpMarketParametersStorage')) - 1); uint256 internal immutable ownCreate2Prefix = LibStoredInitCode.getCreate2Prefix(address(this)); address public immutable override marketInitCodeStorage; uint256 public immutable override marketInitCodeHash; address public immutable override sanctionsSentinel; /** * @dev Return the contract name "WildcatHooksFactory" */ function name() external pure override returns (string memory) { // Use yul to avoid duplicate memory allocation and reduce code size // Uses words at 0x20, 0x40, 0x60 // 0x20 is overwritten with the ABI offset (32) // 0x40 contains the free pointer which will be 1 byte when this function executes. // The length of the string (19) is written to the last byte of the free pointer word. // 0x60 is the zero slot, so it will not have any dirty bits when this function executes. // It is overwritten with the name bytes in the same operation as the length. assembly { mstore(0x53, 0x1357696c64636174486f6f6b73466163746f7279) mstore(0x20, 0x20) return(0x20, 0x60) } } address[] internal _hooksTemplates; /// @dev Mapping from borrower to their deployed hooks instances mapping(address borrower => address[] hooksInstances) internal _hooksInstancesByBorrower; /** * @dev Mapping from hooks template to markets created with it. * Used for pushing protocol fee changes to affected markets. */ mapping(address hooksTemplate => address[] markets) internal _marketsByHooksTemplate; /** * @dev Mapping from hooks instance to markets deployed using it. * Intended primarily for off-chain queries. */ mapping(address hooksInstance => address[] markets) internal _marketsByHooksInstance; /** * @dev Mapping from hooks template to its fee configuration and name */ mapping(address hooksTemplate => HooksTemplate details) internal _templateDetails; mapping(address hooksInstance => address hooksTemplate) public override getHooksTemplateForInstance; constructor( address archController_, address _sanctionsSentinel, address _marketInitCodeStorage, uint256 _marketInitCodeHash ) { marketInitCodeStorage = _marketInitCodeStorage; marketInitCodeHash = _marketInitCodeHash; _archController = archController_; sanctionsSentinel = _sanctionsSentinel; __SphereXProtectedRegisteredBase_init(IWildcatArchController(archController_).sphereXEngine()); } /** * @dev Registers the factory as a controller with the arch-controller, allowing * it to register new markets. * Needs to be executed once at deployment. * Does not need checks for whether it has already been registered as the * arch-controller will revert if it is already registered. */ function registerWithArchController() external override { IWildcatArchController(_archController).registerController(address(this)); } function archController() external view override returns (address) { return _archController; } // ========================================================================== // // Internal Storage Helpers // // ========================================================================== // /** * @dev Get the temporary market parameters from transient storage. */ function _getTmpMarketParameters() internal view returns (TmpMarketParameterStorage memory parameters) { return abi.decode(_tmpMarketParameters.read(), (TmpMarketParameterStorage)); } /** * @dev Set the temporary market parameters in transient storage. */ function _setTmpMarketParameters(TmpMarketParameterStorage memory parameters) internal { _tmpMarketParameters.write(abi.encode(parameters)); } // ========================================================================== // // Modifiers // // ========================================================================== // modifier onlyArchControllerOwner() { if (msg.sender != IWildcatArchController(_archController).owner()) { revert CallerNotArchControllerOwner(); } _; } // ========================================================================== // // Hooks Templates // // ========================================================================== // function addHooksTemplate( address hooksTemplate, string calldata name, address feeRecipient, address originationFeeAsset, uint80 originationFeeAmount, uint16 protocolFeeBips ) external override onlyArchControllerOwner { if (_templateDetails[hooksTemplate].exists) { revert HooksTemplateAlreadyExists(); } _validateFees(feeRecipient, originationFeeAsset, originationFeeAmount, protocolFeeBips); _templateDetails[hooksTemplate] = HooksTemplate({ exists: true, name: name, feeRecipient: feeRecipient, originationFeeAsset: originationFeeAsset, originationFeeAmount: originationFeeAmount, protocolFeeBips: protocolFeeBips, enabled: true, index: uint24(_hooksTemplates.length) }); _hooksTemplates.push(hooksTemplate); emit HooksTemplateAdded( hooksTemplate, name, feeRecipient, originationFeeAsset, originationFeeAmount, protocolFeeBips ); } function _validateFees( address feeRecipient, address originationFeeAsset, uint80 originationFeeAmount, uint16 protocolFeeBips ) internal pure { bool hasOriginationFee = originationFeeAmount > 0; bool nullFeeRecipient = feeRecipient == address(0); bool nullOriginationFeeAsset = originationFeeAsset == address(0); if ( (protocolFeeBips > 0 && nullFeeRecipient) || (hasOriginationFee && nullFeeRecipient) || (hasOriginationFee && nullOriginationFeeAsset) || protocolFeeBips > 1_000 ) { revert InvalidFeeConfiguration(); } } /// @dev Update the fees for a hooks template /// Note: The new fee structure will apply to all NEW markets created with existing /// or future instances of the hooks template, and the protocol fee can be pushed /// to existing markets using `pushProtocolFeeBipsUpdates`. function updateHooksTemplateFees( address hooksTemplate, address feeRecipient, address originationFeeAsset, uint80 originationFeeAmount, uint16 protocolFeeBips ) external override onlyArchControllerOwner { if (!_templateDetails[hooksTemplate].exists) { revert HooksTemplateNotFound(); } _validateFees(feeRecipient, originationFeeAsset, originationFeeAmount, protocolFeeBips); HooksTemplate storage template = _templateDetails[hooksTemplate]; template.feeRecipient = feeRecipient; template.originationFeeAsset = originationFeeAsset; template.originationFeeAmount = originationFeeAmount; template.protocolFeeBips = protocolFeeBips; emit HooksTemplateFeesUpdated( hooksTemplate, feeRecipient, originationFeeAsset, originationFeeAmount, protocolFeeBips ); } function disableHooksTemplate(address hooksTemplate) external override onlyArchControllerOwner { if (!_templateDetails[hooksTemplate].exists) { revert HooksTemplateNotFound(); } _templateDetails[hooksTemplate].enabled = false; // Emit an event to indicate that the template has been removed emit HooksTemplateDisabled(hooksTemplate); } function getHooksTemplateDetails( address hooksTemplate ) external view override returns (HooksTemplate memory) { return _templateDetails[hooksTemplate]; } function isHooksTemplate(address hooksTemplate) external view override returns (bool) { return _templateDetails[hooksTemplate].exists; } function getHooksTemplates() external view override returns (address[] memory) { return _hooksTemplates; } function getHooksTemplates( uint256 start, uint256 end ) external view override returns (address[] memory arr) { uint256 len = _hooksTemplates.length; end = MathUtils.min(end, len); uint256 count = end - start; arr = new address[](count); for (uint256 i = 0; i < count; i++) { arr[i] = _hooksTemplates[start + i]; } } function getHooksTemplatesCount() external view override returns (uint256) { return _hooksTemplates.length; } function getMarketsForHooksTemplate( address hooksTemplate ) external view override returns (address[] memory) { return _marketsByHooksTemplate[hooksTemplate]; } function getMarketsForHooksTemplate( address hooksTemplate, uint256 start, uint256 end ) external view override returns (address[] memory arr) { address[] storage markets = _marketsByHooksTemplate[hooksTemplate]; uint256 len = markets.length; end = MathUtils.min(end, len); uint256 count = end - start; arr = new address[](count); for (uint256 i = 0; i < count; i++) { arr[i] = markets[start + i]; } } function getMarketsForHooksTemplateCount( address hooksTemplate ) external view override returns (uint256) { return _marketsByHooksTemplate[hooksTemplate].length; } // ========================================================================== // // Hooks Instances // // ========================================================================== // /// @dev Deploy a hooks instance for an approved template with constructor args. /// Callable by approved borrowers on the arch-controller. /// May require payment of origination fees. function deployHooksInstance( address hooksTemplate, bytes calldata constructorArgs ) external override nonReentrant returns (address hooksInstance) { if (!IWildcatArchController(_archController).isRegisteredBorrower(msg.sender)) { revert NotApprovedBorrower(); } hooksInstance = _deployHooksInstance(hooksTemplate, constructorArgs); } function getHooksInstancesForBorrower( address borrower ) external view override returns (address[] memory) { return _hooksInstancesByBorrower[borrower]; } function getHooksInstancesCountForBorrower( address borrower ) external view override returns (uint256) { return _hooksInstancesByBorrower[borrower].length; } function isHooksInstance(address hooksInstance) external view override returns (bool) { return getHooksTemplateForInstance[hooksInstance] != address(0); } function _deployHooksInstance( address hooksTemplate, bytes calldata constructorArgs ) internal returns (address hooksInstance) { HooksTemplate storage template = _templateDetails[hooksTemplate]; if (!template.exists) { revert HooksTemplateNotFound(); } if (!template.enabled) { revert HooksTemplateNotAvailable(); } uint256 numHooksForBorrower = _hooksInstancesByBorrower[msg.sender].length; bytes32 salt; assembly { salt := or(shl(96, caller()), numHooksForBorrower) let initCodePointer := mload(0x40) let initCodeSize := sub(extcodesize(hooksTemplate), 1) // Copy code from target address to memory starting at byte 1 extcodecopy(hooksTemplate, initCodePointer, 1, initCodeSize) let endInitCodePointer := add(initCodePointer, initCodeSize) // Write the address of the caller as the first parameter mstore(endInitCodePointer, caller()) // Write the offset to the encoded constructor args mstore(add(endInitCodePointer, 0x20), 0x40) // Write the length of the encoded constructor args let constructorArgsSize := constructorArgs.length mstore(add(endInitCodePointer, 0x40), constructorArgsSize) // Copy constructor args to initcode after the bytes length calldatacopy(add(endInitCodePointer, 0x60), constructorArgs.offset, constructorArgsSize) // Get the full size of the initcode with the constructor args let initCodeSizeWithArgs := add(add(initCodeSize, 0x60), constructorArgsSize) // Deploy the contract with the initcode hooksInstance := create2(0, initCodePointer, initCodeSizeWithArgs, salt) if iszero(hooksInstance) { mstore(0x00, 0x30116425) // DeploymentFailed() revert(0x1c, 0x04) } } _hooksInstancesByBorrower[msg.sender].push(hooksInstance); emit HooksInstanceDeployed(hooksInstance, hooksTemplate); getHooksTemplateForInstance[hooksInstance] = hooksTemplate; } // ========================================================================== // // Markets // // ========================================================================== // function getMarketsForHooksInstance( address hooksInstance ) external view override returns (address[] memory) { return _marketsByHooksInstance[hooksInstance]; } function getMarketsForHooksInstance( address hooksInstance, uint256 start, uint256 end ) external view override returns (address[] memory arr) { address[] storage markets = _marketsByHooksInstance[hooksInstance]; end = MathUtils.min(end, markets.length); uint256 count = end - start; arr = new address[](count); for (uint256 i = 0; i < count; i++) { arr[i] = markets[start + i]; } } function getMarketsForHooksInstanceCount( address hooksInstance ) external view override returns (uint256) { return _marketsByHooksInstance[hooksInstance].length; } /** * @dev Get the temporarily stored market parameters for a market that is * currently being deployed. */ function getMarketParameters() external view override returns (MarketParameters memory parameters) { TmpMarketParameterStorage memory tmp = _getTmpMarketParameters(); parameters.asset = tmp.asset; parameters.packedNameWord0 = tmp.packedNameWord0; parameters.packedNameWord1 = tmp.packedNameWord1; parameters.packedSymbolWord0 = tmp.packedSymbolWord0; parameters.packedSymbolWord1 = tmp.packedSymbolWord1; parameters.decimals = tmp.decimals; parameters.borrower = tmp.borrower; parameters.feeRecipient = tmp.feeRecipient; parameters.sentinel = sanctionsSentinel; parameters.maxTotalSupply = tmp.maxTotalSupply; parameters.protocolFeeBips = tmp.protocolFeeBips; parameters.annualInterestBips = tmp.annualInterestBips; parameters.delinquencyFeeBips = tmp.delinquencyFeeBips; parameters.withdrawalBatchDuration = tmp.withdrawalBatchDuration; parameters.reserveRatioBips = tmp.reserveRatioBips; parameters.delinquencyGracePeriod = tmp.delinquencyGracePeriod; parameters.archController = _archController; parameters.sphereXEngine = sphereXEngine(); parameters.hooks = tmp.hooks; } function computeMarketAddress(bytes32 salt) external view override returns (address) { return LibStoredInitCode.calculateCreate2Address(ownCreate2Prefix, salt, marketInitCodeHash); } /** * @dev Given a string of at most 63 bytes, produces a packed version with two words, * where the first word contains the length byte and the first 31 bytes of the string, * and the second word contains the second 32 bytes of the string. */ function _packString(string memory str) internal pure returns (bytes32 word0, bytes32 word1) { assembly { let length := mload(str) // Equivalent to: // if (str.length > 63) revert NameOrSymbolTooLong(); if gt(length, 0x3f) { mstore(0, 0x19a65cb6) revert(0x1c, 0x04) } // Load the length and first 31 bytes of the string into the first word // by reading from 31 bytes after the length pointer. word0 := mload(add(str, 0x1f)) // If the string is less than 32 bytes, the second word will be zeroed out. word1 := mul(mload(add(str, 0x3f)), gt(mload(str), 0x1f)) } } function _deployMarket( DeployMarketInputs memory parameters, bytes memory hooksData, address hooksTemplate, HooksTemplate memory templateDetails, bytes32 salt, address originationFeeAsset, uint256 originationFeeAmount ) internal returns (address market) { if (IWildcatArchController(_archController).isBlacklistedAsset(parameters.asset)) { revert AssetBlacklisted(); } address hooksInstance = parameters.hooks.hooksAddress(); if (!(address(bytes20(salt)) == msg.sender || bytes20(salt) == bytes20(0))) { revert SaltDoesNotContainSender(); } if ( originationFeeAsset != templateDetails.originationFeeAsset || originationFeeAmount != templateDetails.originationFeeAmount ) { revert FeeMismatch(); } if (originationFeeAsset != address(0)) { originationFeeAsset.safeTransferFrom( msg.sender, templateDetails.feeRecipient, originationFeeAmount ); } market = LibStoredInitCode.calculateCreate2Address(ownCreate2Prefix, salt, marketInitCodeHash); parameters.hooks = IHooks(hooksInstance).onCreateMarket( msg.sender, market, parameters, hooksData ); uint8 decimals = parameters.asset.decimals(); string memory name = string.concat(parameters.namePrefix, parameters.asset.name()); string memory symbol = string.concat(parameters.symbolPrefix, parameters.asset.symbol()); TmpMarketParameterStorage memory tmp = TmpMarketParameterStorage({ borrower: msg.sender, asset: parameters.asset, packedNameWord0: bytes32(0), packedNameWord1: bytes32(0), packedSymbolWord0: bytes32(0), packedSymbolWord1: bytes32(0), decimals: decimals, feeRecipient: templateDetails.feeRecipient, protocolFeeBips: templateDetails.protocolFeeBips, maxTotalSupply: parameters.maxTotalSupply, annualInterestBips: parameters.annualInterestBips, delinquencyFeeBips: parameters.delinquencyFeeBips, withdrawalBatchDuration: parameters.withdrawalBatchDuration, reserveRatioBips: parameters.reserveRatioBips, delinquencyGracePeriod: parameters.delinquencyGracePeriod, hooks: parameters.hooks }); { (tmp.packedNameWord0, tmp.packedNameWord1) = _packString(name); (tmp.packedSymbolWord0, tmp.packedSymbolWord1) = _packString(symbol); } _setTmpMarketParameters(tmp); if (market.code.length != 0) { revert MarketAlreadyExists(); } LibStoredInitCode.create2WithStoredInitCode(marketInitCodeStorage, salt); IWildcatArchController(_archController).registerMarket(market); _tmpMarketParameters.setEmpty(); _marketsByHooksTemplate[hooksTemplate].push(market); _marketsByHooksInstance[hooksInstance].push(market); emit MarketDeployed( hooksTemplate, market, name, symbol, tmp.asset, tmp.maxTotalSupply, tmp.annualInterestBips, tmp.delinquencyFeeBips, tmp.withdrawalBatchDuration, tmp.reserveRatioBips, tmp.delinquencyGracePeriod, tmp.hooks ); } function deployMarket( DeployMarketInputs calldata parameters, bytes calldata hooksData, bytes32 salt, address originationFeeAsset, uint256 originationFeeAmount ) external override nonReentrant returns (address market) { if (!IWildcatArchController(_archController).isRegisteredBorrower(msg.sender)) { revert NotApprovedBorrower(); } address hooksInstance = parameters.hooks.hooksAddress(); address hooksTemplate = getHooksTemplateForInstance[hooksInstance]; if (hooksTemplate == address(0)) { revert HooksInstanceNotFound(); } HooksTemplate memory templateDetails = _templateDetails[hooksTemplate]; market = _deployMarket( parameters, hooksData, hooksTemplate, templateDetails, salt, originationFeeAsset, originationFeeAmount ); } function deployMarketAndHooks( address hooksTemplate, bytes calldata hooksTemplateArgs, DeployMarketInputs memory parameters, bytes calldata hooksData, bytes32 salt, address originationFeeAsset, uint256 originationFeeAmount ) external override nonReentrant returns (address market, address hooksInstance) { if (!IWildcatArchController(_archController).isRegisteredBorrower(msg.sender)) { revert NotApprovedBorrower(); } HooksTemplate memory templateDetails = _templateDetails[hooksTemplate]; if (!templateDetails.exists) { revert HooksTemplateNotFound(); } hooksInstance = _deployHooksInstance(hooksTemplate, hooksTemplateArgs); parameters.hooks = parameters.hooks.setHooksAddress(hooksInstance); market = _deployMarket( parameters, hooksData, hooksTemplate, templateDetails, salt, originationFeeAsset, originationFeeAmount ); } /** * @dev Push any changes to the fee configuration of `hooksTemplate` to markets * using any instances of that template at `_marketsByHooksTemplate[hooksTemplate]`. * Starts at `marketStartIndex` and ends one before `marketEndIndex` or markets.length, * whichever is lowest. */ function pushProtocolFeeBipsUpdates( address hooksTemplate, uint marketStartIndex, uint marketEndIndex ) public override nonReentrant { HooksTemplate memory details = _templateDetails[hooksTemplate]; if (!details.exists) revert HooksTemplateNotFound(); address[] storage markets = _marketsByHooksTemplate[hooksTemplate]; marketEndIndex = MathUtils.min(marketEndIndex, markets.length); uint256 count = marketEndIndex - marketStartIndex; uint256 setProtocolFeeBipsCalldataPointer; uint16 protocolFeeBips = details.protocolFeeBips; assembly { // Write the calldata for `market.setProtocolFeeBips(protocolFeeBips)` // this will be reused for every market setProtocolFeeBipsCalldataPointer := mload(0x40) mstore(0x40, add(setProtocolFeeBipsCalldataPointer, 0x40)) // Write selector for `setProtocolFeeBips(uint16)` mstore(setProtocolFeeBipsCalldataPointer, 0xae6ea191) mstore(add(setProtocolFeeBipsCalldataPointer, 0x20), protocolFeeBips) // Add 28 bytes to get the exact pointer to the first byte of the selector setProtocolFeeBipsCalldataPointer := add(setProtocolFeeBipsCalldataPointer, 0x1c) } for (uint256 i = 0; i < count; i++) { address market = markets[marketStartIndex + i]; assembly { if iszero(call(gas(), market, 0, setProtocolFeeBipsCalldataPointer, 0x24, 0, 0)) { // Equivalent to `revert SetProtocolFeeBipsFailed()` mstore(0, 0x4484a4a9) revert(0x1c, 0x04) } } } } /** * @dev Push any changes to the fee configuration of `hooksTemplate` to all markets * using any instances of that template at `_marketsByHooksTemplate[hooksTemplate]`. */ function pushProtocolFeeBipsUpdates(address hooksTemplate) external override { pushProtocolFeeBipsUpdates(hooksTemplate, 0, type(uint256).max); } }
// 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; interface IWildcatArchController { error NotMarketFactory(); error NotControllerFactory(); function owner() external view returns (address); // ========================================================================== // // SphereX Config // // ========================================================================== // event ChangedSpherexOperator(address oldSphereXAdmin, address newSphereXAdmin); event ChangedSpherexEngineAddress(address oldEngineAddress, address newEngineAddress); event SpherexAdminTransferStarted(address currentAdmin, address pendingAdmin); event SpherexAdminTransferCompleted(address oldAdmin, address newAdmin); event NewAllowedSenderOnchain(address sender); error SphereXOperatorRequired(); error SphereXAdminRequired(); error SphereXOperatorOrAdminRequired(); error SphereXNotPendingAdmin(); error SphereXNotEngine(); function pendingSphereXAdmin() external view returns (address); function sphereXAdmin() external view returns (address); function sphereXOperator() external view returns (address); function sphereXEngine() external view returns (address); function transferSphereXAdminRole(address newAdmin) external virtual; function acceptSphereXAdminRole() external virtual; function changeSphereXOperator(address newSphereXOperator) external; function changeSphereXEngine(address newSphereXEngine) external; // ========================================================================== // // Controller Factory Registry // // ========================================================================== // event ControllerFactoryAdded(address); event ControllerFactoryRemoved(address); function getRegisteredControllerFactories() external view returns (address[] memory); function getRegisteredControllerFactories( uint256 start, uint256 end ) external view returns (address[] memory); function getRegisteredControllerFactoriesCount() external view returns (uint256); function isRegisteredControllerFactory(address factory) external view returns (bool); function registerControllerFactory(address factory) external; function removeControllerFactory(address factory) external; // ========================================================================== // // Controller Registry // // ========================================================================== // event ControllerAdded(address, address); event ControllerRemoved(address); function getRegisteredControllers() external view returns (address[] memory); function getRegisteredControllers( uint256 start, uint256 end ) external view returns (address[] memory); function getRegisteredControllersCount() external view returns (uint256); function isRegisteredController(address controller) external view returns (bool); function registerController(address controller) external; function removeController(address controller) external; // ========================================================================== // // Borrowers Registry // // ========================================================================== // event BorrowerAdded(address); event BorrowerRemoved(address); function getRegisteredBorrowers() external view returns (address[] memory); function getRegisteredBorrowers( uint256 start, uint256 end ) external view returns (address[] memory); function getRegisteredBorrowersCount() external view returns (uint256); function isRegisteredBorrower(address borrower) external view returns (bool); function registerBorrower(address borrower) external; function removeBorrower(address borrower) external; // ========================================================================== // // Asset Blacklist Registry // // ========================================================================== // event AssetPermitted(); event AssetBlacklisted(); function addBlacklist(address asset) external; function removeBlacklist(address asset) external; function isBlacklistedAsset(address asset) external view returns (bool); function getBlacklistedAssets() external view returns (address[] memory); function getBlacklistedAssets( uint256 start, uint256 end ) external view returns (address[] memory); function getBlacklistedAssetsCount() external view returns (uint256); // ========================================================================== // // Markets Registry // // ========================================================================== // event MarketAdded(address, address); event MarketRemoved(address); function getRegisteredMarkets() external view returns (address[] memory); function getRegisteredMarkets( uint256 start, uint256 end ) external view returns (address[] memory); function getRegisteredMarketsCount() external view returns (uint256); function isRegisteredMarket(address market) external view returns (bool); function registerMarket(address market) external; function removeMarket(address market) external; }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.24; library LibStoredInitCode { error InitCodeDeploymentFailed(); error DeploymentFailed(); function deployInitCode(bytes memory data) internal returns (address initCodeStorage) { assembly { let size := mload(data) let createSize := add(size, 0x0b) // Prefix Code // // Has trailing STOP instruction so the deployed data // can not be executed as a smart contract. // // Instruction | Stack // ---------------------------------------------------- // PUSH2 size | size | // PUSH0 | 0, size | // DUP2 | size, 0, size | // PUSH1 10 (offset to STOP) | 10, size, 0, size | // PUSH0 | 0, 10, size, 0, size | // CODECOPY | 0, size | // RETURN | | // STOP | | // ---------------------------------------------------- // Shift (size + 1) to position it in front of the PUSH2 instruction. // Reuse `data.length` memory for the create prefix to avoid // unnecessary memory allocation. mstore(data, or(shl(64, add(size, 1)), 0x6100005f81600a5f39f300)) // Deploy the code storage initCodeStorage := create(0, add(data, 21), createSize) // if (initCodeStorage == address(0)) revert InitCodeDeploymentFailed(); if iszero(initCodeStorage) { mstore(0, 0x11c8c3c0) revert(0x1c, 0x04) } // Restore `data.length` mstore(data, size) } } /** * @dev Returns the create2 prefix for a given deployer address. * Equivalent to `uint256(uint160(deployer)) | (0xff << 160)` */ function getCreate2Prefix(address deployer) internal pure returns (uint256 create2Prefix) { assembly { create2Prefix := or(deployer, 0xff0000000000000000000000000000000000000000) } } function calculateCreate2Address( uint256 create2Prefix, bytes32 salt, uint256 initCodeHash ) internal pure returns (address create2Address) { assembly { // Cache the free memory pointer so it can be restored at the end let freeMemoryPointer := mload(0x40) // Write 0xff + address to bytes 11:32 mstore(0x00, create2Prefix) // Write salt to bytes 32:64 mstore(0x20, salt) // Write initcode hash to bytes 64:96 mstore(0x40, initCodeHash) // Calculate create2 address create2Address := and(keccak256(0x0b, 0x55), 0xffffffffffffffffffffffffffffffffffffffff) // Restore the free memory pointer mstore(0x40, freeMemoryPointer) } } function createWithStoredInitCode(address initCodeStorage) internal returns (address deployment) { deployment = createWithStoredInitCode(initCodeStorage, 0); } function createWithStoredInitCode( address initCodeStorage, uint256 value ) internal returns (address deployment) { assembly { let initCodePointer := mload(0x40) let initCodeSize := sub(extcodesize(initCodeStorage), 1) extcodecopy(initCodeStorage, initCodePointer, 1, initCodeSize) deployment := create(value, initCodePointer, initCodeSize) if iszero(deployment) { mstore(0x00, 0x30116425) // DeploymentFailed() revert(0x1c, 0x04) } } } function create2WithStoredInitCode( address initCodeStorage, bytes32 salt ) internal returns (address deployment) { deployment = create2WithStoredInitCode(initCodeStorage, salt, 0); } function create2WithStoredInitCode( address initCodeStorage, bytes32 salt, uint256 value ) internal returns (address deployment) { assembly { let initCodePointer := mload(0x40) let initCodeSize := sub(extcodesize(initCodeStorage), 1) extcodecopy(initCodeStorage, initCodePointer, 1, initCodeSize) deployment := create2(value, initCodePointer, initCodeSize, salt) if iszero(deployment) { mstore(0x00, 0x30116425) // DeploymentFailed() revert(0x1c, 0x04) } } } function create2WithStoredInitCode( address initCodeStorage, bytes32 salt, uint256 value, bytes memory constructorArgs ) internal returns (address deployment) { assembly { let initCodePointer := mload(0x40) let initCodeSize := sub(extcodesize(initCodeStorage), 1) // Copy code from target address to memory starting at byte 1 extcodecopy(initCodeStorage, initCodePointer, 1, initCodeSize) // Copy constructor args from memory to initcode let constructorArgsSize := mload(constructorArgs) mcopy(add(initCodePointer, initCodeSize), add(constructorArgs, 0x20), constructorArgsSize) let initCodeSizeWithArgs := add(initCodeSize, constructorArgsSize) deployment := create2(value, initCodePointer, initCodeSizeWithArgs, salt) if iszero(deployment) { mstore(0x00, 0x30116425) // DeploymentFailed() revert(0x1c, 0x04) } } } function create2WithStoredInitCode( address initCodeStorage, bytes32 salt, bytes memory constructorArgs ) internal returns (address deployment) { return create2WithStoredInitCode(initCodeStorage, salt, 0, constructorArgs); } function create2WithStoredInitCodeCD( address initCodeStorage, bytes32 salt, uint256 value, bytes calldata constructorArgs ) internal returns (address deployment) { assembly { let initCodePointer := mload(0x40) let initCodeSize := sub(extcodesize(initCodeStorage), 1) // Copy code from target address to memory starting at byte 1 extcodecopy(initCodeStorage, initCodePointer, 1, initCodeSize) // Copy constructor args from calldata to end of initcode let constructorArgsSize := constructorArgs.length calldatacopy(add(initCodePointer, initCodeSize), constructorArgs.offset, constructorArgsSize) let initCodeSizeWithArgs := add(initCodeSize, constructorArgsSize) deployment := create2(value, initCodePointer, initCodeSizeWithArgs, salt) if iszero(deployment) { mstore(0x00, 0x30116425) // DeploymentFailed() revert(0x1c, 0x04) } } } function create2WithStoredInitCodeCD( address initCodeStorage, bytes32 salt, bytes calldata constructorArgs ) internal returns (address deployment) { return create2WithStoredInitCodeCD(initCodeStorage, salt, 0, constructorArgs); } }
// 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; /// @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: 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 '../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 './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.25; import { Panic_ErrorSelector, Panic_ErrorCodePointer, Panic_InvalidStorageByteArray, Error_SelectorPointer, Panic_ErrorLength } from '../libraries/Errors.sol'; type TransientBytesArray is uint256; using LibTransientBytesArray for TransientBytesArray global; library LibTransientBytesArray { /** * @dev Decode a dynamic bytes array from transient storage. * @param transientSlot Slot for the dynamic bytes array in transient storage * @param memoryPointer Pointer to the memory location to write the decoded array to * @return endPointer Pointer to the end of the decoded array */ function readToPointer( TransientBytesArray transientSlot, uint256 memoryPointer ) internal view returns (uint256 endPointer) { assembly { function extractByteArrayLength(data) -> length { length := div(data, 2) let outOfPlaceEncoding := and(data, 1) if iszero(outOfPlaceEncoding) { length := and(length, 0x7f) } if eq(outOfPlaceEncoding, lt(length, 32)) { // Store the Panic error signature. mstore(0, Panic_ErrorSelector) // Store the arithmetic (0x11) panic code. mstore(Panic_ErrorCodePointer, Panic_InvalidStorageByteArray) // revert(abi.encodeWithSignature("Panic(uint256)", 0x22)) revert(Error_SelectorPointer, Panic_ErrorLength) } } let slotValue := tload(transientSlot) let length := extractByteArrayLength(slotValue) mstore(memoryPointer, length) memoryPointer := add(memoryPointer, 0x20) switch and(slotValue, 1) case 0 { // short byte array let value := and(slotValue, not(0xff)) mstore(memoryPointer, value) endPointer := add(memoryPointer, 0x20) } case 1 { // long byte array mstore(0, transientSlot) // Calculate the slot of the data portion of the array let dataTSlot := keccak256(0, 0x20) let i := 0 for { } lt(i, length) { i := add(i, 0x20) } { mstore(add(memoryPointer, i), tload(dataTSlot)) dataTSlot := add(dataTSlot, 1) } endPointer := add(memoryPointer, i) } } } function read(TransientBytesArray transientSlot) internal view returns (bytes memory data) { uint256 dataPointer; assembly { dataPointer := mload(0x40) data := dataPointer mstore(data, 0) } uint256 endPointer = readToPointer(transientSlot, dataPointer); assembly { mstore(0x40, endPointer) } } /** * @dev Write a dynamic bytes array to transient storage. * @param transientSlot Slot for the dynamic bytes array in transient storage * @param memoryPointer Pointer to the memory location of the array to write */ function write(TransientBytesArray transientSlot, bytes memory memoryPointer) internal { assembly { let length := mload(memoryPointer) memoryPointer := add(memoryPointer, 0x20) switch lt(length, 32) case 0 { // For long byte arrays, the length slot holds (length * 2 + 1) tstore(transientSlot, add(1, mul(2, length))) // Calculate the slot of the data portion of the array mstore(0, transientSlot) let dataTSlot := keccak256(0, 0x20) let i := 0 for { } lt(i, length) { i := add(i, 0x20) } { tstore(dataTSlot, mload(add(memoryPointer, i))) dataTSlot := add(dataTSlot, 1) } } case 1 { // For short byte arrays, the first 31 bytes are the data and the last byte is (length * 2). let lengthByte := mul(2, length) let data := mload(memoryPointer) tstore(transientSlot, or(data, lengthByte)) } } } function setEmpty(TransientBytesArray transientSlot) internal { assembly { tstore(transientSlot, 0) } } }
// 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 { 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; 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 '../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: 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.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)) } } }
// 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; 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); } }
{ "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":[{"internalType":"address","name":"archController_","type":"address"},{"internalType":"address","name":"_sanctionsSentinel","type":"address"},{"internalType":"address","name":"_marketInitCodeStorage","type":"address"},{"internalType":"uint256","name":"_marketInitCodeHash","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AssetBlacklisted","type":"error"},{"inputs":[],"name":"CallerNotArchControllerOwner","type":"error"},{"inputs":[],"name":"DeploymentFailed","type":"error"},{"inputs":[],"name":"FeeMismatch","type":"error"},{"inputs":[],"name":"HooksInstanceAlreadyExists","type":"error"},{"inputs":[],"name":"HooksInstanceNotFound","type":"error"},{"inputs":[],"name":"HooksTemplateAlreadyExists","type":"error"},{"inputs":[],"name":"HooksTemplateNotAvailable","type":"error"},{"inputs":[],"name":"HooksTemplateNotFound","type":"error"},{"inputs":[],"name":"InvalidFeeConfiguration","type":"error"},{"inputs":[],"name":"MarketAlreadyExists","type":"error"},{"inputs":[],"name":"NameOrSymbolTooLong","type":"error"},{"inputs":[],"name":"NoReentrantCalls","type":"error"},{"inputs":[],"name":"NotApprovedBorrower","type":"error"},{"inputs":[],"name":"SaltDoesNotContainSender","type":"error"},{"inputs":[],"name":"SetProtocolFeeBipsFailed","type":"error"},{"inputs":[],"name":"SphereXOperatorRequired","type":"error"},{"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":false,"internalType":"address","name":"hooksInstance","type":"address"},{"indexed":false,"internalType":"address","name":"hooksTemplate","type":"address"}],"name":"HooksInstanceDeployed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"hooksTemplate","type":"address"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"address","name":"feeRecipient","type":"address"},{"indexed":false,"internalType":"address","name":"originationFeeAsset","type":"address"},{"indexed":false,"internalType":"uint80","name":"originationFeeAmount","type":"uint80"},{"indexed":false,"internalType":"uint16","name":"protocolFeeBips","type":"uint16"}],"name":"HooksTemplateAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"hooksTemplate","type":"address"}],"name":"HooksTemplateDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"hooksTemplate","type":"address"},{"indexed":false,"internalType":"address","name":"feeRecipient","type":"address"},{"indexed":false,"internalType":"address","name":"originationFeeAsset","type":"address"},{"indexed":false,"internalType":"uint80","name":"originationFeeAmount","type":"uint80"},{"indexed":false,"internalType":"uint16","name":"protocolFeeBips","type":"uint16"}],"name":"HooksTemplateFeesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"hooksTemplate","type":"address"},{"indexed":true,"internalType":"address","name":"market","type":"address"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"string","name":"symbol","type":"string"},{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"maxTotalSupply","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"annualInterestBips","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"delinquencyFeeBips","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"withdrawalBatchDuration","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"reserveRatioBips","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"delinquencyGracePeriod","type":"uint256"},{"indexed":false,"internalType":"HooksConfig","name":"hooks","type":"uint256"}],"name":"MarketDeployed","type":"event"},{"inputs":[{"internalType":"address","name":"hooksTemplate","type":"address"},{"internalType":"string","name":"name","type":"string"},{"internalType":"address","name":"feeRecipient","type":"address"},{"internalType":"address","name":"originationFeeAsset","type":"address"},{"internalType":"uint80","name":"originationFeeAmount","type":"uint80"},{"internalType":"uint16","name":"protocolFeeBips","type":"uint16"}],"name":"addHooksTemplate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"archController","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":[{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"computeMarketAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"hooksTemplate","type":"address"},{"internalType":"bytes","name":"constructorArgs","type":"bytes"}],"name":"deployHooksInstance","outputs":[{"internalType":"address","name":"hooksInstance","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"string","name":"namePrefix","type":"string"},{"internalType":"string","name":"symbolPrefix","type":"string"},{"internalType":"uint128","name":"maxTotalSupply","type":"uint128"},{"internalType":"uint16","name":"annualInterestBips","type":"uint16"},{"internalType":"uint16","name":"delinquencyFeeBips","type":"uint16"},{"internalType":"uint32","name":"withdrawalBatchDuration","type":"uint32"},{"internalType":"uint16","name":"reserveRatioBips","type":"uint16"},{"internalType":"uint32","name":"delinquencyGracePeriod","type":"uint32"},{"internalType":"HooksConfig","name":"hooks","type":"uint256"}],"internalType":"struct DeployMarketInputs","name":"parameters","type":"tuple"},{"internalType":"bytes","name":"hooksData","type":"bytes"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"address","name":"originationFeeAsset","type":"address"},{"internalType":"uint256","name":"originationFeeAmount","type":"uint256"}],"name":"deployMarket","outputs":[{"internalType":"address","name":"market","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"hooksTemplate","type":"address"},{"internalType":"bytes","name":"hooksTemplateArgs","type":"bytes"},{"components":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"string","name":"namePrefix","type":"string"},{"internalType":"string","name":"symbolPrefix","type":"string"},{"internalType":"uint128","name":"maxTotalSupply","type":"uint128"},{"internalType":"uint16","name":"annualInterestBips","type":"uint16"},{"internalType":"uint16","name":"delinquencyFeeBips","type":"uint16"},{"internalType":"uint32","name":"withdrawalBatchDuration","type":"uint32"},{"internalType":"uint16","name":"reserveRatioBips","type":"uint16"},{"internalType":"uint32","name":"delinquencyGracePeriod","type":"uint32"},{"internalType":"HooksConfig","name":"hooks","type":"uint256"}],"internalType":"struct DeployMarketInputs","name":"parameters","type":"tuple"},{"internalType":"bytes","name":"hooksData","type":"bytes"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"address","name":"originationFeeAsset","type":"address"},{"internalType":"uint256","name":"originationFeeAmount","type":"uint256"}],"name":"deployMarketAndHooks","outputs":[{"internalType":"address","name":"market","type":"address"},{"internalType":"address","name":"hooksInstance","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"hooksTemplate","type":"address"}],"name":"disableHooksTemplate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"borrower","type":"address"}],"name":"getHooksInstancesCountForBorrower","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"borrower","type":"address"}],"name":"getHooksInstancesForBorrower","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"hooksTemplate","type":"address"}],"name":"getHooksTemplateDetails","outputs":[{"components":[{"internalType":"address","name":"originationFeeAsset","type":"address"},{"internalType":"uint80","name":"originationFeeAmount","type":"uint80"},{"internalType":"uint16","name":"protocolFeeBips","type":"uint16"},{"internalType":"bool","name":"exists","type":"bool"},{"internalType":"bool","name":"enabled","type":"bool"},{"internalType":"uint24","name":"index","type":"uint24"},{"internalType":"address","name":"feeRecipient","type":"address"},{"internalType":"string","name":"name","type":"string"}],"internalType":"struct HooksTemplate","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"hooksInstance","type":"address"}],"name":"getHooksTemplateForInstance","outputs":[{"internalType":"address","name":"hooksTemplate","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getHooksTemplates","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"end","type":"uint256"}],"name":"getHooksTemplates","outputs":[{"internalType":"address[]","name":"arr","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getHooksTemplatesCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMarketParameters","outputs":[{"components":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"bytes32","name":"packedNameWord0","type":"bytes32"},{"internalType":"bytes32","name":"packedNameWord1","type":"bytes32"},{"internalType":"bytes32","name":"packedSymbolWord0","type":"bytes32"},{"internalType":"bytes32","name":"packedSymbolWord1","type":"bytes32"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"address","name":"feeRecipient","type":"address"},{"internalType":"address","name":"sentinel","type":"address"},{"internalType":"uint128","name":"maxTotalSupply","type":"uint128"},{"internalType":"uint16","name":"protocolFeeBips","type":"uint16"},{"internalType":"uint16","name":"annualInterestBips","type":"uint16"},{"internalType":"uint16","name":"delinquencyFeeBips","type":"uint16"},{"internalType":"uint32","name":"withdrawalBatchDuration","type":"uint32"},{"internalType":"uint16","name":"reserveRatioBips","type":"uint16"},{"internalType":"uint32","name":"delinquencyGracePeriod","type":"uint32"},{"internalType":"address","name":"archController","type":"address"},{"internalType":"address","name":"sphereXEngine","type":"address"},{"internalType":"HooksConfig","name":"hooks","type":"uint256"}],"internalType":"struct MarketParameters","name":"parameters","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"hooksInstance","type":"address"}],"name":"getMarketsForHooksInstance","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"hooksInstance","type":"address"},{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"end","type":"uint256"}],"name":"getMarketsForHooksInstance","outputs":[{"internalType":"address[]","name":"arr","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"hooksInstance","type":"address"}],"name":"getMarketsForHooksInstanceCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"hooksTemplate","type":"address"}],"name":"getMarketsForHooksTemplate","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"hooksTemplate","type":"address"},{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"end","type":"uint256"}],"name":"getMarketsForHooksTemplate","outputs":[{"internalType":"address[]","name":"arr","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"hooksTemplate","type":"address"}],"name":"getMarketsForHooksTemplateCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"hooksInstance","type":"address"}],"name":"isHooksInstance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"hooksTemplate","type":"address"}],"name":"isHooksTemplate","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"marketInitCodeHash","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"marketInitCodeStorage","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"hooksTemplate","type":"address"}],"name":"pushProtocolFeeBipsUpdates","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"hooksTemplate","type":"address"},{"internalType":"uint256","name":"marketStartIndex","type":"uint256"},{"internalType":"uint256","name":"marketEndIndex","type":"uint256"}],"name":"pushProtocolFeeBipsUpdates","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"registerWithArchController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sanctionsSentinel","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","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":[{"internalType":"address","name":"hooksTemplate","type":"address"},{"internalType":"address","name":"feeRecipient","type":"address"},{"internalType":"address","name":"originationFeeAsset","type":"address"},{"internalType":"uint80","name":"originationFeeAmount","type":"uint80"},{"internalType":"uint16","name":"protocolFeeBips","type":"uint16"}],"name":"updateHooksTemplateFees","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
61012080604052346101015760809061446c9081380391829161002183610105565b39126101015761004d61003261013e565b61003a610155565b61004261016c565b9061018051926101a2565b60405161419e90816102ce82396080518181816105b301528181610d8001528181610f3a015281816110bf01528181611170015281816113f1015281816114b2015281816119cb0152818161299f01528181612b0101528181613396015281816137a0015261382a015260a0518181816118de015261347a015260c051818181610e4b0152613764015260e0518181816118a40152818161190901526134580152610100518181816104cc0152610fdc0152f35b5f80fd5b601f01601f1916610120908101906001600160401b0382119082101761012a57604052565b634e487b7160e01b5f52604160045260245ffd5b61012051906001600160a01b038216820361010157565b61014051906001600160a01b038216820361010157565b61016051906001600160a01b038216820361010157565b9081602091031261010157516001600160a01b03811681036101015790565b9060049360209360ff60a01b301760a05260c05260e052816080526101005260405192838092631e1188b360e11b825260018060a01b03165afa801561023f575f906101f5575b6101f3915061024a565b565b506020903d602011610237575b601f8201601f19168101906001600160401b0382118183101761012a576101f39261023292604052810190610183565b6101e9565b3d9150610202565b6040513d5f823e3d90fd5b60018060a01b03608051165f80526020527f2ac55ae7ba47db34b5334622acafeb34a65daf143b47019273185d64c73a35a560405fa1807f1777adabd324f814e2b0e28f6edf876dce01d7d66358c9acfe87b1b5f38338d5556020527ff33499cccaa0611882086224cc48cd82ef54b66a4d2edf4ed67108dd516896d560405fa156fe60806040526004361015610011575f80fd5b5f3560e01c806304032dbb1461022f57806306fdde031461022a578063155733ef146102255780631caab59d146102205780632812d2de1461021b5780632b07f2801461021657806333ee81f2146102115780633476b76d1461020c578063356dd352146102075780633c231166146102025780633fd83e1e146101fd57806341f259b8146101f85780634272711d146101f35780634bd1acf3146101ee5780634c6c848f146101e9578063546355701461019957806362ef8119146101e45780636e50f960146101df5780637a749060146101da5780639c5cd31a146101d55780639f2f94b3146101d0578063ad78e45a146101cb578063aeefe08c146101c6578063c29a7677146101c1578063cd01e52a146101bc578063cdbb8374146101b7578063d14a5402146101b2578063d19bd571146101ad578063d1a0745c146101a8578063d9d58025146101a3578063e7ca86e31461019e578063e7e5db4f14610199578063eae6ff66146101945763fe604ec71461018f575f80fd5b611d64565b611cd7565b611144565b611c65565b611c49565b611c00565b611bb3565b611b6a565b611aab565b61194f565b6118c7565b61188d565b6117d9565b611451565b611362565b6112ab565b611220565b611194565b61108b565b611000565b610fb0565b610f12565b610ec1565b610e6f565b610e1f565b610cd0565b610b4b565b610add565b6109c4565b61087e565b6106de565b610674565b6103c9565b5f91031261023e57565b5f80fd5b815173ffffffffffffffffffffffffffffffffffffffff1681526102608101929160208181015160ff169083015260408101516040830152606081015160608301526080810151608083015260a081015160a08301526102bf60c082015160c084019073ffffffffffffffffffffffffffffffffffffffff169052565b60e08181015173ffffffffffffffffffffffffffffffffffffffff16908301526101008181015173ffffffffffffffffffffffffffffffffffffffff1690830152610120818101516fffffffffffffffffffffffffffffffff16908301526101408181015161ffff16908301526101608181015161ffff16908301526101808181015161ffff16908301526101a08181015163ffffffff16908301526101c08181015161ffff16908301526101e08181015163ffffffff16908301526102008181015173ffffffffffffffffffffffffffffffffffffffff16908301526102208181015173ffffffffffffffffffffffffffffffffffffffff169083015261024080910151910152565b3461023e575f60031936011261023e576103e1611dad565b6103e9612d5a565b602081015173ffffffffffffffffffffffffffffffffffffffff1682526101408082015160408401526101608083015160608501526101808084015160808601526101a08085015160a08701526101c0808601519093929060ff1660ff166020880152855173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660c0880152604086015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660e088015273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016610100888101919091529260808701516fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff166101208981019190915295606088015161ffff1661ffff169089015260a087015161ffff1661ffff169088015260c086015161ffff1661ffff169087015260e085015163ffffffff1663ffffffff169086015283015161ffff1661ffff169084015281015163ffffffff1663ffffffff166101e0838101919091529073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166102008401527f1777adabd324f814e2b0e28f6edf876dce01d7d66358c9acfe87b1b5f38338d55473ffffffffffffffffffffffffffffffffffffffff16610220840152015161024082015260405161062d819282610242565b0390f35b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602080948051918291828752018686015e5f8582860101520116010190565b3461023e575f60031936011261023e57731357696c64636174486f6f6b73466163746f72796053526020805260606020f35b73ffffffffffffffffffffffffffffffffffffffff81160361023e57565b60a435906106d1826106a6565b565b35906106d1826106a6565b3461023e57602060031936011261023e57600480356106fc816106a6565b610704612de0565b61073461072f8273ffffffffffffffffffffffffffffffffffffffff165f52600460205260405f2090565b611f42565b906107496107456060840151151590565b1590565b610803576107759073ffffffffffffffffffffffffffffffffffffffff165f52600260205260405f2090565b6107866040825493015161ffff1690565b90604051916040830160405263ae6ea19183526020830152601c8092015f5b8481106107b6576107b4612dfe565b005b5f80602484826107e96107c9878a612026565b905473ffffffffffffffffffffffffffffffffffffffff9160031b1c1690565b5af1156107f8576001016107a5565b8584634484a4a95f52fd5b60046040517f8cb2227e000000000000000000000000000000000000000000000000000000008152fd5b60209060206040818301928281528551809452019301915f5b828110610854575050505090565b835173ffffffffffffffffffffffffffffffffffffffff1685529381019392810192600101610846565b3461023e5760208060031936011261023e5760043561089c816106a6565b73ffffffffffffffffffffffffffffffffffffffff8091165f52600260205260405f20916040518092602085549283815201945f5260205f20925f915b8383106108fc5761062d866108f0818a0382611592565b6040519182918261082d565b84548116875295810195600194850194909201916108d9565b61012060e06109c1936020845273ffffffffffffffffffffffffffffffffffffffff815116602085015269ffffffffffffffffffff602082015116604085015261096a6040820151606086019061ffff169052565b6060810151151560808501526080810151151560a085015260a081015162ffffff1660c085015260c081015173ffffffffffffffffffffffffffffffffffffffff1684830152015191610100808201520190610631565b90565b3461023e57602060031936011261023e5761062d6004356109e4816106a6565b6040606060e082516109f58161153f565b5f81525f60208201525f848201525f838201525f60808201525f60a08201525f60c0820152015273ffffffffffffffffffffffffffffffffffffffff8092165f526004602052610ace6002825f20610ac8845195610a528761153f565b8254818116885269ffffffffffffffffffff60a082901c16602089015260f01c868801525b600183015460ff811615156060890152600881901c60ff1615156080890152601081901c62ffffff1660a089015260281c1660c087019073ffffffffffffffffffffffffffffffffffffffff169052565b01611e83565b60e08301525191829182610915565b3461023e57602060031936011261023e576020600435610afc816106a6565b73ffffffffffffffffffffffffffffffffffffffff8091165f526005825260405f205416604051908152f35b600319606091011261023e57600435610b40816106a6565b906024359060443590565b3461023e57610b5936610b28565b610b61612de0565b610b8c61072f8473ffffffffffffffffffffffffffffffffffffffff165f52600460205260405f2090565b92610b9d6107456060860151151590565b610803576040610be984610be4610bd5610bf39573ffffffffffffffffffffffffffffffffffffffff165f52600260205260405f2090565b95865490818082039110020190565b611fdf565b94015161ffff1690565b91604051926040840160405263ae6ea19184526020840152601c809301915f5b858110610c22576107b4612dfe565b5f8060248682610c3e6107c9610c38888b611fec565b89612026565b5af115610c4d57600101610c13565b600485634484a4a95f52fd5b9181601f8401121561023e5782359167ffffffffffffffff831161023e576020838186019501011161023e57565b6084359069ffffffffffffffffffff8216820361023e57565b6064359069ffffffffffffffffffff8216820361023e57565b61ffff81160361023e57565b35906106d182610cb9565b3461023e5760c060031936011261023e57600435610ced816106a6565b60243567ffffffffffffffff811161023e57610d0d903690600401610c59565b604435610d19816106a6565b60643590610d26826106a6565b610d2e610c87565b9260a43594610d3c86610cb9565b73ffffffffffffffffffffffffffffffffffffffff6040517f8da5cb5b000000000000000000000000000000000000000000000000000000008152602081600481857f0000000000000000000000000000000000000000000000000000000000000000165afa908115610e1a575f91610deb575b50163303610dc1576107b49661256c565b60046040517f44d783c6000000000000000000000000000000000000000000000000000000008152fd5b610e0d915060203d602011610e13575b610e058183611592565b810190612046565b5f610db0565b503d610dfb565b61205b565b3461023e575f60031936011261023e57602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b3461023e575f60031936011261023e5760207f1777adabd324f814e2b0e28f6edf876dce01d7d66358c9acfe87b1b5f38338d55473ffffffffffffffffffffffffffffffffffffffff60405191168152f35b3461023e57602060031936011261023e5773ffffffffffffffffffffffffffffffffffffffff600435610ef3816106a6565b165f526004602052602060ff600160405f200154166040519015158152f35b3461023e575f8060031936011261023e5773ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016803b1561023e575f80916024604051809481937fd91ae8c20000000000000000000000000000000000000000000000000000000083523060048401525af18015610e1a57610fa6575080f35b6107b49150611561565b3461023e575f60031936011261023e57602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b3461023e5760208060031936011261023e5760043561101e816106a6565b73ffffffffffffffffffffffffffffffffffffffff8091165f52600360205260405f20916040518092602085549283815201945f5260205f20925f915b8383106110725761062d866108f0818a0382611592565b845481168752958101956001948501949092019161105b565b3461023e57602060031936011261023e576004356110a8816106a6565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163303611137577f1777adabd324f814e2b0e28f6edf876dce01d7d66358c9acfe87b1b5f38338d581815491555f526020527ff33499cccaa0611882086224cc48cd82ef54b66a4d2edf4ed67108dd516896d560405fa1005b634ee0b8f85f526004601cfd5b3461023e575f60031936011261023e57602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b3461023e5760208060031936011261023e576004356111b2816106a6565b73ffffffffffffffffffffffffffffffffffffffff8091165f52600191600160205260405f20926040518093602086549283815201955f5260205f20935f915b8383106112095761062d876108f0818b0382611592565b8554811688529681019694840194918401916111f2565b3461023e575f60031936011261023e576040515f8054808352818052602080840193927f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56392915b82821061127e5761062d856108f081890382611592565b835473ffffffffffffffffffffffffffffffffffffffff1686529485019460019384019390910190611267565b3461023e5773ffffffffffffffffffffffffffffffffffffffff6112ce36610b28565b91929092165f52600360205260405f2090815490818082039110020182810390811161135d576112fd816126ff565b915f5b828110611315576040518061062d868261082d565b8085019081861161135d576113576113326107c960019486612026565b61133c838861274e565b9073ffffffffffffffffffffffffffffffffffffffff169052565b01611300565b611fb2565b3461023e5760a060031936011261023e5760043561137f816106a6565b60243561138b816106a6565b604435611397816106a6565b61139f610ca0565b90608435926113ad84610cb9565b73ffffffffffffffffffffffffffffffffffffffff6040517f8da5cb5b000000000000000000000000000000000000000000000000000000008152602081600481857f0000000000000000000000000000000000000000000000000000000000000000165afa908115610e1a575f91611432575b50163303610dc1576107b494612762565b61144b915060203d602011610e1357610e058183611592565b5f611421565b3461023e57602060031936011261023e5760043561146e816106a6565b73ffffffffffffffffffffffffffffffffffffffff6040517f8da5cb5b000000000000000000000000000000000000000000000000000000008152602081600481857f0000000000000000000000000000000000000000000000000000000000000000165afa908115610e1a575f916114f3575b50163303610dc1576107b4906128ca565b61150c915060203d602011610e1357610e058183611592565b5f6114e2565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b610100810190811067ffffffffffffffff82111761155c57604052565b611512565b67ffffffffffffffff811161155c57604052565b610220810190811067ffffffffffffffff82111761155c57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761155c57604052565b60405190610140820182811067ffffffffffffffff82111761155c57604052565b60405190610260820182811067ffffffffffffffff82111761155c57604052565b604051906106d18261153f565b60405190610200820182811067ffffffffffffffff82111761155c57604052565b92919267ffffffffffffffff821161155c576040519161168b60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160184611592565b82948184528183011161023e578281602093845f960137010152565b9080601f8301121561023e578160206109c193359101611643565b6fffffffffffffffffffffffffffffffff81160361023e57565b35906106d1826116c2565b63ffffffff81160361023e57565b35906106d1826116e7565b9190916101408184031261023e576117166115d3565b92611720826106d3565b845267ffffffffffffffff90602083013582811161023e57816117449185016116a7565b6020860152604083013591821161023e576117609183016116a7565b6040840152611771606082016116dc565b606084015261178260808201610cc5565b608084015261179360a08201610cc5565b60a08401526117a460c082016116f5565b60c08401526117b560e08201610cc5565b60e08401526101006117c88183016116f5565b908401526101208091013590830152565b3461023e5760e060031936011261023e576004356117f6816106a6565b67ffffffffffffffff9060243582811161023e57611818903690600401610c59565b909160443584811161023e57611832903690600401611700565b60643594851161023e5761184d611864953690600401610c59565b916118566106c4565b9460c4359660843595612959565b6040805173ffffffffffffffffffffffffffffffffffffffff9384168152919092166020820152f35b3461023e575f60031936011261023e5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b3461023e57602060031936011261023e57604080517f00000000000000000000000000000000000000000000000000000000000000005f5260043560209081527f000000000000000000000000000000000000000000000000000000000000000083526055600b209282905273ffffffffffffffffffffffffffffffffffffffff9092168152f35b3461023e57604060031936011261023e5760043561196c816106a6565b60243567ffffffffffffffff811161023e5761198c903690600401610c59565b611997929192612de0565b6040517f0787c1fe0000000000000000000000000000000000000000000000000000000081523360048201526020816024817f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff165afa908115610e1a575f91611a7c575b5015611a525761062d92611a2392612edb565b611a2b612dfe565b60405173ffffffffffffffffffffffffffffffffffffffff90911681529081906020820190565b60046040517f02171e6a000000000000000000000000000000000000000000000000000000008152fd5b611a9e915060203d602011611aa4575b611a968183611592565b810190612a91565b5f611a10565b503d611a8c565b3461023e57604060031936011261023e575f54600435602435828110908390030282018181039190821161135d57611ae2826126ff565b925f5b838110611afa576040518061062d878261082d565b8083019081841161135d5782821015611b6557611b5f611b556001935f80527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563015473ffffffffffffffffffffffffffffffffffffffff1690565b61133c838961274e565b01611ae5565b611ff9565b3461023e57602060031936011261023e5773ffffffffffffffffffffffffffffffffffffffff600435611b9c816106a6565b165f526001602052602060405f2054604051908152f35b3461023e57602060031936011261023e576020600435611bd2816106a6565b73ffffffffffffffffffffffffffffffffffffffff8091165f526005825260405f2054161515604051908152f35b3461023e57602060031936011261023e5773ffffffffffffffffffffffffffffffffffffffff600435611c32816106a6565b165f526002602052602060405f2054604051908152f35b3461023e575f60031936011261023e5760205f54604051908152f35b3461023e5760031960a08136011261023e576004359067ffffffffffffffff9081831161023e5761014090833603011261023e5760243590811161023e5761062d91611cb8611a2b923690600401610c59565b909160643591611cc7836106a6565b6084359360443592600401612aa9565b3461023e5773ffffffffffffffffffffffffffffffffffffffff611cfa36610b28565b91929092165f52600260205260405f2090815490818082039110020182810390811161135d57611d29816126ff565b915f5b828110611d41576040518061062d868261082d565b8085019081861161135d57611d5e6113326107c960019486612026565b01611d2c565b3461023e57602060031936011261023e5773ffffffffffffffffffffffffffffffffffffffff600435611d96816106a6565b165f526003602052602060405f2054604051908152f35b611db56115f4565b905f82525f60208301525f60408301525f60608301525f60808301525f60a08301525f60c08301525f60e08301525f6101008301525f6101208301525f6101408301525f6101608301525f6101808301525f6101a08301525f6101c08301525f6101e08301525f6102008301525f6102208301525f610240830152565b90600182811c92168015611e79575b6020831014611e4c57565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f1691611e41565b9060405191825f8254611e9581611e32565b908184526020946001916001811690815f14611f015750600114611ec3575b5050506106d192500383611592565b5f90815285812095935091905b818310611ee95750506106d193508201015f8080611eb4565b85548884018501529485019487945091830191611ed0565b9150506106d19593507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682840152151560051b8201015f8080611eb4565b90604051611f4f8161153f565b60e0611fad60028395610ac88154610a7773ffffffffffffffffffffffffffffffffffffffff918281168952611fa369ffffffffffffffffffff8260a01c1660208b019069ffffffffffffffffffff169052565b60f01c6040890152565b910152565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b9190820391821161135d57565b9190820180921161135d57565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b8054821015611b65575f5260205f2001905f90565b51906106d1826106a6565b9081602091031261023e57516109c1816106a6565b6040513d5f823e3d90fd5b601f821161207357505050565b5f5260205f20906020601f840160051c830193106120ab575b601f0160051c01905b8181106120a0575050565b5f8155600101612095565b909150819061208c565b919091825167ffffffffffffffff811161155c576120dd816120d78454611e32565b84612066565b602080601f831160011461213c5750819061212d9394955f92612131575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c19161790565b9055565b015190505f806120fb565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe083169561216e855f5260205f2090565b925f905b8882106121c857505083600195969710612191575b505050811b019055565b01517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690555f8080612187565b80600185968294968601518155019501930190612172565b600260e06106d19361224473ffffffffffffffffffffffffffffffffffffffff825116859073ffffffffffffffffffffffffffffffffffffffff167fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055565b602081015184547fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff1660a09190911b7dffffffffffffffffffff000000000000000000000000000000000000000016178455604081015184547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660f09190911b7fffff000000000000000000000000000000000000000000000000000000000000161784556123fc600185016060830151151560ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0083541691161781556123646123316080850151151590565b82547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690151560081b61ff0016178255565b6123ad61237760a085015162ffffff1690565b82547fffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffff1660109190911b64ffffff000016178255565b60c083015181547fffffffffffffff0000000000000000000000000000000000000000ffffffffff1660289190911b78ffffffffffffffffffffffffffffffffffffffff000000000016179055565b015191016120b5565b5f546801000000000000000081101561155c5760018101805f55811015611b655773ffffffffffffffffffffffffffffffffffffffff905f80527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5630191167fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055565b80546801000000000000000081101561155c576124ae91600182018155612026565b73ffffffffffffffffffffffffffffffffffffffff9291928084549260031b9316831b921b1916179055565b95909160a09569ffffffffffffffffffff9360e07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f885f61ffff9b9f9e9a85908f8173ffffffffffffffffffffffffffffffffffffffff9b8c809b16835260c060208401528160c08401528483013701015201168a01019a16604089015216606087015216608085015216910152565b93959192959490946125a960016125a18773ffffffffffffffffffffffffffffffffffffffff165f52600460205260405f2090565b015460ff1690565b6126bd57866126b8946125df8585857f7735fb05b8e8ddc6039fa70a50d11434f6ba73219f3cc820e8100b10dcaf89ed9c612e07565b6126a36125ef5f5462ffffff1690565b61264a6125fa611615565b73ffffffffffffffffffffffffffffffffffffffff871681529169ffffffffffffffffffff8816602084015261ffff89166040840152600160608401526001608084015262ffffff1660a0830152565b73ffffffffffffffffffffffffffffffffffffffff841660c082015261267136848c611643565b60e082015261269e8973ffffffffffffffffffffffffffffffffffffffff165f52600460205260405f2090565b6121e0565b6126ac87612405565b604051978897886124da565b0390a1565b60046040517f3704fb41000000000000000000000000000000000000000000000000000000008152fd5b67ffffffffffffffff811161155c5760051b60200190565b90612709826126e7565b6127166040519182611592565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061274482946126e7565b0190602036910137565b8051821015611b655760209160051b010190565b929391909173ffffffffffffffffffffffffffffffffffffffff80941692835f52600460205260ff600160405f20015416156108035785858460a097846127da877fba32e46aec30b4be89696b127e3fc9923645feaf4184109ba3627ac28e4de3b59c61ffff9a69ffffffffffffffffffff99612e07565b885f5260046020526128a98760405f2061283c8460018301907fffffffffffffff0000000000000000000000000000000000000000ffffffffff78ffffffffffffffffffffffffffffffffffffffff000000000083549260281b169116179055565b7dffffffffffffffffffff000000000000000000000000000000000000000060a089901b1673ffffffffffffffffffffffffffffffffffffffff87161760f09290921b7fffff00000000000000000000000000000000000000000000000000000000000016919091179055565b604051988952166020880152166040860152166060840152166080820152a1565b73ffffffffffffffffffffffffffffffffffffffff16805f52600460205260ff600160405f2001541615610803576020817ff53ee7e14e8211031e94d3dbef2a1d525daa5842da39bffef5aa54c2cb76214a925f5260048252600160405f20017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff8154169055604051908152a1565b9198979593929096949861296b612de0565b6040517f0787c1fe0000000000000000000000000000000000000000000000000000000081523360048201526020816024817f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff165afa908115610e1a575f91612a72575b5015611a5257612a1561072f8473ffffffffffffffffffffffffffffffffffffffff165f52600460205260405f2090565b93612a266107456060870151151590565b61080357612a3b612a6292612a689a86612edb565b61012084018051919c916bffffffffffffffffffffffff1660608e901b1790523691611643565b90613304565b91906106d1612dfe565b612a8b915060203d602011611aa457611a968183611592565b5f6129e4565b9081602091031261023e5751801515810361023e5790565b9094939291612ab6612de0565b6040517f0787c1fe00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff91906020816024817f000000000000000000000000000000000000000000000000000000000000000087165afa908115610e1a575f91612c05575b5015611a5257612b85612b6b61012085013560601c73ffffffffffffffffffffffffffffffffffffffff165f52600560205260405f2090565b5473ffffffffffffffffffffffffffffffffffffffff1690565b91821615612bdb57612a62612bd297612bca612bc261072f8673ffffffffffffffffffffffffffffffffffffffff165f52600460205260405f2090565b953690611700565b923691611643565b906106d1612dfe565b60046040517f816fefa2000000000000000000000000000000000000000000000000000000008152fd5b612c1e915060203d602011611aa457611a968183611592565b5f612b32565b51906106d182610cb9565b51906106d1826116c2565b51906106d1826116e7565b519060ff8216820361023e57565b908161020091031261023e57612c67611622565b90612c718161203b565b8252612c7f6020820161203b565b6020830152612c906040820161203b565b6040830152612ca160608201612c24565b6060830152612cb260808201612c2f565b6080830152612cc360a08201612c24565b60a0830152612cd460c08201612c24565b60c0830152612ce560e08201612c3a565b60e0830152610100612cf8818301612c24565b90830152610120612d0a818301612c3a565b908301526101408082015190830152610160808201519083015261018080820151908301526101a080820151908301526101c0612d48818301612c45565b908301526101e0809101519082015290565b5f6101e0612d66611622565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e08201528261010082015282610120820152826101408201528261016082015282610180820152826101a0820152826101c082015201526109c1612dd1613b47565b60208082518301019101612c53565b63929eee14805c612df1576001905d565b637fa8a9875f526004601cfd5b5f63929eee145d565b909169ffffffffffffffffffff1615159061ffff73ffffffffffffffffffffffffffffffffffffffff809216159416928315159485612ed3575b8515612eb8575b508415612e97575b5050508115612e8b575b50612e6157565b60046040517f6d24edae000000000000000000000000000000000000000000000000000000008152fd5b6103e89150115f612e5a565b929350909182612ead575b5050905f8080612e50565b161590505f80612ea2565b838092965091612ecb575b50935f612e48565b90505f612ec3565b945084612e41565b92916001612f078573ffffffffffffffffffffffffffffffffffffffff165f52600460205260405f2090565b015460ff8116156108035760081c60ff161561309857605f612f473373ffffffffffffffffffffffffffffffffffffffff165f52600160205260405f2090565b54916040519281873b95847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8089016001898d3c8888019033908201526040601f82015283603f82015201373360601b17930101905ff591821561308b576106d190612fda84612fd53373ffffffffffffffffffffffffffffffffffffffff165f52600160205260405f2090565b61248c565b6040805173ffffffffffffffffffffffffffffffffffffffff8681168252831660208201527fa1d2f67e073e80e6ec12790c669d64ea9a5dbe85ed539a27549f7e447c480dfe9190a161304b8473ffffffffffffffffffffffffffffffffffffffff165f52600560205260405f2090565b9073ffffffffffffffffffffffffffffffffffffffff167fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055565b63301164255f526004601cfd5b60046040517f0e8dc677000000000000000000000000000000000000000000000000000000008152fd5b9081602091031261023e575190565b906109c1949273ffffffffffffffffffffffffffffffffffffffff80921683521660208201526080604082015261312160808201845173ffffffffffffffffffffffffffffffffffffffff169052565b6020830151613175613141610140928360a08601526101c0850190610631565b60408601517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff808583030160c0860152610631565b60608501516fffffffffffffffffffffffffffffffff1660e0840152936131fa60808201516131ad610100918287019061ffff169052565b6131da60a0840151946131c9610120968789019061ffff169052565b60c085015163ffffffff1690870152565b60e083015161ffff1661016086015282015163ffffffff16610180850152565b01516101a08201526060818403910152610631565b805191908290602001825e015f815290565b6106d19061324361323d9493604051958693602085019061320f565b9061320f565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101845283611592565b96959373ffffffffffffffffffffffffffffffffffffffff6132c66101209a959d9c9b97946132b86fffffffffffffffffffffffffffffffff958c6101408091528d0190610631565b908b820360208d0152610631565b9c16604089015216606087015261ffff928380921660808801521660a086015263ffffffff80941660c08601521660e0840152166101008201520152565b9293909695919461337d602061332e865173ffffffffffffffffffffffffffffffffffffffff1690565b6040517fb0018c6000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909116600482015291829081906024820190565b038173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa908115610e1a575f91613b28575b50613afe5761012084015160601c92338360601c148015613ad4575b15613aaa57613421613408875173ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff8316908114801590613a78575b613a4e57613a1a575b505061350060206134c97f0000000000000000000000000000000000000000000000000000000000000000847f0000000000000000000000000000000000000000000000000000000000000000929190604051935f5260205260405273ffffffffffffffffffffffffffffffffffffffff6055600b201691604052565b98604051809381927f28fd0307000000000000000000000000000000000000000000000000000000008352888d33600486016130d1565b03815f73ffffffffffffffffffffffffffffffffffffffff88165af1908115610e1a575f916139eb575b50610120840152825173ffffffffffffffffffffffffffffffffffffffff1661355290613cae565b90602084015184516135779073ffffffffffffffffffffffffffffffffffffffff1690565b61358090613e5b565b61358991613221565b94604085015185516135ae9073ffffffffffffffffffffffffffffffffffffffff1690565b6135b790613fb6565b6135c091613221565b9285516135e09073ffffffffffffffffffffffffffffffffffffffff1690565b9560c08301516136039073ffffffffffffffffffffffffffffffffffffffff1690565b60409093015161ffff1660608201516fffffffffffffffffffffffffffffffff16608083015161ffff1660a084015161ffff169060c08501516136499063ffffffff1690565b9260e086015161365a9061ffff1690565b9461010087015161366e9063ffffffff1690565b9661012001519861367d611622565b33815273ffffffffffffffffffffffffffffffffffffffff9e8f1660208201529d1660408e015261ffff1660608d01526fffffffffffffffffffffffffffffffff1660808c015261ffff1660a08b015261ffff1660c08a015263ffffffff1660e089015261ffff1661010088015263ffffffff166101208701525f6101408701819052610160870181905261018087018190526101a087015260ff166101c08601526101e085015261372e85613ce2565b61016086015261014085015261374382613ce2565b6101a086015261018085015261375884613d0d565b873b6139c157613788907f0000000000000000000000000000000000000000000000000000000000000000614157565b5073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163b1561023e576040517fa79b9ec900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff88166004820152905f82806024810103818373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165af1908115610e1a577f6f8c7c94fc16393d1ebec38de9899ba8c6bd860a025aa60063b7cf4c40a16c09946139118a612fd573ffffffffffffffffffffffffffffffffffffffff976138ed83612fd58e829b6139a39b6139a8575b505f7f78cf023adbf9fec5dbd8e980a6a3526d1d11c66c894ab342ade9ace71f5619045d73ffffffffffffffffffffffffffffffffffffffff165f52600260205260405f2090565b73ffffffffffffffffffffffffffffffffffffffff165f52600360205260405f2090565b602081015173ffffffffffffffffffffffffffffffffffffffff1660808201516fffffffffffffffffffffffffffffffff1660a083015161ffff1660c084015161ffff169061396760e086015163ffffffff1690565b9261397861010087015161ffff1690565b946101e061398e61012089015163ffffffff1690565b970151978b6040519c8d9c169f169d8b61326f565b0390a3565b806139b56139bb92611561565b80610234565b5f6138a5565b60046040517f0313b285000000000000000000000000000000000000000000000000000000008152fd5b613a0d915060203d602011613a13575b613a058183611592565b8101906130c2565b5f61352a565b503d6139fb565b613a4791613a3f60c088015173ffffffffffffffffffffffffffffffffffffffff1690565b903390613c59565b5f8061344c565b60046040517f36a9d011000000000000000000000000000000000000000000000000000000008152fd5b50613aa2613a93602089015169ffffffffffffffffffff1690565b69ffffffffffffffffffff1690565b821415613443565b60046040517f861f5c0b000000000000000000000000000000000000000000000000000000008152fd5b507fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008316156133e2565b60046040517f47426645000000000000000000000000000000000000000000000000000000008152fd5b613b41915060203d602011611aa457611a968183611592565b5f6133c6565b604051905f82525f7f78cf023adbf9fec5dbd8e980a6a3526d1d11c66c894ab342ade9ace71f561904805c9060018260011c9160018416938415613c4f575b6020948585108114613c3e57848952908115613c035750600114613bae575b50505050604052565b5f908152929350837f810543fe2cb308dcc7090dc0718da3cf7b1ea9e6ee6878e7d574d84a057628975b838510613bef57505050508301015f808080613ba5565b805c88860183015293019284908201613bd8565b93505050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff009192501690830152604082015f808080613ba5565b602286634e487b715f52526024601cfd5b92607f1692613b86565b601c5f60649281946020966040519860605260405260601b602c526f23b872dd000000000000000000000000600c525af13d1560015f5114171615613ca1575f606052604052565b637939f4245f526004601cfd5b5f6004601c60209363313ce56784525afa6101005f511060203d14161615613cd5575f5190565b633394d1705f526004601cfd5b90603f825111613d0057601f82015191603f601f8251119101510290565b6319a65cb65f526004601cfd5b604051815173ffffffffffffffffffffffffffffffffffffffff1660208201526106d191602081015173ffffffffffffffffffffffffffffffffffffffff166040830152604081015173ffffffffffffffffffffffffffffffffffffffff166060830152606081015161ffff16608083015260808101516fffffffffffffffffffffffffffffffff1660a083015260a081015161ffff1660c083015260c081015161ffff1660e083015260e0810151613dd1610100918285019063ffffffff169052565b810151613de7610120918285019061ffff169052565b810151613dff610140918285019063ffffffff169052565b810151610160908184015281015161018090818401528101516101a090818401528101516101c0908184015281015190613e416101e0928385019060ff169052565b015161020090818301528152613e5681611575565b614098565b5f6004601c82936306fdde0384525afa3d6020149015605f3d118217158117613f8b575015613f1a5760205f803e6109c15f519060018219018216916007836fffffffffffffffffffffffffffffffff10811b821560081b1784811c67ffffffffffffffff1060061b1784811c63ffffffff1060051b177e1f0d1e100c1d070f090b19131c1706010e11080a1a141802121b1503160405601f6040519660408801604052831c63d76453e004161a1760ff030160031c83526020830152565b60405190602063ffffffe07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3d01168084016040527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03d0182853e013d18613f7e57565b634cb9c0005f526004601cfd5b613f9c57634cb9c0005f526004601cfd5b3d613fae57632ed09f545f526004601cfd5b3d5f803e3d5ffd5b5f6004601c82936395d89b4184525afa3d6020149015605f3d118217158117614075575015613f1a5760205f803e6109c15f519060018219018216916007836fffffffffffffffffffffffffffffffff10811b821560081b1784811c67ffffffffffffffff1060061b1784811c63ffffffff1060051b177e1f0d1e100c1d070f090b19131c1706010e11080a1a141802121b1503160405601f6040519660408801604052831c63d76453e004161a1760ff030160031c83526020830152565b61408657634cb9c0005f526004601cfd5b3d613fae57633ddcc60a5f526004601cfd5b805160208082109081156140e057506001146140b2575050565b60209060011b910151177f78cf023adbf9fec5dbd8e980a6a3526d1d11c66c894ab342ade9ace71f5619045d565b92600191507f78cf023adbf9fec5dbd8e980a6a3526d1d11c66c894ab342ade9ace71f56190483831b8301815d5f527f810543fe2cb308dcc7090dc0718da3cf7b1ea9e6ee6878e7d574d84a05762897905f915b84831061414357505050505050565b838691828585010151815d01920191614134565b6040518160017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83943b019384923c5ff590811561308b5756fea164736f6c6343000819000a000000000000000000000000feb516d9d946dd487a9346f6fee11f40c6945ee4000000000000000000000000437e0551892c2c9b06d3ffd248fe60572e08cd1a000000000000000000000000ac3216fa28f81b8fae150fb5626ca79c7a570dafc152ead6073d54f964e3c2fd317ec6c774e67465cf3e6fb9551badb88a09e43f
Deployed Bytecode
0x60806040526004361015610011575f80fd5b5f3560e01c806304032dbb1461022f57806306fdde031461022a578063155733ef146102255780631caab59d146102205780632812d2de1461021b5780632b07f2801461021657806333ee81f2146102115780633476b76d1461020c578063356dd352146102075780633c231166146102025780633fd83e1e146101fd57806341f259b8146101f85780634272711d146101f35780634bd1acf3146101ee5780634c6c848f146101e9578063546355701461019957806362ef8119146101e45780636e50f960146101df5780637a749060146101da5780639c5cd31a146101d55780639f2f94b3146101d0578063ad78e45a146101cb578063aeefe08c146101c6578063c29a7677146101c1578063cd01e52a146101bc578063cdbb8374146101b7578063d14a5402146101b2578063d19bd571146101ad578063d1a0745c146101a8578063d9d58025146101a3578063e7ca86e31461019e578063e7e5db4f14610199578063eae6ff66146101945763fe604ec71461018f575f80fd5b611d64565b611cd7565b611144565b611c65565b611c49565b611c00565b611bb3565b611b6a565b611aab565b61194f565b6118c7565b61188d565b6117d9565b611451565b611362565b6112ab565b611220565b611194565b61108b565b611000565b610fb0565b610f12565b610ec1565b610e6f565b610e1f565b610cd0565b610b4b565b610add565b6109c4565b61087e565b6106de565b610674565b6103c9565b5f91031261023e57565b5f80fd5b815173ffffffffffffffffffffffffffffffffffffffff1681526102608101929160208181015160ff169083015260408101516040830152606081015160608301526080810151608083015260a081015160a08301526102bf60c082015160c084019073ffffffffffffffffffffffffffffffffffffffff169052565b60e08181015173ffffffffffffffffffffffffffffffffffffffff16908301526101008181015173ffffffffffffffffffffffffffffffffffffffff1690830152610120818101516fffffffffffffffffffffffffffffffff16908301526101408181015161ffff16908301526101608181015161ffff16908301526101808181015161ffff16908301526101a08181015163ffffffff16908301526101c08181015161ffff16908301526101e08181015163ffffffff16908301526102008181015173ffffffffffffffffffffffffffffffffffffffff16908301526102208181015173ffffffffffffffffffffffffffffffffffffffff169083015261024080910151910152565b3461023e575f60031936011261023e576103e1611dad565b6103e9612d5a565b602081015173ffffffffffffffffffffffffffffffffffffffff1682526101408082015160408401526101608083015160608501526101808084015160808601526101a08085015160a08701526101c0808601519093929060ff1660ff166020880152855173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660c0880152604086015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660e088015273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000437e0551892c2c9b06d3ffd248fe60572e08cd1a16610100888101919091529260808701516fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff166101208981019190915295606088015161ffff1661ffff169089015260a087015161ffff1661ffff169088015260c086015161ffff1661ffff169087015260e085015163ffffffff1663ffffffff169086015283015161ffff1661ffff169084015281015163ffffffff1663ffffffff166101e0838101919091529073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000feb516d9d946dd487a9346f6fee11f40c6945ee4166102008401527f1777adabd324f814e2b0e28f6edf876dce01d7d66358c9acfe87b1b5f38338d55473ffffffffffffffffffffffffffffffffffffffff16610220840152015161024082015260405161062d819282610242565b0390f35b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602080948051918291828752018686015e5f8582860101520116010190565b3461023e575f60031936011261023e57731357696c64636174486f6f6b73466163746f72796053526020805260606020f35b73ffffffffffffffffffffffffffffffffffffffff81160361023e57565b60a435906106d1826106a6565b565b35906106d1826106a6565b3461023e57602060031936011261023e57600480356106fc816106a6565b610704612de0565b61073461072f8273ffffffffffffffffffffffffffffffffffffffff165f52600460205260405f2090565b611f42565b906107496107456060840151151590565b1590565b610803576107759073ffffffffffffffffffffffffffffffffffffffff165f52600260205260405f2090565b6107866040825493015161ffff1690565b90604051916040830160405263ae6ea19183526020830152601c8092015f5b8481106107b6576107b4612dfe565b005b5f80602484826107e96107c9878a612026565b905473ffffffffffffffffffffffffffffffffffffffff9160031b1c1690565b5af1156107f8576001016107a5565b8584634484a4a95f52fd5b60046040517f8cb2227e000000000000000000000000000000000000000000000000000000008152fd5b60209060206040818301928281528551809452019301915f5b828110610854575050505090565b835173ffffffffffffffffffffffffffffffffffffffff1685529381019392810192600101610846565b3461023e5760208060031936011261023e5760043561089c816106a6565b73ffffffffffffffffffffffffffffffffffffffff8091165f52600260205260405f20916040518092602085549283815201945f5260205f20925f915b8383106108fc5761062d866108f0818a0382611592565b6040519182918261082d565b84548116875295810195600194850194909201916108d9565b61012060e06109c1936020845273ffffffffffffffffffffffffffffffffffffffff815116602085015269ffffffffffffffffffff602082015116604085015261096a6040820151606086019061ffff169052565b6060810151151560808501526080810151151560a085015260a081015162ffffff1660c085015260c081015173ffffffffffffffffffffffffffffffffffffffff1684830152015191610100808201520190610631565b90565b3461023e57602060031936011261023e5761062d6004356109e4816106a6565b6040606060e082516109f58161153f565b5f81525f60208201525f848201525f838201525f60808201525f60a08201525f60c0820152015273ffffffffffffffffffffffffffffffffffffffff8092165f526004602052610ace6002825f20610ac8845195610a528761153f565b8254818116885269ffffffffffffffffffff60a082901c16602089015260f01c868801525b600183015460ff811615156060890152600881901c60ff1615156080890152601081901c62ffffff1660a089015260281c1660c087019073ffffffffffffffffffffffffffffffffffffffff169052565b01611e83565b60e08301525191829182610915565b3461023e57602060031936011261023e576020600435610afc816106a6565b73ffffffffffffffffffffffffffffffffffffffff8091165f526005825260405f205416604051908152f35b600319606091011261023e57600435610b40816106a6565b906024359060443590565b3461023e57610b5936610b28565b610b61612de0565b610b8c61072f8473ffffffffffffffffffffffffffffffffffffffff165f52600460205260405f2090565b92610b9d6107456060860151151590565b610803576040610be984610be4610bd5610bf39573ffffffffffffffffffffffffffffffffffffffff165f52600260205260405f2090565b95865490818082039110020190565b611fdf565b94015161ffff1690565b91604051926040840160405263ae6ea19184526020840152601c809301915f5b858110610c22576107b4612dfe565b5f8060248682610c3e6107c9610c38888b611fec565b89612026565b5af115610c4d57600101610c13565b600485634484a4a95f52fd5b9181601f8401121561023e5782359167ffffffffffffffff831161023e576020838186019501011161023e57565b6084359069ffffffffffffffffffff8216820361023e57565b6064359069ffffffffffffffffffff8216820361023e57565b61ffff81160361023e57565b35906106d182610cb9565b3461023e5760c060031936011261023e57600435610ced816106a6565b60243567ffffffffffffffff811161023e57610d0d903690600401610c59565b604435610d19816106a6565b60643590610d26826106a6565b610d2e610c87565b9260a43594610d3c86610cb9565b73ffffffffffffffffffffffffffffffffffffffff6040517f8da5cb5b000000000000000000000000000000000000000000000000000000008152602081600481857f000000000000000000000000feb516d9d946dd487a9346f6fee11f40c6945ee4165afa908115610e1a575f91610deb575b50163303610dc1576107b49661256c565b60046040517f44d783c6000000000000000000000000000000000000000000000000000000008152fd5b610e0d915060203d602011610e13575b610e058183611592565b810190612046565b5f610db0565b503d610dfb565b61205b565b3461023e575f60031936011261023e57602060405173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000ac3216fa28f81b8fae150fb5626ca79c7a570daf168152f35b3461023e575f60031936011261023e5760207f1777adabd324f814e2b0e28f6edf876dce01d7d66358c9acfe87b1b5f38338d55473ffffffffffffffffffffffffffffffffffffffff60405191168152f35b3461023e57602060031936011261023e5773ffffffffffffffffffffffffffffffffffffffff600435610ef3816106a6565b165f526004602052602060ff600160405f200154166040519015158152f35b3461023e575f8060031936011261023e5773ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000feb516d9d946dd487a9346f6fee11f40c6945ee416803b1561023e575f80916024604051809481937fd91ae8c20000000000000000000000000000000000000000000000000000000083523060048401525af18015610e1a57610fa6575080f35b6107b49150611561565b3461023e575f60031936011261023e57602060405173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000437e0551892c2c9b06d3ffd248fe60572e08cd1a168152f35b3461023e5760208060031936011261023e5760043561101e816106a6565b73ffffffffffffffffffffffffffffffffffffffff8091165f52600360205260405f20916040518092602085549283815201945f5260205f20925f915b8383106110725761062d866108f0818a0382611592565b845481168752958101956001948501949092019161105b565b3461023e57602060031936011261023e576004356110a8816106a6565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000feb516d9d946dd487a9346f6fee11f40c6945ee4163303611137577f1777adabd324f814e2b0e28f6edf876dce01d7d66358c9acfe87b1b5f38338d581815491555f526020527ff33499cccaa0611882086224cc48cd82ef54b66a4d2edf4ed67108dd516896d560405fa1005b634ee0b8f85f526004601cfd5b3461023e575f60031936011261023e57602060405173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000feb516d9d946dd487a9346f6fee11f40c6945ee4168152f35b3461023e5760208060031936011261023e576004356111b2816106a6565b73ffffffffffffffffffffffffffffffffffffffff8091165f52600191600160205260405f20926040518093602086549283815201955f5260205f20935f915b8383106112095761062d876108f0818b0382611592565b8554811688529681019694840194918401916111f2565b3461023e575f60031936011261023e576040515f8054808352818052602080840193927f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56392915b82821061127e5761062d856108f081890382611592565b835473ffffffffffffffffffffffffffffffffffffffff1686529485019460019384019390910190611267565b3461023e5773ffffffffffffffffffffffffffffffffffffffff6112ce36610b28565b91929092165f52600360205260405f2090815490818082039110020182810390811161135d576112fd816126ff565b915f5b828110611315576040518061062d868261082d565b8085019081861161135d576113576113326107c960019486612026565b61133c838861274e565b9073ffffffffffffffffffffffffffffffffffffffff169052565b01611300565b611fb2565b3461023e5760a060031936011261023e5760043561137f816106a6565b60243561138b816106a6565b604435611397816106a6565b61139f610ca0565b90608435926113ad84610cb9565b73ffffffffffffffffffffffffffffffffffffffff6040517f8da5cb5b000000000000000000000000000000000000000000000000000000008152602081600481857f000000000000000000000000feb516d9d946dd487a9346f6fee11f40c6945ee4165afa908115610e1a575f91611432575b50163303610dc1576107b494612762565b61144b915060203d602011610e1357610e058183611592565b5f611421565b3461023e57602060031936011261023e5760043561146e816106a6565b73ffffffffffffffffffffffffffffffffffffffff6040517f8da5cb5b000000000000000000000000000000000000000000000000000000008152602081600481857f000000000000000000000000feb516d9d946dd487a9346f6fee11f40c6945ee4165afa908115610e1a575f916114f3575b50163303610dc1576107b4906128ca565b61150c915060203d602011610e1357610e058183611592565b5f6114e2565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b610100810190811067ffffffffffffffff82111761155c57604052565b611512565b67ffffffffffffffff811161155c57604052565b610220810190811067ffffffffffffffff82111761155c57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761155c57604052565b60405190610140820182811067ffffffffffffffff82111761155c57604052565b60405190610260820182811067ffffffffffffffff82111761155c57604052565b604051906106d18261153f565b60405190610200820182811067ffffffffffffffff82111761155c57604052565b92919267ffffffffffffffff821161155c576040519161168b60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160184611592565b82948184528183011161023e578281602093845f960137010152565b9080601f8301121561023e578160206109c193359101611643565b6fffffffffffffffffffffffffffffffff81160361023e57565b35906106d1826116c2565b63ffffffff81160361023e57565b35906106d1826116e7565b9190916101408184031261023e576117166115d3565b92611720826106d3565b845267ffffffffffffffff90602083013582811161023e57816117449185016116a7565b6020860152604083013591821161023e576117609183016116a7565b6040840152611771606082016116dc565b606084015261178260808201610cc5565b608084015261179360a08201610cc5565b60a08401526117a460c082016116f5565b60c08401526117b560e08201610cc5565b60e08401526101006117c88183016116f5565b908401526101208091013590830152565b3461023e5760e060031936011261023e576004356117f6816106a6565b67ffffffffffffffff9060243582811161023e57611818903690600401610c59565b909160443584811161023e57611832903690600401611700565b60643594851161023e5761184d611864953690600401610c59565b916118566106c4565b9460c4359660843595612959565b6040805173ffffffffffffffffffffffffffffffffffffffff9384168152919092166020820152f35b3461023e575f60031936011261023e5760206040517fc152ead6073d54f964e3c2fd317ec6c774e67465cf3e6fb9551badb88a09e43f8152f35b3461023e57602060031936011261023e57604080517f0000000000000000000000ffdd7dd3b5076cf89440d05585ff56d246386207be5f5260043560209081527fc152ead6073d54f964e3c2fd317ec6c774e67465cf3e6fb9551badb88a09e43f83526055600b209282905273ffffffffffffffffffffffffffffffffffffffff9092168152f35b3461023e57604060031936011261023e5760043561196c816106a6565b60243567ffffffffffffffff811161023e5761198c903690600401610c59565b611997929192612de0565b6040517f0787c1fe0000000000000000000000000000000000000000000000000000000081523360048201526020816024817f000000000000000000000000feb516d9d946dd487a9346f6fee11f40c6945ee473ffffffffffffffffffffffffffffffffffffffff165afa908115610e1a575f91611a7c575b5015611a525761062d92611a2392612edb565b611a2b612dfe565b60405173ffffffffffffffffffffffffffffffffffffffff90911681529081906020820190565b60046040517f02171e6a000000000000000000000000000000000000000000000000000000008152fd5b611a9e915060203d602011611aa4575b611a968183611592565b810190612a91565b5f611a10565b503d611a8c565b3461023e57604060031936011261023e575f54600435602435828110908390030282018181039190821161135d57611ae2826126ff565b925f5b838110611afa576040518061062d878261082d565b8083019081841161135d5782821015611b6557611b5f611b556001935f80527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563015473ffffffffffffffffffffffffffffffffffffffff1690565b61133c838961274e565b01611ae5565b611ff9565b3461023e57602060031936011261023e5773ffffffffffffffffffffffffffffffffffffffff600435611b9c816106a6565b165f526001602052602060405f2054604051908152f35b3461023e57602060031936011261023e576020600435611bd2816106a6565b73ffffffffffffffffffffffffffffffffffffffff8091165f526005825260405f2054161515604051908152f35b3461023e57602060031936011261023e5773ffffffffffffffffffffffffffffffffffffffff600435611c32816106a6565b165f526002602052602060405f2054604051908152f35b3461023e575f60031936011261023e5760205f54604051908152f35b3461023e5760031960a08136011261023e576004359067ffffffffffffffff9081831161023e5761014090833603011261023e5760243590811161023e5761062d91611cb8611a2b923690600401610c59565b909160643591611cc7836106a6565b6084359360443592600401612aa9565b3461023e5773ffffffffffffffffffffffffffffffffffffffff611cfa36610b28565b91929092165f52600260205260405f2090815490818082039110020182810390811161135d57611d29816126ff565b915f5b828110611d41576040518061062d868261082d565b8085019081861161135d57611d5e6113326107c960019486612026565b01611d2c565b3461023e57602060031936011261023e5773ffffffffffffffffffffffffffffffffffffffff600435611d96816106a6565b165f526003602052602060405f2054604051908152f35b611db56115f4565b905f82525f60208301525f60408301525f60608301525f60808301525f60a08301525f60c08301525f60e08301525f6101008301525f6101208301525f6101408301525f6101608301525f6101808301525f6101a08301525f6101c08301525f6101e08301525f6102008301525f6102208301525f610240830152565b90600182811c92168015611e79575b6020831014611e4c57565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f1691611e41565b9060405191825f8254611e9581611e32565b908184526020946001916001811690815f14611f015750600114611ec3575b5050506106d192500383611592565b5f90815285812095935091905b818310611ee95750506106d193508201015f8080611eb4565b85548884018501529485019487945091830191611ed0565b9150506106d19593507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682840152151560051b8201015f8080611eb4565b90604051611f4f8161153f565b60e0611fad60028395610ac88154610a7773ffffffffffffffffffffffffffffffffffffffff918281168952611fa369ffffffffffffffffffff8260a01c1660208b019069ffffffffffffffffffff169052565b60f01c6040890152565b910152565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b9190820391821161135d57565b9190820180921161135d57565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b8054821015611b65575f5260205f2001905f90565b51906106d1826106a6565b9081602091031261023e57516109c1816106a6565b6040513d5f823e3d90fd5b601f821161207357505050565b5f5260205f20906020601f840160051c830193106120ab575b601f0160051c01905b8181106120a0575050565b5f8155600101612095565b909150819061208c565b919091825167ffffffffffffffff811161155c576120dd816120d78454611e32565b84612066565b602080601f831160011461213c5750819061212d9394955f92612131575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c19161790565b9055565b015190505f806120fb565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe083169561216e855f5260205f2090565b925f905b8882106121c857505083600195969710612191575b505050811b019055565b01517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690555f8080612187565b80600185968294968601518155019501930190612172565b600260e06106d19361224473ffffffffffffffffffffffffffffffffffffffff825116859073ffffffffffffffffffffffffffffffffffffffff167fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055565b602081015184547fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff1660a09190911b7dffffffffffffffffffff000000000000000000000000000000000000000016178455604081015184547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660f09190911b7fffff000000000000000000000000000000000000000000000000000000000000161784556123fc600185016060830151151560ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0083541691161781556123646123316080850151151590565b82547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690151560081b61ff0016178255565b6123ad61237760a085015162ffffff1690565b82547fffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffff1660109190911b64ffffff000016178255565b60c083015181547fffffffffffffff0000000000000000000000000000000000000000ffffffffff1660289190911b78ffffffffffffffffffffffffffffffffffffffff000000000016179055565b015191016120b5565b5f546801000000000000000081101561155c5760018101805f55811015611b655773ffffffffffffffffffffffffffffffffffffffff905f80527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5630191167fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055565b80546801000000000000000081101561155c576124ae91600182018155612026565b73ffffffffffffffffffffffffffffffffffffffff9291928084549260031b9316831b921b1916179055565b95909160a09569ffffffffffffffffffff9360e07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f885f61ffff9b9f9e9a85908f8173ffffffffffffffffffffffffffffffffffffffff9b8c809b16835260c060208401528160c08401528483013701015201168a01019a16604089015216606087015216608085015216910152565b93959192959490946125a960016125a18773ffffffffffffffffffffffffffffffffffffffff165f52600460205260405f2090565b015460ff1690565b6126bd57866126b8946125df8585857f7735fb05b8e8ddc6039fa70a50d11434f6ba73219f3cc820e8100b10dcaf89ed9c612e07565b6126a36125ef5f5462ffffff1690565b61264a6125fa611615565b73ffffffffffffffffffffffffffffffffffffffff871681529169ffffffffffffffffffff8816602084015261ffff89166040840152600160608401526001608084015262ffffff1660a0830152565b73ffffffffffffffffffffffffffffffffffffffff841660c082015261267136848c611643565b60e082015261269e8973ffffffffffffffffffffffffffffffffffffffff165f52600460205260405f2090565b6121e0565b6126ac87612405565b604051978897886124da565b0390a1565b60046040517f3704fb41000000000000000000000000000000000000000000000000000000008152fd5b67ffffffffffffffff811161155c5760051b60200190565b90612709826126e7565b6127166040519182611592565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061274482946126e7565b0190602036910137565b8051821015611b655760209160051b010190565b929391909173ffffffffffffffffffffffffffffffffffffffff80941692835f52600460205260ff600160405f20015416156108035785858460a097846127da877fba32e46aec30b4be89696b127e3fc9923645feaf4184109ba3627ac28e4de3b59c61ffff9a69ffffffffffffffffffff99612e07565b885f5260046020526128a98760405f2061283c8460018301907fffffffffffffff0000000000000000000000000000000000000000ffffffffff78ffffffffffffffffffffffffffffffffffffffff000000000083549260281b169116179055565b7dffffffffffffffffffff000000000000000000000000000000000000000060a089901b1673ffffffffffffffffffffffffffffffffffffffff87161760f09290921b7fffff00000000000000000000000000000000000000000000000000000000000016919091179055565b604051988952166020880152166040860152166060840152166080820152a1565b73ffffffffffffffffffffffffffffffffffffffff16805f52600460205260ff600160405f2001541615610803576020817ff53ee7e14e8211031e94d3dbef2a1d525daa5842da39bffef5aa54c2cb76214a925f5260048252600160405f20017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff8154169055604051908152a1565b9198979593929096949861296b612de0565b6040517f0787c1fe0000000000000000000000000000000000000000000000000000000081523360048201526020816024817f000000000000000000000000feb516d9d946dd487a9346f6fee11f40c6945ee473ffffffffffffffffffffffffffffffffffffffff165afa908115610e1a575f91612a72575b5015611a5257612a1561072f8473ffffffffffffffffffffffffffffffffffffffff165f52600460205260405f2090565b93612a266107456060870151151590565b61080357612a3b612a6292612a689a86612edb565b61012084018051919c916bffffffffffffffffffffffff1660608e901b1790523691611643565b90613304565b91906106d1612dfe565b612a8b915060203d602011611aa457611a968183611592565b5f6129e4565b9081602091031261023e5751801515810361023e5790565b9094939291612ab6612de0565b6040517f0787c1fe00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff91906020816024817f000000000000000000000000feb516d9d946dd487a9346f6fee11f40c6945ee487165afa908115610e1a575f91612c05575b5015611a5257612b85612b6b61012085013560601c73ffffffffffffffffffffffffffffffffffffffff165f52600560205260405f2090565b5473ffffffffffffffffffffffffffffffffffffffff1690565b91821615612bdb57612a62612bd297612bca612bc261072f8673ffffffffffffffffffffffffffffffffffffffff165f52600460205260405f2090565b953690611700565b923691611643565b906106d1612dfe565b60046040517f816fefa2000000000000000000000000000000000000000000000000000000008152fd5b612c1e915060203d602011611aa457611a968183611592565b5f612b32565b51906106d182610cb9565b51906106d1826116c2565b51906106d1826116e7565b519060ff8216820361023e57565b908161020091031261023e57612c67611622565b90612c718161203b565b8252612c7f6020820161203b565b6020830152612c906040820161203b565b6040830152612ca160608201612c24565b6060830152612cb260808201612c2f565b6080830152612cc360a08201612c24565b60a0830152612cd460c08201612c24565b60c0830152612ce560e08201612c3a565b60e0830152610100612cf8818301612c24565b90830152610120612d0a818301612c3a565b908301526101408082015190830152610160808201519083015261018080820151908301526101a080820151908301526101c0612d48818301612c45565b908301526101e0809101519082015290565b5f6101e0612d66611622565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e08201528261010082015282610120820152826101408201528261016082015282610180820152826101a0820152826101c082015201526109c1612dd1613b47565b60208082518301019101612c53565b63929eee14805c612df1576001905d565b637fa8a9875f526004601cfd5b5f63929eee145d565b909169ffffffffffffffffffff1615159061ffff73ffffffffffffffffffffffffffffffffffffffff809216159416928315159485612ed3575b8515612eb8575b508415612e97575b5050508115612e8b575b50612e6157565b60046040517f6d24edae000000000000000000000000000000000000000000000000000000008152fd5b6103e89150115f612e5a565b929350909182612ead575b5050905f8080612e50565b161590505f80612ea2565b838092965091612ecb575b50935f612e48565b90505f612ec3565b945084612e41565b92916001612f078573ffffffffffffffffffffffffffffffffffffffff165f52600460205260405f2090565b015460ff8116156108035760081c60ff161561309857605f612f473373ffffffffffffffffffffffffffffffffffffffff165f52600160205260405f2090565b54916040519281873b95847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8089016001898d3c8888019033908201526040601f82015283603f82015201373360601b17930101905ff591821561308b576106d190612fda84612fd53373ffffffffffffffffffffffffffffffffffffffff165f52600160205260405f2090565b61248c565b6040805173ffffffffffffffffffffffffffffffffffffffff8681168252831660208201527fa1d2f67e073e80e6ec12790c669d64ea9a5dbe85ed539a27549f7e447c480dfe9190a161304b8473ffffffffffffffffffffffffffffffffffffffff165f52600560205260405f2090565b9073ffffffffffffffffffffffffffffffffffffffff167fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055565b63301164255f526004601cfd5b60046040517f0e8dc677000000000000000000000000000000000000000000000000000000008152fd5b9081602091031261023e575190565b906109c1949273ffffffffffffffffffffffffffffffffffffffff80921683521660208201526080604082015261312160808201845173ffffffffffffffffffffffffffffffffffffffff169052565b6020830151613175613141610140928360a08601526101c0850190610631565b60408601517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff808583030160c0860152610631565b60608501516fffffffffffffffffffffffffffffffff1660e0840152936131fa60808201516131ad610100918287019061ffff169052565b6131da60a0840151946131c9610120968789019061ffff169052565b60c085015163ffffffff1690870152565b60e083015161ffff1661016086015282015163ffffffff16610180850152565b01516101a08201526060818403910152610631565b805191908290602001825e015f815290565b6106d19061324361323d9493604051958693602085019061320f565b9061320f565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101845283611592565b96959373ffffffffffffffffffffffffffffffffffffffff6132c66101209a959d9c9b97946132b86fffffffffffffffffffffffffffffffff958c6101408091528d0190610631565b908b820360208d0152610631565b9c16604089015216606087015261ffff928380921660808801521660a086015263ffffffff80941660c08601521660e0840152166101008201520152565b9293909695919461337d602061332e865173ffffffffffffffffffffffffffffffffffffffff1690565b6040517fb0018c6000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909116600482015291829081906024820190565b038173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000feb516d9d946dd487a9346f6fee11f40c6945ee4165afa908115610e1a575f91613b28575b50613afe5761012084015160601c92338360601c148015613ad4575b15613aaa57613421613408875173ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff8316908114801590613a78575b613a4e57613a1a575b505061350060206134c97fc152ead6073d54f964e3c2fd317ec6c774e67465cf3e6fb9551badb88a09e43f847f0000000000000000000000ffdd7dd3b5076cf89440d05585ff56d246386207be929190604051935f5260205260405273ffffffffffffffffffffffffffffffffffffffff6055600b201691604052565b98604051809381927f28fd0307000000000000000000000000000000000000000000000000000000008352888d33600486016130d1565b03815f73ffffffffffffffffffffffffffffffffffffffff88165af1908115610e1a575f916139eb575b50610120840152825173ffffffffffffffffffffffffffffffffffffffff1661355290613cae565b90602084015184516135779073ffffffffffffffffffffffffffffffffffffffff1690565b61358090613e5b565b61358991613221565b94604085015185516135ae9073ffffffffffffffffffffffffffffffffffffffff1690565b6135b790613fb6565b6135c091613221565b9285516135e09073ffffffffffffffffffffffffffffffffffffffff1690565b9560c08301516136039073ffffffffffffffffffffffffffffffffffffffff1690565b60409093015161ffff1660608201516fffffffffffffffffffffffffffffffff16608083015161ffff1660a084015161ffff169060c08501516136499063ffffffff1690565b9260e086015161365a9061ffff1690565b9461010087015161366e9063ffffffff1690565b9661012001519861367d611622565b33815273ffffffffffffffffffffffffffffffffffffffff9e8f1660208201529d1660408e015261ffff1660608d01526fffffffffffffffffffffffffffffffff1660808c015261ffff1660a08b015261ffff1660c08a015263ffffffff1660e089015261ffff1661010088015263ffffffff166101208701525f6101408701819052610160870181905261018087018190526101a087015260ff166101c08601526101e085015261372e85613ce2565b61016086015261014085015261374382613ce2565b6101a086015261018085015261375884613d0d565b873b6139c157613788907f000000000000000000000000ac3216fa28f81b8fae150fb5626ca79c7a570daf614157565b5073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000feb516d9d946dd487a9346f6fee11f40c6945ee4163b1561023e576040517fa79b9ec900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff88166004820152905f82806024810103818373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000feb516d9d946dd487a9346f6fee11f40c6945ee4165af1908115610e1a577f6f8c7c94fc16393d1ebec38de9899ba8c6bd860a025aa60063b7cf4c40a16c09946139118a612fd573ffffffffffffffffffffffffffffffffffffffff976138ed83612fd58e829b6139a39b6139a8575b505f7f78cf023adbf9fec5dbd8e980a6a3526d1d11c66c894ab342ade9ace71f5619045d73ffffffffffffffffffffffffffffffffffffffff165f52600260205260405f2090565b73ffffffffffffffffffffffffffffffffffffffff165f52600360205260405f2090565b602081015173ffffffffffffffffffffffffffffffffffffffff1660808201516fffffffffffffffffffffffffffffffff1660a083015161ffff1660c084015161ffff169061396760e086015163ffffffff1690565b9261397861010087015161ffff1690565b946101e061398e61012089015163ffffffff1690565b970151978b6040519c8d9c169f169d8b61326f565b0390a3565b806139b56139bb92611561565b80610234565b5f6138a5565b60046040517f0313b285000000000000000000000000000000000000000000000000000000008152fd5b613a0d915060203d602011613a13575b613a058183611592565b8101906130c2565b5f61352a565b503d6139fb565b613a4791613a3f60c088015173ffffffffffffffffffffffffffffffffffffffff1690565b903390613c59565b5f8061344c565b60046040517f36a9d011000000000000000000000000000000000000000000000000000000008152fd5b50613aa2613a93602089015169ffffffffffffffffffff1690565b69ffffffffffffffffffff1690565b821415613443565b60046040517f861f5c0b000000000000000000000000000000000000000000000000000000008152fd5b507fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008316156133e2565b60046040517f47426645000000000000000000000000000000000000000000000000000000008152fd5b613b41915060203d602011611aa457611a968183611592565b5f6133c6565b604051905f82525f7f78cf023adbf9fec5dbd8e980a6a3526d1d11c66c894ab342ade9ace71f561904805c9060018260011c9160018416938415613c4f575b6020948585108114613c3e57848952908115613c035750600114613bae575b50505050604052565b5f908152929350837f810543fe2cb308dcc7090dc0718da3cf7b1ea9e6ee6878e7d574d84a057628975b838510613bef57505050508301015f808080613ba5565b805c88860183015293019284908201613bd8565b93505050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff009192501690830152604082015f808080613ba5565b602286634e487b715f52526024601cfd5b92607f1692613b86565b601c5f60649281946020966040519860605260405260601b602c526f23b872dd000000000000000000000000600c525af13d1560015f5114171615613ca1575f606052604052565b637939f4245f526004601cfd5b5f6004601c60209363313ce56784525afa6101005f511060203d14161615613cd5575f5190565b633394d1705f526004601cfd5b90603f825111613d0057601f82015191603f601f8251119101510290565b6319a65cb65f526004601cfd5b604051815173ffffffffffffffffffffffffffffffffffffffff1660208201526106d191602081015173ffffffffffffffffffffffffffffffffffffffff166040830152604081015173ffffffffffffffffffffffffffffffffffffffff166060830152606081015161ffff16608083015260808101516fffffffffffffffffffffffffffffffff1660a083015260a081015161ffff1660c083015260c081015161ffff1660e083015260e0810151613dd1610100918285019063ffffffff169052565b810151613de7610120918285019061ffff169052565b810151613dff610140918285019063ffffffff169052565b810151610160908184015281015161018090818401528101516101a090818401528101516101c0908184015281015190613e416101e0928385019060ff169052565b015161020090818301528152613e5681611575565b614098565b5f6004601c82936306fdde0384525afa3d6020149015605f3d118217158117613f8b575015613f1a5760205f803e6109c15f519060018219018216916007836fffffffffffffffffffffffffffffffff10811b821560081b1784811c67ffffffffffffffff1060061b1784811c63ffffffff1060051b177e1f0d1e100c1d070f090b19131c1706010e11080a1a141802121b1503160405601f6040519660408801604052831c63d76453e004161a1760ff030160031c83526020830152565b60405190602063ffffffe07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3d01168084016040527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03d0182853e013d18613f7e57565b634cb9c0005f526004601cfd5b613f9c57634cb9c0005f526004601cfd5b3d613fae57632ed09f545f526004601cfd5b3d5f803e3d5ffd5b5f6004601c82936395d89b4184525afa3d6020149015605f3d118217158117614075575015613f1a5760205f803e6109c15f519060018219018216916007836fffffffffffffffffffffffffffffffff10811b821560081b1784811c67ffffffffffffffff1060061b1784811c63ffffffff1060051b177e1f0d1e100c1d070f090b19131c1706010e11080a1a141802121b1503160405601f6040519660408801604052831c63d76453e004161a1760ff030160031c83526020830152565b61408657634cb9c0005f526004601cfd5b3d613fae57633ddcc60a5f526004601cfd5b805160208082109081156140e057506001146140b2575050565b60209060011b910151177f78cf023adbf9fec5dbd8e980a6a3526d1d11c66c894ab342ade9ace71f5619045d565b92600191507f78cf023adbf9fec5dbd8e980a6a3526d1d11c66c894ab342ade9ace71f56190483831b8301815d5f527f810543fe2cb308dcc7090dc0718da3cf7b1ea9e6ee6878e7d574d84a05762897905f915b84831061414357505050505050565b838691828585010151815d01920191614134565b6040518160017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83943b019384923c5ff590811561308b5756fea164736f6c6343000819000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000feb516d9d946dd487a9346f6fee11f40c6945ee4000000000000000000000000437e0551892c2c9b06d3ffd248fe60572e08cd1a000000000000000000000000ac3216fa28f81b8fae150fb5626ca79c7a570dafc152ead6073d54f964e3c2fd317ec6c774e67465cf3e6fb9551badb88a09e43f
-----Decoded View---------------
Arg [0] : archController_ (address): 0xfEB516d9D946dD487A9346F6fee11f40C6945eE4
Arg [1] : _sanctionsSentinel (address): 0x437e0551892C2C9b06d3fFd248fe60572e08CD1A
Arg [2] : _marketInitCodeStorage (address): 0xAc3216FA28F81B8FaE150fB5626ca79C7a570DAf
Arg [3] : _marketInitCodeHash (uint256): 87442882014718392767687475768806239364207889234860621178338783312000729080895
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000feb516d9d946dd487a9346f6fee11f40c6945ee4
Arg [1] : 000000000000000000000000437e0551892c2c9b06d3ffd248fe60572e08cd1a
Arg [2] : 000000000000000000000000ac3216fa28f81b8fae150fb5626ca79c7a570daf
Arg [3] : c152ead6073d54f964e3c2fd317ec6c774e67465cf3e6fb9551badb88a09e43f
Deployed Bytecode Sourcemap
960:23507:1:-: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;:::-;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;-1:-1:-1;;960:23507:1;;;;;;;:::i;:::-;15188:25;;:::i;:::-;15239:9;;;960:23507;;;;;15283:19;;;;960:23507;15254:26;;;960:23507;15337:19;;;;960:23507;15308:26;;;960:23507;15393:21;;;;960:23507;15362:28;;;960:23507;15451:21;;;;960:23507;15420:28;;;960:23507;15500:12;;;;960:23507;15500:12;;15337:19;15393:21;960:23507;;;;15239:9;15478:19;;960:23507;;;;;;;15518:19;;;960:23507;15254:26;15584:16;;960:23507;;;;;15558:23;;;960:23507;;15628:17;960:23507;15606:19;;;;960:23507;;;;15606:19;15362:28;15679:18;;960:23507;;;;;15651:25;;;;960:23507;;;;15651:25;15308:26;15732:19;;960:23507;;;;;15703:26;;;960:23507;15420:28;15789:22;;960:23507;;;;;15757:29;;;960:23507;15518:19;15849:22;;960:23507;;;;;15817:29;;;960:23507;15558:23;15914:27;;960:23507;;;;;15877:34;;;960:23507;15977:20;;960:23507;;;;;15947:27;;;960:23507;16039:26;;960:23507;;;;;16003:33;;;;960:23507;;;;16003:33;960:23507;16099:15;960:23507;16071:25;;;960:23507;;;;;16120:24;;;960:23507;16187:9;960:23507;16168:16;;;960:23507;15254:26;960:23507;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;960:23507:1;;;;;;;;;;;:::o;:::-;;;;;-1:-1:-1;;960:23507:1;;;;;2170:129;;;;;;;;;960:23507;;;;;;;:::o;:::-;;;;;;;:::i;:::-;:::o;:::-;;;;;;:::i;:::-;;;;;-1:-1:-1;;960:23507:1;;;;;;;;;;;:::i;:::-;1258:92:3;;:::i;:::-;960:23507:1;22752:31;;960:23507;;;;;;;;;;;;22752:31;960:23507;:::i;:::-;22794:14;22793:15;960:23507;22794:14;;;960:23507;;;;;;22793:15;;960:23507;22793:15;22789:51;;22875:38;;960:23507;;;;22875:23;960:23507;;;;;;;22875:38;960:23507;23114:23;960:23507;;23114:23;;960:23507;;;;;;23143:621;23114:23;23143:621;;23114:23;23143:621;;23114:23;23143:621;;;;960:23507;23143:621;;;;;;;-1:-1:-1;23789:9:1;;;;;;1315:1:3;;:::i;:::-;960:23507:1;23800:3;-1:-1:-1;23830:29:1;23867:243;23830:29;;960:23507;23830:29;;;;:::i;:::-;960:23507;;;;;;;;;;;23867:243;;;;;960:23507;;23774:13;;23867:243;;;;-1:-1:-1;23867:243:1;;22789:51;960:23507;;;22817:23;;;;960:23507;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;960:23507:1;;;;;;;;;;:::i;:::-;;;;;-1:-1:-1;960:23507:1;9858:23;960:23507;;;-1:-1:-1;960:23507:1;;;;;;;;;;;;;;;-1:-1:-1;960:23507:1;;-1:-1:-1;960:23507:1;;-1:-1:-1;960:23507:1;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::o;:::-;;;;;-1:-1:-1;;960:23507:1;;;;;;;;;;;:::i;:::-;;;;;;;;;:::i;:::-;-1:-1:-1;960:23507:1;;-1:-1:-1;960:23507:1;;;;-1:-1:-1;960:23507:1;;;;-1:-1:-1;960:23507:1;;;;-1:-1:-1;960:23507:1;;;;-1:-1:-1;960:23507:1;;;;-1:-1:-1;960:23507:1;;;;;;;;;;-1:-1:-1;960:23507:1;;;;;;;-1:-1:-1;960:23507:1;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;;;;;-1:-1:-1;;960:23507:1;;;;;;;;;;;:::i;:::-;;;;;-1:-1:-1;960:23507:1;3133:107;960:23507;;;-1:-1:-1;960:23507:1;;;;;;;;;;-1:-1:-1;;960:23507:1;;;;;;;;;;;:::i;:::-;;;;;;;;:::o;:::-;;;;;;;:::i;:::-;1258:92:3;;:::i;:::-;960:23507:1;22752:31;;960:23507;;;;;;;;;;;;;22794:14;22793:15;960:23507;22794:14;;;960:23507;;;;;22793:15;22789:51;;23114:23;23003:33;22875:38;22936:45;22875:38;960:23507;22875:38;960:23507;;;;22875:23;960:23507;;;;;;;22875:38;960:23507;;;22936:45;2458:93:12;;;;1275:5;;2458:93;;1188:104;;22936:45:1;23003:33;:::i;:::-;23114:23;;960:23507;;;;;;23143:621;23114:23;23143:621;;23114:23;23143:621;;23114:23;23143:621;;;;;;;;;;;;23774:13;-1:-1:-1;23789:9:1;;;;;;1315:1:3;;:::i;23800:3:1:-;-1:-1:-1;23838:20:1;23867:243;23838:20;;960:23507;23830:29;23838:20;;;;:::i;:::-;23830:29;;:::i;960:23507::-;23867:243;;;;;960:23507;;23774:13;;23867:243;960:23507;23867:243;;-1:-1:-1;23867:243:1;;960:23507;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;:::o;:::-;;;;;;;;;;;:::o;:::-;;;;;;;:::o;:::-;;;;;;:::i;:::-;;;;;-1:-1:-1;;960:23507:1;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;:::i;:::-;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;5341:47;;960:23507;5364:15;960:23507;5364:15;;;960:23507;5341:47;;;;;;;-1:-1:-1;5341:47:1;;;960:23507;;;5327:10;:61;5323:119;;5447:1;;;:::i;5323:119::-;960:23507;;;5405:30;;;;5341:47;;;;960:23507;5341:47;960:23507;5341:47;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;;;;;:::i;960:23507::-;;;;;-1:-1:-1;;960:23507:1;;;;;;;;;1341:55;960:23507;;;;;;;;;-1:-1:-1;;960:23507:1;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;960:23507:1;;;;;;;;;;;:::i;:::-;;-1:-1:-1;960:23507:1;;;;;;9083:38;960:23507;-1:-1:-1;960:23507:1;9083:38;960:23507;;;;;;;;;;;;;;;;-1:-1:-1;;960:23507:1;;;;;;4098:15;960:23507;4075:73;;;;;960:23507;;;;;;4075:73;;;;960:23507;4075:73;;4142:4;960:23507;4075:73;;960:23507;4075:73;;;;;;;;960:23507;;;4075:73;;;;;:::i;960:23507::-;;;;;-1:-1:-1;;960:23507:1;;;;;;;;;1458:51;960:23507;;;;;;;;;;-1:-1:-1;;960:23507:1;;;;;;;;;;:::i;:::-;;;;;-1:-1:-1;960:23507:1;14243:23;960:23507;;;-1:-1:-1;960:23507:1;;;;;;;;;;;;;;;-1:-1:-1;960:23507:1;;-1:-1:-1;960:23507:1;;-1:-1:-1;960:23507:1;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;960:23507:1;;;;;;;;;;:::i;:::-;;3020:15:18;960:23507:1;3006:10:18;:29;3002:82;;960:23507:1;;;;11890:47:18;;-1:-1:-1;416:167:17;960:23507:1;416:167:17;;;-1:-1:-1;416:167:17;960:23507:1;3002:82:18;109:63:16;-1:-1:-1;109:63:16;960:23507:1;109:63:16;;960:23507:1;;;;;-1:-1:-1;;960:23507:1;;;;;;;;;4237:15;960:23507;;;;;;;;;;-1:-1:-1;;960:23507:1;;;;;;;;;;:::i;:::-;;;;;-1:-1:-1;960:23507:1;11487:25;960:23507;11487:25;960:23507;;;-1:-1:-1;960:23507:1;;;;;;;;;;;;;;;-1:-1:-1;960:23507:1;;-1:-1:-1;960:23507:1;;-1:-1:-1;960:23507:1;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;960:23507:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;-1:-1:-1;960:23507:1;14481:23;960:23507;;;-1:-1:-1;960:23507:1;;;;2458:93:12;;;;;1275:5;;2458:93;;960:23507:1;;;;;;;;14610:20;;;:::i;:::-;14641:13;-1:-1:-1;14656:9:1;;;;;;960:23507;;;;;;;:::i;14667:3::-;960:23507;;;;;;;;;14680:27;960:23507;14689:18;960:23507;14689:18;;;:::i;960:23507::-;14680:27;;;;:::i;:::-;960:23507;;;;;;14680:27;960:23507;14641:13;;960:23507;;:::i;:::-;;;;;-1:-1:-1;;960:23507:1;;;;;;;;;;:::i;:::-;;;;;;:::i;:::-;;;;;;:::i;:::-;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;5341:47;;960:23507;5364:15;960:23507;5364:15;;;960:23507;5341:47;;;;;;;-1:-1:-1;5341:47:1;;;960:23507;;;5327:10;:61;5323:119;;5447:1;;;:::i;5341:47::-;;;;960:23507;5341:47;960:23507;5341:47;;;;;;;:::i;:::-;;;;960:23507;;;;;-1:-1:-1;;960:23507:1;;;;;;;;;;:::i;:::-;;;;;5341:47;;960:23507;5364:15;960:23507;5364:15;;;960:23507;5341:47;;;;;;;-1:-1:-1;5341:47:1;;;960:23507;;;5327:10;:61;5323:119;;5447:1;;;:::i;5341:47::-;;;;960:23507;5341:47;960:23507;5341:47;;;;;;;:::i;:::-;;;;960:23507;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;:::i;:::-;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;:::i;:::-;;;;1148:88;960:23507;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;-1:-1:-1;960:23507:1;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;:::o;:::-;;;;;;:::i;:::-;;;;;;;:::o;:::-;;;;;;:::i;:::-;;;;;;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::o;:::-;;;;;-1:-1:-1;;960:23507:1;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;21612:21;960:23507;;;;;;:::i;:::-;;;;:::i;:::-;;;;;;;21612:21;;:::i;:::-;960:23507;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;960:23507:1;;;;;;;;1401:52;960:23507;;;;;;;;-1:-1:-1;;960:23507:1;;;;;2250:561:10;;;16345:16:1;2250:561:10;;960:23507:1;;;2250:561:10;;;16369:18:1;2250:561:10;;;;;;;;;;;;;960:23507:1;;;;;;;;-1:-1:-1;;960:23507:1;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;:::i;:::-;1258:92:3;;;;;:::i;:::-;960:23507:1;;;11161:72;;11222:10;960:23507;11161:72;;960:23507;;;;;11184:15;960:23507;;11161:72;;;;;;;-1:-1:-1;11161:72:1;;;960:23507;11160:73;;11156:122;;960:23507;11299:52;;;;:::i;:::-;1315:1:3;;:::i;:::-;960:23507:1;;;;;;;;;;;;;;;;11156:122;960:23507;;;11250:21;;;;11161:72;;;;960:23507;11161:72;960:23507;11161:72;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;;;960:23507;;;;;-1:-1:-1;;960:23507:1;;;;;-1:-1:-1;960:23507:1;;;;;1275:5:12;;;2458:93;;;;;;;960:23507:1;;;;;;;;;9489:20;;;:::i;:::-;9520:13;-1:-1:-1;9535:9:1;;;;;;960:23507;;;;;;;:::i;9546:3::-;960:23507;;;;;;;;;;;;;;;9559:35;960:23507;;;-1:-1:-1;960:23507:1;;;;;;;;;;9559:35;;;;:::i;:::-;960:23507;9520:13;;960:23507;;:::i;:::-;;;;;-1:-1:-1;;960:23507:1;;;;;;;;;;;:::i;:::-;;-1:-1:-1;960:23507:1;11654:25;960:23507;;;;-1:-1:-1;960:23507:1;;;;;;;;;;;;;-1:-1:-1;;960:23507:1;;;;;;;;;;;:::i;:::-;;;;;-1:-1:-1;960:23507:1;11804:27;960:23507;;;-1:-1:-1;960:23507:1;;;11804:56;;960:23507;;;;;;;;;;;-1:-1:-1;;960:23507:1;;;;;;;;;;;:::i;:::-;;-1:-1:-1;960:23507:1;10486:23;960:23507;;;;-1:-1:-1;960:23507:1;;;;;;;;;;;;;-1:-1:-1;;960:23507:1;;;;;;;;;;;;;;;;;;-1:-1:-1;;960:23507:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;20676:14;960:23507;;;;;;:::i;:::-;;;;;;;;;:::i;:::-;;;;;;;;;20676:14;:::i;960:23507::-;;;;;;;;:::i;:::-;;;;;;-1:-1:-1;960:23507:1;10096:23;960:23507;;;-1:-1:-1;960:23507:1;;;;2458:93:12;;;;;1275:5;;2458:93;;960:23507:1;;;;;;;;10248:20;;;:::i;:::-;10279:13;-1:-1:-1;10294:9:1;;;;;;960:23507;;;;;;;:::i;10305:3::-;960:23507;;;;;;;;;10318:27;960:23507;10327:18;960:23507;10327:18;;;:::i;10318:27::-;960:23507;10279:13;;960:23507;;;;;-1:-1:-1;;960:23507:1;;;;;;;;;;;:::i;:::-;;-1:-1:-1;960:23507:1;14848:23;960:23507;;;;-1:-1:-1;960:23507:1;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;960:23507:1;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;960:23507:1;;;;;;;;-1:-1:-1;;960:23507:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;960:23507:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;-1:-1:-1;960:23507:1;;-1:-1:-1;960:23507:1;;;-1:-1:-1;960:23507:1;:::o;:::-;;;;;;:::i;:::-;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;:::o;:::-;-1:-1:-1;960:23507:1;;-1:-1:-1;960:23507:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;-1:-1:-1;960:23507:1;;;;;;;;;-1:-1:-1;960:23507:1;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;-1:-1:-1;960:23507:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;6451:15;960:23507;;;;;;;;;;;6451:15;960:23507;;;;;;;;6451:15;960:23507;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;5707:986::-;;;;;;;;;5962:38;;:31;;960:23507;;;;;;;;;;;;5962:31;:38;960:23507;;;;;5962:38;5958:94;;6128:15;6533:155;6128:15;;;;;6533:155;6128:15;;:::i;:::-;960:23507;6444:30;6451:15;960:23507;;;;;6444:30;6184:297;960:23507;;:::i;:::-;;;;;;6184:297;960:23507;;;6184:297;;;960:23507;;;;6184:297;;;960:23507;5962:38;6184:297;;;960:23507;5962:38;6184:297;;;960:23507;;;6184:297;;;960:23507;;6184:297;960:23507;;;6184:297;;;960:23507;;;;;;:::i;:::-;6184:297;;;960:23507;6150:31;;960:23507;;;;;;;;;;;;6150:31;960:23507;:::i;:::-;6487:35;;;:::i;:::-;6184:297;960:23507;6533:155;;;;;:::i;:::-;;;;5707:986::o;5958:94::-;5962:16;960:23507;;6017:28;;;;960:23507;;;;;;;;;;;:::o;:::-;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;:::i;:::-;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;:::o;7589:853::-;;;;;;960:23507;;;;;;-1:-1:-1;960:23507:1;7826:16;960:23507;;;7826:38;960:23507;-1:-1:-1;960:23507:1;7826:38;960:23507;;7825:39;7821:90;;7987:15;;;960:23507;7987:15;;;;8288:149;7987:15;960:23507;7987:15;960:23507;7987:15;;:::i;:::-;960:23507;-1:-1:-1;960:23507:1;7826:16;960:23507;;8235:42;960:23507;;-1:-1:-1;960:23507:1;8079:36;:21;7826:38;8079:21;;960:23507;;;;;;;;;;;;;;;8079:36;960:23507;;;;;;;;;;;;;;;;;;;;;;;;8235:42;960:23507;;;;;;;;;;;;;;;;;;;;;;;;;8288:149;7589:853::o;8446:363::-;960:23507;;;-1:-1:-1;960:23507:1;8552:16;960:23507;;;8552:38;960:23507;-1:-1:-1;960:23507:1;8552:38;960:23507;;8551:39;8547:90;;960:23507;;8768:36;960:23507;-1:-1:-1;960:23507:1;8552:16;960:23507;;8552:38;960:23507;-1:-1:-1;960:23507:1;8642:39;960:23507;;;;;;;;;;;8768:36;8446:363::o;1258:92:3:-;;;;;;;;;;;;;:::i;:::-;960:23507:1;;;21646:72;;21707:10;21646:72;;;960:23507;21646:72;960:23507;;;21669:15;960:23507;;21646:72;;;;;;;-1:-1:-1;21646:72:1;;;1258:92:3;21645:73:1;;21641:122;;960:23507;21807:31;;960:23507;;;;;;;;;;;;;21849:22;21848:23;960:23507;21849:22;;;960:23507;;;;;21848:23;21844:74;;21939:54;960:23507;21939:54;22080:165;21939:54;;;:::i;:::-;22018:16;;;960:23507;;22018:16;;;3087:198:19;;;;;;;960:23507:1;;;;;:::i;:::-;22080:165;;:::i;:::-;1315:1:3;;;;:::i;21646:72:1:-;;;;;;;;;;;;;;:::i;:::-;;;;960:23507;;;;;;;;;;;;;;;;;;:::o;1258:92:3:-;;;;;;;;:::i;:::-;960:23507:1;;;20703:72;;20764:10;20703:72;;;960:23507;;;;20703:72;960:23507;;;20726:15;960:23507;;20703:72;;;;;;;960:23507;20703:72;;;1258:92:3;20702:73:1;;20698:122;;20910:42;;20849:16;;;960:23507;6256:47:19;;960:23507:1;;;;20910:27;960:23507;;;;;;;20910:42;960:23507;;;;;20910:42;960:23507;;;20962:27;20958:78;;960:23507;21126:165;21080:31;960:23507;;21080:31;;960:23507;;;;;;;;;;;;;;;;;:::i;:::-;;;;;:::i;21126:165::-;1315:1:3;;;:::i;20958:78:1:-;20703:72;960:23507;;21006:23;;;;20703:72;;;;;;;;;;;;;;:::i;:::-;;;;1148:88;;;;;;:::i;:::-;;;;;;:::i;:::-;;;;;;:::i;:::-;;960:23507;;;;1148:88;;;;:::o;:::-;;;;;;;;;;;:::i;:::-;960:23507;;;;:::i;:::-;1148:88;;960:23507;1148:88;;;960:23507;:::i;:::-;1148:88;;;;960:23507;1148:88;;;960:23507;:::i;:::-;1148:88;;;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;:::o;4593:203::-;-1:-1:-1;960:23507:1;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4723:68;4734:27;;:::i;:::-;960:23507;;;;4723:68;;;;;;:::i;1745:595:3:-;1791:545;;;;;;;;1745:595::o;1791:545::-;;;;;;;2430:177;2478:125;;;2430:177::o;6697:596:1:-;;;960:23507;;6889:24;;960:23507;;;;;;6943:26;960:23507;;7057:19;;;;:39;;;;6697:596;7056:90;;;;6697:596;7056:146;;;;;6697:596;7056:179;;;;;;;6697:596;7045:244;;;6697:596::o;7045:244::-;7257:25;960:23507;;7257:25;;;;7056:179;7230:5;7212:23;;;7056:179;;;:146;7157:44;;-1:-1:-1;7157:44:1;;;;;7056:146;;;;;;;;;7157:44;960:23507;7006:33;;-1:-1:-1;7157:44:1;;;;7056:90;7108:37;;;;;;;;7056:90;;;;;;7108:37;;;;;;7057:39;;-1:-1:-1;7057:39:1;;;11869:1990;;;12088:15;12046:31;;960:23507;;;;;;;;;;;;12046:31;12088:15;960:23507;;;;12087:16;12083:67;;960:23507;;;;12159:17;12155:72;;12331:1334;12263:37;12289:10;960:23507;;;;12088:15;960:23507;;;;;;;12263:37;960:23507;12331:1334;;;;;;;;;;;;;12088:15;12331:1334;;;;;;12289:10;;12331:1334;;;;;;;;;;;;;;;;12289:10;12331:1334;;;;;;;-1:-1:-1;12331:1334:1;;;;;;13796:58;12289:10;13670:57;12289:10;13670:37;12289:10;960:23507;;;;12088:15;960:23507;;;;;;;13670:37;:57;:::i;:::-;12331:1334;960:23507;;;;;;;;;;;;;;13739:51;;12331:1334;13739:51;13796:42;;960:23507;;;;20910:27;960:23507;;;;;;;13796:42;960:23507;;;;;;;;;;;12331:1334;;-1:-1:-1;12331:1334:1;12046:16;12331:1334;;12155:72;12046:16;960:23507;;12193:27;;;;960:23507;;;;;;;;;1148:88;960:23507;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;:::i;:::-;;;:::i;:::-;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;17317:3130::-;;;;;;;;17612:76;;960:23507;;;;;;;;;;;17612:76;;960:23507;;;;17612:76;;;960:23507;;;;;;;;;;;17612:76;;17635:15;960:23507;17635:15;960:23507;17612:76;;;;;;;17671:16;17612:76;;;17317:3130;17608:122;;;17759:16;;;960:23507;6256:47:19;;17829:10:1;;960:23507;;;17803:36;:67;;;;17317:3130;17801:70;17797:124;;17938:58;960:23507;;;;;;;;;;;;17938:58;960:23507;;;17938:58;;;;;:128;;;17317:3130;17927:181;;18114:186;;17317:3130;18381:18;;18426:109;17612:76;18315:85;18381:18;18357:16;;2089:726:10;;;2250:561;;;;;;;;;;;;;;;;;2089:726;18315:85:1;960:23507;;;18426:109;;;;960:23507;18426:109;;17829:10;;;17612:76;18426:109;;;:::i;:::-;;960:23507;17671:16;960:23507;;;18426:109;;;;;;;17671:16;18426:109;;;17317:3130;-1:-1:-1;17759:16:1;;;960:23507;;;;;18558:27;;;:::i;:::-;18627:21;17612:76;18627:21;;;960:23507;;;;;;;;;7737:59:9;;;:::i;:::-;18613:61:1;;;:::i;:::-;18717:23;960:23507;18717:23;;;960:23507;;;;;;;;;8183:59:9;;;:::i;:::-;18703:65:1;;;:::i;:::-;960:23507;;;;;;;;;;19091:28;;;;960:23507;;;;;;;;;19144:31;;;960:23507;;;;19199:25;;960:23507;;;19252:29;;;960:23507;;;19309:29;;;960:23507;;;19371:34;19091:28;19371:34;;960:23507;;;;;;;;19431:27;960:23507;19431:27;;960:23507;;;;;;;;19490:33;;;;960:23507;;;;;;;;17759:16;;;960:23507;;;;:::i;:::-;17829:10;960:23507;;;;;;17612:76;18814:747;;960:23507;;;;18814:747;;960:23507;;;;18814:747;;960:23507;;;19252:29;18814:747;;960:23507;;;19309:29;18814:747;;960:23507;;;19091:28;18814:747;;960:23507;;;;18814:747;;960:23507;;;19490:33;18814:747;;960:23507;;;17759:16;18814:747;;960:23507;17671:16;18814:747;;;960:23507;;;18814:747;;;960:23507;;;18814:747;;;960:23507;;;18814:747;;;960:23507;;;18814:747;;;960:23507;18814:747;;;960:23507;19620:17;;;:::i;:::-;18814:747;;;960:23507;18814:747;;;960:23507;19694:19;;;:::i;:::-;18814:747;;;960:23507;18814:747;;;960:23507;19750:3;;;:::i;:::-;19765:18;;19761:72;;3643:51:10;19882:21:1;;3643:51:10;:::i;:::-;;960:23507:1;17635:15;960:23507;19917:62;;;;960:23507;;;19917:62;;960:23507;;;17612:76;19917:62;;960:23507;;17671:16;960:23507;;;;;19917:62;17635:15;;960:23507;17635:15;960:23507;19917:62;;;;;;;20144:298;19917:62;20081:51;19917:62;20081:38;960:23507;19917:62;20024:51;19917:62;20024:38;19917:62;;;20144:298;19917:62;;;17317:3130;3933:47:20;17671:16:1;960:23507;3933:47:20;960:23507:1;;;;22875:23;960:23507;;;;;;;20024:51;960:23507;;;;20081:23;960:23507;;;;;;;20081:51;17612:76;18814:747;;960:23507;;;19252:29;18814:747;;960:23507;;;19309:29;18814:747;;960:23507;;;19091:28;18814:747;;960:23507;;;18814:747;960:23507;;18814:747;;960:23507;;;;;;18814:747;960:23507;19490:33;18814:747;;960:23507;;;;;;18814:747;;960:23507;17759:16;18814:747;;960:23507;;;;;;18814:747;;960:23507;;;;;;;;;;;20144:298;;;:::i;:::-;;;;17317:3130::o;19917:62::-;;;;;;:::i;:::-;;;:::i;:::-;;;;19761:72;17612:76;960:23507;;19805:21;;;;18426:109;;;;17612:76;18426:109;17612:76;18426:109;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;;;18114:186;18265:20;18227:28;960:23507;18227:28;;;960:23507;;;;;;17829:10;;18265:20;;:::i;:::-;18114:186;;;;17927:181;17612:76;960:23507;;18088:13;;;;17938:128;18030:36;18006:60;960:23507;17612:76;18030:36;;960:23507;;;;;;;;;;18006:60;;;;17938:128;;17797:124;17612:76;960:23507;;17888:26;;;;17803:67;960:23507;;;;17843:27;17803:67;;17608:122;17612:76;960:23507;;17705:18;;;;17612:76;;;;;;;;;;;;;;:::i;:::-;;;;2297:343:20;2419:97;;;-1:-1:-1;2419:97:20;;-1:-1:-1;960:23507:1;802:1487:20;;;;;;;;;;;;;;;;2297:343;802:1487;;;;;;;;;;;;;;;;;2419:97;802:1487;2419:97;;;802:1487;2589:47;;;;2419:97;2589:47;2297:343::o;802:1487::-;-1:-1:-1;802:1487:20;;;;;-1:-1:-1;802:1487:20;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2419:97;802:1487;;;;;;;;;;;;-1:-1:-1;802:1487:20;;;;;;;;;;;;2042:1017:9;2179:876;;;2042:1017;;;2179:876;2042:1017;2179:876;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2042:1017::o;2179:876::-;;;;;;;6547:818;6626:735;;;;6547:818;6626:735;;;;;;;;;;;;;;;;;;;6547:818;:::o;6626:735::-;;;;;;;16665:648:1;;16764:545;;;;;;;;;;;;;;;;;;;;16665:648;:::o;16764:545::-;;;;;;;4880:148;960:23507;;;;;;5000:22;;;960:23507;5000:22;;;960:23507;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5000:22;;;;;:::i;:::-;;:::i;513:2279:14:-;-1:-1:-1;706:997:14;;513:2279;;7773:10:9;706:997:14;;;;;;;;;;;;;;;;;;;-1:-1:-1;1706:1084:14;;;706:997;-1:-1:-1;1746:79:14;;1836:22;-1:-1:-1;1746:79:14;186:325;2602:591:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;383:126:14;;;;;;;;2602:591:0;;;;;;;316:3:14;960:23507:1;;;;383:126:14;;;;;;186:325;1706:1084;1935:851;;;706:997;1935:851;;;;;;;;;;;;;;;;;;;;;513:2279::o;1935:851::-;;-1:-1:-1;1935:851:14;706:997;;1935:851;706:997;;;;-1:-1:-1;706:997:14;;;;;;;;7785:10:9;-1:-1:-1;706:997:14;;;;;;-1:-1:-1;706:997:14;;;-1:-1:-1;706:997:14;513:2279;-1:-1:-1;706:997:14;;513:2279;;8219:10:9;706:997:14;;;;;;;;;;;;;;;;;;;-1:-1:-1;1706:1084:14;;;706:997;-1:-1:-1;1746:79:14;;1836:22;-1:-1:-1;1746:79:14;186:325;2602:591:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;383:126:14;;;;;;;;2602:591:0;;;;;;;316:3:14;960:23507:1;;;;383:126:14;;;;;;186:325;706:997;;;;-1:-1:-1;706:997:14;;;;;;;;8231:10:9;-1:-1:-1;706:997:14;;;;2875:986:20;2968:889;;;;;;;;;;;;;;;;2875:986;;:::o;2968:889::-;;;;;;;;;960:23507:1;2968:889:20;2875:986::o;2968:889::-;;;;-1:-1:-1;960:23507:1;2968:889:20;;;;;960:23507:1;2968:889:20;;;;;;;;;;;;;;;;;2875:986;;:::o;2968:889::-;;;;;;;;;;;;;;;;;;3703:534:10;3852:381;;;;;;;;;;;;;17671:16:1;3852:381:10;;;;;;3703:534::o
Swarm Source
none
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.