Description:
Proxy contract enabling upgradeable smart contract patterns. Delegates calls to an implementation contract.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"settings": {
"evmVersion": "cancun",
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": [],
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
},
"sources": {
"contracts/CrossChainDispatcher.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
import {Initializable} from "./dependencies/openzeppelin-upgradeable/proxy/utils/Initializable.sol";
import {IERC20} from "./dependencies/openzeppelin/token/ERC20/IERC20.sol";
import {BytesLib} from "./dependencies/@layerzerolabs/solidity-examples/util/BytesLib.sol";
import {SafeERC20} from "./dependencies/openzeppelin/token/ERC20/utils/SafeERC20.sol";
import {IStargateRouter} from "./dependencies/stargate-protocol/interfaces/IStargateRouter.sol";
import {IStargateReceiver} from "./dependencies/stargate-protocol/interfaces/IStargateReceiver.sol";
import {IStargateComposer} from "./dependencies/stargate-protocol/interfaces/IStargateComposer.sol";
import {ReentrancyGuardDeprecated} from "./utils/ReentrancyGuardDeprecated.sol";
import {ReentrancyGuardTransient} from "./utils/ReentrancyGuardTransient.sol";
import {SynthContext} from "./utils/SynthContext.sol";
import {IWETH} from "./interfaces/external/IWETH.sol";
import {IStargatePool} from "./interfaces/external/IStargatePool.sol";
import {IStargateFactory} from "./interfaces/external/IStargateFactory.sol";
import {CrossChainDispatcherStorageV2} from "./storage/CrossChainDispatcherStorage.sol";
import {IProxyOFT} from "./interfaces/IProxyOFT.sol";
import {ISmartFarmingManager} from "./interfaces/ISmartFarmingManager.sol";
import {ISyntheticToken} from "./interfaces/ISyntheticToken.sol";
import {IPoolRegistry} from "./interfaces/IPoolRegistry.sol";
import {IPool} from "./interfaces/IPool.sol";
import {IManageable} from "./interfaces/IManageable.sol";
import {ISwapper} from "./interfaces/external/ISwapper.sol";
import {CrossChainLib} from "./lib/CrossChainLib.sol";
error AddressIsNull();
error InvalidMsgSender();
error BridgingIsPaused();
error InvalidFromAddress();
error InvalidToAddress();
error NewValueIsSameAsCurrent();
error SenderIsNotGovernor();
error DestinationChainNotAllowed();
error InvalidOperationType();
error BridgeTokenNotSupported();
error InvalidSlippageParam();
error InvalidPayload();
/**
* @title Cross-chain dispatcher
*/
contract CrossChainDispatcher is
SynthContext,
Initializable,
ReentrancyGuardDeprecated,
ReentrancyGuardTransient,
CrossChainDispatcherStorageV2
{
using SafeERC20 for IERC20;
using BytesLib for bytes;
string public constant VERSION = "1.3.2";
/**
* @dev LayerZero adapter param version
* See more: https://layerzero.gitbook.io/docs/evm-guides/advanced/relayer-adapter-parameters
*/
uint16 private constant LZ_ADAPTER_PARAMS_VERSION = 2;
uint256 private constant MAX_BPS = 100_00;
struct LayerZeroParams {
address tokenIn;
uint16 dstChainId;
uint256 amountIn;
uint256 nativeFee;
bytes payload;
address refundAddress;
uint64 dstGasForCall;
uint256 dstNativeAmount;
}
/// @notice Emitted when Lz base gas limit updated
event LzBaseGasLimitUpdated(uint256 oldLzBaseGasLimit, uint256 newLzBaseGasLimit);
/// @notice Emitted when Stargate composer is updated
event StargateComposerUpdated(IStargateComposer oldStargateComposer, IStargateComposer newStargateComposer);
/// @notice Emitted when Stargate pool id is updated
event StargatePoolIdUpdated(address indexed token, uint256 oldPoolId, uint256 newPoolId);
/// @notice Emitted when Stargate slippage is updated
event StargateSlippageUpdated(uint256 oldStargateSlippage, uint256 newStargateSlippage);
/// @notice Emitted when synth->underlying L1 swap gas limit is updated
event LeverageSwapTxGasLimitUpdated(uint64 oldSwapTxGasLimit, uint64 newSwapTxGasLimit);
/// @notice Emitted when leverage callback gas limit is updated
event LeverageCallbackTxGasLimitUpdated(uint64 oldCallbackTxGasLimit, uint64 newCallbackTxGasLimit);
/// @notice Emitted when underlying->synth L1 swap gas limit is updated
event FlashRepaySwapTxGasLimitUpdated(uint64 oldSwapTxGasLimit, uint64 newSwapTxGasLimit);
/// @notice Emitted when flash repay callback gas limit is updated
event FlashRepayCallbackTxGasLimitUpdated(uint64 oldCallbackTxGasLimit, uint64 newCallbackTxGasLimit);
/// @notice Emitted when flag for pause bridge transfer is toggled
event BridgingIsActiveUpdated(bool newIsActive);
/// @notice Emitted when a Cross-chain dispatcher mapping is updated
event CrossChainDispatcherUpdated(uint16 chainId, address oldCrossChainDispatcher, address newCrossChainDispatcher);
/// @notice Emitted when flag for support chain is toggled
event DestinationChainIsActiveUpdated(uint16 chainId, bool newIsSupported);
modifier onlyGovernor() {
if (_msgSender() != _poolRegistry.governor()) revert SenderIsNotGovernor();
_;
}
modifier onlyIfBridgingIsNotPaused() {
if (!isBridgingActive || !IManageable(_msgSender()).pool().isBridgingActive()) revert BridgingIsPaused();
_;
}
modifier onlyIfSmartFarmingManager() {
IPool _pool = IManageable(_msgSender()).pool();
if (!_poolRegistry.isPoolRegistered(address(_pool))) revert InvalidMsgSender();
if (_msgSender() != address(_pool.smartFarmingManager())) revert InvalidMsgSender();
_;
}
modifier onlyIfStargateComposer() {
if (_msgSender() != address(stargateComposer)) revert InvalidMsgSender();
_;
}
modifier onlyIfProxyOFT() {
if (!_isValidProxyOFT(_msgSender())) revert InvalidMsgSender();
_;
}
constructor() {
_disableInitializers();
}
receive() external payable {}
function initialize(IPoolRegistry poolRegistry_, address weth_, address sgeth_) external initializer {
if (address(poolRegistry_) == address(0)) revert AddressIsNull();
_poolRegistry = poolRegistry_;
stargateSlippage = 50; // 0.5%
lzBaseGasLimit = 200_000;
flashRepayCallbackTxGasLimit = 750_000;
flashRepaySwapTxGasLimit = 500_000;
leverageCallbackTxGasLimit = 750_000;
leverageSwapTxGasLimit = 750_000;
weth = weth_;
sgeth = sgeth_;
}
/**
* @notice Called by the OFT contract when tokens are received from source chain.
* @dev Token received are swapped to another token
* @param srcChainId_ The chain id of the source chain.
* @param from_ The address of the account who calls the sendAndCall() on the source chain.
* @param amount_ The amount of tokens to transfer.
* @param payload_ Additional data with no specified format.
*/
function onOFTReceived(
uint16 srcChainId_,
bytes calldata /*srcAddress_*/,
uint64 /*nonce_*/,
bytes calldata from_,
uint amount_,
bytes calldata payload_
) external override onlyIfProxyOFT {
address _from = from_.toAddress(0);
if (_from == address(0) || _from != crossChainDispatcherOf[srcChainId_]) revert InvalidFromAddress();
uint8 _op = CrossChainLib.getOperationType(payload_);
if (_op == CrossChainLib.FLASH_REPAY) {
_crossChainFlashRepayCallback(amount_, payload_);
} else if (_op == CrossChainLib.LEVERAGE) {
_swapAndTriggerLeverageCallback(srcChainId_, amount_, payload_);
} else {
revert InvalidOperationType();
}
}
/**
* @dev Finalize cross-chain flash repay process. The callback may fail due to slippage.
*/
function _crossChainFlashRepayCallback(uint amount_, bytes calldata payload_) private {
(address proxyOFT_, address _smartFarmingManager, uint256 _requestId) = CrossChainLib
.decodeFlashRepayCallbackPayload(payload_);
IERC20 _syntheticToken = IERC20(IProxyOFT(proxyOFT_).token());
_syntheticToken.safeApprove(_smartFarmingManager, 0);
_syntheticToken.safeApprove(_smartFarmingManager, amount_);
ISmartFarmingManager(_smartFarmingManager).crossChainFlashRepayCallback(_requestId, amount_);
}
/**
* @dev Swap synthetic token for underlying and trigger callback call
*/
function _swapAndTriggerLeverageCallback(uint16 srcChainId_, uint amountIn_, bytes calldata payload_) private {
// 1. Swap
(
address _srcSmartFarmingManager,
address _dstProxyOFT,
uint256 _requestId,
uint256 _sgPoolId,
address _account,
uint256 _amountOutMin,
uint256 _callbackTxNativeFee
) = CrossChainLib.decodeLeverageSwapPayload(payload_);
address _bridgeToken = IStargatePool(IStargateFactory(stargateComposer.factory()).getPool(_sgPoolId)).token();
if (_bridgeToken == sgeth) _bridgeToken = weth;
amountIn_ = _swap({
requestId_: _requestId,
tokenIn_: IProxyOFT(_dstProxyOFT).token(),
tokenOut_: _bridgeToken,
amountIn_: amountIn_,
amountOutMin_: _amountOutMin
});
// 2. Transfer underlying to source chain
uint16 _srcChainId = srcChainId_;
_sendUsingStargate(
LayerZeroParams({
tokenIn: _bridgeToken,
dstChainId: _srcChainId,
amountIn: amountIn_,
nativeFee: _callbackTxNativeFee + extraCallbackTxNativeFee[_requestId],
payload: CrossChainLib.encodeLeverageCallbackPayload(_srcSmartFarmingManager, _requestId),
refundAddress: _account,
dstGasForCall: leverageCallbackTxGasLimit,
dstNativeAmount: 0
})
);
}
/**
* @notice Receive token and payload from Stargate
* @param srcChainId_ The chain id of the source chain.
* @param srcAddress_ The remote Bridge address
* @param token_ The token contract on the local chain
* @param amountLD_ The qty of local _token contract tokens
* @param payload_ The payload
*/
function sgReceive(
uint16 srcChainId_,
bytes memory srcAddress_,
uint256 /*nonce_*/,
address token_,
uint256 amountLD_,
bytes memory payload_
) external override onlyIfStargateComposer {
// Note: Stargate uses SGETH as `token_` when receiving native ETH
if (token_ == sgeth) {
address _weth = weth;
IWETH(_weth).deposit{value: amountLD_}();
token_ = _weth;
}
address _srcAddress = srcAddress_.toAddress(0);
if (_srcAddress == address(0) || _srcAddress != crossChainDispatcherOf[srcChainId_])
revert InvalidFromAddress();
uint8 _op = CrossChainLib.getOperationType(payload_);
if (_op == CrossChainLib.LEVERAGE) {
_crossChainLeverageCallback(token_, amountLD_, payload_);
} else if (_op == CrossChainLib.FLASH_REPAY) {
_swapAndTriggerFlashRepayCallback(srcChainId_, token_, amountLD_, payload_);
} else {
revert InvalidOperationType();
}
}
/**
* @dev Finalize cross-chain leverage process. The callback may fail due to slippage.
*/
function _crossChainLeverageCallback(address bridgeToken_, uint256 amount_, bytes memory payload_) private {
(address _smartFarmingManager, uint256 _requestId) = CrossChainLib.decodeLeverageCallbackPayload(payload_);
IERC20(bridgeToken_).safeApprove(_smartFarmingManager, 0);
IERC20(bridgeToken_).safeApprove(_smartFarmingManager, amount_);
ISmartFarmingManager(_smartFarmingManager).crossChainLeverageCallback(_requestId, amount_);
}
/**
* @dev Send synthetic token cross-chain
*/
function _sendUsingLayerZero(LayerZeroParams memory params_) private {
address _to = crossChainDispatcherOf[params_.dstChainId];
if (_to == address(0)) revert AddressIsNull();
bytes memory _adapterParams = abi.encodePacked(
LZ_ADAPTER_PARAMS_VERSION,
uint256(lzBaseGasLimit + params_.dstGasForCall),
params_.dstNativeAmount,
(params_.dstNativeAmount > 0) ? _to : address(0)
);
ISyntheticToken(params_.tokenIn).proxyOFT().sendAndCall{value: params_.nativeFee}({
_from: address(this),
_dstChainId: params_.dstChainId,
_toAddress: abi.encodePacked(_to),
_amount: params_.amountIn,
_payload: params_.payload,
_dstGasForCall: params_.dstGasForCall,
_refundAddress: payable(params_.refundAddress),
_zroPaymentAddress: address(0),
_adapterParams: _adapterParams
});
}
/**
* @dev Swap underlying for synthetic token and trigger callback call
*/
function _swapAndTriggerFlashRepayCallback(
uint16 srcChainId_,
address token_,
uint256 amount_,
bytes memory payload_
) private {
// 1. Swap
(
address _srcSmartFarmingManager,
address _dstProxyOFT,
uint256 _requestId,
address _account,
uint256 _amountOutMin,
uint256 _callbackTxNativeFee
) = CrossChainLib.decodeFlashRepaySwapPayload(payload_);
address _syntheticToken = IProxyOFT(_dstProxyOFT).token();
amount_ = _swap({
requestId_: _requestId,
tokenIn_: token_,
tokenOut_: _syntheticToken,
amountIn_: amount_,
amountOutMin_: _amountOutMin
});
// 2. Transfer synthetic token to source chain
uint16 _srcChainId = srcChainId_;
address _srcProxyOFT = IProxyOFT(_dstProxyOFT).getProxyOFTOf(_srcChainId);
_sendUsingLayerZero(
LayerZeroParams({
tokenIn: _syntheticToken,
dstChainId: _srcChainId,
amountIn: amount_,
payload: CrossChainLib.encodeFlashRepayCallbackPayload(
_srcProxyOFT,
_srcSmartFarmingManager,
_requestId
),
refundAddress: _account,
dstGasForCall: flashRepayCallbackTxGasLimit,
dstNativeAmount: 0,
nativeFee: _callbackTxNativeFee + extraCallbackTxNativeFee[_requestId]
})
);
}
/**
* @notice Retry swap underlying and trigger callback.
* @param srcChainId_ The source chain of failed tx
* @param srcAddress_ The source path of failed tx
* @param nonce_ The nonce of failed tx
* @param token_ The token of failed tx
* @param amount_ The amountIn of failed tx
* @param payload_ The payload of failed tx
* @param newAmountOutMin_ If swap failed due to slippage, caller may set lower newAmountOutMin_
*/
function retrySwapAndTriggerFlashRepayCallback(
uint16 srcChainId_,
bytes calldata srcAddress_,
uint64 nonce_,
address token_,
uint256 amount_,
bytes calldata payload_,
uint256 newAmountOutMin_
) external payable nonReentrant {
IStargateComposer _stargateComposer = stargateComposer;
bytes memory _sgReceiveCallData = abi.encodeWithSelector(
IStargateReceiver.sgReceive.selector,
srcChainId_,
abi.encodePacked(crossChainDispatcherOf[srcChainId_]),
nonce_,
token_,
amount_,
payload_
);
(, , uint256 _requestId, address _account, , ) = CrossChainLib.decodeFlashRepaySwapPayload(payload_);
if (msg.value > 0) {
extraCallbackTxNativeFee[_requestId] += msg.value;
}
if (_msgSender() == _account) {
// Note: If `swapAmountOutMin[_requestId]` is `0` (default value), swap function will use payload's slippage param
if (newAmountOutMin_ == 0) revert InvalidSlippageParam();
swapAmountOutMin[_requestId] = newAmountOutMin_;
}
// Note: `clearCachedSwap()` has checks to ensure that the args are consistent
_stargateComposer.clearCachedSwap(srcChainId_, srcAddress_, nonce_, address(this), _sgReceiveCallData);
}
/**
* @notice Retry swap and trigger callback.
* @param srcChainId_ The source chain of failed tx
* @param srcAddress_ The source path of failed tx
* @param nonce_ The nonce of failed tx
* @param amount_ The amountIn of failed tx
* @param payload_ The payload of failed tx
* @param newAmountOutMin_ If swap failed due to slippage, caller may set lower newAmountOutMin_
*/
function retrySwapAndTriggerLeverageCallback(
uint16 srcChainId_,
bytes calldata srcAddress_,
uint64 nonce_,
uint256 amount_,
bytes calldata payload_,
uint256 newAmountOutMin_
) external payable nonReentrant {
(, address _dstProxyOFT, uint256 _requestId, , address _account, , ) = CrossChainLib.decodeLeverageSwapPayload(
payload_
);
if (!_isValidProxyOFT(_dstProxyOFT)) revert InvalidPayload();
if (msg.value > 0) {
extraCallbackTxNativeFee[_requestId] += msg.value;
}
if (_msgSender() == _account) {
// Note: If `swapAmountOutMin[_requestId]` is `0` (default value), swap function will use payload's slippage param
if (newAmountOutMin_ == 0) revert InvalidSlippageParam();
swapAmountOutMin[_requestId] = newAmountOutMin_;
}
// Note: `retryOFTReceived()` has checks to ensure that the args are consistent
bytes memory _from = abi.encodePacked(crossChainDispatcherOf[srcChainId_]);
IProxyOFT(_dstProxyOFT).retryOFTReceived(
srcChainId_,
srcAddress_,
nonce_,
_from,
address(this),
amount_,
payload_
);
}
/***
* @notice Trigger swap using Stargate for flashRepay.
* @param requestId_ Request id.
* @param account_ User address and also refund address
* @param tokenIn_ tokenIn
* @param tokenOut_ tokenOut
* @param amountIn_ amountIn_
* @param amountOutMin_ amountOutMin_
* @param lzArgs_ LayerZero method argument
*/
function triggerFlashRepaySwap(
uint256 requestId_,
address payable account_,
address tokenIn_,
address tokenOut_,
uint256 amountIn_,
uint256 amountOutMin_,
bytes calldata lzArgs_
) external payable override nonReentrant onlyIfSmartFarmingManager onlyIfBridgingIsNotPaused {
address _account = account_; // stack too deep
(uint16 _dstChainId, uint256 callbackTxNativeFee_, uint64 flashRepaySwapTxGasLimit_) = CrossChainLib
.decodeLzArgs(lzArgs_);
bytes memory _payload;
{
address _dstProxyOFT = ISyntheticToken(tokenOut_).proxyOFT().getProxyOFTOf(_dstChainId);
if (_dstProxyOFT == address(0)) revert AddressIsNull();
if (!isDestinationChainSupported[_dstChainId]) revert DestinationChainNotAllowed();
uint256 _requestId = requestId_; // stack too deep
_payload = CrossChainLib.encodeFlashRepaySwapPayload({
srcSmartFarmingManager_: _msgSender(),
dstProxyOFT_: _dstProxyOFT,
requestId_: _requestId,
account_: _account,
amountOutMin_: amountOutMin_,
callbackTxNativeFee_: callbackTxNativeFee_
});
}
_sendUsingStargate(
LayerZeroParams({
tokenIn: tokenIn_,
dstChainId: _dstChainId,
amountIn: amountIn_,
nativeFee: msg.value,
payload: _payload,
refundAddress: _account,
dstGasForCall: flashRepaySwapTxGasLimit_,
dstNativeAmount: callbackTxNativeFee_
})
);
}
/***
* @notice Send synthetic token and trigger swap at destination chain
* @dev Not checking if bridging is pause because `ProxyOFT._debitFrom()` does it
* @param requestId_ Request id.
* @param account_ User address and also refund address
* @param tokenOut_ tokenOut
* @param amountIn_ amountIn
* @param amountOutMin_ amountOutMin
* @param lzArgs_ LayerZero method argument
*/
function triggerLeverageSwap(
uint256 requestId_,
address payable account_,
address tokenIn_,
address tokenOut_,
uint256 amountIn_,
uint256 amountOutMin_,
bytes calldata lzArgs_
) external payable override nonReentrant onlyIfSmartFarmingManager onlyIfBridgingIsNotPaused {
address _account = account_; // stack too deep
(uint16 _dstChainId, uint256 _callbackTxNativeFee, uint64 _leverageSwapTxGasLimit) = CrossChainLib.decodeLzArgs(
lzArgs_
);
bytes memory _payload;
{
address _tokenOut = tokenOut_; // stack too deep
uint256 _requestId = requestId_; // stack too deep
uint256 _amountOutMin = amountOutMin_; // stack too deep
address _dstProxyOFT = ISyntheticToken(tokenIn_).proxyOFT().getProxyOFTOf(_dstChainId);
uint256 _sgPoolId = stargatePoolIdOf[_tokenOut];
if (_dstProxyOFT == address(0)) revert AddressIsNull();
if (!isDestinationChainSupported[_dstChainId]) revert DestinationChainNotAllowed();
if (_sgPoolId == 0) revert BridgeTokenNotSupported();
_payload = CrossChainLib.encodeLeverageSwapPayload({
srcSmartFarmingManager_: _msgSender(),
dstProxyOFT_: _dstProxyOFT,
requestId_: _requestId,
sgPoolId_: _sgPoolId,
account_: _account,
amountOutMin_: _amountOutMin,
callbackTxNativeFee_: _callbackTxNativeFee
});
}
_sendUsingLayerZero(
LayerZeroParams({
tokenIn: tokenIn_,
dstChainId: _dstChainId,
amountIn: amountIn_,
payload: _payload,
refundAddress: _account,
dstGasForCall: _leverageSwapTxGasLimit,
dstNativeAmount: _callbackTxNativeFee,
nativeFee: msg.value
})
);
}
/**
* @dev Check wether an address is a proxyOFT or not
*/
function _isValidProxyOFT(address proxyOFT_) private view returns (bool) {
ISyntheticToken _syntheticToken = ISyntheticToken(IProxyOFT(proxyOFT_).token());
if (!_poolRegistry.doesSyntheticTokenExist(_syntheticToken)) return false;
if (proxyOFT_ != address(_syntheticToken.proxyOFT())) return false;
return true;
}
/**
* @dev Send underlying token cross-chain
*/
function _sendUsingStargate(LayerZeroParams memory params_) private {
IStargateRouter.lzTxObj memory _lzTxParams;
bytes memory _to = abi.encodePacked(crossChainDispatcherOf[params_.dstChainId]);
{
if (_to.toAddress(0) == address(0)) revert AddressIsNull();
_lzTxParams = IStargateRouter.lzTxObj({
dstGasForCall: params_.dstGasForCall,
dstNativeAmount: params_.dstNativeAmount,
dstNativeAddr: (params_.dstNativeAmount > 0) ? _to : abi.encode(0)
});
}
uint256 _poolId = stargatePoolIdOf[params_.tokenIn];
if (_poolId == 0) revert BridgeTokenNotSupported();
uint256 _amountOutMin = (params_.amountIn * (MAX_BPS - stargateSlippage)) / MAX_BPS;
bytes memory _payload = params_.payload;
IStargateComposer _stargateComposer = stargateComposer;
// Note: StargateComposer only accepts native for ETH pool
address _weth = weth;
if (params_.tokenIn == _weth) {
IWETH(_weth).withdraw(params_.amountIn);
params_.nativeFee += params_.amountIn;
} else {
IERC20(params_.tokenIn).safeApprove(address(_stargateComposer), 0);
IERC20(params_.tokenIn).safeApprove(address(_stargateComposer), params_.amountIn);
}
_stargateComposer.swap{value: params_.nativeFee}({
_dstChainId: params_.dstChainId,
_srcPoolId: _poolId,
_dstPoolId: _poolId,
_refundAddress: payable(params_.refundAddress),
_amountLD: params_.amountIn,
_minAmountLD: _amountOutMin,
_lzTxParams: _lzTxParams,
_to: _to,
_payload: _payload
});
}
/**
* @dev Perform a swap considering slippage param from user
*/
function _swap(
uint256 requestId_,
address tokenIn_,
address tokenOut_,
uint256 amountIn_,
uint256 amountOutMin_
) private returns (uint256 _amountOut) {
// 1. Use updated slippage if exist
uint256 _storedAmountOutMin = swapAmountOutMin[requestId_];
if (_storedAmountOutMin > 0) {
// Use stored slippage and clear it
amountOutMin_ = _storedAmountOutMin;
delete swapAmountOutMin[requestId_];
}
// 2. Perform swap
ISwapper _swapper = _poolRegistry.swapper();
IERC20(tokenIn_).safeApprove(address(_swapper), 0);
IERC20(tokenIn_).safeApprove(address(_swapper), amountIn_);
_amountOut = _swapper.swapExactInput({
tokenIn_: tokenIn_,
tokenOut_: tokenOut_,
amountIn_: amountIn_,
amountOutMin_: amountOutMin_,
receiver_: address(this)
});
}
/// @inheritdoc SynthContext
function poolRegistry() public view override returns (IPoolRegistry) {
return _poolRegistry;
}
/**
* @notice Update flash repay callback tx gas limit
*/
function updateFlashRepayCallbackTxGasLimit(uint64 newFlashRepayCallbackTxGasLimit_) external onlyGovernor {
uint64 _currentFlashRepayCallbackTxGasLimit = flashRepayCallbackTxGasLimit;
if (newFlashRepayCallbackTxGasLimit_ == _currentFlashRepayCallbackTxGasLimit) revert NewValueIsSameAsCurrent();
emit FlashRepayCallbackTxGasLimitUpdated(
_currentFlashRepayCallbackTxGasLimit,
newFlashRepayCallbackTxGasLimit_
);
flashRepayCallbackTxGasLimit = newFlashRepayCallbackTxGasLimit_;
}
/**
* @notice Update flash repay swap tx gas limit
*/
function updateFlashRepaySwapTxGasLimit(uint64 newFlashRepaySwapTxGasLimit_) external onlyGovernor {
uint64 _currentFlashRepaySwapTxGasLimit = flashRepaySwapTxGasLimit;
if (newFlashRepaySwapTxGasLimit_ == _currentFlashRepaySwapTxGasLimit) revert NewValueIsSameAsCurrent();
emit FlashRepaySwapTxGasLimitUpdated(_currentFlashRepaySwapTxGasLimit, newFlashRepaySwapTxGasLimit_);
flashRepaySwapTxGasLimit = newFlashRepaySwapTxGasLimit_;
}
/**
* @notice Update leverage callback tx gas limit
*/
function updateLeverageCallbackTxGasLimit(uint64 newLeverageCallbackTxGasLimit_) external onlyGovernor {
uint64 _currentLeverageCallbackTxGasLimit = leverageCallbackTxGasLimit;
if (newLeverageCallbackTxGasLimit_ == _currentLeverageCallbackTxGasLimit) revert NewValueIsSameAsCurrent();
emit LeverageCallbackTxGasLimitUpdated(_currentLeverageCallbackTxGasLimit, newLeverageCallbackTxGasLimit_);
leverageCallbackTxGasLimit = newLeverageCallbackTxGasLimit_;
}
/**
* @notice Update leverage swap tx gas limit
*/
function updateLeverageSwapTxGasLimit(uint64 newLeverageSwapTxGasLimit_) external onlyGovernor {
uint64 _currentSwapTxGasLimit = leverageSwapTxGasLimit;
if (newLeverageSwapTxGasLimit_ == _currentSwapTxGasLimit) revert NewValueIsSameAsCurrent();
emit LeverageSwapTxGasLimitUpdated(_currentSwapTxGasLimit, newLeverageSwapTxGasLimit_);
leverageSwapTxGasLimit = newLeverageSwapTxGasLimit_;
}
/**
* @notice Update Lz base gas limit
*/
function updateLzBaseGasLimit(uint256 newLzBaseGasLimit_) external onlyGovernor {
uint256 _currentBaseGasLimit = lzBaseGasLimit;
if (newLzBaseGasLimit_ == _currentBaseGasLimit) revert NewValueIsSameAsCurrent();
emit LzBaseGasLimitUpdated(_currentBaseGasLimit, newLzBaseGasLimit_);
lzBaseGasLimit = newLzBaseGasLimit_;
}
/**
* @notice Update Stargate pool id of token.
* @dev Use LZ ids (https://stargateprotocol.gitbook.io/stargate/developers/pool-ids)
*/
function updateStargatePoolIdOf(address token_, uint256 newPoolId_) external onlyGovernor {
uint256 _currentPoolId = stargatePoolIdOf[token_];
if (newPoolId_ == _currentPoolId) revert NewValueIsSameAsCurrent();
emit StargatePoolIdUpdated(token_, _currentPoolId, newPoolId_);
stargatePoolIdOf[token_] = newPoolId_;
}
/**
* @notice Update Stargate slippage
*/
function updateStargateSlippage(uint256 newStargateSlippage_) external onlyGovernor {
uint256 _currentStargateSlippage = stargateSlippage;
if (newStargateSlippage_ == _currentStargateSlippage) revert NewValueIsSameAsCurrent();
emit StargateSlippageUpdated(_currentStargateSlippage, newStargateSlippage_);
stargateSlippage = newStargateSlippage_;
}
/**
* @notice Update StargateComposer
*/
function updateStargateComposer(IStargateComposer newStargateComposer_) external onlyGovernor {
IStargateComposer _currentStargateComposer = stargateComposer;
if (newStargateComposer_ == _currentStargateComposer) revert NewValueIsSameAsCurrent();
emit StargateComposerUpdated(_currentStargateComposer, newStargateComposer_);
stargateComposer = newStargateComposer_;
}
/**
* @notice Pause/Unpause bridge transfers
*/
function toggleBridgingIsActive() external onlyGovernor {
bool _newIsBridgingActive = !isBridgingActive;
emit BridgingIsActiveUpdated(_newIsBridgingActive);
isBridgingActive = _newIsBridgingActive;
}
/**
* @notice Update Cross-chain dispatcher mapping
*/
function updateCrossChainDispatcherOf(uint16 chainId_, address crossChainDispatcher_) external onlyGovernor {
address _current = crossChainDispatcherOf[chainId_];
if (crossChainDispatcher_ == _current) revert NewValueIsSameAsCurrent();
emit CrossChainDispatcherUpdated(chainId_, _current, crossChainDispatcher_);
crossChainDispatcherOf[chainId_] = crossChainDispatcher_;
}
/**
* @notice Allow/Disallow destination chain
* @dev Use LZ chain id
*/
function toggleDestinationChainIsActive(uint16 chainId_) external onlyGovernor {
bool _isDestinationChainSupported = !isDestinationChainSupported[chainId_];
emit DestinationChainIsActiveUpdated(chainId_, _isDestinationChainSupported);
isDestinationChainSupported[chainId_] = _isDestinationChainSupported;
}
}
"
},
"contracts/dependencies/@layerzerolabs/solidity-examples/contracts-upgradeable/token/oft/IOFTCoreUpgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.2;
import "../../../../../openzeppelin-upgradeable/utils/introspection/IERC165Upgradeable.sol";
/**
* @dev Interface of the IOFT core standard
*/
interface IOFTCoreUpgradeable is IERC165Upgradeable {
/**
* @dev estimate send token `_tokenId` to (`_dstChainId`, `_toAddress`)
* _dstChainId - L0 defined chain id to send tokens too
* _toAddress - dynamic bytes array which contains the address to whom you are sending tokens to on the dstChain
* _amount - amount of the tokens to transfer
* _useZro - indicates to use zro to pay L0 fees
* _adapterParam - flexible bytes array to indicate messaging adapter services in L0
*/
function estimateSendFee(
uint16 _dstChainId,
bytes calldata _toAddress,
uint _amount,
bool _useZro,
bytes calldata _adapterParams
) external view returns (uint nativeFee, uint zroFee);
/**
* @dev send `_amount` amount of token to (`_dstChainId`, `_toAddress`) from `_from`
* `_from` the owner of token
* `_dstChainId` the destination chain identifier
* `_toAddress` can be any size depending on the `dstChainId`.
* `_amount` the quantity of tokens in wei
* `_refundAddress` the address LayerZero refunds if too much message fee is sent
* `_zroPaymentAddress` set to address(0x0) if not paying in ZRO (LayerZero Token)
* `_adapterParams` is a flexible bytes array to indicate messaging adapter services
*/
function sendFrom(
address _from,
uint16 _dstChainId,
bytes calldata _toAddress,
uint _amount,
address payable _refundAddress,
address _zroPaymentAddress,
bytes calldata _adapterParams
) external payable;
/**
* @dev returns the circulating amount of tokens on current chain
*/
function circulatingSupply() external view returns (uint);
/**
* @dev returns the address of the ERC20 token
*/
function token() external view returns (address);
/**
* @dev Emitted when `_amount` tokens are moved from the `_sender` to (`_dstChainId`, `_toAddress`)
* `_nonce` is the outbound nonce
*/
event SendToChain(uint16 indexed _dstChainId, address indexed _from, bytes _toAddress, uint _amount);
/**
* @dev Emitted when `_amount` tokens are received from `_srcChainId` into the `_toAddress` on the local chain.
* `_nonce` is the inbound nonce.
*/
event ReceiveFromChain(uint16 indexed _srcChainId, address indexed _to, uint _amount);
event SetUseCustomAdapterParams(bool _useCustomAdapterParams);
}
"
},
"contracts/dependencies/@layerzerolabs/solidity-examples/contracts-upgradeable/token/oft/composable/IComposableOFTCoreUpgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0;
import "../IOFTCoreUpgradeable.sol";
/**
* @dev Interface of the composable OFT core standard
*/
interface IComposableOFTCoreUpgradeable is IOFTCoreUpgradeable {
function estimateSendAndCallFee(
uint16 _dstChainId,
bytes calldata _toAddress,
uint _amount,
bytes calldata _payload,
uint64 _dstGasForCall,
bool _useZro,
bytes calldata _adapterParams
) external view returns (uint nativeFee, uint zroFee);
function sendAndCall(
address _from,
uint16 _dstChainId,
bytes calldata _toAddress,
uint _amount,
bytes calldata _payload,
uint64 _dstGasForCall,
address payable _refundAddress,
address _zroPaymentAddress,
bytes calldata _adapterParams
) external payable;
function retryOFTReceived(
uint16 _srcChainId,
bytes calldata _srcAddress,
uint64 _nonce,
bytes calldata _from,
address _to,
uint _amount,
bytes calldata _payload
) external;
event CallOFTReceivedFailure(
uint16 indexed _srcChainId,
bytes _srcAddress,
uint64 _nonce,
bytes _from,
address indexed _to,
uint _amount,
bytes _payload,
bytes _reason
);
event CallOFTReceivedSuccess(uint16 indexed _srcChainId, bytes _srcAddress, uint64 _nonce, bytes32 _hash);
event RetryOFTReceivedSuccess(bytes32 _messageHash);
event NonContractAddress(address _address);
}
"
},
"contracts/dependencies/@layerzerolabs/solidity-examples/contracts-upgradeable/token/oft/composable/IOFTReceiverUpgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0;
interface IOFTReceiverUpgradeable {
/**
* @dev Called by the OFT contract when tokens are received from source chain.
* @param _srcChainId The chain id of the source chain.
* @param _srcAddress The address of the OFT token contract on the source chain.
* @param _nonce The nonce of the transaction on the source chain.
* @param _from The address of the account who calls the sendAndCall() on the source chain.
* @param _amount The amount of tokens to transfer.
* @param _payload Additional data with no specified format.
*/
function onOFTReceived(
uint16 _srcChainId,
bytes calldata _srcAddress,
uint64 _nonce,
bytes calldata _from,
uint _amount,
bytes calldata _payload
) external;
}
"
},
"contracts/dependencies/@layerzerolabs/solidity-examples/util/BytesLib.sol": {
"content": "// SPDX-License-Identifier: Unlicense
/*
* @title Solidity Bytes Arrays Utils
* @author Gonçalo Sá <goncalo.sa@consensys.net>
*
* @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.
* The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.
*/
pragma solidity >=0.8.0 <0.9.0;
library BytesLib {
function concat(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bytes memory) {
bytes memory tempBytes;
assembly {
// Get a location of some free memory and store it in tempBytes as
// Solidity does for memory variables.
tempBytes := mload(0x40)
// Store the length of the first bytes array at the beginning of
// the memory for tempBytes.
let length := mload(_preBytes)
mstore(tempBytes, length)
// Maintain a memory counter for the current write location in the
// temp bytes array by adding the 32 bytes for the array length to
// the starting location.
let mc := add(tempBytes, 0x20)
// Stop copying when the memory counter reaches the length of the
// first bytes array.
let end := add(mc, length)
for {
// Initialize a copy counter to the start of the _preBytes data,
// 32 bytes into its memory.
let cc := add(_preBytes, 0x20)
} lt(mc, end) {
// Increase both counters by 32 bytes each iteration.
mc := add(mc, 0x20)
cc := add(cc, 0x20)
} {
// Write the _preBytes data into the tempBytes memory 32 bytes
// at a time.
mstore(mc, mload(cc))
}
// Add the length of _postBytes to the current length of tempBytes
// and store it as the new length in the first 32 bytes of the
// tempBytes memory.
length := mload(_postBytes)
mstore(tempBytes, add(length, mload(tempBytes)))
// Move the memory counter back from a multiple of 0x20 to the
// actual end of the _preBytes data.
mc := end
// Stop copying when the memory counter reaches the new combined
// length of the arrays.
end := add(mc, length)
for {
let cc := add(_postBytes, 0x20)
} lt(mc, end) {
mc := add(mc, 0x20)
cc := add(cc, 0x20)
} {
mstore(mc, mload(cc))
}
// Update the free-memory pointer by padding our last write location
// to 32 bytes: add 31 bytes to the end of tempBytes to move to the
// next 32 byte block, then round down to the nearest multiple of
// 32. If the sum of the length of the two arrays is zero then add
// one before rounding down to leave a blank 32 bytes (the length block with 0).
mstore(
0x40,
and(
add(add(end, iszero(add(length, mload(_preBytes)))), 31),
not(31) // Round down to the nearest 32 bytes.
)
)
}
return tempBytes;
}
function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal {
assembly {
// Read the first 32 bytes of _preBytes storage, which is the length
// of the array. (We don't need to use the offset into the slot
// because arrays use the entire slot.)
let fslot := sload(_preBytes.slot)
// Arrays of 31 bytes or less have an even value in their slot,
// while longer arrays have an odd value. The actual length is
// the slot divided by two for odd values, and the lowest order
// byte divided by two for even values.
// If the slot is even, bitwise and the slot with 255 and divide by
// two to get the length. If the slot is odd, bitwise and the slot
// with -1 and divide by two.
let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
let mlength := mload(_postBytes)
let newlength := add(slength, mlength)
// slength can contain both the length and contents of the array
// if length < 32 bytes so let's prepare for that
// v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
switch add(lt(slength, 32), lt(newlength, 32))
case 2 {
// Since the new array still fits in the slot, we just need to
// update the contents of the slot.
// uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length
sstore(
_preBytes.slot,
// all the modifications to the slot are inside this
// next block
add(
// we can just add to the slot contents because the
// bytes we want to change are the LSBs
fslot,
add(
mul(
div(
// load the bytes from memory
mload(add(_postBytes, 0x20)),
// zero all bytes to the right
exp(0x100, sub(32, mlength))
),
// and now shift left the number of bytes to
// leave space for the length in the slot
exp(0x100, sub(32, newlength))
),
// increase length by the double of the memory
// bytes length
mul(mlength, 2)
)
)
)
}
case 1 {
// The stored value fits in the slot, but the combined value
// will exceed it.
// get the keccak hash to get the contents of the array
mstore(0x0, _preBytes.slot)
let sc := add(keccak256(0x0, 0x20), div(slength, 32))
// save new length
sstore(_preBytes.slot, add(mul(newlength, 2), 1))
// The contents of the _postBytes array start 32 bytes into
// the structure. Our first read should obtain the `submod`
// bytes that can fit into the unused space in the last word
// of the stored array. To get this, we read 32 bytes starting
// from `submod`, so the data we read overlaps with the array
// contents by `submod` bytes. Masking the lowest-order
// `submod` bytes allows us to add that value directly to the
// stored value.
let submod := sub(32, slength)
let mc := add(_postBytes, submod)
let end := add(_postBytes, mlength)
let mask := sub(exp(0x100, submod), 1)
sstore(
sc,
add(
and(fslot, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00),
and(mload(mc), mask)
)
)
for {
mc := add(mc, 0x20)
sc := add(sc, 1)
} lt(mc, end) {
sc := add(sc, 1)
mc := add(mc, 0x20)
} {
sstore(sc, mload(mc))
}
mask := exp(0x100, sub(mc, end))
sstore(sc, mul(div(mload(mc), mask), mask))
}
default {
// get the keccak hash to get the contents of the array
mstore(0x0, _preBytes.slot)
// Start copying to the last used word of the stored array.
let sc := add(keccak256(0x0, 0x20), div(slength, 32))
// save new length
sstore(_preBytes.slot, add(mul(newlength, 2), 1))
// Copy over the first `submod` bytes of the new data as in
// case 1 above.
let slengthmod := mod(slength, 32)
let mlengthmod := mod(mlength, 32)
let submod := sub(32, slengthmod)
let mc := add(_postBytes, submod)
let end := add(_postBytes, mlength)
let mask := sub(exp(0x100, submod), 1)
sstore(sc, add(sload(sc), and(mload(mc), mask)))
for {
sc := add(sc, 1)
mc := add(mc, 0x20)
} lt(mc, end) {
sc := add(sc, 1)
mc := add(mc, 0x20)
} {
sstore(sc, mload(mc))
}
mask := exp(0x100, sub(mc, end))
sstore(sc, mul(div(mload(mc), mask), mask))
}
}
}
function slice(bytes memory _bytes, uint256 _start, uint256 _length) internal pure returns (bytes memory) {
require(_length + 31 >= _length, "slice_overflow");
require(_bytes.length >= _start + _length, "slice_outOfBounds");
bytes memory tempBytes;
assembly {
switch iszero(_length)
case 0 {
// Get a location of some free memory and store it in tempBytes as
// Solidity does for memory variables.
tempBytes := mload(0x40)
// The first word of the slice result is potentially a partial
// word read from the original array. To read it, we calculate
// the length of that partial word and start copying that many
// bytes into the array. The first word we copy will start with
// data we don't care about, but the last `lengthmod` bytes will
// land at the beginning of the contents of the new array. When
// we're done copying, we overwrite the full first word with
// the actual length of the slice.
let lengthmod := and(_length, 31)
// The multiplication in the next line is necessary
// because when slicing multiples of 32 bytes (lengthmod == 0)
// the following copy loop was copying the origin's length
// and then ending prematurely not copying everything it should.
let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
let end := add(mc, _length)
for {
// The multiplication in the next line has the same exact purpose
// as the one above.
let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
} lt(mc, end) {
mc := add(mc, 0x20)
cc := add(cc, 0x20)
} {
mstore(mc, mload(cc))
}
mstore(tempBytes, _length)
//update free-memory pointer
//allocating the array padded to 32 bytes like the compiler does now
mstore(0x40, and(add(mc, 31), not(31)))
}
//if we want a zero-length slice let's just return a zero-length array
default {
tempBytes := mload(0x40)
//zero out the 32 bytes slice we are about to return
//we need to do it because Solidity does not garbage collect
mstore(tempBytes, 0)
mstore(0x40, add(tempBytes, 0x20))
}
}
return tempBytes;
}
function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {
require(_bytes.length >= _start + 20, "toAddress_outOfBounds");
address tempAddress;
assembly {
tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
}
return tempAddress;
}
function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) {
require(_bytes.length >= _start + 1, "toUint8_outOfBounds");
uint8 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x1), _start))
}
return tempUint;
}
function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) {
require(_bytes.length >= _start + 2, "toUint16_outOfBounds");
uint16 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x2), _start))
}
return tempUint;
}
function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) {
require(_bytes.length >= _start + 4, "toUint32_outOfBounds");
uint32 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x4), _start))
}
return tempUint;
}
function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) {
require(_bytes.length >= _start + 8, "toUint64_outOfBounds");
uint64 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x8), _start))
}
return tempUint;
}
function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) {
require(_bytes.length >= _start + 12, "toUint96_outOfBounds");
uint96 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0xc), _start))
}
return tempUint;
}
function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) {
require(_bytes.length >= _start + 16, "toUint128_outOfBounds");
uint128 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x10), _start))
}
return tempUint;
}
function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) {
require(_bytes.length >= _start + 32, "toUint256_outOfBounds");
uint256 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x20), _start))
}
return tempUint;
}
function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) {
require(_bytes.length >= _start + 32, "toBytes32_outOfBounds");
bytes32 tempBytes32;
assembly {
tempBytes32 := mload(add(add(_bytes, 0x20), _start))
}
return tempBytes32;
}
function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) {
bool success = true;
assembly {
let length := mload(_preBytes)
// if lengths don't match the arrays are not equal
switch eq(length, mload(_postBytes))
case 1 {
// cb is a circuit breaker in the for loop since there's
// no said feature for inline assembly loops
// cb = 1 - don't breaker
// cb = 0 - break
let cb := 1
let mc := add(_preBytes, 0x20)
let end := add(mc, length)
for {
let cc := add(_postBytes, 0x20)
// the next line is the loop condition:
// while(uint256(mc < end) + cb == 2)
} eq(add(lt(mc, end), cb), 2) {
mc := add(mc, 0x20)
cc := add(cc, 0x20)
} {
// if any of these checks fails then arrays are not equal
if iszero(eq(mload(mc), mload(cc))) {
// unsuccess:
success := 0
cb := 0
}
}
}
default {
// unsuccess:
success := 0
}
}
return success;
}
function equalStorage(bytes storage _preBytes, bytes memory _postBytes) internal view returns (bool) {
bool success = true;
assembly {
// we know _preBytes_offset is 0
let fslot := sload(_preBytes.slot)
// Decode the length of the stored array like in concatStorage().
let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
let mlength := mload(_postBytes)
// if lengths don't match the arrays are not equal
switch eq(slength, mlength)
case 1 {
// slength can contain both the length and contents of the array
// if length < 32 bytes so let's prepare for that
// v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
if iszero(iszero(slength)) {
switch lt(slength, 32)
case 1 {
// blank the last byte which is the length
fslot := mul(div(fslot, 0x100), 0x100)
if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) {
// unsuccess:
success := 0
}
}
default {
// cb is a circuit breaker in the for loop since there's
// no said feature for inline assembly loops
// cb = 1 - don't breaker
// cb = 0 - break
let cb := 1
// get the keccak hash to get the contents of the array
mstore(0x0, _preBytes.slot)
let sc := keccak256(0x0, 0x20)
let mc := add(_postBytes, 0x20)
let end := add(mc, mlength)
// the next line is the loop condition:
// while(uint256(mc < end) + cb == 2)
for {
} eq(add(lt(mc, end), cb), 2) {
sc := add(sc, 1)
mc := add(mc, 0x20)
} {
if iszero(eq(sload(sc), mload(mc))) {
// unsuccess:
success := 0
cb := 0
}
}
}
}
}
default {
// unsuccess:
success := 0
}
}
return success;
}
}
"
},
"contracts/dependencies/openzeppelin-upgradeable/proxy/utils/Initializable.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`.
*/
modifier initializer() {
bool isTopLevelCall = _setInitializedVersion(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.
*
* `initializer` is equivalent to `reinitializer(1)`, so 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.
*
* 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.
*/
modifier reinitializer(uint8 version) {
bool isTopLevelCall = _setInitializedVersion(version);
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(version);
}
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*/
function _disableInitializers() internal virtual {
_setInitializedVersion(type(uint8).max);
}
function _setInitializedVersion(uint8 version) private returns (bool) {
// If the contract is initializing we ignore whether _initialized is set in order to support multiple
// inheritance patterns, but we only do this in the context of a constructor, and for the lowest level
// of initializers, because in other contexts the contract may have been reentered.
if (_initializing) {
require(
version == 1 && !AddressUpgradeable.isContract(address(this)),
"Initializable: contract is already initialized"
);
return false;
} else {
require(_initialized < version, "Initializable: contract is already initialized");
_initialized = version;
return true;
}
}
}
"
},
"contracts/dependencies/openzeppelin-upgradeable/utils/AddressUpgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It
Submitted on: 2025-11-04 16:25:38
Comments
Log in to comment.
No comments yet.