Source Code
Overview
ETH Balance
ETH Value
$0.00| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 28225684 | 2 days ago | 0 ETH | ||||
| 28187530 | 3 days ago | 0.0219 ETH | ||||
| 28187115 | 3 days ago | 0.03037 ETH | ||||
| 28171422 | 4 days ago | 0 ETH | ||||
| 28171039 | 4 days ago | 0 ETH | ||||
| 28171017 | 4 days ago | 0 ETH | ||||
| 28170672 | 4 days ago | 0 ETH | ||||
| 28157720 | 4 days ago | 0.0184 ETH | ||||
| 28152090 | 4 days ago | 0.00102907 ETH | ||||
| 28151292 | 4 days ago | 0.02715 ETH | ||||
| 28111600 | 5 days ago | 0 ETH | ||||
| 28110226 | 5 days ago | 0.027 ETH | ||||
| 28108553 | 5 days ago | 0.0267 ETH | ||||
| 28066962 | 6 days ago | 0 ETH | ||||
| 28026751 | 7 days ago | 0.002 ETH | ||||
| 28026420 | 7 days ago | 0 ETH | ||||
| 27971385 | 8 days ago | 0.015 ETH | ||||
| 27903076 | 10 days ago | 0 ETH | ||||
| 27894479 | 10 days ago | 0 ETH | ||||
| 27894437 | 10 days ago | 0 ETH | ||||
| 27894367 | 10 days ago | 0 ETH | ||||
| 27894256 | 10 days ago | 0 ETH | ||||
| 27880654 | 10 days ago | 0 ETH | ||||
| 27855337 | 11 days ago | 0 ETH | ||||
| 27797529 | 12 days ago | 0 ETH |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
GenericCrossChainFacet
Compiler Version
v0.8.17+commit.8df45f5f
Optimization Enabled:
Yes with 10000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import { LibMappings } from "../Libraries/LibMappings.sol";
import { IRubic } from "../Interfaces/IRubic.sol";
import { LibAsset, IERC20 } from "../Libraries/LibAsset.sol";
import { LibFees } from "../Libraries/LibFees.sol";
import { LibUtil } from "../Libraries/LibUtil.sol";
import { LibDiamond } from "../Libraries/LibDiamond.sol";
import { ReentrancyGuard } from "../Helpers/ReentrancyGuard.sol";
import { SwapperV2, LibSwap } from "../Helpers/SwapperV2.sol";
import { UnAuthorized, LengthMissmatch, InvalidContract } from "../Errors/GenericErrors.sol";
import { Validatable } from "../Helpers/Validatable.sol";
/// @title Generic Cross-Chain Facet
/// @notice Provides functionality for bridging through arbitrary cross-chain provider
contract GenericCrossChainFacet is
IRubic,
ReentrancyGuard,
SwapperV2,
Validatable
{
/// Events ///
event SelectorToInfoUpdated(
address[] _routers,
bytes4[] _selectors,
LibMappings.ProviderFunctionInfo[] _infos
);
/// Types ///
/// @param router Address of the router that has to be called
/// @param approveTo Address of the gateway to approve to
/// @param extraNative Amount of native to send to a router
/// @param callData Calldata that has to be passed to the router
struct GenericCrossChainData {
address router;
address approveTo;
uint256 extraNative;
bytes callData;
}
/// Modifiers ///
modifier validateGenericData(GenericCrossChainData calldata _genericData) {
if (!LibAsset.isContract(_genericData.router))
revert InvalidContract();
_;
}
/// External Methods ///
/// @notice Updates the amount offset of the specific function of the specific provider's router
/// @param _routers Array of provider's routers
/// @param _selectors Array of function selectors
/// @param _infos Array of params associated with specified function
function updateSelectorInfo(
address[] calldata _routers,
bytes4[] calldata _selectors,
LibMappings.ProviderFunctionInfo[] calldata _infos
) external {
LibDiamond.enforceIsContractOwner();
LibMappings.GenericCrossChainMappings storage sm = LibMappings
.getGenericCrossChainMappings();
if (
_routers.length != _selectors.length ||
_selectors.length != _infos.length
) {
revert LengthMissmatch();
}
for (uint64 i; i < _routers.length; ) {
sm.selectorToInfo[_routers[i]][_selectors[i]] = _infos[i];
unchecked {
++i;
}
}
emit SelectorToInfoUpdated(_routers, _selectors, _infos);
}
/// @notice Bridges tokens via arbitrary cross-chain provider
/// @param _bridgeData the core information needed for bridging
/// @param _genericData data specific to GenericCrossChainFacet
function startBridgeTokensViaGenericCrossChain(
IRubic.BridgeData memory _bridgeData,
GenericCrossChainData calldata _genericData
)
external
payable
nonReentrant
refundExcessNative(payable(_bridgeData.refundee))
validateBridgeData(_bridgeData)
validateGenericData(_genericData)
doesNotContainSourceSwaps(_bridgeData)
doesNotContainDestinationCalls(_bridgeData)
{
_bridgeData.minAmount = LibAsset.depositAssetAndAccrueFees(
_bridgeData.sendingAssetId,
_bridgeData.minAmount,
_genericData.extraNative,
_bridgeData.integrator
);
_startBridge(
_bridgeData,
_patchGenericCrossChainData(_genericData, _bridgeData.minAmount)
);
}
/// @notice Bridges tokens via arbitrary cross-chain provider with swaps before bridging
/// @param _bridgeData the core information needed for bridging
/// @param _swapData an array of swap related data for performing swaps before bridging
/// @param _genericData data specific to GenericCrossChainFacet
function swapAndStartBridgeTokensViaGenericCrossChain(
IRubic.BridgeData memory _bridgeData,
LibSwap.SwapData[] calldata _swapData,
GenericCrossChainData calldata _genericData
)
external
payable
nonReentrant
refundExcessNative(payable(_bridgeData.refundee))
containsSourceSwaps(_bridgeData)
validateBridgeData(_bridgeData)
validateGenericData(_genericData)
{
_bridgeData.minAmount = _depositAndSwap(
_bridgeData.transactionId,
_bridgeData.minAmount,
_swapData,
_bridgeData.integrator,
payable(_bridgeData.refundee),
_genericData.extraNative
);
_startBridge(
_bridgeData,
_patchGenericCrossChainData(_genericData, _bridgeData.minAmount)
);
}
/// View Methods ///
/// @notice Fetches the amount offset of the specific function of the specific provider's router
/// @param _router Address of provider's router
/// @param _selector Selector of the function
/// @return Amount offset
function getSelectorInfo(
address _router,
bytes4 _selector
) external view returns (LibMappings.ProviderFunctionInfo memory) {
LibMappings.GenericCrossChainMappings storage sm = LibMappings
.getGenericCrossChainMappings();
return sm.selectorToInfo[_router][_selector];
}
/// Internal Methods ///
/// @dev Contains the business logic for the bridge via arbitrary cross-chain provider
/// @param _bridgeData the core information needed for bridging
/// @param _genericData data specific to GenericCrossChainFacet
function _startBridge(
IRubic.BridgeData memory _bridgeData,
GenericCrossChainData memory _genericData
) internal {
bool isNative = LibAsset.isNativeAsset(_bridgeData.sendingAssetId);
uint256 nativeAssetAmount;
if (isNative) {
nativeAssetAmount = _bridgeData.minAmount;
} else {
LibAsset.maxApproveERC20(
IERC20(_bridgeData.sendingAssetId),
_genericData.approveTo,
_bridgeData.minAmount
);
}
(bool success, bytes memory res) = _genericData.router.call{
value: nativeAssetAmount + _genericData.extraNative
}(_genericData.callData);
if (!success) {
string memory reason = LibUtil.getRevertMsg(res);
revert(reason);
}
emit RubicTransferStarted(_bridgeData);
}
function _patchGenericCrossChainData(
GenericCrossChainData calldata _genericData,
uint256 amount
) private view returns (GenericCrossChainData memory) {
LibMappings.GenericCrossChainMappings storage sm = LibMappings
.getGenericCrossChainMappings();
LibMappings.ProviderFunctionInfo memory info = sm.selectorToInfo[
_genericData.router
][bytes4(_genericData.callData[:4])];
if (info.isAvailable) {
if (info.offset > 0) {
return
GenericCrossChainData(
_genericData.router,
_genericData.approveTo,
_genericData.extraNative,
bytes.concat(
_genericData.callData[:info.offset],
abi.encode(amount),
_genericData.callData[info.offset + 32:]
)
);
} else {
return
GenericCrossChainData(
_genericData.router,
_genericData.approveTo,
_genericData.extraNative,
_genericData.callData
);
}
} else {
revert UnAuthorized();
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import { CannotAuthoriseSelf, UnAuthorized } from "../Errors/GenericErrors.sol";
import { LibAccess } from "../Libraries/LibAccess.sol";
/// @title Mappings Library
/// @notice Provides mappings for all facets that may need them
library LibMappings {
/// Types ///
bytes32 internal constant STARGATE_NAMESPACE =
keccak256("com.rubic.library.mappings.stargate");
bytes32 internal constant WORMHOLE_NAMESPACE =
keccak256("com.rubic.library.mappings.wormhole");
bytes32 internal constant AMAROK_NAMESPACE =
keccak256("com.rubic.library.mappings.amarok");
bytes32 internal constant GENERIC_CROSS_CHAIN_NAMESAPCE =
keccak256("com.rubic.library.mappings.generic.cross.chain");
/// Storage ///
struct StargateMappings {
mapping(address => uint16) stargatePoolId;
mapping(uint256 => uint16) layerZeroChainId;
bool initialized;
}
struct WormholeMappings {
mapping(uint256 => uint16) wormholeChainId;
bool initialized;
}
struct AmarokMappings {
mapping(uint256 => uint32) amarokDomain;
}
struct ProviderFunctionInfo {
bool isAvailable;
uint256 offset;
}
struct GenericCrossChainMappings {
mapping(address => mapping(bytes4 => ProviderFunctionInfo)) selectorToInfo;
}
/// @dev Fetch local storage for Stargate
function getStargateMappings()
internal
pure
returns (StargateMappings storage ms)
{
bytes32 position = STARGATE_NAMESPACE;
// solhint-disable-next-line no-inline-assembly
assembly {
ms.slot := position
}
}
/// @dev Fetch local storage for Wormhole
function getWormholeMappings()
internal
pure
returns (WormholeMappings storage ms)
{
bytes32 position = WORMHOLE_NAMESPACE;
// solhint-disable-next-line no-inline-assembly
assembly {
ms.slot := position
}
}
/// @dev Fetch local storage for Amarok
function getAmarokMappings()
internal
pure
returns (AmarokMappings storage ms)
{
bytes32 position = AMAROK_NAMESPACE;
// solhint-disable-next-line no-inline-assembly
assembly {
ms.slot := position
}
}
/// @dev Fetch local storage for Generic Cross Chain
function getGenericCrossChainMappings()
internal
pure
returns (GenericCrossChainMappings storage ms)
{
bytes32 position = GENERIC_CROSS_CHAIN_NAMESAPCE;
// solhint-disable-next-line no-inline-assembly
assembly {
ms.slot := position
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
interface IRubic {
/// Structs ///
struct BridgeData {
bytes32 transactionId;
string bridge;
address integrator;
address referrer;
address sendingAssetId;
address receivingAssetId;
address receiver;
address refundee;
uint256 minAmount;
uint256 destinationChainId;
bool hasSourceSwaps;
bool hasDestinationCall;
}
/// Events ///
event RubicTransferStarted(IRubic.BridgeData bridgeData);
event RubicTransferCompleted(
bytes32 indexed transactionId,
address receivingAssetId,
address receiver,
uint256 amount,
uint256 timestamp
);
event RubicTransferRecovered(
bytes32 indexed transactionId,
address receivingAssetId,
address receiver,
uint256 amount,
uint256 timestamp
);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.17;
import { InsufficientBalance, NullAddrIsNotAnERC20Token, NullAddrIsNotAValidSpender, NoTransferToNullAddress, InvalidAmount, NativeValueWithERC, NativeAssetTransferFailed } from "../Errors/GenericErrors.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { ERC20Proxy } from "../Periphery/ERC20Proxy.sol";
import { LibSwap } from "./LibSwap.sol";
import { LibFees } from "./LibFees.sol";
/// @title LibAsset
/// @notice This library contains helpers for dealing with onchain transfers
/// of assets, including accounting for the native asset `assetId`
/// conventions and any noncompliant ERC20 transfers
library LibAsset {
uint256 private constant MAX_UINT = type(uint256).max;
address internal constant NULL_ADDRESS = address(0);
/// @dev All native assets use the empty address for their asset id
/// by convention
address internal constant NATIVE_ASSETID = NULL_ADDRESS; //address(0)
/// @notice Gets the balance of the inheriting contract for the given asset
/// @param assetId The asset identifier to get the balance of
/// @return Balance held by contracts using this library
function getOwnBalance(address assetId) internal view returns (uint256) {
return
assetId == NATIVE_ASSETID
? address(this).balance
: IERC20(assetId).balanceOf(address(this));
}
/// @notice Transfers ether from the inheriting contract to a given
/// recipient
/// @param recipient Address to send ether to
/// @param amount Amount to send to given recipient
function transferNativeAsset(
address payable recipient,
uint256 amount
) internal {
if (recipient == NULL_ADDRESS) revert NoTransferToNullAddress();
if (amount > address(this).balance)
revert InsufficientBalance(amount, address(this).balance);
// solhint-disable-next-line avoid-low-level-calls
(bool success, ) = recipient.call{ value: amount }("");
if (!success) revert NativeAssetTransferFailed();
}
/// @notice If the current allowance is insufficient, the allowance for a given spender
/// is set to MAX_UINT.
/// @param assetId Token address to transfer
/// @param spender Address to give spend approval to
/// @param amount Amount to approve for spending
function maxApproveERC20(
IERC20 assetId,
address spender,
uint256 amount
) internal {
if (address(assetId) == NATIVE_ASSETID) return;
if (spender == NULL_ADDRESS) revert NullAddrIsNotAValidSpender();
uint256 allowance = assetId.allowance(address(this), spender);
if (allowance < amount)
SafeERC20.safeIncreaseAllowance(
IERC20(assetId),
spender,
MAX_UINT - allowance
);
}
/// @notice Transfers tokens from the inheriting contract to a given
/// recipient
/// @param assetId Token address to transfer
/// @param recipient Address to send token to
/// @param amount Amount to send to given recipient
function transferERC20(
address assetId,
address recipient,
uint256 amount
) internal {
if (isNativeAsset(assetId)) revert NullAddrIsNotAnERC20Token();
uint256 assetBalance = IERC20(assetId).balanceOf(address(this));
if (amount > assetBalance)
revert InsufficientBalance(amount, assetBalance);
SafeERC20.safeTransfer(IERC20(assetId), recipient, amount);
}
/// @notice Transfers tokens from a sender to a given recipient
/// @param assetId Token address to transfer
/// @param from Address of sender/owner
/// @param to Address of recipient/spender
/// @param amount Amount to transfer from owner to spender
function transferFromERC20(
address assetId,
address from,
address to,
uint256 amount
) internal {
if (assetId == NATIVE_ASSETID) revert NullAddrIsNotAnERC20Token();
if (to == NULL_ADDRESS) revert NoTransferToNullAddress();
IERC20 asset = IERC20(assetId);
uint256 prevBalance = asset.balanceOf(to);
SafeERC20.safeTransferFrom(asset, from, to, amount);
if (asset.balanceOf(to) - prevBalance != amount)
revert InvalidAmount();
}
/// @dev Deposits asset for bridging and accrues fixed and token fees
/// @param assetId Address of asset to deposit
/// @param amount Amount of asset to bridge
/// @param extraNativeAmount Amount of native token to send to a bridge
/// @param integrator Integrator for whom to count the fees
/// @return amountWithoutFees Amount of tokens to bridge minus fees
function depositAssetAndAccrueFees(
address assetId,
uint256 amount,
uint256 extraNativeAmount,
address integrator
) internal returns (uint256 amountWithoutFees) {
uint256 accruedFixedNativeFee = LibFees.accrueFixedNativeFee(
integrator
);
// Check that msg value is at least greater than fixed native fee + extra fee sending to bridge
if (msg.value < accruedFixedNativeFee + extraNativeAmount)
revert InvalidAmount();
amountWithoutFees = _depositAndAccrueTokenFee(
assetId,
amount,
accruedFixedNativeFee,
extraNativeAmount,
integrator
);
}
/// @dev Deposits assets for each swap that requires and accrues fixed and token fees
/// @param swaps Array of swap datas
/// @param integrator Integrator for whom to count the fees
/// @return amountWithoutFees Array of swap datas with updated amounts
function depositAssetsAndAccrueFees(
LibSwap.SwapData[] memory swaps,
address integrator
) internal returns (LibSwap.SwapData[] memory) {
uint256 accruedFixedNativeFee = LibFees.accrueFixedNativeFee(
integrator
);
if (msg.value < accruedFixedNativeFee) revert InvalidAmount();
for (uint256 i = 0; i < swaps.length; ) {
LibSwap.SwapData memory swap = swaps[i];
if (swap.requiresDeposit) {
swap.fromAmount = _depositAndAccrueTokenFee(
swap.sendingAssetId,
swap.fromAmount,
accruedFixedNativeFee,
0,
integrator
);
}
swaps[i] = swap;
unchecked {
i++;
}
}
return swaps;
}
function _depositAndAccrueTokenFee(
address assetId,
uint256 amount,
uint256 accruedFixedNativeFee,
uint256 extraNativeAmount,
address integrator
) private returns (uint256 amountWithoutFees) {
if (isNativeAsset(assetId)) {
// Check that msg value greater than sending amount + fixed native fees + extra fees sending to bridge
if (msg.value < amount + accruedFixedNativeFee + extraNativeAmount)
revert InvalidAmount();
} else {
if (amount == 0) revert InvalidAmount();
uint256 balance = IERC20(assetId).balanceOf(address(this));
if (balance < amount) revert InsufficientBalance(amount, balance);
// getERC20proxy().transferFrom(
// assetId,
// msg.sender,
// address(this),
// amount
// );
}
amountWithoutFees = LibFees.accrueTokenFees(
integrator,
amount,
assetId
);
}
/// @notice Determines whether the given assetId is the native asset
/// @param assetId The asset identifier to evaluate
/// @return Boolean indicating if the asset is the native asset
function isNativeAsset(address assetId) internal pure returns (bool) {
return assetId == NATIVE_ASSETID;
}
/// @notice Wrapper function to transfer a given asset (native or erc20) to
/// some recipient. Should handle all non-compliant return value
/// tokens as well by using the SafeERC20 contract by open zeppelin.
/// @param assetId Asset id for transfer (address(0) for native asset,
/// token address for erc20s)
/// @param recipient Address to send asset to
/// @param amount Amount to send to given recipient
function transferAsset(
address assetId,
address payable recipient,
uint256 amount
) internal {
(assetId == NATIVE_ASSETID)
? transferNativeAsset(recipient, amount)
: transferERC20(assetId, recipient, amount);
}
/// @dev Checks whether the given address is a contract and contains code
function isContract(address _contractAddr) internal view returns (bool) {
uint256 size;
// solhint-disable-next-line no-inline-assembly
assembly {
size := extcodesize(_contractAddr)
}
return size > 0;
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import { IFeesFacet } from "../Interfaces/IFeesFacet.sol";
import { LibUtil } from "../Libraries/LibUtil.sol";
import { FullMath } from "../Libraries/FullMath.sol";
import { LibAsset } from "../Libraries/LibAsset.sol";
/// Implementation of EIP-2535 Diamond Standard
/// https://eips.ethereum.org/EIPS/eip-2535
library LibFees {
bytes32 internal constant FFES_STORAGE_POSITION =
keccak256("rubic.library.fees.v2");
// Denominator for setting fees
uint256 internal constant DENOMINATOR = 1e6;
// ----------------
event FixedNativeFee(
uint256 RubicPart,
uint256 integratorPart,
address indexed integrator
);
event FixedNativeFeeCollected(uint256 amount, address collector);
event TokenFee(
uint256 RubicPart,
uint256 integratorPart,
address indexed integrator,
address token
);
event IntegratorTokenFeeCollected(
uint256 amount,
address indexed integrator,
address token
);
struct FeesStorage {
mapping(address => IFeesFacet.IntegratorFeeInfo) integratorToFeeInfo;
uint256 maxRubicPlatformFee; // sets while initialize
uint256 maxFixedNativeFee; // sets while initialize & cannot be changed
uint256 RubicPlatformFee;
// Rubic fixed fee for swap
uint256 fixedNativeFee;
address feeTreasure;
bool initialized;
}
function feesStorage() internal pure returns (FeesStorage storage fs) {
bytes32 position = FFES_STORAGE_POSITION;
// solhint-disable-next-line no-inline-assembly
assembly {
fs.slot := position
}
}
/**
* @dev Calculates and accrues fixed crypto fee
* @param _integrator Integrator's address if there is one
* @return The amount of fixedNativeFee
*/
function accrueFixedNativeFee(
address _integrator
) internal returns (uint256) {
uint256 _fixedNativeFee;
uint256 _RubicPart;
FeesStorage storage fs = feesStorage();
IFeesFacet.IntegratorFeeInfo memory _info = fs.integratorToFeeInfo[
_integrator
];
if (_info.isIntegrator) {
_fixedNativeFee = uint256(_info.fixedFeeAmount);
if (_fixedNativeFee > 0) {
_RubicPart =
(_fixedNativeFee * _info.RubicFixedCryptoShare) /
DENOMINATOR;
if (_fixedNativeFee - _RubicPart > 0)
LibAsset.transferNativeAsset(
payable(_integrator),
_fixedNativeFee - _RubicPart
);
}
} else {
_fixedNativeFee = fs.fixedNativeFee;
_RubicPart = _fixedNativeFee;
}
if (_RubicPart > 0)
LibAsset.transferNativeAsset(payable(fs.feeTreasure), _RubicPart);
emit FixedNativeFee(
_RubicPart,
_fixedNativeFee - _RubicPart,
_integrator
);
return _fixedNativeFee;
}
/**
* @dev Calculates token fees and accrues them
* @param _integrator Integrator's address if there is one
* @param _amountWithFee Total amount passed by the user
* @param _token The token in which the fees are collected
* @return Amount of tokens without fee
*/
function accrueTokenFees(
address _integrator,
uint256 _amountWithFee,
address _token
) internal returns (uint256) {
FeesStorage storage fs = feesStorage();
IFeesFacet.IntegratorFeeInfo memory _info = fs.integratorToFeeInfo[
_integrator
];
(uint256 _totalFees, uint256 _RubicFee) = _calculateFee(
fs,
_amountWithFee,
_info
);
if (_integrator != address(0)) {
if (_totalFees - _RubicFee > 0)
LibAsset.transferAsset(
_token,
payable(_integrator),
_totalFees - _RubicFee
);
}
if (_RubicFee > 0)
LibAsset.transferAsset(_token, payable(fs.feeTreasure), _RubicFee);
emit TokenFee(_RubicFee, _totalFees - _RubicFee, _integrator, _token);
return _amountWithFee - _totalFees;
}
/// PRIVATE ///
/**
* @dev Calculates fee amount for integrator and rubic, used in architecture
* @param _amountWithFee the users initial amount
* @param _info the struct with data about integrator
* @return _totalFee the amount of Rubic + integrator fee
* @return _RubicFee the amount of Rubic fee only
*/
function _calculateFeeWithIntegrator(
uint256 _amountWithFee,
IFeesFacet.IntegratorFeeInfo memory _info
) private pure returns (uint256 _totalFee, uint256 _RubicFee) {
if (_info.tokenFee > 0) {
_totalFee = FullMath.mulDiv(
_amountWithFee,
_info.tokenFee,
DENOMINATOR
);
_RubicFee = FullMath.mulDiv(
_totalFee,
_info.RubicTokenShare,
DENOMINATOR
);
}
}
function _calculateFee(
FeesStorage storage _fs,
uint256 _amountWithFee,
IFeesFacet.IntegratorFeeInfo memory _info
) internal view returns (uint256 _totalFee, uint256 _RubicFee) {
if (_info.isIntegrator) {
(_totalFee, _RubicFee) = _calculateFeeWithIntegrator(
_amountWithFee,
_info
);
} else {
_totalFee = FullMath.mulDiv(
_amountWithFee,
_fs.RubicPlatformFee,
DENOMINATOR
);
_RubicFee = _totalFee;
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import "./LibBytes.sol";
library LibUtil {
using LibBytes for bytes;
function getRevertMsg(
bytes memory _res
) internal pure returns (string memory) {
if (_res.length < 68) return string(_res);
bytes memory revertData = _res.slice(4, _res.length - 4); // Remove the selector which is the first 4 bytes
return abi.decode(revertData, (string)); // All that remains is the revert string
}
/// @notice Determines whether the given address is the zero address
/// @param addr The address to verify
/// @return Boolean indicating if the address is the zero address
function isZeroAddress(address addr) internal pure returns (bool) {
return addr == address(0);
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import { IDiamondCut } from "../Interfaces/IDiamondCut.sol";
import { LibUtil } from "../Libraries/LibUtil.sol";
import { OnlyContractOwner } from "../Errors/GenericErrors.sol";
/// Implementation of EIP-2535 Diamond Standard
/// https://eips.ethereum.org/EIPS/eip-2535
library LibDiamond {
bytes32 internal constant DIAMOND_STORAGE_POSITION =
keccak256("diamond.standard.diamond.storage");
// Diamond specific errors
error IncorrectFacetCutAction();
error NoSelectorsInFace();
error FunctionAlreadyExists();
error FacetAddressIsZero();
error FacetAddressIsNotZero();
error FacetContainsNoCode();
error FunctionDoesNotExist();
error FunctionIsImmutable();
error InitZeroButCalldataNotEmpty();
error CalldataEmptyButInitNotZero();
error InitReverted();
// ----------------
struct FacetAddressAndPosition {
address facetAddress;
uint96 functionSelectorPosition; // position in facetFunctionSelectors.functionSelectors array
}
struct FacetFunctionSelectors {
bytes4[] functionSelectors;
uint256 facetAddressPosition; // position of facetAddress in facetAddresses array
}
struct DiamondStorage {
// maps function selector to the facet address and
// the position of the selector in the facetFunctionSelectors.selectors array
mapping(bytes4 => FacetAddressAndPosition) selectorToFacetAndPosition;
// maps facet addresses to function selectors
mapping(address => FacetFunctionSelectors) facetFunctionSelectors;
// facet addresses
address[] facetAddresses;
// Used to query if a contract implements an interface.
// Used to implement ERC-165.
mapping(bytes4 => bool) supportedInterfaces;
// owner of the contract
address contractOwner;
}
function diamondStorage()
internal
pure
returns (DiamondStorage storage ds)
{
bytes32 position = DIAMOND_STORAGE_POSITION;
// solhint-disable-next-line no-inline-assembly
assembly {
ds.slot := position
}
}
event OwnershipTransferred(
address indexed previousOwner,
address indexed newOwner
);
function setContractOwner(address _newOwner) internal {
DiamondStorage storage ds = diamondStorage();
address previousOwner = ds.contractOwner;
ds.contractOwner = _newOwner;
emit OwnershipTransferred(previousOwner, _newOwner);
}
function contractOwner() internal view returns (address contractOwner_) {
contractOwner_ = diamondStorage().contractOwner;
}
function enforceIsContractOwner() internal view {
if (msg.sender != diamondStorage().contractOwner)
revert OnlyContractOwner();
}
event DiamondCut(
IDiamondCut.FacetCut[] _diamondCut,
address _init,
bytes _calldata
);
// Internal function version of diamondCut
function diamondCut(
IDiamondCut.FacetCut[] memory _diamondCut,
address _init,
bytes memory _calldata
) internal {
for (uint256 facetIndex; facetIndex < _diamondCut.length; ) {
IDiamondCut.FacetCutAction action = _diamondCut[facetIndex].action;
if (action == IDiamondCut.FacetCutAction.Add) {
addFunctions(
_diamondCut[facetIndex].facetAddress,
_diamondCut[facetIndex].functionSelectors
);
} else if (action == IDiamondCut.FacetCutAction.Replace) {
replaceFunctions(
_diamondCut[facetIndex].facetAddress,
_diamondCut[facetIndex].functionSelectors
);
} else if (action == IDiamondCut.FacetCutAction.Remove) {
removeFunctions(
_diamondCut[facetIndex].facetAddress,
_diamondCut[facetIndex].functionSelectors
);
} else {
revert IncorrectFacetCutAction();
}
unchecked {
++facetIndex;
}
}
emit DiamondCut(_diamondCut, _init, _calldata);
initializeDiamondCut(_init, _calldata);
}
function addFunctions(
address _facetAddress,
bytes4[] memory _functionSelectors
) internal {
if (_functionSelectors.length == 0) {
revert NoSelectorsInFace();
}
DiamondStorage storage ds = diamondStorage();
if (LibUtil.isZeroAddress(_facetAddress)) {
revert FacetAddressIsZero();
}
uint96 selectorPosition = uint96(
ds.facetFunctionSelectors[_facetAddress].functionSelectors.length
);
// add new facet address if it does not exist
if (selectorPosition == 0) {
addFacet(ds, _facetAddress);
}
for (
uint256 selectorIndex;
selectorIndex < _functionSelectors.length;
) {
bytes4 selector = _functionSelectors[selectorIndex];
address oldFacetAddress = ds
.selectorToFacetAndPosition[selector]
.facetAddress;
if (!LibUtil.isZeroAddress(oldFacetAddress)) {
revert FunctionAlreadyExists();
}
addFunction(ds, selector, selectorPosition, _facetAddress);
unchecked {
++selectorPosition;
++selectorIndex;
}
}
}
function replaceFunctions(
address _facetAddress,
bytes4[] memory _functionSelectors
) internal {
if (_functionSelectors.length == 0) {
revert NoSelectorsInFace();
}
DiamondStorage storage ds = diamondStorage();
if (LibUtil.isZeroAddress(_facetAddress)) {
revert FacetAddressIsZero();
}
uint96 selectorPosition = uint96(
ds.facetFunctionSelectors[_facetAddress].functionSelectors.length
);
// add new facet address if it does not exist
if (selectorPosition == 0) {
addFacet(ds, _facetAddress);
}
for (
uint256 selectorIndex;
selectorIndex < _functionSelectors.length;
) {
bytes4 selector = _functionSelectors[selectorIndex];
address oldFacetAddress = ds
.selectorToFacetAndPosition[selector]
.facetAddress;
if (oldFacetAddress == _facetAddress) {
revert FunctionAlreadyExists();
}
removeFunction(ds, oldFacetAddress, selector);
addFunction(ds, selector, selectorPosition, _facetAddress);
unchecked {
++selectorPosition;
++selectorIndex;
}
}
}
function removeFunctions(
address _facetAddress,
bytes4[] memory _functionSelectors
) internal {
if (_functionSelectors.length == 0) {
revert NoSelectorsInFace();
}
DiamondStorage storage ds = diamondStorage();
// if function does not exist then do nothing and return
if (!LibUtil.isZeroAddress(_facetAddress)) {
revert FacetAddressIsNotZero();
}
for (
uint256 selectorIndex;
selectorIndex < _functionSelectors.length;
) {
bytes4 selector = _functionSelectors[selectorIndex];
address oldFacetAddress = ds
.selectorToFacetAndPosition[selector]
.facetAddress;
removeFunction(ds, oldFacetAddress, selector);
unchecked {
++selectorIndex;
}
}
}
function addFacet(
DiamondStorage storage ds,
address _facetAddress
) internal {
enforceHasContractCode(_facetAddress);
ds.facetFunctionSelectors[_facetAddress].facetAddressPosition = ds
.facetAddresses
.length;
ds.facetAddresses.push(_facetAddress);
}
function addFunction(
DiamondStorage storage ds,
bytes4 _selector,
uint96 _selectorPosition,
address _facetAddress
) internal {
ds
.selectorToFacetAndPosition[_selector]
.functionSelectorPosition = _selectorPosition;
ds.facetFunctionSelectors[_facetAddress].functionSelectors.push(
_selector
);
ds.selectorToFacetAndPosition[_selector].facetAddress = _facetAddress;
}
function removeFunction(
DiamondStorage storage ds,
address _facetAddress,
bytes4 _selector
) internal {
if (LibUtil.isZeroAddress(_facetAddress)) {
revert FunctionDoesNotExist();
}
// an immutable function is a function defined directly in a diamond
if (_facetAddress == address(this)) {
revert FunctionIsImmutable();
}
// replace selector with last selector, then delete last selector
uint256 selectorPosition = ds
.selectorToFacetAndPosition[_selector]
.functionSelectorPosition;
uint256 lastSelectorPosition = ds
.facetFunctionSelectors[_facetAddress]
.functionSelectors
.length - 1;
// if not the same then replace _selector with lastSelector
if (selectorPosition != lastSelectorPosition) {
bytes4 lastSelector = ds
.facetFunctionSelectors[_facetAddress]
.functionSelectors[lastSelectorPosition];
ds.facetFunctionSelectors[_facetAddress].functionSelectors[
selectorPosition
] = lastSelector;
ds
.selectorToFacetAndPosition[lastSelector]
.functionSelectorPosition = uint96(selectorPosition);
}
// delete the last selector
ds.facetFunctionSelectors[_facetAddress].functionSelectors.pop();
delete ds.selectorToFacetAndPosition[_selector];
// if no more selectors for facet address then delete the facet address
if (lastSelectorPosition == 0) {
// replace facet address with last facet address and delete last facet address
uint256 lastFacetAddressPosition = ds.facetAddresses.length - 1;
uint256 facetAddressPosition = ds
.facetFunctionSelectors[_facetAddress]
.facetAddressPosition;
if (facetAddressPosition != lastFacetAddressPosition) {
address lastFacetAddress = ds.facetAddresses[
lastFacetAddressPosition
];
ds.facetAddresses[facetAddressPosition] = lastFacetAddress;
ds
.facetFunctionSelectors[lastFacetAddress]
.facetAddressPosition = facetAddressPosition;
}
ds.facetAddresses.pop();
delete ds
.facetFunctionSelectors[_facetAddress]
.facetAddressPosition;
}
}
function initializeDiamondCut(
address _init,
bytes memory _calldata
) internal {
if (LibUtil.isZeroAddress(_init)) {
if (_calldata.length != 0) {
revert InitZeroButCalldataNotEmpty();
}
} else {
if (_calldata.length == 0) {
revert CalldataEmptyButInitNotZero();
}
if (_init != address(this)) {
enforceHasContractCode(_init);
}
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory error) = _init.delegatecall(_calldata);
if (!success) {
if (error.length > 0) {
// bubble up the error
revert(string(error));
} else {
revert InitReverted();
}
}
}
}
function enforceHasContractCode(address _contract) internal view {
uint256 contractSize;
// solhint-disable-next-line no-inline-assembly
assembly {
contractSize := extcodesize(_contract)
}
if (contractSize == 0) {
revert FacetContainsNoCode();
}
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.17;
/// @title Reentrancy Guard
/// @notice Abstract contract to provide protection against reentrancy
abstract contract ReentrancyGuard {
/// Storage ///
bytes32 private constant NAMESPACE =
keccak256("com.rubic.reentrancyguard");
/// Types ///
struct ReentrancyStorage {
uint256 status;
}
/// Errors ///
error ReentrancyError();
/// Constants ///
uint256 private constant _NOT_ENTERED = 0;
uint256 private constant _ENTERED = 1;
/// Modifiers ///
modifier nonReentrant() {
ReentrancyStorage storage s = reentrancyStorage();
if (s.status == _ENTERED) revert ReentrancyError();
s.status = _ENTERED;
_;
s.status = _NOT_ENTERED;
}
/// Private Methods ///
/// @dev fetch local storage
function reentrancyStorage()
private
pure
returns (ReentrancyStorage storage data)
{
bytes32 position = NAMESPACE;
// solhint-disable-next-line no-inline-assembly
assembly {
data.slot := position
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import { IRubic } from "../Interfaces/IRubic.sol";
import { LibSwap } from "../Libraries/LibSwap.sol";
import { LibBytes } from "../Libraries/LibBytes.sol";
import { LibAsset } from "../Libraries/LibAsset.sol";
import { LibFees } from "../Libraries/LibFees.sol";
import { LibAllowList } from "../Libraries/LibAllowList.sol";
import { InvalidAmount, ContractCallNotAllowed, NoSwapDataProvided, CumulativeSlippageTooHigh } from "../Errors/GenericErrors.sol";
/// @title Swapper
/// @notice Abstract contract to provide swap functionality
contract SwapperV2 is IRubic {
/// Types ///
/// @dev only used to get around "Stack Too Deep" errors
struct ReserveData {
bytes32 transactionId;
address payable leftoverReceiver;
uint256 nativeReserve;
}
/// Modifiers ///
/// @dev Sends any leftover balances back to the user
/// @notice Sends any leftover balances to the user
/// @param _swaps Swap data array
/// @param _leftoverReceiver Address to send leftover tokens to
/// @param _initialBalances Array of initial token balances
modifier noLeftovers(
LibSwap.SwapData[] memory _swaps,
address payable _leftoverReceiver,
uint256[] memory _initialBalances
) {
uint256 numSwaps = _swaps.length;
if (numSwaps != 1) {
address finalAsset = _swaps[numSwaps - 1].receivingAssetId;
uint256 curBalance;
_;
for (uint256 i = 0; i < numSwaps - 1; ) {
address curAsset = _swaps[i].receivingAssetId;
// Handle multi-to-one swaps
if (curAsset != finalAsset) {
curBalance =
LibAsset.getOwnBalance(curAsset) -
_initialBalances[i];
if (curBalance > 0) {
LibAsset.transferAsset(
curAsset,
_leftoverReceiver,
curBalance
);
}
}
unchecked {
++i;
}
}
} else {
_;
}
}
/// @dev Sends any leftover balances back to the user reserving native tokens
/// @notice Sends any leftover balances to the user
/// @param _swaps Swap data array
/// @param _leftoverReceiver Address to send leftover tokens to
/// @param _initialBalances Array of initial token balances
modifier noLeftoversReserve(
LibSwap.SwapData[] memory _swaps,
address payable _leftoverReceiver,
uint256[] memory _initialBalances,
uint256 _nativeReserve
) {
uint256 numSwaps = _swaps.length;
if (numSwaps != 1) {
address finalAsset = _swaps[numSwaps - 1].receivingAssetId;
uint256 curBalance;
_;
for (uint256 i = 0; i < numSwaps - 1; ) {
address curAsset = _swaps[i].receivingAssetId;
// Handle multi-to-one swaps
if (curAsset != finalAsset) {
curBalance =
LibAsset.getOwnBalance(curAsset) -
_initialBalances[i];
uint256 reserve = LibAsset.isNativeAsset(curAsset)
? _nativeReserve
: 0;
if (curBalance > 0) {
LibAsset.transferAsset(
curAsset,
_leftoverReceiver,
curBalance - reserve
);
}
}
unchecked {
++i;
}
}
} else {
_;
}
}
/// @dev Refunds any excess native asset sent to the contract after the main function
/// @notice Refunds any excess native asset sent to the contract after the main function
/// @param _refundReceiver Address to send refunds to
modifier refundExcessNative(address payable _refundReceiver) {
uint256 initialBalance = address(this).balance - msg.value;
_;
uint256 finalBalance = address(this).balance;
uint256 excess = finalBalance > initialBalance
? finalBalance - initialBalance
: 0;
if (excess > 0) {
LibAsset.transferAsset(
LibAsset.NATIVE_ASSETID,
_refundReceiver,
excess
);
}
}
/// Internal Methods ///
/// @dev Deposits value, executes swaps, and performs minimum amount check
/// @param _transactionId the transaction id associated with the operation
/// @param _minAmount the minimum amount of the final asset to receive
/// @param _swaps Array of data used to execute swaps
/// @param _integrator Integrator for whom to count the fees
/// @param _leftoverReceiver The address to send leftover funds to
/// @return uint256 result of the swap
function _depositAndSwap(
bytes32 _transactionId,
uint256 _minAmount,
LibSwap.SwapData[] memory _swaps,
address _integrator,
address payable _leftoverReceiver
) internal returns (uint256) {
uint256 numSwaps = _swaps.length;
if (numSwaps == 0) {
revert NoSwapDataProvided();
}
address finalTokenId = _swaps[numSwaps - 1].receivingAssetId;
uint256 initialBalance = LibAsset.getOwnBalance(finalTokenId);
if (LibAsset.isNativeAsset(finalTokenId)) {
initialBalance -= msg.value;
}
uint256[] memory initialBalances = _fetchBalances(_swaps);
_swaps = LibAsset.depositAssetsAndAccrueFees(_swaps, _integrator);
_executeSwaps(
_transactionId,
_swaps,
_leftoverReceiver,
initialBalances
);
uint256 newBalance = LibAsset.getOwnBalance(finalTokenId) -
initialBalance;
if (newBalance < _minAmount) {
revert CumulativeSlippageTooHigh(_minAmount, newBalance);
}
return newBalance;
}
/// @dev Deposits value, executes swaps, and performs minimum amount check and reserves native token for fees
/// @param _transactionId the transaction id associated with the operation
/// @param _minAmount the minimum amount of the final asset to receive
/// @param _swaps Array of data used to execute swaps
/// @param _integrator Integrator for whom to count the fees
/// @param _leftoverReceiver The address to send leftover funds to
/// @param _nativeReserve Amount of native token to prevent from being swept back to the caller
function _depositAndSwap(
bytes32 _transactionId,
uint256 _minAmount,
LibSwap.SwapData[] memory _swaps,
address _integrator,
address payable _leftoverReceiver,
uint256 _nativeReserve
) internal returns (uint256) {
uint256 numSwaps = _swaps.length;
if (numSwaps == 0) {
revert NoSwapDataProvided();
}
address finalTokenId = _swaps[numSwaps - 1].receivingAssetId;
uint256 initialBalance = LibAsset.getOwnBalance(finalTokenId);
if (LibAsset.isNativeAsset(finalTokenId)) {
initialBalance -= msg.value;
}
uint256[] memory initialBalances = _fetchBalances(_swaps);
_swaps = LibAsset.depositAssetsAndAccrueFees(_swaps, _integrator);
ReserveData memory rd = ReserveData(
_transactionId,
_leftoverReceiver,
_nativeReserve
);
_executeSwaps(rd, _swaps, initialBalances);
uint256 newBalance = LibAsset.getOwnBalance(finalTokenId) -
initialBalance;
if (newBalance < _minAmount) {
revert CumulativeSlippageTooHigh(_minAmount, newBalance);
}
return newBalance;
}
/// Private Methods ///
/// @dev Executes swaps and checks that DEXs used are in the allowList
/// @param _transactionId the transaction id associated with the operation
/// @param _swaps Array of data used to execute swaps
/// @param _leftoverReceiver Address to send leftover tokens to
/// @param _initialBalances Array of initial balances
function _executeSwaps(
bytes32 _transactionId,
LibSwap.SwapData[] memory _swaps,
address payable _leftoverReceiver,
uint256[] memory _initialBalances
) internal noLeftovers(_swaps, _leftoverReceiver, _initialBalances) {
uint256 numSwaps = _swaps.length;
for (uint256 i = 0; i < numSwaps; ) {
LibSwap.SwapData memory currentSwap = _swaps[i];
if (
!((LibAsset.isNativeAsset(currentSwap.sendingAssetId) ||
LibAllowList.contractIsAllowed(currentSwap.approveTo)) &&
LibAllowList.contractIsAllowed(currentSwap.callTo) &&
LibAllowList.selectorIsAllowed(
LibBytes.getFirst4Bytes(currentSwap.callData)
))
) revert ContractCallNotAllowed();
LibSwap.swap(_transactionId, currentSwap);
unchecked {
++i;
}
}
}
/// @dev Executes swaps and checks that DEXs used are in the allowList
/// @param _reserveData Data passed used to reserve native tokens
/// @param _swaps Array of data used to execute swaps
function _executeSwaps(
ReserveData memory _reserveData,
LibSwap.SwapData[] memory _swaps,
uint256[] memory _initialBalances
)
internal
noLeftoversReserve(
_swaps,
_reserveData.leftoverReceiver,
_initialBalances,
_reserveData.nativeReserve
)
{
uint256 numSwaps = _swaps.length;
for (uint256 i = 0; i < numSwaps; ) {
LibSwap.SwapData memory currentSwap = _swaps[i];
if (
!((LibAsset.isNativeAsset(currentSwap.sendingAssetId) ||
LibAllowList.contractIsAllowed(currentSwap.approveTo)) &&
LibAllowList.contractIsAllowed(currentSwap.callTo) &&
LibAllowList.selectorIsAllowed(
LibBytes.getFirst4Bytes(currentSwap.callData)
))
) revert ContractCallNotAllowed();
LibSwap.swap(_reserveData.transactionId, currentSwap);
unchecked {
++i;
}
}
}
/// @dev Fetches balances of tokens to be swapped before swapping.
/// @param _swaps Array of data used to execute swaps
/// @return uint256[] Array of token balances.
function _fetchBalances(
LibSwap.SwapData[] memory _swaps
) private view returns (uint256[] memory) {
uint256 numSwaps = _swaps.length;
uint256[] memory balances = new uint256[](numSwaps);
address asset;
for (uint256 i = 0; i < numSwaps; ) {
asset = _swaps[i].receivingAssetId;
balances[i] = LibAsset.getOwnBalance(asset);
if (LibAsset.isNativeAsset(asset)) {
balances[i] -= msg.value;
}
unchecked {
++i;
}
}
return balances;
}
}// SPDX-License-Identifier: MIT pragma solidity 0.8.17; error TokenAddressIsZero(); error TokenNotSupported(); error CannotBridgeToSameNetwork(); error ZeroPostSwapBalance(); error NoSwapDataProvided(); error NativeValueWithERC(); error ContractCallNotAllowed(); error NullAddrIsNotAValidSpender(); error NullAddrIsNotAnERC20Token(); error NoTransferToNullAddress(); error NativeAssetTransferFailed(); error InvalidBridgeConfigLength(); error InvalidAmount(); error InvalidContract(); error InvalidConfig(); error UnsupportedChainId(uint256 chainId); error InvalidReceiver(); error InvalidDestinationChain(); error InvalidSendingToken(); error InvalidCaller(); error AlreadyInitialized(); error NotInitialized(); error OnlyContractOwner(); error CannotAuthoriseSelf(); error RecoveryAddressCannotBeZero(); error CannotDepositNativeToken(); error InvalidCallData(); error NativeAssetNotSupported(); error UnAuthorized(); error NoSwapFromZeroBalance(); error InvalidFallbackAddress(); error CumulativeSlippageTooHigh(uint256 minAmount, uint256 receivedAmount); error InsufficientBalance(uint256 required, uint256 balance); error ZeroAmount(); error ZeroAddress(); error InvalidFee(); error InformationMismatch(); error LengthMissmatch(); error NotAContract(); error NotEnoughBalance(uint256 requested, uint256 available); error InsufficientMessageValue(); error ExternalCallFailed(); error ReentrancyError();
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.17;
import { LibAsset } from "../Libraries/LibAsset.sol";
import { LibUtil } from "../Libraries/LibUtil.sol";
import { InvalidReceiver, InformationMismatch, InvalidSendingToken, InvalidAmount, NativeAssetNotSupported, InvalidDestinationChain, CannotBridgeToSameNetwork } from "../Errors/GenericErrors.sol";
import { IRubic } from "../Interfaces/IRubic.sol";
import { LibSwap } from "../Libraries/LibSwap.sol";
contract Validatable {
modifier validateBridgeData(IRubic.BridgeData memory _bridgeData) {
if (LibUtil.isZeroAddress(_bridgeData.receiver)) {
revert InvalidReceiver();
}
if (_bridgeData.minAmount == 0) {
revert InvalidAmount();
}
if (_bridgeData.destinationChainId == block.chainid) {
revert CannotBridgeToSameNetwork();
}
_;
}
modifier noNativeAsset(IRubic.BridgeData memory _bridgeData) {
if (LibAsset.isNativeAsset(_bridgeData.sendingAssetId)) {
revert NativeAssetNotSupported();
}
_;
}
modifier onlyAllowSourceToken(
IRubic.BridgeData memory _bridgeData,
address _token
) {
if (_bridgeData.sendingAssetId != _token) {
revert InvalidSendingToken();
}
_;
}
modifier onlyAllowDestinationChain(
IRubic.BridgeData memory _bridgeData,
uint256 _chainId
) {
if (_bridgeData.destinationChainId != _chainId) {
revert InvalidDestinationChain();
}
_;
}
modifier containsSourceSwaps(IRubic.BridgeData memory _bridgeData) {
if (!_bridgeData.hasSourceSwaps) {
revert InformationMismatch();
}
_;
}
modifier doesNotContainSourceSwaps(IRubic.BridgeData memory _bridgeData) {
if (_bridgeData.hasSourceSwaps) {
revert InformationMismatch();
}
_;
}
modifier doesNotContainDestinationCalls(
IRubic.BridgeData memory _bridgeData
) {
if (_bridgeData.hasDestinationCall) {
revert InformationMismatch();
}
_;
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import { CannotAuthoriseSelf, UnAuthorized } from "../Errors/GenericErrors.sol";
/// @title Access Library
/// @notice Provides functionality for managing method level access control
library LibAccess {
/// Types ///
bytes32 internal constant NAMESPACE =
keccak256("com.rubic.library.access.management");
/// Storage ///
struct AccessStorage {
mapping(bytes4 => mapping(address => bool)) execAccess;
}
/// Events ///
event AccessGranted(address indexed account, bytes4 indexed method);
event AccessRevoked(address indexed account, bytes4 indexed method);
/// @dev Fetch local storage
function accessStorage()
internal
pure
returns (AccessStorage storage accStor)
{
bytes32 position = NAMESPACE;
// solhint-disable-next-line no-inline-assembly
assembly {
accStor.slot := position
}
}
/// @notice Gives an address permission to execute a method
/// @param selector The method selector to execute
/// @param executor The address to grant permission to
function addAccess(bytes4 selector, address executor) internal {
if (executor == address(this)) {
revert CannotAuthoriseSelf();
}
AccessStorage storage accStor = accessStorage();
accStor.execAccess[selector][executor] = true;
emit AccessGranted(executor, selector);
}
/// @notice Revokes permission to execute a method
/// @param selector The method selector to execute
/// @param executor The address to revoke permission from
function removeAccess(bytes4 selector, address executor) internal {
AccessStorage storage accStor = accessStorage();
accStor.execAccess[selector][executor] = false;
emit AccessRevoked(executor, selector);
}
/// @notice Enforces access control by reverting if `msg.sender`
/// has not been given permission to execute `msg.sig`
function enforceAccessControl() internal view {
AccessStorage storage accStor = accessStorage();
if (accStor.execAccess[msg.sig][msg.sender] != true)
revert UnAuthorized();
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.sol";
import "../../../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;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @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, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
// Return data is optional
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @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 amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` 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 amount) 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 `amount` 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 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` 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 amount
) external returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { LibAsset } from "../Libraries/LibAsset.sol";
import { LibUtil } from "../Libraries/LibUtil.sol";
import { ZeroAddress, LengthMissmatch, NotInitialized } from "../Errors/GenericErrors.sol";
/// @title ERC20 Proxy
/// @notice Proxy contract for safely transferring ERC20 tokens for swaps/executions
contract ERC20Proxy is Ownable {
/// Storage ///
address public diamond;
/// Events ///
event DiamondSet(address diamond);
/// Constructor
constructor(address _owner, address _diamond) {
transferOwnership(_owner);
diamond = _diamond;
}
function setDiamond(address _diamond) external onlyOwner {
if (_diamond == address(0)) revert ZeroAddress();
diamond = _diamond;
emit DiamondSet(_diamond);
}
/// @dev Transfers tokens from user to the diamond and calls it
/// @param tokens Addresses of tokens that should be sent to the diamond
/// @param amounts Corresponding amounts of tokens
/// @param facetCallData Calldata that should be passed to the diamond
/// Should contain any cross-chain related function
function startViaRubic(
address[] memory tokens,
uint256[] memory amounts,
bytes memory facetCallData
) external payable {
if (diamond == address(0)) revert NotInitialized();
uint256 tokensLength = tokens.length;
if (tokensLength != amounts.length) revert LengthMissmatch();
for (uint256 i = 0; i < tokensLength; ) {
LibAsset.transferFromERC20(
tokens[i],
msg.sender,
diamond,
amounts[i]
);
unchecked {
++i;
}
}
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory res) = diamond.call{ value: msg.value }(
facetCallData
);
if (!success) {
string memory reason = LibUtil.getRevertMsg(res);
revert(reason);
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import { LibAsset } from "./LibAsset.sol";
import { LibUtil } from "./LibUtil.sol";
import { InvalidContract, NoSwapFromZeroBalance, InsufficientBalance, UnAuthorized } from "../Errors/GenericErrors.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
library LibSwap {
struct SwapData {
address callTo;
address approveTo;
address sendingAssetId;
address receivingAssetId;
uint256 fromAmount;
bytes callData;
bool requiresDeposit;
}
event AssetSwapped(
bytes32 transactionId,
address dex,
address fromAssetId,
address toAssetId,
uint256 fromAmount,
uint256 toAmount,
uint256 timestamp
);
function swap(bytes32 transactionId, SwapData memory _swap) internal {
if (!LibAsset.isContract(_swap.callTo)) revert InvalidContract();
uint256 fromAmount = _swap.fromAmount;
if (fromAmount == 0) revert NoSwapFromZeroBalance();
uint256 nativeValue = LibAsset.isNativeAsset(_swap.sendingAssetId)
? _swap.fromAmount
: 0;
uint256 initialSendingAssetBalance = LibAsset.getOwnBalance(
_swap.sendingAssetId
);
uint256 initialReceivingAssetBalance = LibAsset.getOwnBalance(
_swap.receivingAssetId
);
if (nativeValue == 0) {
LibAsset.maxApproveERC20(
IERC20(_swap.sendingAssetId),
_swap.approveTo,
_swap.fromAmount
);
}
if (initialSendingAssetBalance < _swap.fromAmount) {
revert InsufficientBalance(
_swap.fromAmount,
initialSendingAssetBalance
);
}
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory res) = _swap.callTo.call{
value: nativeValue
}(_swap.callData);
if (!success) {
string memory reason = LibUtil.getRevertMsg(res);
revert(reason);
}
uint256 newBalance = LibAsset.getOwnBalance(_swap.receivingAssetId);
emit AssetSwapped(
transactionId,
_swap.callTo,
_swap.sendingAssetId,
_swap.receivingAssetId,
_swap.fromAmount,
newBalance > initialReceivingAssetBalance
? newBalance - initialReceivingAssetBalance
: newBalance,
block.timestamp
);
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
interface IFeesFacet {
struct IntegratorFeeInfo {
bool isIntegrator; // flag for setting 0 fees for integrator - 1 byte
uint32 tokenFee; // total fee percent gathered from user - 4 bytes
uint32 RubicTokenShare; // token share of platform commission - 4 bytes
uint32 RubicFixedCryptoShare; // native share of fixed commission - 4 bytes
uint128 fixedFeeAmount; // custom fixed fee amount - 16 bytes
}
/**
* @dev Initializes the FeesFacet with treasury address and max fee amount
* No need to check initialized status because if max fee is 0 than there is no token fees
* @param _feeTreasure Address to send fees to
* @param _maxRubicPlatformFee Max value of Tubic token fees
*/
function initialize(
address _feeTreasure,
uint256 _maxRubicPlatformFee,
uint256 _maxFixedNativeFee
) external;
/**
* @dev Sets fee info associated with an integrator
* @param _integrator Address of the integrator
* @param _info Struct with fee info
*/
function setIntegratorInfo(
address _integrator,
IntegratorFeeInfo memory _info
) external;
/**
* @dev Sets address of the treasure
* @param _feeTreasure Address of the treasure
*/
function setFeeTreasure(address _feeTreasure) external;
/**
* @dev Sets fixed crypto fee
* @param _fixedNativeFee Fixed crypto fee
*/
function setFixedNativeFee(uint256 _fixedNativeFee) external;
/**
* @dev Sets Rubic token fee
* @notice Cannot be higher than limit set only by an admin
* @param _platformFee Fixed crypto fee
*/
function setRubicPlatformFee(uint256 _platformFee) external;
/**
* @dev Sets the limit of Rubic token fee
* @param _maxFee The limit
*/
function setMaxRubicPlatformFee(uint256 _maxFee) external;
/// VIEW FUNCTIONS ///
function calcTokenFees(
uint256 _amount,
address _integrator
)
external
view
returns (uint256 totalFee, uint256 RubicFee, uint256 integratorFee);
function fixedNativeFee() external view returns (uint256 _fixedNativeFee);
function RubicPlatformFee()
external
view
returns (uint256 _RubicPlatformFee);
function maxRubicPlatformFee()
external
view
returns (uint256 _maxRubicPlatformFee);
function maxFixedNativeFee()
external
view
returns (uint256 _maxFixedNativeFee);
function feeTreasure() external view returns (address feeTreasure);
function integratorToFeeInfo(
address _integrator
) external view returns (IFeesFacet.IntegratorFeeInfo memory _info);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
/// @title Contains 512-bit math functions
/// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision
/// @dev Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits
library FullMath {
/// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
/// @param a The multiplicand
/// @param b The multiplier
/// @param denominator The divisor
/// @return result The 256-bit result
/// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
function mulDiv(
uint256 a,
uint256 b,
uint256 denominator
) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = a * b
// Compute the product mod 2**256 and mod 2**256 - 1
// then 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; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(a, b, not(0))
prod0 := mul(a, b)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division
if (prod1 == 0) {
require(denominator > 0);
assembly {
result := div(prod0, denominator)
}
return result;
}
// Make sure the result is less than 2**256.
// Also prevents denominator == 0
require(denominator > prod1);
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0]
// Compute remainder using mulmod
uint256 remainder;
assembly {
remainder := mulmod(a, b, denominator)
}
// Subtract 256 bit number from 512 bit number
assembly {
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator
// Compute largest power of two divisor of denominator.
// Always >= 1.
uint256 twos = (0 - denominator) & denominator;
// Divide denominator by power of two
assembly {
denominator := div(denominator, twos)
}
// Divide [prod1 prod0] by the factors of two
assembly {
prod0 := div(prod0, twos)
}
// Shift in bits from prod1 into prod0. For this we need
// to flip `twos` such that it is 2**256 / twos.
// If twos is zero, then it becomes one
assembly {
twos := add(div(sub(0, twos), twos), 1)
}
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
// correct for four bits. That is, denominator * inv = 1 mod 2**4
uint256 inv = (3 * denominator) ^ 2;
// Now use 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.
inv *= 2 - denominator * inv; // inverse mod 2**8
inv *= 2 - denominator * inv; // inverse mod 2**16
inv *= 2 - denominator * inv; // inverse mod 2**32
inv *= 2 - denominator * inv; // inverse mod 2**64
inv *= 2 - denominator * inv; // inverse mod 2**128
inv *= 2 - denominator * inv; // 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 precoditions 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 * inv;
return result;
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
library LibBytes {
// solhint-disable no-inline-assembly
// LibBytes specific errors
error SliceOverflow();
error SliceOutOfBounds();
error AddressOutOfBounds();
error UintOutOfBounds();
// -------------------------
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 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) {
if (_length + 31 < _length) revert SliceOverflow();
if (_bytes.length < _start + _length) revert SliceOutOfBounds();
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) {
if (_bytes.length < _start + 20) {
revert AddressOutOfBounds();
}
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) {
if (_bytes.length < _start + 1) {
revert UintOutOfBounds();
}
uint8 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x1), _start))
}
return tempUint;
}
function toUint16(
bytes memory _bytes,
uint256 _start
) internal pure returns (uint16) {
if (_bytes.length < _start + 2) {
revert UintOutOfBounds();
}
uint16 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x2), _start))
}
return tempUint;
}
function toUint32(
bytes memory _bytes,
uint256 _start
) internal pure returns (uint32) {
if (_bytes.length < _start + 4) {
revert UintOutOfBounds();
}
uint32 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x4), _start))
}
return tempUint;
}
function toUint64(
bytes memory _bytes,
uint256 _start
) internal pure returns (uint64) {
if (_bytes.length < _start + 8) {
revert UintOutOfBounds();
}
uint64 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x8), _start))
}
return tempUint;
}
function toUint96(
bytes memory _bytes,
uint256 _start
) internal pure returns (uint96) {
if (_bytes.length < _start + 12) {
revert UintOutOfBounds();
}
uint96 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0xc), _start))
}
return tempUint;
}
function toUint128(
bytes memory _bytes,
uint256 _start
) internal pure returns (uint128) {
if (_bytes.length < _start + 16) {
revert UintOutOfBounds();
}
uint128 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x10), _start))
}
return tempUint;
}
function toUint256(
bytes memory _bytes,
uint256 _start
) internal pure returns (uint256) {
if (_bytes.length < _start + 32) {
revert UintOutOfBounds();
}
uint256 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x20), _start))
}
return tempUint;
}
function toBytes32(
bytes memory _bytes,
uint256 _start
) internal pure returns (bytes32) {
if (_bytes.length < _start + 32) {
revert UintOutOfBounds();
}
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)
// solhint-disable-next-line no-empty-blocks
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;
}
function getFirst4Bytes(
bytes memory data
) internal pure returns (bytes4 outBytes4) {
if (data.length == 0) {
return 0x0;
}
assembly {
outBytes4 := mload(add(data, 32))
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
interface IDiamondCut {
enum FacetCutAction {
Add,
Replace,
Remove
}
// Add=0, Replace=1, Remove=2
struct FacetCut {
address facetAddress;
FacetCutAction action;
bytes4[] functionSelectors;
}
/// @notice Add/replace/remove any number of functions and optionally execute
/// a function with delegatecall
/// @param _diamondCut Contains the facet addresses and function selectors
/// @param _init The address of the contract or facet to execute _calldata
/// @param _calldata A function call, including function selector and arguments
/// _calldata is executed with delegatecall on _init
function diamondCut(
FacetCut[] calldata _diamondCut,
address _init,
bytes calldata _calldata
) external;
event DiamondCut(FacetCut[] _diamondCut, address _init, bytes _calldata);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import { InvalidContract } from "../Errors/GenericErrors.sol";
/// @title Lib Allow List
/// @notice Library for managing and accessing the conract address allow list
library LibAllowList {
/// Storage ///
bytes32 internal constant NAMESPACE =
keccak256("com.rubic.library.allow.list");
struct AllowListStorage {
mapping(address => bool) allowlist;
mapping(bytes4 => bool) selectorAllowList;
address[] contracts;
}
/// @dev Adds a contract address to the allow list
/// @param _contract the contract address to add
function addAllowedContract(address _contract) internal {
_checkAddress(_contract);
AllowListStorage storage als = _getStorage();
if (als.allowlist[_contract]) return;
als.allowlist[_contract] = true;
als.contracts.push(_contract);
}
/// @dev Checks whether a contract address has been added to the allow list
/// @param _contract the contract address to check
function contractIsAllowed(
address _contract
) internal view returns (bool) {
return _getStorage().allowlist[_contract];
}
/// @dev Remove a contract address from the allow list
/// @param _contract the contract address to remove
function removeAllowedContract(address _contract) internal {
AllowListStorage storage als = _getStorage();
if (!als.allowlist[_contract]) {
return;
}
als.allowlist[_contract] = false;
uint256 length = als.contracts.length;
// Find the contract in the list
for (uint256 i = 0; i < length; i++) {
if (als.contracts[i] == _contract) {
// Move the last element into the place to delete
als.contracts[i] = als.contracts[length - 1];
// Remove the last element
als.contracts.pop();
break;
}
}
}
/// @dev Fetch contract addresses from the allow list
function getAllowedContracts() internal view returns (address[] memory) {
return _getStorage().contracts;
}
/// @dev Add a selector to the allow list
/// @param _selector the selector to add
function addAllowedSelector(bytes4 _selector) internal {
_getStorage().selectorAllowList[_selector] = true;
}
/// @dev Removes a selector from the allow list
/// @param _selector the selector to remove
function removeAllowedSelector(bytes4 _selector) internal {
_getStorage().selectorAllowList[_selector] = false;
}
/// @dev Returns if selector has been added to the allow list
/// @param _selector the selector to check
function selectorIsAllowed(bytes4 _selector) internal view returns (bool) {
return _getStorage().selectorAllowList[_selector];
}
/// @dev Fetch local storage struct
function _getStorage()
internal
pure
returns (AllowListStorage storage als)
{
bytes32 position = NAMESPACE;
// solhint-disable-next-line no-inline-assembly
assembly {
als.slot := position
}
}
/// @dev Contains business logic for validating a contract address.
/// @param _contract address of the dex to check
function _checkAddress(address _contract) private view {
if (_contract == address(0)) revert InvalidContract();
if (_contract.code.length == 0) revert InvalidContract();
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @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.
*/
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].
*/
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 v4.8.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @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 breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @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, it is bubbled up by this
* function (like regular Solidity function calls).
*
* 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.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @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`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) 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(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.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.
*
* By default, the owner account will be the one that deploys the contract. 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 Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @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) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing 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 {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @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 Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}{
"remappings": [
"@axelar-network/=node_modules/@axelar-network/",
"@connext/=node_modules/@connext/",
"@eth-optimism/=node_modules/@eth-optimism/",
"@openzeppelin/=node_modules/@openzeppelin/",
"@uniswap/=node_modules/@uniswap/",
"celer-network/=lib/sgn-v2-contracts/",
"create3-factory/=lib/create3-factory/src/",
"ds-test/=lib/ds-test/src/",
"eth-gas-reporter/=node_modules/eth-gas-reporter/",
"forge-std/=lib/forge-std/src/",
"hardhat-deploy/=node_modules/hardhat-deploy/",
"hardhat/=node_modules/hardhat/",
"rubic/=src/",
"sgn-v2-contracts/=lib/sgn-v2-contracts/contracts/",
"solmate/=lib/solmate/src/",
"test/=test/"
],
"optimizer": {
"enabled": true,
"runs": 10000
},
"metadata": {
"bytecodeHash": "ipfs"
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "london",
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"name":"CannotBridgeToSameNetwork","type":"error"},{"inputs":[],"name":"ContractCallNotAllowed","type":"error"},{"inputs":[{"internalType":"uint256","name":"minAmount","type":"uint256"},{"internalType":"uint256","name":"receivedAmount","type":"uint256"}],"name":"CumulativeSlippageTooHigh","type":"error"},{"inputs":[],"name":"InformationMismatch","type":"error"},{"inputs":[{"internalType":"uint256","name":"required","type":"uint256"},{"internalType":"uint256","name":"balance","type":"uint256"}],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InvalidAmount","type":"error"},{"inputs":[],"name":"InvalidContract","type":"error"},{"inputs":[],"name":"InvalidReceiver","type":"error"},{"inputs":[],"name":"LengthMissmatch","type":"error"},{"inputs":[],"name":"NativeAssetTransferFailed","type":"error"},{"inputs":[],"name":"NoSwapDataProvided","type":"error"},{"inputs":[],"name":"NoSwapFromZeroBalance","type":"error"},{"inputs":[],"name":"NoTransferToNullAddress","type":"error"},{"inputs":[],"name":"NullAddrIsNotAValidSpender","type":"error"},{"inputs":[],"name":"NullAddrIsNotAnERC20Token","type":"error"},{"inputs":[],"name":"OnlyContractOwner","type":"error"},{"inputs":[],"name":"ReentrancyError","type":"error"},{"inputs":[],"name":"SliceOutOfBounds","type":"error"},{"inputs":[],"name":"SliceOverflow","type":"error"},{"inputs":[],"name":"UnAuthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":false,"internalType":"address","name":"receivingAssetId","type":"address"},{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"RubicTransferCompleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":false,"internalType":"address","name":"receivingAssetId","type":"address"},{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"RubicTransferRecovered","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"string","name":"bridge","type":"string"},{"internalType":"address","name":"integrator","type":"address"},{"internalType":"address","name":"referrer","type":"address"},{"internalType":"address","name":"sendingAssetId","type":"address"},{"internalType":"address","name":"receivingAssetId","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"refundee","type":"address"},{"internalType":"uint256","name":"minAmount","type":"uint256"},{"internalType":"uint256","name":"destinationChainId","type":"uint256"},{"internalType":"bool","name":"hasSourceSwaps","type":"bool"},{"internalType":"bool","name":"hasDestinationCall","type":"bool"}],"indexed":false,"internalType":"struct IRubic.BridgeData","name":"bridgeData","type":"tuple"}],"name":"RubicTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"_routers","type":"address[]"},{"indexed":false,"internalType":"bytes4[]","name":"_selectors","type":"bytes4[]"},{"components":[{"internalType":"bool","name":"isAvailable","type":"bool"},{"internalType":"uint256","name":"offset","type":"uint256"}],"indexed":false,"internalType":"struct LibMappings.ProviderFunctionInfo[]","name":"_infos","type":"tuple[]"}],"name":"SelectorToInfoUpdated","type":"event"},{"inputs":[{"internalType":"address","name":"_router","type":"address"},{"internalType":"bytes4","name":"_selector","type":"bytes4"}],"name":"getSelectorInfo","outputs":[{"components":[{"internalType":"bool","name":"isAvailable","type":"bool"},{"internalType":"uint256","name":"offset","type":"uint256"}],"internalType":"struct LibMappings.ProviderFunctionInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"string","name":"bridge","type":"string"},{"internalType":"address","name":"integrator","type":"address"},{"internalType":"address","name":"referrer","type":"address"},{"internalType":"address","name":"sendingAssetId","type":"address"},{"internalType":"address","name":"receivingAssetId","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"refundee","type":"address"},{"internalType":"uint256","name":"minAmount","type":"uint256"},{"internalType":"uint256","name":"destinationChainId","type":"uint256"},{"internalType":"bool","name":"hasSourceSwaps","type":"bool"},{"internalType":"bool","name":"hasDestinationCall","type":"bool"}],"internalType":"struct IRubic.BridgeData","name":"_bridgeData","type":"tuple"},{"components":[{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"approveTo","type":"address"},{"internalType":"uint256","name":"extraNative","type":"uint256"},{"internalType":"bytes","name":"callData","type":"bytes"}],"internalType":"struct GenericCrossChainFacet.GenericCrossChainData","name":"_genericData","type":"tuple"}],"name":"startBridgeTokensViaGenericCrossChain","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"string","name":"bridge","type":"string"},{"internalType":"address","name":"integrator","type":"address"},{"internalType":"address","name":"referrer","type":"address"},{"internalType":"address","name":"sendingAssetId","type":"address"},{"internalType":"address","name":"receivingAssetId","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"refundee","type":"address"},{"internalType":"uint256","name":"minAmount","type":"uint256"},{"internalType":"uint256","name":"destinationChainId","type":"uint256"},{"internalType":"bool","name":"hasSourceSwaps","type":"bool"},{"internalType":"bool","name":"hasDestinationCall","type":"bool"}],"internalType":"struct IRubic.BridgeData","name":"_bridgeData","type":"tuple"},{"components":[{"internalType":"address","name":"callTo","type":"address"},{"internalType":"address","name":"approveTo","type":"address"},{"internalType":"address","name":"sendingAssetId","type":"address"},{"internalType":"address","name":"receivingAssetId","type":"address"},{"internalType":"uint256","name":"fromAmount","type":"uint256"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bool","name":"requiresDeposit","type":"bool"}],"internalType":"struct LibSwap.SwapData[]","name":"_swapData","type":"tuple[]"},{"components":[{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"approveTo","type":"address"},{"internalType":"uint256","name":"extraNative","type":"uint256"},{"internalType":"bytes","name":"callData","type":"bytes"}],"internalType":"struct GenericCrossChainFacet.GenericCrossChainData","name":"_genericData","type":"tuple"}],"name":"swapAndStartBridgeTokensViaGenericCrossChain","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_routers","type":"address[]"},{"internalType":"bytes4[]","name":"_selectors","type":"bytes4[]"},{"components":[{"internalType":"bool","name":"isAvailable","type":"bool"},{"internalType":"uint256","name":"offset","type":"uint256"}],"internalType":"struct LibMappings.ProviderFunctionInfo[]","name":"_infos","type":"tuple[]"}],"name":"updateSelectorInfo","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
608060405234801561001057600080fd5b506131c2806100206000396000f3fe60806040526004361061003f5760003560e01c80632bd19fde14610044578063647eb57e14610066578063af58398514610079578063dc7ffff7146100ba575b600080fd5b34801561005057600080fd5b5061006461005f36600461266a565b6100cd565b005b6100646100743660046129a1565b61028e565b34801561008557600080fd5b50610099610094366004612a35565b610530565b60408051825115158152602092830151928101929092520160405180910390f35b6100646100c8366004612a5f565b6105c2565b6100d5610829565b7f54b34910d6d88e05cfc79d100db458238c94af5eb402b5d31b86d5054a10cba683861415806101055750838214155b1561013c576040517fd4e105db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b67ffffffffffffffff81168711156102435783838267ffffffffffffffff1681811061016d5761016d612aed565b9050604002018260000160008a8a8567ffffffffffffffff1681811061019557610195612aed565b90506020020160208101906101aa9190612b1c565b6001600160a01b03166001600160a01b03168152602001908152602001600020600088888567ffffffffffffffff168181106101e8576101e8612aed565b90506020020160208101906101fd9190612b37565b7fffffffff0000000000000000000000000000000000000000000000000000000016815260208101919091526040016000206102398282612b52565b505060010161013f565b507f8621ad378521883daa8108c9f45a36f29f3afaf85b0a464009b9b206aa7126ec87878787878760405161027d96959493929190612be7565b60405180910390a150505050505050565b7fd46a770fdb1d7fb038d450c1aee8cd72c3e44da0efcb53d27f7ff78dac24948280547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01610309576040517f29f745a700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001815560e0830151600061031e3447612cd8565b9050846103368160c001516001600160a01b03161590565b1561036d576040517f1e4ec46b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8061010001516000036103ac576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b46816101200151036103ea576040517f4ac09ad300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b846104016103fb6020830183612b1c565b3b151590565b610437576040517f6eefed2000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8680610140015115610475576040517f50dc905c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b87806101600151156104b3576040517f50dc905c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104d089608001518a61010001518a604001358c60400151610891565b6101008a018190526104ee908a906104e9908b906108f9565b610bb0565b50479250600091505082821161050557600061050f565b61050f8383612cd8565b905080156105235761052360008583610cfd565b5050600090925550505050565b604080518082018252600080825260209182018190526001600160a01b03851681527f54b34910d6d88e05cfc79d100db458238c94af5eb402b5d31b86d5054a10cba682528281207fffffffff000000000000000000000000000000000000000000000000000000008516825282528290208251808401909352805460ff161515835260010154908201525b92915050565b7fd46a770fdb1d7fb038d450c1aee8cd72c3e44da0efcb53d27f7ff78dac24948280547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0161063d576040517f29f745a700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001815560e085015160006106523447612cd8565b905086806101400151610691576040517f50dc905c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b876106a78160c001516001600160a01b03161590565b156106de576040517f1e4ec46b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80610100015160000361071d576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b468161012001510361075b576040517f4ac09ad300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8561076c6103fb6020830183612b1c565b6107a2576040517f6eefed2000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b89516101008b01516107cd91906107b98b8d612ceb565b8d604001518e60e001518c60400135610d26565b6101008b018190526107e6908b906104e9908a906108f9565b50479150600090508282116107fc576000610806565b6108068383612cd8565b9050801561081a5761081a60008583610cfd565b50506000909255505050505050565b7fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c600401546001600160a01b0316331461088f576040517f277d76f800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b60008061089d83610e6b565b90506108a98482612dfc565b3410156108e2576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6108ef8686838787611019565b9695505050505050565b60408051608081018252600080825260208201819052918101829052606080820152907f54b34910d6d88e05cfc79d100db458238c94af5eb402b5d31b86d5054a10cba69050600081816109506020880188612b1c565b6001600160a01b0316815260208101919091526040016000908120906109796060880188612e0f565b61098891600491600091612e74565b61099191612e9e565b7fffffffff0000000000000000000000000000000000000000000000000000000016815260208082019290925260409081016000208151808301909252805460ff161580158352600190910154928201929092529150610b7657602081015115610ad857604080516080810190915280610a0e6020880188612b1c565b6001600160a01b03168152602001866020016020810190610a2f9190612b1c565b6001600160a01b03168152604080880135602083015201610a536060880188612e0f565b6020850151610a66929091600091612e74565b60408051602081018a90520160408051601f19818403018152919052610a8f60608b018b612e0f565b602080890151610a9e91612dfc565b610aa9928290612e74565b604051602001610abd959493929190612f08565b604051602081830303815290604052815250925050506105bc565b604080516080810190915280610af16020880188612b1c565b6001600160a01b03168152602001866020016020810190610b129190612b1c565b6001600160a01b03168152604080880135602083015201610b366060880188612e0f565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250505091525092506105bc915050565b6040517fbe24598300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505092915050565b6000610bc783608001516001600160a01b03161590565b905060008115610bdd5750610100830151610bf5565b610bf58460800151846020015186610100015161118d565b60008084600001516001600160a01b0316856040015184610c169190612dfc565b8660600151604051610c289190612f3c565b60006040518083038185875af1925050503d8060008114610c65576040519150601f19603f3d011682016040523d82523d6000602084013e610c6a565b606091505b509150915081610cbe576000610c7f826112b1565b9050806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cb59190612f84565b60405180910390fd5b7ff834e948c18ff30cc76e65c4bb09ce6f070fcea13e3cb45413d9a66686584b9486604051610ced9190612f97565b60405180910390a1505050505050565b6001600160a01b03831615610d1c57610d178383836112fa565b505050565b610d17828261140f565b8351600090808203610d64576040517f0503c3ed00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600086610d72600184612cd8565b81518110610d8257610d82612aed565b60200260200101516060015190506000610d9b8261151f565b90506001600160a01b038216610db857610db53482612cd8565b90505b6000610dc3896115bd565b9050610dcf89896116a6565b604080516060810182528d81526001600160a01b038a166020820152908101889052909950610dff818b8461176f565b600083610e0b8661151f565b610e159190612cd8565b90508b811015610e5b576040517f275c273c000000000000000000000000000000000000000000000000000000008152600481018d905260248101829052604401610cb5565b9c9b505050505050505050505050565b60008080807fc6c3600a890b88a8f7ea8576d6b77243f564078524498bdcc408f2f4884b7df66001600160a01b03861660009081526020828152604091829020825160a081018452905460ff81161580158352610100820463ffffffff908116948401949094526501000000000082048416948301949094526901000000000000000000810490921660608201526d01000000000000000000000000009091046fffffffffffffffffffffffffffffffff166080820152919250610f985760808101516fffffffffffffffffffffffffffffffff1693508315610f9357620f4240816060015163ffffffff1685610f62919061308d565b610f6c91906130a4565b92506000610f7a8486612cd8565b1115610f9357610f9386610f8e8587612cd8565b61140f565b610fa3565b816004015493508392505b8215610fc1576005820154610fc1906001600160a01b03168461140f565b6001600160a01b0386167f74d5029b0a85dd485bf2414b0920760500d9535db170f72375f811087a6d207384610ff78188612cd8565b6040805192835260208301919091520160405180910390a25091949350505050565b60006001600160a01b03861661107c57826110348587612dfc565b61103e9190612dfc565b341015611077576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611182565b846000036110b6576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000906001600160a01b038816906370a0823190602401602060405180830381865afa158015611116573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061113a91906130df565b905085811015611180576040517fcf4791810000000000000000000000000000000000000000000000000000000081526004810187905260248101829052604401610cb5565b505b6108ef828688611b49565b6001600160a01b0383166111a057505050565b6001600160a01b0382166111e0576040517f63ba9bff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0383811660248301526000919085169063dd62ed3e90604401602060405180830381865afa158015611249573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061126d91906130df565b9050818110156112ab576112ab84846112a6847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff612cd8565b611cce565b50505050565b60606044825110156112c1575090565b60006112dd60048085516112d59190612cd8565b859190611e12565b9050808060200190518101906112f391906130f8565b9392505050565b6001600160a01b03831661133a576040517fd1bebf0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000906001600160a01b038516906370a0823190602401602060405180830381865afa15801561139a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113be91906130df565b905080821115611404576040517fcf4791810000000000000000000000000000000000000000000000000000000081526004810183905260248101829052604401610cb5565b6112ab848484611f0e565b6001600160a01b03821661144f576040517f21f7434500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b47811115611492576040517fcf47918100000000000000000000000000000000000000000000000000000000815260048101829052476024820152604401610cb5565b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146114df576040519150601f19603f3d011682016040523d82523d6000602084013e6114e4565b606091505b5050905080610d17576040517f5a04673700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006001600160a01b038216156115b6576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa15801561158d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115b191906130df565b6105bc565b4792915050565b805160609060008167ffffffffffffffff8111156115dd576115dd612733565b604051908082528060200260200182016040528015611606578160200160208202803683370190505b5090506000805b8381101561169c5785818151811061162757611627612aed565b602002602001015160600151915061163e8261151f565b83828151811061165057611650612aed565b60209081029190910101526001600160a01b038216611694573483828151811061167c5761167c612aed565b602002602001018181516116909190612cd8565b9052505b60010161160d565b5090949350505050565b606060006116b383610e6b565b9050803410156116ef576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b845181101561176657600085828151811061170f5761170f612aed565b602002602001015190508060c001511561173f576117398160400151826080015185600089611019565b60808201525b8086838151811061175257611752612aed565b6020908102919091010152506001016116f2565b50929392505050565b81836020015182856040015160008451905080600114611a0b57600085611797600184612cd8565b815181106117a7576117a7612aed565b60200260200101516060015190506000808951905060005b818110156119415760008b82815181106117db576117db612aed565b602002602001015190506117fa81604001516001600160a01b03161590565b80611845575061184581602001516001600160a01b031660009081527fec46400aeca82eb9145f7fc14dfaa75470e03fc835f1928a29957f5b1b60a5da602052604090205460ff1690565b8015611889575080516001600160a01b031660009081527fec46400aeca82eb9145f7fc14dfaa75470e03fc835f1928a29957f5b1b60a5da602052604090205460ff165b80156118f657506118f66118a08260a00151611f57565b7fffffffff000000000000000000000000000000000000000000000000000000001660009081527fec46400aeca82eb9145f7fc14dfaa75470e03fc835f1928a29957f5b1b60a5db602052604090205460ff1690565b61192c576040517f9453980400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8c516119389082611f72565b506001016117bf565b505060005b611951600185612cd8565b811015611a0357600088828151811061196c5761196c612aed565b6020026020010151606001519050836001600160a01b0316816001600160a01b0316146119fa578682815181106119a5576119a5612aed565b60200260200101516119b68261151f565b6119c09190612cd8565b925060006001600160a01b038216156119da5760006119dc565b865b905083156119f8576119f8828a6119f38488612cd8565b610cfd565b505b50600101611946565b505050611b3f565b865160005b81811015611b3c576000898281518110611a2c57611a2c612aed565b60200260200101519050611a4b81604001516001600160a01b03161590565b80611a965750611a9681602001516001600160a01b031660009081527fec46400aeca82eb9145f7fc14dfaa75470e03fc835f1928a29957f5b1b60a5da602052604090205460ff1690565b8015611ada575080516001600160a01b031660009081527fec46400aeca82eb9145f7fc14dfaa75470e03fc835f1928a29957f5b1b60a5da602052604090205460ff165b8015611af15750611af16118a08260a00151611f57565b611b27576040517f9453980400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8a51611b339082611f72565b50600101611a10565b50505b5050505050505050565b6001600160a01b03831660009081527fc6c3600a890b88a8f7ea8576d6b77243f564078524498bdcc408f2f4884b7df660208181526040808420815160a081018352905460ff811615158252610100810463ffffffff908116948301949094526501000000000081048416928201929092526901000000000000000000820490921660608301526d010000000000000000000000000090046fffffffffffffffffffffffffffffffff1660808201528280611c058488856121ce565b90925090506001600160a01b03881615611c3a576000611c258284612cd8565b1115611c3a57611c3a86896119f38486612cd8565b8015611c5a576005840154611c5a9087906001600160a01b031683610cfd565b6001600160a01b0388167f25471ec9f39b4ceb20d58f63c37f9c738011f0babcc4b6af69bdd82984ca5f8e82611c908186612cd8565b6040805192835260208301919091526001600160a01b038a169082015260600160405180910390a2611cc28288612cd8565b98975050505050505050565b6040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa158015611d38573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d5c91906130df565b611d669190612dfc565b6040516001600160a01b0385166024820152604481018290529091506112ab9085907f095ea7b300000000000000000000000000000000000000000000000000000000906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915261220f565b606081611e2081601f612dfc565b1015611e58576040517f47aaf07a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611e628284612dfc565b84511015611e9c576040517f3b99b53d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606082158015611ebb5760405191506000825260208201604052611f05565b6040519150601f8416801560200281840101858101878315602002848b0101015b81831015611ef4578051835260209283019201611edc565b5050858452601f01601f1916604052505b50949350505050565b6040516001600160a01b038316602482015260448101829052610d179084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611dae565b60008151600003611f6a57506000919050565b506020015190565b80513b611fab576040517f6eefed2000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60808101516000819003611feb576040517fe46e079c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061200283604001516001600160a01b03161590565b61200d576000612013565b82608001515b90506000612024846040015161151f565b90506000612035856060015161151f565b9050826000036120565761205685604001518660200151876080015161118d565b84608001518210156120a45760808501516040517fcf479181000000000000000000000000000000000000000000000000000000008152600481019190915260248101839052604401610cb5565b60008086600001516001600160a01b0316858860a001516040516120c89190612f3c565b60006040518083038185875af1925050503d8060008114612105576040519150601f19603f3d011682016040523d82523d6000602084013e61210a565b606091505b50915091508161211f576000610c7f826112b1565b600061212e886060015161151f565b90507f7bfdfdb5e3a3776976e53cb0607060f54c5312701c8cba1155cc4d5394440b388989600001518a604001518b606001518c60800151898711612173578661217d565b61217d8a88612cd8565b604080519687526001600160a01b0395861660208801529385169386019390935292166060840152608083019190915260a08201524260c082015260e00160405180910390a1505050505050505050565b6000808260000151156121ef576121e5848461230e565b9092509050612207565b612201848660030154620f4240612360565b91508190505b935093915050565b6000612264826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166124309092919063ffffffff16565b805190915015610d175780806020019051810190612282919061316f565b610d17576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610cb5565b6000806000836020015163ffffffff1611156123595761233c84846020015163ffffffff16620f4240612360565b915061235682846040015163ffffffff16620f4240612360565b90505b9250929050565b600080807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff858709858702925082811083820303915050806000036123b757600084116123ac57600080fd5b5082900490506112f3565b8084116123c357600080fd5b6000848688096000868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150509392505050565b606061243f8484600085612447565b949350505050565b6060824710156124d9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610cb5565b600080866001600160a01b031685876040516124f59190612f3c565b60006040518083038185875af1925050503d8060008114612532576040519150601f19603f3d011682016040523d82523d6000602084013e612537565b606091505b509150915061254887838387612553565b979650505050505050565b606083156125dc5782516000036125d5576001600160a01b0385163b6125d5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610cb5565b508161243f565b61243f83838151156125f15781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cb59190612f84565b60008083601f84011261263757600080fd5b50813567ffffffffffffffff81111561264f57600080fd5b6020830191508360208260051b850101111561235957600080fd5b6000806000806000806060878903121561268357600080fd5b863567ffffffffffffffff8082111561269b57600080fd5b6126a78a838b01612625565b909850965060208901359150808211156126c057600080fd5b6126cc8a838b01612625565b909650945060408901359150808211156126e557600080fd5b818901915089601f8301126126f957600080fd5b81358181111561270857600080fd5b8a60208260061b850101111561271d57600080fd5b6020830194508093505050509295509295509295565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610180810167ffffffffffffffff8111828210171561278657612786612733565b60405290565b60405160e0810167ffffffffffffffff8111828210171561278657612786612733565b604051601f8201601f1916810167ffffffffffffffff811182821017156127d8576127d8612733565b604052919050565b600067ffffffffffffffff8211156127fa576127fa612733565b50601f01601f191660200190565b600082601f83011261281957600080fd5b813561282c612827826127e0565b6127af565b81815284602083860101111561284157600080fd5b816020850160208301376000918101602001919091529392505050565b80356001600160a01b038116811461287557600080fd5b919050565b801515811461288857600080fd5b50565b80356128758161287a565b600061018082840312156128a957600080fd5b6128b1612762565b905081358152602082013567ffffffffffffffff8111156128d157600080fd5b6128dd84828501612808565b6020830152506128ef6040830161285e565b60408201526129006060830161285e565b60608201526129116080830161285e565b608082015261292260a0830161285e565b60a082015261293360c0830161285e565b60c082015261294460e0830161285e565b60e08201526101008281013590820152610120808301359082015261014061296d81840161288b565b9082015261016061297f83820161288b565b9082015292915050565b60006080828403121561299b57600080fd5b50919050565b600080604083850312156129b457600080fd5b823567ffffffffffffffff808211156129cc57600080fd5b6129d886838701612896565b935060208501359150808211156129ee57600080fd5b506129fb85828601612989565b9150509250929050565b80357fffffffff000000000000000000000000000000000000000000000000000000008116811461287557600080fd5b60008060408385031215612a4857600080fd5b612a518361285e565b915061235660208401612a05565b60008060008060608587031215612a7557600080fd5b843567ffffffffffffffff80821115612a8d57600080fd5b612a9988838901612896565b95506020870135915080821115612aaf57600080fd5b612abb88838901612625565b90955093506040870135915080821115612ad457600080fd5b50612ae187828801612989565b91505092959194509250565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215612b2e57600080fd5b6112f38261285e565b600060208284031215612b4957600080fd5b6112f382612a05565b8135612b5d8161287a565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082541660ff82151516811783555050602082013560018201555050565b8183526000602080850194508260005b85811015612bdc578135612bbe8161287a565b15158752818301358388015260409687019690910190600101612bab565b509495945050505050565b6060808252810186905260008760808301825b89811015612c28576001600160a01b03612c138461285e565b16825260209283019290910190600101612bfa565b5083810360208581019190915287825291508790820160005b88811015612c86577fffffffff00000000000000000000000000000000000000000000000000000000612c7384612a05565b1682529183019190830190600101612c41565b508481036040860152612c9a818789612b9b565b9b9a5050505050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156105bc576105bc612ca9565b600067ffffffffffffffff80841115612d0657612d06612733565b8360051b6020612d178183016127af565b868152918501918181019036841115612d2f57600080fd5b865b84811015612df057803586811115612d495760008081fd5b880160e0368290031215612d5d5760008081fd5b612d6561278c565b612d6e8261285e565b8152612d7b86830161285e565b868201526040612d8c81840161285e565b908201526060612d9d83820161285e565b908201526080828101359082015260a08083013589811115612dbf5760008081fd5b612dcb36828601612808565b82840152505060c0612dde81840161288b565b90820152845250918301918301612d31565b50979650505050505050565b808201808211156105bc576105bc612ca9565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612e4457600080fd5b83018035915067ffffffffffffffff821115612e5f57600080fd5b60200191503681900382131561235957600080fd5b60008085851115612e8457600080fd5b83861115612e9157600080fd5b5050820193919092039150565b7fffffffff000000000000000000000000000000000000000000000000000000008135818116916004851015610ba85760049490940360031b84901b1690921692915050565b60005b83811015612eff578181015183820152602001612ee7565b50506000910152565b848682376000858201600081528551612f25818360208a01612ee4565b018385823760009301928352509095945050505050565b60008251612f4e818460208701612ee4565b9190910192915050565b60008151808452612f70816020860160208601612ee4565b601f01601f19169290920160200192915050565b6020815260006112f36020830184612f58565b602081528151602082015260006020830151610180806040850152612fc06101a0850183612f58565b91506040850151612fdc60608601826001600160a01b03169052565b5060608501516001600160a01b03811660808601525060808501516001600160a01b03811660a08601525060a08501516001600160a01b03811660c08601525060c08501516001600160a01b03811660e08601525060e085015161010061304d818701836001600160a01b03169052565b8601516101208681019190915286015161014080870191909152860151905061016061307c8187018315159052565b86015180151583870152905061169c565b80820281158282048414176105bc576105bc612ca9565b6000826130da577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000602082840312156130f157600080fd5b5051919050565b60006020828403121561310a57600080fd5b815167ffffffffffffffff81111561312157600080fd5b8201601f8101841361313257600080fd5b8051613140612827826127e0565b81815285602083850101111561315557600080fd5b613166826020830160208601612ee4565b95945050505050565b60006020828403121561318157600080fd5b81516112f38161287a56fea26469706673582212202ca3462270fabca20e393dc0a4f5e9cda6ff598ad6bcdf992dfc0b2006a9cc1c64736f6c63430008110033
Deployed Bytecode
0x60806040526004361061003f5760003560e01c80632bd19fde14610044578063647eb57e14610066578063af58398514610079578063dc7ffff7146100ba575b600080fd5b34801561005057600080fd5b5061006461005f36600461266a565b6100cd565b005b6100646100743660046129a1565b61028e565b34801561008557600080fd5b50610099610094366004612a35565b610530565b60408051825115158152602092830151928101929092520160405180910390f35b6100646100c8366004612a5f565b6105c2565b6100d5610829565b7f54b34910d6d88e05cfc79d100db458238c94af5eb402b5d31b86d5054a10cba683861415806101055750838214155b1561013c576040517fd4e105db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b67ffffffffffffffff81168711156102435783838267ffffffffffffffff1681811061016d5761016d612aed565b9050604002018260000160008a8a8567ffffffffffffffff1681811061019557610195612aed565b90506020020160208101906101aa9190612b1c565b6001600160a01b03166001600160a01b03168152602001908152602001600020600088888567ffffffffffffffff168181106101e8576101e8612aed565b90506020020160208101906101fd9190612b37565b7fffffffff0000000000000000000000000000000000000000000000000000000016815260208101919091526040016000206102398282612b52565b505060010161013f565b507f8621ad378521883daa8108c9f45a36f29f3afaf85b0a464009b9b206aa7126ec87878787878760405161027d96959493929190612be7565b60405180910390a150505050505050565b7fd46a770fdb1d7fb038d450c1aee8cd72c3e44da0efcb53d27f7ff78dac24948280547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01610309576040517f29f745a700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001815560e0830151600061031e3447612cd8565b9050846103368160c001516001600160a01b03161590565b1561036d576040517f1e4ec46b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8061010001516000036103ac576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b46816101200151036103ea576040517f4ac09ad300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b846104016103fb6020830183612b1c565b3b151590565b610437576040517f6eefed2000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8680610140015115610475576040517f50dc905c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b87806101600151156104b3576040517f50dc905c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104d089608001518a61010001518a604001358c60400151610891565b6101008a018190526104ee908a906104e9908b906108f9565b610bb0565b50479250600091505082821161050557600061050f565b61050f8383612cd8565b905080156105235761052360008583610cfd565b5050600090925550505050565b604080518082018252600080825260209182018190526001600160a01b03851681527f54b34910d6d88e05cfc79d100db458238c94af5eb402b5d31b86d5054a10cba682528281207fffffffff000000000000000000000000000000000000000000000000000000008516825282528290208251808401909352805460ff161515835260010154908201525b92915050565b7fd46a770fdb1d7fb038d450c1aee8cd72c3e44da0efcb53d27f7ff78dac24948280547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0161063d576040517f29f745a700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001815560e085015160006106523447612cd8565b905086806101400151610691576040517f50dc905c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b876106a78160c001516001600160a01b03161590565b156106de576040517f1e4ec46b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80610100015160000361071d576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b468161012001510361075b576040517f4ac09ad300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8561076c6103fb6020830183612b1c565b6107a2576040517f6eefed2000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b89516101008b01516107cd91906107b98b8d612ceb565b8d604001518e60e001518c60400135610d26565b6101008b018190526107e6908b906104e9908a906108f9565b50479150600090508282116107fc576000610806565b6108068383612cd8565b9050801561081a5761081a60008583610cfd565b50506000909255505050505050565b7fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c600401546001600160a01b0316331461088f576040517f277d76f800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b60008061089d83610e6b565b90506108a98482612dfc565b3410156108e2576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6108ef8686838787611019565b9695505050505050565b60408051608081018252600080825260208201819052918101829052606080820152907f54b34910d6d88e05cfc79d100db458238c94af5eb402b5d31b86d5054a10cba69050600081816109506020880188612b1c565b6001600160a01b0316815260208101919091526040016000908120906109796060880188612e0f565b61098891600491600091612e74565b61099191612e9e565b7fffffffff0000000000000000000000000000000000000000000000000000000016815260208082019290925260409081016000208151808301909252805460ff161580158352600190910154928201929092529150610b7657602081015115610ad857604080516080810190915280610a0e6020880188612b1c565b6001600160a01b03168152602001866020016020810190610a2f9190612b1c565b6001600160a01b03168152604080880135602083015201610a536060880188612e0f565b6020850151610a66929091600091612e74565b60408051602081018a90520160408051601f19818403018152919052610a8f60608b018b612e0f565b602080890151610a9e91612dfc565b610aa9928290612e74565b604051602001610abd959493929190612f08565b604051602081830303815290604052815250925050506105bc565b604080516080810190915280610af16020880188612b1c565b6001600160a01b03168152602001866020016020810190610b129190612b1c565b6001600160a01b03168152604080880135602083015201610b366060880188612e0f565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250505091525092506105bc915050565b6040517fbe24598300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505092915050565b6000610bc783608001516001600160a01b03161590565b905060008115610bdd5750610100830151610bf5565b610bf58460800151846020015186610100015161118d565b60008084600001516001600160a01b0316856040015184610c169190612dfc565b8660600151604051610c289190612f3c565b60006040518083038185875af1925050503d8060008114610c65576040519150601f19603f3d011682016040523d82523d6000602084013e610c6a565b606091505b509150915081610cbe576000610c7f826112b1565b9050806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cb59190612f84565b60405180910390fd5b7ff834e948c18ff30cc76e65c4bb09ce6f070fcea13e3cb45413d9a66686584b9486604051610ced9190612f97565b60405180910390a1505050505050565b6001600160a01b03831615610d1c57610d178383836112fa565b505050565b610d17828261140f565b8351600090808203610d64576040517f0503c3ed00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600086610d72600184612cd8565b81518110610d8257610d82612aed565b60200260200101516060015190506000610d9b8261151f565b90506001600160a01b038216610db857610db53482612cd8565b90505b6000610dc3896115bd565b9050610dcf89896116a6565b604080516060810182528d81526001600160a01b038a166020820152908101889052909950610dff818b8461176f565b600083610e0b8661151f565b610e159190612cd8565b90508b811015610e5b576040517f275c273c000000000000000000000000000000000000000000000000000000008152600481018d905260248101829052604401610cb5565b9c9b505050505050505050505050565b60008080807fc6c3600a890b88a8f7ea8576d6b77243f564078524498bdcc408f2f4884b7df66001600160a01b03861660009081526020828152604091829020825160a081018452905460ff81161580158352610100820463ffffffff908116948401949094526501000000000082048416948301949094526901000000000000000000810490921660608201526d01000000000000000000000000009091046fffffffffffffffffffffffffffffffff166080820152919250610f985760808101516fffffffffffffffffffffffffffffffff1693508315610f9357620f4240816060015163ffffffff1685610f62919061308d565b610f6c91906130a4565b92506000610f7a8486612cd8565b1115610f9357610f9386610f8e8587612cd8565b61140f565b610fa3565b816004015493508392505b8215610fc1576005820154610fc1906001600160a01b03168461140f565b6001600160a01b0386167f74d5029b0a85dd485bf2414b0920760500d9535db170f72375f811087a6d207384610ff78188612cd8565b6040805192835260208301919091520160405180910390a25091949350505050565b60006001600160a01b03861661107c57826110348587612dfc565b61103e9190612dfc565b341015611077576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611182565b846000036110b6576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000906001600160a01b038816906370a0823190602401602060405180830381865afa158015611116573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061113a91906130df565b905085811015611180576040517fcf4791810000000000000000000000000000000000000000000000000000000081526004810187905260248101829052604401610cb5565b505b6108ef828688611b49565b6001600160a01b0383166111a057505050565b6001600160a01b0382166111e0576040517f63ba9bff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0383811660248301526000919085169063dd62ed3e90604401602060405180830381865afa158015611249573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061126d91906130df565b9050818110156112ab576112ab84846112a6847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff612cd8565b611cce565b50505050565b60606044825110156112c1575090565b60006112dd60048085516112d59190612cd8565b859190611e12565b9050808060200190518101906112f391906130f8565b9392505050565b6001600160a01b03831661133a576040517fd1bebf0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000906001600160a01b038516906370a0823190602401602060405180830381865afa15801561139a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113be91906130df565b905080821115611404576040517fcf4791810000000000000000000000000000000000000000000000000000000081526004810183905260248101829052604401610cb5565b6112ab848484611f0e565b6001600160a01b03821661144f576040517f21f7434500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b47811115611492576040517fcf47918100000000000000000000000000000000000000000000000000000000815260048101829052476024820152604401610cb5565b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146114df576040519150601f19603f3d011682016040523d82523d6000602084013e6114e4565b606091505b5050905080610d17576040517f5a04673700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006001600160a01b038216156115b6576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa15801561158d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115b191906130df565b6105bc565b4792915050565b805160609060008167ffffffffffffffff8111156115dd576115dd612733565b604051908082528060200260200182016040528015611606578160200160208202803683370190505b5090506000805b8381101561169c5785818151811061162757611627612aed565b602002602001015160600151915061163e8261151f565b83828151811061165057611650612aed565b60209081029190910101526001600160a01b038216611694573483828151811061167c5761167c612aed565b602002602001018181516116909190612cd8565b9052505b60010161160d565b5090949350505050565b606060006116b383610e6b565b9050803410156116ef576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b845181101561176657600085828151811061170f5761170f612aed565b602002602001015190508060c001511561173f576117398160400151826080015185600089611019565b60808201525b8086838151811061175257611752612aed565b6020908102919091010152506001016116f2565b50929392505050565b81836020015182856040015160008451905080600114611a0b57600085611797600184612cd8565b815181106117a7576117a7612aed565b60200260200101516060015190506000808951905060005b818110156119415760008b82815181106117db576117db612aed565b602002602001015190506117fa81604001516001600160a01b03161590565b80611845575061184581602001516001600160a01b031660009081527fec46400aeca82eb9145f7fc14dfaa75470e03fc835f1928a29957f5b1b60a5da602052604090205460ff1690565b8015611889575080516001600160a01b031660009081527fec46400aeca82eb9145f7fc14dfaa75470e03fc835f1928a29957f5b1b60a5da602052604090205460ff165b80156118f657506118f66118a08260a00151611f57565b7fffffffff000000000000000000000000000000000000000000000000000000001660009081527fec46400aeca82eb9145f7fc14dfaa75470e03fc835f1928a29957f5b1b60a5db602052604090205460ff1690565b61192c576040517f9453980400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8c516119389082611f72565b506001016117bf565b505060005b611951600185612cd8565b811015611a0357600088828151811061196c5761196c612aed565b6020026020010151606001519050836001600160a01b0316816001600160a01b0316146119fa578682815181106119a5576119a5612aed565b60200260200101516119b68261151f565b6119c09190612cd8565b925060006001600160a01b038216156119da5760006119dc565b865b905083156119f8576119f8828a6119f38488612cd8565b610cfd565b505b50600101611946565b505050611b3f565b865160005b81811015611b3c576000898281518110611a2c57611a2c612aed565b60200260200101519050611a4b81604001516001600160a01b03161590565b80611a965750611a9681602001516001600160a01b031660009081527fec46400aeca82eb9145f7fc14dfaa75470e03fc835f1928a29957f5b1b60a5da602052604090205460ff1690565b8015611ada575080516001600160a01b031660009081527fec46400aeca82eb9145f7fc14dfaa75470e03fc835f1928a29957f5b1b60a5da602052604090205460ff165b8015611af15750611af16118a08260a00151611f57565b611b27576040517f9453980400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8a51611b339082611f72565b50600101611a10565b50505b5050505050505050565b6001600160a01b03831660009081527fc6c3600a890b88a8f7ea8576d6b77243f564078524498bdcc408f2f4884b7df660208181526040808420815160a081018352905460ff811615158252610100810463ffffffff908116948301949094526501000000000081048416928201929092526901000000000000000000820490921660608301526d010000000000000000000000000090046fffffffffffffffffffffffffffffffff1660808201528280611c058488856121ce565b90925090506001600160a01b03881615611c3a576000611c258284612cd8565b1115611c3a57611c3a86896119f38486612cd8565b8015611c5a576005840154611c5a9087906001600160a01b031683610cfd565b6001600160a01b0388167f25471ec9f39b4ceb20d58f63c37f9c738011f0babcc4b6af69bdd82984ca5f8e82611c908186612cd8565b6040805192835260208301919091526001600160a01b038a169082015260600160405180910390a2611cc28288612cd8565b98975050505050505050565b6040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa158015611d38573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d5c91906130df565b611d669190612dfc565b6040516001600160a01b0385166024820152604481018290529091506112ab9085907f095ea7b300000000000000000000000000000000000000000000000000000000906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915261220f565b606081611e2081601f612dfc565b1015611e58576040517f47aaf07a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611e628284612dfc565b84511015611e9c576040517f3b99b53d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606082158015611ebb5760405191506000825260208201604052611f05565b6040519150601f8416801560200281840101858101878315602002848b0101015b81831015611ef4578051835260209283019201611edc565b5050858452601f01601f1916604052505b50949350505050565b6040516001600160a01b038316602482015260448101829052610d179084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611dae565b60008151600003611f6a57506000919050565b506020015190565b80513b611fab576040517f6eefed2000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60808101516000819003611feb576040517fe46e079c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061200283604001516001600160a01b03161590565b61200d576000612013565b82608001515b90506000612024846040015161151f565b90506000612035856060015161151f565b9050826000036120565761205685604001518660200151876080015161118d565b84608001518210156120a45760808501516040517fcf479181000000000000000000000000000000000000000000000000000000008152600481019190915260248101839052604401610cb5565b60008086600001516001600160a01b0316858860a001516040516120c89190612f3c565b60006040518083038185875af1925050503d8060008114612105576040519150601f19603f3d011682016040523d82523d6000602084013e61210a565b606091505b50915091508161211f576000610c7f826112b1565b600061212e886060015161151f565b90507f7bfdfdb5e3a3776976e53cb0607060f54c5312701c8cba1155cc4d5394440b388989600001518a604001518b606001518c60800151898711612173578661217d565b61217d8a88612cd8565b604080519687526001600160a01b0395861660208801529385169386019390935292166060840152608083019190915260a08201524260c082015260e00160405180910390a1505050505050505050565b6000808260000151156121ef576121e5848461230e565b9092509050612207565b612201848660030154620f4240612360565b91508190505b935093915050565b6000612264826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166124309092919063ffffffff16565b805190915015610d175780806020019051810190612282919061316f565b610d17576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610cb5565b6000806000836020015163ffffffff1611156123595761233c84846020015163ffffffff16620f4240612360565b915061235682846040015163ffffffff16620f4240612360565b90505b9250929050565b600080807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff858709858702925082811083820303915050806000036123b757600084116123ac57600080fd5b5082900490506112f3565b8084116123c357600080fd5b6000848688096000868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150509392505050565b606061243f8484600085612447565b949350505050565b6060824710156124d9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610cb5565b600080866001600160a01b031685876040516124f59190612f3c565b60006040518083038185875af1925050503d8060008114612532576040519150601f19603f3d011682016040523d82523d6000602084013e612537565b606091505b509150915061254887838387612553565b979650505050505050565b606083156125dc5782516000036125d5576001600160a01b0385163b6125d5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610cb5565b508161243f565b61243f83838151156125f15781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cb59190612f84565b60008083601f84011261263757600080fd5b50813567ffffffffffffffff81111561264f57600080fd5b6020830191508360208260051b850101111561235957600080fd5b6000806000806000806060878903121561268357600080fd5b863567ffffffffffffffff8082111561269b57600080fd5b6126a78a838b01612625565b909850965060208901359150808211156126c057600080fd5b6126cc8a838b01612625565b909650945060408901359150808211156126e557600080fd5b818901915089601f8301126126f957600080fd5b81358181111561270857600080fd5b8a60208260061b850101111561271d57600080fd5b6020830194508093505050509295509295509295565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610180810167ffffffffffffffff8111828210171561278657612786612733565b60405290565b60405160e0810167ffffffffffffffff8111828210171561278657612786612733565b604051601f8201601f1916810167ffffffffffffffff811182821017156127d8576127d8612733565b604052919050565b600067ffffffffffffffff8211156127fa576127fa612733565b50601f01601f191660200190565b600082601f83011261281957600080fd5b813561282c612827826127e0565b6127af565b81815284602083860101111561284157600080fd5b816020850160208301376000918101602001919091529392505050565b80356001600160a01b038116811461287557600080fd5b919050565b801515811461288857600080fd5b50565b80356128758161287a565b600061018082840312156128a957600080fd5b6128b1612762565b905081358152602082013567ffffffffffffffff8111156128d157600080fd5b6128dd84828501612808565b6020830152506128ef6040830161285e565b60408201526129006060830161285e565b60608201526129116080830161285e565b608082015261292260a0830161285e565b60a082015261293360c0830161285e565b60c082015261294460e0830161285e565b60e08201526101008281013590820152610120808301359082015261014061296d81840161288b565b9082015261016061297f83820161288b565b9082015292915050565b60006080828403121561299b57600080fd5b50919050565b600080604083850312156129b457600080fd5b823567ffffffffffffffff808211156129cc57600080fd5b6129d886838701612896565b935060208501359150808211156129ee57600080fd5b506129fb85828601612989565b9150509250929050565b80357fffffffff000000000000000000000000000000000000000000000000000000008116811461287557600080fd5b60008060408385031215612a4857600080fd5b612a518361285e565b915061235660208401612a05565b60008060008060608587031215612a7557600080fd5b843567ffffffffffffffff80821115612a8d57600080fd5b612a9988838901612896565b95506020870135915080821115612aaf57600080fd5b612abb88838901612625565b90955093506040870135915080821115612ad457600080fd5b50612ae187828801612989565b91505092959194509250565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215612b2e57600080fd5b6112f38261285e565b600060208284031215612b4957600080fd5b6112f382612a05565b8135612b5d8161287a565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082541660ff82151516811783555050602082013560018201555050565b8183526000602080850194508260005b85811015612bdc578135612bbe8161287a565b15158752818301358388015260409687019690910190600101612bab565b509495945050505050565b6060808252810186905260008760808301825b89811015612c28576001600160a01b03612c138461285e565b16825260209283019290910190600101612bfa565b5083810360208581019190915287825291508790820160005b88811015612c86577fffffffff00000000000000000000000000000000000000000000000000000000612c7384612a05565b1682529183019190830190600101612c41565b508481036040860152612c9a818789612b9b565b9b9a5050505050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156105bc576105bc612ca9565b600067ffffffffffffffff80841115612d0657612d06612733565b8360051b6020612d178183016127af565b868152918501918181019036841115612d2f57600080fd5b865b84811015612df057803586811115612d495760008081fd5b880160e0368290031215612d5d5760008081fd5b612d6561278c565b612d6e8261285e565b8152612d7b86830161285e565b868201526040612d8c81840161285e565b908201526060612d9d83820161285e565b908201526080828101359082015260a08083013589811115612dbf5760008081fd5b612dcb36828601612808565b82840152505060c0612dde81840161288b565b90820152845250918301918301612d31565b50979650505050505050565b808201808211156105bc576105bc612ca9565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612e4457600080fd5b83018035915067ffffffffffffffff821115612e5f57600080fd5b60200191503681900382131561235957600080fd5b60008085851115612e8457600080fd5b83861115612e9157600080fd5b5050820193919092039150565b7fffffffff000000000000000000000000000000000000000000000000000000008135818116916004851015610ba85760049490940360031b84901b1690921692915050565b60005b83811015612eff578181015183820152602001612ee7565b50506000910152565b848682376000858201600081528551612f25818360208a01612ee4565b018385823760009301928352509095945050505050565b60008251612f4e818460208701612ee4565b9190910192915050565b60008151808452612f70816020860160208601612ee4565b601f01601f19169290920160200192915050565b6020815260006112f36020830184612f58565b602081528151602082015260006020830151610180806040850152612fc06101a0850183612f58565b91506040850151612fdc60608601826001600160a01b03169052565b5060608501516001600160a01b03811660808601525060808501516001600160a01b03811660a08601525060a08501516001600160a01b03811660c08601525060c08501516001600160a01b03811660e08601525060e085015161010061304d818701836001600160a01b03169052565b8601516101208681019190915286015161014080870191909152860151905061016061307c8187018315159052565b86015180151583870152905061169c565b80820281158282048414176105bc576105bc612ca9565b6000826130da577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000602082840312156130f157600080fd5b5051919050565b60006020828403121561310a57600080fd5b815167ffffffffffffffff81111561312157600080fd5b8201601f8101841361313257600080fd5b8051613140612827826127e0565b81815285602083850101111561315557600080fd5b613166826020830160208601612ee4565b95945050505050565b60006020828403121561318157600080fd5b81516112f38161287a56fea26469706673582212202ca3462270fabca20e393dc0a4f5e9cda6ff598ad6bcdf992dfc0b2006a9cc1c64736f6c63430008110033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
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.