Source Code
Overview
ETH Balance
More Info
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 25 internal transactions (View All)
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
12092583 | 13 secs ago | 0 ETH | ||||
12092550 | 1 min ago | 0 ETH | ||||
12092534 | 1 min ago | 0 ETH | ||||
12092532 | 1 min ago | 0 ETH | ||||
12092437 | 5 mins ago | 0 ETH | ||||
12092418 | 5 mins ago | 0 ETH | ||||
12092410 | 5 mins ago | 0 ETH | ||||
12092359 | 7 mins ago | 0 ETH | ||||
12092294 | 10 mins ago | 0 ETH | ||||
12092273 | 10 mins ago | 0 ETH | ||||
12092204 | 13 mins ago | 0 ETH | ||||
12092170 | 14 mins ago | 0 ETH | ||||
12092159 | 14 mins ago | 0 ETH | ||||
12092129 | 15 mins ago | 0 ETH | ||||
12092129 | 15 mins ago | 0 ETH | ||||
12092129 | 15 mins ago | 0 ETH | ||||
12092129 | 15 mins ago | 0 ETH | ||||
12092115 | 16 mins ago | 0 ETH | ||||
12092115 | 16 mins ago | 0 ETH | ||||
12092115 | 16 mins ago | 0 ETH | ||||
12092084 | 17 mins ago | 0 ETH | ||||
12092046 | 18 mins ago | 0 ETH | ||||
12091984 | 20 mins ago | 0 ETH | ||||
12091973 | 20 mins ago | 0 ETH | ||||
12091965 | 21 mins ago | 0 ETH |
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
mErc20Host
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 2499 runs
Other Settings:
london EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED pragma solidity =0.8.28; /* _____ _____ __ ____ _____ | | _ | | | \| _ | | | | | | |__| | | | |_|_|_|__|__|_____|____/|__|__| */ // interfaces import {Steel} from "risc0/steel/Steel.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; // contracts import {ZkVerifier} from "src/verifier/ZkVerifier.sol"; import {mErc20Upgradable} from "src/mToken/mErc20Upgradable.sol"; import {mTokenProofDecoderLib} from "src/libraries/mTokenProofDecoderLib.sol"; import {ImErc20Host} from "src/interfaces/ImErc20Host.sol"; import {ImTokenOperationTypes} from "src/interfaces/ImToken.sol"; import {IRoles} from "src/interfaces/IRoles.sol"; contract mErc20Host is mErc20Upgradable, ZkVerifier, ImErc20Host, ImTokenOperationTypes { using SafeERC20 for IERC20; // ----------- STORAGE ------------ mapping(uint32 => mapping(address => uint256)) public accAmountInPerChain; mapping(uint32 => mapping(address => uint256)) public accAmountOutPerChain; mapping(address => mapping(address => bool)) public allowedCallers; mapping(uint32 => bool) public allowedChains; /** * @notice Initializes the new money market * @param underlying_ The address of the underlying asset * @param operator_ The address of the Operator * @param interestRateModel_ The address of the interest rate model * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 * @param name_ ERC-20 name of this token * @param symbol_ ERC-20 symbol of this token * @param decimals_ ERC-20 decimal precision of this token * @param admin_ Address of the administrator of this token * @param zkVerifier_ The IRiscZeroVerifier address */ function initialize( address underlying_, address operator_, address interestRateModel_, uint256 initialExchangeRateMantissa_, string memory name_, string memory symbol_, uint8 decimals_, address payable admin_, address zkVerifier_, address roles_ ) external initializer { // Initialize the base contract proxyInitialize( underlying_, operator_, interestRateModel_, initialExchangeRateMantissa_, name_, symbol_, decimals_, admin_ ); // Initialize the ZkVerifier ZkVerifier.initialize(zkVerifier_); rolesOperator = IRoles(roles_); // Set the proper admin now that initialization is done admin = admin_; } // ----------- VIEW ------------ /** * @inheritdoc ImErc20Host */ function isCallerAllowed(address sender, address caller) external view returns (bool) { return allowedCallers[sender][caller]; } /** * @inheritdoc ImErc20Host */ function getProofData(address user, uint32 dstId) external view returns (bytes memory) { return mTokenProofDecoderLib.encodeJournal( user, address(this), accAmountInPerChain[dstId][user], accAmountOutPerChain[dstId][user], uint32(block.chainid), dstId ); } // ----------- OWNER ------------ /** * @notice Sets the _risc0Verifier address * @param _risc0Verifier the new IRiscZeroVerifier address */ function setVerifier(address _risc0Verifier) external onlyAdmin { _setVerifier(_risc0Verifier); } /** * @notice Sets the image id * @param _imageId the new image id */ function setImageId(bytes32 _imageId) external onlyAdmin { _setImageId(_imageId); } function setTotalUnderlying(uint256 _amount) external onlyAdmin { initialExchangeRateMantissa = _amount; } /** * @notice Updates an allowed chain status * @param _chainId the chain id * @param _status the new status */ function updateAllowedChain(uint32 _chainId, bool _status) external { if (msg.sender != admin && !rolesOperator.isAllowedFor(msg.sender, rolesOperator.CHAINS_MANAGER())) { revert mErc20Host_CallerNotAllowed(); } allowedChains[_chainId] = _status; emit mErc20Host_ChainStatusUpdated(_chainId, _status); } /** * @inheritdoc ImErc20Host */ function extractForRebalancing(uint256 amount) external { if (!rolesOperator.isAllowedFor(msg.sender, rolesOperator.REBALANCER())) revert mErc20Host_NotRebalancer(); IERC20(underlying).safeTransfer(msg.sender, amount); } // ----------- PUBLIC ------------ /** * @inheritdoc ImErc20Host */ function updateAllowedCallerStatus(address caller, bool status) external override { allowedCallers[msg.sender][caller] = status; emit AllowedCallerUpdated(msg.sender, caller, status); } /** * @inheritdoc ImErc20Host */ function liquidateExternal( bytes calldata journalData, bytes calldata seal, address[] calldata userToLiquidate, uint256[] calldata liquidateAmount, address[] calldata collateral, address receiver ) external override { // verify received data if (!rolesOperator.isAllowedFor(msg.sender, rolesOperator.PROOF_BATCH_FORWARDER())) { _verifyProof(journalData, seal); } bytes[] memory journals = abi.decode(journalData, (bytes[])); uint256 length = journals.length; require(length == liquidateAmount.length, mErc20Host_LengthMismatch()); require(length == userToLiquidate.length, mErc20Host_LengthMismatch()); require(length == collateral.length, mErc20Host_LengthMismatch()); for (uint256 i; i < length;) { _liquidateExternal(journals[i], userToLiquidate[i], liquidateAmount[i], collateral[i], receiver); unchecked { ++i; } } } /** * @inheritdoc ImErc20Host */ function mintExternal( bytes calldata journalData, bytes calldata seal, uint256[] calldata mintAmount, address receiver ) external override { if (!rolesOperator.isAllowedFor(msg.sender, rolesOperator.PROOF_BATCH_FORWARDER())) { _verifyProof(journalData, seal); } bytes[] memory journals = abi.decode(journalData, (bytes[])); uint256 length = journals.length; require(length == mintAmount.length, mErc20Host_LengthMismatch()); for (uint256 i; i < length;) { _mintExternal(journals[i], mintAmount[i], receiver); unchecked { ++i; } } } /** * @inheritdoc ImErc20Host */ function repayExternal( bytes calldata journalData, bytes calldata seal, uint256[] calldata repayAmount, address receiver ) external override { if (!rolesOperator.isAllowedFor(msg.sender, rolesOperator.PROOF_BATCH_FORWARDER())) { _verifyProof(journalData, seal); } bytes[] memory journals = abi.decode(journalData, (bytes[])); uint256 length = journals.length; require(length == repayAmount.length, mErc20Host_LengthMismatch()); for (uint256 i; i < length;) { _repayExternal(journals[i], repayAmount[i], receiver); unchecked { ++i; } } } /** * @inheritdoc ImErc20Host */ function withdrawOnExtension(uint256 amount, uint32 dstChainId) external override { require(amount > 0, mErc20Host_AmountNotValid()); // actions accAmountOutPerChain[dstChainId][msg.sender] += amount; _redeemUnderlying(msg.sender, amount, false); emit mErc20Host_WithdrawOnExtensionChain(msg.sender, dstChainId, amount); } /** * @inheritdoc ImErc20Host */ function borrowOnExtension(uint256 amount, uint32 dstChainId) external override { require(amount > 0, mErc20Host_AmountNotValid()); // actions accAmountOutPerChain[dstChainId][msg.sender] += amount; _borrow(msg.sender, amount, false); emit mErc20Host_BorrowOnExternsionChain(msg.sender, dstChainId, amount); } // ----------- PRIVATE ------------ function _verifyProof(bytes calldata journalData, bytes calldata seal) private { require(journalData.length > 0, mErc20Host_JournalNotValid()); // verify it using the ZkVerifier contract _verifyInput(journalData, seal); } function _checkSender(address msgSender, address srcSender) private view { if (msgSender != srcSender) { require( allowedCallers[srcSender][msgSender] || msgSender == admin || rolesOperator.isAllowedFor(msgSender, rolesOperator.PROOF_FORWARDER()) || rolesOperator.isAllowedFor(msgSender, rolesOperator.PROOF_BATCH_FORWARDER()), mErc20Host_CallerNotAllowed() ); } } function _liquidateExternal( bytes memory singleJournal, address userToLiquidate, uint256 liquidateAmount, address collateral, address receiver ) internal { (address _sender, address _market, uint256 _accAmountIn,, uint32 _chainId, uint32 _dstChainId) = mTokenProofDecoderLib.decodeJournal(singleJournal); receiver = _sender; // base checks { _checkSender(msg.sender, _sender); require(_dstChainId == uint32(block.chainid), mErc20Host_DstChainNotValid()); require(_market == address(this), mErc20Host_AddressNotValid()); require(allowedChains[_chainId], mErc20Host_ChainNotValid()); } // operation checks { require(liquidateAmount > 0, mErc20Host_AmountNotValid()); require(liquidateAmount <= _accAmountIn - accAmountInPerChain[_chainId][_sender], mErc20Host_AmountTooBig()); require(userToLiquidate != msg.sender && userToLiquidate != _sender, mErc20Host_CallerNotAllowed()); } collateral = collateral == address(0) ? address(this) : collateral; // actions accAmountInPerChain[_chainId][_sender] += liquidateAmount; _liquidate(receiver, userToLiquidate, liquidateAmount, collateral, false); emit mErc20Host_LiquidateExternal( msg.sender, _sender, userToLiquidate, receiver, collateral, _chainId, liquidateAmount ); } function _mintExternal(bytes memory singleJournal, uint256 mintAmount, address receiver) internal { (address _sender, address _market, uint256 _accAmountIn,, uint32 _chainId, uint32 _dstChainId) = mTokenProofDecoderLib.decodeJournal(singleJournal); receiver = _sender; // base checks { _checkSender(msg.sender, _sender); require(_dstChainId == uint32(block.chainid), mErc20Host_DstChainNotValid()); require(_market == address(this), mErc20Host_AddressNotValid()); require(allowedChains[_chainId], mErc20Host_ChainNotValid()); } // operation checks { require(mintAmount > 0, mErc20Host_AmountNotValid()); require(mintAmount <= _accAmountIn - accAmountInPerChain[_chainId][_sender], mErc20Host_AmountTooBig()); } // actions accAmountInPerChain[_chainId][_sender] += mintAmount; _mint(receiver, mintAmount, false); emit mErc20Host_MintExternal(msg.sender, _sender, receiver, _chainId, mintAmount); } function _repayExternal(bytes memory singleJournal, uint256 repayAmount, address receiver) internal { (address _sender, address _market, uint256 _accAmountIn,, uint32 _chainId, uint32 _dstChainId) = mTokenProofDecoderLib.decodeJournal(singleJournal); receiver = _sender; // base checks { _checkSender(msg.sender, _sender); require(_dstChainId == uint32(block.chainid), mErc20Host_DstChainNotValid()); require(_market == address(this), mErc20Host_AddressNotValid()); require(allowedChains[_chainId], mErc20Host_ChainNotValid()); } // operation checks { require(repayAmount > 0, mErc20Host_AmountNotValid()); require(repayAmount <= _accAmountIn - accAmountInPerChain[_chainId][_sender], mErc20Host_AmountTooBig()); } // actions accAmountInPerChain[_chainId][_sender] += repayAmount; _repayBehalf(receiver, repayAmount, false); emit mErc20Host_RepayExternal(msg.sender, _sender, receiver, _chainId, repayAmount); } }
// Copyright 2024 RISC Zero, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.9; /// @title Steel Library /// @notice This library provides a collection of utilities to work with Steel commitments in Solidity. library Steel { /// @notice Represents a commitment to a specific block in the blockchain. /// @dev The `id` combines the version and the actual identifier of the claim, such as the block number. /// @dev The `digest` represents the data being committed to, e.g. the hash of the execution block. /// @dev The `configID` is the cryptographic digest of the network configuration. struct Commitment { uint256 id; bytes32 digest; bytes32 configID; } /// @notice The version of the Commitment is incorrect. error InvalidCommitmentVersion(); /// @notice The Commitment is too old and can no longer be validated. error CommitmentTooOld(); /// @notice Validates if the provided Commitment matches the block hash of the given block number. /// @param commitment The Commitment struct to validate. /// @return True if the commitment's block hash matches the block hash of the block number, false otherwise. function validateCommitment(Commitment memory commitment) internal view returns (bool) { (uint240 claimID, uint16 version) = Encoding.decodeVersionedID(commitment.id); if (version == 0) { return validateBlockCommitment(claimID, commitment.digest); } else if (version == 1) { return validateBeaconCommitment(claimID, commitment.digest); } else { revert InvalidCommitmentVersion(); } } /// @notice Validates if the provided block commitment matches the block hash of the given block number. /// @param blockNumber The block number to compare against. /// @param blockHash The block hash to validate. /// @return True if the block's block hash matches the block hash, false otherwise. function validateBlockCommitment(uint256 blockNumber, bytes32 blockHash) internal view returns (bool) { if (block.number - blockNumber > 256) { revert CommitmentTooOld(); } return blockHash == blockhash(blockNumber); } /// @notice Validates if the provided beacon commitment matches the block root of the given timestamp. /// @param timestamp The timestamp to compare against. /// @param blockRoot The block root to validate. /// @return True if the block's block root matches the block root, false otherwise. function validateBeaconCommitment(uint256 timestamp, bytes32 blockRoot) internal view returns (bool) { if (block.timestamp - timestamp > 12 * 8191) { revert CommitmentTooOld(); } return blockRoot == Beacon.parentBlockRoot(timestamp); } } /// @title Beacon Library library Beacon { /// @notice The address of the Beacon roots contract. /// @dev https://eips.ethereum.org/EIPS/eip-4788 address internal constant BEACON_ROOTS_ADDRESS = 0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02; /// @notice Find the root of the Beacon block corresponding to the parent of the execution block with the given timestamp. /// @return root Returns the corresponding Beacon block root or null, if no such block exists. function parentBlockRoot(uint256 timestamp) internal view returns (bytes32 root) { (bool success, bytes memory result) = BEACON_ROOTS_ADDRESS.staticcall(abi.encode(timestamp)); if (success) { return abi.decode(result, (bytes32)); } } } /// @title Encoding Library library Encoding { /// @notice Encodes a version and ID into a single uint256 value. /// @param id The base ID to be encoded, limited by 240 bits (or the maximum value of a uint240). /// @param version The version number to be encoded, limited by 16 bits (or the maximum value of a uint16). /// @return Returns a single uint256 value that contains both the `id` and the `version` encoded into it. function encodeVersionedID(uint240 id, uint16 version) internal pure returns (uint256) { uint256 encoded; assembly { encoded := or(shl(240, version), id) } return encoded; } /// @notice Decodes a version and ID from a single uint256 value. /// @param id The single uint256 value to be decoded. /// @return Returns two values: a uint240 for the original base ID and a uint16 for the version number encoded into it. function decodeVersionedID(uint256 id) internal pure returns (uint240, uint16) { uint240 decoded; uint16 version; assembly { decoded := and(id, 0x0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) version := shr(240, id) } return (decoded, version); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the value of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the value of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves a `value` amount of tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 value) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the * allowance mechanism. `value` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 value) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; import {IERC20Permit} from "../extensions/IERC20Permit.sol"; import {Address} from "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; /** * @dev An operation with an ERC20 token failed. */ error SafeERC20FailedOperation(address token); /** * @dev Indicates a failed `decreaseAllowance` request. */ error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease); /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value))); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value))); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); forceApprove(token, spender, oldAllowance + value); } /** * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no * value, non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal { unchecked { uint256 currentAllowance = token.allowance(address(this), spender); if (currentAllowance < requestedDecrease) { revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease); } forceApprove(token, spender, currentAllowance - requestedDecrease); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value)); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0))); _callOptionalReturn(token, approvalCall); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data); if (returndata.length != 0 && !abi.decode(returndata, (bool))) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0; } }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity =0.8.28; /* _____ _____ __ ____ _____ | | _ | | | \| _ | | | | | | |__| | | | |_|_|_|__|__|_____|____/|__|__| */ // interfaces import {IRiscZeroVerifier} from "risc0/IRiscZeroVerifier.sol"; import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; // contracts import {Steel} from "risc0/steel/Steel.sol"; abstract contract ZkVerifier is Initializable { // ----------- STORAGE ------------ IRiscZeroVerifier public verifier; bytes32 public imageId; error ZkVerifier_ImageNotValid(); error ZkVerifier_InputNotValid(); error ZkVerifier_VerifierNotSet(); event ImageSet(bytes32 _imageId); event VerifierSet(address indexed oldVerifier, address indexed newVerifier); // ----------- PUBLIC ------------ /** * @notice Initializes a new ZkVerifier contract * @param _verifier IRiscZeroVerifier contract implementation */ function initialize(address _verifier) public initializer { require(_verifier != address(0), ZkVerifier_InputNotValid()); verifier = IRiscZeroVerifier(_verifier); } // ----------- INTERNAL ------------ /** * @notice Sets the _risc0Verifier address * @dev Admin check is needed on the external method * @param _risc0Verifier the new IRiscZeroVerifier address */ function _setVerifier(address _risc0Verifier) internal { require(_risc0Verifier != address(0), ZkVerifier_InputNotValid()); emit VerifierSet(address(verifier), _risc0Verifier); verifier = IRiscZeroVerifier(_risc0Verifier); } /** * @notice Sets the image id * @dev Admin check is needed on the external method * @param _imageId the new image id */ function _setImageId(bytes32 _imageId) internal { require(_imageId != bytes32(0), ZkVerifier_ImageNotValid()); emit ImageSet(_imageId); imageId = _imageId; } /** * @notice Verifies an input * @param journalEntry the risc0 journal entry * @param seal the risc0 seal */ function _verifyInput(bytes calldata journalEntry, bytes calldata seal) internal virtual { // generic checks _checkAddresses(); // verify input __verify(journalEntry, seal); } // ----------- PRIVATE ------------ function _checkAddresses() private view { require(address(verifier) != address(0), ZkVerifier_VerifierNotSet()); } function __verify(bytes calldata journalEntry, bytes calldata seal) private view { verifier.verify(seal, imageId, sha256(journalEntry)); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity =0.8.28; /* _____ _____ __ ____ _____ | | _ | | | \| _ | | | | | | |__| | | | |_|_|_|__|__|_____|____/|__|__| */ import {mErc20} from "./mErc20.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; contract mErc20Upgradable is mErc20, Initializable { /** * @notice Initialize the new money market * @param underlying_ The address of the underlying asset * @param operator_ The address of the Operator * @param interestRateModel_ The address of the interest rate model * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 * @param name_ ERC-20 name of this token * @param symbol_ ERC-20 symbol of this token * @param decimals_ ERC-20 decimal precision of this token */ function proxyInitialize( address underlying_, address operator_, address interestRateModel_, uint256 initialExchangeRateMantissa_, string memory name_, string memory symbol_, uint8 decimals_, address payable admin_ ) public { // Creator of the contract is admin during initialization admin = payable(msg.sender); // mErc20 initialize does the bulk of the work super.initialize( underlying_, operator_, interestRateModel_, initialExchangeRateMantissa_, name_, symbol_, decimals_ ); // Set the proper admin now that initialization is done admin = admin_; } }
// SPDX-License-Identifier: UNLICENSED pragma solidity =0.8.28; import {BytesLib} from "src/libraries/BytesLib.sol"; /* _____ _____ __ ____ _____ | | _ | | | \| _ | | | | | | |__| | | | |_|_|_|__|__|_____|____/|__|__| */ library mTokenProofDecoderLib { uint256 public constant ENTRY_SIZE = 112; // single journal entry size error mTokenProofDecoderLib_ChainNotFound(); function decodeJournal(bytes memory journalData) internal pure returns ( address sender, address market, uint256 accAmountIn, uint256 accAmountOut, uint32 chainId, uint32 dstChainId ) { // decode action data // | Offset | Length | Data Type | // |--------|---------|----------------------- | // | 0 | 20 | address sender | // | 20 | 40 | address market | // | 40 | 32 | uint256 accAmountIn | // | 72 | 32 | uint256 accAmountOut | // | 104 | 4 | uint32 chainId | sender = BytesLib.toAddress(BytesLib.slice(journalData, 0, 20), 0); market = BytesLib.toAddress(BytesLib.slice(journalData, 20, 20), 0); accAmountIn = BytesLib.toUint256(BytesLib.slice(journalData, 40, 32), 0); accAmountOut = BytesLib.toUint256(BytesLib.slice(journalData, 72, 32), 0); chainId = BytesLib.toUint32(BytesLib.slice(journalData, 104, 4), 0); dstChainId = BytesLib.toUint32(BytesLib.slice(journalData, 108, 4), 0); } function encodeJournal( address sender, address market, uint256 accAmountIn, uint256 accAmountOut, uint32 chainId, uint32 dstChainId ) internal pure returns (bytes memory) { return abi.encodePacked(sender, market, accAmountIn, accAmountOut, chainId, dstChainId); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity =0.8.28; /* _____ _____ __ ____ _____ | | _ | | | \| _ | | | | | | |__| | | | |_|_|_|__|__|_____|____/|__|__| */ interface ImErc20Host { // ----------- EVENTS ----------- /** * @notice Emitted when a user updates allowed callers */ event AllowedCallerUpdated(address indexed sender, address indexed caller, bool status); /** * @notice Emitted when a chain id whitelist status is updated */ event mErc20Host_ChainStatusUpdated(uint32 indexed chainId, bool status); /** * @notice Emitted when a liquidate operation is executed */ event mErc20Host_LiquidateExternal( address indexed msgSender, address indexed srcSender, address userToLiquidate, address receiver, address indexed collateral, uint32 srcChainId, uint256 amount ); /** * @notice Emitted when a mint operation is executed */ event mErc20Host_MintExternal( address indexed msgSender, address indexed srcSender, address indexed receiver, uint32 chainId, uint256 amount ); /** * @notice Emitted when a borrow operation is executed */ event mErc20Host_BorrowExternal( address indexed msgSender, address indexed srcSender, uint32 indexed chainId, uint256 amount ); /** * @notice Emitted when a repay operation is executed */ event mErc20Host_RepayExternal( address indexed msgSender, address indexed srcSender, address indexed position, uint32 chainId, uint256 amount ); /** * @notice Emitted when a withdrawal is executed */ event mErc20Host_WithdrawExternal( address indexed msgSender, address indexed srcSender, uint32 indexed chainId, uint256 amount ); /** * @notice Emitted when a borrow operation is triggered for an extension chain */ event mErc20Host_BorrowOnExternsionChain(address indexed sender, uint32 dstChainId, uint256 amount); /** * @notice Emitted when a withdraw operation is triggered for an extension chain */ event mErc20Host_WithdrawOnExtensionChain(address indexed sender, uint32 dstChainId, uint256 amount); // ----------- ERRORS ----------- /** * @notice Thrown when the chain id is not LINEA */ error mErc20Host_ProofGenerationInputNotValid(); /** * @notice Thrown when the dst chain id is not current chain */ error mErc20Host_DstChainNotValid(); /** * @notice Thrown when the chain id is not LINEA */ error mErc20Host_ChainNotValid(); /** * @notice Thrown when the address is not valid */ error mErc20Host_AddressNotValid(); /** * @notice Thrown when the amount provided is bigger than the available amount` */ error mErc20Host_AmountTooBig(); /** * @notice Thrown when the amount specified is invalid (e.g., zero) */ error mErc20Host_AmountNotValid(); /** * @notice Thrown when the journal data provided is invalid or corrupted */ error mErc20Host_JournalNotValid(); /** * @notice Thrown when caller is not allowed */ error mErc20Host_CallerNotAllowed(); /** * @notice Thrown when caller is not rebalancer */ error mErc20Host_NotRebalancer(); /** * @notice Thrown when length of array is not valid */ error mErc20Host_LengthMismatch(); // ----------- VIEW ----------- /** * @notice Returns if a caller is allowed for sender */ function isCallerAllowed(address sender, address caller) external view returns (bool); /** * @notice Returns the proof data journal */ function getProofData(address user, uint32 dstId) external view returns (bytes memory); // ----------- PUBLIC ----------- /** * @notice Extract amount to be used for rebalancing operation * @param amount The amount to rebalance */ function extractForRebalancing(uint256 amount) external; /** * @notice Set caller status for `msg.sender` * @param caller The caller address * @param status The status to set for `caller` */ function updateAllowedCallerStatus(address caller, bool status) external; /** * @notice Mints tokens after external verification * @param journalData The journal data for minting (array of encoded journals) * @param seal The Zk proof seal * @param userToLiquidate Array of positions to liquidate * @param liquidateAmount Array of amounts to liquidate * @param collateral Array of collaterals to seize * @param receiver The collateral receiver */ function liquidateExternal( bytes calldata journalData, bytes calldata seal, address[] calldata userToLiquidate, uint256[] calldata liquidateAmount, address[] calldata collateral, address receiver ) external; /** * @notice Mints tokens after external verification * @param journalData The journal data for minting (array of encoded journals) * @param seal The Zk proof seal * @param mintAmount Array of amounts to mint * @param receiver The tokens receiver */ function mintExternal( bytes calldata journalData, bytes calldata seal, uint256[] calldata mintAmount, address receiver ) external; /** * @notice Repays tokens after external verification * @param journalData The journal data for repayment (array of encoded journals) * @param seal The Zk proof seal * @param repayAmount Array of amounts to repay * @param receiver The position to repay for */ function repayExternal( bytes calldata journalData, bytes calldata seal, uint256[] calldata repayAmount, address receiver ) external; /** * @notice Initiates a withdraw operation * @param amount The amount to withdraw * @param dstChainId The destination chain to recieve funds */ function withdrawOnExtension(uint256 amount, uint32 dstChainId) external; /** * @notice Initiates a withdraw operation * @param amount The amount to withdraw * @param dstChainId The destination chain to recieve funds */ function borrowOnExtension(uint256 amount, uint32 dstChainId) external; }
// SPDX-License-Identifier: UNLICENSED pragma solidity =0.8.28; /* _____ _____ __ ____ _____ | | _ | | | \| _ | | | | | | |__| | | | |_|_|_|__|__|_____|____/|__|__| */ import {IRoles} from "./IRoles.sol"; interface ImTokenOperationTypes { enum OperationType { AmountIn, AmountInHere, AmountOut, AmountOutHere, Seize, Transfer, Mint, Borrow, Repay, Redeem, Liquidate } } interface ImTokenDelegator { /** * @notice Non-standard token able to delegate */ function delegate(address delegatee) external; } interface ImTokenMinimal { /** * @notice EIP-20 token name for this token */ function name() external view returns (string memory); /** * @notice EIP-20 token symbol for this token */ function symbol() external view returns (string memory); /** * @notice EIP-20 token decimals for this token */ function decimals() external view returns (uint8); /** * @notice Returns the value of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @notice Returns the value of tokens owned by `account`. * @param account The account to check for */ function balanceOf(address account) external view returns (uint256); /** * @dev Returns true */ function isMToken() external view returns (bool); /** * @dev Returns the underlying address */ function underlying() external view returns (address); } interface ImToken is ImTokenMinimal { // ----------- STORAGE ------------ /** * @notice Roles manager */ function rolesOperator() external view returns (IRoles); /** * @notice Administrator for this contract */ function admin() external view returns (address payable); /** * @notice Pending administrator for this contract */ function pendingAdmin() external view returns (address payable); /** * @notice Contract which oversees inter-mToken operations */ function operator() external view returns (address); /** * @notice Model which tells what the current interest rate should be */ function interestRateModel() external view returns (address); /** * @notice Fraction of interest currently set aside for reserves */ function reserveFactorMantissa() external view returns (uint256); /** * @notice Block number that interest was last accrued at */ function accrualBlockNumber() external view returns (uint256); /** * @notice Accumulator of the total earned interest rate since the opening of the market */ function borrowIndex() external view returns (uint256); /** * @notice Total amount of outstanding borrows of the underlying in this market */ function totalBorrows() external view returns (uint256); /** * @notice Total amount of reserves of the underlying held in this market */ function totalReserves() external view returns (uint256); // ----------- ACTIONS ------------ /** * @notice Transfers `amount` tokens to the `dst` address * @param dst The address of the recipient * @param amount The number of tokens to transfer * @return Whether the transfer was successful or not */ function transfer(address dst, uint256 amount) external returns (bool); /** * @notice Transfers `amount` tokens from the `src` address to the `dst` address * @param src The address from which tokens are transferred * @param dst The address to which tokens are transferred * @param amount The number of tokens to transfer * @return Whether the transfer was successful or not */ function transferFrom(address src, address dst, uint256 amount) external returns (bool); /** * @notice Approves `spender` to spend `amount` tokens on behalf of the caller * @param spender The address authorized to spend tokens * @param amount The number of tokens to approve * @return Whether the approval was successful or not */ function approve(address spender, uint256 amount) external returns (bool); /** * @notice Returns the current allowance the `spender` has from the `owner` * @param owner The address of the token holder * @param spender The address authorized to spend the tokens * @return The current remaining number of tokens `spender` can spend */ function allowance(address owner, address spender) external view returns (uint256); /** * @notice Returns the balance of tokens held by `owner` * @param owner The address to query the balance for * @return The balance of tokens owned by `owner` */ function balanceOf(address owner) external view returns (uint256); /** * @notice Returns the underlying asset balance of the `owner` * @param owner The address to query the balance of underlying assets for * @return The balance of underlying assets owned by `owner` */ function balanceOfUnderlying(address owner) external returns (uint256); /** * @notice Returns the snapshot of account details for the given `account` * @param account The address to query the account snapshot for * @return (token balance, borrow balance, exchange rate) */ function getAccountSnapshot(address account) external view returns (uint256, uint256, uint256); /** * @notice Returns the current borrow rate per block * @return The current borrow rate per block, scaled by 1e18 */ function borrowRatePerBlock() external view returns (uint256); /** * @notice Returns the current supply rate per block * @return The current supply rate per block, scaled by 1e18 */ function supplyRatePerBlock() external view returns (uint256); /** * @notice Returns the total amount of borrows, accounting for interest * @return The total amount of borrows */ function totalBorrowsCurrent() external returns (uint256); /** * @notice Returns the current borrow balance for `account`, accounting for interest * @param account The address to query the borrow balance for * @return The current borrow balance */ function borrowBalanceCurrent(address account) external returns (uint256); /** * @notice Returns the stored borrow balance for `account`, without accruing interest * @param account The address to query the stored borrow balance for * @return The stored borrow balance */ function borrowBalanceStored(address account) external view returns (uint256); /** * @notice Returns the current exchange rate, with interest accrued * @return The current exchange rate */ function exchangeRateCurrent() external returns (uint256); /** * @notice Returns the stored exchange rate, without accruing interest * @return The stored exchange rate */ function exchangeRateStored() external view returns (uint256); /** * @notice Returns the total amount of available cash in the contract * @return The total amount of cash */ function getCash() external view returns (uint256); /** * @notice Accrues interest on the contract's outstanding loans */ function accrueInterest() external; /** * @notice Transfers collateral tokens (this market) to the liquidator. * @dev Will fail unless called by another mToken during the process of liquidation. * Its absolutely critical to use msg.sender as the borrowed mToken and not a parameter. * @param liquidator The account receiving seized collateral * @param borrower The account having collateral seized * @param seizeTokens The number of mTokens to seize */ function seize(address liquidator, address borrower, uint256 seizeTokens) external; /** * @notice Accrues interest and reduces reserves by transferring to admin * @param reduceAmount Amount of reduction to reserves */ function reduceReserves(uint256 reduceAmount) external; }
// SPDX-License-Identifier: UNLICENSED pragma solidity =0.8.28; /* _____ _____ __ ____ _____ | | _ | | | \| _ | | | | | | |__| | | | |_|_|_|__|__|_____|____/|__|__| */ interface IRoles { error Roles_InputNotValid(); /** * @notice Returns REBALANCER role */ function REBALANCER() external view returns (bytes32); /** * @notice Returns REBALANCER_EOA role */ function REBALANCER_EOA() external view returns (bytes32); /** * @notice Returns GUARDIAN_PAUSE role */ function GUARDIAN_PAUSE() external view returns (bytes32); /** * @notice Returns GUARDIAN_TRANSFER role */ function GUARDIAN_TRANSFER() external view returns (bytes32); /** * @notice Returns GUARDIAN_SEIZE role */ function GUARDIAN_SEIZE() external view returns (bytes32); /** * @notice Returns GUARDIAN_MINT role */ function GUARDIAN_MINT() external view returns (bytes32); /** * @notice Returns GUARDIAN_BORROW role */ function GUARDIAN_BORROW() external view returns (bytes32); /** * @notice Returns GUARDIAN_BRIDGE role */ function GUARDIAN_BRIDGE() external view returns (bytes32); /** * @notice Returns GUARDIAN_BORROW_CAP role */ function GUARDIAN_BORROW_CAP() external view returns (bytes32); /** * @notice Returns GUARDIAN_SUPPLY_CAP role */ function GUARDIAN_SUPPLY_CAP() external view returns (bytes32); /** * @notice Returns GUARDIAN_RESERVE role */ function GUARDIAN_RESERVE() external view returns (bytes32); /** * @notice Returns PROOF_FORWARDER role */ function PROOF_FORWARDER() external view returns (bytes32); /** * @notice Returns PROOF_BATCH_FORWARDER role */ function PROOF_BATCH_FORWARDER() external view returns (bytes32); /** * @notice Returns PAUSE_MANAGER role */ function PAUSE_MANAGER() external view returns (bytes32); /** * @notice Returns CHAINS_MANAGER role */ function CHAINS_MANAGER() external view returns (bytes32); /** * @notice Returns allowance status for a contract and a role * @param _contract the contract address * @param _role the bytes32 role */ function isAllowedFor(address _contract, bytes32 _role) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. * * ==== Security Considerations * * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be * considered as an intention to spend the allowance in any specific way. The second is that because permits have * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be * generally recommended is: * * ```solidity * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} * doThing(..., value); * } * * function doThing(..., uint256 value) public { * token.safeTransferFrom(msg.sender, address(this), value); * ... * } * ``` * * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also * {SafeERC20-safeTransferFrom}). * * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so * contracts should have entry points that don't rely on permit. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. * * CAUTION: See Security Considerations above. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol) pragma solidity ^0.8.20; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev The ETH balance of the account is not enough to perform the operation. */ error AddressInsufficientBalance(address account); /** * @dev There's no code at `target` (it is not a contract). */ error AddressEmptyCode(address target); /** * @dev A call to an address target failed. The target may have reverted. */ error FailedInnerCall(); /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { if (address(this).balance < amount) { revert AddressInsufficientBalance(address(this)); } (bool success, ) = recipient.call{value: amount}(""); if (!success) { revert FailedInnerCall(); } } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason or custom error, it is bubbled * up by this function (like regular Solidity function calls). However, if * the call reverted with no returned reason, this function reverts with a * {FailedInnerCall} error. * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { if (address(this).balance < value) { revert AddressInsufficientBalance(address(this)); } (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an * unsuccessful call. */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata ) internal view returns (bytes memory) { if (!success) { _revert(returndata); } else { // only check if target is a contract if the call was successful and the return data is empty // otherwise we already know that it was a contract if (returndata.length == 0 && target.code.length == 0) { revert AddressEmptyCode(target); } return returndata; } } /** * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the * revert reason or with a default {FailedInnerCall} error. */ function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) { if (!success) { _revert(returndata); } else { return returndata; } } /** * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}. */ function _revert(bytes memory returndata) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert FailedInnerCall(); } } }
// Copyright 2024 RISC Zero, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.9; import {reverseByteOrderUint32} from "./Util.sol"; /// @notice A receipt attesting to the execution of a guest program. /// @dev A receipt contains two parts: a seal and a claim. The seal is a zero-knowledge proof /// attesting to knowledge of a zkVM execution resulting in the claim. The claim is a set of public /// outputs for the execution. Crucially, the claim includes the journal and the image ID. The /// image ID identifies the program that was executed, and the journal is the public data written /// by the program. Note that this struct only contains the claim digest, as can be obtained with /// the `digest()` function on `ReceiptClaimLib`. struct Receipt { bytes seal; bytes32 claimDigest; } /// @notice Public claims about a zkVM guest execution, such as the journal committed to by the guest. /// @dev Also includes important information such as the exit code and the starting and ending system /// state (i.e. the state of memory). `ReceiptClaim` is a "Merkle-ized struct" supporting /// partial openings of the underlying fields from a hash commitment to the full structure. struct ReceiptClaim { /// @notice Digest of the SystemState just before execution has begun. bytes32 preStateDigest; /// @notice Digest of the SystemState just after execution has completed. bytes32 postStateDigest; /// @notice The exit code for the execution. ExitCode exitCode; /// @notice A digest of the input to the guest. /// @dev This field is currently unused and must be set to the zero digest. bytes32 input; /// @notice Digest of the Output of the guest, including the journal /// and assumptions set during execution. bytes32 output; } library ReceiptClaimLib { using OutputLib for Output; using SystemStateLib for SystemState; bytes32 constant TAG_DIGEST = sha256("risc0.ReceiptClaim"); // Define a constant to ensure hashing is done at compile time. Can't use the // SystemStateLib.digest method here because the Solidity compiler complains. bytes32 constant SYSTEM_STATE_ZERO_DIGEST = 0xa3acc27117418996340b84e5a90f3ef4c49d22c79e44aad822ec9c313e1eb8e2; /// @notice Construct a ReceiptClaim from the given imageId and journalDigest. /// Returned ReceiptClaim will represent a successful execution of the zkVM, running /// the program committed by imageId and resulting in the journal specified by /// journalDigest. /// @param imageId The identifier for the guest program. /// @param journalDigest The SHA-256 digest of the journal bytes. /// @dev Input hash and postStateDigest are set to all-zeros (i.e. no committed input, or /// final memory state), the exit code is (Halted, 0), and there are no assumptions /// (i.e. the receipt is unconditional). function ok(bytes32 imageId, bytes32 journalDigest) internal pure returns (ReceiptClaim memory) { return ReceiptClaim( imageId, SYSTEM_STATE_ZERO_DIGEST, ExitCode(SystemExitCode.Halted, 0), bytes32(0), Output(journalDigest, bytes32(0)).digest() ); } function digest(ReceiptClaim memory claim) internal pure returns (bytes32) { return sha256( abi.encodePacked( TAG_DIGEST, // down claim.input, claim.preStateDigest, claim.postStateDigest, claim.output, // data uint32(claim.exitCode.system) << 24, uint32(claim.exitCode.user) << 24, // down.length uint16(4) << 8 ) ); } } /// @notice Commitment to the memory state and program counter (pc) of the zkVM. /// @dev The "pre" and "post" fields of the ReceiptClaim are digests of the system state at the /// start are stop of execution. Programs are loaded into the zkVM by creating a memory image /// of the loaded program, and creating a system state for initializing the zkVM. This is /// known as the "image ID". struct SystemState { /// @notice Program counter. uint32 pc; /// @notice Root hash of a merkle tree which confirms the integrity of the memory image. bytes32 merkle_root; } library SystemStateLib { bytes32 constant TAG_DIGEST = sha256("risc0.SystemState"); function digest(SystemState memory state) internal pure returns (bytes32) { return sha256( abi.encodePacked( TAG_DIGEST, // down state.merkle_root, // data reverseByteOrderUint32(state.pc), // down.length uint16(1) << 8 ) ); } } /// @notice Exit condition indicated by the zkVM at the end of the guest execution. /// @dev Exit codes have a "system" part and a "user" part. Semantically, the system part is set to /// indicate the type of exit (e.g. halt, pause, or system split) and is directly controlled by the /// zkVM. The user part is an exit code, similar to exit codes used in Linux, chosen by the guest /// program to indicate additional information (e.g. 0 to indicate success or 1 to indicate an /// error). struct ExitCode { SystemExitCode system; uint8 user; } /// @notice Exit condition indicated by the zkVM at the end of the execution covered by this proof. /// @dev /// `Halted` indicates normal termination of a program with an interior exit code returned from the /// guest program. A halted program cannot be resumed. /// /// `Paused` indicates the execution ended in a paused state with an interior exit code set by the /// guest program. A paused program can be resumed such that execution picks up where it left /// of, with the same memory state. /// /// `SystemSplit` indicates the execution ended on a host-initiated system split. System split is /// mechanism by which the host can temporarily stop execution of the execution ended in a system /// split has no output and no conclusions can be drawn about whether the program will eventually /// halt. System split is used in continuations to split execution into individually provable segments. enum SystemExitCode { Halted, Paused, SystemSplit } /// @notice Output field in the `ReceiptClaim`, committing to a claimed journal and assumptions list. struct Output { /// @notice Digest of the journal committed to by the guest execution. bytes32 journalDigest; /// @notice Digest of the ordered list of `ReceiptClaim` digests corresponding to the /// calls to `env::verify` and `env::verify_integrity`. /// @dev Verifying the integrity of a `Receipt` corresponding to a `ReceiptClaim` with a /// non-empty assumptions list does not guarantee unconditionally any of the claims over the /// guest execution (i.e. if the assumptions list is non-empty, then the journal digest cannot /// be trusted to correspond to a genuine execution). The claims can be checked by additional /// verifying a `Receipt` for every digest in the assumptions list. bytes32 assumptionsDigest; } library OutputLib { bytes32 constant TAG_DIGEST = sha256("risc0.Output"); function digest(Output memory output) internal pure returns (bytes32) { return sha256( abi.encodePacked( TAG_DIGEST, // down output.journalDigest, output.assumptionsDigest, // down.length uint16(2) << 8 ) ); } } /// @notice Error raised when cryptographic verification of the zero-knowledge proof fails. error VerificationFailed(); /// @notice Verifier interface for RISC Zero receipts of execution. interface IRiscZeroVerifier { /// @notice Verify that the given seal is a valid RISC Zero proof of execution with the /// given image ID and journal digest. Reverts on failure. /// @dev This method additionally ensures that the input hash is all-zeros (i.e. no /// committed input), the exit code is (Halted, 0), and there are no assumptions (i.e. the /// receipt is unconditional). /// @param seal The encoded cryptographic proof (i.e. SNARK). /// @param imageId The identifier for the guest program. /// @param journalDigest The SHA-256 digest of the journal bytes. function verify(bytes calldata seal, bytes32 imageId, bytes32 journalDigest) external view; /// @notice Verify that the given receipt is a valid RISC Zero receipt, ensuring the `seal` is /// valid a cryptographic proof of the execution with the given `claim`. Reverts on failure. /// @param receipt The receipt to be verified. function verifyIntegrity(Receipt calldata receipt) external view; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.20; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Storage of the initializable contract. * * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions * when using with upgradeable contracts. * * @custom:storage-location erc7201:openzeppelin.storage.Initializable */ struct InitializableStorage { /** * @dev Indicates that the contract has been initialized. */ uint64 _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool _initializing; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00; /** * @dev The contract is already initialized. */ error InvalidInitialization(); /** * @dev The contract is not initializing. */ error NotInitializing(); /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint64 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in * production. * * Emits an {Initialized} event. */ modifier initializer() { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); // Cache values to avoid duplicated sloads bool isTopLevelCall = !$._initializing; uint64 initialized = $._initialized; // Allowed calls: // - initialSetup: the contract is not in the initializing state and no previous version was // initialized // - construction: the contract is initialized at version 1 (no reininitialization) and the // current contract is just being deployed bool initialSetup = initialized == 0 && isTopLevelCall; bool construction = initialized == 1 && address(this).code.length == 0; if (!initialSetup && !construction) { revert InvalidInitialization(); } $._initialized = 1; if (isTopLevelCall) { $._initializing = true; } _; if (isTopLevelCall) { $._initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint64 version) { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing || $._initialized >= version) { revert InvalidInitialization(); } $._initialized = version; $._initializing = true; _; $._initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { _checkInitializing(); _; } /** * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}. */ function _checkInitializing() internal view virtual { if (!_isInitializing()) { revert NotInitializing(); } } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing) { revert InvalidInitialization(); } if ($._initialized != type(uint64).max) { $._initialized = type(uint64).max; emit Initialized(type(uint64).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint64) { return _getInitializableStorage()._initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _getInitializableStorage()._initializing; } /** * @dev Returns a pointer to the storage namespace. */ // solhint-disable-next-line var-name-mixedcase function _getInitializableStorage() private pure returns (InitializableStorage storage $) { assembly { $.slot := INITIALIZABLE_STORAGE } } }
// SPDX-License-Identifier: UNLICENSED pragma solidity =0.8.28; /* _____ _____ __ ____ _____ | | _ | | | \| _ | | | | | | |__| | | | |_|_|_|__|__|_____|____/|__|__| */ // interfaces import {ImErc20} from "src/interfaces/ImErc20.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {ImTokenMinimal, ImTokenDelegator} from "src/interfaces/ImToken.sol"; // contracts import {mToken} from "./mToken.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; /** * @title Malda's mErc20 Contract * @notice mTokens which wrap an EIP-20 underlying */ contract mErc20 is mToken, ImErc20 { using SafeERC20 for IERC20; // ----------- STORAGE ------------ /** * @notice Underlying asset for this mToken */ address public underlying; // ----------- ERRORS ------------ error mErc20_TokenNotValid(); /** * @notice Initialize the new money market * @param underlying_ The address of the underlying asset * @param operator_ The address of the Operator * @param interestRateModel_ The address of the interest rate model * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 * @param name_ ERC-20 name of this token * @param symbol_ ERC-20 symbol of this token * @param decimals_ ERC-20 decimal precision of this token */ function initialize( address underlying_, address operator_, address interestRateModel_, uint256 initialExchangeRateMantissa_, string memory name_, string memory symbol_, uint8 decimals_ ) public { // mToken initialize does the bulk of the work super.initialize(operator_, interestRateModel_, initialExchangeRateMantissa_, name_, symbol_, decimals_); // Set underlying and sanity check it underlying = underlying_; ImTokenMinimal(underlying).totalSupply(); } // ----------- OWNER ------------ /** * @notice Admin call to delegate the votes of the MALDA-like underlying * @param delegatee The address to delegate votes to * @dev mTokens whose underlying are not should revert here */ function delegateMaldaLikeTo(address delegatee) external onlyAdmin { ImTokenDelegator(underlying).delegate(delegatee); } /** * @notice A public function to sweep accidental ERC-20 transfers to this contract. Tokens are sent to admin (timelock) * @param token The address of the ERC-20 token to sweep */ function sweepToken(IERC20 token) external onlyAdmin { require(address(token) != underlying, mErc20_TokenNotValid()); uint256 balance = token.balanceOf(address(this)); token.safeTransfer(admin, balance); } // ----------- MARKET PUBLIC ------------ /** * @inheritdoc ImErc20 */ function mint(uint256 mintAmount) external { _mint(msg.sender, mintAmount, true); } /** * @inheritdoc ImErc20 */ function redeem(uint256 redeemTokens) external { _redeem(msg.sender, redeemTokens, true); } /** * @inheritdoc ImErc20 */ function redeemUnderlying(uint256 redeemAmount) external { _redeemUnderlying(msg.sender, redeemAmount, true); } /** * @inheritdoc ImErc20 */ function borrow(uint256 borrowAmount) external { _borrow(msg.sender, borrowAmount, true); } /** * @inheritdoc ImErc20 */ function repay(uint256 repayAmount) external { _repay(repayAmount, true); } /** * @inheritdoc ImErc20 */ function repayBehalf(address borrower, uint256 repayAmount) external { _repayBehalf(borrower, repayAmount, true); } /** * @inheritdoc ImErc20 */ function liquidate(address borrower, uint256 repayAmount, address mTokenCollateral) external { _liquidate(msg.sender, borrower, repayAmount, mTokenCollateral, true); } /** * @inheritdoc ImErc20 */ function addReserves(uint256 addAmount) external { return _addReserves(addAmount); } // ----------- INTERNAL ------------ /** * @notice Gets balance of this contract in terms of the underlying * @dev This excludes the value of the current message, if any * @return The quantity of underlying tokens owned by this contract */ function _getCashPrior() internal view virtual override returns (uint256) { return initialExchangeRateMantissa; } /** * @dev Performs a transfer in, reverting upon failure. Returns the amount actually transferred to the protocol, in case of a fee. * This may revert due to insufficient balance or insufficient allowance. */ function _doTransferIn(address from, uint256 amount) internal virtual override returns (uint256) { uint256 balanceBefore = IERC20(underlying).balanceOf(address(this)); IERC20(underlying).safeTransferFrom(from, address(this), amount); uint256 balanceAfter = IERC20(underlying).balanceOf(address(this)); return balanceAfter - balanceBefore; } /** * @dev Performs a transfer out, ideally returning an explanatory error code upon failure rather than reverting. * If caller has not called checked protocol's balance, may revert due to insufficient cash held in the contract. * If caller has checked protocol's balance, and verified it is >= amount, this should not revert in normal conditions. */ function _doTransferOut(address payable to, uint256 amount) internal virtual override { IERC20(underlying).safeTransfer(to, amount); } }
// SPDX-License-Identifier: Unlicense /* * @title Solidity Bytes Arrays Utils * @author Gonçalo Sá <[email protected]> * * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity. * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage. */ pragma solidity =0.8.28; library BytesLib { function concat(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bytes memory) { bytes memory tempBytes; assembly { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // Store the length of the first bytes array at the beginning of // the memory for tempBytes. let length := mload(_preBytes) mstore(tempBytes, length) // Maintain a memory counter for the current write location in the // temp bytes array by adding the 32 bytes for the array length to // the starting location. let mc := add(tempBytes, 0x20) // Stop copying when the memory counter reaches the length of the // first bytes array. let end := add(mc, length) for { // Initialize a copy counter to the start of the _preBytes data, // 32 bytes into its memory. let cc := add(_preBytes, 0x20) } lt(mc, end) { // Increase both counters by 32 bytes each iteration. mc := add(mc, 0x20) cc := add(cc, 0x20) } { // Write the _preBytes data into the tempBytes memory 32 bytes // at a time. mstore(mc, mload(cc)) } // Add the length of _postBytes to the current length of tempBytes // and store it as the new length in the first 32 bytes of the // tempBytes memory. length := mload(_postBytes) mstore(tempBytes, add(length, mload(tempBytes))) // Move the memory counter back from a multiple of 0x20 to the // actual end of the _preBytes data. mc := end // Stop copying when the memory counter reaches the new combined // length of the arrays. end := add(mc, length) for { let cc := add(_postBytes, 0x20) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } // Update the free-memory pointer by padding our last write location // to 32 bytes: add 31 bytes to the end of tempBytes to move to the // next 32 byte block, then round down to the nearest multiple of // 32. If the sum of the length of the two arrays is zero then add // one before rounding down to leave a blank 32 bytes (the length block with 0). mstore( 0x40, and( add(add(end, iszero(add(length, mload(_preBytes)))), 31), not(31) // Round down to the nearest 32 bytes. ) ) } return tempBytes; } function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal { assembly { // Read the first 32 bytes of _preBytes storage, which is the length // of the array. (We don't need to use the offset into the slot // because arrays use the entire slot.) let fslot := sload(_preBytes.slot) // Arrays of 31 bytes or less have an even value in their slot, // while longer arrays have an odd value. The actual length is // the slot divided by two for odd values, and the lowest order // byte divided by two for even values. // If the slot is even, bitwise and the slot with 255 and divide by // two to get the length. If the slot is odd, bitwise and the slot // with -1 and divide by two. let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2) let mlength := mload(_postBytes) let newlength := add(slength, mlength) // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage switch add(lt(slength, 32), lt(newlength, 32)) case 2 { // Since the new array still fits in the slot, we just need to // update the contents of the slot. // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length sstore( _preBytes.slot, // all the modifications to the slot are inside this // next block add( // we can just add to the slot contents because the // bytes we want to change are the LSBs fslot, add( mul( div( // load the bytes from memory mload(add(_postBytes, 0x20)), // zero all bytes to the right exp(0x100, sub(32, mlength)) ), // and now shift left the number of bytes to // leave space for the length in the slot exp(0x100, sub(32, newlength)) ), // increase length by the double of the memory // bytes length mul(mlength, 2) ) ) ) } case 1 { // The stored value fits in the slot, but the combined value // will exceed it. // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // The contents of the _postBytes array start 32 bytes into // the structure. Our first read should obtain the `submod` // bytes that can fit into the unused space in the last word // of the stored array. To get this, we read 32 bytes starting // from `submod`, so the data we read overlaps with the array // contents by `submod` bytes. Masking the lowest-order // `submod` bytes allows us to add that value directly to the // stored value. let submod := sub(32, slength) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore( sc, add( and(fslot, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00), and(mload(mc), mask) ) ) for { mc := add(mc, 0x20) sc := add(sc, 1) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } default { // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) // Start copying to the last used word of the stored array. let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // Copy over the first `submod` bytes of the new data as in // case 1 above. let slengthmod := mod(slength, 32) let mlengthmod := mod(mlength, 32) let submod := sub(32, slengthmod) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore(sc, add(sload(sc), and(mload(mc), mask))) for { sc := add(sc, 1) mc := add(mc, 0x20) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } } } function slice(bytes memory _bytes, uint256 _start, uint256 _length) internal pure returns (bytes memory) { require(_length + 31 >= _length, "slice_overflow"); require(_bytes.length >= _start + _length, "slice_outOfBounds"); bytes memory tempBytes; assembly { switch iszero(_length) case 0 { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // The first word of the slice result is potentially a partial // word read from the original array. To read it, we calculate // the length of that partial word and start copying that many // bytes into the array. The first word we copy will start with // data we don't care about, but the last `lengthmod` bytes will // land at the beginning of the contents of the new array. When // we're done copying, we overwrite the full first word with // the actual length of the slice. let lengthmod := and(_length, 31) // The multiplication in the next line is necessary // because when slicing multiples of 32 bytes (lengthmod == 0) // the following copy loop was copying the origin's length // and then ending prematurely not copying everything it should. let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod))) let end := add(mc, _length) for { // The multiplication in the next line has the same exact purpose // as the one above. let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } mstore(tempBytes, _length) //update free-memory pointer //allocating the array padded to 32 bytes like the compiler does now mstore(0x40, and(add(mc, 31), not(31))) } //if we want a zero-length slice let's just return a zero-length array default { tempBytes := mload(0x40) //zero out the 32 bytes slice we are about to return //we need to do it because Solidity does not garbage collect mstore(tempBytes, 0) mstore(0x40, add(tempBytes, 0x20)) } } return tempBytes; } function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) { require(_bytes.length >= _start + 20, "toAddress_outOfBounds"); address tempAddress; assembly { tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000) } return tempAddress; } function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) { require(_bytes.length >= _start + 1, "toUint8_outOfBounds"); uint8 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x1), _start)) } return tempUint; } function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) { require(_bytes.length >= _start + 2, "toUint16_outOfBounds"); uint16 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x2), _start)) } return tempUint; } function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) { require(_bytes.length >= _start + 4, "toUint32_outOfBounds"); uint32 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x4), _start)) } return tempUint; } function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) { require(_bytes.length >= _start + 8, "toUint64_outOfBounds"); uint64 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x8), _start)) } return tempUint; } function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) { require(_bytes.length >= _start + 12, "toUint96_outOfBounds"); uint96 tempUint; assembly { tempUint := mload(add(add(_bytes, 0xc), _start)) } return tempUint; } function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) { require(_bytes.length >= _start + 16, "toUint128_outOfBounds"); uint128 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x10), _start)) } return tempUint; } function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) { require(_bytes.length >= _start + 32, "toUint256_outOfBounds"); uint256 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x20), _start)) } return tempUint; } function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) { require(_bytes.length >= _start + 32, "toBytes32_outOfBounds"); bytes32 tempBytes32; assembly { tempBytes32 := mload(add(add(_bytes, 0x20), _start)) } return tempBytes32; } function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) { bool success = true; assembly { let length := mload(_preBytes) // if lengths don't match the arrays are not equal switch eq(length, mload(_postBytes)) case 1 { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 let mc := add(_preBytes, 0x20) let end := add(mc, length) for { let cc := add(_postBytes, 0x20) } // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) eq(add(lt(mc, end), cb), 2) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { // if any of these checks fails then arrays are not equal if iszero(eq(mload(mc), mload(cc))) { // unsuccess: success := 0 cb := 0 } } } default { // unsuccess: success := 0 } } return success; } function equal_nonAligned(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) { bool success = true; assembly { let length := mload(_preBytes) // if lengths don't match the arrays are not equal switch eq(length, mload(_postBytes)) case 1 { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 let endMinusWord := add(_preBytes, length) let mc := add(_preBytes, 0x20) let cc := add(_postBytes, 0x20) for { // the next line is the loop condition: // while(uint256(mc < endWord) + cb == 2) } eq(add(lt(mc, endMinusWord), cb), 2) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { // if any of these checks fails then arrays are not equal if iszero(eq(mload(mc), mload(cc))) { // unsuccess: success := 0 cb := 0 } } // Only if still successful // For <1 word tail bytes if gt(success, 0) { // Get the remainder of length/32 // length % 32 = AND(length, 32 - 1) let numTailBytes := and(length, 0x1f) let mcRem := mload(mc) let ccRem := mload(cc) for { let i := 0 } // the next line is the loop condition: // while(uint256(i < numTailBytes) + cb == 2) eq(add(lt(i, numTailBytes), cb), 2) { i := add(i, 1) } { if iszero(eq(byte(i, mcRem), byte(i, ccRem))) { // unsuccess: success := 0 cb := 0 } } } } default { // unsuccess: success := 0 } } return success; } function equalStorage(bytes storage _preBytes, bytes memory _postBytes) internal view returns (bool) { bool success = true; assembly { // we know _preBytes_offset is 0 let fslot := sload(_preBytes.slot) // Decode the length of the stored array like in concatStorage(). let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2) let mlength := mload(_postBytes) // if lengths don't match the arrays are not equal switch eq(slength, mlength) case 1 { // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage if iszero(iszero(slength)) { switch lt(slength, 32) case 1 { // blank the last byte which is the length fslot := mul(div(fslot, 0x100), 0x100) if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) { // unsuccess: success := 0 } } default { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := keccak256(0x0, 0x20) let mc := add(_postBytes, 0x20) let end := add(mc, mlength) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) for {} eq(add(lt(mc, end), cb), 2) { sc := add(sc, 1) mc := add(mc, 0x20) } { if iszero(eq(sload(sc), mload(mc))) { // unsuccess: success := 0 cb := 0 } } } } } default { // unsuccess: success := 0 } } return success; } }
// Copyright 2024 RISC Zero, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.9; /// @notice reverse the byte order of the uint256 value. /// @dev Solidity uses a big-endian ABI encoding. Reversing the byte order before encoding /// ensure that the encoded value will be little-endian. /// Written by k06a. https://ethereum.stackexchange.com/a/83627 function reverseByteOrderUint256(uint256 input) pure returns (uint256 v) { v = input; // swap bytes v = ((v & 0xFF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00) >> 8) | ((v & 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) << 8); // swap 2-byte long pairs v = ((v & 0xFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000) >> 16) | ((v & 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) << 16); // swap 4-byte long pairs v = ((v & 0xFFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000) >> 32) | ((v & 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) << 32); // swap 8-byte long pairs v = ((v & 0xFFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF0000000000000000) >> 64) | ((v & 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) << 64); // swap 16-byte long pairs v = (v >> 128) | (v << 128); } /// @notice reverse the byte order of the uint32 value. /// @dev Solidity uses a big-endian ABI encoding. Reversing the byte order before encoding /// ensure that the encoded value will be little-endian. /// Written by k06a. https://ethereum.stackexchange.com/a/83627 function reverseByteOrderUint32(uint32 input) pure returns (uint32 v) { v = input; // swap bytes v = ((v & 0xFF00FF00) >> 8) | ((v & 0x00FF00FF) << 8); // swap 2-byte long pairs v = (v >> 16) | (v << 16); } /// @notice reverse the byte order of the uint16 value. /// @dev Solidity uses a big-endian ABI encoding. Reversing the byte order before encoding /// ensure that the encoded value will be little-endian. /// Written by k06a. https://ethereum.stackexchange.com/a/83627 function reverseByteOrderUint16(uint16 input) pure returns (uint16 v) { v = input; // swap bytes v = (v >> 8) | ((v & 0x00FF) << 8); }
// SPDX-License-Identifier: UNLICENSED pragma solidity =0.8.28; /* _____ _____ __ ____ _____ | | _ | | | \| _ | | | | | | |__| | | | |_|_|_|__|__|_____|____/|__|__| */ interface ImErc20 { /** * @notice Sender supplies assets into the market and receives mTokens in exchange * @dev Accrues interest whether or not the operation succeeds, unless reverted * @param mintAmount The amount of the underlying asset to supply */ function mint(uint256 mintAmount) external; /** * @notice Sender redeems mTokens in exchange for the underlying asset * @dev Accrues interest whether or not the operation succeeds, unless reverted * @param redeemTokens The number of mTokens to redeem into underlying */ function redeem(uint256 redeemTokens) external; /** * @notice Sender redeems mTokens in exchange for a specified amount of underlying asset * @dev Accrues interest whether or not the operation succeeds, unless reverted * @param redeemAmount The amount of underlying to redeem */ function redeemUnderlying(uint256 redeemAmount) external; /** * @notice Sender borrows assets from the protocol to their own address * @param borrowAmount The amount of the underlying asset to borrow */ function borrow(uint256 borrowAmount) external; /** * @notice Sender repays their own borrow * @param repayAmount The amount to repay, or -1 for the full outstanding amount */ function repay(uint256 repayAmount) external; /** * @notice Sender repays a borrow belonging to borrower * @param borrower the account with the debt being payed off * @param repayAmount The amount to repay, or -1 for the full outstanding amount */ function repayBehalf(address borrower, uint256 repayAmount) external; /** * @notice The sender liquidates the borrowers collateral. * The collateral seized is transferred to the liquidator. * @param borrower The borrower of this mToken to be liquidated * @param repayAmount The amount of the underlying borrowed asset to repay * @param mTokenCollateral The market in which to seize collateral from the borrower */ function liquidate(address borrower, uint256 repayAmount, address mTokenCollateral) external; /** * @notice The sender adds to reserves. * @param addAmount The amount fo underlying token to add as reserves */ function addReserves(uint256 addAmount) external; }
// SPDX-License-Identifier: UNLICENSED pragma solidity =0.8.28; /* _____ _____ __ ____ _____ | | _ | | | \| _ | | | | | | |__| | | | |_|_|_|__|__|_____|____/|__|__| */ // interfaces import {IRoles} from "src/interfaces/IRoles.sol"; import {ImToken, ImTokenMinimal} from "src/interfaces/ImToken.sol"; import {IInterestRateModel} from "src/interfaces/IInterestRateModel.sol"; import {IOperator, IOperatorDefender} from "src/interfaces/IOperator.sol"; // contracts import {mTokenConfiguration} from "./mTokenConfiguration.sol"; import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; abstract contract mToken is mTokenConfiguration, ReentrancyGuard { /** * @notice Initialize the money market * @param operator_ The address of the Operator * @param interestRateModel_ The address of the interest rate model * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 * @param name_ EIP-20 name of this token * @param symbol_ EIP-20 symbol of this token * @param decimals_ EIP-20 decimal precision of this token */ function initialize( address operator_, address interestRateModel_, uint256 initialExchangeRateMantissa_, string memory name_, string memory symbol_, uint8 decimals_ ) public onlyAdmin { require(accrualBlockNumber == 0 && borrowIndex == 0, mToken_AlreadyInitialized()); require(initialExchangeRateMantissa_ > 0, mToken_ExchangeRateNotValid()); // Set initial exchange rate initialExchangeRateMantissa = initialExchangeRateMantissa_; _setOperator(operator_); accrualBlockNumber = _getBlockNumber(); borrowIndex = mantissaOne; _setInterestRateModel(interestRateModel_); name = name_; symbol = symbol_; decimals = decimals_; } function isMToken() external pure override returns (bool) { return true; } // ----------- TOKENS VIEW ------------ /** * @inheritdoc ImToken */ function allowance(address owner, address spender) external view override returns (uint256) { return transferAllowances[owner][spender]; } /** * @inheritdoc ImTokenMinimal */ function balanceOf(address owner) external view override returns (uint256) { return accountTokens[owner]; } /** * @inheritdoc ImToken */ function balanceOfUnderlying(address owner) external override returns (uint256) { Exp memory exchangeRate = Exp({mantissa: exchangeRateCurrent()}); return mul_ScalarTruncate(exchangeRate, accountTokens[owner]); } // ----------- MARKETS VIEW ------------ /** * @inheritdoc ImToken */ function getAccountSnapshot(address account) external view override returns (uint256, uint256, uint256) { return (accountTokens[account], _borrowBalanceStored(account), _exchangeRateStored()); } /** * @inheritdoc ImToken */ function borrowRatePerBlock() external view override returns (uint256) { return IInterestRateModel(interestRateModel).getBorrowRate(_getCashPrior(), totalBorrows, totalReserves); } /** * @inheritdoc ImToken */ function supplyRatePerBlock() external view override returns (uint256) { return IInterestRateModel(interestRateModel).getSupplyRate( _getCashPrior(), totalBorrows, totalReserves, reserveFactorMantissa ); } /** * @inheritdoc ImToken */ function borrowBalanceStored(address account) external view override returns (uint256) { return _borrowBalanceStored(account); } /** * @inheritdoc ImToken */ function getCash() external view override returns (uint256) { return _getCashPrior(); } /** * @inheritdoc ImToken */ function exchangeRateStored() external view override returns (uint256) { return _exchangeRateStored(); } // ----------- TOKENS PUBLIC ------------ /** * @inheritdoc ImToken */ function transfer(address dst, uint256 amount) external override nonReentrant returns (bool) { _transferTokens(msg.sender, msg.sender, dst, amount); return true; } /** * @inheritdoc ImToken */ function transferFrom(address src, address dst, uint256 amount) external override nonReentrant returns (bool) { _transferTokens(msg.sender, src, dst, amount); return true; } /** * @inheritdoc ImToken */ function approve(address spender, uint256 amount) external override returns (bool) { address src = msg.sender; transferAllowances[src][spender] = amount; emit Approval(src, spender, amount); return true; } // ----------- MARKETS PUBLIC ------------ /** * @inheritdoc ImToken */ function totalBorrowsCurrent() external override nonReentrant returns (uint256) { _accrueInterest(); return totalBorrows; } /** * @inheritdoc ImToken */ function borrowBalanceCurrent(address account) external override nonReentrant returns (uint256) { _accrueInterest(); return _borrowBalanceStored(account); } /** * @inheritdoc ImToken */ function exchangeRateCurrent() public override nonReentrant returns (uint256) { _accrueInterest(); return _exchangeRateStored(); } /** * @inheritdoc ImToken */ function seize(address liquidator, address borrower, uint256 seizeTokens) external override nonReentrant { _seize(msg.sender, liquidator, borrower, seizeTokens); } /** * @inheritdoc ImToken */ function reduceReserves(uint256 reduceAmount) external override nonReentrant { require( msg.sender == admin || rolesOperator.isAllowedFor(msg.sender, rolesOperator.GUARDIAN_RESERVE()), mToken_OnlyAdminOrRole() ); _accrueInterest(); require(_getCashPrior() >= reduceAmount, mToken_ReserveCashNotAvailable()); require(reduceAmount <= totalReserves, mToken_ReserveCashNotAvailable()); ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) // totalReserves - reduceAmount uint256 totalReservesNew = totalReserves - reduceAmount; // Store reserves[n+1] = reserves[n] - reduceAmount totalReserves = totalReservesNew; // doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred. _doTransferOut(payable(msg.sender), reduceAmount); initialExchangeRateMantissa -= reduceAmount; emit ReservesReduced(admin, reduceAmount, totalReservesNew); } // ----------- INTERNAL VIEW ------------ /** * @notice Return the borrow balance of account based on stored data * @param account The address whose balance should be calculated * @return (error code, the calculated balance or 0 if error code is non-zero) */ function _borrowBalanceStored(address account) internal view returns (uint256) { /* Get borrowBalance and borrowIndex */ BorrowSnapshot storage borrowSnapshot = accountBorrows[account]; /* If borrowBalance = 0 then borrowIndex is likely also 0. * Rather than failing the calculation with a division by 0, we immediately return 0 in this case. */ if (borrowSnapshot.principal == 0) { return 0; } /* Calculate new borrow balance using the interest index: * recentBorrowBalance = borrower.borrowBalance * market.borrowIndex / borrower.borrowIndex */ uint256 principalTimesIndex = borrowSnapshot.principal * borrowIndex; return principalTimesIndex / borrowSnapshot.interestIndex; } // ----------- INTERNAL ------------ /** * @notice Sender supplies assets into the market and receives mTokens in exchange * @dev Accrues interest whether or not the operation succeeds, unless reverted * @param user The user address * @param mintAmount The amount of the underlying asset to supply * @param doTransfer If an actual transfer should be performed */ function _mint(address user, uint256 mintAmount, bool doTransfer) internal nonReentrant { _accrueInterest(); // emits the actual Mint event if successful and logs on errors, so we don't need to __mint(user, mintAmount, doTransfer); } /** * @notice Sender redeems mTokens in exchange for the underlying asset * @dev Accrues interest whether or not the operation succeeds, unless reverted * @param user The user address * @param redeemTokens The number of mTokens to redeem into underlying * @param doTransfer If an actual transfer should be performed */ function _redeem(address user, uint256 redeemTokens, bool doTransfer) internal nonReentrant { _accrueInterest(); // emits redeem-specific logs on errors, so we don't need to __redeem(payable(user), redeemTokens, 0, doTransfer); } /** * @notice Sender redeems mTokens in exchange for a specified amount of underlying asset * @dev Accrues interest whether or not the operation succeeds, unless reverted * @param user The user address * @param redeemAmount The amount of underlying to receive from redeeming mTokens * @param doTransfer If an actual transfer should be performed */ function _redeemUnderlying(address user, uint256 redeemAmount, bool doTransfer) internal nonReentrant { _accrueInterest(); // emits redeem-specific logs on errors, so we don't need to __redeem(payable(user), 0, redeemAmount, doTransfer); } /** * @notice Sender borrows assets from the protocol to their own address * @param user The user address * @param borrowAmount The amount of the underlying asset to borrow * @param doTransfer If an actual transfer should be performed */ function _borrow(address user, uint256 borrowAmount, bool doTransfer) internal nonReentrant { _accrueInterest(); // emits borrow-specific logs on errors, so we don't need to __borrow(payable(user), borrowAmount, doTransfer); } /** * @notice Sender repays their own borrow * @param repayAmount The amount to repay, or -1 for the full outstanding amount * @param doTransfer If an actual transfer should be performed */ function _repay(uint256 repayAmount, bool doTransfer) internal nonReentrant { _accrueInterest(); // emits repay-borrow-specific logs on errors, so we don't need to __repay(msg.sender, msg.sender, repayAmount, doTransfer); } /** * @notice Sender repays a borrow belonging to borrower * @param borrower the account with the debt being payed off * @param repayAmount The amount to repay, or -1 for the full outstanding amount * @param doTransfer If an actual transfer should be performed */ function _repayBehalf(address borrower, uint256 repayAmount, bool doTransfer) internal nonReentrant { _accrueInterest(); // emits repay-borrow-specific logs on errors, so we don't need to __repay(msg.sender, borrower, repayAmount, doTransfer); } /** * @notice The sender liquidates the borrowers collateral. * The collateral seized is transferred to the liquidator. * @param borrower The liquidator address * @param borrower The borrower of this mToken to be liquidated * @param mTokenCollateral The market in which to seize collateral from the borrower * @param repayAmount The amount of the underlying borrowed asset to repay * @param doTransfer If an actual transfer should be performed */ function _liquidate( address liquidator, address borrower, uint256 repayAmount, address mTokenCollateral, bool doTransfer ) internal nonReentrant { _accrueInterest(); ImToken(mTokenCollateral).accrueInterest(); // emits borrow-specific logs on errors, so we don't need to __liquidate(liquidator, borrower, repayAmount, mTokenCollateral, doTransfer); } /** * @notice Transfers collateral tokens (this market) to the liquidator. * @dev Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another mToken. * Its absolutely critical to use msg.sender as the seizer mToken and not a parameter. * @param seizerToken The contract seizing the collateral (i.e. borrowed mToken) * @param liquidator The account receiving seized collateral * @param borrower The account having collateral seized * @param seizeTokens The number of mTokens to seize */ function _seize(address seizerToken, address liquidator, address borrower, uint256 seizeTokens) internal { IOperatorDefender(operator).beforeMTokenSeize(address(this), seizerToken, liquidator, borrower); require(borrower != liquidator, mToken_InvalidInput()); /* * We calculate the new borrower and liquidator token balances, failing on underflow/overflow: * borrowerTokensNew = accountTokens[borrower] - seizeTokens * liquidatorTokensNew = accountTokens[liquidator] + seizeTokens */ uint256 protocolSeizeTokens = mul_(seizeTokens, Exp({mantissa: PROTOCOL_SEIZE_SHARE_MANTISSA})); uint256 liquidatorSeizeTokens = seizeTokens - protocolSeizeTokens; Exp memory exchangeRate = Exp({mantissa: _exchangeRateStored()}); uint256 protocolSeizeAmount = mul_ScalarTruncate(exchangeRate, protocolSeizeTokens); uint256 totalReservesNew = totalReserves + protocolSeizeAmount; ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) /* We write the calculated values into storage */ totalReserves = totalReservesNew; totalSupply = totalSupply - protocolSeizeTokens; accountTokens[borrower] = accountTokens[borrower] - seizeTokens; accountTokens[liquidator] = accountTokens[liquidator] + liquidatorSeizeTokens; /* Emit a Transfer event */ emit Transfer(borrower, liquidator, liquidatorSeizeTokens); emit Transfer(borrower, address(this), protocolSeizeTokens); emit ReservesAdded(address(this), protocolSeizeAmount, totalReservesNew); } /** * @notice Accrues interest and reduces reserves by transferring from msg.sender * @param addAmount Amount of addition to reserves */ function _addReserves(uint256 addAmount) internal nonReentrant { _accrueInterest(); // totalReserves + actualAddAmount uint256 totalReservesNew; uint256 actualAddAmount; ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) /* * We call doTransferIn for the caller and the addAmount * Note: The mToken must handle variations between ERC-20 and ETH underlying. * On success, the mToken holds an additional addAmount of cash. * doTransferIn reverts if anything goes wrong, since we can't be sure if side effects occurred. * it returns the amount actually transferred, in case of a fee. */ actualAddAmount = _doTransferIn(msg.sender, addAmount); initialExchangeRateMantissa += actualAddAmount; totalReservesNew = totalReserves + actualAddAmount; // Store reserves[n+1] = reserves[n] + actualAddAmount totalReserves = totalReservesNew; /* Emit NewReserves(admin, actualAddAmount, reserves[n+1]) */ emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew); } // ----------- PRIVATE ------------ /** * @notice The liquidator liquidates the borrowers collateral. * The collateral seized is transferred to the liquidator. * @param liquidator The address repaying the borrow and seizing collateral * @param borrower The borrower of this mToken to be liquidated * @param mTokenCollateral The market in which to seize collateral from the borrower * @param repayAmount The amount of the underlying borrowed asset to repay * @param doTransfer If an actual transfer should be performed */ function __liquidate( address liquidator, address borrower, uint256 repayAmount, address mTokenCollateral, bool doTransfer ) internal { require(borrower != liquidator, mToken_InvalidInput()); require(repayAmount > 0 && repayAmount != type(uint256).max, mToken_InvalidInput()); IOperatorDefender(operator).beforeMTokenLiquidate(address(this), mTokenCollateral, borrower, repayAmount); require( ImToken(mTokenCollateral).accrualBlockNumber() == _getBlockNumber(), mToken_CollateralBlockNumberNotValid() ); /* Fail if repayBorrow fails */ uint256 actualRepayAmount = __repay(liquidator, borrower, repayAmount, doTransfer); ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) /* We calculate the number of collateral tokens that will be seized */ uint256 seizeTokens = IOperator(operator).liquidateCalculateSeizeTokens(address(this), mTokenCollateral, actualRepayAmount); /* Revert if borrower collateral token balance < seizeTokens */ require(ImToken(mTokenCollateral).balanceOf(borrower) >= seizeTokens, mToken_LiquidateSeizeTooMuch()); // If this is also the collateral, run _seize to avoid re-entrancy, otherwise make an external call if (address(mTokenCollateral) == address(this)) { _seize(address(this), liquidator, borrower, seizeTokens); } else { ImToken(mTokenCollateral).seize(liquidator, borrower, seizeTokens); } /* We emit a LiquidateBorrow event */ emit LiquidateBorrow(liquidator, borrower, actualRepayAmount, address(mTokenCollateral), seizeTokens); } /** * @notice Borrows are repaid by another user (possibly the borrower). * @param payer the account paying off the borrow * @param borrower the account with the debt being payed off * @param repayAmount the amount of underlying tokens being returned, or -1 for the full outstanding amount * @param doTransfer If an actual transfer should be performed */ function __repay(address payer, address borrower, uint256 repayAmount, bool doTransfer) private returns (uint256) { IOperatorDefender(operator).beforeMTokenRepay(address(this), borrower); /* We fetch the amount the borrower owes, with accumulated interest */ uint256 accountBorrowsPrev = _borrowBalanceStored(borrower); /* If repayAmount == type(uint256).max , repayAmount = accountBorrows */ uint256 repayAmountFinal = repayAmount == type(uint256).max ? accountBorrowsPrev : repayAmount; ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) /* * We call _doTransferIn for the payer and the repayAmount * Note: The mToken must handle variations between ERC-20 and ETH underlying. * On success, the mToken holds an additional repayAmount of cash. * _doTransferIn reverts if anything goes wrong, since we can't be sure if side effects occurred. * it returns the amount actually transferred, in case of a fee. */ uint256 actualRepayAmount = doTransfer ? _doTransferIn(payer, repayAmountFinal) : repayAmountFinal; initialExchangeRateMantissa += actualRepayAmount; /* * We calculate the new borrower and total borrow balances, failing on underflow: * accountBorrowsNew = accountBorrows - actualRepayAmount * totalBorrowsNew = totalBorrows - actualRepayAmount */ uint256 accountBorrowsNew = accountBorrowsPrev - actualRepayAmount; uint256 totalBorrowsNew = totalBorrows - actualRepayAmount; /* We write the previously calculated values into storage */ accountBorrows[borrower].principal = accountBorrowsNew; accountBorrows[borrower].interestIndex = borrowIndex; totalBorrows = totalBorrowsNew; /* We emit a RepayBorrow event */ emit RepayBorrow(payer, borrower, actualRepayAmount, accountBorrowsNew, totalBorrowsNew); return actualRepayAmount; } /** * @notice Users borrow assets from the protocol to their own address * @param borrowAmount The amount of the underlying asset to borrow */ function __borrow(address payable borrower, uint256 borrowAmount, bool doTransfer) private { IOperatorDefender(operator).beforeMTokenBorrow(address(this), borrower, borrowAmount); require(_getCashPrior() >= borrowAmount, mToken_BorrowCashNotAvailable()); /* * We calculate the new borrower and total borrow balances, failing on overflow: * accountBorrowNew = accountBorrow + borrowAmount * totalBorrowsNew = totalBorrows + borrowAmount */ uint256 accountBorrowsPrev = _borrowBalanceStored(borrower); uint256 accountBorrowsNew = accountBorrowsPrev + borrowAmount; uint256 totalBorrowsNew = totalBorrows + borrowAmount; ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) /* * We write the previously calculated values into storage. * Note: Avoid token reentrancy attacks by writing increased borrow before external transfer. `*/ accountBorrows[borrower].principal = accountBorrowsNew; accountBorrows[borrower].interestIndex = borrowIndex; totalBorrows = totalBorrowsNew; if (doTransfer) { /* * We invoke _doTransferOut for the borrower and the borrowAmount. * Note: The mToken must handle variations between ERC-20 and ETH underlying. * On success, the mToken borrowAmount less of cash. * _doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred. */ _doTransferOut(borrower, borrowAmount); } initialExchangeRateMantissa -= borrowAmount; /* We emit a Borrow event */ emit Borrow(borrower, borrowAmount, accountBorrowsNew, totalBorrowsNew); } function __redeem(address payable redeemer, uint256 redeemTokensIn, uint256 redeemAmountIn, bool doTransfer) private { require(redeemTokensIn == 0 || redeemAmountIn == 0, mToken_InvalidInput()); /* exchangeRate = invoke Exchange Rate Stored() */ Exp memory exchangeRate = Exp({mantissa: _exchangeRateStored()}); uint256 redeemTokens; uint256 redeemAmount; /* If redeemTokensIn > 0: */ if (redeemTokensIn > 0) { /* * We calculate the exchange rate and the amount of underlying to be redeemed: * redeemTokens = redeemTokensIn * redeemAmount = redeemTokensIn x exchangeRateCurrent */ redeemTokens = redeemTokensIn; redeemAmount = mul_ScalarTruncate(exchangeRate, redeemTokensIn); } else { /* * We get the current exchange rate and calculate the amount to be redeemed: * redeemTokens = redeemAmountIn / exchangeRate * redeemAmount = redeemAmountIn */ redeemTokens = div_(redeemAmountIn, exchangeRate); redeemAmount = redeemAmountIn; } if (redeemTokens == 0 && redeemAmount == 0) revert mToken_RedeemEmpty(); /* Fail if redeem not allowed */ IOperatorDefender(operator).beforeMTokenRedeem(address(this), redeemer, redeemTokens); require(_getCashPrior() >= redeemAmount, mToken_RedeemCashNotAvailable()); ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) /* * We write the previously calculated values into storage. * Note: Avoid token reentrancy attacks by writing reduced supply before external transfer. */ totalSupply = totalSupply - redeemTokens; accountTokens[redeemer] = accountTokens[redeemer] - redeemTokens; /* * We invoke _doTransferOut for the redeemer and the redeemAmount. * Note: The mToken must handle variations between ERC-20 and ETH underlying. * On success, the mToken has redeemAmount less of cash. * _doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred. */ if (doTransfer) _doTransferOut(redeemer, redeemAmount); initialExchangeRateMantissa -= redeemAmount; /* We emit a Transfer event, and a Redeem event */ emit Transfer(redeemer, address(this), redeemTokens); emit Redeem(redeemer, redeemAmount, redeemTokens); } /** * @notice User supplies assets into the market and receives mTokens in exchange * @dev Assumes interest has already been accrued up to the current block * @param minter The address of the account which is supplying the assets * @param mintAmount The amount of the underlying asset to supply * @param doTransfer If an actual transfer should be performed */ function __mint(address minter, uint256 mintAmount, bool doTransfer) private { IOperatorDefender(operator).beforeMTokenMint(address(this), minter); Exp memory exchangeRate = Exp({mantissa: _exchangeRateStored()}); ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) /* * We call `_doTransferIn` for the minter and the mintAmount. * Note: The mToken must handle variations between ERC-20 and ETH underlying. * `_doTransferIn` reverts if anything goes wrong, since we can't be sure if * side-effects occurred. The function returns the amount actually transferred, * in case of a fee. On success, the mToken holds an additional `actualMintAmount` * of cash. */ uint256 actualMintAmount = doTransfer ? _doTransferIn(minter, mintAmount) : mintAmount; initialExchangeRateMantissa += actualMintAmount; /* * We get the current exchange rate and calculate the number of mTokens to be minted: * mintTokens = actualMintAmount / exchangeRate */ uint256 mintTokens = div_(actualMintAmount, exchangeRate); // avoid exchangeRate manipulation if (totalSupply == 0) { totalSupply = 1000; accountTokens[address(0)] = 1000; mintTokens -= 1000; } /* * We calculate the new total supply of mTokens and minter token balance, checking for overflow: * totalSupplyNew = totalSupply + mintTokens * accountTokensNew = accountTokens[minter] + mintTokens * And write them into storage */ totalSupply = totalSupply + mintTokens; accountTokens[minter] = accountTokens[minter] + mintTokens; /* We emit a Mint event, and a Transfer event */ emit Mint(minter, actualMintAmount, mintTokens); emit Transfer(address(this), minter, mintTokens); /* We call the defense hook */ IOperatorDefender(operator).afterMTokenMint(address(this)); } /** * @notice Transfer `tokens` tokens from `src` to `dst` by `spender` * @dev Called by both `transfer` and `transferFrom` internally * @param spender The address of the account performing the transfer * @param src The address of the source account * @param dst The address of the destination account * @param tokens The number of tokens to transfer */ function _transferTokens(address spender, address src, address dst, uint256 tokens) private { IOperatorDefender(operator).beforeMTokenTransfer(address(this), src, dst, tokens); require(src != dst, mToken_TransferNotValid()); /* Get the allowance, infinite for the account owner */ uint256 startingAllowance = 0; if (spender == src) { startingAllowance = type(uint256).max; } else { startingAllowance = transferAllowances[src][spender]; } /* Do the calculations, checking for {under,over}flow */ uint256 allowanceNew = startingAllowance - tokens; uint256 srcTokensNew = accountTokens[src] - tokens; uint256 dstTokensNew = accountTokens[dst] + tokens; ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) accountTokens[src] = srcTokensNew; accountTokens[dst] = dstTokensNew; /* Eat some of the allowance (if necessary) */ if (startingAllowance != type(uint256).max) { transferAllowances[src][spender] = allowanceNew; } /* We emit a Transfer event */ emit Transfer(src, dst, tokens); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity =0.8.28; /* _____ _____ __ ____ _____ | | _ | | | \| _ | | | | | | |__| | | | |_|_|_|__|__|_____|____/|__|__| */ /** * @title IInterestRateModel * @notice Interface for the interest rate contracts */ interface IInterestRateModel { /// @notice Emitted when interest rate parameters are updated /// @param baseRatePerBlock The base rate per block /// @param multiplierPerBlock The multiplier per block for the interest rate slope /// @param jumpMultiplierPerBlock The multiplier after hitting the kink /// @param kink The utilization point where the jump multiplier is applied event NewInterestParams( uint256 baseRatePerBlock, uint256 multiplierPerBlock, uint256 jumpMultiplierPerBlock, uint256 kink ); /** * @notice Should return true */ function isInterestRateModel() external view returns (bool); /** * @notice The approximate number of blocks per year that is assumed by the interest rate model * @return The number of blocks per year */ function blocksPerYear() external view returns (uint256); /** * @notice The multiplier of utilization rate that gives the slope of the interest rate * @return The multiplier per block */ function multiplierPerBlock() external view returns (uint256); /** * @notice The base interest rate which is the y-intercept when utilization rate is 0 * @return The base rate per block */ function baseRatePerBlock() external view returns (uint256); /** * @notice The multiplierPerBlock after hitting a specified utilization point * @return The jump multiplier per block */ function jumpMultiplierPerBlock() external view returns (uint256); /** * @notice The utilization point at which the jump multiplier is applied * @return The utilization point (kink) */ function kink() external view returns (uint256); /** * @notice A name for user-friendliness, e.g. WBTC * @return The name of the interest rate model */ function name() external view returns (string memory); /** * @notice Calculates the utilization rate of the market * @param cash The total cash in the market * @param borrows The total borrows in the market * @param reserves The total reserves in the market * @return The utilization rate as a mantissa between [0, 1e18] */ function utilizationRate(uint256 cash, uint256 borrows, uint256 reserves) external pure returns (uint256); /** * @notice Returns the current borrow rate per block for the market * @param cash The total cash in the market * @param borrows The total borrows in the market * @param reserves The total reserves in the market * @return The current borrow rate per block, scaled by 1e18 */ function getBorrowRate(uint256 cash, uint256 borrows, uint256 reserves) external view returns (uint256); /** * @notice Returns the current supply rate per block for the market * @param cash The total cash in the market * @param borrows The total borrows in the market * @param reserves The total reserves in the market * @param reserveFactorMantissa The current reserve factor for the market * @return The current supply rate per block, scaled by 1e18 */ function getSupplyRate(uint256 cash, uint256 borrows, uint256 reserves, uint256 reserveFactorMantissa) external view returns (uint256); }
// SPDX-License-Identifier: UNLICENSED pragma solidity =0.8.28; /* _____ _____ __ ____ _____ | | _ | | | \| _ | | | | | | |__| | | | |_|_|_|__|__|_____|____/|__|__| */ import {IRoles} from "./IRoles.sol"; import {ImTokenOperationTypes} from "./ImToken.sol"; interface IOperatorData { struct Market { // Whether or not this market is listed bool isListed; // Multiplier representing the most one can borrow against their collateral in this market. // For instance, 0.9 to allow borrowing 90% of collateral value. // Must be between 0 and 1, and stored as a mantissa. uint256 collateralFactorMantissa; // Per-market mapping of "accounts in this asset" mapping(address => bool) accountMembership; // Whether or not this market receives MALDA bool isMalded; } } interface IOperatorDefender { /** * @notice Checks if the account should be allowed to transfer tokens in the given market * @param mToken The market to verify the transfer against * @param src The account which sources the tokens * @param dst The account which receives the tokens * @param transferTokens The number of mTokens to transfer */ function beforeMTokenTransfer(address mToken, address src, address dst, uint256 transferTokens) external; /** * @notice Checks if the account should be allowed to mint tokens in the given market * @param mToken The market to verify the mint against * @param minter The account which would get the minted tokens */ function beforeMTokenMint(address mToken, address minter) external; /** * @notice Validates mint and reverts on rejection. May emit logs. * @param mToken Asset being minted */ function afterMTokenMint(address mToken) external view; /** * @notice Checks if the account should be allowed to redeem tokens in the given market * @param mToken The market to verify the redeem against * @param redeemer The account which would redeem the tokens * @param redeemTokens The number of mTokens to exchange for the underlying asset in the market */ function beforeMTokenRedeem(address mToken, address redeemer, uint256 redeemTokens) external; /** * @notice Checks if the account should be allowed to borrow the underlying asset of the given market * @param mToken The market to verify the borrow against * @param borrower The account which would borrow the asset * @param borrowAmount The amount of underlying the account would borrow */ function beforeMTokenBorrow(address mToken, address borrower, uint256 borrowAmount) external; /** * @notice Checks if the account should be allowed to repay a borrow in the given market * @param mToken The market to verify the repay against * @param borrower The account which would borrowed the asset */ function beforeMTokenRepay(address mToken, address borrower) external; /** * @notice Checks if the liquidation should be allowed to occur * @param mTokenBorrowed Asset which was borrowed by the borrower * @param mTokenCollateral Asset which was used as collateral and will be seized * @param borrower The address of the borrower * @param repayAmount The amount of underlying being repaid */ function beforeMTokenLiquidate( address mTokenBorrowed, address mTokenCollateral, address borrower, uint256 repayAmount ) external view; /** * @notice Checks if the seizing of assets should be allowed to occur * @param mTokenCollateral Asset which was used as collateral and will be seized * @param mTokenBorrowed Asset which was borrowed by the borrower * @param liquidator The address repaying the borrow and seizing the collateral * @param borrower The address of the borrower */ function beforeMTokenSeize(address mTokenCollateral, address mTokenBorrowed, address liquidator, address borrower) external; } interface IOperator { // ----------- VIEW ------------ /** * @notice Should return true */ function isOperator() external view returns (bool); /** * @notice Returns if operation is paused * @param mToken The mToken to check * @param _type the operation type */ function isPaused(address mToken, ImTokenOperationTypes.OperationType _type) external view returns (bool); /** * @notice Roles manager */ function rolesOperator() external view returns (IRoles); /** * @notice Oracle which gives the price of any given asset */ function oracleOperator() external view returns (address); /** * @notice Multiplier used to calculate the maximum repayAmount when liquidating a borrow */ function closeFactorMantissa() external view returns (uint256); /** * @notice Multiplier representing the discount on collateral that a liquidator receives */ function liquidationIncentiveMantissa() external view returns (uint256); /** * @notice Returns the assets an account has entered * @param _user The address of the account to pull assets for * @return mTokens A dynamic list with the assets the account has entered */ function getAssetsIn(address _user) external view returns (address[] memory mTokens); /** * @notice A list of all markets */ function getAllMarkets() external view returns (address[] memory mTokens); /** * @notice Borrow caps enforced by borrowAllowed for each mToken address. Defaults to zero which corresponds to unlimited borrowing. */ function borrowCaps(address _mToken) external view returns (uint256); /** * @notice Supply caps enforced by supplyAllowed for each mToken address. Defaults to zero which corresponds to unlimited supplying. */ function supplyCaps(address _mToken) external view returns (uint256); /** * @notice Reward Distributor to markets supply and borrow (including protocol token) */ function rewardDistributor() external view returns (address); /** * @notice Returns whether the given account is entered in the given asset * @param account The address of the account to check * @param mToken The mToken to check * @return True if the account is in the asset, otherwise false. */ function checkMembership(address account, address mToken) external view returns (bool); /** * @notice Determine the current account liquidity wrt collateral requirements * @return account liquidity in excess of collateral requirements, * account shortfall below collateral requirements) */ function getAccountLiquidity(address account) external view returns (uint256, uint256); /** * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed * @param mTokenModify The market to hypothetically redeem/borrow in * @param account The account to determine liquidity for * @param redeemTokens The number of tokens to hypothetically redeem * @param borrowAmount The amount of underlying to hypothetically borrow * @return hypothetical account liquidity in excess of collateral requirements, * hypothetical account shortfall below collateral requirements) */ function getHypotheticalAccountLiquidity( address account, address mTokenModify, uint256 redeemTokens, uint256 borrowAmount ) external view returns (uint256, uint256); /** * @notice Calculate number of tokens of collateral asset to seize given an underlying amount * @dev Used in liquidation (called in mTokenBorrowed.liquidate) * @param mTokenBorrowed The address of the borrowed mToken * @param mTokenCollateral The address of the collateral mToken * @param actualRepayAmount The amount of mTokenBorrowed underlying to convert into mTokenCollateral tokens * @return number of mTokenCollateral tokens to be seized in a liquidation */ function liquidateCalculateSeizeTokens(address mTokenBorrowed, address mTokenCollateral, uint256 actualRepayAmount) external view returns (uint256); /** * @notice Returns true if the given mToken market has been deprecated * @dev All borrows in a deprecated mToken market can be immediately liquidated * @param mToken The market to check if deprecated */ function isDeprecated(address mToken) external view returns (bool); // ----------- ACTIONS ------------ /** * @notice Set pause for a specific operation * @param mToken The market token address * @param _type The pause operation type * @param state The pause operation status */ function setPaused(address mToken, ImTokenOperationTypes.OperationType _type, bool state) external; /** * @notice Add assets to be included in account liquidity calculation * @param _mTokens The list of addresses of the mToken markets to be enabled */ function enterMarkets(address[] calldata _mTokens) external; /** * @notice Removes asset from sender's account liquidity calculation * @dev Sender must not have an outstanding borrow balance in the asset, * or be providing necessary collateral for an outstanding borrow. * @param _mToken The address of the asset to be removed */ function exitMarket(address _mToken) external; /** * @notice Claim all the MALDA accrued by holder in all markets * @param holder The address to claim MALDA for */ function claimMalda(address holder) external; /** * @notice Claim all the MALDA accrued by holder in the specified markets * @param holder The address to claim MALDA for * @param mTokens The list of markets to claim MALDA in */ function claimMalda(address holder, address[] memory mTokens) external; /** * @notice Claim all MALDA accrued by the holders * @param holders The addresses to claim MALDA for * @param mTokens The list of markets to claim MALDA in * @param borrowers Whether or not to claim MALDA earned by borrowing * @param suppliers Whether or not to claim MALDA earned by supplying */ function claimMalda(address[] memory holders, address[] memory mTokens, bool borrowers, bool suppliers) external; }
// SPDX-License-Identifier: UNLICENSED pragma solidity =0.8.28; /* _____ _____ __ ____ _____ | | _ | | | \| _ | | | | | | |__| | | | |_|_|_|__|__|_____|____/|__|__| */ // interfaces import {IRoles} from "src/interfaces/IRoles.sol"; import {IOperator} from "src/interfaces/IOperator.sol"; import {IInterestRateModel} from "src/interfaces/IInterestRateModel.sol"; import {mTokenStorage} from "./mTokenStorage.sol"; abstract contract mTokenConfiguration is mTokenStorage { // ----------- MODIFIERS ------------ modifier onlyAdmin() { require(msg.sender == admin, mToken_OnlyAdmin()); _; } // ----------- OWNER ------------ /** * @notice Sets a new Operator for the market * @dev Admin function to set a new operator */ function setOperator(address _operator) external onlyAdmin { _setOperator(_operator); } /** * @notice Sets a new Operator for the market * @dev Admin function to set a new operator */ function setRolesOperator(address _roles) external onlyAdmin { require(_roles != address(0), mToken_InvalidInput()); emit NewRolesOperator(address(rolesOperator), _roles); rolesOperator = IRoles(_roles); } /** * @notice accrues interest and updates the interest rate model using _setInterestRateModelFresh * @dev Admin function to accrue interest and update the interest rate model * @param newInterestRateModel the new interest rate model to use */ function setInterestRateModel(address newInterestRateModel) external onlyAdmin { _accrueInterest(); // emits interest-rate-model-update-specific logs on errors, so we don't need to. return _setInterestRateModel(newInterestRateModel); } function setBorrowRateMaxMantissa(uint256 maxMantissa) external onlyAdmin { uint256 _oldVal = borrowRateMaxMantissa; borrowRateMaxMantissa = maxMantissa; // validate new mantissa _accrueInterest(); emit NewBorrowRateMaxMantissa(_oldVal, maxMantissa); } /** * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh * @dev Admin function to accrue interest and set a new reserve factor */ function setReserveFactor(uint256 newReserveFactorMantissa) external onlyAdmin { _accrueInterest(); require(newReserveFactorMantissa <= RESERVE_FACTOR_MAX_MANTISSA, mToken_ReserveFactorTooHigh()); emit NewReserveFactor(reserveFactorMantissa, newReserveFactorMantissa); reserveFactorMantissa = newReserveFactorMantissa; } /** * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. * @param newPendingAdmin New pending admin. */ function setPendingAdmin(address payable newPendingAdmin) external onlyAdmin { // Emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin) emit NewPendingAdmin(pendingAdmin, newPendingAdmin); // Store pendingAdmin with value newPendingAdmin pendingAdmin = newPendingAdmin; } /** * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin * @dev Admin function for pending admin to accept role and update admin */ function acceptAdmin() external { // Check caller is pendingAdmin require(msg.sender == pendingAdmin, mToken_OnlyAdmin()); // Save current values for inclusion in log address oldAdmin = admin; address oldPendingAdmin = pendingAdmin; // Store admin with value pendingAdmin admin = pendingAdmin; // Clear the pending value pendingAdmin = payable(address(0)); emit NewAdmin(oldAdmin, admin); emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); } // ----------- INTERNAL ------------ /** * @notice updates the interest rate model (*requires fresh interest accrual) * @dev Admin function to update the interest rate model * @param newInterestRateModel the new interest rate model to use */ function _setInterestRateModel(address newInterestRateModel) internal onlyAdmin { // Ensure invoke newInterestRateModel.isInterestRateModel() returns true require(IInterestRateModel(newInterestRateModel).isInterestRateModel(), mToken_MarketMethodNotValid()); emit NewMarketInterestRateModel(interestRateModel, newInterestRateModel); interestRateModel = newInterestRateModel; } function _setOperator(address _operator) internal { require(IOperator(_operator).isOperator(), mToken_MarketMethodNotValid()); emit NewOperator(operator, _operator); operator = _operator; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol) pragma solidity ^0.8.20; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant NOT_ENTERED = 1; uint256 private constant ENTERED = 2; uint256 private _status; /** * @dev Unauthorized reentrant call. */ error ReentrancyGuardReentrantCall(); constructor() { _status = NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be NOT_ENTERED if (_status == ENTERED) { revert ReentrancyGuardReentrantCall(); } // Any calls to nonReentrant after this point will fail _status = ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return _status == ENTERED; } }
// SPDX-License-Identifier: UNLICENSED pragma solidity =0.8.28; /* _____ _____ __ ____ _____ | | _ | | | \| _ | | | | | | |__| | | | |_|_|_|__|__|_____|____/|__|__| */ // interfaces import {IRoles} from "src/interfaces/IRoles.sol"; import {ImToken, ImTokenMinimal} from "src/interfaces/ImToken.sol"; import {IInterestRateModel} from "src/interfaces/IInterestRateModel.sol"; // contracts import {ExponentialNoError} from "src/utils/ExponentialNoError.sol"; abstract contract mTokenStorage is ImToken, ExponentialNoError { // ----------- ACCESS STORAGE ------------ /** * @inheritdoc ImToken */ address payable public admin; /** * @inheritdoc ImToken */ address payable public pendingAdmin; /** * @inheritdoc ImToken */ address public operator; /** * @inheritdoc ImToken */ IRoles public rolesOperator; // ----------- TOKENS STORAGE ------------ /** * @inheritdoc ImTokenMinimal */ string public name; /** * @inheritdoc ImTokenMinimal */ string public symbol; /** * @inheritdoc ImTokenMinimal */ uint8 public decimals; // ----------- MARKET STORAGE ------------ /** * @inheritdoc ImToken */ address public interestRateModel; /** * @inheritdoc ImToken */ uint256 public reserveFactorMantissa; /** * @inheritdoc ImToken */ uint256 public accrualBlockNumber; /** * @inheritdoc ImToken */ uint256 public borrowIndex; /** * @inheritdoc ImToken */ uint256 public totalBorrows; /** * @inheritdoc ImToken */ uint256 public totalReserves; /** * @inheritdoc ImTokenMinimal */ uint256 public totalSupply; /** * @notice Maximum borrow rate that can ever be applied (.0005% / block) */ uint256 public borrowRateMaxMantissa = 0.00004e16; /** * @notice Container for borrow balance information * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action * @member interestIndex Global borrowIndex as of the most recent balance-changing action */ struct BorrowSnapshot { uint256 principal; uint256 interestIndex; } // Mapping of account addresses to outstanding borrow balances mapping(address => BorrowSnapshot) internal accountBorrows; // Official record of token balances for each account mapping(address => uint256) internal accountTokens; // Approved token transfer amounts on behalf of others mapping(address => mapping(address => uint256)) internal transferAllowances; /** * @notice Initial exchange rate used when minting the first mTokens (used when totalSupply = 0) */ uint256 internal initialExchangeRateMantissa; /** * @notice Maximum fraction of interest that can be set aside for reserves */ uint256 internal constant RESERVE_FACTOR_MAX_MANTISSA = 1e18; /** * @notice Share of seized collateral that is added to reserves */ uint256 internal constant PROTOCOL_SEIZE_SHARE_MANTISSA = 2.8e16; //2.8% // ----------- ERRORS ------------ error mToken_OnlyAdmin(); error mToken_RedeemEmpty(); error mToken_InvalidInput(); error mToken_OnlyAdminOrRole(); error mToken_TransferNotValid(); error mToken_BorrowRateTooHigh(); error mToken_AlreadyInitialized(); error mToken_ReserveFactorTooHigh(); error mToken_BlockNumberNotValid(); error mToken_ExchangeRateNotValid(); error mToken_MarketMethodNotValid(); error mToken_LiquidateSeizeTooMuch(); error mToken_RedeemCashNotAvailable(); error mToken_BorrowCashNotAvailable(); error mToken_ReserveCashNotAvailable(); error mToken_RedeemTransferOutNotPossible(); error mToken_CollateralBlockNumberNotValid(); // ----------- ACCESS EVENTS ------------ /** * @notice Event emitted when rolesOperator is changed */ event NewRolesOperator(address indexed oldRoles, address indexed newRoles); /** * @notice Event emitted when pendingAdmin is changed */ event NewPendingAdmin(address indexed oldPendingAdmin, address indexed newPendingAdmin); /** * @notice Event emitted when pendingAdmin is accepted, which means admin is updated */ event NewAdmin(address indexed oldAdmin, address indexed newAdmin); /** * @notice Event emitted when Operator is changed */ event NewOperator(address indexed oldOperator, address indexed newOperator); // ----------- TOKENS EVENTS ------------ /** * @notice EIP20 Transfer event */ event Transfer(address indexed from, address indexed to, uint256 amount); /** * @notice EIP20 Approval event */ event Approval(address indexed owner, address indexed spender, uint256 amount); // ----------- MARKETS EVENTS ------------ /** * @notice Event emitted when interest is accrued */ event AccrueInterest(uint256 cashPrior, uint256 interestAccumulated, uint256 borrowIndex, uint256 totalBorrows); /** * @notice Event emitted when tokens are minted */ event Mint(address indexed minter, uint256 mintAmount, uint256 mintTokens); /** * @notice Event emitted when tokens are redeemed */ event Redeem(address indexed redeemer, uint256 redeemAmount, uint256 redeemTokens); /** * @notice Event emitted when underlying is borrowed */ event Borrow(address indexed borrower, uint256 borrowAmount, uint256 accountBorrows, uint256 totalBorrows); /** * @notice Event emitted when a borrow is repaid */ event RepayBorrow( address indexed payer, address indexed borrower, uint256 repayAmount, uint256 accountBorrows, uint256 totalBorrows ); /** * @notice Event emitted when a borrow is liquidated */ event LiquidateBorrow( address indexed liquidator, address indexed borrower, uint256 repayAmount, address indexed mTokenCollateral, uint256 seizeTokens ); /** * @notice Event emitted when interestRateModel is changed */ event NewMarketInterestRateModel(address indexed oldInterestRateModel, address indexed newInterestRateModel); /** * @notice Event emitted when the reserve factor is changed */ event NewReserveFactor(uint256 oldReserveFactorMantissa, uint256 newReserveFactorMantissa); /** * @notice Event emitted when the reserves are added */ event ReservesAdded(address indexed benefactor, uint256 addAmount, uint256 newTotalReserves); /** * @notice Event emitted when the reserves are reduced */ event ReservesReduced(address indexed admin, uint256 reduceAmount, uint256 newTotalReserves); /** * @notice Event emitted when the borrow max mantissa is updated */ event NewBorrowRateMaxMantissa(uint256 oldVal, uint256 maxMantissa); // ----------- VIRTUAL ------------ /** * @inheritdoc ImToken */ function accrueInterest() external virtual { _accrueInterest(); } /** * @dev Function to simply retrieve block number * This exists mainly for inheriting test contracts to stub this result. */ function _getBlockNumber() internal view virtual returns (uint256) { return block.timestamp; } /** * @notice Calculates the exchange rate from the underlying to the MToken * @dev This function does not accrue interest before calculating the exchange rate * Can generate issues if inflated by an attacker when market is created * Solution: use 0 collateral factor initially * @return calculated exchange rate scaled by 1e18 */ function _exchangeRateStored() internal view virtual returns (uint256) { uint256 _totalSupply = totalSupply; if (_totalSupply == 0) { /* * If there are no tokens minted: * exchangeRate = initialExchangeRate */ return initialExchangeRateMantissa; } else { /* * Otherwise: * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply */ uint256 totalCash = _getCashPrior(); uint256 cashPlusBorrowsMinusReserves = totalCash + totalBorrows - totalReserves; uint256 exchangeRate = (cashPlusBorrowsMinusReserves * expScale) / _totalSupply; return exchangeRate; } } /** * @notice Gets balance of this contract in terms of the underlying * @dev This excludes the value of the current message, if any * @return The quantity of underlying owned by this contract */ function _getCashPrior() internal view virtual returns (uint256); /** * @dev Performs a transfer in, reverting upon failure. Returns the amount actually transferred to the protocol, in case of a fee. * This may revert due to insufficient balance or insufficient allowance. */ function _doTransferIn(address from, uint256 amount) internal virtual returns (uint256); /** * @dev Performs a transfer out, ideally returning an explanatory error code upon failure rather than reverting. * If caller has not called checked protocol's balance, may revert due to insufficient cash held in the contract. * If caller has checked protocol's balance, and verified it is >= amount, this should not revert in normal conditions. */ function _doTransferOut(address payable to, uint256 amount) internal virtual; // ----------- NON-VIRTUAL ------------ function _accrueInterest() internal { /* Remember the initial block number */ uint256 currentBlockNumber = _getBlockNumber(); uint256 accrualBlockNumberPrior = accrualBlockNumber; /* Short-circuit accumulating 0 interest */ if (accrualBlockNumberPrior == currentBlockNumber) return; /* Read the previous values out of storage */ uint256 cashPrior = _getCashPrior(); uint256 borrowsPrior = totalBorrows; uint256 reservesPrior = totalReserves; uint256 borrowIndexPrior = borrowIndex; /* Calculate the current borrow interest rate */ uint256 borrowRateMantissa = IInterestRateModel(interestRateModel).getBorrowRate(cashPrior, borrowsPrior, reservesPrior); require(borrowRateMantissa <= borrowRateMaxMantissa, mToken_BorrowRateTooHigh()); /* Calculate the number of blocks elapsed since the last accrual */ uint256 blockDelta = currentBlockNumber - accrualBlockNumberPrior; /* * Calculate the interest accumulated into borrows and reserves and the new index: * simpleInterestFactor = borrowRate * blockDelta * interestAccumulated = simpleInterestFactor * totalBorrows * totalBorrowsNew = interestAccumulated + totalBorrows * totalReservesNew = interestAccumulated * reserveFactor + totalReserves * borrowIndexNew = simpleInterestFactor * borrowIndex + borrowIndex */ Exp memory simpleInterestFactor = mul_(Exp({mantissa: borrowRateMantissa}), blockDelta); uint256 interestAccumulated = mul_ScalarTruncate(simpleInterestFactor, borrowsPrior); uint256 totalBorrowsNew = interestAccumulated + borrowsPrior; uint256 totalReservesNew = mul_ScalarTruncateAddUInt(Exp({mantissa: reserveFactorMantissa}), interestAccumulated, reservesPrior); uint256 borrowIndexNew = mul_ScalarTruncateAddUInt(simpleInterestFactor, borrowIndexPrior, borrowIndexPrior); ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) /* We write the previously calculated values into storage */ accrualBlockNumber = currentBlockNumber; borrowIndex = borrowIndexNew; totalBorrows = totalBorrowsNew; totalReserves = totalReservesNew; /* We emit an AccrueInterest event */ emit AccrueInterest(cashPrior, interestAccumulated, borrowIndexNew, totalBorrowsNew); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity =0.8.28; /* _____ _____ __ ____ _____ | | _ | | | \| _ | | | | | | |__| | | | |_|_|_|__|__|_____|____/|__|__| */ /** * @title Exponential module for storing fixed-precision decimals * @author Compound * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: * `Exp({mantissa: 5100000000000000000})`. */ abstract contract ExponentialNoError { uint256 constant expScale = 1e18; uint256 constant doubleScale = 1e36; uint256 constant halfExpScale = expScale / 2; uint256 constant mantissaOne = expScale; struct Exp { uint256 mantissa; } struct Double { uint256 mantissa; } /** * @dev Truncates the given exp to a whole number value. * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 */ function truncate(Exp memory exp) internal pure returns (uint256) { // Note: We are not using careful math here as we're performing a division that cannot fail return exp.mantissa / expScale; } /** * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. */ function mul_ScalarTruncate(Exp memory a, uint256 scalar) internal pure returns (uint256) { Exp memory product = mul_(a, scalar); return truncate(product); } /** * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. */ function mul_ScalarTruncateAddUInt(Exp memory a, uint256 scalar, uint256 addend) internal pure returns (uint256) { Exp memory product = mul_(a, scalar); return add_(truncate(product), addend); } /** * @dev Checks if first Exp is less than second Exp. */ function lessThanExp(Exp memory left, Exp memory right) internal pure returns (bool) { return left.mantissa < right.mantissa; } /** * @dev Checks if left Exp <= right Exp. */ function lessThanOrEqualExp(Exp memory left, Exp memory right) internal pure returns (bool) { return left.mantissa <= right.mantissa; } /** * @dev Checks if left Exp > right Exp. */ function greaterThanExp(Exp memory left, Exp memory right) internal pure returns (bool) { return left.mantissa > right.mantissa; } /** * @dev returns true if Exp is exactly zero */ function isZeroExp(Exp memory value) internal pure returns (bool) { return value.mantissa == 0; } function safe224(uint256 n, string memory errorMessage) internal pure returns (uint224) { require(n < 2 ** 224, errorMessage); return uint224(n); } function safe32(uint256 n, string memory errorMessage) internal pure returns (uint32) { require(n < 2 ** 32, errorMessage); return uint32(n); } function add_(Exp memory a, Exp memory b) internal pure returns (Exp memory) { return Exp({mantissa: add_(a.mantissa, b.mantissa)}); } function add_(Double memory a, Double memory b) internal pure returns (Double memory) { return Double({mantissa: add_(a.mantissa, b.mantissa)}); } function add_(uint256 a, uint256 b) internal pure returns (uint256) { return a + b; } function sub_(Exp memory a, Exp memory b) internal pure returns (Exp memory) { return Exp({mantissa: sub_(a.mantissa, b.mantissa)}); } function sub_(Double memory a, Double memory b) internal pure returns (Double memory) { return Double({mantissa: sub_(a.mantissa, b.mantissa)}); } function sub_(uint256 a, uint256 b) internal pure returns (uint256) { return a - b; } function mul_(Exp memory a, Exp memory b) internal pure returns (Exp memory) { return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale}); } function mul_(Exp memory a, uint256 b) internal pure returns (Exp memory) { return Exp({mantissa: mul_(a.mantissa, b)}); } function mul_(uint256 a, Exp memory b) internal pure returns (uint256) { return mul_(a, b.mantissa) / expScale; } function mul_(Double memory a, Double memory b) internal pure returns (Double memory) { return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale}); } function mul_(Double memory a, uint256 b) internal pure returns (Double memory) { return Double({mantissa: mul_(a.mantissa, b)}); } function mul_(uint256 a, Double memory b) internal pure returns (uint256) { return mul_(a, b.mantissa) / doubleScale; } function mul_(uint256 a, uint256 b) internal pure returns (uint256) { return a * b; } function div_(Exp memory a, Exp memory b) internal pure returns (Exp memory) { return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)}); } function div_(Exp memory a, uint256 b) internal pure returns (Exp memory) { return Exp({mantissa: div_(a.mantissa, b)}); } function div_(uint256 a, Exp memory b) internal pure returns (uint256) { return div_(mul_(a, expScale), b.mantissa); } function div_(Double memory a, Double memory b) internal pure returns (Double memory) { return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)}); } function div_(Double memory a, uint256 b) internal pure returns (Double memory) { return Double({mantissa: div_(a.mantissa, b)}); } function div_(uint256 a, Double memory b) internal pure returns (uint256) { return div_(mul_(a, doubleScale), b.mantissa); } function div_(uint256 a, uint256 b) internal pure returns (uint256) { return a / b; } function fraction(uint256 a, uint256 b) internal pure returns (Double memory) { return Double({mantissa: div_(mul_(a, doubleScale), b)}); } }
{ "remappings": [ "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", "risc0/=lib/risc0-ethereum/contracts/src/", "forge-std/=lib/forge-std/src/", "ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/", "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/", "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/", "risc0-ethereum/=lib/risc0-ethereum/", "solidity-stringutils/=lib/openzeppelin-foundry-upgrades/lib/solidity-stringutils/" ], "optimizer": { "enabled": true, "runs": 2499 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "viaIR": false, "libraries": {} }
Contract ABI
API[{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"ZkVerifier_ImageNotValid","type":"error"},{"inputs":[],"name":"ZkVerifier_InputNotValid","type":"error"},{"inputs":[],"name":"ZkVerifier_VerifierNotSet","type":"error"},{"inputs":[],"name":"mErc20Host_AddressNotValid","type":"error"},{"inputs":[],"name":"mErc20Host_AmountNotValid","type":"error"},{"inputs":[],"name":"mErc20Host_AmountTooBig","type":"error"},{"inputs":[],"name":"mErc20Host_CallerNotAllowed","type":"error"},{"inputs":[],"name":"mErc20Host_ChainNotValid","type":"error"},{"inputs":[],"name":"mErc20Host_DstChainNotValid","type":"error"},{"inputs":[],"name":"mErc20Host_JournalNotValid","type":"error"},{"inputs":[],"name":"mErc20Host_LengthMismatch","type":"error"},{"inputs":[],"name":"mErc20Host_NotRebalancer","type":"error"},{"inputs":[],"name":"mErc20Host_ProofGenerationInputNotValid","type":"error"},{"inputs":[],"name":"mErc20_TokenNotValid","type":"error"},{"inputs":[],"name":"mToken_AlreadyInitialized","type":"error"},{"inputs":[],"name":"mToken_BlockNumberNotValid","type":"error"},{"inputs":[],"name":"mToken_BorrowCashNotAvailable","type":"error"},{"inputs":[],"name":"mToken_BorrowRateTooHigh","type":"error"},{"inputs":[],"name":"mToken_CollateralBlockNumberNotValid","type":"error"},{"inputs":[],"name":"mToken_ExchangeRateNotValid","type":"error"},{"inputs":[],"name":"mToken_InvalidInput","type":"error"},{"inputs":[],"name":"mToken_LiquidateSeizeTooMuch","type":"error"},{"inputs":[],"name":"mToken_MarketMethodNotValid","type":"error"},{"inputs":[],"name":"mToken_OnlyAdmin","type":"error"},{"inputs":[],"name":"mToken_OnlyAdminOrRole","type":"error"},{"inputs":[],"name":"mToken_RedeemCashNotAvailable","type":"error"},{"inputs":[],"name":"mToken_RedeemEmpty","type":"error"},{"inputs":[],"name":"mToken_RedeemTransferOutNotPossible","type":"error"},{"inputs":[],"name":"mToken_ReserveCashNotAvailable","type":"error"},{"inputs":[],"name":"mToken_ReserveFactorTooHigh","type":"error"},{"inputs":[],"name":"mToken_TransferNotValid","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"cashPrior","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"interestAccumulated","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"borrowIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrows","type":"uint256"}],"name":"AccrueInterest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"bool","name":"status","type":"bool"}],"name":"AllowedCallerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"borrowAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"accountBorrows","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrows","type":"uint256"}],"name":"Borrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"_imageId","type":"bytes32"}],"name":"ImageSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"liquidator","type":"address"},{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"repayAmount","type":"uint256"},{"indexed":true,"internalType":"address","name":"mTokenCollateral","type":"address"},{"indexed":false,"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"LiquidateBorrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"uint256","name":"mintAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mintTokens","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldAdmin","type":"address"},{"indexed":true,"internalType":"address","name":"newAdmin","type":"address"}],"name":"NewAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldVal","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"maxMantissa","type":"uint256"}],"name":"NewBorrowRateMaxMantissa","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldInterestRateModel","type":"address"},{"indexed":true,"internalType":"address","name":"newInterestRateModel","type":"address"}],"name":"NewMarketInterestRateModel","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOperator","type":"address"},{"indexed":true,"internalType":"address","name":"newOperator","type":"address"}],"name":"NewOperator","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldPendingAdmin","type":"address"},{"indexed":true,"internalType":"address","name":"newPendingAdmin","type":"address"}],"name":"NewPendingAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldReserveFactorMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newReserveFactorMantissa","type":"uint256"}],"name":"NewReserveFactor","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldRoles","type":"address"},{"indexed":true,"internalType":"address","name":"newRoles","type":"address"}],"name":"NewRolesOperator","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"redeemer","type":"address"},{"indexed":false,"internalType":"uint256","name":"redeemAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"redeemTokens","type":"uint256"}],"name":"Redeem","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"payer","type":"address"},{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"repayAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"accountBorrows","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrows","type":"uint256"}],"name":"RepayBorrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"benefactor","type":"address"},{"indexed":false,"internalType":"uint256","name":"addAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTotalReserves","type":"uint256"}],"name":"ReservesAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"admin","type":"address"},{"indexed":false,"internalType":"uint256","name":"reduceAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTotalReserves","type":"uint256"}],"name":"ReservesReduced","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldVerifier","type":"address"},{"indexed":true,"internalType":"address","name":"newVerifier","type":"address"}],"name":"VerifierSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"msgSender","type":"address"},{"indexed":true,"internalType":"address","name":"srcSender","type":"address"},{"indexed":true,"internalType":"uint32","name":"chainId","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mErc20Host_BorrowExternal","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint32","name":"dstChainId","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mErc20Host_BorrowOnExternsionChain","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"chainId","type":"uint32"},{"indexed":false,"internalType":"bool","name":"status","type":"bool"}],"name":"mErc20Host_ChainStatusUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"msgSender","type":"address"},{"indexed":true,"internalType":"address","name":"srcSender","type":"address"},{"indexed":false,"internalType":"address","name":"userToLiquidate","type":"address"},{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"collateral","type":"address"},{"indexed":false,"internalType":"uint32","name":"srcChainId","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mErc20Host_LiquidateExternal","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"msgSender","type":"address"},{"indexed":true,"internalType":"address","name":"srcSender","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint32","name":"chainId","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mErc20Host_MintExternal","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"msgSender","type":"address"},{"indexed":true,"internalType":"address","name":"srcSender","type":"address"},{"indexed":true,"internalType":"address","name":"position","type":"address"},{"indexed":false,"internalType":"uint32","name":"chainId","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mErc20Host_RepayExternal","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"msgSender","type":"address"},{"indexed":true,"internalType":"address","name":"srcSender","type":"address"},{"indexed":true,"internalType":"uint32","name":"chainId","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mErc20Host_WithdrawExternal","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint32","name":"dstChainId","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mErc20Host_WithdrawOnExtensionChain","type":"event"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"},{"internalType":"address","name":"","type":"address"}],"name":"accAmountInPerChain","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"},{"internalType":"address","name":"","type":"address"}],"name":"accAmountOutPerChain","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"accrualBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accrueInterest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"addAmount","type":"uint256"}],"name":"addReserves","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowedCallers","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"allowedChains","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOfUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"borrowAmount","type":"uint256"}],"name":"borrow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"borrowBalanceCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"borrowBalanceStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"borrowIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint32","name":"dstChainId","type":"uint32"}],"name":"borrowOnExtension","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"borrowRateMaxMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"borrowRatePerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"delegatee","type":"address"}],"name":"delegateMaldaLikeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"exchangeRateCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"exchangeRateStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"extractForRebalancing","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getAccountSnapshot","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCash","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint32","name":"dstId","type":"uint32"}],"name":"getProofData","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"imageId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"underlying_","type":"address"},{"internalType":"address","name":"operator_","type":"address"},{"internalType":"address","name":"interestRateModel_","type":"address"},{"internalType":"uint256","name":"initialExchangeRateMantissa_","type":"uint256"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"uint8","name":"decimals_","type":"uint8"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"underlying_","type":"address"},{"internalType":"address","name":"operator_","type":"address"},{"internalType":"address","name":"interestRateModel_","type":"address"},{"internalType":"uint256","name":"initialExchangeRateMantissa_","type":"uint256"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"uint8","name":"decimals_","type":"uint8"},{"internalType":"address payable","name":"admin_","type":"address"},{"internalType":"address","name":"zkVerifier_","type":"address"},{"internalType":"address","name":"roles_","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator_","type":"address"},{"internalType":"address","name":"interestRateModel_","type":"address"},{"internalType":"uint256","name":"initialExchangeRateMantissa_","type":"uint256"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"uint8","name":"decimals_","type":"uint8"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_verifier","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"interestRateModel","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"caller","type":"address"}],"name":"isCallerAllowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isMToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"repayAmount","type":"uint256"},{"internalType":"address","name":"mTokenCollateral","type":"address"}],"name":"liquidate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"journalData","type":"bytes"},{"internalType":"bytes","name":"seal","type":"bytes"},{"internalType":"address[]","name":"userToLiquidate","type":"address[]"},{"internalType":"uint256[]","name":"liquidateAmount","type":"uint256[]"},{"internalType":"address[]","name":"collateral","type":"address[]"},{"internalType":"address","name":"receiver","type":"address"}],"name":"liquidateExternal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"mintAmount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"journalData","type":"bytes"},{"internalType":"bytes","name":"seal","type":"bytes"},{"internalType":"uint256[]","name":"mintAmount","type":"uint256[]"},{"internalType":"address","name":"receiver","type":"address"}],"name":"mintExternal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"operator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingAdmin","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"underlying_","type":"address"},{"internalType":"address","name":"operator_","type":"address"},{"internalType":"address","name":"interestRateModel_","type":"address"},{"internalType":"uint256","name":"initialExchangeRateMantissa_","type":"uint256"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"uint8","name":"decimals_","type":"uint8"},{"internalType":"address payable","name":"admin_","type":"address"}],"name":"proxyInitialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"redeemTokens","type":"uint256"}],"name":"redeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"redeemAmount","type":"uint256"}],"name":"redeemUnderlying","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"reduceAmount","type":"uint256"}],"name":"reduceReserves","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"repayAmount","type":"uint256"}],"name":"repay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"repayAmount","type":"uint256"}],"name":"repayBehalf","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"journalData","type":"bytes"},{"internalType":"bytes","name":"seal","type":"bytes"},{"internalType":"uint256[]","name":"repayAmount","type":"uint256[]"},{"internalType":"address","name":"receiver","type":"address"}],"name":"repayExternal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"reserveFactorMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rolesOperator","outputs":[{"internalType":"contract IRoles","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"seize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxMantissa","type":"uint256"}],"name":"setBorrowRateMaxMantissa","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_imageId","type":"bytes32"}],"name":"setImageId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newInterestRateModel","type":"address"}],"name":"setInterestRateModel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"}],"name":"setOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"newPendingAdmin","type":"address"}],"name":"setPendingAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newReserveFactorMantissa","type":"uint256"}],"name":"setReserveFactor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_roles","type":"address"}],"name":"setRolesOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"setTotalUnderlying","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_risc0Verifier","type":"address"}],"name":"setVerifier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"supplyRatePerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"sweepToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalBorrows","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalBorrowsCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalReserves","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"underlying","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"bool","name":"status","type":"bool"}],"name":"updateAllowedCallerStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_chainId","type":"uint32"},{"internalType":"bool","name":"_status","type":"bool"}],"name":"updateAllowedChain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"verifier","outputs":[{"internalType":"contract IRiscZeroVerifier","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint32","name":"dstChainId","type":"uint32"}],"name":"withdrawOnExtension","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
6080604052645d21dba000600d55348015601857600080fd5b506001601255615d538061002d6000396000f3fe608060405234801561001057600080fd5b50600436106105145760003560e01c80637f7b13d4116102a1578063b2a02ff11161016b578063dd62ed3e116100e3578063f851a44011610097578063f8f9da281161007c578063f8f9da2814610ad6578063fe62355f14610ade578063ffcaadfe14610b1a57600080fd5b8063f851a44014610ab0578063f89416ee14610ac357600080fd5b8063ee27a2f2116100c8578063ee27a2f214610a86578063ef3f7dd514610a8f578063f3fdb15a14610a9857600080fd5b8063dd62ed3e14610a3a578063e67218cd14610a7357600080fd5b8063c37f68e21161013a578063c5ebeaec1161011f578063c5ebeaec14610a01578063d87f7cad14610a14578063db006a7514610a2757600080fd5b8063c37f68e2146109c0578063c4d66de8146109ee57600080fd5b8063b2a02ff11461097f578063b3ab15fb14610992578063b57a4a72146109a5578063bd6d894d146109b857600080fd5b806399c4383711610219578063a66b92ab116101cd578063a9059cbb116101b2578063a9059cbb1461095b578063aa5af0fd1461096e578063ae9d70b01461097757600080fd5b8063a66b92ab14610940578063a6afed951461095357600080fd5b80639d9339b3116101fe5780639d9339b314610907578063a0712d681461091a578063a4777a7a1461092d57600080fd5b806399c43837146108e157806399d8c1b4146108f457600080fd5b80638f840ddd1161027057806391a0d4381161025557806391a0d438146108b357806395d89b41146108c657806395dd9193146108ce57600080fd5b80638f840ddd14610897578063901129c2146108a057600080fd5b80637f7b13d41461083b578063852a12e31461084e5780638bcd4016146108615780638da735271461087457600080fd5b80633936c445116103e25780635437988d1161035a5780636c540baf1161030e57806370a08231116102f357806370a08231146107f757806373acee98146108205780637821a5141461082857600080fd5b80636c540baf146107db5780636f307dc3146107e457600080fd5b80635bdcecb71161033f5780635bdcecb714610793578063600bb376146107a6578063699cd5e2146107d457600080fd5b80635437988d1461076d578063570ca7351461078057600080fd5b80634914c008116103b15780634f2be4ce116103965780634f2be4ce1461071c5780634fbdc6ae1461072f5780634fecab701461075a57600080fd5b80634914c008146106f65780634dd18bf51461070957600080fd5b80633936c445146106a75780633af9e669146106d25780633b1d21a2146106e557806347bd3718146106ed57600080fd5b8063182df0f51161049057806326782247116104445780632b7ac3f3116104295780632b7ac3f314610662578063313ce56714610675578063371fd8e61461069457600080fd5b80632678224714610624578063277cd86a1461064f57600080fd5b80631be19560116104755780631be19560146105eb5780631c446983146105fe57806323b872dd1461061157600080fd5b8063182df0f5146105d05780631a31d465146105d857600080fd5b8063095ea7b3116104e7578063173b9904116104cc578063173b99041461059d57806317bfdfbc146105b457806318160ddd146105c757600080fd5b8063095ea7b3146105725780630e18b6811461059557600080fd5b806306fdde031461051957806307d923e91461053757806307e279591461054a57806308fee2631461055f575b600080fd5b610521610b2d565b60405161052e919061512e565b60405180910390f35b610521610545366004615175565b610bbb565b61055d6105583660046151aa565b610c7e565b005b61055d61056d366004615251565b610ee1565b61058561058036600461530b565b611063565b604051901515815260200161052e565b61055d6110d1565b6105a660075481565b60405190815260200161052e565b6105a66105c2366004615337565b6111a0565b6105a6600c5481565b6105a66111cc565b61055d6105e6366004615428565b6111db565b61055d6105f9366004615337565b611296565b61055d61060c3660046151aa565b611395565b61058561061f3660046154e3565b61144b565b600154610637906001600160a01b031681565b6040516001600160a01b03909116815260200161052e565b61055d61065d366004615524565b611475565b601454610637906001600160a01b031681565b6006546106829060ff1681565b60405160ff909116815260200161052e565b61055d6106a23660046151aa565b61151e565b6105a66106b5366004615547565b601760209081526000928352604080842090915290825290205481565b6105a66106e0366004615337565b611529565b6105a6611568565b6105a6600a5481565b61055d61070436600461557e565b611573565b61055d610717366004615337565b611586565b61055d61072a3660046155ce565b61161a565b6105a661073d366004615547565b601660209081526000928352604080842090915290825290205481565b600354610637906001600160a01b031681565b61055d61077b366004615337565b611686565b600254610637906001600160a01b031681565b61055d6107a136600461530b565b6116ba565b6105856107b43660046155fc565b601860209081526000928352604080842090915290825290205460ff1681565b6001610585565b6105a660085481565b601354610637906001600160a01b031681565b6105a6610805366004615337565b6001600160a01b03166000908152600f602052604090205490565b6105a66116c6565b61055d6108363660046151aa565b6116e9565b61055d61084936600461561a565b6116f2565b61055d61085c3660046151aa565b611885565b61055d61086f366004615337565b611891565b610585610882366004615703565b60196020526000908152604090205460ff1681565b6105a6600b5481565b61055d6108ae3660046151aa565b6118cd565b61055d6108c13660046151aa565b611901565b610521611931565b6105a66108dc366004615337565b61193e565b61055d6108ef36600461571e565b611949565b61055d61090236600461573a565b611ad1565b61055d610915366004615251565b611bd8565b61055d6109283660046151aa565b611d4e565b61055d61093b3660046157e1565b611d5a565b61055d61094e366004615524565b611f6e565b61055d61200f565b61058561096936600461530b565b612019565b6105a660095481565b6105a661203c565b61055d61098d3660046154e3565b6120db565b61055d6109a0366004615337565b6120f9565b61055d6109b33660046158fa565b61212d565b6105a6612191565b6109d36109ce366004615337565b6121b7565b6040805193845260208401929092529082015260600161052e565b61055d6109fc366004615337565b6121f2565b61055d610a0f3660046151aa565b61238e565b61055d610a22366004615337565b61239a565b61055d610a353660046151aa565b612440565b6105a6610a483660046155fc565b6001600160a01b03918216600090815260106020908152604080832093909416825291909152205490565b61055d610a813660046151aa565b61244c565b6105a6600d5481565b6105a660155481565b6006546106379061010090046001600160a01b031681565b600054610637906001600160a01b031681565b61055d610ad1366004615337565b6124c4565b6105a661257f565b610585610aec3660046155fc565b6001600160a01b03918216600090815260186020908152604080832093909416825291909152205460ff1690565b61055d610b283660046151aa565b6125d9565b60048054610b3a906159ca565b80601f0160208091040260200160405190810160405280929190818152602001828054610b66906159ca565b8015610bb35780601f10610b8857610100808354040283529160200191610bb3565b820191906000526020600020905b815481529060010190602001808311610b9657829003601f168201915b505050505081565b63ffffffff811660008181526016602090815260408083206001600160a01b03871680855290835281842054948452601783528184209084528252918290205482517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606088811b82169483019490945230841b166034820152604881019490945260688401526001600160e01b03194660e090811b8216608886015285901b16608c840152815180840360700181526090909301909152905b90505b92915050565b610c86612722565b6000546001600160a01b0316331480610d975750600354604080517fd71c72e000000000000000000000000000000000000000000000000000000000815290516001600160a01b03909216916338dd8c2c913391849163d71c72e09160048083019260209291908290030181865afa158015610d06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d2a9190615a04565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015610d73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d979190615a1d565b610dcd576040517f90b0f0f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610dd5612765565b80610ddf60115490565b1015610e17576040517f72d33f5d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b54811115610e53576040517f72d33f5d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081600b54610e639190615a50565b600b8190559050610e74338361294a565b8160116000828254610e869190615a50565b909155505060005460408051848152602081018490526001600160a01b03909216917f3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e910160405180910390a250610ede6001601255565b50565b6003546040805163a1bd302d60e01b815290516001600160a01b03909216916338dd8c2c913391849163a1bd302d9160048083019260209291908290030181865afa158015610f34573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f589190615a04565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015610fa1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc59190615a1d565b610fd557610fd587878787612961565b6000610fe387890189615a63565b8051909150838114611008576040516302e262f160e01b815260040160405180910390fd5b60005b818110156110575761104f83828151811061102857611028615b49565b602002602001015187878481811061104257611042615b49565b90506020020135866129aa565b60010161100b565b50505050505050505050565b3360008181526010602090815260408083206001600160a01b03871680855292528083208590555191929182907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906110bf9087815260200190565b60405180910390a35060019392505050565b6001546001600160a01b031633146110fc5760405163303676d360e01b815260040160405180910390fd5b60008054600180546001600160a01b0380821673ffffffffffffffffffffffffffffffffffffffff19808616821787559092169092556040519190921692829184917ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc91a36001546040516001600160a01b03918216918316907fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a990600090a35050565b60006111aa612722565b6111b2612765565b6111bb82612b7a565b90506111c76001601255565b919050565b60006111d6612bce565b905090565b6111e9868686868686611ad1565b6013805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b038916908117909155604080517f18160ddd00000000000000000000000000000000000000000000000000000000815290516318160ddd916004808201926020929091908290030181865afa158015611268573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061128c9190615a04565b5050505050505050565b6000546001600160a01b031633146112c15760405163303676d360e01b815260040160405180910390fd5b6013546001600160a01b0390811690821603611309576040517f9e14909700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa158015611350573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113749190615a04565b600054909150611391906001600160a01b03848116911683612c37565b5050565b6000546001600160a01b031633146113c05760405163303676d360e01b815260040160405180910390fd5b6113c8612765565b670de0b6b3a764000081111561140a576040517fea1eeb4500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60075460408051918252602082018390527faaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460910160405180910390a1600755565b6000611455612722565b61146133858585612cab565b50600161146e6001601255565b9392505050565b600082116114965760405163fd7850ff60e01b815260040160405180910390fd5b63ffffffff81166000908152601760209081526040808320338452909152812080548492906114c6908490615b5f565b909155506114d8905033836000612edc565b6040805163ffffffff831681526020810184905233917fffb02ed8426abe4f31f431f9f4c6075fcf5916fb1ba83041a0979073b27a3d7191015b60405180910390a25050565b610ede816001612ef9565b600080604051806020016040528061153f612191565b90526001600160a01b0384166000908152600f602052604090205490915061146e908290612f20565b60006111d660115490565b611581338484846001612f38565b505050565b6000546001600160a01b031633146115b15760405163303676d360e01b815260040160405180910390fd5b6001546040516001600160a01b038084169216907fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a990600090a36001805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b3360008181526018602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917fb2cc4dde7f9044ba1999f7843e2f9cd1e4ce506f8cc2e16de26ce982bf113fa6910160405180910390a35050565b6000546001600160a01b031633146116b15760405163303676d360e01b815260040160405180910390fd5b610ede81612fb2565b6113918282600161305b565b60006116d0612722565b6116d8612765565b50600a546116e66001601255565b90565b610ede81613082565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff1660008115801561173d5750825b905060008267ffffffffffffffff16600114801561175a5750303b155b905081158015611768575080155b1561179f576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b845467ffffffffffffffff1916600117855583156117d357845468ff00000000000000001916680100000000000000001785555b6117e38f8f8f8f8f8f8f8f61212d565b6117ec876121f2565b600380546001600160a01b0380891673ffffffffffffffffffffffffffffffffffffffff199283161790925560008054928b1692909116919091179055831561187457845468ff000000000000000019168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050505050505050505050565b610ede33826001612edc565b6000546001600160a01b031633146118bc5760405163303676d360e01b815260040160405180910390fd5b6118c4612765565b610ede81613115565b6000546001600160a01b031633146118f85760405163303676d360e01b815260040160405180910390fd5b610ede81613256565b6000546001600160a01b0316331461192c5760405163303676d360e01b815260040160405180910390fd5b601155565b60058054610b3a906159ca565b6000610c7882612b7a565b6000546001600160a01b03163314801590611a5e5750600354604080517fe048241300000000000000000000000000000000000000000000000000000000815290516001600160a01b03909216916338dd8c2c913391849163e04824139160048083019260209291908290030181865afa1580156119cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119ef9190615a04565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015611a38573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a5c9190615a1d565b155b15611a7c5760405163271bd90b60e01b815260040160405180910390fd5b63ffffffff8216600081815260196020908152604091829020805460ff191685151590811790915591519182527f3615c8513bc6436318086c0663e19b0334871c8c175a33b9340c3ecab97137cc9101611512565b6000546001600160a01b03163314611afc5760405163303676d360e01b815260040160405180910390fd5b600854158015611b0c5750600954155b611b42576040517fc99314d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008411611b7c576040517fa08b42d000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6011849055611b8a866132c5565b42600855670de0b6b3a7640000600955611ba385613115565b6004611baf8482615bb9565b506005611bbc8382615bb9565b506006805460ff191660ff929092169190911790555050505050565b6003546040805163a1bd302d60e01b815290516001600160a01b03909216916338dd8c2c913391849163a1bd302d9160048083019260209291908290030181865afa158015611c2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c4f9190615a04565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015611c98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cbc9190615a1d565b611ccc57611ccc87878787612961565b6000611cda87890189615a63565b8051909150838114611cff576040516302e262f160e01b815260040160405180910390fd5b60005b8181101561105757611d46838281518110611d1f57611d1f615b49565b6020026020010151878784818110611d3957611d39615b49565b90506020020135866133c6565b600101611d02565b610ede33826001613588565b6003546040805163a1bd302d60e01b815290516001600160a01b03909216916338dd8c2c913391849163a1bd302d9160048083019260209291908290030181865afa158015611dad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dd19190615a04565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015611e1a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e3e9190615a1d565b611e4e57611e4e8b8b8b8b612961565b6000611e5c8b8d018d615a63565b8051909150858114611e81576040516302e262f160e01b815260040160405180910390fd5b808814611ea1576040516302e262f160e01b815260040160405180910390fd5b808414611ec1576040516302e262f160e01b815260040160405180910390fd5b60005b81811015611f5e57611f56838281518110611ee157611ee1615b49565b60200260200101518b8b84818110611efb57611efb615b49565b9050602002016020810190611f109190615337565b8a8a85818110611f2257611f22615b49565b90506020020135898986818110611f3b57611f3b615b49565b9050602002016020810190611f509190615337565b886135a3565b600101611ec4565b5050505050505050505050505050565b60008211611f8f5760405163fd7850ff60e01b815260040160405180910390fd5b63ffffffff8116600090815260176020908152604080832033845290915281208054849290611fbf908490615b5f565b90915550611fd19050338360006137e9565b6040805163ffffffff831681526020810184905233917febeabb72629991c0657c42b5db17113f1eb371cca1f8f30ee73c9f66232c2a629101611512565b612017612765565b565b6000612023612722565b61202f33338585612cab565b506001610c786001601255565b6006546000906001600160a01b036101009091041663b816881661205f60115490565b600a54600b546007546040516001600160e01b031960e087901b16815260048101949094526024840192909252604483015260648201526084015b602060405180830381865afa1580156120b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111d69190615a04565b6120e3612722565b6120ef33848484613804565b6115816001601255565b6000546001600160a01b031633146121245760405163303676d360e01b815260040160405180910390fd5b610ede816132c5565b6000805473ffffffffffffffffffffffffffffffffffffffff19163317905561215b888888888888886111db565b6000805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b039290921691909117905550505050505050565b600061219b612722565b6121a3612765565b6121ab612bce565b90506116e66001601255565b6001600160a01b0381166000908152600f6020526040812054819081906121dd85612b7a565b6121e5612bce565b9250925092509193909250565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff1660008115801561223d5750825b905060008267ffffffffffffffff16600114801561225a5750303b155b905081158015612268575080155b1561229f576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b845467ffffffffffffffff1916600117855583156122d357845468ff00000000000000001916680100000000000000001785555b6001600160a01b038616612313576040517f2756006b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6014805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b038816179055831561238657845468ff000000000000000019168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050565b610ede338260016137e9565b6000546001600160a01b031633146123c55760405163303676d360e01b815260040160405180910390fd5b6013546040517f5c19a95c0000000000000000000000000000000000000000000000000000000081526001600160a01b03838116600483015290911690635c19a95c90602401600060405180830381600087803b15801561242557600080fd5b505af1158015612439573d6000803e3d6000fd5b5050505050565b610ede33826001613a7b565b6000546001600160a01b031633146124775760405163303676d360e01b815260040160405180910390fd5b600d805490829055612487612765565b60408051828152602081018490527f3ae66e204f1f2ae1bf6ea9ddb0331246f344118a48794bc9351cc730a0486658910160405180910390a15050565b6000546001600160a01b031633146124ef5760405163303676d360e01b815260040160405180910390fd5b6001600160a01b0381166125165760405163bca3ab8960e01b815260040160405180910390fd5b6003546040516001600160a01b038084169216907f9859cd0a756b5f08366068b791448fb837581d3b8afc097914d88edbc7bff2a390600090a36003805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b6006546000906001600160a01b03610100909104166315f240536125a260115490565b600a54600b546040516001600160e01b031960e086901b16815260048101939093526024830191909152604482015260640161209a565b600354604080517f9e106dc700000000000000000000000000000000000000000000000000000000815290516001600160a01b03909216916338dd8c2c9133918491639e106dc79160048083019260209291908290030181865afa158015612645573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126699190615a04565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa1580156126b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126d69190615a1d565b61270b576040517ea1222300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601354610ede906001600160a01b03163383612c37565b60026012540361275e576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002601255565b6008544290818103612775575050565b600061278060115490565b600a54600b546009546006546040517f15f2405300000000000000000000000000000000000000000000000000000000815260048101869052602481018590526044810184905294955092939192909160009161010090046001600160a01b0316906315f2405390606401602060405180830381865afa158015612808573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061282c9190615a04565b9050600d5481111561286a576040517f8179ac1a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006128768789615a50565b9050600061289260405180602001604052808581525083613a98565b905060006128a08288612f20565b905060006128ae8883615b5f565b905060006128cd6040518060200160405280600754815250848a613ac9565b905060006128dc85898a613ac9565b60088e90556009819055600a849055600b839055604080518d815260208101879052908101829052606081018590529091507f4dec04e750ca11537cabcd8a9eab06494de08da3735bc8871cd41250e190bc049060800160405180910390a150505050505050505050505050565b601354611391906001600160a01b03168383612c37565b82612998576040517fc39550bb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6129a484848484613aea565b50505050565b60008060008060006129bb88613afe565b95509550509450945094508495506129d33386613b90565b4663ffffffff168163ffffffff16146129ff57604051632b25fce360e01b815260040160405180910390fd5b6001600160a01b0384163014612a285760405163fb7dcd6b60e01b815260040160405180910390fd5b63ffffffff821660009081526019602052604090205460ff16612a5e576040516357e05e4960e01b815260040160405180910390fd5b60008711612a7f5760405163fd7850ff60e01b815260040160405180910390fd5b63ffffffff821660009081526016602090815260408083206001600160a01b0389168452909152902054612ab39084615a50565b871115612ad3576040516361ee36eb60e01b815260040160405180910390fd5b63ffffffff821660009081526016602090815260408083206001600160a01b038916845290915281208054899290612b0c908490615b5f565b90915550612b1e90508688600061305b565b6040805163ffffffff84168152602081018990526001600160a01b03808916929088169133917fe2cce63addd46173601de3603e8e65733e0aeb61b438aba8c8b139fae31a673291015b60405180910390a45050505050505050565b6001600160a01b0381166000908152600e6020526040812080548203612ba35750600092915050565b6009548154600091612bb491615c78565b9050816001015481612bc69190615c8f565b949350505050565b600c54600090808203612be357505060115490565b6000612bee60115490565b90506000600b54600a5483612c039190615b5f565b612c0d9190615a50565b9050600083612c24670de0b6b3a764000084615c78565b612c2e9190615c8f565b95945050505050565b6040516001600160a01b0383811660248301526044820183905261158191859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050613df4565b6002546040517f17bf120e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038581166024830152848116604483015260648201849052909116906317bf120e90608401600060405180830381600087803b158015612d2057600080fd5b505af1158015612d34573d6000803e3d6000fd5b50505050816001600160a01b0316836001600160a01b031603612d83576040517f98a79b5400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000836001600160a01b0316856001600160a01b031603612da75750600019612dcf565b506001600160a01b038084166000908152601060209081526040808320938816835292905220545b6000612ddb8383615a50565b6001600160a01b0386166000908152600f602052604081205491925090612e03908590615a50565b6001600160a01b0386166000908152600f602052604081205491925090612e2b908690615b5f565b6001600160a01b038089166000908152600f602052604080822086905591891681522081905590506000198414612e85576001600160a01b038088166000908152601060209081526040808320938c168352929052208390555b856001600160a01b0316876001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef87604051612eca91815260200190565b60405180910390a35050505050505050565b612ee4612722565b612eec612765565b6120ef8360008484613e75565b612f01612722565b612f09612765565b612f15333384846140ef565b506113916001601255565b600080612f2d8484613a98565b9050612bc681614261565b612f40612722565b612f48612765565b816001600160a01b031663a6afed956040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612f8357600080fd5b505af1158015612f97573d6000803e3d6000fd5b50505050612fa88585858585614279565b6124396001601255565b6001600160a01b038116612ff2576040517f2756006b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6014546040516001600160a01b038084169216907fab81081e8fd2866d32d2dd90fdfa53fa9e0aa3d7eed73c684b6dcc4e2c0369fd90600090a36014805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b613063612722565b61306b612765565b613077338484846140ef565b506115816001601255565b61308a612722565b613092612765565b60008061309f3384614662565b905080601160008282546130b39190615b5f565b9091555050600b546130c6908290615b5f565b600b819055604080518381526020810183905291935033917fa91e67c5ea634cd43a12c5a482724b03de01e85ca68702a53d0c2f45cb7c1dc5910160405180910390a25050610ede6001601255565b6000546001600160a01b031633146131405760405163303676d360e01b815260040160405180910390fd5b806001600160a01b0316632191f92a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561317e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131a29190615a1d565b6131d8576040517f3e1fc32700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006546040516001600160a01b0380841692610100900416907fedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f92690600090a3600680546001600160a01b03909216610100027fffffffffffffffffffffff0000000000000000000000000000000000000000ff909216919091179055565b8061328d576040517ffa79c3a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040518181527fe02ca3e718b01d09207861e781e45e3c93060b331a03eed1ab268d12e793583f9060200160405180910390a1601555565b806001600160a01b0316634456eda26040518163ffffffff1660e01b8152600401602060405180830381865afa158015613303573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133279190615a1d565b61335d576040517f3e1fc32700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002546040516001600160a01b038084169216907ff1e04d73c4304b5ff164f9d10c7473e2a1593b740674a6107975e2a7001c1e5c90600090a36002805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b60008060008060006133d788613afe565b95509550509450945094508495506133ef3386613b90565b4663ffffffff168163ffffffff161461341b57604051632b25fce360e01b815260040160405180910390fd5b6001600160a01b03841630146134445760405163fb7dcd6b60e01b815260040160405180910390fd5b63ffffffff821660009081526019602052604090205460ff1661347a576040516357e05e4960e01b815260040160405180910390fd5b6000871161349b5760405163fd7850ff60e01b815260040160405180910390fd5b63ffffffff821660009081526016602090815260408083206001600160a01b03891684529091529020546134cf9084615a50565b8711156134ef576040516361ee36eb60e01b815260040160405180910390fd5b63ffffffff821660009081526016602090815260408083206001600160a01b038916845290915281208054899290613528908490615b5f565b9091555061353a905086886000613588565b6040805163ffffffff84168152602081018990526001600160a01b03808916929088169133917fadedbbedfe5f9c3d3ea9e37eda061744d9ca5a97fbe143765b6164fcee7108569101612b68565b613590612722565b613598612765565b6120ef838383614767565b60008060008060006135b48a613afe565b95509550509450945094508495506135cc3386613b90565b4663ffffffff168163ffffffff16146135f857604051632b25fce360e01b815260040160405180910390fd5b6001600160a01b03841630146136215760405163fb7dcd6b60e01b815260040160405180910390fd5b63ffffffff821660009081526019602052604090205460ff16613657576040516357e05e4960e01b815260040160405180910390fd5b600088116136785760405163fd7850ff60e01b815260040160405180910390fd5b63ffffffff821660009081526016602090815260408083206001600160a01b03891684529091529020546136ac9084615a50565b8811156136cc576040516361ee36eb60e01b815260040160405180910390fd5b6001600160a01b03891633148015906136f75750846001600160a01b0316896001600160a01b031614155b6137145760405163271bd90b60e01b815260040160405180910390fd5b6001600160a01b03871615613729578661372b565b305b63ffffffff831660009081526016602090815260408083206001600160a01b038a168452909152812080549299508a92909190613769908490615b5f565b9091555061377d9050868a8a8a6000612f38565b604080516001600160a01b038b81168252888116602083015263ffffffff851682840152606082018b905291518983169288169133917fc643e0e4d5d1082f6bfc662466c6ee07f745f7725754c136e448452d1f1878679181900360800190a450505050505050505050565b6137f1612722565b6137f9612765565b6120ef8383836149c6565b6002546040517f6765dff90000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0386811660248301528581166044830152848116606483015290911690636765dff990608401600060405180830381600087803b15801561387a57600080fd5b505af115801561388e573d6000803e3d6000fd5b50505050826001600160a01b0316826001600160a01b0316036138c45760405163bca3ab8960e01b815260040160405180910390fd5b60006138e5826040518060200160405280666379da05b60000815250614b5e565b905060006138f38284615a50565b90506000604051806020016040528061390a612bce565b90529050600061391a8285612f20565b9050600081600b5461392c9190615b5f565b600b819055600c54909150613942908690615a50565b600c556001600160a01b0387166000908152600f6020526040902054613969908790615a50565b6001600160a01b038089166000908152600f602052604080822093909355908a1681522054613999908590615b5f565b6001600160a01b03808a166000818152600f602052604090819020939093559151908916907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906139ed9088815260200190565b60405180910390a360405185815230906001600160a01b038916907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a3604080518381526020810183905230917fa91e67c5ea634cd43a12c5a482724b03de01e85ca68702a53d0c2f45cb7c1dc5910160405180910390a2505050505050505050565b613a83612722565b613a8b612765565b6120ef8383600084613e75565b6040805160208101909152600081526040518060200160405280613ac0856000015185614b81565b90529392505050565b600080613ad68585613a98565b9050612c2e613ae482614261565b84614b8d565b613af2614b99565b6129a484848484614bdb565b600080600080600080613b1e613b178860006014614c96565b6000614dbe565b9550613b2f613b1788601480614c96565b9450613b48613b418860286020614c96565b6000614e34565b9350613b5a613b418860486020614c96565b9250613b73613b6c8860686004614c96565b6000614e9a565b9150613b85613b6c88606c6004614c96565b905091939550919395565b806001600160a01b0316826001600160a01b031614611391576001600160a01b0380821660009081526018602090815260408083209386168352929052205460ff1680613bea57506000546001600160a01b038381169116145b80613ced5750600354604080517fa872019500000000000000000000000000000000000000000000000000000000815290516001600160a01b03909216916338dd8c2c918591849163a87201959160048083019260209291908290030181865afa158015613c5c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c809190615a04565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015613cc9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ced9190615a1d565b80613dd757506003546040805163a1bd302d60e01b815290516001600160a01b03909216916338dd8c2c918591849163a1bd302d9160048083019260209291908290030181865afa158015613d46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d6a9190615a04565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015613db3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613dd79190615a1d565b6113915760405163271bd90b60e01b815260040160405180910390fd5b6000613e096001600160a01b03841683614f00565b90508051600014158015613e2e575080806020019051810190613e2c9190615a1d565b155b15611581576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b03841660048201526024015b60405180910390fd5b821580613e80575081155b613e9d5760405163bca3ab8960e01b815260040160405180910390fd5b60006040518060200160405280613eb2612bce565b905290506000808515613ed357859150613ecc8387612f20565b9050613ee3565b613edd8584614f0e565b91508490505b81158015613eef575080155b15613f26576040517fbbf3e56400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002546040517f1e32bd9b0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0389811660248301526044820185905290911690631e32bd9b90606401600060405180830381600087803b158015613f9357600080fd5b505af1158015613fa7573d6000803e3d6000fd5b5050505080613fb560115490565b1015613fed576040517f14ec588c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81600c54613ffb9190615a50565b600c556001600160a01b0387166000908152600f6020526040902054614022908390615a50565b6001600160a01b0388166000908152600f6020526040902055831561404b5761404b878261294a565b806011600082825461405d9190615a50565b909155505060405182815230906001600160a01b038916907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a360408051828152602081018490526001600160a01b038916917fe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929910160405180910390a250505050505050565b6002546040517fc321fbcc0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038581166024830152600092169063c321fbcc90604401600060405180830381600087803b15801561415657600080fd5b505af115801561416a573d6000803e3d6000fd5b50505050600061417985612b7a565b90506000600019851461418c578461418e565b815b905060008461419d57816141a7565b6141a78883614662565b905080601160008282546141bb9190615b5f565b90915550600090506141cd8285615a50565b9050600082600a546141df9190615a50565b6001600160a01b038a81166000818152600e6020908152604091829020878155600954600190910155600a859055815188815290810187905290810184905292935091908c16907f1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a19060600160405180910390a3509098975050505050505050565b8051600090610c7890670de0b6b3a764000090615c8f565b846001600160a01b0316846001600160a01b0316036142ab5760405163bca3ab8960e01b815260040160405180910390fd5b6000831180156142bd57506000198314155b6142da5760405163bca3ab8960e01b815260040160405180910390fd5b6002546040517fb50ce7620000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0384811660248301528681166044830152606482018690529091169063b50ce7629060840160006040518083038186803b15801561434d57600080fd5b505afa158015614361573d6000803e3d6000fd5b5050505061436c4290565b826001600160a01b0316636c540baf6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156143aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143ce9190615a04565b14614405576040517fdf70808000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000614413868686856140ef565b6002546040517fc488847b0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038681166024830152604482018490529293506000929091169063c488847b90606401602060405180830381865afa158015614489573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144ad9190615a04565b6040516370a0823160e01b81526001600160a01b03888116600483015291925082918616906370a0823190602401602060405180830381865afa1580156144f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061451c9190615a04565b1015614554576040517f7286c37500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b306001600160a01b038516036145755761457030888884613804565b6145f9565b6040517fb2a02ff10000000000000000000000000000000000000000000000000000000081526001600160a01b03888116600483015287811660248301526044820183905285169063b2a02ff190606401600060405180830381600087803b1580156145e057600080fd5b505af11580156145f4573d6000803e3d6000fd5b505050505b836001600160a01b0316866001600160a01b0316886001600160a01b03167f298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb528585604051614651929190918252602082015260400190565b60405180910390a450505050505050565b6013546040516370a0823160e01b815230600482015260009182916001600160a01b03909116906370a0823190602401602060405180830381865afa1580156146af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146d39190615a04565b6013549091506146ee906001600160a01b0316853086614f2c565b6013546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015614737573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061475b9190615a04565b9050612c2e8282615a50565b6002546040517fc0f1ee090000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0385811660248301529091169063c0f1ee0990604401600060405180830381600087803b1580156147cd57600080fd5b505af11580156147e1573d6000803e3d6000fd5b50505050600060405180602001604052806147fa612bce565b9052905060008261480b5783614815565b6148158585614662565b905080601160008282546148299190615b5f565b909155506000905061483b8284614f0e565b9050600c54600003614889576103e8600c81905560008052600f6020527ff4803e074bd026baaf6ed2e288c9515f68c72fb7216eebdd7cae1718a53ec3758190556148869082615a50565b90505b80600c546148979190615b5f565b600c556001600160a01b0386166000908152600f60205260409020546148be908290615b5f565b6001600160a01b0387166000818152600f602090815260409182902093909355805185815292830184905290917f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f910160405180910390a26040518181526001600160a01b0387169030907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a36002546040517f0d926fc80000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0390911690630d926fc89060240160006040518083038186803b1580156149b257600080fd5b505afa158015611057573d6000803e3d6000fd5b6002546040517f50795f8a0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b03858116602483015260448201859052909116906350795f8a90606401600060405180830381600087803b158015614a3357600080fd5b505af1158015614a47573d6000803e3d6000fd5b5050505081614a5560115490565b1015614a8d576040517fcd85b93e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000614a9884612b7a565b90506000614aa68483615b5f565b9050600084600a54614ab89190615b5f565b6001600160a01b0387166000908152600e60205260409020838155600954600190910155600a81905590508315614af357614af3868661294a565b8460116000828254614b059190615a50565b909155505060408051868152602081018490529081018290526001600160a01b038716907f13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab809060600160405180910390a2505050505050565b6000670de0b6b3a7640000614b77848460000151614b81565b610c759190615c8f565b6000610c758284615c78565b6000610c758284615b5f565b6014546001600160a01b0316612017576040517ff242df5300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6014546015546040516001600160a01b039092169163ab750e75918591859190600290614c0b908b908b90615cb1565b602060405180830381855afa158015614c28573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190614c4b9190615a04565b6040518563ffffffff1660e01b8152600401614c6a9493929190615cc1565b60006040518083038186803b158015614c8257600080fd5b505afa15801561128c573d6000803e3d6000fd5b606081614ca481601f615b5f565b1015614cf25760405162461bcd60e51b815260206004820152600e60248201527f736c6963655f6f766572666c6f770000000000000000000000000000000000006044820152606401613e6c565b614cfc8284615b5f565b84511015614d4c5760405162461bcd60e51b815260206004820152601160248201527f736c6963655f6f75744f66426f756e64730000000000000000000000000000006044820152606401613e6c565b606082158015614d6b5760405191506000825260208201604052614db5565b6040519150601f8416801560200281840101858101878315602002848b0101015b81831015614da4578051835260209283019201614d8c565b5050858452601f01601f1916604052505b50949350505050565b6000614dcb826014615b5f565b83511015614e1b5760405162461bcd60e51b815260206004820152601560248201527f746f416464726573735f6f75744f66426f756e647300000000000000000000006044820152606401613e6c565b5001602001516c01000000000000000000000000900490565b6000614e41826020615b5f565b83511015614e915760405162461bcd60e51b815260206004820152601560248201527f746f55696e743235365f6f75744f66426f756e647300000000000000000000006044820152606401613e6c565b50016020015190565b6000614ea7826004615b5f565b83511015614ef75760405162461bcd60e51b815260206004820152601460248201527f746f55696e7433325f6f75744f66426f756e64730000000000000000000000006044820152606401613e6c565b50016004015190565b6060610c7583836000614f65565b6000610c75614f2584670de0b6b3a7640000614b81565b835161501b565b6040516001600160a01b0384811660248301528381166044830152606482018390526129a49186918216906323b872dd90608401612c64565b606081471015614fa3576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401613e6c565b600080856001600160a01b03168486604051614fbf9190615d01565b60006040518083038185875af1925050503d8060008114614ffc576040519150601f19603f3d011682016040523d82523d6000602084013e615001565b606091505b5091509150615011868383615027565b9695505050505050565b6000610c758284615c8f565b60608261503c576150378261509c565b61146e565b815115801561505357506001600160a01b0384163b155b15615095576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401613e6c565b508061146e565b8051156150ac5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b838110156150f95781810151838201526020016150e1565b50506000910152565b6000815180845261511a8160208601602086016150de565b601f01601f19169290920160200192915050565b602081526000610c756020830184615102565b6001600160a01b0381168114610ede57600080fd5b80356111c781615141565b803563ffffffff811681146111c757600080fd5b6000806040838503121561518857600080fd5b823561519381615141565b91506151a160208401615161565b90509250929050565b6000602082840312156151bc57600080fd5b5035919050565b60008083601f8401126151d557600080fd5b50813567ffffffffffffffff8111156151ed57600080fd5b60208301915083602082850101111561520557600080fd5b9250929050565b60008083601f84011261521e57600080fd5b50813567ffffffffffffffff81111561523657600080fd5b6020830191508360208260051b850101111561520557600080fd5b60008060008060008060006080888a03121561526c57600080fd5b873567ffffffffffffffff81111561528357600080fd5b61528f8a828b016151c3565b909850965050602088013567ffffffffffffffff8111156152af57600080fd5b6152bb8a828b016151c3565b909650945050604088013567ffffffffffffffff8111156152db57600080fd5b6152e78a828b0161520c565b90945092505060608801356152fb81615141565b8091505092959891949750929550565b6000806040838503121561531e57600080fd5b823561532981615141565b946020939093013593505050565b60006020828403121561534957600080fd5b813561146e81615141565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561539357615393615354565b604052919050565b60008067ffffffffffffffff8411156153b6576153b6615354565b50601f8301601f19166020016153cb8161536a565b9150508281528383830111156153e057600080fd5b828260208301376000602084830101529392505050565b600082601f83011261540857600080fd5b610c758383356020850161539b565b803560ff811681146111c757600080fd5b600080600080600080600060e0888a03121561544357600080fd5b873561544e81615141565b9650602088013561545e81615141565b9550604088013561546e81615141565b945060608801359350608088013567ffffffffffffffff81111561549157600080fd5b61549d8a828b016153f7565b93505060a088013567ffffffffffffffff8111156154ba57600080fd5b6154c68a828b016153f7565b9250506154d560c08901615417565b905092959891949750929550565b6000806000606084860312156154f857600080fd5b833561550381615141565b9250602084013561551381615141565b929592945050506040919091013590565b6000806040838503121561553757600080fd5b823591506151a160208401615161565b6000806040838503121561555a57600080fd5b61556383615161565b9150602083013561557381615141565b809150509250929050565b60008060006060848603121561559357600080fd5b833561559e81615141565b92506020840135915060408401356155b581615141565b809150509250925092565b8015158114610ede57600080fd5b600080604083850312156155e157600080fd5b82356155ec81615141565b91506020830135615573816155c0565b6000806040838503121561560f57600080fd5b823561556381615141565b6000806000806000806000806000806101408b8d03121561563a57600080fd5b6156438b615156565b995061565160208c01615156565b985061565f60408c01615156565b975060608b0135965060808b013567ffffffffffffffff81111561568257600080fd5b61568e8d828e016153f7565b96505060a08b013567ffffffffffffffff8111156156ab57600080fd5b6156b78d828e016153f7565b9550506156c660c08c01615417565b93506156d460e08c01615156565b92506156e36101008c01615156565b91506156f26101208c01615156565b90509295989b9194979a5092959850565b60006020828403121561571557600080fd5b610c7582615161565b6000806040838503121561573157600080fd5b6155ec83615161565b60008060008060008060c0878903121561575357600080fd5b863561575e81615141565b9550602087013561576e81615141565b945060408701359350606087013567ffffffffffffffff81111561579157600080fd5b61579d89828a016153f7565b935050608087013567ffffffffffffffff8111156157ba57600080fd5b6157c689828a016153f7565b9250506157d560a08801615417565b90509295509295509295565b600080600080600080600080600080600060c08c8e03121561580257600080fd5b8b3567ffffffffffffffff81111561581957600080fd5b6158258e828f016151c3565b909c509a505060208c013567ffffffffffffffff81111561584557600080fd5b6158518e828f016151c3565b909a5098505060408c013567ffffffffffffffff81111561587157600080fd5b61587d8e828f0161520c565b90985096505060608c013567ffffffffffffffff81111561589d57600080fd5b6158a98e828f0161520c565b90965094505060808c013567ffffffffffffffff8111156158c957600080fd5b6158d58e828f0161520c565b90945092506158e8905060a08d01615156565b90509295989b509295989b9093969950565b600080600080600080600080610100898b03121561591757600080fd5b883561592281615141565b9750602089013561593281615141565b9650604089013561594281615141565b955060608901359450608089013567ffffffffffffffff81111561596557600080fd5b6159718b828c016153f7565b94505060a089013567ffffffffffffffff81111561598e57600080fd5b61599a8b828c016153f7565b9350506159a960c08a01615417565b915060e08901356159b981615141565b809150509295985092959890939650565b600181811c908216806159de57607f821691505b6020821081036159fe57634e487b7160e01b600052602260045260246000fd5b50919050565b600060208284031215615a1657600080fd5b5051919050565b600060208284031215615a2f57600080fd5b815161146e816155c0565b634e487b7160e01b600052601160045260246000fd5b81810381811115610c7857610c78615a3a565b600060208284031215615a7557600080fd5b813567ffffffffffffffff811115615a8c57600080fd5b8201601f81018413615a9d57600080fd5b803567ffffffffffffffff811115615ab757615ab7615354565b8060051b615ac76020820161536a565b91825260208184018101929081019087841115615ae357600080fd5b6020850192505b83831015615b3e57823567ffffffffffffffff811115615b0957600080fd5b8501603f81018913615b1a57600080fd5b615b2c8960208301356040840161539b565b83525060209283019290910190615aea565b979650505050505050565b634e487b7160e01b600052603260045260246000fd5b80820180821115610c7857610c78615a3a565b601f82111561158157806000526020600020601f840160051c81016020851015615b995750805b601f840160051c820191505b818110156124395760008155600101615ba5565b815167ffffffffffffffff811115615bd357615bd3615354565b615be781615be184546159ca565b84615b72565b6020601f821160018114615c1b5760008315615c035750848201515b600019600385901b1c1916600184901b178455612439565b600084815260208120601f198516915b82811015615c4b5787850151825560209485019460019092019101615c2b565b5084821015615c695786840151600019600387901b60f8161c191681555b50505050600190811b01905550565b8082028115828204841417610c7857610c78615a3a565b600082615cac57634e487b7160e01b600052601260045260246000fd5b500490565b8183823760009101908152919050565b606081528360608201528385608083013760006080858301015260006080601f19601f870116830101905083602083015282604083015295945050505050565b60008251615d138184602087016150de565b919091019291505056fea2646970667358221220724ffecd1dda03b6a8f003dfa58cd82a8ac6d25418fd46d9382ac52b8b1e24df64736f6c634300081c0033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106105145760003560e01c80637f7b13d4116102a1578063b2a02ff11161016b578063dd62ed3e116100e3578063f851a44011610097578063f8f9da281161007c578063f8f9da2814610ad6578063fe62355f14610ade578063ffcaadfe14610b1a57600080fd5b8063f851a44014610ab0578063f89416ee14610ac357600080fd5b8063ee27a2f2116100c8578063ee27a2f214610a86578063ef3f7dd514610a8f578063f3fdb15a14610a9857600080fd5b8063dd62ed3e14610a3a578063e67218cd14610a7357600080fd5b8063c37f68e21161013a578063c5ebeaec1161011f578063c5ebeaec14610a01578063d87f7cad14610a14578063db006a7514610a2757600080fd5b8063c37f68e2146109c0578063c4d66de8146109ee57600080fd5b8063b2a02ff11461097f578063b3ab15fb14610992578063b57a4a72146109a5578063bd6d894d146109b857600080fd5b806399c4383711610219578063a66b92ab116101cd578063a9059cbb116101b2578063a9059cbb1461095b578063aa5af0fd1461096e578063ae9d70b01461097757600080fd5b8063a66b92ab14610940578063a6afed951461095357600080fd5b80639d9339b3116101fe5780639d9339b314610907578063a0712d681461091a578063a4777a7a1461092d57600080fd5b806399c43837146108e157806399d8c1b4146108f457600080fd5b80638f840ddd1161027057806391a0d4381161025557806391a0d438146108b357806395d89b41146108c657806395dd9193146108ce57600080fd5b80638f840ddd14610897578063901129c2146108a057600080fd5b80637f7b13d41461083b578063852a12e31461084e5780638bcd4016146108615780638da735271461087457600080fd5b80633936c445116103e25780635437988d1161035a5780636c540baf1161030e57806370a08231116102f357806370a08231146107f757806373acee98146108205780637821a5141461082857600080fd5b80636c540baf146107db5780636f307dc3146107e457600080fd5b80635bdcecb71161033f5780635bdcecb714610793578063600bb376146107a6578063699cd5e2146107d457600080fd5b80635437988d1461076d578063570ca7351461078057600080fd5b80634914c008116103b15780634f2be4ce116103965780634f2be4ce1461071c5780634fbdc6ae1461072f5780634fecab701461075a57600080fd5b80634914c008146106f65780634dd18bf51461070957600080fd5b80633936c445146106a75780633af9e669146106d25780633b1d21a2146106e557806347bd3718146106ed57600080fd5b8063182df0f51161049057806326782247116104445780632b7ac3f3116104295780632b7ac3f314610662578063313ce56714610675578063371fd8e61461069457600080fd5b80632678224714610624578063277cd86a1461064f57600080fd5b80631be19560116104755780631be19560146105eb5780631c446983146105fe57806323b872dd1461061157600080fd5b8063182df0f5146105d05780631a31d465146105d857600080fd5b8063095ea7b3116104e7578063173b9904116104cc578063173b99041461059d57806317bfdfbc146105b457806318160ddd146105c757600080fd5b8063095ea7b3146105725780630e18b6811461059557600080fd5b806306fdde031461051957806307d923e91461053757806307e279591461054a57806308fee2631461055f575b600080fd5b610521610b2d565b60405161052e919061512e565b60405180910390f35b610521610545366004615175565b610bbb565b61055d6105583660046151aa565b610c7e565b005b61055d61056d366004615251565b610ee1565b61058561058036600461530b565b611063565b604051901515815260200161052e565b61055d6110d1565b6105a660075481565b60405190815260200161052e565b6105a66105c2366004615337565b6111a0565b6105a6600c5481565b6105a66111cc565b61055d6105e6366004615428565b6111db565b61055d6105f9366004615337565b611296565b61055d61060c3660046151aa565b611395565b61058561061f3660046154e3565b61144b565b600154610637906001600160a01b031681565b6040516001600160a01b03909116815260200161052e565b61055d61065d366004615524565b611475565b601454610637906001600160a01b031681565b6006546106829060ff1681565b60405160ff909116815260200161052e565b61055d6106a23660046151aa565b61151e565b6105a66106b5366004615547565b601760209081526000928352604080842090915290825290205481565b6105a66106e0366004615337565b611529565b6105a6611568565b6105a6600a5481565b61055d61070436600461557e565b611573565b61055d610717366004615337565b611586565b61055d61072a3660046155ce565b61161a565b6105a661073d366004615547565b601660209081526000928352604080842090915290825290205481565b600354610637906001600160a01b031681565b61055d61077b366004615337565b611686565b600254610637906001600160a01b031681565b61055d6107a136600461530b565b6116ba565b6105856107b43660046155fc565b601860209081526000928352604080842090915290825290205460ff1681565b6001610585565b6105a660085481565b601354610637906001600160a01b031681565b6105a6610805366004615337565b6001600160a01b03166000908152600f602052604090205490565b6105a66116c6565b61055d6108363660046151aa565b6116e9565b61055d61084936600461561a565b6116f2565b61055d61085c3660046151aa565b611885565b61055d61086f366004615337565b611891565b610585610882366004615703565b60196020526000908152604090205460ff1681565b6105a6600b5481565b61055d6108ae3660046151aa565b6118cd565b61055d6108c13660046151aa565b611901565b610521611931565b6105a66108dc366004615337565b61193e565b61055d6108ef36600461571e565b611949565b61055d61090236600461573a565b611ad1565b61055d610915366004615251565b611bd8565b61055d6109283660046151aa565b611d4e565b61055d61093b3660046157e1565b611d5a565b61055d61094e366004615524565b611f6e565b61055d61200f565b61058561096936600461530b565b612019565b6105a660095481565b6105a661203c565b61055d61098d3660046154e3565b6120db565b61055d6109a0366004615337565b6120f9565b61055d6109b33660046158fa565b61212d565b6105a6612191565b6109d36109ce366004615337565b6121b7565b6040805193845260208401929092529082015260600161052e565b61055d6109fc366004615337565b6121f2565b61055d610a0f3660046151aa565b61238e565b61055d610a22366004615337565b61239a565b61055d610a353660046151aa565b612440565b6105a6610a483660046155fc565b6001600160a01b03918216600090815260106020908152604080832093909416825291909152205490565b61055d610a813660046151aa565b61244c565b6105a6600d5481565b6105a660155481565b6006546106379061010090046001600160a01b031681565b600054610637906001600160a01b031681565b61055d610ad1366004615337565b6124c4565b6105a661257f565b610585610aec3660046155fc565b6001600160a01b03918216600090815260186020908152604080832093909416825291909152205460ff1690565b61055d610b283660046151aa565b6125d9565b60048054610b3a906159ca565b80601f0160208091040260200160405190810160405280929190818152602001828054610b66906159ca565b8015610bb35780601f10610b8857610100808354040283529160200191610bb3565b820191906000526020600020905b815481529060010190602001808311610b9657829003601f168201915b505050505081565b63ffffffff811660008181526016602090815260408083206001600160a01b03871680855290835281842054948452601783528184209084528252918290205482517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606088811b82169483019490945230841b166034820152604881019490945260688401526001600160e01b03194660e090811b8216608886015285901b16608c840152815180840360700181526090909301909152905b90505b92915050565b610c86612722565b6000546001600160a01b0316331480610d975750600354604080517fd71c72e000000000000000000000000000000000000000000000000000000000815290516001600160a01b03909216916338dd8c2c913391849163d71c72e09160048083019260209291908290030181865afa158015610d06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d2a9190615a04565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015610d73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d979190615a1d565b610dcd576040517f90b0f0f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610dd5612765565b80610ddf60115490565b1015610e17576040517f72d33f5d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b54811115610e53576040517f72d33f5d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081600b54610e639190615a50565b600b8190559050610e74338361294a565b8160116000828254610e869190615a50565b909155505060005460408051848152602081018490526001600160a01b03909216917f3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e910160405180910390a250610ede6001601255565b50565b6003546040805163a1bd302d60e01b815290516001600160a01b03909216916338dd8c2c913391849163a1bd302d9160048083019260209291908290030181865afa158015610f34573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f589190615a04565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015610fa1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc59190615a1d565b610fd557610fd587878787612961565b6000610fe387890189615a63565b8051909150838114611008576040516302e262f160e01b815260040160405180910390fd5b60005b818110156110575761104f83828151811061102857611028615b49565b602002602001015187878481811061104257611042615b49565b90506020020135866129aa565b60010161100b565b50505050505050505050565b3360008181526010602090815260408083206001600160a01b03871680855292528083208590555191929182907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906110bf9087815260200190565b60405180910390a35060019392505050565b6001546001600160a01b031633146110fc5760405163303676d360e01b815260040160405180910390fd5b60008054600180546001600160a01b0380821673ffffffffffffffffffffffffffffffffffffffff19808616821787559092169092556040519190921692829184917ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc91a36001546040516001600160a01b03918216918316907fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a990600090a35050565b60006111aa612722565b6111b2612765565b6111bb82612b7a565b90506111c76001601255565b919050565b60006111d6612bce565b905090565b6111e9868686868686611ad1565b6013805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b038916908117909155604080517f18160ddd00000000000000000000000000000000000000000000000000000000815290516318160ddd916004808201926020929091908290030181865afa158015611268573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061128c9190615a04565b5050505050505050565b6000546001600160a01b031633146112c15760405163303676d360e01b815260040160405180910390fd5b6013546001600160a01b0390811690821603611309576040517f9e14909700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa158015611350573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113749190615a04565b600054909150611391906001600160a01b03848116911683612c37565b5050565b6000546001600160a01b031633146113c05760405163303676d360e01b815260040160405180910390fd5b6113c8612765565b670de0b6b3a764000081111561140a576040517fea1eeb4500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60075460408051918252602082018390527faaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460910160405180910390a1600755565b6000611455612722565b61146133858585612cab565b50600161146e6001601255565b9392505050565b600082116114965760405163fd7850ff60e01b815260040160405180910390fd5b63ffffffff81166000908152601760209081526040808320338452909152812080548492906114c6908490615b5f565b909155506114d8905033836000612edc565b6040805163ffffffff831681526020810184905233917fffb02ed8426abe4f31f431f9f4c6075fcf5916fb1ba83041a0979073b27a3d7191015b60405180910390a25050565b610ede816001612ef9565b600080604051806020016040528061153f612191565b90526001600160a01b0384166000908152600f602052604090205490915061146e908290612f20565b60006111d660115490565b611581338484846001612f38565b505050565b6000546001600160a01b031633146115b15760405163303676d360e01b815260040160405180910390fd5b6001546040516001600160a01b038084169216907fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a990600090a36001805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b3360008181526018602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917fb2cc4dde7f9044ba1999f7843e2f9cd1e4ce506f8cc2e16de26ce982bf113fa6910160405180910390a35050565b6000546001600160a01b031633146116b15760405163303676d360e01b815260040160405180910390fd5b610ede81612fb2565b6113918282600161305b565b60006116d0612722565b6116d8612765565b50600a546116e66001601255565b90565b610ede81613082565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff1660008115801561173d5750825b905060008267ffffffffffffffff16600114801561175a5750303b155b905081158015611768575080155b1561179f576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b845467ffffffffffffffff1916600117855583156117d357845468ff00000000000000001916680100000000000000001785555b6117e38f8f8f8f8f8f8f8f61212d565b6117ec876121f2565b600380546001600160a01b0380891673ffffffffffffffffffffffffffffffffffffffff199283161790925560008054928b1692909116919091179055831561187457845468ff000000000000000019168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050505050505050505050565b610ede33826001612edc565b6000546001600160a01b031633146118bc5760405163303676d360e01b815260040160405180910390fd5b6118c4612765565b610ede81613115565b6000546001600160a01b031633146118f85760405163303676d360e01b815260040160405180910390fd5b610ede81613256565b6000546001600160a01b0316331461192c5760405163303676d360e01b815260040160405180910390fd5b601155565b60058054610b3a906159ca565b6000610c7882612b7a565b6000546001600160a01b03163314801590611a5e5750600354604080517fe048241300000000000000000000000000000000000000000000000000000000815290516001600160a01b03909216916338dd8c2c913391849163e04824139160048083019260209291908290030181865afa1580156119cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119ef9190615a04565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015611a38573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a5c9190615a1d565b155b15611a7c5760405163271bd90b60e01b815260040160405180910390fd5b63ffffffff8216600081815260196020908152604091829020805460ff191685151590811790915591519182527f3615c8513bc6436318086c0663e19b0334871c8c175a33b9340c3ecab97137cc9101611512565b6000546001600160a01b03163314611afc5760405163303676d360e01b815260040160405180910390fd5b600854158015611b0c5750600954155b611b42576040517fc99314d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008411611b7c576040517fa08b42d000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6011849055611b8a866132c5565b42600855670de0b6b3a7640000600955611ba385613115565b6004611baf8482615bb9565b506005611bbc8382615bb9565b506006805460ff191660ff929092169190911790555050505050565b6003546040805163a1bd302d60e01b815290516001600160a01b03909216916338dd8c2c913391849163a1bd302d9160048083019260209291908290030181865afa158015611c2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c4f9190615a04565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015611c98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cbc9190615a1d565b611ccc57611ccc87878787612961565b6000611cda87890189615a63565b8051909150838114611cff576040516302e262f160e01b815260040160405180910390fd5b60005b8181101561105757611d46838281518110611d1f57611d1f615b49565b6020026020010151878784818110611d3957611d39615b49565b90506020020135866133c6565b600101611d02565b610ede33826001613588565b6003546040805163a1bd302d60e01b815290516001600160a01b03909216916338dd8c2c913391849163a1bd302d9160048083019260209291908290030181865afa158015611dad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dd19190615a04565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015611e1a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e3e9190615a1d565b611e4e57611e4e8b8b8b8b612961565b6000611e5c8b8d018d615a63565b8051909150858114611e81576040516302e262f160e01b815260040160405180910390fd5b808814611ea1576040516302e262f160e01b815260040160405180910390fd5b808414611ec1576040516302e262f160e01b815260040160405180910390fd5b60005b81811015611f5e57611f56838281518110611ee157611ee1615b49565b60200260200101518b8b84818110611efb57611efb615b49565b9050602002016020810190611f109190615337565b8a8a85818110611f2257611f22615b49565b90506020020135898986818110611f3b57611f3b615b49565b9050602002016020810190611f509190615337565b886135a3565b600101611ec4565b5050505050505050505050505050565b60008211611f8f5760405163fd7850ff60e01b815260040160405180910390fd5b63ffffffff8116600090815260176020908152604080832033845290915281208054849290611fbf908490615b5f565b90915550611fd19050338360006137e9565b6040805163ffffffff831681526020810184905233917febeabb72629991c0657c42b5db17113f1eb371cca1f8f30ee73c9f66232c2a629101611512565b612017612765565b565b6000612023612722565b61202f33338585612cab565b506001610c786001601255565b6006546000906001600160a01b036101009091041663b816881661205f60115490565b600a54600b546007546040516001600160e01b031960e087901b16815260048101949094526024840192909252604483015260648201526084015b602060405180830381865afa1580156120b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111d69190615a04565b6120e3612722565b6120ef33848484613804565b6115816001601255565b6000546001600160a01b031633146121245760405163303676d360e01b815260040160405180910390fd5b610ede816132c5565b6000805473ffffffffffffffffffffffffffffffffffffffff19163317905561215b888888888888886111db565b6000805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b039290921691909117905550505050505050565b600061219b612722565b6121a3612765565b6121ab612bce565b90506116e66001601255565b6001600160a01b0381166000908152600f6020526040812054819081906121dd85612b7a565b6121e5612bce565b9250925092509193909250565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff1660008115801561223d5750825b905060008267ffffffffffffffff16600114801561225a5750303b155b905081158015612268575080155b1561229f576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b845467ffffffffffffffff1916600117855583156122d357845468ff00000000000000001916680100000000000000001785555b6001600160a01b038616612313576040517f2756006b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6014805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b038816179055831561238657845468ff000000000000000019168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050565b610ede338260016137e9565b6000546001600160a01b031633146123c55760405163303676d360e01b815260040160405180910390fd5b6013546040517f5c19a95c0000000000000000000000000000000000000000000000000000000081526001600160a01b03838116600483015290911690635c19a95c90602401600060405180830381600087803b15801561242557600080fd5b505af1158015612439573d6000803e3d6000fd5b5050505050565b610ede33826001613a7b565b6000546001600160a01b031633146124775760405163303676d360e01b815260040160405180910390fd5b600d805490829055612487612765565b60408051828152602081018490527f3ae66e204f1f2ae1bf6ea9ddb0331246f344118a48794bc9351cc730a0486658910160405180910390a15050565b6000546001600160a01b031633146124ef5760405163303676d360e01b815260040160405180910390fd5b6001600160a01b0381166125165760405163bca3ab8960e01b815260040160405180910390fd5b6003546040516001600160a01b038084169216907f9859cd0a756b5f08366068b791448fb837581d3b8afc097914d88edbc7bff2a390600090a36003805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b6006546000906001600160a01b03610100909104166315f240536125a260115490565b600a54600b546040516001600160e01b031960e086901b16815260048101939093526024830191909152604482015260640161209a565b600354604080517f9e106dc700000000000000000000000000000000000000000000000000000000815290516001600160a01b03909216916338dd8c2c9133918491639e106dc79160048083019260209291908290030181865afa158015612645573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126699190615a04565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa1580156126b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126d69190615a1d565b61270b576040517ea1222300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601354610ede906001600160a01b03163383612c37565b60026012540361275e576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002601255565b6008544290818103612775575050565b600061278060115490565b600a54600b546009546006546040517f15f2405300000000000000000000000000000000000000000000000000000000815260048101869052602481018590526044810184905294955092939192909160009161010090046001600160a01b0316906315f2405390606401602060405180830381865afa158015612808573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061282c9190615a04565b9050600d5481111561286a576040517f8179ac1a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006128768789615a50565b9050600061289260405180602001604052808581525083613a98565b905060006128a08288612f20565b905060006128ae8883615b5f565b905060006128cd6040518060200160405280600754815250848a613ac9565b905060006128dc85898a613ac9565b60088e90556009819055600a849055600b839055604080518d815260208101879052908101829052606081018590529091507f4dec04e750ca11537cabcd8a9eab06494de08da3735bc8871cd41250e190bc049060800160405180910390a150505050505050505050505050565b601354611391906001600160a01b03168383612c37565b82612998576040517fc39550bb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6129a484848484613aea565b50505050565b60008060008060006129bb88613afe565b95509550509450945094508495506129d33386613b90565b4663ffffffff168163ffffffff16146129ff57604051632b25fce360e01b815260040160405180910390fd5b6001600160a01b0384163014612a285760405163fb7dcd6b60e01b815260040160405180910390fd5b63ffffffff821660009081526019602052604090205460ff16612a5e576040516357e05e4960e01b815260040160405180910390fd5b60008711612a7f5760405163fd7850ff60e01b815260040160405180910390fd5b63ffffffff821660009081526016602090815260408083206001600160a01b0389168452909152902054612ab39084615a50565b871115612ad3576040516361ee36eb60e01b815260040160405180910390fd5b63ffffffff821660009081526016602090815260408083206001600160a01b038916845290915281208054899290612b0c908490615b5f565b90915550612b1e90508688600061305b565b6040805163ffffffff84168152602081018990526001600160a01b03808916929088169133917fe2cce63addd46173601de3603e8e65733e0aeb61b438aba8c8b139fae31a673291015b60405180910390a45050505050505050565b6001600160a01b0381166000908152600e6020526040812080548203612ba35750600092915050565b6009548154600091612bb491615c78565b9050816001015481612bc69190615c8f565b949350505050565b600c54600090808203612be357505060115490565b6000612bee60115490565b90506000600b54600a5483612c039190615b5f565b612c0d9190615a50565b9050600083612c24670de0b6b3a764000084615c78565b612c2e9190615c8f565b95945050505050565b6040516001600160a01b0383811660248301526044820183905261158191859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050613df4565b6002546040517f17bf120e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038581166024830152848116604483015260648201849052909116906317bf120e90608401600060405180830381600087803b158015612d2057600080fd5b505af1158015612d34573d6000803e3d6000fd5b50505050816001600160a01b0316836001600160a01b031603612d83576040517f98a79b5400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000836001600160a01b0316856001600160a01b031603612da75750600019612dcf565b506001600160a01b038084166000908152601060209081526040808320938816835292905220545b6000612ddb8383615a50565b6001600160a01b0386166000908152600f602052604081205491925090612e03908590615a50565b6001600160a01b0386166000908152600f602052604081205491925090612e2b908690615b5f565b6001600160a01b038089166000908152600f602052604080822086905591891681522081905590506000198414612e85576001600160a01b038088166000908152601060209081526040808320938c168352929052208390555b856001600160a01b0316876001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef87604051612eca91815260200190565b60405180910390a35050505050505050565b612ee4612722565b612eec612765565b6120ef8360008484613e75565b612f01612722565b612f09612765565b612f15333384846140ef565b506113916001601255565b600080612f2d8484613a98565b9050612bc681614261565b612f40612722565b612f48612765565b816001600160a01b031663a6afed956040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612f8357600080fd5b505af1158015612f97573d6000803e3d6000fd5b50505050612fa88585858585614279565b6124396001601255565b6001600160a01b038116612ff2576040517f2756006b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6014546040516001600160a01b038084169216907fab81081e8fd2866d32d2dd90fdfa53fa9e0aa3d7eed73c684b6dcc4e2c0369fd90600090a36014805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b613063612722565b61306b612765565b613077338484846140ef565b506115816001601255565b61308a612722565b613092612765565b60008061309f3384614662565b905080601160008282546130b39190615b5f565b9091555050600b546130c6908290615b5f565b600b819055604080518381526020810183905291935033917fa91e67c5ea634cd43a12c5a482724b03de01e85ca68702a53d0c2f45cb7c1dc5910160405180910390a25050610ede6001601255565b6000546001600160a01b031633146131405760405163303676d360e01b815260040160405180910390fd5b806001600160a01b0316632191f92a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561317e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131a29190615a1d565b6131d8576040517f3e1fc32700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006546040516001600160a01b0380841692610100900416907fedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f92690600090a3600680546001600160a01b03909216610100027fffffffffffffffffffffff0000000000000000000000000000000000000000ff909216919091179055565b8061328d576040517ffa79c3a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040518181527fe02ca3e718b01d09207861e781e45e3c93060b331a03eed1ab268d12e793583f9060200160405180910390a1601555565b806001600160a01b0316634456eda26040518163ffffffff1660e01b8152600401602060405180830381865afa158015613303573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133279190615a1d565b61335d576040517f3e1fc32700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002546040516001600160a01b038084169216907ff1e04d73c4304b5ff164f9d10c7473e2a1593b740674a6107975e2a7001c1e5c90600090a36002805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b60008060008060006133d788613afe565b95509550509450945094508495506133ef3386613b90565b4663ffffffff168163ffffffff161461341b57604051632b25fce360e01b815260040160405180910390fd5b6001600160a01b03841630146134445760405163fb7dcd6b60e01b815260040160405180910390fd5b63ffffffff821660009081526019602052604090205460ff1661347a576040516357e05e4960e01b815260040160405180910390fd5b6000871161349b5760405163fd7850ff60e01b815260040160405180910390fd5b63ffffffff821660009081526016602090815260408083206001600160a01b03891684529091529020546134cf9084615a50565b8711156134ef576040516361ee36eb60e01b815260040160405180910390fd5b63ffffffff821660009081526016602090815260408083206001600160a01b038916845290915281208054899290613528908490615b5f565b9091555061353a905086886000613588565b6040805163ffffffff84168152602081018990526001600160a01b03808916929088169133917fadedbbedfe5f9c3d3ea9e37eda061744d9ca5a97fbe143765b6164fcee7108569101612b68565b613590612722565b613598612765565b6120ef838383614767565b60008060008060006135b48a613afe565b95509550509450945094508495506135cc3386613b90565b4663ffffffff168163ffffffff16146135f857604051632b25fce360e01b815260040160405180910390fd5b6001600160a01b03841630146136215760405163fb7dcd6b60e01b815260040160405180910390fd5b63ffffffff821660009081526019602052604090205460ff16613657576040516357e05e4960e01b815260040160405180910390fd5b600088116136785760405163fd7850ff60e01b815260040160405180910390fd5b63ffffffff821660009081526016602090815260408083206001600160a01b03891684529091529020546136ac9084615a50565b8811156136cc576040516361ee36eb60e01b815260040160405180910390fd5b6001600160a01b03891633148015906136f75750846001600160a01b0316896001600160a01b031614155b6137145760405163271bd90b60e01b815260040160405180910390fd5b6001600160a01b03871615613729578661372b565b305b63ffffffff831660009081526016602090815260408083206001600160a01b038a168452909152812080549299508a92909190613769908490615b5f565b9091555061377d9050868a8a8a6000612f38565b604080516001600160a01b038b81168252888116602083015263ffffffff851682840152606082018b905291518983169288169133917fc643e0e4d5d1082f6bfc662466c6ee07f745f7725754c136e448452d1f1878679181900360800190a450505050505050505050565b6137f1612722565b6137f9612765565b6120ef8383836149c6565b6002546040517f6765dff90000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0386811660248301528581166044830152848116606483015290911690636765dff990608401600060405180830381600087803b15801561387a57600080fd5b505af115801561388e573d6000803e3d6000fd5b50505050826001600160a01b0316826001600160a01b0316036138c45760405163bca3ab8960e01b815260040160405180910390fd5b60006138e5826040518060200160405280666379da05b60000815250614b5e565b905060006138f38284615a50565b90506000604051806020016040528061390a612bce565b90529050600061391a8285612f20565b9050600081600b5461392c9190615b5f565b600b819055600c54909150613942908690615a50565b600c556001600160a01b0387166000908152600f6020526040902054613969908790615a50565b6001600160a01b038089166000908152600f602052604080822093909355908a1681522054613999908590615b5f565b6001600160a01b03808a166000818152600f602052604090819020939093559151908916907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906139ed9088815260200190565b60405180910390a360405185815230906001600160a01b038916907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a3604080518381526020810183905230917fa91e67c5ea634cd43a12c5a482724b03de01e85ca68702a53d0c2f45cb7c1dc5910160405180910390a2505050505050505050565b613a83612722565b613a8b612765565b6120ef8383600084613e75565b6040805160208101909152600081526040518060200160405280613ac0856000015185614b81565b90529392505050565b600080613ad68585613a98565b9050612c2e613ae482614261565b84614b8d565b613af2614b99565b6129a484848484614bdb565b600080600080600080613b1e613b178860006014614c96565b6000614dbe565b9550613b2f613b1788601480614c96565b9450613b48613b418860286020614c96565b6000614e34565b9350613b5a613b418860486020614c96565b9250613b73613b6c8860686004614c96565b6000614e9a565b9150613b85613b6c88606c6004614c96565b905091939550919395565b806001600160a01b0316826001600160a01b031614611391576001600160a01b0380821660009081526018602090815260408083209386168352929052205460ff1680613bea57506000546001600160a01b038381169116145b80613ced5750600354604080517fa872019500000000000000000000000000000000000000000000000000000000815290516001600160a01b03909216916338dd8c2c918591849163a87201959160048083019260209291908290030181865afa158015613c5c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c809190615a04565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015613cc9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ced9190615a1d565b80613dd757506003546040805163a1bd302d60e01b815290516001600160a01b03909216916338dd8c2c918591849163a1bd302d9160048083019260209291908290030181865afa158015613d46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d6a9190615a04565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015613db3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613dd79190615a1d565b6113915760405163271bd90b60e01b815260040160405180910390fd5b6000613e096001600160a01b03841683614f00565b90508051600014158015613e2e575080806020019051810190613e2c9190615a1d565b155b15611581576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b03841660048201526024015b60405180910390fd5b821580613e80575081155b613e9d5760405163bca3ab8960e01b815260040160405180910390fd5b60006040518060200160405280613eb2612bce565b905290506000808515613ed357859150613ecc8387612f20565b9050613ee3565b613edd8584614f0e565b91508490505b81158015613eef575080155b15613f26576040517fbbf3e56400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002546040517f1e32bd9b0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0389811660248301526044820185905290911690631e32bd9b90606401600060405180830381600087803b158015613f9357600080fd5b505af1158015613fa7573d6000803e3d6000fd5b5050505080613fb560115490565b1015613fed576040517f14ec588c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81600c54613ffb9190615a50565b600c556001600160a01b0387166000908152600f6020526040902054614022908390615a50565b6001600160a01b0388166000908152600f6020526040902055831561404b5761404b878261294a565b806011600082825461405d9190615a50565b909155505060405182815230906001600160a01b038916907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a360408051828152602081018490526001600160a01b038916917fe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929910160405180910390a250505050505050565b6002546040517fc321fbcc0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038581166024830152600092169063c321fbcc90604401600060405180830381600087803b15801561415657600080fd5b505af115801561416a573d6000803e3d6000fd5b50505050600061417985612b7a565b90506000600019851461418c578461418e565b815b905060008461419d57816141a7565b6141a78883614662565b905080601160008282546141bb9190615b5f565b90915550600090506141cd8285615a50565b9050600082600a546141df9190615a50565b6001600160a01b038a81166000818152600e6020908152604091829020878155600954600190910155600a859055815188815290810187905290810184905292935091908c16907f1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a19060600160405180910390a3509098975050505050505050565b8051600090610c7890670de0b6b3a764000090615c8f565b846001600160a01b0316846001600160a01b0316036142ab5760405163bca3ab8960e01b815260040160405180910390fd5b6000831180156142bd57506000198314155b6142da5760405163bca3ab8960e01b815260040160405180910390fd5b6002546040517fb50ce7620000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0384811660248301528681166044830152606482018690529091169063b50ce7629060840160006040518083038186803b15801561434d57600080fd5b505afa158015614361573d6000803e3d6000fd5b5050505061436c4290565b826001600160a01b0316636c540baf6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156143aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143ce9190615a04565b14614405576040517fdf70808000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000614413868686856140ef565b6002546040517fc488847b0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038681166024830152604482018490529293506000929091169063c488847b90606401602060405180830381865afa158015614489573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144ad9190615a04565b6040516370a0823160e01b81526001600160a01b03888116600483015291925082918616906370a0823190602401602060405180830381865afa1580156144f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061451c9190615a04565b1015614554576040517f7286c37500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b306001600160a01b038516036145755761457030888884613804565b6145f9565b6040517fb2a02ff10000000000000000000000000000000000000000000000000000000081526001600160a01b03888116600483015287811660248301526044820183905285169063b2a02ff190606401600060405180830381600087803b1580156145e057600080fd5b505af11580156145f4573d6000803e3d6000fd5b505050505b836001600160a01b0316866001600160a01b0316886001600160a01b03167f298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb528585604051614651929190918252602082015260400190565b60405180910390a450505050505050565b6013546040516370a0823160e01b815230600482015260009182916001600160a01b03909116906370a0823190602401602060405180830381865afa1580156146af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146d39190615a04565b6013549091506146ee906001600160a01b0316853086614f2c565b6013546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015614737573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061475b9190615a04565b9050612c2e8282615a50565b6002546040517fc0f1ee090000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0385811660248301529091169063c0f1ee0990604401600060405180830381600087803b1580156147cd57600080fd5b505af11580156147e1573d6000803e3d6000fd5b50505050600060405180602001604052806147fa612bce565b9052905060008261480b5783614815565b6148158585614662565b905080601160008282546148299190615b5f565b909155506000905061483b8284614f0e565b9050600c54600003614889576103e8600c81905560008052600f6020527ff4803e074bd026baaf6ed2e288c9515f68c72fb7216eebdd7cae1718a53ec3758190556148869082615a50565b90505b80600c546148979190615b5f565b600c556001600160a01b0386166000908152600f60205260409020546148be908290615b5f565b6001600160a01b0387166000818152600f602090815260409182902093909355805185815292830184905290917f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f910160405180910390a26040518181526001600160a01b0387169030907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a36002546040517f0d926fc80000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0390911690630d926fc89060240160006040518083038186803b1580156149b257600080fd5b505afa158015611057573d6000803e3d6000fd5b6002546040517f50795f8a0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b03858116602483015260448201859052909116906350795f8a90606401600060405180830381600087803b158015614a3357600080fd5b505af1158015614a47573d6000803e3d6000fd5b5050505081614a5560115490565b1015614a8d576040517fcd85b93e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000614a9884612b7a565b90506000614aa68483615b5f565b9050600084600a54614ab89190615b5f565b6001600160a01b0387166000908152600e60205260409020838155600954600190910155600a81905590508315614af357614af3868661294a565b8460116000828254614b059190615a50565b909155505060408051868152602081018490529081018290526001600160a01b038716907f13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab809060600160405180910390a2505050505050565b6000670de0b6b3a7640000614b77848460000151614b81565b610c759190615c8f565b6000610c758284615c78565b6000610c758284615b5f565b6014546001600160a01b0316612017576040517ff242df5300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6014546015546040516001600160a01b039092169163ab750e75918591859190600290614c0b908b908b90615cb1565b602060405180830381855afa158015614c28573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190614c4b9190615a04565b6040518563ffffffff1660e01b8152600401614c6a9493929190615cc1565b60006040518083038186803b158015614c8257600080fd5b505afa15801561128c573d6000803e3d6000fd5b606081614ca481601f615b5f565b1015614cf25760405162461bcd60e51b815260206004820152600e60248201527f736c6963655f6f766572666c6f770000000000000000000000000000000000006044820152606401613e6c565b614cfc8284615b5f565b84511015614d4c5760405162461bcd60e51b815260206004820152601160248201527f736c6963655f6f75744f66426f756e64730000000000000000000000000000006044820152606401613e6c565b606082158015614d6b5760405191506000825260208201604052614db5565b6040519150601f8416801560200281840101858101878315602002848b0101015b81831015614da4578051835260209283019201614d8c565b5050858452601f01601f1916604052505b50949350505050565b6000614dcb826014615b5f565b83511015614e1b5760405162461bcd60e51b815260206004820152601560248201527f746f416464726573735f6f75744f66426f756e647300000000000000000000006044820152606401613e6c565b5001602001516c01000000000000000000000000900490565b6000614e41826020615b5f565b83511015614e915760405162461bcd60e51b815260206004820152601560248201527f746f55696e743235365f6f75744f66426f756e647300000000000000000000006044820152606401613e6c565b50016020015190565b6000614ea7826004615b5f565b83511015614ef75760405162461bcd60e51b815260206004820152601460248201527f746f55696e7433325f6f75744f66426f756e64730000000000000000000000006044820152606401613e6c565b50016004015190565b6060610c7583836000614f65565b6000610c75614f2584670de0b6b3a7640000614b81565b835161501b565b6040516001600160a01b0384811660248301528381166044830152606482018390526129a49186918216906323b872dd90608401612c64565b606081471015614fa3576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401613e6c565b600080856001600160a01b03168486604051614fbf9190615d01565b60006040518083038185875af1925050503d8060008114614ffc576040519150601f19603f3d011682016040523d82523d6000602084013e615001565b606091505b5091509150615011868383615027565b9695505050505050565b6000610c758284615c8f565b60608261503c576150378261509c565b61146e565b815115801561505357506001600160a01b0384163b155b15615095576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401613e6c565b508061146e565b8051156150ac5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b838110156150f95781810151838201526020016150e1565b50506000910152565b6000815180845261511a8160208601602086016150de565b601f01601f19169290920160200192915050565b602081526000610c756020830184615102565b6001600160a01b0381168114610ede57600080fd5b80356111c781615141565b803563ffffffff811681146111c757600080fd5b6000806040838503121561518857600080fd5b823561519381615141565b91506151a160208401615161565b90509250929050565b6000602082840312156151bc57600080fd5b5035919050565b60008083601f8401126151d557600080fd5b50813567ffffffffffffffff8111156151ed57600080fd5b60208301915083602082850101111561520557600080fd5b9250929050565b60008083601f84011261521e57600080fd5b50813567ffffffffffffffff81111561523657600080fd5b6020830191508360208260051b850101111561520557600080fd5b60008060008060008060006080888a03121561526c57600080fd5b873567ffffffffffffffff81111561528357600080fd5b61528f8a828b016151c3565b909850965050602088013567ffffffffffffffff8111156152af57600080fd5b6152bb8a828b016151c3565b909650945050604088013567ffffffffffffffff8111156152db57600080fd5b6152e78a828b0161520c565b90945092505060608801356152fb81615141565b8091505092959891949750929550565b6000806040838503121561531e57600080fd5b823561532981615141565b946020939093013593505050565b60006020828403121561534957600080fd5b813561146e81615141565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561539357615393615354565b604052919050565b60008067ffffffffffffffff8411156153b6576153b6615354565b50601f8301601f19166020016153cb8161536a565b9150508281528383830111156153e057600080fd5b828260208301376000602084830101529392505050565b600082601f83011261540857600080fd5b610c758383356020850161539b565b803560ff811681146111c757600080fd5b600080600080600080600060e0888a03121561544357600080fd5b873561544e81615141565b9650602088013561545e81615141565b9550604088013561546e81615141565b945060608801359350608088013567ffffffffffffffff81111561549157600080fd5b61549d8a828b016153f7565b93505060a088013567ffffffffffffffff8111156154ba57600080fd5b6154c68a828b016153f7565b9250506154d560c08901615417565b905092959891949750929550565b6000806000606084860312156154f857600080fd5b833561550381615141565b9250602084013561551381615141565b929592945050506040919091013590565b6000806040838503121561553757600080fd5b823591506151a160208401615161565b6000806040838503121561555a57600080fd5b61556383615161565b9150602083013561557381615141565b809150509250929050565b60008060006060848603121561559357600080fd5b833561559e81615141565b92506020840135915060408401356155b581615141565b809150509250925092565b8015158114610ede57600080fd5b600080604083850312156155e157600080fd5b82356155ec81615141565b91506020830135615573816155c0565b6000806040838503121561560f57600080fd5b823561556381615141565b6000806000806000806000806000806101408b8d03121561563a57600080fd5b6156438b615156565b995061565160208c01615156565b985061565f60408c01615156565b975060608b0135965060808b013567ffffffffffffffff81111561568257600080fd5b61568e8d828e016153f7565b96505060a08b013567ffffffffffffffff8111156156ab57600080fd5b6156b78d828e016153f7565b9550506156c660c08c01615417565b93506156d460e08c01615156565b92506156e36101008c01615156565b91506156f26101208c01615156565b90509295989b9194979a5092959850565b60006020828403121561571557600080fd5b610c7582615161565b6000806040838503121561573157600080fd5b6155ec83615161565b60008060008060008060c0878903121561575357600080fd5b863561575e81615141565b9550602087013561576e81615141565b945060408701359350606087013567ffffffffffffffff81111561579157600080fd5b61579d89828a016153f7565b935050608087013567ffffffffffffffff8111156157ba57600080fd5b6157c689828a016153f7565b9250506157d560a08801615417565b90509295509295509295565b600080600080600080600080600080600060c08c8e03121561580257600080fd5b8b3567ffffffffffffffff81111561581957600080fd5b6158258e828f016151c3565b909c509a505060208c013567ffffffffffffffff81111561584557600080fd5b6158518e828f016151c3565b909a5098505060408c013567ffffffffffffffff81111561587157600080fd5b61587d8e828f0161520c565b90985096505060608c013567ffffffffffffffff81111561589d57600080fd5b6158a98e828f0161520c565b90965094505060808c013567ffffffffffffffff8111156158c957600080fd5b6158d58e828f0161520c565b90945092506158e8905060a08d01615156565b90509295989b509295989b9093969950565b600080600080600080600080610100898b03121561591757600080fd5b883561592281615141565b9750602089013561593281615141565b9650604089013561594281615141565b955060608901359450608089013567ffffffffffffffff81111561596557600080fd5b6159718b828c016153f7565b94505060a089013567ffffffffffffffff81111561598e57600080fd5b61599a8b828c016153f7565b9350506159a960c08a01615417565b915060e08901356159b981615141565b809150509295985092959890939650565b600181811c908216806159de57607f821691505b6020821081036159fe57634e487b7160e01b600052602260045260246000fd5b50919050565b600060208284031215615a1657600080fd5b5051919050565b600060208284031215615a2f57600080fd5b815161146e816155c0565b634e487b7160e01b600052601160045260246000fd5b81810381811115610c7857610c78615a3a565b600060208284031215615a7557600080fd5b813567ffffffffffffffff811115615a8c57600080fd5b8201601f81018413615a9d57600080fd5b803567ffffffffffffffff811115615ab757615ab7615354565b8060051b615ac76020820161536a565b91825260208184018101929081019087841115615ae357600080fd5b6020850192505b83831015615b3e57823567ffffffffffffffff811115615b0957600080fd5b8501603f81018913615b1a57600080fd5b615b2c8960208301356040840161539b565b83525060209283019290910190615aea565b979650505050505050565b634e487b7160e01b600052603260045260246000fd5b80820180821115610c7857610c78615a3a565b601f82111561158157806000526020600020601f840160051c81016020851015615b995750805b601f840160051c820191505b818110156124395760008155600101615ba5565b815167ffffffffffffffff811115615bd357615bd3615354565b615be781615be184546159ca565b84615b72565b6020601f821160018114615c1b5760008315615c035750848201515b600019600385901b1c1916600184901b178455612439565b600084815260208120601f198516915b82811015615c4b5787850151825560209485019460019092019101615c2b565b5084821015615c695786840151600019600387901b60f8161c191681555b50505050600190811b01905550565b8082028115828204841417610c7857610c78615a3a565b600082615cac57634e487b7160e01b600052601260045260246000fd5b500490565b8183823760009101908152919050565b606081528360608201528385608083013760006080858301015260006080601f19601f870116830101905083602083015282604083015295945050505050565b60008251615d138184602087016150de565b919091019291505056fea2646970667358221220724ffecd1dda03b6a8f003dfa58cd82a8ac6d25418fd46d9382ac52b8b1e24df64736f6c634300081c0033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.