Overview
ETH Balance
0 ETH
ETH Value
$0.00More Info
Private Name Tags
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
5886777 | 11 days ago | Contract Creation | 0 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Source Code Verified (Exact Match)
Contract Name:
ZKSyncLST
Compiler Version
v0.8.25+commit.b61c2a91
ZkSolc Version
v1.5.12
Optimization Enabled:
Yes with Mode 3
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.25; import {LiquidStakingTokenCompose} from "./LiquidStakingTokenCompose.sol"; import {IL2BaseToken} from "./interfaces/IL2BaseToken.sol"; import {IL1Receiver} from "./vendor/layerzero/syncpools/interfaces/IL1Receiver.sol"; /** * @title ZKSyncLST * @notice An implementation of the LiquidStakingToken contract on ZkSync Era that sends slow sync messages to the L2 system. * @dev This contract facilitates interactions between mainnet PirexEth contracts and the ZKSync. * @author Dinero Protocol */ contract ZKSyncLST is LiquidStakingTokenCompose { /** * @notice Contract constructor to initialize LiquidStakingTokenVault with necessary parameters and configurations. * @dev This constructor sets up the LiquidStakingTokenVault contract, configuring key parameters and initializing state variables. * @param _endpoint address The address of the LOCAL LayerZero endpoint. * @param _srcEid uint32 The source endpoint ID. */ /// @custom:oz-upgrades-unsafe-allow constructor constructor( address _endpoint, uint32 _srcEid ) LiquidStakingTokenCompose(_endpoint, _srcEid) {} /** * @dev Internal function to send a slow sync message * @param _value Amount of ETH to send * @param _data Data to send */ function _sendSlowSyncMessage( address, uint256 _value, uint256, bytes memory _data ) internal override { bytes memory message = abi.encodeCall( IL1Receiver.onMessageReceived, _data ); IL2BaseToken(getMessenger()).withdrawWithMessage{value: _value}( getReceiver(), message ); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.25; import {LiquidStakingToken} from "./LiquidStakingToken.sol"; import {Origin} from "./vendor/layerzero-upgradeable/oapp/interfaces/IOAppReceiver.sol"; import {OFTComposeMsgCodec} from "./vendor/layerzero/oft/libs/OFTComposeMsgCodec.sol"; import {MsgCodec} from "./libraries/MsgCodec.sol"; /** * @title LiquidStakingTokenCompose * @notice An DineroERC20Rebase OApp contract for handling LST operations between L2 and mainnet. * @dev This contract facilitates interactions between mainnet PirexEth contracts and the L2 system. * @author redactedcartel.finance */ abstract contract LiquidStakingTokenCompose is LiquidStakingToken { /** * @dev Library: MsgCodec - Provides encoding and decoding of messages. */ using MsgCodec for bytes; /** * @notice Contract constructor to initialize LiquidStakingToken with necessary parameters and configurations. * @dev This constructor sets up the LiquidStakingToken contract, configuring key parameters and initializing state variables. * @param _endpoint address The address of the LOCAL LayerZero endpoint. * @param _srcEid uint32 The source endpoint ID. */ /// @custom:oz-upgrades-unsafe-allow constructor constructor( address _endpoint, uint32 _srcEid ) LiquidStakingToken(_endpoint, _srcEid) {} /** * @notice Handler for processing layerzero messages from L2. * @dev Only accept and handle the deposit and rebase messages from mainnet, which mints and stakes LiquidStakingToken. * @dev _origin Origin The origin information containing the source endpoint and sender address. * @dev _guid bytes32 The unique identifier for the received LayerZero message. * @param _message bytes The payload of the received message. * @dev address The address of the executor for the received message. * @dev bytes Additional arbitrary data provided by the corresponding executor. */ function _lzReceive( Origin calldata _origin, bytes32 _guid, bytes calldata _message, address, bytes calldata ) internal virtual override nonReentrant { _acceptNonce(_origin.srcEid, _origin.sender, _origin.nonce); uint256 amountReceived = _handleMessageReceived(_guid, _message); (bool isComposed, ) = _message.isComposed(); if (isComposed) { _sendCompose( _origin.srcEid, _origin.nonce, _guid, amountReceived, _message ); } } /** * @dev Decode the received message. * @param _message bytes The message to decode. * @return messageType uint256 The message type. * @return amount uint256 The amount. * @return assetsPerShare uint256 The assets per share. * @return receiver address The receiver address. * @return syncedIds bytes32[] The synced IDs. */ function _decodeReceivedMessage( bytes calldata _message ) internal pure override returns ( uint256 messageType, uint256 amount, uint256 assetsPerShare, address receiver, bytes32[] memory syncedIds ) { return _message.decodeL1Msg(); } /** * @dev Send compose message to the destination endpoint. * @param _srcEid endpoint ID of the source. * @param _nonce nonce of the message. * @param _guid GUID of the message. * @param _amountReceived amount received. * @param _message message to compose. */ function _sendCompose( uint32 _srcEid, uint64 _nonce, bytes32 _guid, uint256 _amountReceived, bytes calldata _message ) internal virtual { // @dev composeMsg format for the OFT. bytes memory composeMsg = OFTComposeMsgCodec.encode( _nonce, _srcEid, _amountReceived, abi.encodePacked( OFTComposeMsgCodec.addressToBytes32(address(this)), _message.composeMsg() ) ); endpoint.sendCompose( _message.composeTo(), _guid, 0 /* the index of the composed message*/, composeMsg ); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.25; interface IL2BaseToken { function withdrawWithMessage( address _l1Receiver, bytes calldata _additionalData ) external payable; }
// SPDX-License-Identifier: LZBL-1.2 pragma solidity ^0.8.20; interface IL1Receiver { function onMessageReceived(bytes calldata message) external payable; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.25; import {DineroERC20RebaseUpgradeable} from "./DineroERC20RebaseUpgradeable.sol"; import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol"; import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol"; import {OAppUpgradeable} from "contracts/vendor/layerzero-upgradeable/oapp/OAppUpgradeable.sol"; import {MessagingFee, MessagingReceipt} from "contracts/vendor/layerzero-upgradeable/oapp/OAppSenderUpgradeable.sol"; import {OAppOptionsType3Upgradeable} from "contracts/vendor/layerzero-upgradeable/oapp/libs/OAppOptionsType3Upgradeable.sol"; import {Origin} from "contracts/vendor/layerzero-upgradeable/oapp/interfaces/IOAppReceiver.sol"; import {FixedPointMathLib} from "solmate/src/utils/FixedPointMathLib.sol"; import {Constants} from "./libraries/Constants.sol"; import {Errors} from "./libraries/Errors.sol"; import {L2SyncPool} from "./L2SyncPool.sol"; import {BaseMessengerUpgradeable} from "contracts/vendor/layerzero/syncpools/utils/BaseMessengerUpgradeable.sol"; import {BaseReceiverUpgradeable} from "contracts/vendor/layerzero/syncpools/utils/BaseReceiverUpgradeable.sol"; import {IRateProvider} from "./interfaces/IRateProvider.sol"; import {IRateLimiter} from "contracts/vendor/layerzero/syncpools/interfaces/IRateLimiter.sol"; import {IWrappedLiquidStakedToken} from "./interfaces/IWrappedLiquidStakedToken.sol"; /** * @title LiquidStakingToken * @notice An DineroERC20Rebase OApp contract for handling LST operations between L2 and mainnet. * @dev This contract facilitates interactions between mainnet PirexEth contracts and the L2 system. * @author redactedcartel.finance */ abstract contract LiquidStakingToken is DineroERC20RebaseUpgradeable, L2SyncPool, BaseMessengerUpgradeable, BaseReceiverUpgradeable, OAppUpgradeable, OAppOptionsType3Upgradeable, ReentrancyGuardUpgradeable, PausableUpgradeable { /** * @dev Library: FixedPointMathLib - Provides fixed-point arithmetic for uint256. */ using FixedPointMathLib for uint256; /** * @notice The endpoint ID for L1. * @dev This constant defines the source endpoint ID for the L1. */ uint32 internal immutable L1_EID; /// @custom:storage-location erc7201:redacted.storage.LiquidStakingToken struct L2TokenStorage { /** * @notice Total assets actively staked in the vault. * @dev This variable holds the total assets actively staked, follows totalAssets in the mainnet lockbox. */ uint256 totalStaked; /** * @notice The last assets per share value. * @dev This variable holds the last assets per share value received form deposit or rebase. */ uint256 lastAssetsPerShare; /** * @notice The unsynced pending deposit amount. * @dev This variable holds the pending deposit amount that has not been synced and is not staked in the mainnet vault and will not be rebased. */ uint256 unsyncedPendingDeposit; /** * @notice The synced pending deposit amount. * @dev This variable holds the pending deposit amount that has been synced and is not staked in the mainnet vault and will not be rebased. */ uint256 syncedPendingDeposit; /** * @notice The total unsynced shares. * @dev This variable holds the total unsynced shares. */ uint256 unsyncedShares; /** * @notice The rebase fee that is charged on each rebase. * @dev This variable holds the rebase fee that is charged on each rebase. */ uint256 rebaseFee; /** * @notice The sync deposit fee that is charged on each sync pool L2 deposit. * @dev This variable holds the sync deposit fee that is charged on each sync pool L2 deposit. */ uint256 syncDepositFee; /** * @notice The treasury address that receives the treasury fee. * @dev This variable holds the address of the treasury, which receives the treasury fee when a rebase occurs. */ address treasury; /** * @notice Last pending sync index. * @dev This variable holds the last pending sync index. */ uint256 lastPendingSyncIndex; /** * @notice Last completed sync index. * @dev This variable holds the last completed sync index. */ uint256 lastCompletedSyncIndex; /** * @notice Sync index to pending amount mapping. * @dev This mapping holds the sync index to pending amount mapping. */ mapping(uint256 => uint256) syncIndexPendingAmount; /** * @notice Sync ID to index mapping. * @dev This mapping holds the sync ID to index mapping. */ mapping(bytes32 => uint256) syncIdIndex; /** * @notice The nonce for the received messages. * @dev Mapping to track the maximum received nonce for each source endpoint and sender */ mapping(uint32 eid => mapping(bytes32 sender => uint64 nonce)) receivedNonce; /** * @notice Mapping to track the accounts that can pause the contract. * @dev This mapping holds the accounts that can pause the contract. */ mapping(address => bool) canPause; /** * @dev The address of the Wrapped Liquid Staked Token contract. * @dev This variable holds the address of the Wrapped Liquid Staked Token contract. */ address wLST; } // keccak256(abi.encode(uint256(keccak256(redacted.storage.LiquidStakingToken)) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant LiquidStakingTokenStorageLocation = 0xdd932cf12f0dd29482349e8f041f211cd1a01e556f17b4835472bd462fb09100; function _getLiquidStakingTokenStorage() internal pure returns (L2TokenStorage storage $) { assembly { $.slot := LiquidStakingTokenStorageLocation } } // Events /** * @notice Emitted on sending withdrawal message. * @param guid bytes32 GUID of the OFT message. * @param fromAddress address Address of the sender on the src chain. * @param toAddress address Address of the recipient on the src chain. * @param amount uint256 Withdrawal amount (in LiquidStakingToken). */ event Withdrawal( bytes32 indexed guid, address indexed fromAddress, address indexed toAddress, uint256 amount ); /** * @notice Emitted on receiving the deposit message. * @param guid bytes32 GUID of the OFT message. * @param toAddress address Address of the recipient on L2. * @param shares uint256 Deposit amount (in shares). * @param amount uint256 Deposit amount (in LiquidStakingToken). */ event Deposit( bytes32 indexed guid, address indexed toAddress, uint256 shares, uint256 amount ); /** * @notice Emitted on minting tokens from SyncPool. * @param toAddress address Address of the recipient on L2. * @param shares uint256 Deposit amount (in shares). * @param amount uint256 Deposit amount (in LiquidStakingToken). */ event Mint(address indexed toAddress, uint256 shares, uint256 amount); /** * @notice Emitted on receiving rebase message. * @param guid bytes32 GUID of the OFT message. * @param treasury address Address of the treasury. * @param assetsPerShare uint256 The current assets per share. * @param amount uint256 Deposit amount (in LiquidStakingToken). * @param fee uint256 Fee amount (in LiquidStakingToken). * @param feeShares uint256 Fee amount (in shares). */ event Rebase( bytes32 indexed guid, address indexed treasury, uint256 assetsPerShare, uint256 amount, uint256 fee, uint256 feeShares ); /** * @notice Emitted when the pause is set. * @param account address The account that can pause the contract. * @param allowed bool The allowed status. */ event canPauseSet(address indexed account, bool allowed); /** * @notice Contract constructor to initialize LiquidStakingTokenVault with necessary parameters and configurations. * @dev This constructor sets up the LiquidStakingTokenVault contract, configuring key parameters and initializing state variables. * @param _endpoint address The address of the LOCAL LayerZero endpoint. * @param _srcEid uint32 The source endpoint ID. */ /// @custom:oz-upgrades-unsafe-allow constructor constructor(address _endpoint, uint32 _srcEid) OAppUpgradeable(_endpoint) { L1_EID = _srcEid; _disableInitializers(); } /** * @dev modifier to allow only the owner or the canPause address to pause the contract */ modifier onlyCanPause() { if (!_canPause(_msgSender())) revert Errors.NotAllowed(); _; } /** * @notice Initialize the LiquidStakingToken contract. * @param _delegate address The delegate capable of making OApp configurations inside of the endpoint. * @param _owner address The owner of the contract. * @param _treasury address The treasury address. * @param _l2ExchangeRateProvider Address of the exchange rate provider * @param _rateLimiter address The rate limiter address. * @param _messenger Address of the messenger contract (most of the time, the L2 native bridge address) * @param _receiver Address of the receiver contract (most of the time, the L1 receiver contract) * @param _bridgeQuoter Address of the bridge quoter contract * @param _name string The name of the token. * @param _symbol string The symbol of the token. */ function initialize( address _delegate, address _owner, address _treasury, address _l2ExchangeRateProvider, address _rateLimiter, address _messenger, address _receiver, address _bridgeQuoter, string memory _name, string memory _symbol ) external initializer { __LiquidStakingToken_init(_delegate, _owner, _treasury, _name, _symbol); __L2BaseSyncPool_init( _l2ExchangeRateProvider, _rateLimiter, _bridgeQuoter ); __BaseMessenger_init(_messenger); __BaseReceiver_init(_receiver); } function __LiquidStakingToken_init( address _delegate, address _owner, address _treasury, string memory _name, string memory _symbol ) internal onlyInitializing { __ReentrancyGuard_init(); __Pausable_init(); __Ownable_init(_owner); __OAppCore_init(_delegate); __DineroERC20Rebase_init(_name, _symbol); _setTreasury(_treasury); } /** * @notice Handler for processing layerzero messages from L2. * @dev Only accept and handle the deposit and rebase messages from mainnet, which mints and stakes LiquidStakingToken. * @dev _origin Origin The origin information containing the source endpoint and sender address. * @dev _guid bytes32 The unique identifier for the received LayerZero message. * @param _message bytes The payload of the received message. * @dev address The address of the executor for the received message. * @dev bytes Additional arbitrary data provided by the corresponding executor. */ function _lzReceive( Origin calldata _origin, bytes32 _guid, bytes calldata _message, address, bytes calldata ) internal virtual override nonReentrant { _acceptNonce(_origin.srcEid, _origin.sender, _origin.nonce); _handleMessageReceived(_guid, _message); } /** * @notice Handler for processing layerzero messages. * @dev Only accept and handle the deposit and rebase messages from mainnet, which mints and stakes LiquidStakingToken. * @dev _guid bytes32 The unique identifier for the received LayerZero message. * @param _message bytes The payload of the received message. * @dev address The address of the executor for the received message. * @dev bytes Additional arbitrary data provided by the corresponding executor. */ function _handleMessageReceived( bytes32 _guid, bytes calldata _message ) internal virtual returns (uint256 amountReceived) { ( uint256 _messageType, uint256 _amount, uint256 _assetsPerShare, address _receiver, bytes32[] memory _syncedIds ) = _decodeReceivedMessage(_message); L2TokenStorage storage $ = _getLiquidStakingTokenStorage(); if ( _messageType == Constants.MESSAGE_TYPE_DEPOSIT || _messageType == Constants.MESSAGE_TYPE_DEPOSIT_WRAP ) { _updateTotalStaked(_assetsPerShare); uint256 shares = getTotalShares() == 0 ? _amount : convertToShares(_amount); if (_messageType == Constants.MESSAGE_TYPE_DEPOSIT_WRAP) { _mintShares(address(this), shares); $.totalStaked += _amount; uint256 amount = convertToAssets(shares, true); _approve(address(this), $.wLST, amount, false); uint256 wAmount = IWrappedLiquidStakedToken($.wLST).wrap( amount ); IWrappedLiquidStakedToken($.wLST).transfer(_receiver, wAmount); } else { _mintShares(_receiver, shares); $.totalStaked += _amount; } IRateLimiter(getRateLimiter()).updateRateLimit( address(this), address(this), shares, 0 ); emit Deposit(_guid, _receiver, shares, _amount); } else if (_messageType == Constants.MESSAGE_TYPE_REBASE) { _updateTotalStaked(_assetsPerShare); uint256 fee = _amount.mulDivDown( $.rebaseFee, Constants.FEE_DENOMINATOR ); uint256 shares; if (fee > 0 && _totalAssets() > fee) { shares = fee.mulDivDown(getTotalShares(), _totalAssets() - fee); _mintShares($.treasury, shares); IRateLimiter(getRateLimiter()).updateRateLimit( address(this), address(this), shares, 0 ); } else { fee = 0; } emit Rebase( _guid, $.treasury, _assetsPerShare, _amount, fee, shares ); } else { revert Errors.NotAllowed(); } if (_syncedIds.length > 0) { uint256 staked = _updateSyncQueue(_syncedIds); if (staked > 0) { $.totalStaked += staked; $.syncedPendingDeposit -= staked; } } return _amount; } /** * @dev Decode the received message. * @param _message bytes The message to decode. * @return messageType uint256 The message type. * @return amount uint256 The amount. * @return assetsPerShare uint256 The assets per share. * @return receiver address The receiver address. * @return syncedIds bytes32[] The synced IDs. */ function _decodeReceivedMessage( bytes calldata _message ) internal pure virtual returns ( uint256 messageType, uint256 amount, uint256 assetsPerShare, address receiver, bytes32[] memory syncedIds ) { return abi.decode( _message, (uint256, uint256, uint256, address, bytes32[]) ); } /** * @notice Mint LiquidStakingToken tokens to the recipient. * @dev Only the Sync Pool contract can mint LiquidStakingToken tokens. * @param _to address The recipient of the minted tokens. * @param _assetsPerShare uint256 The assets per share value. * @param _amount uint256 The amount of assets to mint. */ function _mint( address _to, uint256 _assetsPerShare, uint256 _amount ) internal { L2TokenStorage storage $ = _getLiquidStakingTokenStorage(); if ($.lastAssetsPerShare < _assetsPerShare) _updateTotalStaked(_assetsPerShare); uint256 _totalShares = getTotalShares(); uint256 shares = _totalShares == 0 ? _amount : convertToShares(_amount); uint256 depositFee = $.syncDepositFee; if (depositFee > 0) { uint256 feeShares = shares.mulDivDown( depositFee, Constants.FEE_DENOMINATOR ); _mintShares($.treasury, feeShares); $.unsyncedShares += feeShares; shares -= feeShares; } _mintShares(_to, shares); $.unsyncedShares += shares; $.unsyncedPendingDeposit += _amount; emit Mint(_to, shares, _amount); } /** * @dev Add msg id to sync queue. * @param _msgReceipt bytes32 The unique identifier for the message. * @param _amount uint256 Sync amount */ function _addToSyncQueue( MessagingReceipt memory _msgReceipt, uint256 _amount ) internal { // add to sync queue L2TokenStorage storage $ = _getLiquidStakingTokenStorage(); $.lastPendingSyncIndex += 1; uint256 id = $.lastPendingSyncIndex; $.syncIdIndex[_msgReceipt.guid] = id; $.syncIndexPendingAmount[id] = _amount; $.syncedPendingDeposit += _amount; $.unsyncedPendingDeposit -= _amount; } /** * @notice Perform withdraw and burn of LiquidStakingToken tokens relaying the withdrawal message to Mainnet. * @param _receiver address The recipient of the withdrawal on Mainnet. * @param _refundAddress The address to receive any excess funds sent to layer zero. * @param _amount uint256 Withdrawal amount (in assets). * @param _options bytes Additional options for the message. */ function withdraw( address _receiver, address _refundAddress, uint256 _amount, bytes calldata _options ) external payable virtual nonReentrant whenNotPaused { if (_receiver == address(0)) revert Errors.ZeroAddress(); // revert if the receiver is a smart contract on the source chain if (_receiver.code.length > 0) revert Errors.InvalidReceiver(); if (_amount == 0) revert Errors.ZeroAmount(); L2TokenStorage storage $ = _getLiquidStakingTokenStorage(); uint256 shares = previewWithdraw(_amount); IRateLimiter(getRateLimiter()).updateRateLimit( address(this), address(this), 0, shares ); _burnShares(msg.sender, shares); bytes memory payload = abi.encode( Constants.MESSAGE_TYPE_WITHDRAW, _amount, _receiver ); bytes memory combinedOptions = combineOptions(L1_EID, 0, _options); uint256 synced = $.syncedPendingDeposit; if (synced > 0) { uint256 remaining = _withdrawPendingDeposit(_amount); if (remaining > 0) { $.totalStaked -= remaining; } } else { $.totalStaked -= _amount; } MessagingReceipt memory msgReceipt = _lzSend( L1_EID, payload, combinedOptions, MessagingFee(msg.value, 0), payable(_refundAddress) ); emit Withdrawal(msgReceipt.guid, msg.sender, _receiver, _amount); } /** * @notice Deposit tokens on Layer 2 * This will mint tokenOut on Layer 2 using the exchange rate for tokenIn to tokenOut. * The amount deposited and minted will be stored in the token data which can be synced to Layer 1. * Will revert if: * - The amountIn is zero * - The token is unauthorized (that is, the l1Address is address(0)) * - The amountOut is less than the minAmountOut * @param tokenIn Address of the token * @param amountIn Amount of tokens to deposit * @param minAmountOut Minimum amount of tokens to mint on Layer 2 * @param shouldWrap Whether to wrap the tokenIn before depositing * @return amountOut Amount of tokens minted on Layer 2 */ function deposit( address tokenIn, uint256 amountIn, uint256 minAmountOut, bool shouldWrap ) public payable virtual override nonReentrant whenNotPaused returns (uint256) { return super.deposit(tokenIn, amountIn, minAmountOut, shouldWrap); } /** * @notice Quote gas cost for withdrawal messages * @param _receiver address The recipient of the withdrawal on Mainnet. * @param _amount uint256 The withdrawal amount. * @param _options bytes Additional options for the message. */ function quoteWithdraw( address _receiver, uint256 _amount, bytes calldata _options ) external view virtual returns (MessagingFee memory msgFee) { bytes memory _payload = abi.encode( Constants.MESSAGE_TYPE_WITHDRAW, _amount, _receiver ); bytes memory _combinedOptions = combineOptions(L1_EID, 0, _options); return _quote(L1_EID, _payload, _combinedOptions, false); } /** * @dev Quote the messaging fee for a sync * @param _tokenIn address Address of the input token * @param _options bytes Additional options for the message. */ function quoteSync( address _tokenIn, bytes calldata _options ) external view virtual returns (MessagingFee memory msgFee) { Token storage token = _getL2SyncPoolStorage().tokens[_tokenIn]; bytes memory _payload = abi.encode( Constants.MESSAGE_TYPE_SYNC, _tokenIn, token.unsyncedAmountIn, token.unsyncedAmountOut ); bytes memory _combinedOptions = combineOptions(L1_EID, 0, _options); return _quote(L1_EID, _payload, _combinedOptions, false); } /** * @notice Internal function to set the canPause address. * @param _address the address to check if it can pause the contract. */ function _canPause(address _address) internal view returns (bool) { return _getLiquidStakingTokenStorage().canPause[_address] || _address == owner(); } /** * @notice Function to set the canPause address. * @param _address the address to check if it can pause the contract. */ function setCanPause(address _address, bool _allowed) external onlyOwner { _getLiquidStakingTokenStorage().canPause[_address] = _allowed; } /** * @notice Check if an address can pause the contract. * @param _address the address to check if it can pause the contract. */ function canPause(address _address) external view returns (bool) { return _canPause(_address); } /** * @notice Pause SyncPool deposits and withdrawals. */ function pause() external onlyCanPause { _pause(); } /** * @notice Unpause SyncPool deposits and withdrawals. */ function unpause() external onlyCanPause { _unpause(); } /** * @notice Set the rebase fee. * @param _rebaseFee uint256 Rebase fee. */ function setRebaseFee(uint256 _rebaseFee) external onlyOwner { if (_rebaseFee > Constants.MAX_REBASE_FEE) revert Errors.InvalidFee(); _getLiquidStakingTokenStorage().rebaseFee = _rebaseFee; } /** * @notice Set the rebase fee. * @param _syncDepositFee uint256 Rebase fee. */ function setSyncDepositFee(uint256 _syncDepositFee) external onlyOwner { if (_syncDepositFee > Constants.MAX_DEPOSIT_FEE) revert Errors.InvalidFee(); _getLiquidStakingTokenStorage().syncDepositFee = _syncDepositFee; } /** * @notice Set the treasury address. * @param _treasury address Treasury address. */ function setTreasury(address _treasury) external onlyOwner { _setTreasury(_treasury); } /** * @notice Set the Wrapped Liquid Staked Token address. * @param _wLST address Wrapped Liquid Staked Token address. */ function setWrappedLST(address _wLST) external onlyOwner { if (_wLST == address(0)) revert Errors.ZeroAddress(); _getLiquidStakingTokenStorage().wLST = _wLST; } /** * @return the total amount (in wei) of Pirex Ether controlled by the protocol. */ function totalAssets() public view returns (uint256) { return _totalAssets(); } /** * @return The treasury address that receives the treasury fee. */ function treasury() public view returns (address) { return _getLiquidStakingTokenStorage().treasury; } /** * @return The rebase fee that is charged on each rebase. */ function rebaseFee() public view returns (uint256) { return _getLiquidStakingTokenStorage().rebaseFee; } /** * @return The sync deposit fee that is charged on each sync pool L2 deposit. */ function syncDepositFee() public view returns (uint256) { return _getLiquidStakingTokenStorage().syncDepositFee; } /** * @return The last assets per share value. */ function lastAssetsPerShare() public view returns (uint256) { return _getLiquidStakingTokenStorage().lastAssetsPerShare; } /** * @param idx uint256 Sync index * @return Pending amount. */ function syncIndexPendingAmount( uint256 idx ) external view returns (uint256) { return _getLiquidStakingTokenStorage().syncIndexPendingAmount[idx]; } /** * @notice Returns the current sync indexes. * @return lastPendingSyncIndex The last pending sync index. * @return lastCompletedSyncIndex The last completed sync index. */ function syncIndexes() external view returns (uint256 lastPendingSyncIndex, uint256 lastCompletedSyncIndex) { return ( _getLiquidStakingTokenStorage().lastPendingSyncIndex, _getLiquidStakingTokenStorage().lastCompletedSyncIndex ); } /** * @return The total staked amount. */ function totalStaked() external view returns (uint256) { return _getLiquidStakingTokenStorage().totalStaked; } /** * @param includeUnsynced bool Include unsynced pending deposit. * @return The total amount (in wei) of pending deposit. */ function pendingDeposit( bool includeUnsynced ) public view returns (uint256) { L2TokenStorage storage $ = _getLiquidStakingTokenStorage(); return $.syncedPendingDeposit + (includeUnsynced ? $.unsyncedPendingDeposit : 0); } /** * @return the total amount (in wei) of Pirex Ether controlled by the protocol. */ function _totalAssets() internal view override returns (uint256) { L2TokenStorage storage $ = _getLiquidStakingTokenStorage(); return $.totalStaked + $.unsyncedPendingDeposit + $.syncedPendingDeposit; } /** * @notice Set the treasury address. * @param _treasury address Treasury address. */ function _setTreasury(address _treasury) internal { if (_treasury == address(0)) revert Errors.ZeroAddress(); _getLiquidStakingTokenStorage().treasury = _treasury; } /** * @notice Update the total staked amount. * @param _assetsPerShare uint256 The assets per share value. */ function _updateTotalStaked(uint256 _assetsPerShare) internal { L2TokenStorage storage $ = _getLiquidStakingTokenStorage(); uint256 _lastAssetsPerShare = $.lastAssetsPerShare; uint256 _totalStaked = $.totalStaked; if (_lastAssetsPerShare > 0) _totalStaked.mulDivDown(_assetsPerShare, _lastAssetsPerShare); $.lastAssetsPerShare = _assetsPerShare; } /** * @notice Withdraw from the pending deposit. * @param _withdrawAmount uint256 The amount to withdraw. * @return The remaining amount to withdraw from total staked. */ function _withdrawPendingDeposit( uint256 _withdrawAmount ) internal returns (uint256) { L2TokenStorage storage $ = _getLiquidStakingTokenStorage(); uint256 lastPendingIndex = $.lastPendingSyncIndex; uint256 lastCompletedIndex = $.lastCompletedSyncIndex; uint256 remaining = _withdrawAmount; for (uint256 i = lastCompletedIndex + 1; i <= lastPendingIndex; i++) { uint256 pendingAmount = $.syncIndexPendingAmount[i]; if (pendingAmount > remaining) { $.syncIndexPendingAmount[i] -= remaining; remaining = 0; break; } remaining -= pendingAmount; $.syncIndexPendingAmount[i] = 0; $.lastCompletedSyncIndex++; } $.syncedPendingDeposit -= (_withdrawAmount - remaining); return remaining; } /** * @notice Update the sync queue. * @param _syncedIds bytes The last synced ids. * @return The staked amount. */ function _updateSyncQueue( bytes32[] memory _syncedIds ) internal returns (uint256) { L2TokenStorage storage $ = _getLiquidStakingTokenStorage(); uint256 staked; uint256 index; uint256 pendingAmount; uint256 syncIdsLen = _syncedIds.length; uint256 lastPendingIndex = $.lastPendingSyncIndex; uint256 lastCompletedIndex = $.lastCompletedSyncIndex; for (uint256 i; i < syncIdsLen; i++) { index = $.syncIdIndex[_syncedIds[i]]; pendingAmount = $.syncIndexPendingAmount[index]; if (pendingAmount > 0) { $.syncIndexPendingAmount[index] = 0; staked += pendingAmount; } } // update last completed index uint256 startIndex = lastCompletedIndex + 1; uint256 maxSyncIndex = syncIdsLen + lastCompletedIndex > lastPendingIndex ? lastPendingIndex : syncIdsLen + lastCompletedIndex; for (uint256 i = startIndex; i <= maxSyncIndex; i++) { if ($.syncIndexPendingAmount[i] > 0) { $.lastCompletedSyncIndex = i - 1; break; } if (i == maxSyncIndex && $.syncIndexPendingAmount[i] == 0) { $.lastCompletedSyncIndex = i; } } return staked; } /** * @dev Internal function to sync tokens to L1 * This will send an additional message to the messenger contract after the LZ message * This message will contain the ETH that the LZ message anticipates to receive * @param _l2TokenIn Address of the token on Layer 2 * @param _l1TokenIn Address of the token on Layer 1 * @param _amountIn Amount of tokens deposited on Layer 2 * @param _amountOut Amount of tokens minted on Layer 2 * @param _totalAmountIn Total amount of tokens deposited on Layer 2 * @param _extraOptions Extra options for the messaging protocol * @param _fee Messaging fee * @return receipt Messaging receipt */ function _sync( address _l2TokenIn, address _l1TokenIn, uint256 _amountIn, uint256 _amountOut, uint256 _totalAmountIn, bytes calldata _extraOptions, MessagingFee calldata _fee ) internal virtual override nonReentrant whenNotPaused returns (MessagingReceipt memory) { // send fast sync message MessagingReceipt memory receipt = _lzSend( L1_EID, abi.encode( Constants.MESSAGE_TYPE_SYNC, _l1TokenIn, _amountIn, _amountOut ), combineOptions(L1_EID, 0, _extraOptions), MessagingFee(_fee.nativeFee, 0), payable(msg.sender) ); _addToSyncQueue(receipt, _amountOut); bytes memory data = abi.encode( endpoint.eid(), receipt.guid, _l1TokenIn, _amountIn, _amountOut ); // send slow sync message _sendSlowSyncMessage(_l2TokenIn, _amountIn, _fee.nativeFee, data); L2TokenStorage storage $ = _getLiquidStakingTokenStorage(); uint256 unsyncedShares = $.unsyncedShares; uint256 syncedShares = _totalAmountIn == _amountIn ? unsyncedShares : unsyncedShares.mulDivDown(_amountIn, _totalAmountIn); IRateLimiter(getRateLimiter()).updateRateLimit( address(this), Constants.ETH_ADDRESS, syncedShares, 0 ); $.unsyncedShares -= syncedShares; return receipt; } /** * @dev Internal function to send tokenOut to an account * @param _account Address of the account * @param _amount Amount of tokens to send * @param shouldWrap bool Whether to wrap the tokens before sending */ function _sendTokenOut( address _account, uint256 _amount, bool shouldWrap ) internal override { L2TokenStorage storage $ = _getLiquidStakingTokenStorage(); uint256 assetsPerShare = IRateProvider(getL2ExchangeRateProvider()) .getAssetsPerShare(); if (shouldWrap) { _mint(address(this), assetsPerShare, _amount); _approve(address(this), $.wLST, _amount, false); uint256 wAmount = IWrappedLiquidStakedToken($.wLST).wrap(_amount); IWrappedLiquidStakedToken($.wLST).transfer(_account, wAmount); } else { _mint(_account, assetsPerShare, _amount); } } /** * @dev Internal function to send a slow sync message * This function should be overridden to send a slow sync message to the L1 receiver contract * @param _l2TokenIn Address of the token on Layer 2 * @param _amountIn Amount of tokens deposited on Layer 2 * @param _fastSyncNativeFee The amount of ETH already used as native fee in the fast sync * @param _message Message to send */ function _sendSlowSyncMessage( address _l2TokenIn, uint256 _amountIn, uint256 _fastSyncNativeFee, bytes memory _message ) internal virtual; /** * @dev Internal function to get the minimum gas limit * This function should be overridden to set a minimum gas limit to forward during the execution of the message * by the L1 receiver contract. This is mostly needed if the underlying contract have some try/catch mechanism * as this could be abused by gas-griefing attacks. * @return minGasLimit Minimum gas limit */ function _minGasLimit() internal view virtual returns (uint32) { return 0; } /** * @notice Set the last received nonce for the specified source endpoint and sender. * @dev this should be used to fix the nonce if there's a problem in the execution of a particular message. * @param _srcEid Source endpoint ID. * @param _sender Sender's address in bytes32 format. * @param _nonce The nonce to be set. */ function setNonce( uint32 _srcEid, bytes32 _sender, uint64 _nonce ) external onlyOwner { _getLiquidStakingTokenStorage().receivedNonce[_srcEid][ _sender ] = _nonce; } /** * @dev Public function to get the next expected nonce for a given source endpoint and sender. * @param _srcEid Source endpoint ID. * @param _sender Sender's address in bytes32 format. * @return uint64 Next expected nonce. */ function nextNonce( uint32 _srcEid, bytes32 _sender ) public view override returns (uint64) { return _getLiquidStakingTokenStorage().receivedNonce[_srcEid][_sender] + 1; } /** * @dev Internal function to accept nonce from the specified source endpoint and sender. * @param _srcEid Source endpoint ID. * @param _sender Sender's address in bytes32 format. * @param _nonce The nonce to be accepted. */ function _acceptNonce( uint32 _srcEid, bytes32 _sender, uint64 _nonce ) internal { L2TokenStorage storage $ = _getLiquidStakingTokenStorage(); if (_nonce != $.receivedNonce[_srcEid][_sender] + 1) revert Errors.InvalidNonce(); $.receivedNonce[_srcEid][_sender] += 1; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; library MsgCodec { // Offset constants for decoding messages uint256 private constant MESSAGE_TYPE_OFFSET = 32; uint256 private constant COMPOSE_TYPE_OFFSET = 64; uint256 private constant COMPOSE_RECEIVER_OFFSET = 32; /** * @dev Retrieves the message type from the message. * @param _msg The message. * @return The message type. */ function messageType(bytes calldata _msg) internal pure returns (uint8) { return abi.decode(_msg[:MESSAGE_TYPE_OFFSET], (uint8)); } /** * @dev Retrieve the relavant parameters from the message. * @param _msg The message. * @return msgType The message type. * @return amount The amount. * @return assetsPerShare The assets per share. * @return receiver The token receiver. * @return syncedIds The synced IDs. */ function decodeL1Msg( bytes calldata _msg ) internal pure returns ( uint8 msgType, uint256 amount, uint256 assetsPerShare, address receiver, bytes32[] memory syncedIds ) { (, uint256 composeMsgLen) = isComposed(_msg); (msgType, amount, assetsPerShare, receiver, syncedIds) = abi.decode( _msg[COMPOSE_TYPE_OFFSET:_msg.length - composeMsgLen], (uint8, uint256, uint256, address, bytes32[]) ); } /** * @dev Retrieve the relavant parameters from the sync message. * @param _msg The message. * @return token The deposited token. * @return amountIn The amount in. * @return amountOut The amount out. */ function decodeSync( bytes calldata _msg ) internal pure returns (address token, uint256 amountIn, uint256 amountOut) { (token, amountIn, amountOut) = abi.decode( _msg[MESSAGE_TYPE_OFFSET:], (address, uint256, uint256) ); } /** * @dev Retrieve the relavant parameters from the withdraw message. * @param _msg The message. * @return amount The amount. * @return receiver The receiver address. */ function decodeWithdraw( bytes calldata _msg ) internal pure returns (uint256 amount, address receiver) { (amount, receiver) = abi.decode( _msg[MESSAGE_TYPE_OFFSET:], (uint256, address) ); } /** * @dev Retrieve the compose message. * @param _payload The LayerZero msg payload. * @return The compose message. */ function composeMsg( bytes calldata _payload ) internal pure returns (bytes memory) { (bool composed, uint256 composeMsgLen) = isComposed(_payload); uint256 payloadLen = _payload.length; return composed ? _payload[COMPOSE_RECEIVER_OFFSET + payloadLen - composeMsgLen:] : new bytes(0); } /** * @dev Check if the message is composed. * @param _payload The LayerZero msg payload. * @return Boolean if paylaod is composed and the length of the compose message. */ function isComposed( bytes calldata _payload ) internal pure returns (bool, uint256) { (bool isCompose, uint256 composeMsgLen) = abi.decode( _payload[:COMPOSE_TYPE_OFFSET], (bool, uint256) ); return (isCompose, composeMsgLen); } /** * @dev Encode the message. * @param _msg The message. * @param _composeMsg The compose message. * @return The encoded message. */ function encode( bytes memory _msg, bytes memory _composeMsg ) internal pure returns (bytes memory) { uint256 composeMsgLen = _composeMsg.length; bool isCompose = composeMsgLen != 0; return abi.encodePacked( abi.encode(isCompose, composeMsgLen), _msg, _composeMsg ); } /** * @dev Encode the compose message receiver. * The compose message must reserve its first 32 bytes for the receiver. * @param _payload The LayerZero msg payload. * @return The receiver address. */ function composeTo( bytes calldata _payload ) internal pure returns (address) { (, uint256 composeMsgLen) = isComposed(_payload); uint256 payloadLen = _payload.length; uint256 start = payloadLen - composeMsgLen; uint256 end = start + 32; return address(uint160(uint256(bytes32(_payload[start:end])))); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import { ILayerZeroReceiver, Origin } from "contracts/vendor/layerzero/protocol/interfaces/ILayerZeroReceiver.sol"; interface IOAppReceiver is ILayerZeroReceiver { /** * @notice Retrieves the address responsible for 'sending' composeMsg's to the Endpoint. * @return sender The address responsible for 'sending' composeMsg's to the Endpoint. * * @dev Applications can optionally choose to implement a separate composeMsg sender that is NOT the bridging layer. * @dev The default sender IS the OApp implementer. */ function composeMsgSender() external view returns (address sender); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; library OFTComposeMsgCodec { // Offset constants for decoding composed messages uint8 private constant NONCE_OFFSET = 8; uint8 private constant SRC_EID_OFFSET = 12; uint8 private constant AMOUNT_LD_OFFSET = 44; uint8 private constant COMPOSE_FROM_OFFSET = 76; /** * @dev Encodes a OFT composed message. * @param _nonce The nonce value. * @param _srcEid The source endpoint ID. * @param _amountLD The amount in local decimals. * @param _composeMsg The composed message. * @return _msg The encoded Composed message. */ function encode( uint64 _nonce, uint32 _srcEid, uint256 _amountLD, bytes memory _composeMsg // 0x[composeFrom][composeMsg] ) internal pure returns (bytes memory _msg) { _msg = abi.encodePacked(_nonce, _srcEid, _amountLD, _composeMsg); } /** * @dev Retrieves the nonce from the composed message. * @param _msg The message. * @return The nonce value. */ function nonce(bytes calldata _msg) internal pure returns (uint64) { return uint64(bytes8(_msg[:NONCE_OFFSET])); } /** * @dev Retrieves the source endpoint ID from the composed message. * @param _msg The message. * @return The source endpoint ID. */ function srcEid(bytes calldata _msg) internal pure returns (uint32) { return uint32(bytes4(_msg[NONCE_OFFSET:SRC_EID_OFFSET])); } /** * @dev Retrieves the amount in local decimals from the composed message. * @param _msg The message. * @return The amount in local decimals. */ function amountLD(bytes calldata _msg) internal pure returns (uint256) { return uint256(bytes32(_msg[SRC_EID_OFFSET:AMOUNT_LD_OFFSET])); } /** * @dev Retrieves the composeFrom value from the composed message. * @param _msg The message. * @return The composeFrom value. */ function composeFrom(bytes calldata _msg) internal pure returns (bytes32) { return bytes32(_msg[AMOUNT_LD_OFFSET:COMPOSE_FROM_OFFSET]); } /** * @dev Retrieves the composed message. * @param _msg The message. * @return The composed message. */ function composeMsg(bytes calldata _msg) internal pure returns (bytes memory) { return _msg[COMPOSE_FROM_OFFSET:]; } /** * @dev Converts an address to bytes32. * @param _addr The address to convert. * @return The bytes32 representation of the address. */ function addressToBytes32(address _addr) internal pure returns (bytes32) { return bytes32(uint256(uint160(_addr))); } /** * @dev Converts bytes32 to an address. * @param _b The bytes32 value to convert. * @return The address representation of bytes32. */ function bytes32ToAddress(bytes32 _b) internal pure returns (address) { return address(uint160(uint256(_b))); } }
// SPDX-License-Identifier: LZBL-1.2 pragma solidity ^0.8.20; import {SafeERC20, IERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {MessagingFee, MessagingReceipt} from "./vendor/layerzero/protocol/interfaces/ILayerZeroEndpointV2.sol"; import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import {IL2ExchangeRateProvider} from "./vendor/layerzero/syncpools/interfaces/IL2ExchangeRateProvider.sol"; import {IRateLimiter} from "./vendor/layerzero/syncpools/interfaces/IRateLimiter.sol"; import {IBridgeQuoter} from "./interfaces/IBridgeQuoter.sol"; import {Constants} from "./libraries/Constants.sol"; import {Errors} from "./libraries/Errors.sol"; /** * @title L2 Base Sync Pool * @dev Base contract for Layer 2 sync pools * A sync pool is an OApp that allows users to deposit tokens on Layer 2, and then sync them to Layer 1 * The L2 sync pool takes care of deposits on the L2 and syncing to the L1 using the L1 sync pool. * Once enough tokens have been deposited, anyone can trigger a sync to Layer 1. */ abstract contract L2SyncPool is OwnableUpgradeable { struct L2SyncPoolStorage { /** * @notice The address of the exchange rate provider contract. * @dev This variable holds the address of the exchange rate provider contract, which is used to get the conversion rate. */ IL2ExchangeRateProvider l2ExchangeRateProvider; /** * @notice The address of the rate limiter contract. * @dev This variable holds the address of the rate limiter contract, which is used to limit mint and withdrawal. */ IRateLimiter rateLimiter; /** * @notice The address of the bridge quoter contract. * @dev This variable holds the address of the bridge quoter contract, which is used to get the min amount receive when bridging to L1. */ IBridgeQuoter bridgeQuoter; /** * @notice The token data. * @dev This mapping holds the token data, which includes the amount of tokens deposited and minted, and the minimum amount required to sync. */ mapping(address => Token) tokens; /** * @notice The sync keeper. * @dev This mapping holds the sync keepers, which are allowed to trigger a sync to Layer 1. */ mapping(address => bool) syncKeeper; } /** * @dev Token data * @param unsyncedAmountIn Amount of tokens deposited on Layer 2 * @param unsyncedAmountOut Amount of tokens minted on Layer 2 * @param minSyncAmount Minimum amount of tokens required to sync * @param maxSyncAmount Maximum amount of tokens required to sync * @param l1Address Address of the token on Layer 1, address(0) is unauthorized */ struct Token { uint256 unsyncedAmountIn; uint256 unsyncedAmountOut; uint256 minSyncAmount; uint256 maxSyncAmount; address l1Address; } // keccak256(abi.encode(uint256(keccak256(syncpools.storage.l2syncpool)) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant L2SyncPoolStorageLocation = 0xc064a301e926254981c9bd3b3225923d097271573deb3cc61ae7f6a144f10a00; function _getL2SyncPoolStorage() internal pure returns (L2SyncPoolStorage storage $) { assembly { $.slot := L2SyncPoolStorageLocation } } event L2ExchangeRateProviderSet(address l2ExchangeRateProvider); event RateLimiterSet(address rateLimiter); event MinSyncAmountSet(address tokenIn, uint256 minSyncAmount); event MaxSyncAmountSet(address tokenIn, uint256 maxSyncAmount); event L1TokenInSet(address tokenIn, address l1TokenIn); event Deposit(address indexed tokenIn, uint256 amountIn, uint256 amountOut); event Sync(address indexed tokenIn, uint256 amountIn, uint256 amountOut); event SyncKeeperSet(address syncKeeper, bool status); event BridgeQuoterSet(address bridgeQuoter); /** * @dev Modifier to allow only the sync keeper to call the function */ modifier onlySyncKeeper() { if (!_getL2SyncPoolStorage().syncKeeper[msg.sender]) { revert Errors.UnauthorizedCaller(); } _; } /** * @dev Initialize the L2 Base Sync Pool * @param l2ExchangeRateProvider Address of the exchange rate provider * @param rateLimiter Address of the rate limiter * @param bridgeQuoter Address of the bridge quoter */ function __L2BaseSyncPool_init( address l2ExchangeRateProvider, address rateLimiter, address bridgeQuoter ) internal { __L2BaseSyncPool_init_unchained( l2ExchangeRateProvider, rateLimiter, bridgeQuoter ); } function __L2BaseSyncPool_init_unchained( address l2ExchangeRateProvider, address rateLimiter, address bridgeQuoter ) internal { _setL2ExchangeRateProvider(l2ExchangeRateProvider); _setRateLimiter(rateLimiter); _setBridgeQuoter(bridgeQuoter); } /** * @dev Get the exchange rate provider * @return l2ExchangeRateProvider Address of the exchange rate provider */ function getL2ExchangeRateProvider() public view virtual returns (address) { L2SyncPoolStorage storage $ = _getL2SyncPoolStorage(); return address($.l2ExchangeRateProvider); } /** * @dev Get the rate limiter * @return rateLimiter Address of the rate limiter */ function getRateLimiter() public view virtual returns (address) { L2SyncPoolStorage storage $ = _getL2SyncPoolStorage(); return address($.rateLimiter); } /** * @dev Get token data * If the l1Address is address(0), the token is unauthorized * @param tokenIn Address of the token * @return token Token data */ function getTokenData( address tokenIn ) public view virtual returns (Token memory) { L2SyncPoolStorage storage $ = _getL2SyncPoolStorage(); return $.tokens[tokenIn]; } /** * @dev Check if the address is a sync keeper * @param syncKeeper Address of the sync keeper * @return status True if the address is a sync keeper */ function isSyncKeeper( address syncKeeper ) public view virtual returns (bool) { return _getL2SyncPoolStorage().syncKeeper[syncKeeper]; } /** * @notice Deposit tokens on Layer 2 * This will mint tokenOut on Layer 2 using the exchange rate for tokenIn to tokenOut. * The amount deposited and minted will be stored in the token data which can be synced to Layer 1. * @param tokenIn Address of the token * @param amountIn Amount of tokens to deposit * @param minAmountOut Minimum amount of tokens to mint on Layer 2 * @param shouldWrap True if the token should be wrapped * @return amountOut Amount of tokens minted on Layer 2 */ function deposit( address tokenIn, uint256 amountIn, uint256 minAmountOut, bool shouldWrap ) public payable virtual returns (uint256 amountOut) { amountOut = _deposit(tokenIn, amountIn, minAmountOut); _sendTokenOut(msg.sender, amountOut, shouldWrap); } /** * @dev Deposit tokens on Layer 2 * This will mint tokenOut on Layer 2 using the exchange rate for tokenIn to tokenOut. * The amount deposited and minted will be stored in the token data which can be synced to Layer 1. * Will revert if: * - The amountIn is zero * - The token is unauthorized (that is, the l1Address is address(0)) * - The amountOut is less than the minAmountOut * @param tokenIn Address of the token * @param amountIn Amount of tokens to deposit * @param minAmountOut Minimum amount of tokens to mint on Layer 2 * @return amountOut Amount of tokens minted on Layer 2 */ function _deposit( address tokenIn, uint256 amountIn, uint256 minAmountOut ) internal virtual returns (uint256 amountOut) { if (amountIn == 0) revert Errors.ZeroAmount(); L2SyncPoolStorage storage $ = _getL2SyncPoolStorage(); Token storage token = $.tokens[tokenIn]; if (token.l1Address == address(0)) revert Errors.UnauthorizedToken(); uint256 amountReceived = amountIn; if (tokenIn != Constants.ETH_ADDRESS) { // get the actual amount sent and the expected amount received after bridging (amountIn, amountReceived) = $.bridgeQuoter.getAmountOut( tokenIn, amountIn ); // as only WETH deposits are allowed, the amount received should be greater than the amount sent // otherwise, therer might be some temporary pool imbalance if (amountReceived > amountIn) revert Errors.InvalidRate(); } amountOut = $.l2ExchangeRateProvider.getPostFeeAmount( tokenIn, amountReceived ); if (amountOut < minAmountOut) revert Errors.InsufficientAmountOut(); emit Deposit(tokenIn, amountIn, minAmountOut); _receiveTokenIn(tokenIn, amountIn); token.unsyncedAmountIn += amountIn; if ( token.maxSyncAmount != 0 && token.unsyncedAmountIn > token.maxSyncAmount ) { revert Errors.MaxSyncAmountExceeded(); } token.unsyncedAmountOut += amountOut; } /** * @dev Sync tokens to Layer 1 * This will send a message to the destination endpoint with the token data to * sync the tokens minted on Layer 2 to Layer 1. * Will revert if: * - The token is unauthorized (that is, the l1Address is address(0)) * - The amount to sync is zero or less than the minSyncAmount * @dev It is very important to listen for the Sync event to know when and how much tokens were synced * especially if an action is required on another chain (for example, executing the message). If an action * was required but was not executed, the tokens won't be sent to the L1. * @param tokenIn Address of the token * @param extraOptions Extra options for the messaging protocol * @param fee Fast sync messaging fee, does not consider token bridge fees * @return unsyncedAmountIn Amount of tokens deposited on Layer 2 * @return unsyncedAmountOut Amount of tokens minted on Layer 2 */ function sync( address tokenIn, bytes calldata extraOptions, MessagingFee calldata fee ) public payable virtual onlySyncKeeper returns (uint256 unsyncedAmountIn, uint256 unsyncedAmountOut) { L2SyncPoolStorage storage $ = _getL2SyncPoolStorage(); Token storage token = $.tokens[tokenIn]; address l1TokenIn = token.l1Address; if (l1TokenIn == address(0)) revert Errors.UnauthorizedToken(); unsyncedAmountIn = token.unsyncedAmountIn; unsyncedAmountOut = token.unsyncedAmountOut; if (unsyncedAmountIn == 0 || unsyncedAmountIn < token.minSyncAmount) { revert Errors.InsufficientAmountToSync(); } token.unsyncedAmountIn = 0; token.unsyncedAmountOut = 0; emit Sync(tokenIn, unsyncedAmountIn, unsyncedAmountOut); _sync( tokenIn, l1TokenIn, unsyncedAmountIn, unsyncedAmountOut, unsyncedAmountIn, extraOptions, fee ); return (unsyncedAmountIn, unsyncedAmountOut); } /** * @dev Sync tokens to Layer 1 * This will send a message to the destination endpoint with the token data to * sync the tokens minted on Layer 2 to Layer 1. * Will revert if: * - The token is unauthorized (that is, the l1Address is address(0)) * - The amount to sync is zero or less than the minSyncAmount * @dev It is very important to listen for the Sync event to know when and how much tokens were synced * especially if an action is required on another chain (for example, executing the message). If an action * was required but was not executed, the tokens won't be sent to the L1. * @param tokenIn Address of the token * @param amount Amount of tokens to sync * @param extraOptions Extra options for the messaging protocol * @param fee Fast sync messaging fee, does not consider token bridge fees * @return syncedAmountIn Amount of synced tokens deposited on Layer 2 * @return syncedAmountOut Amount of synced tokens minted on Layer 2 */ function sync( address tokenIn, uint256 amount, bytes calldata extraOptions, MessagingFee calldata fee ) public payable virtual onlySyncKeeper returns (uint256, uint256) { L2SyncPoolStorage storage $ = _getL2SyncPoolStorage(); Token storage token = $.tokens[tokenIn]; if (token.l1Address == address(0)) revert Errors.UnauthorizedToken(); uint256 unsyncedAmountIn = token.unsyncedAmountIn; if ( unsyncedAmountIn == 0 || unsyncedAmountIn < token.minSyncAmount || amount > unsyncedAmountIn ) { revert Errors.InsufficientAmountToSync(); } // Reduce unsyncedAmountOut proportionally to unsyncedAmountIn uint256 amountOut = (token.unsyncedAmountOut * amount) / unsyncedAmountIn; token.unsyncedAmountIn -= amount; token.unsyncedAmountOut -= amountOut; emit Sync(tokenIn, amount, amountOut); _sync( tokenIn, token.l1Address, amount, amountOut, unsyncedAmountIn, extraOptions, fee ); return (amount, amountOut); } /** * @dev Set the exchange rate provider * @param l2ExchangeRateProvider Address of the exchange rate provider */ function setL2ExchangeRateProvider( address l2ExchangeRateProvider ) public virtual onlyOwner { _setL2ExchangeRateProvider(l2ExchangeRateProvider); } /** * @dev Set the rate limiter * @param rateLimiter Address of the rate limiter */ function setRateLimiter(address rateLimiter) public virtual onlyOwner { _setRateLimiter(rateLimiter); } /** * @dev Set the minimum amount of tokens required to sync * @param tokenIn Address of the token * @param minSyncAmount Minimum amount of tokens required to sync */ function setMinSyncAmount( address tokenIn, uint256 minSyncAmount ) public virtual onlyOwner { if (minSyncAmount == 0) revert Errors.ZeroAmount(); L2SyncPoolStorage storage $ = _getL2SyncPoolStorage(); $.tokens[tokenIn].minSyncAmount = minSyncAmount; emit MinSyncAmountSet(tokenIn, minSyncAmount); } /** * @dev Set the maximum amount of tokens to sync * @param tokenIn Address of the token * @param maxSyncAmount Maximum amount of tokens to sync */ function setMaxSyncAmount( address tokenIn, uint256 maxSyncAmount ) public virtual onlyOwner { L2SyncPoolStorage storage $ = _getL2SyncPoolStorage(); $.tokens[tokenIn].maxSyncAmount = maxSyncAmount; emit MaxSyncAmountSet(tokenIn, maxSyncAmount); } /** * @dev Set the Layer 1 address of the token * @param l2TokenIn Address of the token on Layer 2 * @param l1TokenIn Address of the token on Layer 1 */ function setL1TokenIn( address l2TokenIn, address l1TokenIn ) public virtual onlyOwner { if (l1TokenIn == address(0)) revert Errors.ZeroAddress(); L2SyncPoolStorage storage $ = _getL2SyncPoolStorage(); $.tokens[l2TokenIn].l1Address = l1TokenIn; emit L1TokenInSet(l2TokenIn, l1TokenIn); } /** * @dev Set the sync keeper * @param syncKeeper Address of the sync keeper * @param status True to set as a sync keeper */ function setSyncKeeper( address syncKeeper, bool status ) public virtual onlyOwner { _getL2SyncPoolStorage().syncKeeper[syncKeeper] = status; emit SyncKeeperSet(syncKeeper, status); } /** * @dev Set bridge quoter * @param bridgeQuoter Bridge quoter contract to get the min amount receive when bridging to L1 */ function setBridgeQuoter(address bridgeQuoter) public virtual onlyOwner { _setBridgeQuoter(bridgeQuoter); } /** * @dev Internal function to set bridge quoter * @param bridgeQuoter Bridge quoter contract */ function _setBridgeQuoter(address bridgeQuoter) internal { _getL2SyncPoolStorage().bridgeQuoter = IBridgeQuoter(bridgeQuoter); emit BridgeQuoterSet(bridgeQuoter); } /** * @dev Internal function to set the exchange rate provider * @param l2ExchangeRateProvider Address of the exchange rate provider */ function _setL2ExchangeRateProvider( address l2ExchangeRateProvider ) internal virtual { if (l2ExchangeRateProvider == address(0)) revert Errors.ZeroAddress(); L2SyncPoolStorage storage $ = _getL2SyncPoolStorage(); $.l2ExchangeRateProvider = IL2ExchangeRateProvider( l2ExchangeRateProvider ); emit L2ExchangeRateProviderSet(l2ExchangeRateProvider); } /** * @dev Internal function to set the rate limiter * @param rateLimiter Address of the rate limiter */ function _setRateLimiter(address rateLimiter) internal virtual { if (rateLimiter == address(0)) revert Errors.ZeroAddress(); L2SyncPoolStorage storage $ = _getL2SyncPoolStorage(); $.rateLimiter = IRateLimiter(rateLimiter); emit RateLimiterSet(rateLimiter); } /** * @dev Internal function to receive tokens on Layer 2 * @param tokenIn Address of the token * @param amountIn Amount of tokens to receive */ function _receiveTokenIn( address tokenIn, uint256 amountIn ) internal virtual { if (tokenIn == Constants.ETH_ADDRESS) { if (amountIn != msg.value) revert Errors.InvalidAmountIn(); } else { if (msg.value != 0) revert Errors.InvalidAmountIn(); // warning: not safe with transfer tax tokens SafeERC20.safeTransferFrom( IERC20(tokenIn), msg.sender, address(this), amountIn ); } } /** * @dev Internal function to sync tokens to Layer 1 * @param l2TokenIn Address of the token on Layer 2 * @param l1TokenIn Address of the token on Layer 1 * @param amountIn Amount of tokens deposited on Layer 2 * @param amountOut Amount of tokens minted on Layer 2 * @param totalAmountIn Total amount of tokens deposited on Layer 2 * @param extraOptions Extra options for the messaging protocol * @param fee Messaging fee * @return receipt Messaging receipt */ function _sync( address l2TokenIn, address l1TokenIn, uint256 amountIn, uint256 amountOut, uint256 totalAmountIn, bytes calldata extraOptions, MessagingFee calldata fee ) internal virtual returns (MessagingReceipt memory); /** * @dev Internal function to send tokenOut to an account * @param account Address of the account * @param amount Amount of tokens to send * @param shouldWrap True if the token should be wrapped */ function _sendTokenOut( address account, uint256 amount, bool shouldWrap ) internal virtual; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.25; import {ERC20PermitUpgradeable, Initializable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PermitUpgradeable.sol"; import {FixedPointMathLib} from "solmate/src/utils/FixedPointMathLib.sol"; import {Errors} from "./libraries/Errors.sol"; /** * @title Interest-bearing ERC20-like token for L2LiquidStakingToken assets. * * This contract is abstract. To make the contract deployable override the * `_totalAssets` function. `L2LiquidStakingToken.sol` contract inherits DineroERC20Rebase and defines * the `_totalAssets` function. * * DineroERC20Rebase balances are dynamic and represent the holder's share in the total amount * of Pirex assets controlled by the protocol. Account shares aren't normalized, so the * contract also stores the sum of all shares to calculate each account's token balance * which equals to: * * shares[account] * _totalAssets() / totalShares * * For example, assume that we have: * * _totalAssets() -> 10 ETH * sharesOf(user1) -> 100 * sharesOf(user2) -> 400 * * Therefore: * * balanceOf(user1) -> 2 tokens which corresponds 2 ETH * balanceOf(user2) -> 8 tokens which corresponds 8 ETH * * Since balances of all token holders change when the amount of total pooled assets * changes, this token cannot fully implement ERC20 standard: it only emits `Transfer` * events upon explicit transfer between holders. In contrast, when total amount of * pooled assets increases, no `Transfer` events are generated: doing so would require * emitting an event for each token holder and thus running an unbounded loop. */ abstract contract DineroERC20RebaseUpgradeable is Initializable, ERC20PermitUpgradeable { /** * @dev Library: FixedPointMathLib - Provides fixed-point arithmetic for uint256. */ using FixedPointMathLib for uint256; /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ /** * @notice An executed shares transfer from `sender` to `recipient`. * * @dev emitted in pair with an ERC20-defined `Transfer` event. */ event TransferShares( address indexed from, address indexed to, uint256 sharesValue ); /** * @notice An executed `burnShares` request * * @dev Reports simultaneously burnt shares amount * and corresponding DineroERC20Rebase amount. * The DineroERC20Rebase amount is calculated twice: before and after the burning incurred rebase. * * @param account holder of the burnt shares * @param preRebaseTokenAmount amount of DineroERC20Rebase the burnt shares corresponded to before the burn * @param postRebaseTokenAmount amount of DineroERC20Rebase the burnt shares corresponded to after the burn * @param sharesAmount amount of burnt shares */ event SharesBurnt( address indexed account, uint256 preRebaseTokenAmount, uint256 postRebaseTokenAmount, uint256 sharesAmount ); /*////////////////////////////////////////////////////////////// ERC20 REBASE STORAGE //////////////////////////////////////////////////////////////*/ /// @custom:storage-location erc7201:redacted.storage.DineroERC20Rebase struct DineroERC20RebaseStorage { /** * @notice Total amount of shares in existence. * * @dev The sum of all accounts' shares can be an arbitrary number, therefore * it is necessary to store it in order to calculate each account's relative share. */ uint256 totalShares; /** * @dev DineroERC20Rebase balances are dynamic and are calculated based on the accounts' shares * and the total amount of assets controlled by the protocol. Account shares aren't * normalized, so the contract also stores the sum of all shares to calculate * each account's token balance which equals to: * * shares[account] * _totalAssets() / totalShares() */ mapping(address => uint256) shares; } // keccak256(abi.encode(uint256(keccak256(redacted.storage.DineroERC20Rebase)) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant DineroERC20RebaseStorageLocation = 0xddf967707f52bbdea6c202114c491d81e6de0cb9ded430e88a276a6f8d3e3800; function _getDineroERC20RebaseStorage() private pure returns (DineroERC20RebaseStorage storage $) { assembly { $.slot := DineroERC20RebaseStorageLocation } } /*////////////////////////////////////////////////////////////// INITIALIZER //////////////////////////////////////////////////////////////*/ function __DineroERC20Rebase_init( string memory name_, string memory symbol_ ) internal onlyInitializing { // Set decoded values for name and symbol. __ERC20_init_unchained(name_, symbol_); // Set the name for EIP-712 signature. __ERC20Permit_init(name_); } /*////////////////////////////////////////////////////////////// ERC20 OVERRIDES //////////////////////////////////////////////////////////////*/ /** * @return the amount of tokens in existence. * * @dev Always equals to `_totalAssets()` since token amount * is pegged to the total amount of assets controlled by the protocol. */ function totalSupply() public view override returns (uint256) { return _totalAssets(); } /** * @return the amount of tokens owned by the `_account`. * * @dev Balances are dynamic and equal the `_account`'s share in the amount of the * total assets controlled by the protocol. See `sharesOf`. */ function balanceOf( address _account ) public view override returns (uint256) { return convertToAssets(_sharesOf(_account), true); } /** * @notice Moves `_amount` tokens from `_sender` to `_recipient`. * Emits a `Transfer` event. * Emits a `TransferShares` event. */ function _update( address _sender, address _recipient, uint256 _amount ) internal override { uint256 sharesToTransfer = convertToShares(_amount); if (sharesToTransfer == 0) revert Errors.InvalidAmount(); _transferShares(_sender, _recipient, sharesToTransfer); _emitTransferEvents(_sender, _recipient, _amount, sharesToTransfer); } /*////////////////////////////////////////////////////////////// ERC20 REBASE FUNCTIONS //////////////////////////////////////////////////////////////*/ /** * @notice Moves `_shares` token shares from the caller's account to the `_recipient` account. * * @return amount of transferred tokens. * Emits a `TransferShares` event. * Emits a `Transfer` event. * * Requirements: * * - `_recipient` cannot be the zero address. * - the caller must have at least `_shares` shares. * - the contract must not be paused. * * @dev The `_shares` argument is the amount of shares, not tokens. */ function transferShares( address _recipient, uint256 _shares ) external returns (uint256) { _transferShares(msg.sender, _recipient, _shares); uint256 assets = convertToAssets(_shares, true); _emitTransferEvents(msg.sender, _recipient, assets, _shares); return assets; } /** * @notice Moves `_shares` token shares from the `_sender` account to the `_recipient` account. * * @return amount of transferred tokens. * Emits a `TransferShares` event. * Emits a `Transfer` event. * * Requirements: * * - `_sender` and `_recipient` cannot be the zero addresses. * - `_sender` must have at least `_shares` shares. * - the caller must have allowance for `_sender`'s tokens of at least `getPooledPxEthByShares(_shares)`. * - the contract must not be paused. * * @dev The `_shares` argument is the amount of shares, not tokens. */ function transferSharesFrom( address _sender, address _recipient, uint256 _shares ) external returns (uint256) { uint256 assets = convertToAssets(_shares, false); _spendAllowance(_sender, msg.sender, assets); _transferShares(_sender, _recipient, _shares); _emitTransferEvents(_sender, _recipient, assets, _shares); return assets; } /** * @return the amount of shares owned by `_account`. */ function getTotalShares() public view returns (uint256) { return _getDineroERC20RebaseStorage().totalShares; } /** * @return the amount of shares owned by `_account`. */ function sharesOf(address _account) external view returns (uint256) { return _sharesOf(_account); } /** * @return the amount of assets that corresponds to `_shares` token shares. * @param floor if true, the result is rounded down, otherwise it's rounded up. */ function convertToAssets( uint256 _shares, bool floor ) public view returns (uint256) { uint256 totalShares = _getDineroERC20RebaseStorage().totalShares; return totalShares == 0 ? 0 : floor ? _shares.mulDivDown(_totalAssets(), totalShares) : _shares.mulDivUp(_totalAssets(), totalShares); } /** * @return the amount of shares that corresponds to `_assets` (pxEth). */ function convertToShares(uint256 _assets) public view returns (uint256) { return _convertToShares(_assets, true); } /** * @return the amount of shares that corresponds to `_assets` (pxEth) rounding up. */ function previewWithdraw(uint256 _assets) public view returns (uint256) { return _convertToShares(_assets, false); } /*////////////////////////////////////////////////////////////// INTERNAL LOGIC //////////////////////////////////////////////////////////////*/ /** * @return the total amount (in wei) of Pirex assets controlled by the protocol. * @dev This is used for calculating tokens from shares and vice versa. * @dev This function is required to be implemented in a derived contract. */ function _totalAssets() internal view virtual returns (uint256); /** * @return the amount of shares owned by `_account`. */ function _sharesOf(address _account) internal view returns (uint256) { return _getDineroERC20RebaseStorage().shares[_account]; } /** * @notice Moves `_shares` shares from `_sender` to `_recipient`. * * Requirements: * * - `_sender` cannot be the zero address. * - `_recipient` cannot be the zero address or the `DineroERC20Rebase` token contract itself * - `_sender` must hold at least `_shares` shares. * - the contract must not be paused. */ function _transferShares( address _sender, address _recipient, uint256 _shares ) internal { if (_sender == address(0) || _recipient == address(0)) revert Errors.ZeroAddress(); if (_recipient == address(this) || _sender == _recipient) revert Errors.NotAllowed(); DineroERC20RebaseStorage storage $ = _getDineroERC20RebaseStorage(); uint256 currentSenderShares = $.shares[_sender]; if (_shares > currentSenderShares) revert Errors.InvalidAmount(); $.shares[_sender] = currentSenderShares - _shares; $.shares[_recipient] += _shares; } /** * @notice Creates `_shares` shares and assigns them to `_recipient`, increasing the total amount of shares. * @dev This doesn't increase the token total supply. * * NB: The method doesn't check protocol pause relying on the external enforcement. * * Requirements: * * - `_recipient` cannot be the zero address. * - the contract must not be paused. */ function _mintShares( address _recipient, uint256 _shares ) internal returns (uint256) { if (_recipient == address(0)) revert Errors.ZeroAddress(); DineroERC20RebaseStorage storage $ = _getDineroERC20RebaseStorage(); $.totalShares += _shares; $.shares[_recipient] = $.shares[_recipient] + _shares; return $.totalShares; // Notice: we're not emitting a Transfer event from the zero address here since shares mint // works by taking the amount of tokens corresponding to the minted shares from all other // token holders, proportionally to their share. The total supply of the token doesn't change // as the result. This is equivalent to performing a send from each other token holder's // address to `address`, but we cannot reflect this as it would require sending an unbounded // number of events. } /** * @notice Destroys `_shares` shares from `_account`'s holdings, decreasing the total amount of shares. * @dev This doesn't decrease the token total supply. * * Requirements: * * - `_account` cannot be the zero address. * - `_account` must hold at least `_shares` shares. * - the contract must not be paused. */ function _burnShares( address _account, uint256 _shares ) internal returns (uint256) { if (_account == address(0)) revert Errors.ZeroAddress(); DineroERC20RebaseStorage storage $ = _getDineroERC20RebaseStorage(); uint256 accountShares = $.shares[_account]; if (_shares > accountShares) revert Errors.InvalidAmount(); uint256 preRebaseTokenAmount = convertToAssets(_shares, true); $.totalShares -= _shares; $.shares[_account] = accountShares - _shares; uint256 postRebaseTokenAmount = convertToAssets(_shares, true); emit SharesBurnt( _account, preRebaseTokenAmount, postRebaseTokenAmount, _shares ); return $.totalShares; // Notice: we're not emitting a Transfer event to the zero address here since shares burn // works by redistributing the amount of tokens corresponding to the burned shares between // all other token holders. The total supply of the token doesn't change as the result. // This is equivalent to performing a send from `address` to each other token holder address, // but we cannot reflect this as it would require sending an unbounded number of events. // We're emitting `SharesBurnt` event to provide an explicit rebase log record nonetheless. } /** * @dev Emits {Transfer} and {TransferShares} events */ function _emitTransferEvents( address _from, address _to, uint256 _assets, uint256 _shares ) internal { emit Transfer(_from, _to, _assets); emit TransferShares(_from, _to, _shares); } /** * @dev Converts `_assets` (pxEth) to shares. * * @param _assets amount of assets to convert to shares. * @param floor if true, the result is rounded down, otherwise it's rounded up. */ function _convertToShares( uint256 _assets, bool floor ) internal view returns (uint256) { uint256 totalShares = _getDineroERC20RebaseStorage().totalShares; uint256 totalPooledPxEth = _totalAssets(); if (totalPooledPxEth == 0) return 0; return floor ? _assets.mulDivDown(totalShares, totalPooledPxEth) : _assets.mulDivUp(totalShares, totalPooledPxEth); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.25; /** * @title Constants * @notice Library containing various constants for the L2LiquidStakingToken system. * @author redactedcartel.finance */ library Constants { /** * @notice Message type constant for deposit. * @dev This constant defines the message type for deposit operations. */ uint8 constant MESSAGE_TYPE_DEPOSIT = 1; /** * @notice Message type constant for deposit. * @dev This constant defines the message type for deposit operations. */ uint8 constant MESSAGE_TYPE_DEPOSIT_WRAP = 2; /** * @notice Message type constant for withdrawal. * @dev This constant defines the message type for withdrawal operations. */ uint8 constant MESSAGE_TYPE_WITHDRAW = 3; /** * @notice Message type constant for rebase. * @dev This constant defines the message type for rebase operations. */ uint8 constant MESSAGE_TYPE_REBASE = 4; /** * @notice Message type constant for sync. * @dev This constant defines the message type for sync operations. */ uint8 constant MESSAGE_TYPE_SYNC = 5; /** * @notice The destination endpoint ID for Mainnet. * @dev This constant holds the destination endpoint ID for Mainnet. */ uint32 constant MAINNET_EID = 30101; /** * @notice Fee denominator for precise fee calculations. * @dev This constant holds the fee denominator for precise fee calculations. */ uint256 constant FEE_DENOMINATOR = 1_000_000; /** * @notice Max rebase fee. * @dev This constant holds the maximum rebase fee that can be set. */ uint256 constant MAX_REBASE_FEE = 200_000; /** * @notice Max deposit fee. * @dev This constant holds the maximum sync deposit fee that can be set. */ uint256 constant MAX_DEPOSIT_FEE = 200_000; /** * @dev The address of the ETH token. */ address constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.25; library Errors { /** * @dev Zero address specified */ error ZeroAddress(); /** * @dev Zero amount specified */ error ZeroAmount(); /** * @dev Invalid fee specified */ error InvalidFee(); /** * @dev not same as deposit size */ error InvalidAmount(); /** * @dev Invalid nonce */ error InvalidNonce(); /** * @dev not allowed */ error NotAllowed(); /** * @dev Only ETH allowed */ error OnlyETH(); /** * @dev Invalid rate */ error InvalidRate(); /** * @dev Withdraw limit exceeded */ error WithdrawLimitExceeded(); /** * @dev Unauthorized caller on SyncPool */ error UnauthorizedCaller(); /** * @dev Native transfer failed on SyncPool */ error NativeTransferFailed(); /** * @dev Insufficient amount out */ error InsufficientAmountOut(); /** * @dev Insufficient amount to sync */ error InsufficientAmountToSync(); /** * @dev Unauthorized token */ error UnauthorizedToken(); /** * @dev Invalid amount in */ error InvalidAmountIn(); /** * @dev Max sync amount exceeded, to prevent going over the bridge limit */ error MaxSyncAmountExceeded(); /** * @dev Unsupported destination chain */ error UnsupportedEid(); /** * @dev Multichain eposits can't be wrapped */ error MultichainDepositsCannotBeWrapped(); /** * @dev OFT lockbox not set for multichain deposit */ error OFTLockboxNotSet(); /** * @dev Invalid receiver address */ error InvalidReceiver(); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {IL2ExchangeRateProvider} from "contracts/vendor/layerzero/syncpools/interfaces/IL2ExchangeRateProvider.sol"; interface IRateProvider is IL2ExchangeRateProvider { function getConversionAmount( address tokenIn, uint256 amountIn ) external returns (uint256 amountOut); function getAssetsPerShare() external returns (uint256 assetsPerShare); }
//SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IWrappedLiquidStakedToken { function wrap(uint256 _amount) external returns (uint256); function unwrap(uint256 _amount) external returns (uint256); function getLSTAddress() external view returns (address); function transfer(address recipient, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import { SafeERC20, IERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { MessagingParams, MessagingFee, MessagingReceipt } from "contracts/vendor/layerzero/protocol/interfaces/ILayerZeroEndpointV2.sol"; import { OAppCoreUpgradeable } from "./OAppCoreUpgradeable.sol"; /** * @title OAppSender * @dev Abstract contract implementing the OAppSender functionality for sending messages to a LayerZero endpoint. */ abstract contract OAppSenderUpgradeable is OAppCoreUpgradeable { using SafeERC20 for IERC20; // Custom error messages error NotEnoughNative(uint256 msgValue); error LzTokenUnavailable(); // @dev The version of the OAppSender implementation. // @dev Version is bumped when changes are made to this contract. uint64 internal constant SENDER_VERSION = 1; /** * @dev Ownable is not initialized here on purpose. It should be initialized in the child contract to * accommodate the different version of Ownable. */ function __OAppSender_init() internal onlyInitializing {} function __OAppSender_init_unchained() internal onlyInitializing {} /** * @notice Retrieves the OApp version information. * @return senderVersion The version of the OAppSender.sol contract. * @return receiverVersion The version of the OAppReceiver.sol contract. * * @dev Providing 0 as the default for OAppReceiver version. Indicates that the OAppReceiver is not implemented. * ie. this is a SEND only OApp. * @dev If the OApp uses both OAppSender and OAppReceiver, then this needs to be override returning the correct versions */ function oAppVersion() public view virtual returns (uint64 senderVersion, uint64 receiverVersion) { return (SENDER_VERSION, 0); } /** * @dev Internal function to interact with the LayerZero EndpointV2.quote() for fee calculation. * @param _dstEid The destination endpoint ID. * @param _message The message payload. * @param _options Additional options for the message. * @param _payInLzToken Flag indicating whether to pay the fee in LZ tokens. * @return fee The calculated MessagingFee for the message. * - nativeFee: The native fee for the message. * - lzTokenFee: The LZ token fee for the message. */ function _quote( uint32 _dstEid, bytes memory _message, bytes memory _options, bool _payInLzToken ) internal view virtual returns (MessagingFee memory fee) { return endpoint.quote( MessagingParams(_dstEid, _getPeerOrRevert(_dstEid), _message, _options, _payInLzToken), address(this) ); } /** * @dev Internal function to interact with the LayerZero EndpointV2.send() for sending a message. * @param _dstEid The destination endpoint ID. * @param _message The message payload. * @param _options Additional options for the message. * @param _fee The calculated LayerZero fee for the message. * - nativeFee: The native fee. * - lzTokenFee: The lzToken fee. * @param _refundAddress The address to receive any excess fee values sent to the endpoint. * @return receipt The receipt for the sent message. * - guid: The unique identifier for the sent message. * - nonce: The nonce of the sent message. * - fee: The LayerZero fee incurred for the message. */ function _lzSend( uint32 _dstEid, bytes memory _message, bytes memory _options, MessagingFee memory _fee, address _refundAddress ) internal virtual returns (MessagingReceipt memory receipt) { // @dev Push corresponding fees to the endpoint, any excess is sent back to the _refundAddress from the endpoint. uint256 messageValue = _payNative(_fee.nativeFee); if (_fee.lzTokenFee > 0) _payLzToken(_fee.lzTokenFee); return endpoint.send{ value: messageValue }( // solhint-disable-next-line check-send-result MessagingParams(_dstEid, _getPeerOrRevert(_dstEid), _message, _options, _fee.lzTokenFee > 0), _refundAddress ); } /** * @dev Internal function to pay the native fee associated with the message. * @param _nativeFee The native fee to be paid. * @return nativeFee The amount of native currency paid. * * @dev If the OApp needs to initiate MULTIPLE LayerZero messages in a single transaction, * this will need to be overridden because msg.value would contain multiple lzFees. * @dev Should be overridden in the event the LayerZero endpoint requires a different native currency. * @dev Some EVMs use an ERC20 as a method for paying transactions/gasFees. * @dev The endpoint is EITHER/OR, ie. it will NOT support both types of native payment at a time. */ function _payNative(uint256 _nativeFee) internal virtual returns (uint256 nativeFee) { if (msg.value != _nativeFee) revert NotEnoughNative(msg.value); return _nativeFee; } /** * @dev Internal function to pay the LZ token fee associated with the message. * @param _lzTokenFee The LZ token fee to be paid. * * @dev If the caller is trying to pay in the specified lzToken, then the lzTokenFee is passed to the endpoint. * @dev Any excess sent, is passed back to the specified _refundAddress in the _lzSend(). */ function _payLzToken(uint256 _lzTokenFee) internal virtual { // @dev Cannot cache the token because it is not immutable in the endpoint. address lzToken = endpoint.lzToken(); if (lzToken == address(0)) revert LzTokenUnavailable(); // Pay LZ token fee by sending tokens to the endpoint. IERC20(lzToken).safeTransferFrom(msg.sender, address(endpoint), _lzTokenFee); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; // @dev Import the 'MessagingFee' and 'MessagingReceipt' so it's exposed to OApp implementers // solhint-disable-next-line no-unused-import import { OAppSenderUpgradeable, MessagingFee, MessagingReceipt } from "./OAppSenderUpgradeable.sol"; // @dev Import the 'Origin' so it's exposed to OApp implementers // solhint-disable-next-line no-unused-import import { OAppReceiverUpgradeable, Origin } from "./OAppReceiverUpgradeable.sol"; import { OAppCoreUpgradeable } from "./OAppCoreUpgradeable.sol"; /** * @title OApp * @dev Abstract contract serving as the base for OApp implementation, combining OAppSender and OAppReceiver functionality. */ abstract contract OAppUpgradeable is OAppSenderUpgradeable, OAppReceiverUpgradeable { /** * @dev Constructor to initialize the OApp with the provided endpoint and owner. * @param _endpoint The address of the LOCAL LayerZero endpoint. */ /// @custom:oz-upgrades-unsafe-allow constructor constructor(address _endpoint) OAppCoreUpgradeable(_endpoint) {} /** * @dev Initializes the OApp with the provided delegate. * @param _delegate The delegate capable of making OApp configurations inside of the endpoint. * * @dev The delegate typically should be set as the owner of the contract. * @dev Ownable is not initialized here on purpose. It should be initialized in the child contract to * accommodate the different version of Ownable. */ function __OApp_init(address _delegate) internal onlyInitializing { __OAppCore_init(_delegate); } function __OApp_init_unchained() internal onlyInitializing {} /** * @notice Retrieves the OApp version information. * @return senderVersion The version of the OAppSender.sol implementation. * @return receiverVersion The version of the OAppReceiver.sol implementation. */ function oAppVersion() public pure virtual override(OAppSenderUpgradeable, OAppReceiverUpgradeable) returns (uint64 senderVersion, uint64 receiverVersion) { return (SENDER_VERSION, RECEIVER_VERSION); } }
// SPDX-License-Identifier: LZBL-1.2 pragma solidity ^0.8.20; interface IRateLimiter { function updateRateLimit(address sender, address tokenIn, uint256 amountIn, uint256 amountOut) external; }
// SPDX-License-Identifier: LZBL-1.2 pragma solidity ^0.8.20; import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; /** * @title Base Messenger * @dev Base contract for setting the messenger contract */ abstract contract BaseMessengerUpgradeable is OwnableUpgradeable { struct BaseMessengerStorage { address messenger; } // keccak256(abi.encode(uint256(keccak256(syncpools.storage.basemessenger)) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant BaseMessengerStorageLocation = 0x2d365d82646798ae645c4baa2dc2ee228626f61d8b5395bf298ba125a3c6b100; function _getBaseMessengerStorage() internal pure returns (BaseMessengerStorage storage $) { assembly { $.slot := BaseMessengerStorageLocation } } event MessengerSet(address messenger); function __BaseMessenger_init(address messenger) internal onlyInitializing { __BaseMessenger_init_unchained(messenger); } function __BaseMessenger_init_unchained(address messenger) internal onlyInitializing { _setMessenger(messenger); } /** * @dev Get the messenger address * @return The messenger address */ function getMessenger() public view virtual returns (address) { BaseMessengerStorage storage $ = _getBaseMessengerStorage(); return $.messenger; } /** * @dev Set the messenger address * @param messenger The messenger address */ function setMessenger(address messenger) public virtual onlyOwner { _setMessenger(messenger); } /** * @dev Internal function to set the messenger address * @param messenger The messenger address */ function _setMessenger(address messenger) internal { BaseMessengerStorage storage $ = _getBaseMessengerStorage(); $.messenger = messenger; emit MessengerSet(messenger); } }
// SPDX-License-Identifier: LZBL-1.2 pragma solidity ^0.8.20; import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; /** * @title Base Receiver * @dev Base contract for setting the receiver contract */ abstract contract BaseReceiverUpgradeable is OwnableUpgradeable { struct BaseReceiverStorage { address receiver; } // keccak256(abi.encode(uint256(keccak256(syncpools.storage.basereceiver)) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant BaseReceiverStorageLocation = 0x487698e326934c06370ca3c28e3bca79fe27d578048e9d42af7fa98f2e481e00; function _getBaseReceiverStorage() internal pure returns (BaseReceiverStorage storage $) { assembly { $.slot := BaseReceiverStorageLocation } } event ReceiverSet(address receiver); function __BaseReceiver_init(address receiver) internal onlyInitializing { __BaseReceiver_init_unchained(receiver); } function __BaseReceiver_init_unchained(address receiver) internal onlyInitializing { _setReceiver(receiver); } /** * @dev Get the receiver address * @return The receiver address */ function getReceiver() public view virtual returns (address) { BaseReceiverStorage storage $ = _getBaseReceiverStorage(); return $.receiver; } /** * @dev Set the receiver address * @param receiver The receiver address */ function setReceiver(address receiver) public virtual onlyOwner { _setReceiver(receiver); } /** * @dev Internal function to set the receiver address * @param receiver The receiver address */ function _setReceiver(address receiver) internal { BaseReceiverStorage storage $ = _getBaseReceiverStorage(); $.receiver = receiver; emit ReceiverSet(receiver); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import { IOAppOptionsType3, EnforcedOptionParam } from "../interfaces/IOAppOptionsType3.sol"; /** * @title OAppOptionsType3 * @dev Abstract contract implementing the IOAppOptionsType3 interface with type 3 options. */ abstract contract OAppOptionsType3Upgradeable is IOAppOptionsType3, OwnableUpgradeable { struct OAppOptionsType3Storage { // @dev The "msgType" should be defined in the child contract. mapping(uint32 => mapping(uint16 => bytes)) enforcedOptions; } // keccak256(abi.encode(uint256(keccak256("layerzerov2.storage.oappoptionstype3")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant OAppOptionsType3StorageLocation = 0x8d2bda5d9f6ffb5796910376005392955773acee5548d0fcdb10e7c264ea0000; uint16 internal constant OPTION_TYPE_3 = 3; function _getOAppOptionsType3Storage() internal pure returns (OAppOptionsType3Storage storage $) { assembly { $.slot := OAppOptionsType3StorageLocation } } /** * @dev Ownable is not initialized here on purpose. It should be initialized in the child contract to * accommodate the different version of Ownable. */ function __OAppOptionsType3_init() internal onlyInitializing {} function __OAppOptionsType3_init_unchained() internal onlyInitializing {} function enforcedOptions(uint32 _eid, uint16 _msgType) public view returns (bytes memory) { OAppOptionsType3Storage storage $ = _getOAppOptionsType3Storage(); return $.enforcedOptions[_eid][_msgType]; } /** * @dev Sets the enforced options for specific endpoint and message type combinations. * @param _enforcedOptions An array of EnforcedOptionParam structures specifying enforced options. * * @dev Only the owner/admin of the OApp can call this function. * @dev Provides a way for the OApp to enforce things like paying for PreCrime, AND/OR minimum dst lzReceive gas amounts etc. * @dev These enforced options can vary as the potential options/execution on the remote may differ as per the msgType. * eg. Amount of lzReceive() gas necessary to deliver a lzCompose() message adds overhead you dont want to pay * if you are only making a standard LayerZero message ie. lzReceive() WITHOUT sendCompose(). */ function setEnforcedOptions(EnforcedOptionParam[] calldata _enforcedOptions) public virtual onlyOwner { OAppOptionsType3Storage storage $ = _getOAppOptionsType3Storage(); for (uint256 i = 0; i < _enforcedOptions.length; i++) { // @dev Enforced options are only available for optionType 3, as type 1 and 2 dont support combining. _assertOptionsType3(_enforcedOptions[i].options); $.enforcedOptions[_enforcedOptions[i].eid][_enforcedOptions[i].msgType] = _enforcedOptions[i].options; } emit EnforcedOptionSet(_enforcedOptions); } /** * @notice Combines options for a given endpoint and message type. * @param _eid The endpoint ID. * @param _msgType The OAPP message type. * @param _extraOptions Additional options passed by the caller. * @return options The combination of caller specified options AND enforced options. * * @dev If there is an enforced lzReceive option: * - {gasLimit: 200k, msg.value: 1 ether} AND a caller supplies a lzReceive option: {gasLimit: 100k, msg.value: 0.5 ether} * - The resulting options will be {gasLimit: 300k, msg.value: 1.5 ether} when the message is executed on the remote lzReceive() function. * @dev This presence of duplicated options is handled off-chain in the verifier/executor. */ function combineOptions( uint32 _eid, uint16 _msgType, bytes calldata _extraOptions ) public view virtual returns (bytes memory) { OAppOptionsType3Storage storage $ = _getOAppOptionsType3Storage(); bytes memory enforced = $.enforcedOptions[_eid][_msgType]; // No enforced options, pass whatever the caller supplied, even if it's empty or legacy type 1/2 options. if (enforced.length == 0) return _extraOptions; // No caller options, return enforced if (_extraOptions.length == 0) return enforced; // @dev If caller provided _extraOptions, must be type 3 as its the ONLY type that can be combined. if (_extraOptions.length >= 2) { _assertOptionsType3(_extraOptions); // @dev Remove the first 2 bytes containing the type from the _extraOptions and combine with enforced. return bytes.concat(enforced, _extraOptions[2:]); } // No valid set of options was found. revert InvalidOptions(_extraOptions); } /** * @dev Internal function to assert that options are of type 3. * @param _options The options to be checked. */ function _assertOptionsType3(bytes calldata _options) internal pure virtual { uint16 optionsType = uint16(bytes2(_options[0:2])); if (optionsType != OPTION_TYPE_3) revert InvalidOptions(_options); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol) pragma solidity ^0.8.20; import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol"; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract PausableUpgradeable is Initializable, ContextUpgradeable { /// @custom:storage-location erc7201:openzeppelin.storage.Pausable struct PausableStorage { bool _paused; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Pausable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant PausableStorageLocation = 0xcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300; function _getPausableStorage() private pure returns (PausableStorage storage $) { assembly { $.slot := PausableStorageLocation } } /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); /** * @dev The operation failed because the contract is paused. */ error EnforcedPause(); /** * @dev The operation failed because the contract is not paused. */ error ExpectedPause(); /** * @dev Initializes the contract in unpaused state. */ function __Pausable_init() internal onlyInitializing { __Pausable_init_unchained(); } function __Pausable_init_unchained() internal onlyInitializing { PausableStorage storage $ = _getPausableStorage(); $._paused = false; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { _requireNotPaused(); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { _requirePaused(); _; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { PausableStorage storage $ = _getPausableStorage(); return $._paused; } /** * @dev Throws if the contract is paused. */ function _requireNotPaused() internal view virtual { if (paused()) { revert EnforcedPause(); } } /** * @dev Throws if the contract is not paused. */ function _requirePaused() internal view virtual { if (!paused()) { revert ExpectedPause(); } } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { PausableStorage storage $ = _getPausableStorage(); $._paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { PausableStorage storage $ = _getPausableStorage(); $._paused = false; emit Unpaused(_msgSender()); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol) pragma solidity ^0.8.20; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at, * consider using {ReentrancyGuardTransient} instead. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuardUpgradeable is Initializable { // 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; /// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard struct ReentrancyGuardStorage { uint256 _status; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00; function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) { assembly { $.slot := ReentrancyGuardStorageLocation } } /** * @dev Unauthorized reentrant call. */ error ReentrancyGuardReentrantCall(); function __ReentrancyGuard_init() internal onlyInitializing { __ReentrancyGuard_init_unchained(); } function __ReentrancyGuard_init_unchained() internal onlyInitializing { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); $._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 { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); // 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 { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); // 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) { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); return $._status == ENTERED; } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Arithmetic library with operations for fixed-point numbers. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol) /// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol) library FixedPointMathLib { /*////////////////////////////////////////////////////////////// SIMPLIFIED FIXED POINT OPERATIONS //////////////////////////////////////////////////////////////*/ uint256 internal constant MAX_UINT256 = 2**256 - 1; uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s. function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down. } function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up. } function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down. } function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up. } /*////////////////////////////////////////////////////////////// LOW LEVEL FIXED POINT OPERATIONS //////////////////////////////////////////////////////////////*/ function mulDivDown( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y)) if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) { revert(0, 0) } // Divide x * y by the denominator. z := div(mul(x, y), denominator) } } function mulDivUp( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y)) if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) { revert(0, 0) } // If x * y modulo the denominator is strictly greater than 0, // 1 is added to round up the division of x * y by the denominator. z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator)) } } function rpow( uint256 x, uint256 n, uint256 scalar ) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { switch x case 0 { switch n case 0 { // 0 ** 0 = 1 z := scalar } default { // 0 ** n = 0 z := 0 } } default { switch mod(n, 2) case 0 { // If n is even, store scalar in z for now. z := scalar } default { // If n is odd, store x in z for now. z := x } // Shifting right by 1 is like dividing by 2. let half := shr(1, scalar) for { // Shift n right by 1 before looping to halve it. n := shr(1, n) } n { // Shift n right by 1 each iteration to halve it. n := shr(1, n) } { // Revert immediately if x ** 2 would overflow. // Equivalent to iszero(eq(div(xx, x), x)) here. if shr(128, x) { revert(0, 0) } // Store x squared. let xx := mul(x, x) // Round to the nearest number. let xxRound := add(xx, half) // Revert if xx + half overflowed. if lt(xxRound, xx) { revert(0, 0) } // Set x to scaled xxRound. x := div(xxRound, scalar) // If n is even: if mod(n, 2) { // Compute z * x. let zx := mul(z, x) // If z * x overflowed: if iszero(eq(div(zx, x), z)) { // Revert if x is non-zero. if iszero(iszero(x)) { revert(0, 0) } } // Round to the nearest number. let zxRound := add(zx, half) // Revert if zx + half overflowed. if lt(zxRound, zx) { revert(0, 0) } // Return properly scaled zxRound. z := div(zxRound, scalar) } } } } } /*////////////////////////////////////////////////////////////// GENERAL NUMBER UTILITIES //////////////////////////////////////////////////////////////*/ function sqrt(uint256 x) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { let y := x // We start y at x, which will help us make our initial estimate. z := 181 // The "correct" value is 1, but this saves a multiplication later. // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically. // We check y >= 2^(k + 8) but shift right by k bits // each branch to ensure that if x >= 256, then y >= 256. if iszero(lt(y, 0x10000000000000000000000000000000000)) { y := shr(128, y) z := shl(64, z) } if iszero(lt(y, 0x1000000000000000000)) { y := shr(64, y) z := shl(32, z) } if iszero(lt(y, 0x10000000000)) { y := shr(32, y) z := shl(16, z) } if iszero(lt(y, 0x1000000)) { y := shr(16, y) z := shl(8, z) } // Goal was to get z*z*y within a small factor of x. More iterations could // get y in a tighter range. Currently, we will have y in [256, 256*2^16). // We ensured y >= 256 so that the relative difference between y and y+1 is small. // That's not possible if x < 256 but we can just verify those cases exhaustively. // Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256. // Correctness can be checked exhaustively for x < 256, so we assume y >= 256. // Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps. // For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range // (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256. // Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate // sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18. // There is no overflow risk here since y < 2^136 after the first branch above. z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181. // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough. z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) // If x+1 is a perfect square, the Babylonian method cycles between // floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor. // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division // Since the ceil is rare, we save gas on the assignment and repeat division in the rare case. // If you don't care whether the floor or ceil square root is returned, you can remove this statement. z := sub(z, lt(div(x, z), z)) } } function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Mod x by y. Note this will return // 0 instead of reverting if y is zero. z := mod(x, y) } } function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { // Divide x by y. Note this will return // 0 instead of reverting if y is zero. r := div(x, y) } } function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Add 1 to x * y if x % y > 0. Note this will // return 0 instead of reverting if y is zero. z := add(gt(mod(x, y), 0), div(x, y)) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; interface IBridgeQuoter { function getAmountOut( address token, uint256 amountIn ) external view returns (uint256 amountSent, uint256 amountReceived); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; import { Origin } from "./ILayerZeroEndpointV2.sol"; interface ILayerZeroReceiver { function allowInitializePath(Origin calldata _origin) external view returns (bool); function nextNonce(uint32 _eid, bytes32 _sender) external view returns (uint64); function lzReceive( Origin calldata _origin, bytes32 _guid, bytes calldata _message, address _executor, bytes calldata _extraData ) external payable; }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; import { IMessageLibManager } from "./IMessageLibManager.sol"; import { IMessagingComposer } from "./IMessagingComposer.sol"; import { IMessagingChannel } from "./IMessagingChannel.sol"; import { IMessagingContext } from "./IMessagingContext.sol"; struct MessagingParams { uint32 dstEid; bytes32 receiver; bytes message; bytes options; bool payInLzToken; } struct MessagingReceipt { bytes32 guid; uint64 nonce; MessagingFee fee; } struct MessagingFee { uint256 nativeFee; uint256 lzTokenFee; } struct Origin { uint32 srcEid; bytes32 sender; uint64 nonce; } interface ILayerZeroEndpointV2 is IMessageLibManager, IMessagingComposer, IMessagingChannel, IMessagingContext { event PacketSent(bytes encodedPayload, bytes options, address sendLibrary); event PacketVerified(Origin origin, address receiver, bytes32 payloadHash); event PacketDelivered(Origin origin, address receiver); event LzReceiveAlert( address indexed receiver, address indexed executor, Origin origin, bytes32 guid, uint256 gas, uint256 value, bytes message, bytes extraData, bytes reason ); event LzTokenSet(address token); event DelegateSet(address sender, address delegate); function quote(MessagingParams calldata _params, address _sender) external view returns (MessagingFee memory); function send( MessagingParams calldata _params, address _refundAddress ) external payable returns (MessagingReceipt memory); function verify(Origin calldata _origin, address _receiver, bytes32 _payloadHash) external; function verifiable(Origin calldata _origin, address _receiver) external view returns (bool); function initializable(Origin calldata _origin, address _receiver) external view returns (bool); function lzReceive( Origin calldata _origin, address _receiver, bytes32 _guid, bytes calldata _message, bytes calldata _extraData ) external payable; // oapp can burn messages partially by calling this function with its own business logic if messages are verified in order function clear(address _oapp, Origin calldata _origin, bytes32 _guid, bytes calldata _message) external; function setLzToken(address _lzToken) external; function lzToken() external view returns (address); function nativeToken() external view returns (address); function setDelegate(address _delegate) external; }
// SPDX-License-Identifier: LZBL-1.2 pragma solidity ^0.8.20; interface IL2ExchangeRateProvider { function getConversionAmount(address tokenIn, uint256 amountIn) external returns (uint256 amountOut); function getPostFeeAmount(address tokenIn, uint256 amountIn) external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; /** * @dev Struct representing enforced option parameters. */ struct EnforcedOptionParam { uint32 eid; // Endpoint ID uint16 msgType; // Message Type bytes options; // Additional options } /** * @title IOAppOptionsType3 * @dev Interface for the OApp with Type 3 Options, allowing the setting and combining of enforced options. */ interface IOAppOptionsType3 { // Custom error message for invalid options error InvalidOptions(bytes options); // Event emitted when enforced options are set event EnforcedOptionSet(EnforcedOptionParam[] _enforcedOptions); /** * @notice Sets enforced options for specific endpoint and message type combinations. * @param _enforcedOptions An array of EnforcedOptionParam structures specifying enforced options. */ function setEnforcedOptions(EnforcedOptionParam[] calldata _enforcedOptions) external; /** * @notice Combines options for a given endpoint and message type. * @param _eid The endpoint ID. * @param _msgType The OApp message type. * @param _extraOptions Additional options passed by the caller. * @return options The combination of caller specified options AND enforced options. */ function combineOptions( uint32 _eid, uint16 _msgType, bytes calldata _extraOptions ) external view returns (bytes memory options); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import { IOAppCore, ILayerZeroEndpointV2 } from "./interfaces/IOAppCore.sol"; /** * @title OAppCore * @dev Abstract contract implementing the IOAppCore interface with basic OApp configurations. */ abstract contract OAppCoreUpgradeable is IOAppCore, OwnableUpgradeable { struct OAppCoreStorage { mapping(uint32 => bytes32) peers; } // keccak256(abi.encode(uint256(keccak256("layerzerov2.storage.oappcore")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant OAppCoreStorageLocation = 0x72ab1bc1039b79dc4724ffca13de82c96834302d3c7e0d4252232d4b2dd8f900; function _getOAppCoreStorage() internal pure returns (OAppCoreStorage storage $) { assembly { $.slot := OAppCoreStorageLocation } } // The LayerZero endpoint associated with the given OApp /// @custom:oz-upgrades-unsafe-allow state-variable-immutable ILayerZeroEndpointV2 public immutable endpoint; /** * @dev Constructor to initialize the OAppCore with the provided endpoint and delegate. * @param _endpoint The address of the LOCAL Layer Zero endpoint. */ /// @custom:oz-upgrades-unsafe-allow constructor constructor(address _endpoint) { endpoint = ILayerZeroEndpointV2(_endpoint); } /** * @dev Initializes the OAppCore with the provided delegate. * @param _delegate The delegate capable of making OApp configurations inside of the endpoint. * * @dev The delegate typically should be set as the owner of the contract. * @dev Ownable is not initialized here on purpose. It should be initialized in the child contract to * accommodate the different version of Ownable. */ function __OAppCore_init(address _delegate) internal onlyInitializing { __OAppCore_init_unchained(_delegate); } function __OAppCore_init_unchained(address _delegate) internal onlyInitializing { if (_delegate == address(0)) revert InvalidDelegate(); endpoint.setDelegate(_delegate); } /** * @notice Returns the peer address (OApp instance) associated with a specific endpoint. * @param _eid The endpoint ID. * @return peer The address of the peer associated with the specified endpoint. */ function peers(uint32 _eid) public view override returns (bytes32) { OAppCoreStorage storage $ = _getOAppCoreStorage(); return $.peers[_eid]; } /** * @notice Sets the peer address (OApp instance) for a corresponding endpoint. * @param _eid The endpoint ID. * @param _peer The address of the peer to be associated with the corresponding endpoint. * * @dev Only the owner/admin of the OApp can call this function. * @dev Indicates that the peer is trusted to send LayerZero messages to this OApp. * @dev Set this to bytes32(0) to remove the peer address. * @dev Peer is a bytes32 to accommodate non-evm chains. */ function setPeer(uint32 _eid, bytes32 _peer) public virtual onlyOwner { OAppCoreStorage storage $ = _getOAppCoreStorage(); $.peers[_eid] = _peer; emit PeerSet(_eid, _peer); } /** * @notice Internal function to get the peer address associated with a specific endpoint; reverts if NOT set. * ie. the peer is set to bytes32(0). * @param _eid The endpoint ID. * @return peer The address of the peer associated with the specified endpoint. */ function _getPeerOrRevert(uint32 _eid) internal view virtual returns (bytes32) { OAppCoreStorage storage $ = _getOAppCoreStorage(); bytes32 peer = $.peers[_eid]; if (peer == bytes32(0)) revert NoPeer(_eid); return peer; } /** * @notice Sets the delegate address for the OApp. * @param _delegate The address of the delegate to be set. * * @dev Only the owner/admin of the OApp can call this function. * @dev Provides the ability for a delegate to set configs, on behalf of the OApp, directly on the Endpoint contract. */ function setDelegate(address _delegate) public onlyOwner { endpoint.setDelegate(_delegate); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import { IOAppReceiver, Origin } from "./interfaces/IOAppReceiver.sol"; import { OAppCoreUpgradeable } from "./OAppCoreUpgradeable.sol"; /** * @title OAppReceiver * @dev Abstract contract implementing the ILayerZeroReceiver interface and extending OAppCore for OApp receivers. */ abstract contract OAppReceiverUpgradeable is IOAppReceiver, OAppCoreUpgradeable { // Custom error message for when the caller is not the registered endpoint/ error OnlyEndpoint(address addr); // @dev The version of the OAppReceiver implementation. // @dev Version is bumped when changes are made to this contract. uint64 internal constant RECEIVER_VERSION = 1; /** * @dev Ownable is not initialized here on purpose. It should be initialized in the child contract to * accommodate the different version of Ownable. */ function __OAppReceiver_init() internal onlyInitializing {} function __OAppReceiver_init_unchained() internal onlyInitializing {} /** * @notice Retrieves the OApp version information. * @return senderVersion The version of the OAppSender.sol contract. * @return receiverVersion The version of the OAppReceiver.sol contract. * * @dev Providing 0 as the default for OAppSender version. Indicates that the OAppSender is not implemented. * ie. this is a RECEIVE only OApp. * @dev If the OApp uses both OAppSender and OAppReceiver, then this needs to be override returning the correct versions. */ function oAppVersion() public view virtual returns (uint64 senderVersion, uint64 receiverVersion) { return (0, RECEIVER_VERSION); } /** * @notice Retrieves the address responsible for 'sending' composeMsg's to the Endpoint. * @return sender The address responsible for 'sending' composeMsg's to the Endpoint. * * @dev Applications can optionally choose to implement a separate composeMsg sender that is NOT the bridging layer. * @dev The default sender IS the OApp implementer. */ function composeMsgSender() public view virtual returns (address sender) { return address(this); } /** * @notice Checks if the path initialization is allowed based on the provided origin. * @param origin The origin information containing the source endpoint and sender address. * @return Whether the path has been initialized. * * @dev This indicates to the endpoint that the OApp has enabled msgs for this particular path to be received. * @dev This defaults to assuming if a peer has been set, its initialized. * Can be overridden by the OApp if there is other logic to determine this. */ function allowInitializePath(Origin calldata origin) public view virtual returns (bool) { return peers(origin.srcEid) == origin.sender; } /** * @notice Retrieves the next nonce for a given source endpoint and sender address. * @dev _srcEid The source endpoint ID. * @dev _sender The sender address. * @return nonce The next nonce. * * @dev The path nonce starts from 1. If 0 is returned it means that there is NO nonce ordered enforcement. * @dev Is required by the off-chain executor to determine the OApp expects msg execution is ordered. * @dev This is also enforced by the OApp. * @dev By default this is NOT enabled. ie. nextNonce is hardcoded to return 0. */ function nextNonce(uint32, /*_srcEid*/ bytes32 /*_sender*/) public view virtual returns (uint64 nonce) { return 0; } /** * @dev Entry point for receiving messages or packets from the endpoint. * @param _origin The origin information containing the source endpoint and sender address. * - srcEid: The source chain endpoint ID. * - sender: The sender address on the src chain. * - nonce: The nonce of the message. * @param _guid The unique identifier for the received LayerZero message. * @param _message The payload of the received message. * @param _executor The address of the executor for the received message. * @param _extraData Additional arbitrary data provided by the corresponding executor. * * @dev Entry point for receiving msg/packet from the LayerZero endpoint. */ function lzReceive( Origin calldata _origin, bytes32 _guid, bytes calldata _message, address _executor, bytes calldata _extraData ) public payable virtual { // Ensures that only the endpoint can attempt to lzReceive() messages to this OApp. if (address(endpoint) != msg.sender) revert OnlyEndpoint(msg.sender); // Ensure that the sender matches the expected peer for the source endpoint. if (_getPeerOrRevert(_origin.srcEid) != _origin.sender) revert OnlyPeer(_origin.srcEid, _origin.sender); // Call the internal OApp implementation of lzReceive. _lzReceive(_origin, _guid, _message, _executor, _extraData); } /** * @dev Internal function to implement lzReceive logic without needing to copy the basic parameter validation. */ function _lzReceive( Origin calldata _origin, bytes32 _guid, bytes calldata _message, address _executor, bytes calldata _extraData ) internal virtual; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) pragma solidity ^0.8.20; import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol"; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * The initial owner is set to the address provided by the deployer. This can * later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { /// @custom:storage-location erc7201:openzeppelin.storage.Ownable struct OwnableStorage { address _owner; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300; function _getOwnableStorage() private pure returns (OwnableStorage storage $) { assembly { $.slot := OwnableStorageLocation } } /** * @dev The caller account is not authorized to perform an operation. */ error OwnableUnauthorizedAccount(address account); /** * @dev The owner is not a valid owner account. (eg. `address(0)`) */ error OwnableInvalidOwner(address owner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the address provided by the deployer as the initial owner. */ function __Ownable_init(address initialOwner) internal onlyInitializing { __Ownable_init_unchained(initialOwner); } function __Ownable_init_unchained(address initialOwner) internal onlyInitializing { if (initialOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(initialOwner); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { OwnableStorage storage $ = _getOwnableStorage(); return $._owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { if (owner() != _msgSender()) { revert OwnableUnauthorizedAccount(_msgSender()); } } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { if (newOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { OwnableStorage storage $ = _getOwnableStorage(); address oldOwner = $._owner; $._owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/ERC20Permit.sol) pragma solidity ^0.8.20; import {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol"; import {ERC20Upgradeable} from "../ERC20Upgradeable.sol"; import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import {EIP712Upgradeable} from "../../../utils/cryptography/EIP712Upgradeable.sol"; import {NoncesUpgradeable} from "../../../utils/NoncesUpgradeable.sol"; import {Initializable} from "../../../proxy/utils/Initializable.sol"; /** * @dev Implementation of the ERC-20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[ERC-2612]. * * Adds the {permit} method, which can be used to change an account's ERC-20 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. */ abstract contract ERC20PermitUpgradeable is Initializable, ERC20Upgradeable, IERC20Permit, EIP712Upgradeable, NoncesUpgradeable { bytes32 private constant PERMIT_TYPEHASH = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); /** * @dev Permit deadline has expired. */ error ERC2612ExpiredSignature(uint256 deadline); /** * @dev Mismatched signature. */ error ERC2612InvalidSigner(address signer, address owner); /** * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`. * * It's a good idea to use the same `name` that is defined as the ERC-20 token name. */ function __ERC20Permit_init(string memory name) internal onlyInitializing { __EIP712_init_unchained(name, "1"); } function __ERC20Permit_init_unchained(string memory) internal onlyInitializing {} /** * @inheritdoc IERC20Permit */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual { if (block.timestamp > deadline) { revert ERC2612ExpiredSignature(deadline); } bytes32 structHash = keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline)); bytes32 hash = _hashTypedDataV4(structHash); address signer = ECDSA.recover(hash, v, r, s); if (signer != owner) { revert ERC2612InvalidSigner(signer, owner); } _approve(owner, spender, value); } /** * @inheritdoc IERC20Permit */ function nonces(address owner) public view virtual override(IERC20Permit, NoncesUpgradeable) returns (uint256) { return super.nonces(owner); } /** * @inheritdoc IERC20Permit */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view virtual returns (bytes32) { return _domainSeparatorV4(); } }
// 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: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// 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: MIT pragma solidity >=0.8.0; struct SetConfigParam { uint32 eid; uint32 configType; bytes config; } interface IMessageLibManager { struct Timeout { address lib; uint256 expiry; } event LibraryRegistered(address newLib); event DefaultSendLibrarySet(uint32 eid, address newLib); event DefaultReceiveLibrarySet(uint32 eid, address newLib); event DefaultReceiveLibraryTimeoutSet(uint32 eid, address oldLib, uint256 expiry); event SendLibrarySet(address sender, uint32 eid, address newLib); event ReceiveLibrarySet(address receiver, uint32 eid, address newLib); event ReceiveLibraryTimeoutSet(address receiver, uint32 eid, address oldLib, uint256 timeout); function registerLibrary(address _lib) external; function isRegisteredLibrary(address _lib) external view returns (bool); function getRegisteredLibraries() external view returns (address[] memory); function setDefaultSendLibrary(uint32 _eid, address _newLib) external; function defaultSendLibrary(uint32 _eid) external view returns (address); function setDefaultReceiveLibrary(uint32 _eid, address _newLib, uint256 _timeout) external; function defaultReceiveLibrary(uint32 _eid) external view returns (address); function setDefaultReceiveLibraryTimeout(uint32 _eid, address _lib, uint256 _expiry) external; function defaultReceiveLibraryTimeout(uint32 _eid) external view returns (address lib, uint256 expiry); function isSupportedEid(uint32 _eid) external view returns (bool); function isValidReceiveLibrary(address _receiver, uint32 _eid, address _lib) external view returns (bool); /// ------------------- OApp interfaces ------------------- function setSendLibrary(address _oapp, uint32 _eid, address _newLib) external; function getSendLibrary(address _sender, uint32 _eid) external view returns (address lib); function isDefaultSendLibrary(address _sender, uint32 _eid) external view returns (bool); function setReceiveLibrary(address _oapp, uint32 _eid, address _newLib, uint256 _gracePeriod) external; function getReceiveLibrary(address _receiver, uint32 _eid) external view returns (address lib, bool isDefault); function setReceiveLibraryTimeout(address _oapp, uint32 _eid, address _lib, uint256 _gracePeriod) external; function receiveLibraryTimeout(address _receiver, uint32 _eid) external view returns (address lib, uint256 expiry); function setConfig(address _oapp, address _lib, SetConfigParam[] calldata _params) external; function getConfig( address _oapp, address _lib, uint32 _eid, uint32 _configType ) external view returns (bytes memory config); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; interface IMessagingComposer { event ComposeSent(address from, address to, bytes32 guid, uint16 index, bytes message); event ComposeDelivered(address from, address to, bytes32 guid, uint16 index); event LzComposeAlert( address indexed from, address indexed to, address indexed executor, bytes32 guid, uint16 index, uint256 gas, uint256 value, bytes message, bytes extraData, bytes reason ); function composeQueue( address _from, address _to, bytes32 _guid, uint16 _index ) external view returns (bytes32 messageHash); function sendCompose(address _to, bytes32 _guid, uint16 _index, bytes calldata _message) external; function lzCompose( address _from, address _to, bytes32 _guid, uint16 _index, bytes calldata _message, bytes calldata _extraData ) external payable; }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; interface IMessagingContext { function isSendingMessage() external view returns (bool); function getSendContext() external view returns (uint32 dstEid, address sender); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; interface IMessagingChannel { event InboundNonceSkipped(uint32 srcEid, bytes32 sender, address receiver, uint64 nonce); event PacketNilified(uint32 srcEid, bytes32 sender, address receiver, uint64 nonce, bytes32 payloadHash); event PacketBurnt(uint32 srcEid, bytes32 sender, address receiver, uint64 nonce, bytes32 payloadHash); function eid() external view returns (uint32); // this is an emergency function if a message cannot be verified for some reasons // required to provide _nextNonce to avoid race condition function skip(address _oapp, uint32 _srcEid, bytes32 _sender, uint64 _nonce) external; function nilify(address _oapp, uint32 _srcEid, bytes32 _sender, uint64 _nonce, bytes32 _payloadHash) external; function burn(address _oapp, uint32 _srcEid, bytes32 _sender, uint64 _nonce, bytes32 _payloadHash) external; function nextGuid(address _sender, uint32 _dstEid, bytes32 _receiver) external view returns (bytes32); function inboundNonce(address _receiver, uint32 _srcEid, bytes32 _sender) external view returns (uint64); function outboundNonce(address _sender, uint32 _dstEid, bytes32 _receiver) external view returns (uint64); function inboundPayloadHash( address _receiver, uint32 _srcEid, bytes32 _sender, uint64 _nonce ) external view returns (bytes32); function lazyInboundNonce(address _receiver, uint32 _srcEid, bytes32 _sender) external view returns (uint64); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import { ILayerZeroEndpointV2 } from "contracts/vendor/layerzero/protocol/interfaces/ILayerZeroEndpointV2.sol"; /** * @title IOAppCore */ interface IOAppCore { // Custom error messages error OnlyPeer(uint32 eid, bytes32 sender); error NoPeer(uint32 eid); error InvalidEndpointCall(); error InvalidDelegate(); // Event emitted when a peer (OApp) is set for a corresponding endpoint event PeerSet(uint32 eid, bytes32 peer); /** * @notice Retrieves the OApp version information. * @return senderVersion The version of the OAppSender.sol contract. * @return receiverVersion The version of the OAppReceiver.sol contract. */ function oAppVersion() external view returns (uint64 senderVersion, uint64 receiverVersion); /** * @notice Retrieves the LayerZero endpoint associated with the OApp. * @return iEndpoint The LayerZero endpoint as an interface. */ function endpoint() external view returns (ILayerZeroEndpointV2 iEndpoint); /** * @notice Retrieves the peer (OApp) associated with a corresponding endpoint. * @param _eid The endpoint ID. * @return peer The peer address (OApp instance) associated with the corresponding endpoint. */ function peers(uint32 _eid) external view returns (bytes32 peer); /** * @notice Sets the peer address (OApp instance) for a corresponding endpoint. * @param _eid The endpoint ID. * @param _peer The address of the peer to be associated with the corresponding endpoint. */ function setPeer(uint32 _eid, bytes32 _peer) external; /** * @notice Sets the delegate address for the OApp Core. * @param _delegate The address of the delegate to be set. */ function setDelegate(address _delegate) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Nonces.sol) pragma solidity ^0.8.20; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Provides tracking nonces for addresses. Nonces will only increment. */ abstract contract NoncesUpgradeable is Initializable { /** * @dev The nonce used for an `account` is not the expected current nonce. */ error InvalidAccountNonce(address account, uint256 currentNonce); /// @custom:storage-location erc7201:openzeppelin.storage.Nonces struct NoncesStorage { mapping(address account => uint256) _nonces; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Nonces")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant NoncesStorageLocation = 0x5ab42ced628888259c08ac98db1eb0cf702fc1501344311d8b100cd1bfe4bb00; function _getNoncesStorage() private pure returns (NoncesStorage storage $) { assembly { $.slot := NoncesStorageLocation } } function __Nonces_init() internal onlyInitializing { } function __Nonces_init_unchained() internal onlyInitializing { } /** * @dev Returns the next unused nonce for an address. */ function nonces(address owner) public view virtual returns (uint256) { NoncesStorage storage $ = _getNoncesStorage(); return $._nonces[owner]; } /** * @dev Consumes a nonce. * * Returns the current value and increments nonce. */ function _useNonce(address owner) internal virtual returns (uint256) { NoncesStorage storage $ = _getNoncesStorage(); // For each account, the nonce has an initial value of 0, can only be incremented by one, and cannot be // decremented or reset. This guarantees that the nonce never overflows. unchecked { // It is important to do x++ and not ++x here. return $._nonces[owner]++; } } /** * @dev Same as {_useNonce} but checking that `nonce` is the next valid for `owner`. */ function _useCheckedNonce(address owner, uint256 nonce) internal virtual { uint256 current = _useNonce(owner); if (nonce != current) { revert InvalidAccountNonce(owner, current); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {ContextUpgradeable} from "../../utils/ContextUpgradeable.sol"; import {IERC20Errors} from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; import {Initializable} from "../../proxy/utils/Initializable.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * * TIP: For a detailed writeup see our guide * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * The default value of {decimals} is 18. To change this, you should override * this function so it returns a different value. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC-20 * applications. */ abstract contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20, IERC20Metadata, IERC20Errors { /// @custom:storage-location erc7201:openzeppelin.storage.ERC20 struct ERC20Storage { mapping(address account => uint256) _balances; mapping(address account => mapping(address spender => uint256)) _allowances; uint256 _totalSupply; string _name; string _symbol; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ERC20")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant ERC20StorageLocation = 0x52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00; function _getERC20Storage() private pure returns (ERC20Storage storage $) { assembly { $.slot := ERC20StorageLocation } } /** * @dev Sets the values for {name} and {symbol}. * * All two of these values are immutable: they can only be set once during * construction. */ function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing { __ERC20_init_unchained(name_, symbol_); } function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing { ERC20Storage storage $ = _getERC20Storage(); $._name = name_; $._symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual returns (string memory) { ERC20Storage storage $ = _getERC20Storage(); return $._name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual returns (string memory) { ERC20Storage storage $ = _getERC20Storage(); return $._symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the default value returned by this function, unless * it's overridden. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual returns (uint256) { ERC20Storage storage $ = _getERC20Storage(); return $._totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual returns (uint256) { ERC20Storage storage $ = _getERC20Storage(); return $._balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `to` cannot be the zero address. * - the caller must have a balance of at least `value`. */ function transfer(address to, uint256 value) public virtual returns (bool) { address owner = _msgSender(); _transfer(owner, to, value); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual returns (uint256) { ERC20Storage storage $ = _getERC20Storage(); return $._allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * NOTE: If `value` is the maximum `uint256`, the allowance is not updated on * `transferFrom`. This is semantically equivalent to an infinite approval. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 value) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, value); return true; } /** * @dev See {IERC20-transferFrom}. * * Skips emitting an {Approval} event indicating an allowance update. This is not * required by the ERC. See {xref-ERC20-_approve-address-address-uint256-bool-}[_approve]. * * NOTE: Does not update the allowance if the current allowance * is the maximum `uint256`. * * Requirements: * * - `from` and `to` cannot be the zero address. * - `from` must have a balance of at least `value`. * - the caller must have allowance for ``from``'s tokens of at least * `value`. */ function transferFrom(address from, address to, uint256 value) public virtual returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, value); _transfer(from, to, value); return true; } /** * @dev Moves a `value` amount of tokens from `from` to `to`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * NOTE: This function is not virtual, {_update} should be overridden instead. */ function _transfer(address from, address to, uint256 value) internal { if (from == address(0)) { revert ERC20InvalidSender(address(0)); } if (to == address(0)) { revert ERC20InvalidReceiver(address(0)); } _update(from, to, value); } /** * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from` * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding * this function. * * Emits a {Transfer} event. */ function _update(address from, address to, uint256 value) internal virtual { ERC20Storage storage $ = _getERC20Storage(); if (from == address(0)) { // Overflow check required: The rest of the code assumes that totalSupply never overflows $._totalSupply += value; } else { uint256 fromBalance = $._balances[from]; if (fromBalance < value) { revert ERC20InsufficientBalance(from, fromBalance, value); } unchecked { // Overflow not possible: value <= fromBalance <= totalSupply. $._balances[from] = fromBalance - value; } } if (to == address(0)) { unchecked { // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply. $._totalSupply -= value; } } else { unchecked { // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256. $._balances[to] += value; } } emit Transfer(from, to, value); } /** * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0). * Relies on the `_update` mechanism * * Emits a {Transfer} event with `from` set to the zero address. * * NOTE: This function is not virtual, {_update} should be overridden instead. */ function _mint(address account, uint256 value) internal { if (account == address(0)) { revert ERC20InvalidReceiver(address(0)); } _update(address(0), account, value); } /** * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply. * Relies on the `_update` mechanism. * * Emits a {Transfer} event with `to` set to the zero address. * * NOTE: This function is not virtual, {_update} should be overridden instead */ function _burn(address account, uint256 value) internal { if (account == address(0)) { revert ERC20InvalidSender(address(0)); } _update(account, address(0), value); } /** * @dev Sets `value` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. * * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument. */ function _approve(address owner, address spender, uint256 value) internal { _approve(owner, spender, value, true); } /** * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event. * * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any * `Approval` event during `transferFrom` operations. * * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to * true using the following override: * * ```solidity * function _approve(address owner, address spender, uint256 value, bool) internal virtual override { * super._approve(owner, spender, value, true); * } * ``` * * Requirements are the same as {_approve}. */ function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual { ERC20Storage storage $ = _getERC20Storage(); if (owner == address(0)) { revert ERC20InvalidApprover(address(0)); } if (spender == address(0)) { revert ERC20InvalidSpender(address(0)); } $._allowances[owner][spender] = value; if (emitEvent) { emit Approval(owner, spender, value); } } /** * @dev Updates `owner` s allowance for `spender` based on spent `value`. * * Does not update the allowance value in case of infinite allowance. * Revert if not enough allowance is available. * * Does not emit an {Approval} event. */ function _spendAllowance(address owner, address spender, uint256 value) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { if (currentAllowance < value) { revert ERC20InsufficientAllowance(spender, currentAllowance, value); } unchecked { _approve(owner, spender, currentAllowance - value, false); } } } }
// 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(); } } }
// 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.1.0) (utils/cryptography/EIP712.sol) pragma solidity ^0.8.20; import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol"; import {IERC5267} from "@openzeppelin/contracts/interfaces/IERC5267.sol"; import {Initializable} from "../../proxy/utils/Initializable.sol"; /** * @dev https://eips.ethereum.org/EIPS/eip-712[EIP-712] is a standard for hashing and signing of typed structured data. * * The encoding scheme specified in the EIP requires a domain separator and a hash of the typed structured data, whose * encoding is very generic and therefore its implementation in Solidity is not feasible, thus this contract * does not implement the encoding itself. Protocols need to implement the type-specific encoding they need in order to * produce the hash of their typed data using a combination of `abi.encode` and `keccak256`. * * This contract implements the EIP-712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA * ({_hashTypedDataV4}). * * The implementation of the domain separator was designed to be as efficient as possible while still properly updating * the chain id to protect against replay attacks on an eventual fork of the chain. * * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask]. * * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain * separator of the implementation contract. This will cause the {_domainSeparatorV4} function to always rebuild the * separator from the immutable values, which is cheaper than accessing a cached version in cold storage. */ abstract contract EIP712Upgradeable is Initializable, IERC5267 { bytes32 private constant TYPE_HASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); /// @custom:storage-location erc7201:openzeppelin.storage.EIP712 struct EIP712Storage { /// @custom:oz-renamed-from _HASHED_NAME bytes32 _hashedName; /// @custom:oz-renamed-from _HASHED_VERSION bytes32 _hashedVersion; string _name; string _version; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.EIP712")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant EIP712StorageLocation = 0xa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d100; function _getEIP712Storage() private pure returns (EIP712Storage storage $) { assembly { $.slot := EIP712StorageLocation } } /** * @dev Initializes the domain separator and parameter caches. * * The meaning of `name` and `version` is specified in * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP-712]: * * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol. * - `version`: the current major version of the signing domain. * * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart * contract upgrade]. */ function __EIP712_init(string memory name, string memory version) internal onlyInitializing { __EIP712_init_unchained(name, version); } function __EIP712_init_unchained(string memory name, string memory version) internal onlyInitializing { EIP712Storage storage $ = _getEIP712Storage(); $._name = name; $._version = version; // Reset prior values in storage if upgrading $._hashedName = 0; $._hashedVersion = 0; } /** * @dev Returns the domain separator for the current chain. */ function _domainSeparatorV4() internal view returns (bytes32) { return _buildDomainSeparator(); } function _buildDomainSeparator() private view returns (bytes32) { return keccak256(abi.encode(TYPE_HASH, _EIP712NameHash(), _EIP712VersionHash(), block.chainid, address(this))); } /** * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this * function returns the hash of the fully encoded EIP712 message for this domain. * * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: * * ```solidity * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( * keccak256("Mail(address to,string contents)"), * mailTo, * keccak256(bytes(mailContents)) * ))); * address signer = ECDSA.recover(digest, signature); * ``` */ function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) { return MessageHashUtils.toTypedDataHash(_domainSeparatorV4(), structHash); } /** * @dev See {IERC-5267}. */ function eip712Domain() public view virtual returns ( bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions ) { EIP712Storage storage $ = _getEIP712Storage(); // If the hashed name and version in storage are non-zero, the contract hasn't been properly initialized // and the EIP712 domain is not reliable, as it will be missing name and version. require($._hashedName == 0 && $._hashedVersion == 0, "EIP712: Uninitialized"); return ( hex"0f", // 01111 _EIP712Name(), _EIP712Version(), block.chainid, address(this), bytes32(0), new uint256[](0) ); } /** * @dev The name parameter for the EIP712 domain. * * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs * are a concern. */ function _EIP712Name() internal view virtual returns (string memory) { EIP712Storage storage $ = _getEIP712Storage(); return $._name; } /** * @dev The version parameter for the EIP712 domain. * * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs * are a concern. */ function _EIP712Version() internal view virtual returns (string memory) { EIP712Storage storage $ = _getEIP712Storage(); return $._version; } /** * @dev The hash of the name parameter for the EIP712 domain. * * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Name` instead. */ function _EIP712NameHash() internal view returns (bytes32) { EIP712Storage storage $ = _getEIP712Storage(); string memory name = _EIP712Name(); if (bytes(name).length > 0) { return keccak256(bytes(name)); } else { // If the name is empty, the contract may have been upgraded without initializing the new storage. // We return the name hash in storage if non-zero, otherwise we assume the name is empty by design. bytes32 hashedName = $._hashedName; if (hashedName != 0) { return hashedName; } else { return keccak256(""); } } } /** * @dev The hash of the version parameter for the EIP712 domain. * * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Version` instead. */ function _EIP712VersionHash() internal view returns (bytes32) { EIP712Storage storage $ = _getEIP712Storage(); string memory version = _EIP712Version(); if (bytes(version).length > 0) { return keccak256(bytes(version)); } else { // If the version is empty, the contract may have been upgraded without initializing the new storage. // We return the version hash in storage if non-zero, otherwise we assume the version is empty by design. bytes32 hashedVersion = $._hashedVersion; if (hashedVersion != 0) { return hashedVersion; } else { return keccak256(""); } } } }
// 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/cryptography/ECDSA.sol) pragma solidity ^0.8.20; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS } /** * @dev The signature derives the `address(0)`. */ error ECDSAInvalidSignature(); /** * @dev The signature has an invalid length. */ error ECDSAInvalidSignatureLength(uint256 length); /** * @dev The signature has an S value that is in the upper half order. */ error ECDSAInvalidSignatureS(bytes32 s); /** * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not * return address(0) without also returning an error description. Errors are documented using an enum (error type) * and a bytes32 providing additional information about the error. * * If no error is returned, then the address can be used for verification purposes. * * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) { if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. /// @solidity memory-safe-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else { return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length)); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature); _throwError(error, errorArg); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] */ function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) { unchecked { bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); // We do not check for an overflow here since the shift operation results in 0 or 1. uint8 v = uint8((uint256(vs) >> 255) + 27); return tryRecover(hash, v, r, s); } } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. */ function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) { (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs); _throwError(error, errorArg); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. */ function tryRecover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address, RecoverError, bytes32) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS, s); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature, bytes32(0)); } return (signer, RecoverError.NoError, bytes32(0)); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) { (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s); _throwError(error, errorArg); return recovered; } /** * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided. */ function _throwError(RecoverError error, bytes32 errorArg) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert ECDSAInvalidSignature(); } else if (error == RecoverError.InvalidSignatureLength) { revert ECDSAInvalidSignatureLength(uint256(errorArg)); } else if (error == RecoverError.InvalidSignatureS) { revert ECDSAInvalidSignatureS(errorArg); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MessageHashUtils.sol) pragma solidity ^0.8.20; import {Strings} from "../Strings.sol"; /** * @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing. * * The library provides methods for generating a hash of a message that conforms to the * https://eips.ethereum.org/EIPS/eip-191[EIP 191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712] * specifications. */ library MessageHashUtils { /** * @dev Returns the keccak256 digest of an EIP-191 signed data with version * `0x45` (`personal_sign` messages). * * The digest is calculated by prefixing a bytes32 `messageHash` with * `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method. * * NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with * keccak256, although any bytes32 value can be safely used because the final digest will * be re-hashed. * * See {ECDSA-recover}. */ function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) { /// @solidity memory-safe-assembly assembly { mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20) } } /** * @dev Returns the keccak256 digest of an EIP-191 signed data with version * `0x45` (`personal_sign` messages). * * The digest is calculated by prefixing an arbitrary `message` with * `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method. * * See {ECDSA-recover}. */ function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) { return keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message)); } /** * @dev Returns the keccak256 digest of an EIP-191 signed data with version * `0x00` (data with intended validator). * * The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended * `validator` address. Then hashing the result. * * See {ECDSA-recover}. */ function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) { return keccak256(abi.encodePacked(hex"19_00", validator, data)); } /** * @dev Returns the keccak256 digest of an EIP-712 typed data (EIP-191 version `0x01`). * * The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with * `\x19\x01` and hashing the result. It corresponds to the hash signed by the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712. * * See {ECDSA-recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) mstore(ptr, hex"19_01") mstore(add(ptr, 0x02), domainSeparator) mstore(add(ptr, 0x22), structHash) digest := keccak256(ptr, 0x42) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5267.sol) pragma solidity ^0.8.20; interface IERC5267 { /** * @dev MAY be emitted to signal that the domain could have changed. */ event EIP712DomainChanged(); /** * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712 * signature. */ function eip712Domain() external view returns ( bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions ); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol) pragma solidity ^0.8.20; /** * @dev Standard ERC20 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens. */ interface IERC20Errors { /** * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. * @param balance Current balance for the interacting account. * @param needed Minimum amount required to perform a transfer. */ error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC20InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC20InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers. * @param spender Address that may be allowed to operate on tokens without being their owner. * @param allowance Amount of tokens a `spender` is allowed to operate with. * @param needed Minimum amount required to perform a transfer. */ error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC20InvalidApprover(address approver); /** * @dev Indicates a failure with the `spender` to be approved. Used in approvals. * @param spender Address that may be allowed to operate on tokens without being their owner. */ error ERC20InvalidSpender(address spender); } /** * @dev Standard ERC721 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens. */ interface IERC721Errors { /** * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20. * Used in balance queries. * @param owner Address of the current owner of a token. */ error ERC721InvalidOwner(address owner); /** * @dev Indicates a `tokenId` whose `owner` is the zero address. * @param tokenId Identifier number of a token. */ error ERC721NonexistentToken(uint256 tokenId); /** * @dev Indicates an error related to the ownership over a particular token. Used in transfers. * @param sender Address whose tokens are being transferred. * @param tokenId Identifier number of a token. * @param owner Address of the current owner of a token. */ error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC721InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC721InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `operator`’s approval. Used in transfers. * @param operator Address that may be allowed to operate on tokens without being their owner. * @param tokenId Identifier number of a token. */ error ERC721InsufficientApproval(address operator, uint256 tokenId); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC721InvalidApprover(address approver); /** * @dev Indicates a failure with the `operator` to be approved. Used in approvals. * @param operator Address that may be allowed to operate on tokens without being their owner. */ error ERC721InvalidOperator(address operator); } /** * @dev Standard ERC1155 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens. */ interface IERC1155Errors { /** * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. * @param balance Current balance for the interacting account. * @param needed Minimum amount required to perform a transfer. * @param tokenId Identifier number of a token. */ error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC1155InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC1155InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `operator`’s approval. Used in transfers. * @param operator Address that may be allowed to operate on tokens without being their owner. * @param owner Address of the current owner of a token. */ error ERC1155MissingApprovalForAll(address operator, address owner); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC1155InvalidApprover(address approver); /** * @dev Indicates a failure with the `operator` to be approved. Used in approvals. * @param operator Address that may be allowed to operate on tokens without being their owner. */ error ERC1155InvalidOperator(address operator); /** * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation. * Used in batch transfers. * @param idsLength Length of the array of token identifiers * @param valuesLength Length of the array of token amounts */ error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol) pragma solidity ^0.8.20; import {Math} from "./math/Math.sol"; import {SignedMath} from "./math/SignedMath.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant HEX_DIGITS = "0123456789abcdef"; uint8 private constant ADDRESS_LENGTH = 20; /** * @dev The `value` string doesn't fit in the specified `length`. */ error StringsInsufficientHexLength(uint256 value, uint256 length); /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), HEX_DIGITS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toStringSigned(int256 value) internal pure returns (string memory) { return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value))); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { uint256 localValue = value; bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = HEX_DIGITS[localValue & 0xf]; localValue >>= 4; } if (localValue != 0) { revert StringsInsufficientHexLength(value, length); } return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal * representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.20; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol) pragma solidity ^0.8.20; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Muldiv operation overflow. */ error MathOverflowedMulDiv(); enum Rounding { Floor, // Toward negative infinity Ceil, // Toward positive infinity Trunc, // Toward zero Expand // Away from zero } /** * @dev Returns the addition of two unsigned integers, with an overflow flag. */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the subtraction of two unsigned integers, with an overflow flag. */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a / b); } } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds towards infinity instead * of rounding towards zero. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { if (b == 0) { // Guarantee the same behavior as in a regular Solidity division. return a / b; } // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or * denominator == 0. * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by * Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0 = x * y; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. if (denominator <= prod1) { revert MathOverflowedMulDiv(); } /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. // Always >= 1. See https://cs.stackexchange.com/q/138556/92363. uint256 twos = denominator & (0 - denominator); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also // works in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded * towards zero. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256 of a positive value rounded towards zero. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0); } } /** * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers. */ function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) { return uint8(rounding) % 2 == 1; } }
{ "evmVersion": "paris", "optimizer": { "enabled": true, "mode": "3" }, "outputSelection": { "*": { "*": [ "abi" ] } }, "detectMissingLibraries": false, "forceEVMLA": false, "enableEraVMExtensions": true, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_endpoint","type":"address"},{"internalType":"uint32","name":"_srcEid","type":"uint32"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"ECDSAInvalidSignature","type":"error"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"name":"ECDSAInvalidSignatureLength","type":"error"},{"inputs":[{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"ECDSAInvalidSignatureS","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC20InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC20InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC20InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"ERC20InvalidSpender","type":"error"},{"inputs":[{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"ERC2612ExpiredSignature","type":"error"},{"inputs":[{"internalType":"address","name":"signer","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"ERC2612InvalidSigner","type":"error"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"InsufficientAmountOut","type":"error"},{"inputs":[],"name":"InsufficientAmountToSync","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"currentNonce","type":"uint256"}],"name":"InvalidAccountNonce","type":"error"},{"inputs":[],"name":"InvalidAmount","type":"error"},{"inputs":[],"name":"InvalidAmountIn","type":"error"},{"inputs":[],"name":"InvalidDelegate","type":"error"},{"inputs":[],"name":"InvalidEndpointCall","type":"error"},{"inputs":[],"name":"InvalidFee","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"InvalidNonce","type":"error"},{"inputs":[{"internalType":"bytes","name":"options","type":"bytes"}],"name":"InvalidOptions","type":"error"},{"inputs":[],"name":"InvalidRate","type":"error"},{"inputs":[],"name":"InvalidReceiver","type":"error"},{"inputs":[],"name":"LzTokenUnavailable","type":"error"},{"inputs":[],"name":"MaxSyncAmountExceeded","type":"error"},{"inputs":[{"internalType":"uint32","name":"eid","type":"uint32"}],"name":"NoPeer","type":"error"},{"inputs":[],"name":"NotAllowed","type":"error"},{"inputs":[{"internalType":"uint256","name":"msgValue","type":"uint256"}],"name":"NotEnoughNative","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"OnlyEndpoint","type":"error"},{"inputs":[{"internalType":"uint32","name":"eid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"}],"name":"OnlyPeer","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"UnauthorizedCaller","type":"error"},{"inputs":[],"name":"UnauthorizedToken","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroAmount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"bridgeQuoter","type":"address"}],"name":"BridgeQuoterSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tokenIn","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOut","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"guid","type":"bytes32"},{"indexed":true,"internalType":"address","name":"toAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[],"name":"EIP712DomainChanged","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint32","name":"eid","type":"uint32"},{"internalType":"uint16","name":"msgType","type":"uint16"},{"internalType":"bytes","name":"options","type":"bytes"}],"indexed":false,"internalType":"struct EnforcedOptionParam[]","name":"_enforcedOptions","type":"tuple[]"}],"name":"EnforcedOptionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"tokenIn","type":"address"},{"indexed":false,"internalType":"address","name":"l1TokenIn","type":"address"}],"name":"L1TokenInSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"l2ExchangeRateProvider","type":"address"}],"name":"L2ExchangeRateProviderSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"tokenIn","type":"address"},{"indexed":false,"internalType":"uint256","name":"maxSyncAmount","type":"uint256"}],"name":"MaxSyncAmountSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"messenger","type":"address"}],"name":"MessengerSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"tokenIn","type":"address"},{"indexed":false,"internalType":"uint256","name":"minSyncAmount","type":"uint256"}],"name":"MinSyncAmountSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"toAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"eid","type":"uint32"},{"indexed":false,"internalType":"bytes32","name":"peer","type":"bytes32"}],"name":"PeerSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"rateLimiter","type":"address"}],"name":"RateLimiterSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"guid","type":"bytes32"},{"indexed":true,"internalType":"address","name":"treasury","type":"address"},{"indexed":false,"internalType":"uint256","name":"assetsPerShare","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"feeShares","type":"uint256"}],"name":"Rebase","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"receiver","type":"address"}],"name":"ReceiverSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"preRebaseTokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"postRebaseTokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesAmount","type":"uint256"}],"name":"SharesBurnt","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tokenIn","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOut","type":"uint256"}],"name":"Sync","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"syncKeeper","type":"address"},{"indexed":false,"internalType":"bool","name":"status","type":"bool"}],"name":"SyncKeeperSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"sharesValue","type":"uint256"}],"name":"TransferShares","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"guid","type":"bytes32"},{"indexed":true,"internalType":"address","name":"fromAddress","type":"address"},{"indexed":true,"internalType":"address","name":"toAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"bool","name":"allowed","type":"bool"}],"name":"canPauseSet","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"internalType":"struct Origin","name":"origin","type":"tuple"}],"name":"allowInitializePath","outputs":[{"internalType":"bool","name":"","type":"bool"}],"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":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"canPause","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_eid","type":"uint32"},{"internalType":"uint16","name":"_msgType","type":"uint16"},{"internalType":"bytes","name":"_extraOptions","type":"bytes"}],"name":"combineOptions","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"composeMsgSender","outputs":[{"internalType":"address","name":"sender","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_shares","type":"uint256"},{"internalType":"bool","name":"floor","type":"bool"}],"name":"convertToAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assets","type":"uint256"}],"name":"convertToShares","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":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"bool","name":"shouldWrap","type":"bool"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"endpoint","outputs":[{"internalType":"contract ILayerZeroEndpointV2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_eid","type":"uint32"},{"internalType":"uint16","name":"_msgType","type":"uint16"}],"name":"enforcedOptions","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getL2ExchangeRateProvider","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMessenger","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRateLimiter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getReceiver","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"}],"name":"getTokenData","outputs":[{"components":[{"internalType":"uint256","name":"unsyncedAmountIn","type":"uint256"},{"internalType":"uint256","name":"unsyncedAmountOut","type":"uint256"},{"internalType":"uint256","name":"minSyncAmount","type":"uint256"},{"internalType":"uint256","name":"maxSyncAmount","type":"uint256"},{"internalType":"address","name":"l1Address","type":"address"}],"internalType":"struct L2SyncPool.Token","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_delegate","type":"address"},{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_treasury","type":"address"},{"internalType":"address","name":"_l2ExchangeRateProvider","type":"address"},{"internalType":"address","name":"_rateLimiter","type":"address"},{"internalType":"address","name":"_messenger","type":"address"},{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"address","name":"_bridgeQuoter","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"syncKeeper","type":"address"}],"name":"isSyncKeeper","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastAssetsPerShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"internalType":"struct Origin","name":"_origin","type":"tuple"},{"internalType":"bytes32","name":"_guid","type":"bytes32"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"address","name":"_executor","type":"address"},{"internalType":"bytes","name":"_extraData","type":"bytes"}],"name":"lzReceive","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_srcEid","type":"uint32"},{"internalType":"bytes32","name":"_sender","type":"bytes32"}],"name":"nextNonce","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oAppVersion","outputs":[{"internalType":"uint64","name":"senderVersion","type":"uint64"},{"internalType":"uint64","name":"receiverVersion","type":"uint64"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_eid","type":"uint32"}],"name":"peers","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"includeUnsynced","type":"bool"}],"name":"pendingDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assets","type":"uint256"}],"name":"previewWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenIn","type":"address"},{"internalType":"bytes","name":"_options","type":"bytes"}],"name":"quoteSync","outputs":[{"components":[{"internalType":"uint256","name":"nativeFee","type":"uint256"},{"internalType":"uint256","name":"lzTokenFee","type":"uint256"}],"internalType":"struct MessagingFee","name":"msgFee","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes","name":"_options","type":"bytes"}],"name":"quoteWithdraw","outputs":[{"components":[{"internalType":"uint256","name":"nativeFee","type":"uint256"},{"internalType":"uint256","name":"lzTokenFee","type":"uint256"}],"internalType":"struct MessagingFee","name":"msgFee","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rebaseFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"bridgeQuoter","type":"address"}],"name":"setBridgeQuoter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"},{"internalType":"bool","name":"_allowed","type":"bool"}],"name":"setCanPause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_delegate","type":"address"}],"name":"setDelegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"eid","type":"uint32"},{"internalType":"uint16","name":"msgType","type":"uint16"},{"internalType":"bytes","name":"options","type":"bytes"}],"internalType":"struct EnforcedOptionParam[]","name":"_enforcedOptions","type":"tuple[]"}],"name":"setEnforcedOptions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"l2TokenIn","type":"address"},{"internalType":"address","name":"l1TokenIn","type":"address"}],"name":"setL1TokenIn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"l2ExchangeRateProvider","type":"address"}],"name":"setL2ExchangeRateProvider","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"maxSyncAmount","type":"uint256"}],"name":"setMaxSyncAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"messenger","type":"address"}],"name":"setMessenger","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"minSyncAmount","type":"uint256"}],"name":"setMinSyncAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_srcEid","type":"uint32"},{"internalType":"bytes32","name":"_sender","type":"bytes32"},{"internalType":"uint64","name":"_nonce","type":"uint64"}],"name":"setNonce","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_eid","type":"uint32"},{"internalType":"bytes32","name":"_peer","type":"bytes32"}],"name":"setPeer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"rateLimiter","type":"address"}],"name":"setRateLimiter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_rebaseFee","type":"uint256"}],"name":"setRebaseFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"setReceiver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_syncDepositFee","type":"uint256"}],"name":"setSyncDepositFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"syncKeeper","type":"address"},{"internalType":"bool","name":"status","type":"bool"}],"name":"setSyncKeeper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_treasury","type":"address"}],"name":"setTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wLST","type":"address"}],"name":"setWrappedLST","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"sharesOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"bytes","name":"extraOptions","type":"bytes"},{"components":[{"internalType":"uint256","name":"nativeFee","type":"uint256"},{"internalType":"uint256","name":"lzTokenFee","type":"uint256"}],"internalType":"struct MessagingFee","name":"fee","type":"tuple"}],"name":"sync","outputs":[{"internalType":"uint256","name":"unsyncedAmountIn","type":"uint256"},{"internalType":"uint256","name":"unsyncedAmountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"extraOptions","type":"bytes"},{"components":[{"internalType":"uint256","name":"nativeFee","type":"uint256"},{"internalType":"uint256","name":"lzTokenFee","type":"uint256"}],"internalType":"struct MessagingFee","name":"fee","type":"tuple"}],"name":"sync","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"syncDepositFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"idx","type":"uint256"}],"name":"syncIndexPendingAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"syncIndexes","outputs":[{"internalType":"uint256","name":"lastPendingSyncIndex","type":"uint256"},{"internalType":"uint256","name":"lastCompletedSyncIndex","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalStaked","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_shares","type":"uint256"}],"name":"transferShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_shares","type":"uint256"}],"name":"transferSharesFrom","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"address","name":"_refundAddress","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes","name":"_options","type":"bytes"}],"name":"withdraw","outputs":[],"stateMutability":"payable","type":"function"}]
Contract Creation Code
9c4d535b000000000000000000000000000000000000000000000000000000000000000001000b7dd690c72c7c839a760ef97505f037b722cbac3c96143a05c98d8f21c9000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000400000000000000000000000005c6cff4b7c49805f8295ff73c204ac83f3bc4ae70000000000000000000000000000000000000000000000000000000000007595
Deployed Bytecode
0x000200000000000200120000000000020001000000010355000000600310027000000a400030019d00000a40033001970000000100200190000000310000c13d0000008002000039000a00000002001d000000400020043f000b00000003001d000000040030008c000000580000413d000000000201043b000000e00220027000000a4a0020009c0000005a0000213d00000a800020009c0000000b03000029000000740000213d00000a9b0020009c000000cc0000a13d00000a9c0020009c000001890000213d00000aa30020009c000005a90000a13d00000aa40020009c000008c10000613d00000aa50020009c00000aba0000613d00000aa60020009c000000580000c13d0000000b02000029000000240020008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000401100370000000000101043b000c00000001001d00000a430010009c000000580000213d28fd206a0000040f0000000c0100002928fd22d60000040f0000000001000019000028fe0001042e0000000002000416000000000002004b000000580000c13d00000000080300190000001f0230003900000a4102200197000000c002200039000000400020043f0000001f0430018f00000a4205300198000000c002500039000000430000613d000000c006000039000000000701034f000000007307043c0000000006360436000000000026004b0000003f0000c13d000000000004004b000000500000613d000000000151034f0000000303400210000000000402043300000000043401cf000000000434022f000000000101043b0000010003300089000000000131022f00000000013101cf000000000141019f0000000000120435000000400080008c000000580000413d000000c00200043d00000a430020009c000000580000213d000000e00100043d00000a400010009c000000a10000a13d0000000001000019000028ff0001043000000a4b0020009c0000000b03000029000000850000213d00000a660020009c000001130000a13d00000a670020009c000001cf0000213d00000a6e0020009c000005b20000a13d00000a6f0020009c000008f10000613d00000a700020009c00000ac80000613d00000a710020009c000000580000c13d0000000001000416000000000001004b000000580000c13d00000ae001000041000000000101041a00000adf02000041000000000202041a000000800020043f000000a00010043f00000b3401000041000028fe0001042e00000a810020009c000001330000a13d00000a820020009c0000021a0000213d00000a890020009c000005bb0000a13d00000a8a0020009c000009110000613d00000a8b0020009c00000ad70000613d00000a8c0020009c000000580000c13d0000000001000416000000000001004b000000580000c13d00000b2001000041000008120000013d00000a4c0020009c0000014b0000a13d00000a4d0020009c000002590000213d00000a540020009c000005de0000a13d00000a550020009c000009240000613d00000a560020009c00000ae50000613d00000a570020009c000000580000c13d0000000b02000029000000240020008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000401100370000000000101043b000c00000001001d00000a430010009c000000580000213d28fd206a0000040f0000000c0100002928fd23d80000040f0000000001000019000028fe0001042e00000a4302200197000000800020043f000000a00010043f00000a4403000041000000000303041a00000a45003001980000158e0000c13d00000a460430019700000a460040009c000000c20000613d00000a46013001c700000a4402000041000000000012041b00000a4601000041000000400200043d000000000012043500000a400020009c00000a40020080410000004001200210000000000200041400000a400020009c00000a4002008041000000c002200210000000000112019f00000a47011001c70000800d02000039000000010300003900000a480400004128fd28f30000040f0000000100200190000000580000613d000000a00100043d000000800200043d0000014000000443000001600020044300000020020000390000018000200443000001a00010044300000100002004430000000201000039000001200010044300000a4901000041000028fe0001042e00000aa90020009c000002730000a13d00000aaa0020009c0000056e0000a13d00000aab0020009c000008340000613d00000aac0020009c00000a370000613d00000aad0020009c000000580000c13d0000000b02000029000000240020008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000401100370000000000101043b00000a430010009c000000580000213d0000012002000039000000400020043f000000800000043f000000a00000043f000000c00000043f000000e00000043f000001000000043f28fd1e380000040f000c00000001001d000000400100043d000b00000001001d28fd1dff0000040f0000000c06000029000000000106041a0000000b0700002900000000021704360000000103600039000000000303041a00000000003204350000000203600039000000000303041a000000400470003900000000003404350000000303600039000000000303041a0000006005700039000000000035043500000080037000390000000406600039000000000606041a00000a43066001970000000000630435000000400600043d000000000116043600000000020204330000000000210435000000000104043300000040026000390000000000120435000000000105043300000060026000390000000000120435000000000103043300000a43011001970000008002600039000000000012043500000a400060009c00000a4006008041000000400160021000000b49011001c7000028fe0001042e00000a740020009c000004860000a13d00000a750020009c0000057c0000a13d00000a760020009c0000084a0000613d00000a770020009c00000a950000613d00000a780020009c000000580000c13d0000000001000416000000000001004b000000580000c13d00000b0d01000041000000000201041a000000010420019000000001012002700000007f0310018f00000000010360190000001f0010008c00000000050000390000000105002039000000000552013f00000001005001900000070c0000c13d000000800010043f000000000004004b00000ba00000c13d00000b5f01200197000000a00010043f000000000003004b00000b800000013d00000a8f0020009c000004910000a13d00000a900020009c000005850000a13d00000a910020009c000008650000613d00000a920020009c00000aad0000613d00000a930020009c000000580000c13d0000000b02000029000000240020008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000401100370000000000101043b00000a430010009c000000580000213d28fd1e5a0000040f000000000101041a28fd20040000040f00000b320000013d00000a5a0020009c000004a20000a13d00000a5b0020009c0000058e0000a13d00000a5c0020009c000008a60000613d00000a5d0020009c00000ab20000613d00000a5e0020009c000000580000c13d0000000b02000029000000e40020008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000402100370000000000202043b000c00000002001d00000a430020009c000000580000213d0000002402100370000000000202043b000b00000002001d00000a430020009c000000580000213d0000006402100370000000000202043b000a00000002001d0000004402100370000000000202043b000900000002001d0000008401100370000000000101043b000800000001001d000000ff0010008c000000580000213d00000aed010000410000000000100443000000000100041400000a400010009c00000a4001008041000000c00110021000000aee011001c70000800b0200003928fd28f80000040f000000010020019000001da20000613d000000000101043b0000000a0010006c00000ce30000a13d000000400100043d00000afa02000041000000000021043500000004021000390000000a03000029000000000032043500000a400010009c00000a4001008041000000400110021000000ac8011001c7000028ff0001043000000a9d0020009c000005f60000a13d00000a9e0020009c000009650000613d00000a9f0020009c00000af40000613d00000aa00020009c000000580000c13d0000000b02000029000000440020008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000402100370000000000202043b000c00000002001d00000a430020009c000000580000213d0000002401100370000000000201043b000000000002004b0000000001000039000000010100c039000b00000002001d000000000012004b000000580000c13d00000ae801000041000000000101041a00000a43021001970000000001000411000000000012004b00000b570000c13d0000000c01000029000000000010043f00000b2901000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000000101043b000000000201041a00000b5f022001970000000b03000029000000000232019f000000000021041b000000400100043d000000200210003900000000003204350000000c02000029000000000021043500000a400010009c00000a40010080410000004001100210000000000200041400000a400020009c00000a4002008041000000c002200210000000000112019f00000ab9011001c70000800d02000039000000010300003900000b440400004100000cab0000013d00000a680020009c000006300000a13d00000a690020009c0000096a0000613d00000a6a0020009c00000b160000613d00000a6b0020009c000000580000c13d0000000b02000029000000240020008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000402100370000000000202043b000c00000002001d00000a460020009c000000580000213d0000000c0200002900000023022000390000000b0020006c000000580000813d0000000c020000290000000402200039000000000221034f000000000202043b000900000002001d00000a460020009c000000580000213d000000090200002900000005032002100000000c020000290000002402200039000800000002001d000300000003001d00000000023200190000000b0020006c000000580000213d00000ae802000041000000000202041a00000a43032001970000000002000411000000000023004b00000b520000c13d000000090000006b00000d4a0000c13d00000020020000390000000a040000290000000002240436000000090300002900000000003204350000004002400039000000030b200029000000000003004b00000eab0000c13d0000000a0200002900000000012b004900000a400010009c00000a4001008041000000600110021000000a400020009c00000a40020080410000004002200210000000000121019f000000000200041400000a400020009c00000a4002008041000000c002200210000000000121019f00000af2011001c70000800d02000039000000010300003900000b040400004100000cab0000013d00000a830020009c000006660000a13d00000a840020009c00000a1e0000613d00000a850020009c00000b1d0000613d00000a860020009c000000580000c13d0000000b02000029000000440020008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000402100370000000000202043b000c00000002001d00000a430020009c000000580000213d0000002401100370000000000301043b00000ae801000041000000000101041a00000a43021001970000000001000411000000000012004b00000b570000c13d000b00000003001d0000000c01000029000000000010043f00000ab801000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000000101043b00000003011000390000000b03000029000000000031041b000000400100043d000000200210003900000000003204350000000c02000029000000000021043500000a400010009c00000a40010080410000004001100210000000000200041400000a400020009c00000a4002008041000000c002200210000000000112019f00000ab9011001c70000800d02000039000000010300003900000b3f0400004100000cab0000013d00000a4e0020009c000006840000a13d00000a4f0020009c00000a2b0000613d00000a500020009c00000b390000613d00000a510020009c000000580000c13d0000000b02000029000000640020008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000401100370000000000101043b00000a400010009c000000580000213d28fd1ef90000040f00000024020000390000000102200367000000000202043b000000000021004b0000000001000039000000010100603900000b320000013d00000ab00020009c000005040000213d00000ab30020009c000005ad0000613d00000ab40020009c000000580000c13d0000000b02000029000000840020008c000000580000413d0000000402100370000000000202043b000c00000002001d00000a430020009c000000580000213d0000002402100370000000000202043b00000a460020009c000000580000213d00000023032000390000000b0030006c000000580000813d0000000403200039000000000131034f000000000101043b000a00000001001d00000a460010009c000000580000213d0000002402200039000900000002001d0000000a012000290000000b0010006c000000580000213d000000000100041100000a4301100197000000000010043f00000b2901000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000000101043b000000000101041a000000ff00100190000006630000613d0000000c01000029000000000010043f00000ab801000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000000101043b0000000402100039000000000202041a000b0a430020019c00000f4f0000613d000000000201041a000800000002001d000000000002004b000010dc0000613d0000000202100039000000000202041a000000080020006b000010dc0000413d0000000102100039000000000302041a000000000001041b000000000002041b000000400100043d0000002002100039000700000003001d00000000003204350000000802000029000000000021043500000a400010009c00000a40010080410000004001100210000000000200041400000a400020009c00000a4002008041000000c002200210000000000112019f00000ab9011001c70000800d02000039000000020300003900000b2a040000410000000c0500002928fd28f30000040f0000000100200190000000580000613d000000400100043d00000b5b0010009c00000cbd0000813d0000006002100039000000400020043f000000200210003900000000000204350000000000010435000000400200043d00000ae20020009c00000cbd0000213d0000004003200039000000400030043f0000002003200039000000000003043500000000000204350000004001100039000000000021043500000ab601000041000000000201041a000000020020008c000012960000613d0000000202000039000000000021041b00000ab701000041000000000101041a000000ff00100190000010d90000c13d00000add0100004100000000001004430000000001000412000000040010044300000020010000390000002400100443000000000100041400000a400010009c00000a4001008041000000c00110021000000ade011001c7000080050200003928fd28f80000040f000000010020019000001da20000613d000000000101043b000c00000001001d000000400300043d00000080013000390000000702000029000000000021043500000060013000390000000802000029000000000021043500000040013000390000000b02000029000000000021043500000020013000390000000502000039000000000021043500000080010000390000000000130435000600000003001d00000b2c0030009c00000cbd0000213d0000000601000029000000a001100039000000400010043f0000000c0100002900000009020000290000000a0300002928fd1f0b0000040f000000400400043d00000ae20040009c00000cbd0000213d00000000030100190000004001400039000000400010043f00000044010000390000000101100367000000000101043b000000000114043600000000000104350000000c010000290000000602000029000000000500041128fd23e80000040f000c00000001001d00000adf01000041000000000201041a000000010020003a00000bb90000413d0000000102200039000a00000002001d000000000021041b0000000c010000290000000001010433000000000010043f00000b2d01000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000000101043b0000000a02000029000000000021041b000000000020043f00000ae101000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000000101043b0000000703000029000000000031041b00000ad501000041000000000201041a000000000032001a00000bb90000413d0000000702200029000000000021041b00000ad401000041000000000201041a000000070220006c00000bb90000413d000000000021041b00000b2e01000041000000400200043d000a00000002001d000000000012043500000add010000410000000000100443000000000100041200000004001004430000002400000443000000000100041400000a400010009c00000a4001008041000000c00110021000000ade011001c7000080050200003928fd28f80000040f000000010020019000001da20000613d000000000201043b0000000a0100002900000a400010009c00000a40010080410000004001100210000000000300041400000a400030009c00000a4003008041000000c003300210000000000113019f00000abf011001c700000a430220019728fd28f80000040f000000600310027000000a4003300197000000200030008c000000200400003900000000040340190000001f0640018f00000020074001900000000a057000290000038f0000613d000000000801034f0000000a09000029000000008a08043c0000000009a90436000000000059004b0000038b0000c13d000000000006004b0000039c0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000017290000613d0000001f01400039000000600210018f0000000a01200029000000000021004b0000000002000039000000010200403900000a460010009c00000cbd0000213d000000010020019000000cbd0000c13d000000400010043f000000200030008c000000580000413d0000000a02000029000000000302043300000a400030009c000000580000213d0000000c020000290000000002020433000000a0041000390000000705000029000000000054043500000080041000390000000805000029000000000054043500000060041000390000000b0500002900000000005404350000004004100039000000000024043500000020021000390000000000320435000000a003000039000000000031043500000b2f0010009c00000cbd0000213d000000c003100039000b00000003001d000000400030043f000000e00410003900000b3003000041000c00000004001d0000000000340435000000e403100039000000200400003900000000004304350000010404100039000000000301043300000000003404350000012401100039000000000003004b000003da0000613d000000000400001900000000051400190000000006240019000000000606043300000000006504350000002004400039000000000034004b000003d30000413d000000000113001900000000000104350000001f0130003900000b600110019700000044021000390000000b030000290000000000230435000000830110003900000b60021001970000000001320019000000000021004b0000000002000039000000010200403900000a460010009c00000cbd0000213d000000010020019000000cbd0000c13d000000400010043f00000b2201000041000000000101041a000900000001001d00000b2001000041000000000101041a00000acf02000041000000000020044300000a4301100197000a00000001001d0000000400100443000000000100041400000a400010009c00000a4001008041000000c00110021000000ad0011001c7000080020200003928fd28f80000040f000000010020019000001da20000613d000000000101043b000000000001004b000000580000613d000000090100002900000a4301100197000000400400043d00000024024000390000004003000039000000000032043500000b31020000410000000000240435000000040240003900000000001204350000000b01000029000000000101043300000044024000390000000000120435000b00000004001d0000006402400039000000000001004b0000041c0000613d000000000300001900000000042300190000000c05300029000000000505043300000000005404350000002003300039000000000013004b000004150000413d0000001f0310003900000b600330019700000000012100190000000000010435000000640130003900000a400010009c00000a400100804100000060011002100000000b0200002900000a400020009c00000a40020080410000004002200210000000000121019f000000000200041400000a400020009c00000a4002008041000000c002200210000000000112019f00000af2011001c7000080090200003900000008030000290000000a04000029000000000500001928fd28f30000040f0000000100200190000018210000613d0000000b0100002900000a460010009c00000cbd0000213d0000000b01000029000000400010043f00000b3201000041000000000101041a000c00000001001d00000ad601000041000000000101041a00000acf02000041000000000020044300000a4301100197000b00000001001d0000000400100443000000000100041400000a400010009c00000a4001008041000000c00110021000000ad0011001c7000080020200003928fd28f80000040f000000010020019000001da20000613d000000000101043b000000000001004b000000580000613d000000400300043d00000044013000390000000c020000290000000000210435000000240130003900000aba02000041000000000021043500000ad7010000410000000001130436000900000001001d000000000100041000000a4301100197000000040230003900000000001204350000006401300039000000000001043500000a400030009c000a00000003001d00000a400100004100000000010340190006004000100218000000000100041400000a400010009c00000a4001008041000000c00110021000000006011001af00000ad8011001c70000000b0200002928fd28f30000040f0000000100200190000018f80000613d0000000a0100002900000a460010009c00000cbd0000213d0000000a01000029000000400010043f00000b3201000041000000000201041a0000000c0220006c00000bb90000413d000000000021041b000000010100003900000ab602000041000000000012041b00000007010000290000000902000029000000000012043500000008010000290000000a020000290000000000120435000000060100002900000b33011001c7000028fe0001042e00000a7b0020009c000005210000213d00000a7e0020009c000006cb0000613d00000a7f0020009c000000580000c13d0000000001000416000000000001004b000000580000c13d00000b3e0100004100000ab60000013d00000a960020009c000005570000213d00000a990020009c000006d70000613d00000a9a0020009c000000580000c13d0000000001000416000000000001004b000000580000c13d00000ab701000041000000000101041a000000ff001001900000000001000039000000010100c039000000800010043f00000afb01000041000028fe0001042e00000a610020009c000005600000213d00000a640020009c000006f40000613d00000a650020009c000000580000c13d0000000b02000029000000640020008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000402100370000000000202043b00000a400020009c000000580000213d0000002403100370000000000303043b000c00000003001d0000ffff0030008c000000580000213d0000004403100370000000000403043b00000a460040009c000000580000213d00000023034000390000000b0030006c000000580000813d000900040040003d0000000901100360000000000101043b000a00000001001d00000a460010009c000000580000213d0000002403400039000800000003001d0000000a03300029000700000003001d0000000b0030006c000000580000213d000000000020043f00000aff01000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000000101043b0000000c02000029000000000020043f000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000000101043b000000000201041a000000010320019000000001042002700000007f0440618f000c00000004001d0000001f0040008c00000000040000390000000104002039000000000442013f00000001004001900000070c0000c13d000000400400043d000b00000004001d0000000c050000290000000004540436000600000004001d000000000003004b000011500000613d000000000010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000a47011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d0000000c0000006b000011b80000c13d0000000001000019000011c30000013d00000ab10020009c000006ff0000613d00000ab20020009c000000580000c13d0000000b02000029000000240020008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000401100370000000000101043b00000a430010009c000000580000213d00000ae802000041000000000202041a00000a43032001970000000002000411000000000023004b00000b520000c13d000000000001004b000008bd0000613d00000ac502000041000000000302041a00000afc03300197000000000113019f000000000012041b0000000001000019000028fe0001042e00000a7c0020009c000007120000613d00000a7d0020009c000000580000c13d0000000001000416000000000001004b000000580000c13d000000000100041100000a4301100197000000000010043f00000b3c01000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000000101043b000000000101041a000000ff00100190000005400000c13d00000ae801000041000000000101041a0000000002000411000000000121013f00000a4300100198000019200000c13d00000ab701000041000000000201041a000000ff00200190000010d90000c13d00000b5f0220019700000001022001bf000000000021041b000000400100043d0000000002000411000000000021043500000a400010009c00000a40010080410000004001100210000000000200041400000a400020009c00000a4002008041000000c002200210000000000112019f00000a47011001c70000800d02000039000000010300003900000b3d0400004100000cab0000013d00000a970020009c000007170000613d00000a980020009c000000580000c13d0000000001000416000000000001004b000000580000c13d00000b1c01000041000008120000013d00000a620020009c000007250000613d00000a630020009c000000580000c13d0000000b02000029000000240020008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000401100370000000000101043b28fd20a20000040f00000b320000013d00000aae0020009c000007340000613d00000aaf0020009c000000580000c13d0000000b02000029000000240020008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000401100370000000000101043b28fd207b0000040f00000b320000013d00000a790020009c000007430000613d00000a7a0020009c000000580000c13d0000000001000416000000000001004b000000580000c13d00000ae801000041000008120000013d00000a940020009c000007630000613d00000a950020009c000000580000c13d0000000001000416000000000001004b000000580000c13d00000b410100004100000ab60000013d00000a5f0020009c000007810000613d00000a600020009c000000580000c13d0000000b02000029000000440020008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000402100370000000000202043b0000002401100370000000000401043b000000000004004b0000000001000039000000010100c039000000000014004b000000580000c13d00000ad201000041000000000101041a000000000001004b000000000300001900000b830000c13d000000800030043f00000afb01000041000028fe0001042e00000aa70020009c000007cd0000613d00000aa80020009c000000580000c13d0000000001000416000000000001004b000000580000c13d28fd20540000040f00000b320000013d00000a720020009c000007d50000613d00000a730020009c000000580000c13d0000000001000416000000000001004b000000580000c13d00000ad601000041000008120000013d00000a8d0020009c000007da0000613d00000a8e0020009c000000580000c13d0000000b02000029000000240020008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000401100370000000000101043b00000a430010009c000000580000213d00000ae802000041000000000202041a00000a43032001970000000002000411000000000023004b00000b520000c13d00000b2202000041000000000302041a00000afc03300197000000000313019f000000000032041b000000800010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000b43011001c70000800d02000039000000010300003900000b230400004100000cab0000013d00000a580020009c000007ef0000613d00000a590020009c000000580000c13d0000000b02000029000000240020008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000401100370000000000101043b00000ae802000041000000000202041a00000a43032001970000000002000411000000000023004b00000b520000c13d00000aeb0010009c000009200000213d00000aec02000041000000000012041b0000000001000019000028fe0001042e00000aa10020009c000008070000613d00000aa20020009c000000580000c13d0000000b02000029000000440020008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000402100370000000000202043b000c00000002001d00000a400020009c000000580000213d0000002401100370000000000301043b00000ae801000041000000000101041a00000a43021001970000000001000411000000000012004b00000b570000c13d000b00000003001d0000000c01000029000000000010043f00000b4701000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000000101043b0000000b03000029000000000031041b000000400100043d000000200210003900000000003204350000000c02000029000000000021043500000a400010009c00000a40010080410000004001100210000000000200041400000a400020009c00000a4002008041000000c002200210000000000112019f00000ab9011001c70000800d02000039000000010300003900000b480400004100000cab0000013d00000a6c0020009c0000080e0000613d00000a6d0020009c000000580000c13d0000000b02000029000000a40020008c000000580000413d0000000402100370000000000202043b000c00000002001d00000a430020009c000000580000213d0000002402100370000000000202043b000a00000002001d0000004402100370000000000202043b00000a460020009c000000580000213d00000023032000390000000b0030006c000000580000813d0000000403200039000000000131034f000000000101043b000900000001001d00000a460010009c000000580000213d0000002402200039000800000002001d00000009012000290000000b0010006c000000580000213d000000000100041100000a4301100197000000000010043f00000b2901000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000000101043b000000000101041a000000ff0010019000000f3d0000c13d000000400100043d00000b5e02000041000015900000013d00000a870020009c000008170000613d00000a880020009c000000580000c13d0000000b02000029000000240020008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000401100370000000000201043b000000000002004b0000000001000039000000010100c039000000000012004b000000580000c13d00000ad501000041000000000101041a000000000002004b00000000020000190000067e0000613d00000ad402000041000000000202041a000000000012001a00000bb90000413d0000000001120019000000800010043f00000afb01000041000028fe0001042e00000a520020009c000008250000613d00000a530020009c000000580000c13d0000000b02000029000000840020008c000000580000413d0000000402100370000000000202043b000c00000002001d00000a430020009c000000580000213d0000002402100370000000000202043b000a00000002001d00000a430020009c000000580000213d0000004402100370000000000202043b000900000002001d0000006402100370000000000202043b00000a460020009c000000580000213d00000023032000390000000b0030006c000000580000813d0000000403200039000000000131034f000000000101043b000800000001001d00000a460010009c000000580000213d0000002402200039000700000002001d00000008012000290000000b0010006c000000580000213d00000ab601000041000000000201041a000000020020008c00000b4e0000613d0000000202000039000000000021041b00000ab701000041000000000101041a000000ff0010019000000c6e0000c13d0000000c0000006b000008bd0000613d00000acf0100004100000000001004430000000c010000290000000400100443000000000100041400000a400010009c00000a4001008041000000c00110021000000ad0011001c7000080020200003928fd28f80000040f000000010020019000001da20000613d000000000101043b000000000001004b0000117b0000c13d000000090000006b0000120f0000c13d000000400100043d00000ae602000041000015900000013d000000240030008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000401100370000000000101043b00000a430010009c000000580000213d000000000010043f00000aef01000041000008200000013d000000440030008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000402100370000000000202043b00000a400020009c000000580000213d0000002401100370000000000101043b000c00000001001d0000ffff0010008c000000580000213d000000000020043f00000aff01000041000000200010043f0000004002000039000000000100001928fd28c00000040f0000000c02000029000000000020043f000000200010043f0000000001000019000000400200003928fd28c00000040f000000800200003928fd1e7c0000040f00000bca0000013d000000240030008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000401100370000000000101043b00000a400010009c000000580000213d28fd1ef90000040f00000b320000013d0000000001000416000000000001004b000000580000c13d00000b0901000041000000000201041a000000010320019000000001012002700000007f0110618f0000001f0010008c00000000040000390000000104002039000000000043004b00000b660000613d00000b5501000041000000000010043f0000002201000039000000040010043f00000ac801000041000028ff000104300000000001000416000000000001004b000000580000c13d00000ad30100004100000ab60000013d0000000001000416000000000001004b000000580000c13d0000000001000412001000000001001d000f00000000003d000080050100003900000044030000390000000004000415000000100440008a000000050440021000000add0200004128fd28d50000040f000008130000013d000000240030008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000401100370000000000101043b000c00000001001d00000a430010009c000000580000213d28fd206a0000040f0000000c0100002928fd239c0000040f0000000001000019000028fe0001042e000000440030008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000402100370000000000202043b00000a430020009c000000580000213d0000002401100370000000000301043b000000000100041128fd262e0000040f000000010100003900000b320000013d0000000001000416000000000001004b000000580000c13d00000b1a01000041000000000101041a000000000001004b00000b5c0000c13d00000b1b01000041000000000101041a000000000001004b00000b5c0000c13d00000b1201000041000000000201041a000000010320019000000001012002700000007f0110618f0000001f0010008c00000000040000390000000104002039000000000442013f00000001004001900000070c0000c13d000000800010043f000000000003004b00000c720000613d00000b1202000041000000000020043f000000000001004b00000cb00000c13d0000002002000039000000a00100003900000cc40000013d000000240030008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000401100370000000000101043b00000a430010009c000000580000213d00000ae802000041000000000202041a00000a43032001970000000002000411000000000023004b00000b520000c13d00000b2002000041000000000302041a00000afc03300197000000000313019f000000000032041b000000800010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000b43011001c70000800d02000039000000010300003900000b210400004100000cab0000013d000000240030008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000401100370000000000101043b000c00000001001d00000a430010009c000000580000213d00000ae801000041000000000101041a00000a43021001970000000001000411000000000012004b00000b570000c13d00000add010000410000000000100443000000000100041200000004001004430000002400000443000000000100041400000a400010009c00000a4001008041000000c00110021000000ade011001c7000080050200003928fd28f80000040f000000010020019000001da20000613d000000000101043b00000acf02000041000000000020044300000a4301100197000b00000001001d0000000400100443000000000100041400000a400010009c00000a4001008041000000c00110021000000ad0011001c7000080020200003928fd28f80000040f000000010020019000001da20000613d000000000101043b000000000001004b000000580000613d000000400300043d00000afe01000041000000000013043500000004013000390000000c02000029000000000021043500000a400030009c000c00000003001d00000a400100004100000000010340190000004001100210000000000200041400000a400020009c00000a4002008041000000c002200210000000000112019f00000ac8011001c70000000b0200002928fd28f30000040f000000010020019000000f210000613d0000000c0100002900000a460010009c00000cbd0000213d0000000c01000029000000400010043f0000000001000019000028fe0001042e0000000001000416000000000001004b000000580000c13d0000000101000039000000800010043f000000a00010043f00000b3401000041000028fe0001042e0000000001000416000000000001004b000000580000c13d00000b2201000041000008120000013d0000000001000416000000000001004b000000580000c13d00000ae801000041000000000201041a00000a43032001970000000005000411000000000053004b00000b780000c13d00000afc02200197000000000021041b000000000100041400000a400010009c00000a4001008041000000c00110021000000af2011001c70000800d02000039000000030300003900000b0804000041000000000600001900000cab0000013d000000440030008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000402100370000000000202043b00000a430020009c000000580000213d0000002401100370000000000101043b000c00000001001d00000a430010009c000000580000213d000000000102001928fd1e6b0000040f0000000c02000029000000000020043f000000200010043f0000004002000039000000000100001928fd28c00000040f000000000101041a00000b320000013d0000000001000416000000000001004b000000580000c13d0000001201000039000000800010043f00000afb01000041000028fe0001042e0000000001000416000000000001004b000000580000c13d00000ac001000041000000000101041a00000a4301100197000000800010043f00000afb01000041000028fe0001042e000000240030008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000401100370000000000101043b000000000010043f00000ae101000041000000200010043f0000004002000039000000000100001928fd28c00000040f00000ab60000013d000000240030008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000401100370000000000101043b000c00000001001d00000a430010009c000000580000213d28fd206a0000040f0000000c0100002928fd20340000040f0000000001000019000028fe0001042e000000440030008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000401100370000000000101043b000c00000001001d00000a430010009c000000580000213d28fd1ddc0000040f000b00000001001d28fd206a0000040f0000000c0100002928fd1e490000040f000000000301041a00000b5f023001970000000b0000006b000000010220c1bf000000000021041b0000000001000019000028fe0001042e000000440030008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000402100370000000000302043b00000a430030009c000000580000213d00000000020300190000002401100370000000000301043b000c00000003001d0000000001000411000b00000002001d28fd23150000040f0000000c0100002928fd20040000040f0000000003010019000a00000001001d00000000010004110000000b020000290000000c0400002928fd236d0000040f000000400100043d0000000a02000029000008a00000013d000000640030008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000402100370000000000202043b00000a430020009c000000580000213d00000000040200190000002402100370000000000202043b000c00000002001d00000a430020009c000000580000213d0000004401100370000000000501043b00000ad201000041000000000101041a000000000001004b00000000030000190000088f0000613d00000ad302000041000000000202041a00000ad403000041000000000303041a000000000023001a00000bb90000413d000000000223001900000ad503000041000000000303041a000000000023001a00000bb90000413d000000000223001a0000088b0000613d00000b6103200129000000000053004b000000580000413d00000000025200a900000000131200d9000000000001004b000000010330c039000a00000005001d00000000020004110000000001040019000900000004001d000b00000003001d28fd21c40000040f00000009010000290000000c020000290000000a0300002928fd23150000040f00000009010000290000000c020000290000000b030000290000000a0400002928fd236d0000040f000000400100043d0000000b02000029000000000021043500000a400010009c00000a4001008041000000400110021000000ab5011001c7000028fe0001042e000000440030008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000402100370000000000202043b000c00000002001d00000a430020009c000000580000213d0000002401100370000000000101043b000b00000001001d00000a430010009c000000580000213d00000ae801000041000000000101041a00000a43021001970000000001000411000000000012004b00000b570000c13d0000000b0000006b00000c860000c13d00000ae501000041000000800010043f00000ace01000041000028ff00010430000000640030008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000402100370000000000202043b000c00000002001d00000a430020009c000000580000213d0000004401100370000000000101043b00000a460010009c000000580000213d00000004011000390000000b0200002928fd1db00000040f000a00000001001d000900000002001d000000400100043d000b00000001001d28fd1e0a0000040f0000000b0200002900000020012000390000000000010435000000000002043500000024010000390000000101100367000000000201043b000000400100043d000b00000001001d00000020011000390000000c0300002928fd1eb50000040f0000000b030000290000000002310049000000200120008a0000000000130435000000000103001928fd1e150000040f0000000001000412001200000001001d001100200000003d000080050100003900000044030000390000000004000415000000120440008a000009550000013d000000640030008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000402100370000000000202043b000c00000002001d00000a400020009c000000580000213d0000004401100370000000000101043b000b00000001001d00000a460010009c000000580000213d28fd206a0000040f0000000c0100002928fd1ebe0000040f00000024020000390000000102200367000000000202043b000000000020043f000000200010043f0000004002000039000000000100001928fd28c00000040f000000000201041a00000b05022001970000000b022001af000000000021041b0000000001000019000028fe0001042e000000240030008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000401100370000000000101043b00000ae802000041000000000202041a00000a43032001970000000002000411000000000023004b00000b520000c13d00000b400010009c00000b9c0000413d00000b4201000041000000800010043f00000ace01000041000028ff00010430000000440030008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000402100370000000000202043b000c00000002001d00000a430020009c000000580000213d0000002401100370000000000101043b00000a460010009c000000580000213d00000004011000390000000b0200002928fd1db00000040f000a00000001001d000900000002001d000000400100043d000b00000001001d28fd1e0a0000040f0000000b020000290000002001200039000000000001043500000000000204350000000c0100002928fd1e380000040f000000000301041a0000000101100039000000000401041a000000400100043d000b00000001001d00000020011000390000000c0200002928fd20290000040f0000000b030000290000000002310049000000200120008a0000000000130435000000000103001928fd1e150000040f0000000001000412000e00000001001d000d00200000003d0000800501000039000000440300003900000000040004150000000e0440008a000000050440021000000add0200004128fd28d50000040f000c00000001001d0000000a02000029000000090300002928fd1f0b0000040f00000000030100190000000c010000290000000b0200002928fd20c70000040f0000000002010019000000400100043d000c00000001001d28fd1de70000040f00000bd30000013d0000000001000416000000000001004b000000580000c13d28fd26740000040f00000b320000013d000001440030008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000402100370000000000202043b000c00000002001d00000a430020009c000000580000213d0000002402100370000000000202043b000a00000002001d00000a430020009c000000580000213d0000004402100370000000000202043b00000a430020009c000000580000213d0000006402100370000000000202043b00000a430020009c000000580000213d0000008402100370000000000202043b00000a430020009c000000580000213d000000a402100370000000000202043b000900000002001d00000a430020009c000000580000213d000000c402100370000000000202043b000800000002001d00000a430020009c000000580000213d000000e402100370000000000202043b00000a430020009c000000580000213d0000010402100370000000000402043b00000a460040009c000000580000213d00000023024000390000000b0020006c000000580000813d0000000405400039000000000251034f000000000202043b00000a460020009c00000cbd0000213d0000001f0320003900000b60033001970000003f0330003900000b600330019700000adc0030009c00000cbd0000213d00000024044000390000008003300039000000400030043f000000800020043f00000000034200190000000b0030006c000000580000213d0000002003500039000000000531034f00000b60062001980000001f0720018f000000a004600039000009b80000613d000000a008000039000000000905034f000000009309043c0000000008380436000000000048004b000009b40000c13d000000000007004b000009c50000613d000000000365034f0000000305700210000000000604043300000000065601cf000000000656022f000000000303043b0000010005500089000000000353022f00000000035301cf000000000363019f0000000000340435000000a00220003900000000000204350000012402100370000000000402043b00000a460040009c000000580000213d00000023024000390000000b0020006c000000580000813d0000000405400039000000000251034f000000000202043b00000a460020009c00000cbd0000213d0000001f0320003900000b60033001970000003f0330003900000b6003300197000000400700043d0000000006370019000700000007001d000000000076004b0000000003000039000000010300403900000a460060009c00000cbd0000213d000000010030019000000cbd0000c13d0000002403400039000000400060043f00000007040000290000000004240436000600000004001d00000000033200190000000b0030006c000000580000213d0000002003500039000000000331034f00000b60042001980000001f0520018f0000000601400029000009f50000613d000000000603034f0000000607000029000000006806043c0000000007870436000000000017004b000009f10000c13d000000000005004b00000a020000613d000000000343034f0000000304500210000000000501043300000000054501cf000000000545022f000000000303043b0000010004400089000000000343022f00000000034301cf000000000353019f00000000003104350000000601200029000000000001043500000a4401000041000000000101041a000b00000001001d00000a46011001980000157c0000613d000000010010008c0000158e0000c13d00000acf01000041000000000010044300000000010004100000000400100443000000000100041400000a400010009c00000a4001008041000000c00110021000000ad0011001c7000080020200003928fd28f80000040f000000010020019000001da20000613d000000000101043b000000000001004b0000158e0000c13d0000000b0100002900050a450010019b000015800000013d000000240030008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000401100370000000000101043b00000a430010009c000000580000213d28fd1e270000040f000000000101041a000000ff0010019000000ae20000013d000000240030008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000401100370000000000101043b00000a430010009c000000580000213d28fd1e5a0000040f000000000101041a00000b320000013d000000e40030008c000000580000413d0000008402100370000000000202043b000c00000002001d00000a460020009c000000580000213d0000000c0200002900000023022000390000000b0020006c000000580000813d0000000c02000029000900040020003d0000000902100360000000000202043b000a00000002001d00000a460020009c000000580000213d0000000c020000290000002403200039000800000003001d0000000a02300029000700000002001d0000000b0020006c000000580000213d000000a402100370000000000202043b00000a430020009c000000580000213d000000c402100370000000000202043b00000a460020009c000000580000213d00000023032000390000000b0030006c000000580000813d0000000403200039000000000131034f000000000101043b00000a460010009c000000580000213d000000000112001900000024011000390000000b0010006c000000580000213d00000add010000410000000000100443000000000100041200000004001004430000002400000443000000000100041400000a400010009c00000a4001008041000000c00110021000000ade011001c7000080050200003928fd28f80000040f000000010020019000001da20000613d0000000002000411000000000101043b00000a4301100197000000000021004b000011570000c13d00000004010000390000000101100367000000000101043b000b00000001001d00000a400010009c000000580000213d0000000b01000029000000000010043f00000b4701000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000000101043b000000000101041a000600000001001d000000000001004b0000128d0000c13d000000400100043d00000b5a02000041000000000021043500000004021000390000000b03000029000001830000013d000000440030008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000402100370000000000202043b000c00000002001d00000a430020009c000000580000213d0000002401100370000000000301043b00000ae801000041000000000101041a00000a43021001970000000001000411000000000012004b00000b570000c13d000000000003004b00000c4a0000c13d00000ae601000041000000800010043f00000ace01000041000028ff000104300000000001000416000000000001004b000000580000c13d00000aec0100004100000ab60000013d0000000001000416000000000001004b000000580000c13d00000ad201000041000000000101041a000000800010043f00000afb01000041000028fe0001042e0000000001000416000000000001004b000000580000c13d0000000b0100002928fd1ded0000040f000b00000001001d000c00000002001d000a00000003001d000000000200041128fd21c40000040f0000000b010000290000000c020000290000000a0300002900000ad40000013d000000440030008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000402100370000000000202043b00000a430020009c000000580000213d0000002401100370000000000301043b000000000100041128fd222c0000040f000000010100003900000b320000013d000000240030008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000401100370000000000101043b00000a430010009c000000580000213d28fd22f80000040f000000000001004b0000000001000039000000010100c03900000b320000013d000000240030008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000401100370000000000101043b000c00000001001d00000a430010009c000000580000213d28fd206a0000040f0000000c0100002928fd23b60000040f0000000001000019000028fe0001042e0000000001000416000000000001004b000000580000c13d000000000100041100000a4301100197000000000010043f00000b3c01000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000000101043b000000000101041a000000ff0010019000000b0f0000c13d00000ae801000041000000000101041a0000000002000411000000000121013f00000a4300100198000019200000c13d000000400100043d00000ab702000041000000000302041a000000ff0030019000000ba60000c13d00000b4602000041000015900000013d0000000001000416000000000001004b000000580000c13d0000000001000410000000800010043f00000afb01000041000028fe0001042e000000440030008c000000580000413d0000000002000416000000000002004b000000580000c13d0000000401100370000000000101043b00000a400010009c000000580000213d28fd1ebe0000040f00000024020000390000000102200367000000000202043b000000000020043f000000200010043f0000004002000039000000000100001928fd28c00000040f000000000101041a00000a460110019728fd1ecf0000040f000000400200043d000000000012043500000a400020009c00000a4002008041000000400120021000000ab5011001c7000028fe0001042e000000840030008c000000580000413d0000000402100370000000000202043b000c00000002001d00000a430020009c000000580000213d0000002402100370000000000202043b000b00000002001d0000006401100370000000000101043b000000000001004b0000000002000039000000010200c039000000000021004b000000580000c13d00000ab601000041000000000201041a000000020020008c00000bdd0000c13d00000ae701000041000000800010043f00000ace01000041000028ff0001043000000ae901000041000000800010043f000000840020043f00000aea01000041000028ff0001043000000ae902000041000000800020043f000000840010043f00000aea01000041000028ff0001043000000b3601000041000000800010043f0000002001000039000000840010043f0000001501000039000000a40010043f00000b3701000041000000c40010043f00000b3801000041000028ff00010430000000800010043f000000000003004b00000b7d0000613d00000b0902000041000000000020043f000000000001004b00000ba40000613d00000b0b0200004100000000040000190000000003040019000000000402041a000000a005300039000000000045043500000001022000390000002004300039000000000014004b00000b6f0000413d00000bc90000013d00000ae901000041000000800010043f000000840050043f00000aea01000041000028ff0001043000000b5f02200197000000a00020043f000000000001004b000000c001000039000000a00100603900000bca0000013d00000ad303000041000000000503041a00000ad403000041000000000303041a0000000003530019000000000004004b00000bb70000c13d000000000053004b00000bb90000413d00000ad504000041000000000404041a000000000034001a00000bb90000413d000000000334001a00000b950000613d00000b6104300129000000000024004b000000580000413d00000000022300a900000000131200d9000000000001004b000000010330c039000000800030043f00000afb01000041000028fe0001042e00000b4102000041000000000012041b0000000001000019000028fe0001042e00000b0d03000041000000000030043f000000020020008c00000bbf0000813d000000a00100003900000bca0000013d00000b5f03300197000000000032041b0000000002000411000000000021043500000a400010009c00000a40010080410000004001100210000000000200041400000a400020009c00000a4002008041000000c002200210000000000112019f00000a47011001c70000800d02000039000000010300003900000b450400004100000cab0000013d000000000053004b00000c780000813d00000b5501000041000000000010043f0000001101000039000000040010043f00000ac801000041000028ff0001043000000b0f0200004100000000040000190000000003040019000000000402041a000000a005300039000000000045043500000001022000390000002004300039000000000014004b00000bc10000413d000000c001300039000000800210008a000000800100003928fd1e150000040f0000002001000039000000400200043d000c00000002001d0000000002120436000000800100003928fd1dca0000040f0000000c02000029000000000121004900000a400010009c00000a4001008041000000600110021000000a400020009c00000a40020080410000004002200210000000000121019f000028fe0001042e0000000202000039000000000021041b00000ab701000041000000000101041a000000ff0010019000000c6e0000c13d0000000b0000006b00000aa90000613d0000000c01000029000000000010043f00000ab801000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000000101043b000900000001001d0000000401100039000000000101041a00000a430010019800000f4f0000613d000000400100043d000a00000001001d0000000c0100002900000aba0010009c000010df0000c13d0000000b0200002900000ac001000041000000000301041a0000000a04000029000a00000004001d0000002401400039000000000021043500000ac101000041000000000014043500000004014000390000000c02000029000000000021043500000a400040009c00000a400100004100000000010440190000004001100210000000000200041400000a400020009c00000a4002008041000000c002200210000000000112019f00000abd011001c700000a430230019728fd28f80000040f000000600310027000000a4003300197000000200030008c000000200400003900000000040340190000001f0640018f00000020074001900000000a0570002900000c240000613d000000000801034f0000000a09000029000000008a08043c0000000009a90436000000000059004b00000c200000c13d000000000006004b00000c310000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000011440000613d0000001f01400039000000600210018f0000000a01200029000000000021004b0000000002000039000000010200403900000a460010009c00000cbd0000213d000000010020019000000cbd0000c13d000000400010043f000000200030008c000000580000413d0000000a02000029000000000302043300000044020000390000000102200367000000000202043b000a00000003001d000000000023004b000012720000813d00000acc02000041000015900000013d000b00000003001d0000000c01000029000000000010043f00000ab801000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000000101043b00000002011000390000000b03000029000000000031041b000000400100043d000000200210003900000000003204350000000c02000029000000000021043500000a400010009c00000a40010080410000004001100210000000000200041400000a400020009c00000a4002008041000000c002200210000000000112019f00000ab9011001c70000800d02000039000000010300003900000b350400004100000cab0000013d00000acd01000041000000800010043f00000ace01000041000028ff0001043000000b5f02200197000000a00020043f000000000001004b0000002002000039000000000200603900000cb90000013d00000ad504000041000000000404041a000000000034001a00000bb90000413d000000000334001a00000c810000613d00000b6104300129000000000024004b000000580000413d00000000022300a900000000031200d9000000800030043f00000afb01000041000028fe0001042e0000000c01000029000000000010043f00000ab801000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000000101043b0000000401100039000000000201041a00000afc022001970000000b03000029000000000232019f000000000021041b000000400100043d000000200210003900000000003204350000000c02000029000000000021043500000a400010009c00000a40010080410000004001100210000000000200041400000a400020009c00000a4002008041000000c002200210000000000112019f00000ab9011001c70000800d02000039000000010300003900000afd0400004128fd28f30000040f0000000100200190000000580000613d0000000001000019000028fe0001042e00000b14030000410000000002000019000000000403041a000000a005200039000000000045043500000001033000390000002002200039000000000012004b00000cb20000413d0000003f0120003900000b600210019700000adc0020009c00000cc30000a13d00000b5501000041000000000010043f0000004101000039000000040010043f00000ac801000041000028ff000104300000008001200039000000400010043f00000b1603000041000000000403041a000000010540019000000001034002700000007f0330618f0000001f0030008c00000000060000390000000106002039000000000664013f00000001006001900000070c0000c13d0000000000310435000000a002200039000000000005004b00000e390000613d00000b1604000041000000000040043f000000000003004b000000000400001900000e3e0000613d00000b180500004100000000040000190000000006240019000000000705041a000000000076043500000001055000390000002004400039000000000034004b00000cdb0000413d00000e3e0000013d0000000c01000029000000000010043f00000aef01000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000000101043b000000000201041a0000000103200039000000000031041b000000400100043d000000c0031000390000000a040000290000000000430435000000a003100039000000000023043500000080021000390000000903000029000000000032043500000060021000390000000b03000029000000000032043500000040021000390000000c030000290000000000320435000000c002000039000000000221043600000af003000041000000000032043500000af10010009c00000cbd0000213d000000e003100039000000400030043f00000a400020009c00000a40020080410000004002200210000000000101043300000a400010009c00000a40010080410000006001100210000000000121019f000000000200041400000a400020009c00000a4002008041000000c002200210000000000112019f00000af2011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000000101043b000a00000001001d28fd26740000040f00000af302000041000000400300043d00000000002304350000000202300039000000000012043500000022013000390000000a0200002900000000002104350000000101000367000000c402100370000000000202043b000a00000002001d000000a401100370000000000101043b000700000001001d00000a400030009c00000a40030080410000004001300210000000000200041400000a400020009c00000a4002008041000000c002200210000000000121019f00000af4011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000400200043d0000000a0300002900000af50030009c0000117e0000a13d00000af901000041000000000012043500000004012000390000000a03000029000000000031043500000a400020009c00000a4002008041000000400120021000000ac8011001c7000028ff000104300000000c02000029000500440020003d0000000007000019000000080600002900000d5e0000013d000000030140021000000b610110027f00000b610210016700000001010003670000000b03100360000000000303043b000000000223016f0000000103400210000000000232019f0000000806000029000000070700002900000000002a041b0000000107700039000000090070006c000011400000813d000700000007001d00000005027002100000000009620019000000000291034f000000000202043b00000000030000310000000c0430006a000000830440008a00000b030540019700000b0306200197000000000756013f000000000056004b000000000500001900000b0305004041000000000042004b000000000400001900000b030400804100000b030070009c000000000504c019000000000005004b000000580000c13d00000008022000290000004004200039000000000441034f000000000404043b00000000052300490000001f0550008a00000b030650019700000b0307400197000000000867013f000000000067004b000000000600001900000b0306004041000000000054004b000000000500001900000b030500804100000b030080009c000000000605c019000000000006004b000000580000c13d0000000004240019000000000541034f000000000705043b00000a460070009c000000580000213d000000020070008c000000580000413d00000000037300490000002005400039000000000035004b000000000400001900000b030400204100000b0303300197000b00000005001d00000b0305500197000000000635013f000000000035004b000000000300001900000b030300404100000b030060009c000000000304c019000000000003004b000000580000c13d0000000b03100360000000000303043b00000b010330019700000b020030009c0000112b0000c13d000000000121034f000000000101043b00000a400010009c000000580000213d000000000010043f00000aff01000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c70000801002000039000a00000007001d000600000009001d28fd28f80000040f00000006030000290000000100200190000000580000613d0000000102000367000000000332034f000000000303043b0000000c040000290000000004400079000000830440008a00000b030530019700000b0306400197000000000765013f000000000065004b000000000500001900000b0305004041000000000043004b000000000400001900000b030400804100000b030070009c000000000504c019000000000101043b000000000005004b000000580000c13d0000000503300029000000000232034f000000000202043b0000ffff0020008c000000580000213d000000000020043f000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000a040000290000000100200190000000580000613d000000000a01043b00000000010a041a000000010010019000000001031002700000007f0330618f0000001f0030008c00000000020000390000000102002039000000000121013f00000001001001900000070c0000c13d000000200030008c00060000000a001d00000e050000413d000400000003001d0000000000a0043f000000000100041400000a400010009c00000a4001008041000000c00110021000000a47011001c7000080100200003928fd28f80000040f0000000a040000290000000100200190000000580000613d0000001f024000390000000502200270000000200040008c0000000002004019000000000301043b00000004010000290000001f01100039000000050110027000000000011300190000000002230019000000000012004b000000060a00002900000e050000813d000000000002041b0000000102200039000000000012004b00000e010000413d0000001f0040008c00000d4f0000a13d0000000000a0043f000000000100041400000a400010009c00000a4001008041000000c00110021000000a47011001c7000080100200003928fd28f80000040f0000000a080000290000000100200190000000580000613d000000000301034f00000b60048001980000000101000367000000000203043b000000000300001900000e320000613d000000080600002900000007070000290000000b09000029000000060a0000290000000005930019000000000551034f000000000505043b000000000052041b00000001022000390000002003300039000000000043004b00000e1c0000413d000000000084004b00000e2f0000813d0000000304800210000000f80440018f00000b610440027f00000b61044001670000000003930019000000000331034f000000000303043b000000000343016f000000000032041b000000010280021000000001022001bf00000d5a0000013d000000080600002900000007070000290000000b09000029000000060a000029000000000084004b00000e260000413d00000e2f0000013d00000b5f044001970000000000420435000000000003004b00000020040000390000000004006039000000000312004900000000034300190000001f0330003900000b60033001970000000004130019000000000034004b00000000030000390000000103004039000c00000004001d00000a460040009c00000cbd0000213d000000010030019000000cbd0000c13d0000000c03000029000000400030043f00000b390030009c00000cbd0000213d0000000c040000290000002003400039000800000003001d000000400030043f0000000000040435000000400500043d0000002003500039000000e004000039000000000043043500000b3a030000410000000000350435000000e004500039000000800300043d0000000000340435000b00000005001d0000010004500039000000000003004b00000e690000613d00000000050000190000000006450019000000a007500039000000000707043300000000007604350000002005500039000000000035004b00000e620000413d000000000543001900000000000504350000001f0330003900000b600330019700000000034300190000000b0500002900000000045300490000004005500039000000000045043500000000060104330000000005630436000000000006004b00000e7e0000613d000000000100001900000000035100190000000004120019000000000404043300000000004304350000002001100039000000000061004b00000e770000413d000a00000005001d000900000006001d0000000001560019000000000001043500000b3b010000410000000000100443000000000100041400000a400010009c00000a4001008041000000c00110021000000aee011001c70000800b0200003928fd28f80000040f000000010020019000001da20000613d000000000101043b0000000b040000290000008002400039000000000300041000000000003204350000006002400039000000000012043500000009010000290000001f0110003900000b60011001970000000a011000290000000002410049000000c0034000390000000000230435000000a00240003900000000000204350000000c0200002900000000020204330000000001210436000000000002004b00000ea90000613d00000000030000190000000805000029000000005405043400000000014104360000000103300039000000000023004b00000ea40000413d0000000b0200002900000bd40000013d0000000b040000290000000c0340006a000000830330008a0007004300400092000000000603001900000b0307300197000000000a000019000000080400002900000ebd0000013d0000001f03c0003900000b600330019700000000048c00190000000000040435000000000b8300190000002004500039000000010aa000390000000900a0006c000002070000813d0000000a03b0006a000000400330008a0000000002320436000000000341034f000000000c03043b00000b0303c00197000000000873013f000000000073004b000000000300001900000b030300204100000000006c004b000000000d00001900000b030d00404100000b030080009c00000000030dc019000000000003004b000000580000613d0000000c0cc000290000002403c00039000000000831034f000000000808043b00000a400080009c000000580000213d00000000088b04360000002003300039000000000d31034f000000000d0d043b0000ffff00d0008c000000580000213d00000000050400190000000000d804350000000708c000690000002003300039000000000331034f000000000d03043b00000b030380019700000b030ed00197000000000f3e013f00000000003e004b000000000300001900000b030300404100000000008d004b000000000800001900000b030800804100000b0300f0009c000000000308c019000000000003004b000000580000c13d0000000003cd0019000000240d3000390000000008d1034f000000000c08043b00000a4600c0009c000000580000213d00000044033000390000000b08c00069000000000083004b000000000e00001900000b030e00204100000b030880019700000b0303300197000000000f83013f000000000083004b000000000300001900000b030300404100000b0300f0009c00000000030ec019000000000003004b000000580000c13d0000004003b00039000000600400003900000000004304350000006003b000390000000000c304350000002003d00039000000000331034f00000b600fc001980000008008b00039000000000df8001900000f130000613d000000000e03034f000000000b08001900000000e40e043c000000000b4b04360000000000db004b00000f0f0000c13d0000001f0bc0019000000eb40000613d0000000003f3034f0000000304b00210000000000b0d0433000000000b4b01cf000000000b4b022f000000000303043b0000010004400089000000000343022f00000000034301cf0000000003b3019f00000000003d043500000eb40000013d00000060061002700000001f0460018f00000a4205600198000000400200043d000000000352001900000f2d0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b00000f290000c13d00000a4006600197000000000004004b00000f3b0000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f00000000001304350000006001600210000011760000013d0000000c01000029000000000010043f00000ab801000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000000101043b0000000402100039000000000202041a00070a430020019c00000f520000c13d000000400100043d00000b5d02000041000015900000013d000000000201041a000b00000002001d000000000002004b000010dc0000613d0000000202100039000000000202041a0000000b0020006b000010dc0000413d0000000b030000290000000a0330006c000010dc0000413d0000000102100039000000000402041a0000000a054000b9000000000004004b00000f650000613d00000000064500d90000000a0060006b00000bb90000c13d000000000031041b0006000b00500102000000060140006c00000bb90000413d000000000012041b000000400100043d0000002002100039000000060300002900000000003204350000000a02000029000000000021043500000a400010009c00000a40010080410000004001100210000000000200041400000a400020009c00000a4002008041000000c002200210000000000112019f00000ab9011001c70000800d02000039000000020300003900000b2a040000410000000c0500002928fd28f30000040f0000000100200190000000580000613d000000400100043d00000b2b0010009c00000cbd0000213d0000006002100039000000400020043f000000200210003900000000000204350000000000010435000000400200043d00000ae20020009c00000cbd0000213d0000004003200039000000400030043f0000002003200039000000000003043500000000000204350000004001100039000000000021043500000ab601000041000000000201041a000000020020008c000012960000613d0000000202000039000000000021041b00000ab701000041000000000101041a000000ff00100190000010d90000c13d00000add0100004100000000001004430000000001000412000000040010044300000020010000390000002400100443000000000100041400000a400010009c00000a4001008041000000c00110021000000ade011001c7000080050200003928fd28f80000040f000000010020019000001da20000613d000000000101043b000c00000001001d000000400300043d00000080013000390000000602000029000000000021043500000060013000390000000a02000029000000000021043500000040013000390000000702000029000000000021043500000020013000390000000502000039000000000021043500000080010000390000000000130435000500000003001d00000b2c0030009c00000cbd0000213d0000000501000029000000a001100039000000400010043f0000000c010000290000000802000029000000090300002928fd1f0b0000040f000000400400043d00000ae20040009c00000cbd0000213d00000000030100190000004001400039000000400010043f00000064010000390000000101100367000000000101043b000000000114043600000000000104350000000c010000290000000502000029000000000500041128fd23e80000040f000c00000001001d00000adf01000041000000000201041a000000010020003a00000bb90000413d0000000102200039000900000002001d000000000021041b0000000c010000290000000001010433000000000010043f00000b2d01000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000000101043b0000000902000029000000000021041b000000000020043f00000ae101000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000000101043b0000000603000029000000000031041b00000ad501000041000000000201041a000000000032001a00000bb90000413d0000000602200029000000000021041b00000ad401000041000000000201041a000000060220006c00000bb90000413d000000000021041b00000b2e01000041000000400200043d000900000002001d000000000012043500000add010000410000000000100443000000000100041200000004001004430000002400000443000000000100041400000a400010009c00000a4001008041000000c00110021000000ade011001c7000080050200003928fd28f80000040f000000010020019000001da20000613d000000000201043b000000090100002900000a400010009c00000a40010080410000004001100210000000000300041400000a400030009c00000a4003008041000000c003300210000000000113019f00000abf011001c700000a430220019728fd28f80000040f000000600310027000000a4003300197000000200030008c000000200400003900000000040340190000001f0640018f00000020074001900000000905700029000010360000613d000000000801034f0000000909000029000000008a08043c0000000009a90436000000000059004b000010320000c13d000000000006004b000010430000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000017860000613d0000001f01400039000000600210018f0000000901200029000000000021004b0000000002000039000000010200403900000a460010009c00000cbd0000213d000000010020019000000cbd0000c13d000000400010043f000000200030008c000000580000413d0000000902000029000000000302043300000a400030009c000000580000213d0000000c020000290000000002020433000000a0041000390000000605000029000000000054043500000080041000390000000a0500002900000000005404350000006004100039000000070500002900000000005404350000004004100039000000000024043500000020021000390000000000320435000000a003000039000000000031043500000b2f0010009c00000cbd0000213d000000c003100039000900000003001d000000400030043f000000e00410003900000b3003000041000c00000004001d0000000000340435000000e403100039000000200400003900000000004304350000010404100039000000000301043300000000003404350000012401100039000000000003004b000010810000613d000000000400001900000000051400190000000006240019000000000606043300000000006504350000002004400039000000000034004b0000107a0000413d000000000113001900000000000104350000001f0130003900000b6001100197000000440210003900000009030000290000000000230435000000830110003900000b60021001970000000001320019000000000021004b0000000002000039000000010200403900000a460010009c00000cbd0000213d000000010020019000000cbd0000c13d000000400010043f00000b2201000041000000000101041a000800000001001d00000b2001000041000000000101041a00000acf02000041000000000020044300000a4301100197000700000001001d0000000400100443000000000100041400000a400010009c00000a4001008041000000c00110021000000ad0011001c7000080020200003928fd28f80000040f000000010020019000001da20000613d000000000101043b000000000001004b000000580000613d000000080100002900000a4301100197000000400400043d00000024024000390000004003000039000000000032043500000b31020000410000000000240435000000040240003900000000001204350000000901000029000000000101043300000044024000390000000000120435000900000004001d0000006402400039000000000001004b000010c30000613d000000000300001900000000042300190000000c05300029000000000505043300000000005404350000002003300039000000000013004b000010bc0000413d0000001f0310003900000b600330019700000000012100190000000000010435000000640130003900000a400010009c00000a40010080410000006001100210000000090200002900000a400020009c00000a40020080410000004002200210000000000121019f000000000200041400000a400020009c00000a4002008041000000c002200210000000000112019f0000000a0000006b000018380000c13d00000007020000290000183d0000013d000000400100043d00000acd02000041000015900000013d000000400100043d00000b5c02000041000015900000013d00000abb01000041000000000201041a0000000a0400002900000024014000390000000b03000029000000000031043500000abc010000410000000001140436000b00000001001d00000004014000390000000c03000029000000000031043500000a400040009c00000a400100004100000000010440190000004001100210000000000300041400000a400030009c00000a4003008041000000c003300210000000000113019f00000abd011001c700000a430220019728fd28f80000040f000000600310027000000a4003300197000000400030008c000000400400003900000000040340190000001f0640018f00000060074001900000000a05700029000011060000613d000000000801034f0000000a09000029000000008a08043c0000000009a90436000000000059004b000011020000c13d000000000006004b000011130000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f000000000065043500000001002001900000115d0000613d0000001f01400039000000e00210018f0000000a01200029000000000021004b0000000002000039000000010200403900000a460010009c00000cbd0000213d000000010020019000000cbd0000c13d000000400010043f000000400030008c000000580000413d0000000a0200002900000000030204330000000b020000290000000002020433000b00000003001d000000000032004b000012990000a13d00000abe02000041000015900000013d000000400300043d000c00000003001d00000b0001000041000000000013043500000004013000390000002002000039000000000021043500000024033000390000000b01000029000000000207001928fd1eda0000040f0000000c02000029000000000121004900000a400010009c00000a400100804100000a400020009c00000a400200804100000060011002100000004002200210000000000121019f000028ff00010430000b000000000035000000400200043d000a00000002001d000001fe0000013d0000001f0530018f00000a4206300198000000400200043d0000000004620019000011680000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b0000114b0000c13d000011680000013d00000b5f01200197000000060200002900000000001204350000000c0000006b00000020010000390000000001006039000011c30000013d000000400100043d00000b4a03000041000000000031043500000004031000390000000000230435000001840000013d0000001f0530018f00000a4206300198000000400200043d0000000004620019000011680000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000011640000c13d000000000005004b000011750000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f0000000000140435000000600130021000000a400020009c00000a40020080410000004002200210000000000112019f000028ff00010430000000400100043d00000ad102000041000015900000013d000000000101043b00000060032000390000000a0400002900000000004304350000004003200039000000070400002900000000004304350000002003200039000000080400002900000000004304350000000000120435000000000000043f00000a400020009c00000a40020080410000004001200210000000000200041400000a400020009c00000a4002008041000000c002200210000000000112019f00000af6011001c7000000010200003928fd28f80000040f000000600310027000000a4003300197000000200030008c000000200400003900000000040340190000001f0540018f0000002004400190000011a30000613d000000000601034f0000000007000019000000006806043c0000000007870436000000000047004b0000119f0000c13d000000000005004b000011b00000613d000000000641034f0000000305500210000000000704043300000000075701cf000000000757022f000000000606043b0000010005500089000000000656022f00000000055601cf000000000575019f00000000005404350000000100200190000012660000613d000000000100043d00000a43011001980000129b0000c13d000000400100043d00000af802000041000015900000013d000000000201043b000000000100001900000006050000290000000c060000290000000003510019000000000402041a000000000043043500000001022000390000002001100039000000000061004b000011bc0000413d0000003f0210003900000b60022001970000000b03200029000000000023004b0000000002000039000000010200403900000a460030009c00000cbd0000213d000000010020019000000cbd0000c13d000000000a030019000000400030043f0000000b020000290000000002020433000000000002004b000012000000c13d0000000a020000290000001f0220003900000b60022001970000003f0220003900000b600220019700000000022a001900000a460020009c00000cbd0000213d000000400020043f0000000a0200002900000000022a04360000000704000029000000000040007c000000580000213d0000000a0400002900000b60034001980000001f0440018f0000000001320019000000090500002900000020055000390000000105500367000011ef0000613d000000000605034f0000000007020019000000006806043c0000000007870436000000000017004b000011eb0000c13d000000000004004b000011fc0000613d000000000335034f0000000304400210000000000501043300000000054501cf000000000545022f000000000303043b0000010004400089000000000343022f00000000034301cf000000000353019f00000000003104350000000a012000290000000000010435000000400200043d000012e80000013d0000000a0000006b000012a30000613d0000000a03000029000000010030008c000012a60000c13d00000b0001000041000c0000000a001d00000000001a04350000000401a00039000000200200003900000000002104350000002403a0003900000001020000390000000801000029000011350000013d00000ad301000041000000000101041a00000ad402000041000000000202041a000000000012001a00000bb90000413d000000000112001900000ad502000041000000000202041a000000000012001a00000bb90000413d000000000112001a000b00000000001d000012290000613d00000ad202000041000000000202041a000000000002004b000012240000613d00000b6103200129000000090030006c000000580000413d00000009022000b900000000121200d9000000000001004b000000010220c039000b00000002001d00000ad601000041000000000101041a00000acf02000041000000000020044300000a4301100197000600000001001d0000000400100443000000000100041400000a400010009c00000a4001008041000000c00110021000000ad0011001c7000080020200003928fd28f80000040f000000010020019000001da20000613d000000000101043b000000000001004b000000580000613d000000400300043d00000064013000390000000b02000029000000000021043500000ad7010000410000000000130435000000240130003900000000020004100000000000210435000000040130003900000000002104350000004401300039000000000001043500000a400030009c000500000003001d00000a400100004100000000010340190004004000100218000000000100041400000a400010009c00000a4001008041000000c00110021000000004011001af00000ad8011001c7000000060200002928fd28f30000040f0000000100200190000014fb0000613d000000050100002900000a460010009c00000cbd0000213d0000000501000029000000400010043f0000000001000411000000000001004b000015670000c13d00000ae50100004100000005020000290000000000120435000000040100002900000abf011001c7000028ff000104300000001f0530018f00000a4206300198000000400200043d0000000004620019000011680000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b0000126d0000c13d000011680000013d000000200310003900000000002304350000000b02000029000000000021043500000a400010009c00000a40010080410000004001100210000000000200041400000a400020009c00000a4002008041000000c002200210000000000112019f00000ab9011001c70000800d02000039000000020300003900000ac2040000410000000c0500002928fd28f30000040f0000000100200190000000580000613d00000000010004160000000c0200002900000aba0020009c000013140000c13d0000000b0010006b0000131b0000613d0000132b0000013d00000001010003670000002402100370000000000202043b000000060020006b000012ed0000c13d00000ab602000041000000000302041a000000020030008c0000132e0000c13d000000400100043d00000ae702000041000015900000013d000a00000001001d00000bfe0000013d0000000c0010006c000012fd0000c13d0000000c010000290000000b02000029000000090300002928fd262e0000040f0000000001000019000028fe0001042e00000000020a00190000000b0a000029000012e80000013d000000090300002900000020043000390000000103000367000000000543034f000000000505043b00000b010550019700000b020050009c0000130a0000c13d0000002005a000390000000006000019000000060900002900000000075600190000000008690019000000000808043300000000008704350000002006600039000000000026004b000012b10000413d0000000204400039000000000443034f000000000352001900000000000304350000000002a200190000000a03000029000000020330008a00000b60053001980000001f0630018f00000020072000390000000003570019000012c90000613d000000000804034f000000008908043c0000000007970436000000000037004b000012c50000c13d000000000006004b000012d60000613d000000000454034f0000000305600210000000000603043300000000065601cf000000000656022f000000000404043b0000010005500089000000000454022f00000000045401cf000000000464019f00000000004304350000000a022000290000001e0320003900000000000304350000000002a20049000000020320008a00000000003a04350000003d0220003900000b60012001970000000003a10019000000000013004b0000000001000039000000010100403900000a460030009c00000cbd0000213d000000010010019000000cbd0000c13d0000000002030019000000400030043f0000002001000039000c00000002001d000000000212043600000000010a001900000bd20000013d0000000401100370000000000101043b00000a400010009c000000580000213d000000400300043d0000002404300039000000000024043500000b4b0200004100000000002304350000000402300039000000000012043500000a400030009c00000a4003008041000000400130021000000abd011001c7000028ff00010430000000400200043d00000024032000390000000c04000029000000000043043500000af70300004100000000003204350000000403200039000000000013043500000a400020009c00000a4002008041000000400120021000000abd011001c7000028ff0001043000000b0001000041000c0000000a001d00000000001a04350000000401a00039000000200200003900000000002104350000002403a0003900000008010000290000000a02000029000011350000013d000000000001004b0000132b0000c13d000000000200041100000000030004100000000c010000290000000b0400002928fd27500000040f0000000901000029000000000101041a0000000b0010002a00000bb90000413d0000000b011000290000000902000029000000000012041b0000000302200039000000000202041a000000000002004b000015080000613d000000000021004b000015080000a13d000000400100043d00000acb02000041000015900000013d000000400100043d00000ac302000041000015900000013d0000000203000039000000000032041b0000000402100370000000000202043b000b00000002001d00000a400020009c000000580000213d0000004401100370000000000101043b000500000001001d00000a460010009c000000580000213d0000000b01000029000000000010043f00000b4c01000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000000101043b0000000602000029000000000020043f000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000000101043b000000000101041a00000a460110019700000a460010009c00000bb90000613d0000000101100039000000050010006b000016670000c13d0000000b01000029000000000010043f00000b4c01000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000000101043b0000000602000029000000000020043f000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000000101043b000000000201041a00000a460320019700000a460030009c00000bb90000613d00000b05022001970000000103300039000000000223019f000000000021041b0000000a01000029000000400010008c000000580000413d000000090100002900000020021000390000000101000367000000000321034f000000000303043b000000000003004b0000000004000039000000010400c039000000000043004b000000580000c13d0000002002200039000000000321034f000000000303043b0000000a0430006b00000bb90000413d00000b4e0340009a00000b4f0030009c000000580000413d0000002003200039000000000231034f000000000202043b000000ff0020008c000000580000213d0000006003300039000000000531034f000000000505043b000b00000005001d00000a430050009c000000580000213d0000002003300039000000000531034f000000000505043b00000a460050009c000000580000213d0000000805500029000000080440002900000b03064001970000005f0750003900000b0308700197000000000968013f000000000068004b000000000600001900000b0306004041000000000047004b000000000700001900000b030700804100000b030090009c000000000607c019000000000006004b000000580000c13d0000004006500039000000000661034f000000000606043b00000a460060009c00000cbd0000213d00000005076002100000003f0870003900000b5008800197000000400900043d0000000008890019000900000009001d000000000098004b0000000009000039000000010900403900000a460080009c00000cbd0000213d000000010090019000000cbd0000c13d000000400080043f00000009080000290000000008680436000600000008001d00000060055000390000000007570019000000000047004b000000580000213d000000000006004b000013d70000613d0000000604000029000000000651034f000000000606043b00000000046404360000002005500039000000000075004b000013d10000413d000000ff0220018f000000010420008a000000020040008c000019050000813d000000400330008a000000000431034f000000000404043b00000b3e05000041000000000605041a000000000006004b000013e90000613d000000000004004b000013e90000613d00000b610640012900000ad307000041000000000707041a000000000076004b000000580000413d000000000045041b00030020003000920000000301100360000000000301043b00000ad201000041000000000101041a000000000001004b000014040000613d00000ad304000041000000000404041a00000ad405000041000000000505041a000000000045001a00000bb90000413d000000000445001900000ad505000041000000000505041a000000000045001a00000bb90000413d000000000445001a000500000000001d000014050000613d00000b6105100129000000000035004b000000580000413d00000000031300a900000000034300d9000500000003001d0000000c03000029000400840030003d000000020020008c000019760000c13d0000000002000410000c0a430020019c00001bbd0000613d000000050010002a00000bb90000413d000000050110002900000ad202000041000000000012041b0000000c01000029000000000010043f00000ad901000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000000101043b000000000201041a000200000002001d000000050020002a00000bb90000413d0000000c01000029000000000010043f00000ad901000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d00000002030000290000000502300029000000000101043b000000000021041b00000ad301000041000000000201041a00000003030000290000000103300367000000000303043b000000000032001a00000bb90000413d0000000002320019000000000021041b00000ad201000041000000000101041a000000000001004b000300000000001d000014520000613d00000ad403000041000000000303041a000000000023001a00000bb90000413d000000000223001900000ad503000041000000000303041a000000000023001a00000bb90000413d000000000223001a000014500000613d00000b6103200129000000050030006c000000580000413d00000005022000b900030000001200e100000ac501000041000000000101041a00020a430010019c000016610000613d0000000c01000029000000000010043f00000ac601000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000000101043b0000000202000029000000000020043f000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000000101043b0000000303000029000000000031041b00000ac501000041000000000201041a000000400400043d000200000004001d00000ac70100004100000000001404350000000401400039000000000031043500000a400040009c00000a400100004100000000010440190000004001100210000000000300041400000a400030009c00000a4003008041000000c003300210000000000113019f00000ac8011001c700000a430220019728fd28f30000040f000000600310027000000a4003300197000000200030008c000000200400003900000000040340190000001f0640018f0000002007400190000000020b0000290000000205700029000014970000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b000014930000c13d000000000006004b000014a40000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000010020019000001a020000613d0000001f01400039000000600110018f0000000002b10019000000000012004b00000000010000390000000101004039000c00000002001d00000a460020009c00000cbd0000213d000000010010019000000cbd0000c13d0000000c01000029000000400010043f000000200030008c000000580000413d00000ac501000041000000000201041a00000000010b04330000000c040000290000002403400039000000000013043500000ac90100004100000000001404350000000b0100002900000a43011001970000000403400039000000000013043500000a400040009c00000a400100004100000000010440190000004001100210000000000300041400000a400030009c00000a4003008041000000c003300210000000000113019f00000abd011001c700000a430220019728fd28f30000040f000000600310027000000a4003300197000000200030008c000000200400003900000000040340190000001f0640018f00000020074001900000000c05700029000014dc0000613d000000000801034f0000000c09000029000000008a08043c0000000009a90436000000000059004b000014d80000c13d000000000006004b000014e90000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000010020019000001a0e0000613d0000001f01400039000000600110018f0000000c0110002900000a460010009c00000cbd0000213d000000400010043f000000200030008c000000580000413d0000000c010000290000000001010433000000000001004b0000000002000039000000010200c039000000000021004b000000580000c13d000019aa0000013d00000060061002700000001f0460018f00000a4205600198000000400200043d000000000352001900000f2d0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b000015030000c13d00000f2d0000013d00000009010000290000000101100039000000000201041a0000000a0020002a00000bb90000413d0000000a02200029000000000021041b00000ac001000041000000000201041a000000400300043d000c00000003001d00000ac401000041000000000013043500000a400030009c00000a400100004100000000010340190000004001100210000000000300041400000a400030009c00000a4003008041000000c003300210000000000113019f00000abf011001c700000a430220019728fd28f30000040f000000600310027000000a4003300197000000200030008c000000200400003900000000040340190000001f0640018f00000020074001900000000c0b0000290000000c05700029000015310000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b0000152d0000c13d000000000006004b0000153e0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f000000000065043500000001002001900000155b0000613d0000001f01400039000000600210018f0000000001b20019000000000021004b0000000002000039000000010200403900000a460010009c00000cbd0000213d000000010020019000000cbd0000c13d000000400010043f000000200030008c000000580000413d00000000020b043300000064010000390000000101100367000000000101043b000000000001004b000016480000c13d00000000010004110000000a0300002928fd27f20000040f000000400100043d000000010200003900000ab603000041000000000023041b000008630000013d0000001f0530018f00000a4206300198000000400200043d0000000004620019000011680000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000015620000c13d000011680000013d00000a4301100197000600000001001d000000000010043f00000ad901000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000000101043b000000000101041a0005000b00100074000015960000813d000000400100043d00000ae402000041000015900000013d0000000b0100002900000a4500100198000500000000001d0000158e0000c13d0000000b0200002900000b050120019700000001011001bf00000b060220019700000b07022001c7000000050000006b000000000201c01900000a4401000041000000000021041b00000a4500200198000016510000c13d000000400100043d00000b2502000041000015900000013d000000400100043d00000b2802000041000000000021043500000a400010009c00000a4001008041000000400110021000000abf011001c7000028ff0001043000000ad201000041000000000101041a000000000001004b000400000000001d000015ad0000613d00000ad302000041000000000202041a00000ad403000041000000000303041a000000000023001a00000bb90000413d000000000223001900000ad503000041000000000303041a000000000023001a00000bb90000413d000000000223001a000015ab0000613d00000b61032001290000000b0030006c000000580000413d0000000b022000b900040000001200e10000000b0110006c00000bb90000413d00000ad202000041000000000012041b0000000601000029000000000010043f00000ad901000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000000101043b0000000502000029000000000021041b00000ad201000041000000000101041a000000000001004b0000000002000019000015d80000613d00000ad302000041000000000202041a00000ad403000041000000000303041a000000000023001a00000bb90000413d000000000223001900000ad503000041000000000303041a000000000023001a00000bb90000413d000000000223001a000015d60000613d00000b61032001290000000b0030006c000000580000413d0000000b022000b900000000021200d9000000400100043d00000040031000390000000b040000290000000000430435000000200310003900000000002304350000000402000029000000000021043500000a400010009c00000a40010080410000004001100210000000000200041400000a400020009c00000a4002008041000000c002200210000000000112019f00000ada011001c70000800d02000039000000020300003900000adb04000041000000000500041128fd28f30000040f0000000100200190000000580000613d000000400300043d00000060013000390000000c02000029000000000021043500000040013000390000000902000029000000000021043500000020013000390000000302000039000000000021043500000060010000390000000000130435000500000003001d00000adc0030009c00000cbd0000213d00000005010000290000008001100039000000400010043f00000add0100004100000000001004430000000001000412000000040010044300000020010000390000002400100443000000000100041400000a400010009c00000a4001008041000000c00110021000000ade011001c7000080050200003928fd28f80000040f000000010020019000001da20000613d000000000101043b000400000001001d0000000702000029000000080300002928fd1f0b0000040f000300000001001d00000ad501000041000000000101041a000000000001004b000017920000c13d00000ad301000041000000000201041a000000090220006c00000bb90000413d000000000021041b000000400400043d00000ae20040009c00000cbd0000213d0000004001400039000000400010043f0000000001000416000000000114043600000000000104350000000a0100002900000a430510019700000004010000290000000502000029000000030300002928fd23e80000040f0000000005010433000000400100043d0000000902000029000000000021043500000a400010009c00000a40010080410000004001100210000000000200041400000a400020009c00000a4002008041000000c002200210000000000112019f00000a47011001c70000800d02000039000000040300003900000ae30400004100000000060004110000000c0700002928fd28f30000040f0000000100200190000000580000613d000000010100003900000ab602000041000000000012041b0000000001000019000028fe0001042e00000000010004100000000a0300002928fd27f20000040f000000000100041000000a43011001980000165d0000c13d000000400100043d00000aca02000041000016630000013d000000010200003900000ab601000041000000000021041b00000ab701000041000000000201041a00000b5f02200197000000000021041b0000000a0000006b0000166a0000c13d000000400100043d00000b2702000041000016630000013d00000ac502000041000000000202041a000c0a430020019c000016850000c13d000000400100043d00000b5802000041000000000021043500000004021000390000000000020435000001840000013d000000400100043d00000b4d02000041000015900000013d00000ae801000041000000000201041a00000afc032001970000000a06000029000000000363019f000000000031041b000000000100041400000a430520019700000a400010009c00000a4001008041000000c00110021000000af2011001c70000800d02000039000000030300003900000b080400004128fd28f30000040f0000000100200190000000580000613d00000a4401000041000000000101041a00000a45001001980000158b0000613d0000000c0000006b000017350000c13d000000400100043d00000b2602000041000015900000013d000000000010043f00000ac601000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000000101043b0000000c02000029000000000020043f000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000000101043b0000000a03000029000000000031041b00000ac501000041000000000201041a000000400400043d000c00000004001d00000ac70100004100000000001404350000000401400039000000000031043500000a400040009c00000a400100004100000000010440190000004001100210000000000300041400000a400030009c00000a4003008041000000c003300210000000000113019f00000ac8011001c700000a430220019728fd28f30000040f000000600310027000000a4003300197000000200030008c000000200400003900000000040340190000001f0640018f00000020074001900000000c0b0000290000000c05700029000016c50000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b000016c10000c13d000000000006004b000016d20000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f000000000065043500000001002001900000177a0000613d0000001f01400039000000600110018f0000000002b10019000000000012004b00000000010000390000000101004039000b00000002001d00000a460020009c00000cbd0000213d000000010010019000000cbd0000c13d0000000b01000029000000400010043f000000200030008c000000580000413d00000ac501000041000000000201041a00000000010b04330000000b040000290000002403400039000000000013043500000ac9010000410000000000140435000000000100041100000a43011001970000000403400039000000000013043500000a400040009c00000a400100004100000000010440190000004001100210000000000300041400000a400030009c00000a4003008041000000c003300210000000000113019f00000abd011001c700000a430220019728fd28f30000040f000000600310027000000a4003300197000000200030008c000000200400003900000000040340190000001f0640018f00000020074001900000000b057000290000170a0000613d000000000801034f0000000b09000029000000008a08043c0000000009a90436000000000059004b000017060000c13d000000000006004b000017170000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000017cb0000613d0000001f01400039000000600110018f0000000b0110002900000a460010009c00000cbd0000213d000000400010043f000000200030008c000000580000413d0000000b020000290000000002020433000000000002004b0000000003000039000000010300c039000000000032004b000015570000613d000000580000013d0000001f0530018f00000a4206300198000000400200043d0000000004620019000011680000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000017300000c13d000011680000013d00000add010000410000000000100443000000000100041200000004001004430000002400000443000000000100041400000a400010009c00000a4001008041000000c00110021000000ade011001c7000080050200003928fd28f80000040f000000010020019000001da20000613d000000000101043b00000acf02000041000000000020044300000a4301100197000b00000001001d0000000400100443000000000100041400000a400010009c00000a4001008041000000c00110021000000ad0011001c7000080020200003928fd28f80000040f000000010020019000001da20000613d000000000101043b000000000001004b000000580000613d000000400200043d00000afe010000410000000001120436000400000001001d00000004012000390000000c03000029000000000031043500000a400020009c000c00000002001d00000a40010000410000000001024019000a004000100218000000000100041400000a400010009c00000a4001008041000000c0011002100000000a011001af00000ac8011001c70000000b0200002928fd28f30000040f0000000100200190000017d70000613d0000000c0100002900000a460010009c00000cbd0000213d0000000c01000029000000400010043f00000a4401000041000000000101041a00000a4500100198000017f70000c13d00000b25010000410000000c0200002900000000001204350000000a0100002900000abf011001c7000028ff000104300000001f0530018f00000a4206300198000000400200043d0000000004620019000011680000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000017810000c13d000011680000013d0000001f0530018f00000a4206300198000000400200043d0000000004620019000011680000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b0000178d0000c13d000011680000013d00000ae001000041000000000101041a000b00000001001d00000b610010009c00000bb90000613d00000adf01000041000000000101041a000600000001001d000800090000002d00000006020000290000000b0020006b000017e40000813d0000000b010000290000000101100039000b00000001001d000000000010043f00000ae101000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000000101043b000000000201041a0007000800200073000017f30000413d0000000b01000029000000000010043f00000ae101000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000000101043b000000000001041b00000ae001000041000000000101041a000000010110003a00000bb90000613d00000ae002000041000000000012041b000000010200008a0000000b0020006b000800070000002d0000179b0000c13d00000bb90000013d0000001f0530018f00000a4206300198000000400200043d0000000004620019000011680000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000017d20000c13d000011680000013d00000060061002700000001f0460018f00000a4205600198000000400200043d000000000352001900000f2d0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b000017df0000c13d00000f2d0000013d0000000802000029000000090120006b00000bb90000413d00000ad502000041000000000302041a000000000113004b00000bb90000413d000000000012041b000000080000006b000016200000613d00000ad301000041000000000201041a000000080220006c00000bb90000413d0000161f0000013d000000080220006a000000000021041b00000ad5010000410000161c0000013d000000800100043d00000a460010009c00000cbd0000213d00000b0902000041000000000302041a000000010030019000000001023002700000007f0220618f0000001f0020008c00000000040000390000000104002039000000000343013f00000001003001900000070c0000c13d000000200020008c000018170000413d00000b0903000041000000000030043f0000001f03100039000000050330027000000b0a0330009a000000200010008c00000b0b030040410000001f02200039000000050220027000000b0a0220009a000000000023004b000018170000813d000000000003041b0000000103300039000000000023004b000018130000413d0000001f0010008c00000001021002100000182e0000a13d00000b0903000041000000000030043f00000b6005100198000018a90000c13d000000200400003900000b0b03000041000018b50000013d00000060061002700000001f0460018f00000a4205600198000000400200043d000000000352001900000f2d0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b000018290000c13d00000f2d0000013d000000000001004b0000000003000019000018320000613d000000a00300043d000000030110021000000b610110027f00000b6101100167000000000113016f000000000121019f000018c00000013d00000af2011001c700008009020000390000000a030000290000000704000029000000000500001928fd28f30000040f00000001002001900000189c0000613d000000090100002900000a460010009c00000cbd0000213d0000000901000029000000400010043f00000b3201000041000000000101041a000c00000001001d0000000b020000290000000a0020006c000018540000613d0000000a0000006b000018510000613d000000010100008a0000000a011000fa0000000c0010006c000000580000413d0000000c020000290000000a012000b9000c000b0010010200000ad601000041000000000101041a00000acf02000041000000000020044300000a4301100197000b00000001001d0000000400100443000000000100041400000a400010009c00000a4001008041000000c00110021000000ad0011001c7000080020200003928fd28f80000040f000000010020019000001da20000613d000000000101043b000000000001004b000000580000613d000000400300043d00000044013000390000000c020000290000000000210435000000240130003900000aba02000041000000000021043500000ad7010000410000000001130436000800000001001d000000000100041000000a4301100197000000040230003900000000001204350000006401300039000000000001043500000a400030009c000900000003001d00000a400100004100000000010340190007004000100218000000000100041400000a400010009c00000a4001008041000000c00110021000000007011001af00000ad8011001c70000000b0200002928fd28f30000040f0000000100200190000019f50000613d000000090100002900000a460010009c00000cbd0000213d0000000901000029000000400010043f00000b3201000041000000000201041a0000000c0220006c00000bb90000413d000000000021041b000000010100003900000ab602000041000000000012041b0000000601000029000000080200002900000000001204350000000a0100002900000009020000290000000000120435000000070100002900000b33011001c7000028fe0001042e00000060061002700000001f0460018f00000a4205600198000000400200043d000000000352001900000f2d0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b000018a40000c13d00000f2d0000013d00000b0b030000410000002004000039000000010650008a000000050660027000000b0c0660009a00000080074000390000000007070433000000000073041b00000020044000390000000103300039000000000063004b000018ae0000c13d000000000015004b000018bf0000813d0000000301100210000000f80110018f00000b610110027f00000b610110016700000080044000390000000004040433000000000114016f000000000013041b00000001012001bf00000b0902000041000000000012041b0000000701000029000000000101043300000a460010009c00000cbd0000213d00000b0d02000041000000000302041a000000010030019000000001023002700000007f0220618f0000001f0020008c00000000040000390000000104002039000000000343013f00000001003001900000070c0000c13d000000200020008c000018e30000413d00000b0d03000041000000000030043f0000001f03100039000000050330027000000b0e0330009a000000200010008c00000b0f030040410000001f02200039000000050220027000000b0e0220009a000000000023004b000018e30000813d000000000003041b0000000103300039000000000023004b000018df0000413d0000001f0010008c0000000102100210000018ed0000a13d00000b0d03000041000000000030043f00000b6005100198000019230000c13d000000200400003900000b0f030000410000192f0000013d000000000001004b0000000003000019000018f20000613d00000006030000290000000003030433000000030110021000000b610110027f00000b6101100167000000000113016f000000000121019f0000193a0000013d00000060061002700000001f0460018f00000a4205600198000000400200043d000000000352001900000f2d0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b000019000000c13d00000f2d0000013d000000040020008c000019200000c13d0000000c02000029000b00a40020003d0000000b02100360000000000202043b00000b3e03000041000000000403041a000000000004004b000019160000613d000000000002004b000019160000613d00000b610420012900000ad305000041000000000505041a000000000054004b000000580000413d000000000023041b00000b4103000041000000000303041a000000000003004b00001a1a0000c13d0000000b04000029000000200440008a000000000441034f000000000404043b00001a210000013d000000400100043d00000b5902000041000015900000013d00000b0f030000410000002004000039000000010650008a000000050660027000000b100660009a00000007074000290000000007070433000000000073041b00000020044000390000000103300039000000000063004b000019280000c13d000000000015004b000019390000813d0000000301100210000000f80110018f00000b610110027f00000b610110016700000007044000290000000004040433000000000114016f000000000013041b00000001012001bf00000b0d02000041000000000012041b00000a4401000041000000000101041a00000a4500100198000017740000613d0000000c0100002900000ae20010009c00000cbd0000213d0000000c020000290000004001200039000000400010043f0000000101000039000000000012043500000b110100004100000004020000290000000000120435000000800100043d00000a460010009c00000cbd0000213d00000b1202000041000000000302041a000000010030019000000001023002700000007f0220618f0000001f0020008c00000000040000390000000104002039000000000343013f00000001003001900000070c0000c13d000000200020008c0000196b0000413d00000b1203000041000000000030043f0000001f03100039000000050330027000000b130330009a000000200010008c00000b14030040410000001f02200039000000050220027000000b130220009a000000000023004b0000196b0000813d000000000003041b0000000103300039000000000023004b000019670000413d0000001f0010008c0000000102100210000000030310021000001aa10000a13d00000b1204000041000000000040043f00000b600610019800001aaa0000c13d000000200500003900000b140400004100001ab60000013d0000000b02000029000c0a430020019c00001bbd0000613d000000050010002a00000bb90000413d000000050110002900000ad202000041000000000012041b0000000c01000029000000000010043f00000ad901000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000000101043b000000000201041a000300000002001d000000050020002a00000bb90000413d0000000c01000029000000000010043f00000ad901000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d00000003030000290000000502300029000000000101043b000000000021041b00000ad301000041000000000201041a00000004030000290000000103300367000000000303043b000000000032001a00000bb90000413d0000000002320019000000000021041b00000ad601000041000000000101041a00000acf02000041000000000020044300000a4301100197000300000001001d0000000400100443000000000100041400000a400010009c00000a4001008041000000c00110021000000ad0011001c7000080020200003928fd28f80000040f000000010020019000001da20000613d000000000101043b000000000001004b000000580000613d000000400300043d00000044013000390000000502000029000000000021043500000ad7010000410000000001130436000200000001001d000000000100041000000a430110019700000024023000390000000000120435000000040230003900000000001204350000006401300039000000000001043500000a400030009c000c00000003001d00000a400100004100000000010340190001004000100218000000000100041400000a400010009c00000a4001008041000000c00110021000000001011001af00000ad8011001c7000000030200002928fd28f30000040f000000010020019000001aec0000613d0000000c0100002900000a460010009c00000cbd0000213d0000000c02000029000000400020043f0000000501000029000000000012043500000001010003670000000402100360000000000202043b000000020300002900000000002304350000006401100370000000000501043b000000000100041400000a400010009c00000a4001008041000000c00110021000000001011001af0000000b0200002900000a430620019700000ab9011001c70000800d02000039000000030300003900000b540400004100001b1c0000013d00000060061002700000001f0460018f00000a4205600198000000400200043d000000000352001900000f2d0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b000019fd0000c13d00000f2d0000013d0000001f0530018f00000a4206300198000000400200043d0000000004620019000011680000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00001a090000c13d000011680000013d0000001f0530018f00000a4206300198000000400200043d0000000004620019000011680000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00001a150000c13d000011680000013d00000b61053001290000000c040000290000008404400039000000000441034f000000000404043b000000000054004b000000580000213d00000000033400a900000b510030009c00001af90000413d00000ad304000041000000000404041a00000ad405000041000000000505041a000000000045001a00000bb90000413d000000000445001900000ad505000041000000000505041a000000000045001a00000bb90000413d00050b51003001320000000003450019000000050330006c00001af90000a13d00000ad201000041000000000101041a000000000001004b00001a3a0000613d00000b6102100129000000050020006c000000580000413d00000b1c02000041000000000202041a00040a430020019c00001bbd0000613d00000005021000b9000c0000003200e10000000c0010002a00000bb90000413d0000000c0110002900000ad202000041000000000012041b0000000401000029000000000010043f00000ad901000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000000101043b000000000201041a000300000002001d0000000c0020002a00000bb90000413d0000000401000029000000000010043f00000ad901000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d00000003030000290000000c02300029000000000101043b000000000021041b00000ad601000041000000000101041a00000acf02000041000000000020044300000a4301100197000200000001001d0000000400100443000000000100041400000a400010009c00000a4001008041000000c00110021000000ad0011001c7000080020200003928fd28f80000040f000000010020019000001da20000613d000000000101043b000000000001004b000000580000613d000000400300043d00000044013000390000000c02000029000000000021043500000ad7010000410000000000130435000000000100041000000a430110019700000024023000390000000000120435000000040230003900000000001204350000006401300039000000000001043500000a400030009c000400000003001d00000a400100004100000000010340190003004000100218000000000100041400000a400010009c00000a4001008041000000c00110021000000003011001af00000ad8011001c7000000020200002928fd28f30000040f000000010020019000001b5d0000613d000000040100002900000a460010009c00000cbd0000213d0000000401000029000000400010043f00000001010003670000000b02100360000000000202043b00001b000000013d000000000001004b000000000100001900001aa50000613d000000a00100043d00000b610330027f00000b6103300167000000000131016f000000000121019f00001ac00000013d00000b14040000410000002005000039000000010760008a000000050770027000000b150770009a00000080085000390000000008080433000000000084041b00000020055000390000000104400039000000000074004b00001aaf0000c13d000000000016004b00001abf0000813d000000f80130018f00000b610110027f00000b610110016700000080035000390000000003030433000000000113016f000000000014041b00000001012001bf00000b1202000041000000000012041b0000000c01000029000000000101043300000a460010009c00000cbd0000213d00000b1602000041000000000302041a000000010030019000000001023002700000007f0220618f0000001f0020008c00000000040000390000000104002039000000000343013f00000001003001900000070c0000c13d000000200020008c00001ae30000413d00000b1603000041000000000030043f0000001f03100039000000050330027000000b170330009a000000200010008c00000b18030040410000001f02200039000000050220027000000b170220009a000000000023004b00001ae30000813d000000000003041b0000000103300039000000000023004b00001adf0000413d0000001f0010008c00001b6a0000a13d00000b1602000041000000000020043f00000b600410019800001b760000c13d000000200300003900000b180200004100001b820000013d00000060061002700000001f0460018f00000a4205600198000000400200043d000000000352001900000f2d0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b00001af40000c13d00000f2d0000013d000000400300043d00000a400030009c000400000003001d00000a40030080410003004000300218000c00000000001d000500000000001d00000b1c03000041000000000303041a000000040600002900000000002604350000000b02000029000000200220008a000000000221034f000000000202043b00000060046000390000000c050000290000000000540435000000400460003900000005050000290000000000540435000000200460003900000000002404350000006401100370000000000501043b000000000100041400000a400010009c00000a4001008041000000c00110021000000003011001af00000a430630019700000b52011001c70000800d02000039000000030300003900000b530400004128fd28f30000040f0000000100200190000000580000613d00000009010000290000000001010433000500000001001d000000000001004b00001c910000613d00000ae001000041000000000101041a000400000001001d00000adf01000041000000000101041a000300000001001d000c00000000001d000b00000000001d00001b320000013d0000000c020000290000000102200039000c00000002001d000000050020006c00001bc00000813d000000090100002900000000010104330000000c0010006b00001bfe0000813d0000000c01000029000000050110021000000006011000290000000001010433000000000010043f00000b2d01000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000000101043b000000000101041a000000000010043f00000ae101000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000000201043b000000000102041a000000000001004b00001b2d0000613d000000000002041b0000000b0010002a00000bb90000413d000b000b0010002d00001b2d0000013d00000060061002700000001f0460018f00000a4205600198000000400200043d000000000352001900000f2d0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b00001b650000c13d00000f2d0000013d000000000001004b000000000200001900001b6f0000613d00000004020000290000000002020433000000030310021000000b610330027f00000b6103300167000000000232016f0000000101100210000000000112019f00001b8e0000013d00000b18020000410000002003000039000000010540008a000000050550027000000b190550009a0000000c063000290000000006060433000000000062041b00000020033000390000000102200039000000000052004b00001b7b0000c13d000000000014004b00001b8c0000813d0000000304100210000000f80440018f00000b610440027f00000b61044001670000000c033000290000000003030433000000000343016f000000000032041b000000010110021000000001011001bf00000b1602000041000000000012041b00000b1a01000041000000000001041b00000b1b01000041000000000001041b00000001010003670000004402100370000000000202043b00000a430220019800001bbd0000613d00000b1c03000041000000000403041a00000afc04400197000000000224019f000000000023041b0000006401100370000000000101043b00000a430110019800001bbd0000613d00000ac002000041000000000302041a00000afc03300197000000000313019f000000000032041b000000400200043d000000000012043500000a400020009c00000a40020080410000004001200210000000000200041400000a400020009c00000a4002008041000000c002200210000000000112019f00000a47011001c70000800d02000039000000010300003900000b1d0400004128fd28f30000040f0000000100200190000000580000613d00000084010000390000000101100367000000000101043b00000a430110019800001c040000c13d000000400100043d00000ae502000041000015900000013d000000010200008a000000040020006b00000bb90000613d0000000502000029000000040020002a00000bb90000413d00000005020000290000000402200029000000030020006c0000000302008029000c00000002001d00001bcf0000013d000000010200008a000000040020006b00000bb90000613d0000000c01000029000900040000002d000000040010006b00001c840000813d00000009010000290000000101100039000400000001001d000000000010043f00000ae101000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000000101043b000000000101041a000000000001004b00001c810000c13d0000000c02000029000000040020006b00001bcc0000c13d0000000c01000029000000000010043f00000ae101000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000000580000613d000000000101043b000000000101041a000000000001004b00001bcc0000c13d0000000c0100002900000ae002000041000000000012041b00001bcc0000013d00000b5501000041000000000010043f0000003201000039000000040010043f00000ac801000041000028ff0001043000000ad602000041000000000302041a00000afc03300197000000000313019f000000000032041b000000400200043d000000000012043500000a400020009c00000a40020080410000004001200210000000000200041400000a400020009c00000a4002008041000000c002200210000000000112019f00000a47011001c70000800d02000039000000010300003900000b1e0400004128fd28f30000040f0000000100200190000000580000613d00000abb01000041000000000201041a00000afc02200197000000e4030000390000000103300367000000000303043b00000a4303300197000000000232019f000000000021041b000000400100043d000000000031043500000a400010009c00000a40010080410000004001100210000000000200041400000a400020009c00000a4002008041000000c002200210000000000112019f00000a47011001c70000800d02000039000000010300003900000b1f0400004128fd28f30000040f0000000100200190000000580000613d00000a4401000041000000000101041a00000a45001001980000158b0000613d000000090100002900000a430110019700000b2002000041000000000302041a00000afc03300197000000000313019f000000000032041b000000400200043d000000000012043500000a400020009c00000a40020080410000004001200210000000000200041400000a400020009c00000a4002008041000000c002200210000000000112019f00000a47011001c70000800d02000039000000010300003900000b210400004128fd28f30000040f0000000100200190000000580000613d00000a4401000041000000000101041a00000a45001001980000158b0000613d000000080100002900000a430110019700000b2202000041000000000302041a00000afc03300197000000000313019f000000000032041b000000400200043d000000000012043500000a400020009c00000a40020080410000004001200210000000000200041400000a400020009c00000a4002008041000000c002200210000000000112019f00000a47011001c70000800d02000039000000010300003900000b230400004128fd28f30000040f0000000100200190000000580000613d000000050000006b00000cae0000c13d00000a4401000041000000000201041a00000b2402200197000000000021041b000000400100043d0000000103000039000000000031043500000a400010009c00000a40010080410000004001100210000000000200041400000a400020009c00000a4002008041000000c002200210000000000112019f00000a47011001c70000800d0200003900000a480400004100000cab0000013d00000ae0010000410000000902000029000000000021041b0000000b0000006b00001c910000613d00000ad301000041000000000201041a0000000b0020002a00000bb90000413d0000000b02200029000000000021041b00000ad501000041000000000201041a0000000b0220006c00000bb90000413d000000000021041b00000001010003670000000802100360000000000302043b000000000003004b0000000002000039000000010200c039000000000023004b000000580000c13d00000008020000290000002004200039000000000241034f000000000202043b000000000003004b000016430000613d0000000405100370000000000505043b00000a400050009c000000580000213d0000004406100370000000000606043b000000010030008c000000580000c13d00000b560060009c000000580000813d000000210700008a0000000a0070006b00000bb90000213d0000000a030000290000002003300039000000000a23004b00000bb90000413d0000000a07a0006b000000580000413d00000a460070009c00000cbd0000213d0000001f0370003900000b60033001970000003f0330003900000b6003300197000000400900043d0000000008390019000000000098004b000000000b000039000000010b00403900000a460080009c00000cbd0000213d0000000100b0019000000cbd0000c13d000000400080043f0000000008790436000000070b0000290000000000b0007c000000580000213d000000080aa00029000000000ba1034f00000b600c7001980000001f0d70018f000000000ac8001900001cd20000613d000000000e0b034f000000000f08001900000000e30e043c000000000f3f04360000000000af004b00001cce0000c13d00000000000d004b00001cdf0000613d0000000003cb034f000000030bd00210000000000c0a0433000000000cbc01cf000000000cbc022f000000000303043b000001000bb000890000000003b3022f0000000003b301cf0000000003c3019f00000000003a043500000000037800190000000000030435000000400a00043d0000002007a0003900000000030004100000000000370435000000400ba000390000000009090433000000000009004b00001cf10000613d000000000c0000190000000003bc0019000000000d8c0019000000000d0d04330000000000d30435000000200cc0003900000000009c004b00001cea0000413d0000000003b900190000000000030435000000200390003900000000003a04350000005f0390003900000b60033001970000000009a30019000000000039004b00000000080000390000000108004039000c00000009001d00000a460090009c00000cbd0000213d000000010080019000000cbd0000c13d0000000c08000029000000400080043f000000c0036002100000002006800039000b00000006001d0000000000360435000000e003500210000000280580003900000000003504350000004003400039000000000331034f000000000303043b0000002c0480003900000000003404350000004c0580003900000000040a0433000000000004004b00001d1a0000613d000000000600001900000000035600190000000008760019000000000808043300000000008304350000002006600039000000000046004b00001d130000413d000000000354001900000000000304350000002c034000390000000c0500002900000000003504350000006b0340003900000b60033001970000000004530019000000000034004b0000000005000039000000010500403900000a460040009c00000cbd0000213d000000010050019000000cbd0000c13d000000400040043f0000000a0220006b00000bb90000413d00000b620020009c00000bb90000213d00000020032000390000000a0030006c000000580000213d0000000802200029000000000121034f000000000101043b000a00000001001d00000add010000410000000000100443000000000100041200000004001004430000002400000443000000000100041400000a400010009c00000a4001008041000000c00110021000000ade011001c7000080050200003928fd28f80000040f000000010020019000001da20000613d000000000101043b00000acf02000041000000000020044300000a43011001970000000400100443000000000100041400000a400010009c00000a4001008041000000c00110021000000ad0011001c7000080020200003928fd28f80000040f000000010020019000001da20000613d000000000101043b000000000001004b000000580000613d000000400400043d00000b570100004100000000001404350000000a0100002900000a43011001970000000402400039000000000012043500000064010000390000000101100367000000000101043b00000064024000390000008003000039000000000032043500000024024000390000000000120435000000440140003900000000000104350000000c01000029000000000201043300000084014000390000000000210435000a00000004001d000000a401400039000c00000002001d000000000002004b00001d760000613d000000000200001900000000031200190000000b042000290000000004040433000000000043043500000020022000390000000c0020006c00001d6f0000413d0000000c01100029000000000001043500000add010000410000000000100443000000000100041200000004001004430000002400000443000000000100041400000a400010009c00000a4001008041000000c00110021000000ade011001c7000080050200003928fd28f80000040f000000010020019000001da20000613d0000000c020000290000001f0220003900000b6002200197000000a40220003900000a400020009c00000a400200804100000060022002100000000a0300002900000a400030009c00000a40030080410000004003300210000000000232019f000000000301043b000000000100041400000a400010009c00000a4001008041000000c001100210000000000121019f00000a430230019728fd28f30000040f000000010020019000001da30000613d0000000a0100002900000a460010009c00000cbd0000213d0000000a01000029000000400010043f000016430000013d000000000001042f00000060061002700000001f0460018f00000a4205600198000000400200043d000000000352001900000f2d0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b00001dab0000c13d00000f2d0000013d0000001f03100039000000000023004b000000000400001900000b030400404100000b030520019700000b0303300197000000000653013f000000000053004b000000000300001900000b030300204100000b030060009c000000000304c019000000000003004b00001dc80000613d0000000103100367000000000303043b00000a460030009c00001dc80000213d00000020011000390000000004310019000000000024004b00001dc80000213d0000000002030019000000000001042d0000000001000019000028ff0001043000000000430104340000000001320436000000000003004b00001dd60000613d000000000200001900000000051200190000000006240019000000000606043300000000006504350000002002200039000000000032004b00001dcf0000413d000000000213001900000000000204350000001f0230003900000b60022001970000000001210019000000000001042d00000024010000390000000101100367000000000101043b000000000001004b0000000002000039000000010200c039000000000021004b00001de50000c13d000000000001042d0000000001000019000028ff0001043000000000320204340000000002210436000000000303043300000000003204350000004001100039000000000001042d00000b630010009c00001dfd0000213d000000630010008c00001dfd0000a13d00000001030003670000000401300370000000000101043b00000a430010009c00001dfd0000213d0000002402300370000000000202043b00000a430020009c00001dfd0000213d0000004403300370000000000303043b000000000001042d0000000001000019000028ff0001043000000b640010009c00001e040000813d000000a001100039000000400010043f000000000001042d00000b5501000041000000000010043f0000004101000039000000040010043f00000ac801000041000028ff0001043000000b650010009c00001e0f0000813d0000004001100039000000400010043f000000000001042d00000b5501000041000000000010043f0000004101000039000000040010043f00000ac801000041000028ff000104300000001f0220003900000b60022001970000000001120019000000000021004b0000000002000039000000010200403900000a460010009c00001e210000213d000000010020019000001e210000c13d000000400010043f000000000001042d00000b5501000041000000000010043f0000004101000039000000040010043f00000ac801000041000028ff0001043000000a4301100197000000000010043f00000b2901000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f000000010020019000001e360000613d000000000101043b000000000001042d0000000001000019000028ff0001043000000a4301100197000000000010043f00000ab801000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f000000010020019000001e470000613d000000000101043b000000000001042d0000000001000019000028ff0001043000000a4301100197000000000010043f00000b3c01000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f000000010020019000001e580000613d000000000101043b000000000001042d0000000001000019000028ff0001043000000a4301100197000000000010043f00000ad901000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f000000010020019000001e690000613d000000000101043b000000000001042d0000000001000019000028ff0001043000000a4301100197000000000010043f00000ac601000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f000000010020019000001e7a0000613d000000000101043b000000000001042d0000000001000019000028ff000104300002000000000002000000000301041a000000010430019000000001063002700000007f0660618f0000001f0060008c00000000050000390000000105002039000000000054004b00001ead0000c13d0000000005620436000000000004004b00001ea40000613d000200000006001d000100000005001d000000000010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000a47011001c7000080100200003928fd28f80000040f000000010020019000001eb30000613d0000000206000029000000000006004b00001eab0000613d000000000201043b000000000100001900000001050000290000000003150019000000000402041a000000000043043500000001022000390000002001100039000000000061004b00001e9b0000413d0000000001150019000000000001042d00000b5f013001970000000000150435000000000006004b000000200100003900000000010060390000000001150019000000000001042d0000000101000029000000000001042d00000b5501000041000000000010043f0000002201000039000000040010043f00000ac801000041000028ff000104300000000001000019000028ff0001043000000a43033001970000004004100039000000000034043500000020031000390000000000230435000000030200003900000000002104350000006001100039000000000001042d00000a4001100197000000000010043f00000b4c01000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f000000010020019000001ecd0000613d000000000101043b000000000001042d0000000001000019000028ff0001043000000a460110019700000a460010009c00001ed40000613d0000000101100039000000000001042d00000b5501000041000000000010043f0000001101000039000000040010043f00000ac801000041000028ff00010430000000000323043600000b60062001980000001f0720018f0000000005630019000000010110036700001ee60000613d000000000801034f0000000009030019000000008a08043c0000000009a90436000000000059004b00001ee20000c13d000000000007004b00001ef30000613d000000000161034f0000000306700210000000000705043300000000076701cf000000000767022f000000000101043b0000010006600089000000000161022f00000000016101cf000000000171019f0000000000150435000000000123001900000000000104350000001f0120003900000b60011001970000000001130019000000000001042d00000a4001100197000000000010043f00000b4701000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f000000010020019000001f090000613d000000000101043b000000000101041a000000000001042d0000000001000019000028ff000104300005000000000002000500000003001d000400000002001d00000a4001100197000000000010043f00000aff01000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f000000010020019000001fd90000613d000000000101043b000000000000043f000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f000000010020019000001fd90000613d000000000501043b000000000205041a000000010320019000000001062002700000007f0660618f0000001f0060008c00000000040000390000000104002039000000000043004b00001fe10000c13d000000400100043d0000000008610436000000000003004b00001f510000613d000300000006001d000100000001001d000200000008001d000000000050043f000000000100041400000a400010009c00000a4001008041000000c00110021000000a47011001c7000080100200003928fd28f80000040f000000010020019000001fd90000613d0000000306000029000000000006004b00001f580000613d000000000201043b0000000005000019000000050a00002900000002080000290000000003850019000000000402041a000000000043043500000001022000390000002005500039000000000065004b00001f490000413d00001f5b0000013d00000b5f022001970000000000280435000000000006004b00000020050000390000000005006039000000050a00002900001f5c0000013d0000000005000019000000050a000029000000020800002900000001010000290000003f0250003900000b6002200197000000000b12001900000000002b004b0000000002000039000000010200403900000a4600b0009c00001fdb0000213d000000010020019000001fdb0000c13d0000004000b0043f0000000002010433000000000002004b00001fad0000613d00000000000a004b00001fd80000613d0000000100a0008c00001fe70000613d00000001030003670000000404300360000000000404043b00000b010440019700000b020040009c00001ff00000c13d0000002005b00039000000000400001900000000065400190000000007480019000000000707043300000000007604350000002004400039000000000024004b00001f760000413d00000004040000290000000204400039000000000443034f000000000352001900000000000304350000000002b200190000000203a0008a00000b60053001980000001f0630018f0000002007200039000000000357001900001f8e0000613d000000000804034f000000008908043c0000000007970436000000000037004b00001f8a0000c13d000000000006004b00001f9b0000613d000000000454034f0000000305600210000000000603043300000000065601cf000000000656022f000000000404043b0000010005500089000000000454022f00000000045401cf000000000464019f00000000004304350000000002a200190000001e0320003900000000000304350000000002b20049000000020320008a00000000003b04350000003d0220003900000b60022001970000000001b20019000000000021004b0000000002000039000000010200403900000a460010009c00001fdb0000213d000000010020019000001fdb0000c13d000000400010043f00001fd70000013d00000a4600a0009c00001fdb0000213d0000001f02a0003900000b60022001970000003f0220003900000b600220019700000000022b001900000a460020009c00001fdb0000213d000000400020043f0000000002ab04360000000404a00029000000000040007c00001fd90000213d000000050900002900000b60039001980000001f0490018f00000004010000290000000105100367000000000132001900001fc80000613d000000000605034f0000000007020019000000006806043c0000000007870436000000000017004b00001fc40000c13d000000000004004b00001fd50000613d000000000335034f0000000304400210000000000501043300000000054501cf000000000545022f000000000303043b0000010004400089000000000343022f00000000034301cf000000000353019f00000000003104350000000001920019000000000001043500000000010b0019000000000001042d0000000001000019000028ff0001043000000b5501000041000000000010043f0000004101000039000000040010043f00000ac801000041000028ff0001043000000b5501000041000000000010043f0000002201000039000000040010043f00000ac801000041000028ff0001043000000b000100004100000000001b04350000000401b00039000000200200003900000000002104350000002403b000390000000102000039000000040100002900001ff80000013d00000b000100004100000000001b04350000000401b00039000000200200003900000000002104350000002403b00039000000040100002900000000020a001900050000000b001d28fd1eda0000040f0000000502000029000000000121004900000a400010009c00000a400100804100000a400020009c00000a400200804100000060011002100000004002200210000000000121019f000028ff0001043000000ad202000041000000000202041a000000000002004b0000201f0000613d00000ad303000041000000000303041a00000ad404000041000000000404041a000000000034001a000020210000413d000000000334001900000ad504000041000000000404041a0000000003340019000000000043004b00000000040000390000000104004039000000010040008c000020210000613d000000000003004b0000201c0000613d00000b6104300129000000000014004b000020270000413d00000000011300a900000000012100d9000000000001042d0000000001000019000000000001042d00000b5501000041000000000010043f0000001101000039000000040010043f00000ac801000041000028ff000104300000000001000019000028ff00010430000000600510003900000000004504350000004004100039000000000034043500000a430220019700000020031000390000000000230435000000050200003900000000002104350000008001100039000000000001042d00000a4306100198000020480000613d00000ae801000041000000000201041a00000afc03200197000000000363019f000000000031041b000000000100041400000a430520019700000a400010009c00000a4001008041000000c00110021000000af2011001c70000800d02000039000000030300003900000b080400004128fd28f30000040f0000000100200190000020520000613d000000000001042d000000400100043d00000b270200004100000000002104350000000402100039000000000002043500000a400010009c00000a4001008041000000400110021000000ac8011001c7000028ff000104300000000001000019000028ff0001043000000ad301000041000000000101041a00000ad402000041000000000202041a000000000012001a000020640000413d000000000112001900000ad502000041000000000202041a0000000001120019000000000021004b00000000020000390000000102004039000000010020008c000020640000613d000000000001042d00000b5501000041000000000010043f0000001101000039000000040010043f00000ac801000041000028ff0001043000000ae801000041000000000101041a00000a43021001970000000001000411000000000012004b000020710000c13d000000000001042d000000400200043d00000ae90300004100000000003204350000000403200039000000000013043500000a400020009c00000a4002008041000000400120021000000ac8011001c7000028ff0001043000000ad302000041000000000202041a00000ad403000041000000000303041a000000000023001a0000209a0000413d000000000223001900000ad503000041000000000303041a0000000002230019000000000032004b00000000030000390000000103004039000000010030008c0000209a0000613d000000000002004b000020980000613d00000ad203000041000000000303041a000000000003004b000020930000613d00000b6104300129000000000014004b000020a00000413d00000000011300a900000000212100d9000000000002004b000000010110c039000000000001042d0000000001000019000000000001042d00000b5501000041000000000010043f0000001101000039000000040010043f00000ac801000041000028ff000104300000000001000019000028ff0001043000000ad302000041000000000202041a00000ad403000041000000000303041a000000000023001a000020bf0000413d000000000223001900000ad503000041000000000303041a0000000002230019000000000032004b00000000030000390000000103004039000000010030008c000020bf0000613d000000000002004b000020bd0000613d00000ad203000041000000000303041a000000000003004b000020ba0000613d00000b6104300129000000000014004b000020c50000413d00000000011300a900000000012100d9000000000001042d0000000001000019000000000001042d00000b5501000041000000000010043f0000001101000039000000040010043f00000ac801000041000028ff000104300000000001000019000028ff000104300004000000000002000300000003001d000400000002001d000000400200043d00000b650020009c000021930000813d0000004003200039000000400030043f00000020032000390000000000030435000000000002043500000a4001100197000200000001001d000000000010043f00000b4701000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000021990000613d000000400300043d000000000101043b000000000101041a000000000001004b0000219b0000613d00000b2c0030009c000021930000213d000000a002300039000000400020043f00000060023000390000000304000029000000000042043500000040043000390000000405000029000000000054043500000020053000390000000000150435000000020100002900000000001304350000008001300039000000000001043500000b6606000041000000400900043d0000000006690436000100000006001d000000040690003900000040070000390000000000760435000000000303043300000a40033001970000004406900039000000000036043500000000030504330000006405900039000000000035043500000000030404330000008404900039000000a0050000390000000000540435000000e404900039000000003503043400000000005404350000010404900039000000000005004b000021150000613d000000000600001900000000074600190000000008630019000000000808043300000000008704350000002006600039000000000056004b0000210e0000413d0000000003000410000000000645001900000000000604350000001f0550003900000b60055001970000000002020433000000a406900039000000c0075000390000000000760435000000000445001900000000280204340000000007840436000000000008004b0000212b0000613d000000000400001900000000057400190000000006420019000000000606043300000000006504350000002004400039000000000084004b000021240000413d00000000027800190000000000020435000000000101043300000a430230019700000024039000390000000000230435000000c402900039000000000001004b0000000001000039000000010100c039000000000012043500000add010000410000000000100443000000000100041200000004001004430000002400000443000000000100041400000a400010009c00000a4001008041000000c00110021000000ade011001c70000800502000039000400000009001d000300000007001d000200000008001d28fd28f80000040f0000000100200190000021a50000613d00000002020000290000001f0220003900000b600220019700000004040000290000000303400069000000000223001900000a400020009c00000a4002008041000000600220021000000a400040009c00000a400300004100000000030440190000004003300210000000000232019f000000000301043b000000000100041400000a400010009c00000a4001008041000000c001100210000000000121019f00000a430230019728fd28f80000040f000000600310027000000a4003300197000000400030008c000000400400003900000000040340190000001f0640018f0000006007400190000000040b00002900000000057b00190000216d0000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b000021690000c13d000000000006004b0000217a0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000021a60000613d0000001f01400039000000e00210018f0000000001b20019000000000021004b0000000002000039000000010200403900000a460010009c000021930000213d0000000100200190000021930000c13d000000400010043f000000400030008c000021990000413d00000ae20010009c000021930000213d0000004002100039000000400020043f00000000020b04330000000002210436000000010300002900000000030304330000000000320435000000000001042d00000b5501000041000000000010043f0000004101000039000000040010043f00000ac801000041000028ff000104300000000001000019000028ff0001043000000b5a01000041000000000013043500000004013000390000000202000029000000000021043500000a400030009c00000a4003008041000000400130021000000ac8011001c7000028ff00010430000000000001042f0000001f0530018f00000a4206300198000000400200043d0000000004620019000021b10000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000021ad0000c13d000000000005004b000021be0000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f0000000000140435000000600130021000000a400020009c00000a40020080410000004002200210000000000112019f000028ff000104300003000000000002000200000003001d000300000002001d00000a4301100197000100000001001d000000000010043f00000ac601000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f00000001002001900000220e0000613d000000000101043b000000030200002900000a4302200197000300000002001d000000000020043f000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f00000001002001900000220e0000613d000000000101043b000000000101041a00000b610010009c0000220d0000613d0000000204000029000000000341004b000022100000413d0000000102000029000000000002004b0000221f0000613d000200000003001d000000030000006b000022220000613d000000000020043f00000ac601000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f00000001002001900000220e0000613d000000000101043b0000000302000029000000000020043f000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f00000001002001900000220e0000613d000000000101043b0000000202000029000000000021041b000000000001042d0000000001000019000028ff00010430000000400200043d000000440320003900000000004304350000002403200039000000000013043500000b6701000041000000000012043500000004012000390000000303000029000000000031043500000a400020009c00000a4002008041000000400120021000000b68011001c7000028ff00010430000000400100043d00000aca02000041000022240000013d000000400100043d00000b580200004100000000002104350000000402100039000000000002043500000a400010009c00000a4001008041000000400110021000000ac8011001c7000028ff000104300005000000000002000300000003001d00050a430010019c000022bb0000613d00000a4303200198000022be0000613d00000ad301000041000000000101041a00000ad402000041000000000202041a000000000012001a000022d00000413d000000000112001900000ad502000041000000000202041a0000000005120019000000000025004b00000000010000390000000101004039000000010010008c000022d00000613d000000000005004b000022b80000613d00000ad201000041000000000101041a000000000001004b0000224a0000613d00000b6102100129000000030020006c000022b60000413d00000003011000b9000000000015004b000022b80000213d000100000001001d000200000005001d000000050030006b000022c80000613d0000000001000410000000000013004b000022c80000613d0000000501000029000000000010043f00000ad901000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c70000801002000039000400000003001d28fd28f80000040f00000001002001900000000202000029000022b60000613d0002000100200101000000000101043b000000000101041a000000020110006c000100000001001d000022b80000413d0000000501000029000000000010043f00000ad901000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f00000004030000290000000100200190000022b60000613d000000000101043b0000000102000029000000000021041b000000000030043f00000ad901000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000022b60000613d000000000101043b000000000201041a0000000203000029000000000032001a000022d00000413d0000000002320019000000000021041b000000400100043d0000000302000029000000000021043500000a400010009c00000a40010080410000004001100210000000000200041400000a400020009c00000a4002008041000000c002200210000000000112019f00000a47011001c70000800d02000039000000030300003900000b69040000410000000505000029000000040600002928fd28f30000040f00000004060000290000000100200190000022b60000613d000000400100043d0000000202000029000000000021043500000a400010009c00000a40010080410000004001100210000000000200041400000a400020009c00000a4002008041000000c002200210000000000112019f00000a47011001c70000800d02000039000000030300003900000b6a04000041000000050500002928fd28f30000040f0000000100200190000022b60000613d000000000001042d0000000001000019000028ff00010430000000400100043d00000ae402000041000022ca0000013d000000400100043d00000b6c02000041000022c00000013d000000400100043d00000b6b0200004100000000002104350000000402100039000000000002043500000a400010009c00000a4001008041000000400110021000000ac8011001c7000028ff00010430000000400100043d00000b5902000041000000000021043500000a400010009c00000a4001008041000000400110021000000abf011001c7000028ff0001043000000b5501000041000000000010043f0000001101000039000000040010043f00000ac801000041000028ff00010430000000400200043d00000a4301100198000022ef0000613d00000ac003000041000000000403041a00000afc04400197000000000414019f000000000043041b000000000012043500000a400020009c00000a40020080410000004001200210000000000200041400000a400020009c00000a4002008041000000c002200210000000000112019f00000a47011001c70000800d02000039000000010300003900000b1d0400004128fd28f30000040f0000000100200190000022f60000613d000000000001042d00000ae501000041000000000012043500000a400020009c00000a4002008041000000400120021000000abf011001c7000028ff000104300000000001000019000028ff000104300001000000000002000100000001001d00000a4301100197000000000010043f00000b3c01000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000023130000613d000000000101043b000000000101041a000000ff011001900000230c0000613d000000000001042d00000ae801000041000000000101041a000000010110014f00000a430010019800000000010000390000000101006039000000000001042d0000000001000019000028ff00010430000400000000000200000a4304100198000023590000613d00000a4302200198000023590000613d000400000003001d000000000024004b0000235c0000613d0000000001000410000000000012004b0000235c0000613d000200000002001d000300000004001d000000000040043f00000ad901000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000023570000613d000000000101043b000000000101041a00010004001000740000235f0000413d0000000301000029000000000010043f00000ad901000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000023570000613d000000000101043b0000000102000029000000000021041b0000000201000029000000000010043f00000ad901000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000023570000613d000000000101043b000000000201041a0000000403000029000000000032001a000023670000413d0000000002320019000000000021041b000000000001042d0000000001000019000028ff00010430000000400100043d00000ae502000041000023610000013d000000400100043d00000b5902000041000023610000013d000000400100043d00000ae402000041000000000021043500000a400010009c00000a4001008041000000400110021000000abf011001c7000028ff0001043000000b5501000041000000000010043f0000001101000039000000040010043f00000ac801000041000028ff000104300003000000000002000100000004001d000000400400043d000000000034043500000a400040009c00000a40040080410000004003400210000000000400041400000a400040009c00000a4004008041000000c004400210000000000334019f00000a47043001c700000a430510019700000a43062001970000800d020000390000000303000039000000000104001900000b6904000041000300000005001d000200000006001d28fd28f30000040f00000001002001900000239a0000613d000000400100043d0000000102000029000000000021043500000a400010009c00000a40010080410000004001100210000000000200041400000a400020009c00000a4002008041000000c002200210000000000112019f00000a47011001c70000800d02000039000000030300003900000b6a040000410000000305000029000000020600002928fd28f30000040f00000001002001900000239a0000613d000000000001042d0000000001000019000028ff0001043000000a430110019700000abb02000041000000000302041a00000afc03300197000000000313019f000000000032041b000000400200043d000000000012043500000a400020009c00000a40020080410000004001200210000000000200041400000a400020009c00000a4002008041000000c002200210000000000112019f00000a47011001c70000800d02000039000000010300003900000b1f0400004128fd28f30000040f0000000100200190000023b40000613d000000000001042d0000000001000019000028ff00010430000000400200043d00000a4301100198000023cf0000613d00000ad603000041000000000403041a00000afc04400197000000000414019f000000000043041b000000000012043500000a400020009c00000a40020080410000004001200210000000000200041400000a400020009c00000a4002008041000000c002200210000000000112019f00000a47011001c70000800d02000039000000010300003900000b1e0400004128fd28f30000040f0000000100200190000023d60000613d000000000001042d00000ae501000041000000000012043500000a400020009c00000a4002008041000000400120021000000abf011001c7000028ff000104300000000001000019000028ff0001043000000a4301100198000023e00000613d00000b1c02000041000000000302041a00000afc03300197000000000113019f000000000012041b000000000001042d000000400100043d00000ae502000041000000000021043500000a400010009c00000a4001008041000000400110021000000abf011001c7000028ff000104300009000000000002000800000005001d000600000003001d000700000002001d000900000001001d000000400100043d00000b5b0010009c000025b00000813d0000006002100039000000400020043f000000200210003900000000000204350000000000010435000000400200043d00000ae20020009c000025b00000213d0000004003200039000000400030043f0000002003200039000000000003043500000000000204350000004001100039000000000021043500000000320404340000000001000416000500000002001d000000000021004b000025b90000c13d000400000003001d0000000001030433000000000001004b000024d20000613d000200000001001d00000add010000410000000000100443000000000100041200000004001004430000002400000443000000000100041400000a400010009c00000a4001008041000000c00110021000000ade011001c7000080050200003928fd28f80000040f0000000100200190000025b80000613d000000000201043b000000400300043d000300000003001d00000b6e01000041000000000013043500000a400030009c00000a400100004100000000010340190000004001100210000000000300041400000a400030009c00000a4003008041000000c003300210000000000113019f00000abf011001c700000a4302200197000100000002001d28fd28f80000040f000000030b000029000000600310027000000a4003300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b0019000024390000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b000024350000c13d000000000006004b000024460000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000025eb0000613d0000001f01400039000000600210018f0000000001b20019000000000021004b0000000002000039000000010200403900000a460010009c000025b00000213d0000000100200190000025b00000c13d000000400010043f000000200030008c000025b60000413d00000000020b043300000b6f0020009c000025b60000813d000000000002004b000026090000613d000000640310003900000002040000290000000000430435000000440310003900000001040000290000000000430435000000200510003900000b70030000410000000000350435000000000300041100000a4303300197000000240410003900000000003404350000006403000039000000000031043500000b2c0010009c000025b00000213d000000a003100039000000400030043f00000a400050009c00000a40050080410000004003500210000000000101043300000a400010009c00000a40010080410000006001100210000000000131019f000000000300041400000a400030009c00000a4003008041000000c003300210000000000131019f000300000002001d28fd28f30000040f000000600310027000000a4003300198000024a70000613d0000001f0430003900000a41044001970000003f0440003900000b7104400197000000400b00043d00000000044b00190000000000b4004b0000000005000039000000010500403900000a460040009c0000000309000029000025b00000213d0000000100500190000025b00000c13d000000400040043f0000001f0430018f000000000a3b043600000a420530019800000000035a0019000024990000613d000000000601034f00000000070a0019000000006806043c0000000007870436000000000037004b000024950000c13d000000000004004b000024aa0000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f0000000000130435000024aa0000013d000000600b000039000000800a000039000000030900002900000000010b043300000001002001900000260b0000613d000000000001004b000024c60000c13d00020000000b001d00010000000a001d00000acf0100004100000000001004430000000400900443000000000100041400000a400010009c00000a4001008041000000c00110021000000ad0011001c7000080020200003928fd28f80000040f0000000100200190000025b80000613d000000000101043b000000000001004b0000000201000029000026230000613d0000000001010433000000000001004b0000000309000029000000010a000029000024d20000613d00000b630010009c000025b60000213d000000200010008c000025b60000413d00000000010a0433000000000001004b0000000002000039000000010200c039000000000021004b000025b60000c13d000000000001004b000026150000613d000000090100002900000a4001100197000900000001001d000000000010043f00000b4701000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f0000000100200190000025b60000613d000000400300043d000000000101043b000000000401041a000000000004004b000025c30000613d00000b2c0030009c000025b00000213d00000004010000290000000001010433000000a002300039000000400020043f000000000001004b0000000002000039000000010200c03900000080013000390000000000210435000000600230003900000006050000290000000000520435000000400530003900000007060000290000000000650435000000200630003900000000004604350000000904000029000000000043043500000b7604000041000000400900043d0000000004490436000600000004001d000000040490003900000040070000390000000000740435000000000303043300000a40033001970000004404900039000000000034043500000000030604330000006404900039000000000034043500000000030504330000008404900039000000a0050000390000000000540435000000e406900039000000005403043400000000004604350000010403900039000000000004004b0000251b0000613d000000000600001900000000073600190000000008650019000000000808043300000000008704350000002006600039000000000046004b000025140000413d000000000534001900000000000504350000001f0440003900000b60044001970000000002020433000000a405900039000000c0064000390000000000650435000000000334001900000000270204340000000006730436000000000007004b000025300000613d000000000300001900000000046300190000000005320019000000000505043300000000005404350000002003300039000000000073004b000025290000413d000000000267001900000000000204350000000001010433000000080200002900000a430220019700000024039000390000000000230435000000c402900039000000000001004b0000000001000039000000010100c039000000000012043500000add010000410000000000100443000000000100041200000004001004430000002400000443000000000100041400000a400010009c00000a4001008041000000c00110021000000ade011001c70000800502000039000900000009001d000800000006001d000700000007001d28fd28f80000040f0000000100200190000025b80000613d00000007020000290000001f0220003900000b600220019700000009040000290000000803400069000000000223001900000a400020009c00000a4002008041000000600220021000000a400040009c00000a400300004100000000030440190000004003300210000000000232019f000000000301043b000000000100041400000a400010009c00000a4001008041000000c001100210000000000121019f00000a43043001970000000503000029000000000003004b000025690000613d00000af2011001c7000080090200003900000000050000190000256a0000013d000000000204001928fd28f30000040f000000600310027000000a4003300197000000800030008c000000800400003900000000040340190000001f0640018f000000e007400190000000090b00002900000000057b00190000257b0000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b000025770000c13d000000000006004b000025880000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000025cd0000613d0000001f01400039000001e00210018f0000000001b20019000000000021004b0000000002000039000000010200403900000a460010009c000025b00000213d0000000100200190000025b00000c13d000000400010043f000000800030008c000025b60000413d00000b2b0010009c000025b00000213d0000006002100039000000400020043f00000000020b043300000000022104360000000603000029000000000303043300000a460030009c000025b60000213d0000000000320435000000400200043d00000ae20020009c000025b00000213d0000004003200039000000400030043f0000004003b00039000000000303043300000000033204360000006004b000390000000004040433000000000043043500000040031000390000000000230435000000000001042d00000b5501000041000000000010043f0000004101000039000000040010043f00000ac801000041000028ff000104300000000001000019000028ff00010430000000000001042f000000400200043d00000b6d0300004100000000003204350000000403200039000000000013043500000a400020009c00000a4002008041000000400120021000000ac8011001c7000028ff0001043000000b5a01000041000000000013043500000004013000390000000902000029000000000021043500000a400030009c00000a4003008041000000400130021000000ac8011001c7000028ff000104300000001f0530018f00000a4206300198000000400200043d0000000004620019000025d80000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000025d40000c13d000000000005004b000025e50000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f0000000000140435000000600130021000000a400020009c00000a40020080410000004002200210000000000121019f000028ff000104300000001f0530018f00000a4206300198000000400200043d0000000004620019000025f60000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000025f20000c13d000000000005004b000026030000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f0000000000140435000000600130021000000a400020009c00000a40020080410000004002200210000000000112019f000028ff0001043000000b75020000410000260f0000013d000000000001004b0000261b0000c13d000000400100043d00000b7202000041000000000021043500000a400010009c00000a4001008041000000400110021000000abf011001c7000028ff00010430000000400100043d00000b7302000041000000000021043500000004021000390000000000920435000026290000013d00000a4000a0009c00000a400a0080410000004002a0021000000a400010009c00000a40010080410000006001100210000000000121019f000028ff00010430000000400100043d00000b7402000041000000000021043500000004021000390000000303000029000000000032043500000a400010009c00000a4001008041000000400110021000000ac8011001c7000028ff00010430000300000000000200000a4301100198000026670000613d000200000003001d00030a430020019c0000266a0000613d000100000001001d000000000010043f00000ac601000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f00000001002001900000000303000029000026650000613d000000000101043b000000000030043f000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f00000003060000290000000100200190000026650000613d000000000101043b0000000202000029000000000021041b000000400100043d000000000021043500000a400010009c00000a40010080410000004001100210000000000200041400000a400020009c00000a4002008041000000c002200210000000000112019f00000a47011001c70000800d02000039000000030300003900000b7704000041000000010500002928fd28f30000040f0000000100200190000026650000613d000000000001042d0000000001000019000028ff00010430000000400100043d00000aca020000410000266c0000013d000000400100043d00000b580200004100000000002104350000000402100039000000000002043500000a400010009c00000a4001008041000000400110021000000ac8011001c7000028ff00010430000200000000000200000b1201000041000000000401041a000000010540019000000001024002700000007f0220618f0000001f0020008c00000000010000390000000101002039000000000015004b000027490000c13d000000400300043d0000000001230436000000000005004b000026910000613d00000b1204000041000000000040043f000000000002004b000026970000613d00000b140500004100000000040000190000000006140019000000000705041a000000000076043500000001055000390000002004400039000000000024004b000026890000413d000026980000013d00000b5f044001970000000000410435000000000002004b00000020040000390000000004006039000026980000013d00000000040000190000003f02400039000000200900008a000000000492016f0000000002340019000000000042004b0000000004000039000000010400403900000a460020009c000027410000213d0000000100400190000027410000c13d000000400020043f0000000003030433000000000003004b000026bc0000613d00000a400010009c00000a4001008041000000400110021000000a400030009c00000a40030080410000006002300210000000000112019f000000000200041400000a400020009c00000a4002008041000000c002200210000000000112019f00000af2011001c7000080100200003928fd28f80000040f0000000100200190000027470000613d000000400200043d000000000801043b000000200900008a000026c00000013d00000b1a01000041000000000801041a000000000008004b00000b780800604100000b1601000041000000000401041a000000010540019000000001034002700000007f0330618f0000001f0030008c00000000010000390000000101002039000000000114013f0000000100100190000027490000c13d0000000001320436000000000005004b000026dc0000613d00000b1604000041000000000040043f000000000003004b000026e20000613d00000b180500004100000000040000190000000006140019000000000705041a000000000076043500000001055000390000002004400039000000000034004b000026d40000413d000026e30000013d00000b5f044001970000000000410435000000000003004b00000020040000390000000004006039000026e30000013d00000000040000190000003f03400039000000000393016f0000000004230019000000000034004b0000000003000039000000010300403900000a460040009c000027410000213d0000000100300190000027410000c13d000000400040043f0000000002020433000000000002004b000027070000613d000200000008001d00000a400010009c00000a4001008041000000400110021000000a400020009c00000a40020080410000006002200210000000000112019f000000000200041400000a400020009c00000a4002008041000000c002200210000000000112019f00000af2011001c7000080100200003928fd28f80000040f0000000100200190000027470000613d000000400400043d000000000101043b00000002080000290000270b0000013d00000b1b01000041000000000101041a000000000001004b00000b7801006041000200000004001d0000006002400039000000000012043500000040014000390000000000810435000000200240003900000b7901000041000100000002001d000000000012043500000b3b010000410000000000100443000000000100041400000a400010009c00000a4001008041000000c00110021000000aee011001c70000800b0200003928fd28f80000040f00000001002001900000274f0000613d000000000101043b0000000204000029000000a0024000390000000003000410000000000032043500000080024000390000000000120435000000a001000039000000000014043500000b2f0040009c000027410000213d000000c001400039000000400010043f000000010100002900000a400010009c00000a40010080410000004001100210000000000204043300000a400020009c00000a40020080410000006002200210000000000112019f000000000200041400000a400020009c00000a4002008041000000c002200210000000000112019f00000af2011001c7000080100200003928fd28f80000040f0000000100200190000027470000613d000000000101043b000000000001042d00000b5501000041000000000010043f0000004101000039000000040010043f00000ac801000041000028ff000104300000000001000019000028ff0001043000000b5501000041000000000010043f0000002201000039000000040010043f00000ac801000041000028ff00010430000000000001042f0003000000000002000000400500043d0000006406500039000000000046043500000a430330019700000044045000390000000000340435000000200350003900000b7004000041000000000043043500000a4302200197000000240450003900000000002404350000006402000039000000000025043500000b640050009c000027cb0000813d000000a002500039000000400020043f00000a400030009c00000a40030080410000004002300210000000000305043300000a400030009c00000a40030080410000006003300210000000000223019f000000000300041400000a400030009c00000a4003008041000000c003300210000000000332019f00000a43021001970000000001030019000300000002001d28fd28f30000040f000000600310027000000a40033001980000279e0000613d0000001f0430003900000a41044001970000003f0440003900000b7104400197000000400a00043d00000000044a00190000000000a4004b0000000005000039000000010500403900000a460040009c000027cb0000213d0000000100500190000027cb0000c13d000000400040043f0000001f0430018f00000000093a043600000a42053001980000000003590019000027900000613d000000000601034f0000000007090019000000006806043c0000000007870436000000000037004b0000278c0000c13d000000000004004b000027a00000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f0000000000130435000027a00000013d000000600a000039000000800900003900000000010a04330000000100200190000027d10000613d000000000001004b000027bc0000c13d00020000000a001d000100000009001d00000acf01000041000000000010044300000003010000290000000400100443000000000100041400000a400010009c00000a4001008041000000c00110021000000ad0011001c7000080020200003928fd28f80000040f0000000100200190000027e60000613d000000000101043b000000000001004b0000000201000029000027e70000613d0000000001010433000000000001004b0000000109000029000027c80000613d00000b630010009c000027c90000213d0000001f0010008c000027c90000a13d0000000001090433000000000001004b0000000002000039000000010200c039000000000021004b000027c90000c13d000000000001004b000027db0000613d000000000001042d0000000001000019000028ff0001043000000b5501000041000000000010043f0000004101000039000000040010043f00000ac801000041000028ff00010430000000000001004b000027de0000c13d000000400100043d00000b7202000041000000000021043500000a400010009c00000a4001008041000000400110021000000abf011001c7000028ff00010430000000400100043d00000b7302000041000027e90000013d00000a400090009c00000a4009008041000000400290021000000a400010009c00000a40010080410000006001100210000000000121019f000028ff00010430000000000001042f000000400100043d00000b7402000041000000000021043500000004021000390000000303000029000000000032043500000a400010009c00000a4001008041000000400110021000000ac8011001c7000028ff000104300006000000000002000600000003001d000400000001001d00000b3e01000041000000000301041a000000000023004b000028020000813d000000000003004b000028000000613d00000b610320012900000ad304000041000000000404041a000000000043004b000028af0000413d00000b3e03000041000000000023041b00000ad202000041000000000202041a000000000002004b00000006040000290000281f0000613d00000ad303000041000000000303041a00000ad404000041000000000404041a000000000034001a000028b90000413d000000000334001900000ad504000041000000000404041a0000000003340019000000000043004b00000000040000390000000104004039000000010040008c000028b90000613d000000000003004b0000281e0000613d00000b6104200129000000060040006c000028af0000413d00000006042000b900000000043400d90000281f0000013d000000000400001900000aec03000041000000000303041a000000000003004b0000285f0000613d00000b6101300129000000000014004b000028af0000213d00000b1c01000041000000000101041a00000a4305100198000028b10000613d00000000014300a900000b510310012a000000000023001a000028b90000413d000000000123001900000ad202000041000000000012041b000200000005001d000000000050043f00000ad901000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c70000801002000039000500000004001d000300000003001d28fd28f80000040f0000000100200190000028af0000613d000000000101043b000000000101041a000100000001001d000000030010002a0000000201000029000028b90000413d000000000010043f00000ad901000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f00000005040000290000000100200190000028af0000613d00000003030000290000000102300029000000000101043b000000000021041b00000b3201000041000000000201041a000000000032001a000028b90000413d0000000002320019000000000021041b000000000434004b000028b90000413d000000040100002900000a4303100198000028b10000613d00000ad201000041000000000201041a000000000042001a000028b90000413d0000000002420019000000000021041b000400000003001d000000000030043f00000ad901000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c70000801002000039000500000004001d28fd28f80000040f00000005030000290000000100200190000028af0000613d000000000101043b000000000101041a000300000001001d000000000031001a0000000401000029000028b90000413d000000000010043f00000ad901000041000000200010043f000000000100041400000a400010009c00000a4001008041000000c00110021000000ab9011001c7000080100200003928fd28f80000040f00000005040000290000000100200190000028af0000613d0000000302400029000000000101043b000000000021041b00000b3201000041000000000201041a000000000042001a0000000405000029000028b90000413d0000000002420019000000000021041b00000ad401000041000000000201041a000000060020002a000028b90000413d00000006030000290000000002320019000000000021041b000000400100043d00000020021000390000000000320435000000000041043500000a400010009c00000a40010080410000004001100210000000000200041400000a400020009c00000a4002008041000000c002200210000000000112019f00000ab9011001c70000800d02000039000000020300003900000b7a0400004128fd28f30000040f0000000100200190000028af0000613d000000000001042d0000000001000019000028ff00010430000000400100043d00000ae502000041000000000021043500000a400010009c00000a4001008041000000400110021000000abf011001c7000028ff0001043000000b5501000041000000000010043f0000001101000039000000040010043f00000ac801000041000028ff00010430000000000001042f00000a400010009c00000a4001008041000000400110021000000a400020009c00000a40020080410000006002200210000000000112019f000000000200041400000a400020009c00000a4002008041000000c002200210000000000112019f00000af2011001c7000080100200003928fd28f80000040f0000000100200190000028d30000613d000000000101043b000000000001042d0000000001000019000028ff0001043000000000050100190000000000200443000000050030008c000028e30000413d000000040100003900000000020000190000000506200210000000000664001900000005066002700000000006060031000000000161043a0000000102200039000000000031004b000028db0000413d00000a400030009c00000a40030080410000006001300210000000000200041400000a400020009c00000a4002008041000000c002200210000000000112019f00000b7b011001c7000000000205001928fd28f80000040f0000000100200190000028f20000613d000000000101043b000000000001042d000000000001042f000028f6002104210000000102000039000000000001042d0000000002000019000000000001042d000028fb002104230000000102000039000000000001042d0000000002000019000000000001042d000028fd00000432000028fe0001042e000028ff0001043000000000000000000000000000000000000000000000000000000000ffffffff00000000000000000000000000000000000000000000000000000001ffffffe000000000000000000000000000000000000000000000000000000000ffffffe0000000000000000000000000fffffffffffffffffffffffffffffffffffffffff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a000000000000000000000000000000000000000000000000ff0000000000000000000000000000000000000000000000000000000000000000ffffffffffffffff0200000000000000000000000000000000000020000000000000000000000000c7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d200000002000000000000000000000000000000c0000001000000000000000000000000000000000000000000000000000000000000000000000000007ecebdff00000000000000000000000000000000000000000000000000000000bb0b6a5200000000000000000000000000000000000000000000000000000000dd62ed3d00000000000000000000000000000000000000000000000000000000f2fde38a00000000000000000000000000000000000000000000000000000000f5eb42db00000000000000000000000000000000000000000000000000000000f5eb42dc00000000000000000000000000000000000000000000000000000000fe41e52400000000000000000000000000000000000000000000000000000000ff7bd03d00000000000000000000000000000000000000000000000000000000f2fde38b00000000000000000000000000000000000000000000000000000000f37e8d3800000000000000000000000000000000000000000000000000000000ebfd66e700000000000000000000000000000000000000000000000000000000ebfd66e800000000000000000000000000000000000000000000000000000000f018d7c000000000000000000000000000000000000000000000000000000000f0f4426000000000000000000000000000000000000000000000000000000000dd62ed3e00000000000000000000000000000000000000000000000000000000e4e4856000000000000000000000000000000000000000000000000000000000ca5eb5e000000000000000000000000000000000000000000000000000000000d038c4a800000000000000000000000000000000000000000000000000000000d038c4a900000000000000000000000000000000000000000000000000000000d5002f2e00000000000000000000000000000000000000000000000000000000d505accf00000000000000000000000000000000000000000000000000000000ca5eb5e100000000000000000000000000000000000000000000000000000000cae791ed00000000000000000000000000000000000000000000000000000000bf5eb2bc00000000000000000000000000000000000000000000000000000000bf5eb2bd00000000000000000000000000000000000000000000000000000000c6e6f59200000000000000000000000000000000000000000000000000000000bb0b6a5300000000000000000000000000000000000000000000000000000000bc70b3540000000000000000000000000000000000000000000000000000000098aca92100000000000000000000000000000000000000000000000000000000b3b4084400000000000000000000000000000000000000000000000000000000b5f3a12700000000000000000000000000000000000000000000000000000000b5f3a12800000000000000000000000000000000000000000000000000000000b92d0eff00000000000000000000000000000000000000000000000000000000b98bd07000000000000000000000000000000000000000000000000000000000b3b4084500000000000000000000000000000000000000000000000000000000b5d2074b00000000000000000000000000000000000000000000000000000000a8edcb8b00000000000000000000000000000000000000000000000000000000a8edcb8c00000000000000000000000000000000000000000000000000000000a9059cbb00000000000000000000000000000000000000000000000000000000ab88ecb20000000000000000000000000000000000000000000000000000000098aca92200000000000000000000000000000000000000000000000000000000a38097680000000000000000000000000000000000000000000000000000000084b0196d000000000000000000000000000000000000000000000000000000008fcb4e5a000000000000000000000000000000000000000000000000000000008fcb4e5b000000000000000000000000000000000000000000000000000000009388bd520000000000000000000000000000000000000000000000000000000095d89b410000000000000000000000000000000000000000000000000000000084b0196e000000000000000000000000000000000000000000000000000000008da5cb5b00000000000000000000000000000000000000000000000000000000817b1cd100000000000000000000000000000000000000000000000000000000817b1cd2000000000000000000000000000000000000000000000000000000008456cb59000000000000000000000000000000000000000000000000000000007ecebe00000000000000000000000000000000000000000000000000000000007edddbb2000000000000000000000000000000000000000000000000000000005535d46000000000000000000000000000000000000000000000000000000000715018a5000000000000000000000000000000000000000000000000000000007bb4ec30000000000000000000000000000000000000000000000000000000007d00a54e000000000000000000000000000000000000000000000000000000007d00a54f000000000000000000000000000000000000000000000000000000007d25a05e000000000000000000000000000000000000000000000000000000007e071776000000000000000000000000000000000000000000000000000000007bb4ec31000000000000000000000000000000000000000000000000000000007be98ea30000000000000000000000000000000000000000000000000000000073334d5a0000000000000000000000000000000000000000000000000000000073334d5b0000000000000000000000000000000000000000000000000000000075b24ebe00000000000000000000000000000000000000000000000000000000779c9ad800000000000000000000000000000000000000000000000000000000715018a600000000000000000000000000000000000000000000000000000000718da7ee0000000000000000000000000000000000000000000000000000000066285966000000000000000000000000000000000000000000000000000000006d780458000000000000000000000000000000000000000000000000000000006d780459000000000000000000000000000000000000000000000000000000006daf72840000000000000000000000000000000000000000000000000000000070a0823100000000000000000000000000000000000000000000000000000000662859670000000000000000000000000000000000000000000000000000000067700b99000000000000000000000000000000000000000000000000000000005e280f10000000000000000000000000000000000000000000000000000000005e280f110000000000000000000000000000000000000000000000000000000061d027b3000000000000000000000000000000000000000000000000000000005535d461000000000000000000000000000000000000000000000000000000005c975abb0000000000000000000000000000000000000000000000000000000017442b6f00000000000000000000000000000000000000000000000000000000313ce566000000000000000000000000000000000000000000000000000000003644e514000000000000000000000000000000000000000000000000000000003644e515000000000000000000000000000000000000000000000000000000003f4ba83a00000000000000000000000000000000000000000000000000000000489641cc00000000000000000000000000000000000000000000000000000000313ce567000000000000000000000000000000000000000000000000000000003400288b000000000000000000000000000000000000000000000000000000001c5aaf8a000000000000000000000000000000000000000000000000000000001c5aaf8b0000000000000000000000000000000000000000000000000000000023b872dd00000000000000000000000000000000000000000000000000000000293e2fb50000000000000000000000000000000000000000000000000000000017442b700000000000000000000000000000000000000000000000000000000018160ddd00000000000000000000000000000000000000000000000000000000095ea7b200000000000000000000000000000000000000000000000000000000121c55ec00000000000000000000000000000000000000000000000000000000121c55ed0000000000000000000000000000000000000000000000000000000013137d650000000000000000000000000000000000000000000000000000000013ff7e9f00000000000000000000000000000000000000000000000000000000095ea7b3000000000000000000000000000000000000000000000000000000000a28a4770000000000000000000000000000000000000000000000000000000006fdde020000000000000000000000000000000000000000000000000000000006fdde0300000000000000000000000000000000000000000000000000000000076a09f70000000000000000000000000000000000000000000000000000000001e1d1140000000000000000000000000000000000000000000000000000000003e7467500000000000000000000000000000000000000200000000000000000000000009b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00cd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300c064a301e926254981c9bd3b3225923d097271573deb3cc61ae7f6a144f10a030200000000000000000000000000000000000040000000000000000000000000000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeec064a301e926254981c9bd3b3225923d097271573deb3cc61ae7f6a144f10a02ca706bcf0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000440000000000000000000000006a43f8d1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000c064a301e926254981c9bd3b3225923d097271573deb3cc61ae7f6a144f10a00312ddf7d0000000000000000000000000000000000000000000000000000000090890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a15cae33fc2000000000000000000000000000000000000000000000000000000004105f5e700000000000000000000000000000000000000000000000000000000dd932cf12f0dd29482349e8f041f211cd1a01e556f17b4835472bd462fb0910e52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace01ea598cb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024000000000000000000000000a9059cbb00000000000000000000000000000000000000000000000000000000e602df05000000000000000000000000000000000000000000000000000000000bc48bc300000000000000000000000000000000000000000000000000000000e52970aa00000000000000000000000000000000000000000000000000000000d93c06650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000008000000000000000001806aa1896bbf26568e884a7374b41e002500962caba6a15023a8d90e8508b8302000002000000000000000000000000000000240000000000000000000000001e4ec46b00000000000000000000000000000000000000000000000000000000ddf967707f52bbdea6c202114c491d81e6de0cb9ded430e88a276a6f8d3e3800dd932cf12f0dd29482349e8f041f211cd1a01e556f17b4835472bd462fb09100dd932cf12f0dd29482349e8f041f211cd1a01e556f17b4835472bd462fb09102dd932cf12f0dd29482349e8f041f211cd1a01e556f17b4835472bd462fb09103c064a301e926254981c9bd3b3225923d097271573deb3cc61ae7f6a144f10a017c134b5c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000084000000000000000000000000ddf967707f52bbdea6c202114c491d81e6de0cb9ded430e88a276a6f8d3e380102000000000000000000000000000000000000600000000000000000000000008b2a1e1ad5e0578c3dd82494156e985dade827a87c573b5c1c7716a32162ad64000000000000000000000000000000000000000000000000ffffffffffffff7f310ab089e4439a4c15d089f94afb7896ff553aecb10793d0ab882de59d99a32e0200000200000000000000000000000000000044000000000000000000000000dd932cf12f0dd29482349e8f041f211cd1a01e556f17b4835472bd462fb09108dd932cf12f0dd29482349e8f041f211cd1a01e556f17b4835472bd462fb09109dd932cf12f0dd29482349e8f041f211cd1a01e556f17b4835472bd462fb0910a000000000000000000000000000000000000000000000000ffffffffffffffbf6c3a45613039e0a1117bd6ce110ab3c920271709c010983d921a2cd268e2ea472c5211c600000000000000000000000000000000000000000000000000000000d92e233d000000000000000000000000000000000000000000000000000000001f2a2005000000000000000000000000000000000000000000000000000000003ee5aeb5000000000000000000000000000000000000000000000000000000009016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300118cdaa70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000240000008000000000000000000000000000000000000000000000000000000000000000000000000000030d40dd932cf12f0dd29482349e8f041f211cd1a01e556f17b4835472bd462fb09106796b89b91644bc98cd93958e4c9038275d622183e25ac5af08cc6b5d9553913202000002000000000000000000000000000000040000000000000000000000005ab42ced628888259c08ac98db1eb0cf702fc1501344311d8b100cd1bfe4bb006e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9000000000000000000000000000000000000000000000000ffffffffffffff1f0200000000000000000000000000000000000000000000000000000000000000190100000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000420000000000000000000000007fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a000000000000000000000000000000000000000800000000000000000000000004b800e4600000000000000000000000000000000000000000000000000000000f645eedf00000000000000000000000000000000000000000000000000000000d78bce0c0000000000000000000000000000000000000000000000000000000062791302000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000800000000000000000ffffffffffffffffffffffff0000000000000000000000000000000000000000ef31c3aa06f1248be5c6b6e1e2d20eadd1a9b8ba067380b4a303ef49f9a489acca5eb5e1000000000000000000000000000000000000000000000000000000008d2bda5d9f6ffb5796910376005392955773acee5548d0fcdb10e7c264ea00009a6d49cd00000000000000000000000000000000000000000000000000000000ffff00000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000be4864a8e820971c0247f5992e2da559595f7bf076a21cb5928d443d2a13b674ffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000000100000000000000018be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e052c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace03d51f7571d6dac09653a26865efe6a95470726282129c05857c4e903b89b715502ae08a8e29253f69ac5d979a101956ab8f8d9d7ded63fa7a83b16fc47648eab0d51f7571d6dac09653a26865efe6a95470726282129c05857c4e903b89b7154f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace04b95d7fc1a65b21b185b3a8b4edbc0da68853b3882a5e5b59f64ac6b3144b5d5646a2803e59a4de4e7a4c574b1243f25977ac4c77d5a1a4a609b5394cebb4a2aab95d7fc1a65b21b185b3a8b4edbc0da68853b3882a5e5b59f64ac6b3144b5d553100000000000000000000000000000000000000000000000000000000000000a16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d102bd52a2c1e0d1918f12309266e475cfdc2c0357fb85ecea6d0612460264762a8342ad5d3e1f2e6e70edcf6d991b8a3023d3fca8047a131592f9edb9fd9b89d57dbd52a2c1e0d1918f12309266e475cfdc2c0357fb85ecea6d0612460264762a82a16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d103a0631cb7ea071eebce38448a571977956eb8708003e244f56723dbf02228948b5f9ce34815f8e11431c7bb75a8e6886a91478f7ffc1dbb0a98dc240fddd76b75a0631cb7ea071eebce38448a571977956eb8708003e244f56723dbf02228948aa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d100a16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d101dd932cf12f0dd29482349e8f041f211cd1a01e556f17b4835472bd462fb091074a0f73c7c1971268d36d35f4aa566bc6bf4d11a95048a36db084492132ab6f743881bcae1b79d28312da310a8d211e93a9d6ea5a30e04f43bca54b0768e5b3e756586991759b0dd92948599d3a023e9ba12504fa867fbc532ba4e1d2502a6f262d365d82646798ae645c4baa2dc2ee228626f61d8b5395bf298ba125a3c6b100af53bfd91676a5f7c3d8a2bcd6a9df83b50bde13a00670e3db6a6cefa04823bc487698e326934c06370ca3c28e3bca79fe27d578048e9d42af7fa98f2e481e00b68fd1a788a85f8f18de7976d851969ff9ff2216de81169c17a6f4ac94c23defffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffd7e6bcf800000000000000000000000000000000000000000000000000000000b5863604000000000000000000000000000000000000000000000000000000001e4fbdf700000000000000000000000000000000000000000000000000000000f92ee8a900000000000000000000000000000000000000000000000000000000c064a301e926254981c9bd3b3225923d097271573deb3cc61ae7f6a144f10a04f10fc780c78f994a214c79a2ae8d8b7bfe7cc3f0f935a8f05a29525e71d7f127000000000000000000000000000000000000000000000000ffffffffffffff9f000000000000000000000000000000000000000000000000ffffffffffffff5fdd932cf12f0dd29482349e8f041f211cd1a01e556f17b4835472bd462fb0910b416ecebf00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff3f3a69197e0000000000000000000000000000000000000000000000000000000084bc3eb000000000000000000000000000000000000000000000000000000000dd932cf12f0dd29482349e8f041f211cd1a01e556f17b4835472bd462fb091040000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004000000080000000000000000094ba8d5f7922370aad18b707619f668a8fd07cbdf364eeaa6a048e737c9f2a8208c379a0000000000000000000000000000000000000000000000000000000004549503731323a20556e696e697469616c697a656400000000000000000000000000000000000000000000000000000000000064000000800000000000000000000000000000000000000000000000000000000000000000ffffffffffffffdf0f000000000000000000000000000000000000000000000000000000000000009a8a0592ac89c5ad3bc6df8224c17b485976f597df104ee20d0df415241f670bdd932cf12f0dd29482349e8f041f211cd1a01e556f17b4835472bd462fb0910d62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258dd932cf12f0dd29482349e8f041f211cd1a01e556f17b4835472bd462fb0910196a88a019b24fd6b65f34b2d2145e4c74f774e5ef02b2b85180a51fae1918a580000000000000000000000000000000000000000000000000000000000030d41dd932cf12f0dd29482349e8f041f211cd1a01e556f17b4835472bd462fb0910558d620b3000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000020000000800000000000000000d9933b26b990ffbd85af14fd2796031d934c55d6148174e62f05a912a837f9ed5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa8dfc202b0000000000000000000000000000000000000000000000000000000072ab1bc1039b79dc4724ffca13de82c96834302d3c7e0d4252232d4b2dd8f900238399d427b947898edb290f5ff0f9109849b1c3ba196a42e35f00c50a54b98b00000000000000000000000000000000000000a000000000000000000000000091ac5e4f00000000000000000000000000000000000000000000000000000000c26bebcc00000000000000000000000000000000000000000000000000000000dd932cf12f0dd29482349e8f041f211cd1a01e556f17b4835472bd462fb0910c756688fe00000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000004080000000000000000000000000000000000000000000000000000000000000a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe000000000000000000000000000000000000000000000000000000000000f42400200000000000000000000000000000000000080000000000000000000000000d36e76ee550c32ed4f6b9d679dd357f6eece52b7634554661fcd8d02eebfb6646849bd31a1772b1b6992f1f328cce6888b435faff25d13805baee12a8a944bbe4e487b710000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000007cb590120000000000000000000000000000000000000000000000000000000094280d62000000000000000000000000000000000000000000000000000000003d693ada00000000000000000000000000000000000000000000000000000000f6ff4fb700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffa05bf93781000000000000000000000000000000000000000000000000000000007e5f9349000000000000000000000000000000000000000000000000000000005c427cd900000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdf7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000ffffffffffffff60000000000000000000000000000000000000000000000000ffffffffffffffc0ddc28c5800000000000000000000000000000000000000000000000000000000fb8f41b2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064000000000000000000000000ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9d9c909296d9c674451c0c24f02cb64981eb3b727f99865939192f880a755dcbec442f050000000000000000000000000000000000000000000000000000000096c6fd1e000000000000000000000000000000000000000000000000000000009f70412000000000000000000000000000000000000000000000000000000000e4fe1d9400000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000023b872dd0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ffffffe01425ea42000000000000000000000000000000000000000000000000000000005274afe7000000000000000000000000000000000000000000000000000000009996b315000000000000000000000000000000000000000000000000000000005373352a000000000000000000000000000000000000000000000000000000002637a450000000000000000000000000000000000000000000000000000000008c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f0200000200000000000000000000000000000000000000000000000000000000d3fd81a241ed1a61a6b8479304e83088dbed5066b2f866e7f9318f57203c7397
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000005c6cff4b7c49805f8295ff73c204ac83f3bc4ae70000000000000000000000000000000000000000000000000000000000007595
-----Decoded View---------------
Arg [0] : _endpoint (address): 0x5c6cfF4b7C49805F8295Ff73C204ac83f3bC4AE7
Arg [1] : _srcEid (uint32): 30101
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000005c6cff4b7c49805f8295ff73c204ac83f3bc4ae7
Arg [1] : 0000000000000000000000000000000000000000000000000000000000007595
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.