@etherspot/contracts
Version:
Etherspot Solidity contracts
97 lines • 88.4 kB
JSON
{
"language": "Solidity",
"sources": {
"src/bridges/facets/StargateFacet.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.4;\n\nimport {IStargateRouter} from \"../interfaces/IStargateRouter.sol\";\nimport {IStargateReceiver} from \"../interfaces/IStargateReceiver.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {SafeERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport {ReentrancyGuard} from \"../../common/helpers/DiamondReentrancyGuard.sol\";\nimport {CannotBridgeToSameNetwork, InvalidAmount, InvalidConfig} from \"../errors/GenericErrors.sol\";\nimport {SenderNotStargateRouter, NoMsgValueForCrossChainMessage, StargateRouterAddressZero, InvalidSourcePoolId, InvalidDestinationPoolId} from \"../errors/StargateErrors.sol\";\nimport {LibDiamond} from \"../libs/LibDiamond.sol\";\n\n/// @title StargateFacet\n/// @author Luke Wickens <luke@pillarproject.io>\n/// @notice Stargate/LayerZero intergration for bridging tokens\n\ncontract StargateFacet is IStargateReceiver, ReentrancyGuard {\n using SafeERC20 for IERC20;\n\n //////////////////////////////////////////////////////////////\n /////////////////////////// Events ///////////////////////////\n //////////////////////////////////////////////////////////////\n event SGInitialized(address stargate, uint16 chainId);\n event SGTransferStarted(\n string bridgeUsed,\n address fromToken,\n address toToken,\n address from,\n address to,\n uint256 amount,\n uint16 chainIdTo\n );\n event SGReceivedOnDestination(address token, uint256 amount);\n event SGUpdatedRouter(address newAddress);\n event SGUpdatedSlippageTolerance(uint256 newSlippage);\n event SGAddedPool(uint16 chainId, address token, uint16 poolId);\n\n //////////////////////////////////////////////////////////////\n ////////////////////////// Storage ///////////////////////////\n //////////////////////////////////////////////////////////////\n\n bytes32 internal constant NAMESPACE =\n keccak256(\"io.etherspot.facets.stargate\");\n struct Storage {\n address stargateRouter;\n uint16 chainId;\n uint256 dstGas;\n uint256 slippage;\n mapping(uint16 => mapping(address => uint16)) poolIds;\n }\n\n //////////////////////////////////////////////////////////////\n ////////////////////////// Structs ///////////////////////////\n //////////////////////////////////////////////////////////////\n\n struct StargateData {\n uint256 qty;\n address fromToken;\n address toToken;\n uint16 dstChainId;\n address to;\n address destStargateComposed;\n }\n\n /// @notice initializes state variables for the Stargate facet\n /// @param _stargateRouter - address of the Stargate router contract\n /// @param _chainId - current chain id\n function sgInitialize(address _stargateRouter, uint16 _chainId) external {\n if (_stargateRouter == address(0)) revert InvalidConfig();\n LibDiamond.enforceIsContractOwner();\n Storage storage s = getStorage();\n s.stargateRouter = address(_stargateRouter);\n s.chainId = _chainId;\n s.slippage = 50; // equates to 0.5%\n // Adding pre-existing pools => USDC: 1, USDT: 2, BUSD: 5\n sgAddPool(1, 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48, 1);\n sgAddPool(1, 0xdAC17F958D2ee523a2206206994597C13D831ec7, 2);\n sgAddPool(2, 0x55d398326f99059fF775485246999027B3197955, 2);\n sgAddPool(2, 0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56, 5);\n sgAddPool(6, 0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E, 1);\n sgAddPool(6, 0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7, 2);\n sgAddPool(9, 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174, 1);\n sgAddPool(9, 0xc2132D05D31c914a87C6611C10748AEb04B58e8F, 2);\n sgAddPool(10, 0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8, 1);\n sgAddPool(10, 0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9, 2);\n sgAddPool(11, 0x7F5c764cBc14f9669B88837ca1490cCa17c31607, 1);\n sgAddPool(12, 0x04068DA6C83AFCFA0e13ba15A6696662335D5B75, 1);\n emit SGInitialized(_stargateRouter, _chainId);\n }\n\n /// @notice initializes state variables for the stargate facet\n /// @param _sgData - struct containing information required to execute bridge\n function sgBridgeTokens(StargateData memory _sgData)\n external\n payable\n nonReentrant\n {\n // if (msg.value <= 0) revert NoMsgValueForCrossChainMessage();\n if (_sgData.qty <= 0) revert InvalidAmount();\n if (\n _sgData.fromToken == address(0) ||\n _sgData.toToken == address(0) ||\n _sgData.to == address(0) ||\n _sgData.destStargateComposed == address(0)\n ) revert InvalidConfig();\n\n // access storage\n Storage storage s = getStorage();\n\n // check pool ids are valid\n uint16 srcPoolId = sgRetrievePoolId(s.chainId, _sgData.fromToken);\n if (srcPoolId == 0) revert InvalidSourcePoolId();\n uint16 dstPoolId = sgRetrievePoolId(\n _sgData.dstChainId,\n _sgData.toToken\n );\n\n // calculate cross chain fees\n uint256 fees = sgCalculateFees(\n _sgData.dstChainId,\n _sgData.to,\n s.stargateRouter\n );\n\n // calculate slippage\n uint256 minAmountOut = sgMinAmountOut(_sgData.qty);\n\n // encode sgReceive implemented\n bytes memory destination = abi.encodePacked(\n _sgData.destStargateComposed\n );\n\n // encode payload data to send to destination contract, which it will handle with sgReceive()\n bytes memory payload = abi.encode(_sgData.to);\n\n // this contract calls stargate swap()\n IERC20(_sgData.fromToken).safeTransferFrom(\n msg.sender,\n address(this),\n _sgData.qty\n );\n\n IERC20(_sgData.fromToken).safeApprove(\n address(s.stargateRouter),\n _sgData.qty\n );\n\n // Stargate's Router.swap() function sends the tokens to the destination chain.\n IStargateRouter(s.stargateRouter).swap{value: fees}(\n _sgData.dstChainId, // the destination chain id\n srcPoolId, // the source Stargate poolId\n dstPoolId, // the destination Stargate poolId\n payable(msg.sender), // refund adddress. if msg.sender pays too much gas, return extra eth\n _sgData.qty, // total tokens to send to destination chain\n minAmountOut, // min amount allowed out\n IStargateRouter.lzTxObj(200000, 0, \"0x\"), // default lzTxObj\n destination, // destination address, the sgReceive() implementer\n payload // bytes payload\n );\n\n emit SGTransferStarted(\n \"stargate\",\n _sgData.fromToken,\n _sgData.toToken,\n msg.sender,\n _sgData.to,\n _sgData.qty,\n _sgData.dstChainId\n );\n }\n\n /// @notice required to receive tokens on destination chain\n /// @param _chainId The remote chainId sending the tokens\n /// @param _srcAddress The remote Bridge address\n /// @param _nonce The message ordering nonce\n /// @param _token The token contract on the local chain\n /// @param amountLD The qty of local _token contract tokens\n /// @param _payload The bytes containing the toAddress\n function sgReceive(\n uint16 _chainId,\n bytes memory _srcAddress,\n uint256 _nonce,\n address _token,\n uint256 amountLD,\n bytes memory _payload\n ) external override {\n Storage storage s = getStorage();\n if (msg.sender != address(s.stargateRouter))\n revert SenderNotStargateRouter();\n\n address _toAddr = abi.decode(_payload, (address));\n IERC20(_token).transfer(_toAddr, amountLD);\n emit SGReceivedOnDestination(_token, amountLD);\n }\n\n /// @notice Calculates cross chain fee\n /// @param _destChain Destination chain id\n /// @param _receiver Receiver on destination chain\n /// @param _router Address of stargate router\n function sgCalculateFees(\n uint16 _destChain,\n address _receiver,\n address _router\n ) public view returns (uint256) {\n (uint256 nativeFee, ) = IStargateRouter(_router).quoteLayerZeroFee(\n _destChain, // destination chain id\n 1, // 1 = swap\n abi.encodePacked(_receiver), // receiver on destination chain\n \"0x\", // payload, using abi.encode()\n IStargateRouter.lzTxObj(200000, 0, \"0x\")\n );\n return nativeFee;\n }\n\n /// @notice Calculates the minimum amount out using slippage tolerance\n /// @param _amount Transfer amount\n function sgMinAmountOut(uint256 _amount) public view returns (uint256) {\n Storage storage s = getStorage();\n // equates to 0.5% slippage\n return (_amount * (10000 - s.slippage)) / (10000);\n }\n\n /// @notice Updates stargate router address for deployed chain\n /// @param _newAddress Address of the new router\n function sgUpdateRouter(address _newAddress) external {\n LibDiamond.enforceIsContractOwner();\n if (_newAddress == address(0)) revert StargateRouterAddressZero();\n Storage storage s = getStorage();\n s.stargateRouter = address(_newAddress);\n emit SGUpdatedRouter(_newAddress);\n }\n\n /// @notice Updates slippage tolerance amount\n /// @param _newSlippage New slippage amount\n function sgUpdateSlippageTolerance(uint256 _newSlippage) external {\n LibDiamond.enforceIsContractOwner();\n Storage storage s = getStorage();\n s.slippage = _newSlippage;\n emit SGUpdatedSlippageTolerance(_newSlippage);\n }\n\n /// @notice Adds a new pool for a specific token and chain\n /// @param _chainId Chain id of new pool (NOT actual chain id - check stargate pool ids docs)\n /// @param _token Address of token\n /// @param _poolId Pool id (check stargate pool ids docs)\n function sgAddPool(\n uint16 _chainId,\n address _token,\n uint16 _poolId\n ) public {\n LibDiamond.enforceIsContractOwner();\n Storage storage s = getStorage();\n s.poolIds[_chainId][_token] = _poolId;\n emit SGAddedPool(_chainId, _token, _poolId);\n }\n\n /// @notice Checks for a valid token pool on specific chain\n /// @param _chainId Chain id of new pool (NOT actual chain id - check stargate pool ids docs)\n /// @param _token Address of token\n /// @param _poolId Pool id (check stargate pool ids docs)\n function sgCheckPoolId(\n uint16 _chainId,\n address _token,\n uint16 _poolId\n ) external view returns (bool) {\n Storage storage s = getStorage();\n return s.poolIds[_chainId][_token] == _poolId ? true : false;\n }\n\n /// @notice Retrieves pool id for a token on a specified chain\n /// @param _chainId Chain id of new pool (NOT actual chain id - check stargate pool ids docs)\n /// @param _token Address of token\n function sgRetrievePoolId(uint16 _chainId, address _token)\n public\n view\n returns (uint16)\n {\n Storage storage s = getStorage();\n return s.poolIds[_chainId][_token];\n }\n\n //////////////////////////////////////////////////////////////\n ////////////////////// Private Functions /////////////////////\n //////////////////////////////////////////////////////////////\n\n /// @dev fetch local storage\n function getStorage() private pure returns (Storage storage s) {\n bytes32 namespace = NAMESPACE;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n s.slot := namespace\n }\n }\n}\n"
},
"src/bridges/interfaces/IStargateRouter.sol": {
"content": "// SPDX-License-Identifier:MIT\n\npragma solidity 0.8.4;\npragma abicoder v2;\n\ninterface IStargateRouter {\n struct lzTxObj {\n uint256 dstGasForCall;\n uint256 dstNativeAmount;\n bytes dstNativeAddr;\n }\n\n function addLiquidity(\n uint256 _poolId,\n uint256 _amountLD,\n address _to\n ) external;\n\n function swap(\n uint16 _dstChainId,\n uint256 _srcPoolId,\n uint256 _dstPoolId,\n address payable _refundAddress,\n uint256 _amountLD,\n uint256 _minAmountLD,\n lzTxObj memory _lzTxParams,\n bytes calldata _to,\n bytes calldata _payload\n ) external payable;\n\n function redeemRemote(\n uint16 _dstChainId,\n uint256 _srcPoolId,\n uint256 _dstPoolId,\n address payable _refundAddress,\n uint256 _amountLP,\n uint256 _minAmountLD,\n bytes calldata _to,\n lzTxObj memory _lzTxParams\n ) external payable;\n\n function instantRedeemLocal(\n uint16 _srcPoolId,\n uint256 _amountLP,\n address _to\n ) external returns (uint256);\n\n function redeemLocal(\n uint16 _dstChainId,\n uint256 _srcPoolId,\n uint256 _dstPoolId,\n address payable _refundAddress,\n uint256 _amountLP,\n bytes calldata _to,\n lzTxObj memory _lzTxParams\n ) external payable;\n\n function sendCredits(\n uint16 _dstChainId,\n uint256 _srcPoolId,\n uint256 _dstPoolId,\n address payable _refundAddress\n ) external payable;\n\n function quoteLayerZeroFee(\n uint16 _dstChainId,\n uint8 _functionType,\n bytes calldata _toAddress,\n bytes calldata _transferAndCallPayload,\n lzTxObj memory _lzTxParams\n ) external view returns (uint256, uint256);\n}\n"
},
"src/bridges/interfaces/IStargateReceiver.sol": {
"content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.4;\n\ninterface IStargateReceiver {\n function sgReceive(\n uint16 _srcChainId, // the remote chainId sending the tokens\n bytes memory _srcAddress, // the remote Bridge address\n uint256 _nonce,\n address _token, // the token contract on the local chain\n uint256 amountLD, // the qty of local _token contract tokens\n bytes memory payload\n ) external;\n}\n"
},
"@openzeppelin/contracts/token/ERC20/IERC20.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n}\n"
},
"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n"
},
"src/common/helpers/DiamondReentrancyGuard.sol": {
"content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.4;\n\n/// @title Reentrancy Guard\n/// @notice Abstract contract to provide protection against reentrancy\nabstract contract ReentrancyGuard {\n //////////////////////////////////////////////////////////////\n ////////////////////////// Storage ///////////////////////////\n //////////////////////////////////////////////////////////////\n\n bytes32 private constant NAMESPACE =\n keccak256(\"io.etherspot.helpers.reentrancyguard\");\n\n //////////////////////////////////////////////////////////////\n ////////////////////////// Structs ///////////////////////////\n //////////////////////////////////////////////////////////////\n\n struct ReentrancyStorage {\n uint256 status;\n }\n\n //////////////////////////////////////////////////////////////\n ////////////////////////// Errors ////////////////////////////\n //////////////////////////////////////////////////////////////\n\n error ReentrancyError();\n\n //////////////////////////////////////////////////////////////\n ///////////////////////// Constants //////////////////////////\n //////////////////////////////////////////////////////////////\n\n uint256 private constant _NOT_ENTERED = 0;\n uint256 private constant _ENTERED = 1;\n\n //////////////////////////////////////////////////////////////\n ///////////////////////// Modifiers ///////////////////////////\n //////////////////////////////////////////////////////////////\n\n modifier nonReentrant() {\n ReentrancyStorage storage s = reentrancyStorage();\n if (s.status == _ENTERED) revert ReentrancyError();\n s.status = _ENTERED;\n _;\n s.status = _NOT_ENTERED;\n }\n\n //////////////////////////////////////////////////////////////\n ////////////////////// Private Functions /////////////////////\n //////////////////////////////////////////////////////////////\n\n /// @dev fetch local storage\n function reentrancyStorage()\n private\n pure\n returns (ReentrancyStorage storage data)\n {\n bytes32 position = NAMESPACE;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n data.slot := position\n }\n }\n}\n"
},
"src/bridges/errors/GenericErrors.sol": {
"content": "// SPDX-License-Identifier: MIT\n// solhint-disable-next-line\npragma solidity 0.8.4;\n\nerror InvalidAmount();\nerror TokenAddressIsZero();\nerror CannotBridgeToSameNetwork();\nerror ZeroPostSwapBalance();\nerror InvalidBridgeConfigLength();\nerror NoSwapDataProvided();\nerror NativeValueWithERC();\nerror ContractCallNotAllowed();\nerror NullAddrIsNotAValidSpender();\nerror NullAddrIsNotAnERC20Token();\nerror NoTransferToNullAddress();\nerror NativeAssetTransferFailed();\nerror InvalidContract();\nerror InvalidConfig();\nerror ZeroAddressProvided();\n"
},
"src/bridges/errors/StargateErrors.sol": {
"content": "// SPDX-License-Identifier: MIT\n// solhint-disable-next-line\npragma solidity 0.8.4;\n\nerror SenderNotStargateRouter();\nerror NoMsgValueForCrossChainMessage();\nerror StargateRouterAddressZero();\nerror InvalidSourcePoolId();\nerror InvalidDestinationPoolId();\n"
},
"src/bridges/libs/LibDiamond.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.4 <0.9.0;\n\nimport {IDiamondCut} from \"../interfaces/IDiamondCut.sol\";\n\nlibrary LibDiamond {\n bytes32 internal constant DIAMOND_STORAGE_POSITION =\n keccak256(\"diamond.standard.diamond.storage\");\n\n struct FacetAddressAndPosition {\n address facetAddress;\n uint96 functionSelectorPosition; // position in facetFunctionSelectors.functionSelectors array\n }\n\n struct FacetFunctionSelectors {\n bytes4[] functionSelectors;\n uint256 facetAddressPosition; // position of facetAddress in facetAddresses array\n }\n\n struct DiamondStorage {\n // maps function selector to the facet address and\n // the position of the selector in the facetFunctionSelectors.selectors array\n mapping(bytes4 => FacetAddressAndPosition) selectorToFacetAndPosition;\n // maps facet addresses to function selectors\n mapping(address => FacetFunctionSelectors) facetFunctionSelectors;\n // facet addresses\n address[] facetAddresses;\n // Used to query if a contract implements an interface.\n // Used to implement ERC-165.\n mapping(bytes4 => bool) supportedInterfaces;\n // owner of the contract\n address contractOwner;\n }\n\n function diamondStorage()\n internal\n pure\n returns (DiamondStorage storage ds)\n {\n bytes32 position = DIAMOND_STORAGE_POSITION;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n ds.slot := position\n }\n }\n\n event OwnershipTransferred(\n address indexed previousOwner,\n address indexed newOwner\n );\n\n function setContractOwner(address _newOwner) internal {\n DiamondStorage storage ds = diamondStorage();\n address previousOwner = ds.contractOwner;\n ds.contractOwner = _newOwner;\n emit OwnershipTransferred(previousOwner, _newOwner);\n }\n\n function contractOwner() internal view returns (address contractOwner_) {\n contractOwner_ = diamondStorage().contractOwner;\n }\n\n function enforceIsContractOwner() internal view {\n require(\n msg.sender == diamondStorage().contractOwner,\n \"LibDiamond: Must be contract owner\"\n );\n }\n\n event DiamondCut(\n IDiamondCut.FacetCut[] _diamondCut,\n address _init,\n bytes _calldata\n );\n\n // Internal function version of diamondCut\n function diamondCut(\n IDiamondCut.FacetCut[] memory _diamondCut,\n address _init,\n bytes memory _calldata\n ) internal {\n for (\n uint256 facetIndex;\n facetIndex < _diamondCut.length;\n facetIndex++\n ) {\n IDiamondCut.FacetCutAction action = _diamondCut[facetIndex].action;\n if (action == IDiamondCut.FacetCutAction.Add) {\n addFunctions(\n _diamondCut[facetIndex].facetAddress,\n _diamondCut[facetIndex].functionSelectors\n );\n } else if (action == IDiamondCut.FacetCutAction.Replace) {\n replaceFunctions(\n _diamondCut[facetIndex].facetAddress,\n _diamondCut[facetIndex].functionSelectors\n );\n } else if (action == IDiamondCut.FacetCutAction.Remove) {\n removeFunctions(\n _diamondCut[facetIndex].facetAddress,\n _diamondCut[facetIndex].functionSelectors\n );\n } else {\n revert(\"LibDiamondCut: Incorrect FacetCutAction\");\n }\n }\n emit DiamondCut(_diamondCut, _init, _calldata);\n initializeDiamondCut(_init, _calldata);\n }\n\n function addFunctions(\n address _facetAddress,\n bytes4[] memory _functionSelectors\n ) internal {\n require(\n _functionSelectors.length > 0,\n \"LibDiamondCut: No selectors in facet to cut\"\n );\n DiamondStorage storage ds = diamondStorage();\n require(\n _facetAddress != address(0),\n \"LibDiamondCut: Add facet can't be address(0)\"\n );\n uint96 selectorPosition = uint96(\n ds.facetFunctionSelectors[_facetAddress].functionSelectors.length\n );\n // add new facet address if it does not exist\n if (selectorPosition == 0) {\n addFacet(ds, _facetAddress);\n }\n for (\n uint256 selectorIndex;\n selectorIndex < _functionSelectors.length;\n selectorIndex++\n ) {\n bytes4 selector = _functionSelectors[selectorIndex];\n address oldFacetAddress = ds\n .selectorToFacetAndPosition[selector]\n .facetAddress;\n require(\n oldFacetAddress == address(0),\n \"LibDiamondCut: Can't add function that already exists\"\n );\n addFunction(ds, selector, selectorPosition, _facetAddress);\n selectorPosition++;\n }\n }\n\n function replaceFunctions(\n address _facetAddress,\n bytes4[] memory _functionSelectors\n ) internal {\n require(\n _functionSelectors.length > 0,\n \"LibDiamondCut: No selectors in facet to cut\"\n );\n DiamondStorage storage ds = diamondStorage();\n require(\n _facetAddress != address(0),\n \"LibDiamondCut: Add facet can't be address(0)\"\n );\n uint96 selectorPosition = uint96(\n ds.facetFunctionSelectors[_facetAddress].functionSelectors.length\n );\n // add new facet address if it does not exist\n if (selectorPosition == 0) {\n addFacet(ds, _facetAddress);\n }\n for (\n uint256 selectorIndex;\n selectorIndex < _functionSelectors.length;\n selectorIndex++\n ) {\n bytes4 selector = _functionSelectors[selectorIndex];\n address oldFacetAddress = ds\n .selectorToFacetAndPosition[selector]\n .facetAddress;\n require(\n oldFacetAddress != _facetAddress,\n \"LibDiamondCut: Can't replace function with same function\"\n );\n removeFunction(ds, oldFacetAddress, selector);\n addFunction(ds, selector, selectorPosition, _facetAddress);\n selectorPosition++;\n }\n }\n\n function removeFunctions(\n address _facetAddress,\n bytes4[] memory _functionSelectors\n ) internal {\n require(\n _functionSelectors.length > 0,\n \"LibDiamondCut: No selectors in facet to cut\"\n );\n DiamondStorage storage ds = diamondStorage();\n // if function does not exist then do nothing and return\n require(\n _facetAddress == address(0),\n \"LibDiamondCut: Remove facet address must be address(0)\"\n );\n for (\n uint256 selectorIndex;\n selectorIndex < _functionSelectors.length;\n selectorIndex++\n ) {\n bytes4 selector = _functionSelectors[selectorIndex];\n address oldFacetAddress = ds\n .selectorToFacetAndPosition[selector]\n .facetAddress;\n removeFunction(ds, oldFacetAddress, selector);\n }\n }\n\n function addFacet(DiamondStorage storage ds, address _facetAddress)\n internal\n {\n enforceHasContractCode(\n _facetAddress,\n \"LibDiamondCut: New facet has no code\"\n );\n ds.facetFunctionSelectors[_facetAddress].facetAddressPosition = ds\n .facetAddresses\n .length;\n ds.facetAddresses.push(_facetAddress);\n }\n\n function addFunction(\n DiamondStorage storage ds,\n bytes4 _selector,\n uint96 _selectorPosition,\n address _facetAddress\n ) internal {\n ds\n .selectorToFacetAndPosition[_selector]\n .functionSelectorPosition = _selectorPosition;\n ds.facetFunctionSelectors[_facetAddress].functionSelectors.push(\n _selector\n );\n ds.selectorToFacetAndPosition[_selector].facetAddress = _facetAddress;\n }\n\n function removeFunction(\n DiamondStorage storage ds,\n address _facetAddress,\n bytes4 _selector\n ) internal {\n require(\n _facetAddress != address(0),\n \"LibDiamondCut: Can't remove function that doesn't exist\"\n );\n // an immutable function is a function defined directly in a diamond\n require(\n _facetAddress != address(this),\n \"LibDiamondCut: Can't remove immutable function\"\n );\n // replace selector with last selector, then delete last selector\n uint256 selectorPosition = ds\n .selectorToFacetAndPosition[_selector]\n .functionSelectorPosition;\n uint256 lastSelectorPosition = ds\n .facetFunctionSelectors[_facetAddress]\n .functionSelectors\n .length - 1;\n // if not the same then replace _selector with lastSelector\n if (selectorPosition != lastSelectorPosition) {\n bytes4 lastSelector = ds\n .facetFunctionSelectors[_facetAddress]\n .functionSelectors[lastSelectorPosition];\n ds.facetFunctionSelectors[_facetAddress].functionSelectors[\n selectorPosition\n ] = lastSelector;\n ds\n .selectorToFacetAndPosition[lastSelector]\n .functionSelectorPosition = uint96(selectorPosition);\n }\n // delete the last selector\n ds.facetFunctionSelectors[_facetAddress].functionSelectors.pop();\n delete ds.selectorToFacetAndPosition[_selector];\n\n // if no more selectors for facet address then delete the facet address\n if (lastSelectorPosition == 0) {\n // replace facet address with last facet address and delete last facet address\n uint256 lastFacetAddressPosition = ds.facetAddresses.length - 1;\n uint256 facetAddressPosition = ds\n .facetFunctionSelectors[_facetAddress]\n .facetAddressPosition;\n if (facetAddressPosition != lastFacetAddressPosition) {\n address lastFacetAddress = ds.facetAddresses[\n lastFacetAddressPosition\n ];\n ds.facetAddresses[facetAddressPosition] = lastFacetAddress;\n ds\n .facetFunctionSelectors[lastFacetAddress]\n .facetAddressPosition = facetAddressPosition;\n }\n ds.facetAddresses.pop();\n delete ds\n .facetFunctionSelectors[_facetAddress]\n .facetAddressPosition;\n }\n }\n\n function initializeDiamondCut(address _init, bytes memory _calldata)\n internal\n {\n if (_init == address(0)) {\n require(\n _calldata.length == 0,\n \"LibDiamondCut: _init is address(0) but_calldata is not empty\"\n );\n } else {\n require(\n _calldata.length > 0,\n \"LibDiamondCut: _calldata is empty but _init is not address(0)\"\n );\n if (_init != address(this)) {\n enforceHasContractCode(\n _init,\n \"LibDiamondCut: _init address has no code\"\n );\n }\n // solhint-disable-next-line avoid-low-level-calls\n (bool success, bytes memory error) = _init.delegatecall(_calldata);\n if (!success) {\n if (error.length > 0) {\n // bubble up the error\n revert(string(error));\n } else {\n revert(\"LibDiamondCut: _init function reverted\");\n }\n }\n }\n }\n\n function enforceHasContractCode(\n address _contract,\n string memory _errorMessage\n ) internal view {\n uint256 contractSize;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n contractSize := extcodesize(_contract)\n }\n require(contractSize > 0, _errorMessage);\n }\n}\n"
},
"@openzeppelin/contracts/utils/Address.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n"
},
"src/bridges/interfaces/IDiamondCut.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.4 <0.9.0;\n\ninterface IDiamondCut {\n enum FacetCutAction {\n Add,\n Replace,\n Remove\n }\n // Add=0, Replace=1, Remove=2\n\n struct FacetCut {\n address facetAddress;\n FacetCutAction action;\n bytes4[] functionSelectors;\n }\n\n /// @notice Add/replace/remove any number of functions and optionally execute\n /// a function with delegatecall\n /// @param _diamondCut Contains the facet addresses and function selectors\n /// @param _init The address of the contract or facet to execute _calldata\n /// @param _calldata A function call, including function selector and arguments\n /// _calldata is executed with delegatecall on _init\n function diamondCut(\n FacetCut[] calldata _diamondCut,\n address _init,\n bytes calldata _calldata\n ) external;\n\n event DiamondCut(FacetCut[] _diamondCut, address _init, bytes _calldata);\n}\n"
},
"src/bridges/libs/LibAsset.sol": {
"content": "// SPDX-License-Identifier: UNLICENSED\n// solhint-disable-next-line\npragma solidity 0.8.4;\nimport {NullAddrIsNotAnERC20Token, NullAddrIsNotAValidSpender, NoTransferToNullAddress, InvalidAmount, NativeValueWithERC, NativeAssetTransferFailed} from \"../errors/GenericErrors.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/// @title LibAsset\n/// @author Connext <support@connext.network>\n/// @notice This library contains helpers for dealing with onchain transfers\n/// of assets, including accounting for the native asset `assetId`\n/// conventions and any noncompliant ERC20 transfers\nlibrary LibAsset {\n uint256 private constant MAX_INT = type(uint256).max;\n\n address internal constant NULL_ADDRESS =\n 0x0000000000000000000000000000000000000000; //address(0)\n\n /// @dev All native assets use the empty address for their asset id\n /// by convention\n\n address internal constant NATIVE_ASSETID = NULL_ADDRESS; //address(0)\n\n /// @notice Gets the balance of the inheriting contract for the given asset\n /// @param assetId The asset identifier to get the balance of\n /// @return Balance held by contracts using this library\n function getOwnBalance(address assetId) internal view returns (uint256) {\n return\n assetId == NATIVE_ASSETID\n ? address(this).balance\n : IERC20(assetId).balanceOf(address(this));\n }\n\n /// @notice Transfers ether from the inheriting contract to a given\n /// recipient\n /// @param recipient Address to send ether to\n /// @param amount Amount to send to given recipient\n function transferNativeAsset(address payable recipient, uint256 amount)\n private\n {\n if (recipient == NULL_ADDRESS) revert NoTransferToNullAddress();\n // solhint-disable-next-line avoid-low-level-calls\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) revert NativeAssetTransferFailed();\n }\n\n /// @notice Gives MAX approval for another address to spend tokens\n /// @param assetId Token address to transfer\n /// @param spender Address to give spend approval to\n /// @param amount Amount to approve for spending\n function maxApproveERC20(\n IERC20 assetId,\n address spender,\n uint256 amount\n ) internal {\n if (address(assetId) == NATIVE_ASSETID) return;\n if (spender == NULL_ADDRESS) revert NullAddrIsNotAValidSpender();\n uint256 allowance = assetId.allowance(address(this), spender);\n if (allowance < amount)\n SafeERC20.safeApprove(IERC20(assetId), spender, MAX_INT);\n }\n\n /// @notice Transfers tokens from the inheriting contract to a given\n /// recipient\n /// @param assetId Token address to transfer\n /// @param recipient Address to send token to\n /// @param amount Amount to send to given recipient\n function transferERC20(\n address assetId,\n address recipient,\n uint256 amount\n ) private {\n if (isNativeAsset(assetId)) revert NullAddrIsNotAnERC20Token();\n SafeERC20.safeTransfer(IERC20(assetId), recipient, amount);\n }\n\n /// @notice Transfers tokens from a sender to a given recipient\n /// @param assetId Token address to transfer\n /// @param from Address of sender/owner\n /// @param to Address of recipient/spender\n /// @param amount Amount to transfer from owner to spender\n function transferFromERC20(\n address assetId,\n address from,\n address to,\n uint256 amount\n ) internal {\n if (assetId == NATIVE_ASSETID) revert NullAddrIsNotAnERC20Token();\n if (to == NULL_ADDRESS) revert NoTransferToNullAddress();\n SafeERC20.safeTransferFrom(IERC20(assetId), from, to, amount);\n }\n\n /// @notice Deposits an asset into the contract and performs checks to avoid NativeValueWithERC\n /// @param tokenId Token to deposit\n /// @param amount Amount to deposit\n /// @param isNative Wether the token is native or ERC20\n function depositAsset(\n address tokenId,\n uint256 amount,\n bool isNative\n ) internal {\n if (amount == 0) revert InvalidAmount();\n if (isNative) {\n if (msg.value != amount) revert InvalidAmount();\n } else {\n if (msg.value != 0) revert NativeValueWithERC();\n uint256 _fromTokenBalance = LibAsset.getOwnBalance(tokenId);\n LibAsset.transferFromERC20(\n tokenId,\n msg.sender,\n address(this),\n amount\n );\n if (LibAsset.getOwnBalance(tokenId) - _fromTokenBalance != amount)\n revert InvalidAmount();\n }\n }\n\n /// @notice Overload for depositAsset(address tokenId, uint256 amount, bool isNative)\n /// @param tokenId Token to deposit\n /// @param amount Amount to deposit\n function depositAsset(address tokenId, uint256 amount) internal {\n return depositAsset(tokenId, amount, tokenId == NATIVE_ASSETID);\n }\n\n /// @notice Determines whether the given assetId is the native asset\n /// @param assetId The asset identifier to evaluate\n /// @return Boolean indicating if the asset is the native asset\n function isNativeAsset(address assetId) internal pure returns (bool) {\n return assetId == NATIVE_ASSETID;\n }\n\n /// @notice Wrapper function to transfer a given asset (native or erc20) to\n /// some recipient. Should handle all non-compliant return value\n /// tokens as well by using the SafeERC20 contract by open zeppelin.\n /// @param assetId Asset id for transfer (address(0) for native asset,\n /// token address for erc20s)\n /// @param recipient Address to send asset to\n /// @param amount Amount to send to given recipient\n function transferAsset(\n address assetId,\n address payable recipient,\n uint256 amount\n ) internal {\n (assetId == NATIVE_ASSETID)\n ? transferNativeAsset(recipient, amount)\n : transferERC20(assetId, recipient, amount);\n }\n\n /// @dev Checks whether the given address is a contract and contains code\n function isContract(address _contractAddr) internal view returns (bool) {\n uint256 size;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n size := extcodesize(_contractAddr)\n }\n return size > 0;\n }\n}\n"
},
"src/common/helpers/BalancesHelperV2.sol": {
"content": "// SPDX-License-Identifier: MIT\n// solhint-disable-next-line\npragma solidity 0.8.4;\n\n/// @title BalancesHelperV2\n/// @author Luke Wickens <luke@pillarproject.io>\n/// @notice Used to get account balances of ERC20 tokens and Wrapped Super Tokens\n\nimport {ISuperfluidToken} from \"@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluidToken.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/interfaces/IERC20.sol\";\nimport {Address} from \"@openzeppelin/contracts/utils/Address.sol\";\n\ncontract BalancesHelperV2 {\n using Address for address;\n\n /// @notice Custom errors to handle address(0)\n error AccountZeroAddress(address account, address token);\n error TokenZeroAddress(address account, address token);\n\n constructor() {}\n\n /// @notice Returns balances of accounts for multiple ERC20 tokens.\n /// @dev Error thrown if: account or token address is address(0),\n /// large arrays of accounts/tokens are passed in could cause gas block limit issue\n /// @param accounts = Array of accounts addresses\n /// @param tokens = Array of tokens addresses\n /// @return One-dimensional that's accounts.length * tokens.length long. The\n /// array is ordered by all of accounts[0] token balances, then accounts[1] etc.\n\n function getBalances(address[] calldata accounts, address[] calldata tokens)\n external\n view\n returns (uint256[] memory)\n {\n uint256[] memory result = new uint256[](\n accounts.length * tokens.length\n );\n\n for (uint256 i; i < accounts.length; i++) {\n for (uint256 j; j < tokens.length; j++) {\n uint256 index = j + (tokens.length * i);\n result[index] = _getBalance(accounts[i], tokens[j]);\n }\n }\n return result;\n }\n\n /// @notice Returns balances of accounts for multiple Wrapped Super Tokens.\n /// @dev Error thrown if: account or token address is address(0),\n /// large arrays of accounts/tokens are passed in could cause gas block limit issue\n /// @param accounts = Array of accounts addresses\n /// @param tokens = Array of tokens addresses\n /// @return One-dimensional that's accounts.length * tokens.length long. The\n /// array is ordered by all of accounts[0] token balances, then accounts[1] etc.\n\n function getSuperfluidWrappedTokenBalances(\n address[] calldata accounts,\n address[] calldata tokens\n ) external view returns (int256[] memory) {\n int256[] memory result = new int256[](accounts.length * tokens.length);\n\n for (uint256 i; i < accounts.length; i++) {\n for (uint256 j; j < tokens.length; j++) {\n uint256 index = j + (tokens.length * i);\n result[index] = _getSuperfluidWrappedTokenBalance(\n accounts[i],\n tokens[j]\n );\n }\n }\n return result;\n }\n\n /// Private fuctions\n\n /// @notice Returns balance of account for an ERC20 token.\n /// @dev Error thrown if: account or token address is address(0)\n /// @param account = account address\n /// @param token = tokens address\n /// @return balance of account as uint256.\n\n function _getBalance(address account, address token)\n private\n view\n returns (uint256)\n {\n if (account == address(0)) revert AccountZeroAddress(account, token);\n if (token == address(0)) revert TokenZeroAddress(account, token);\n\n bytes memory returnedData = token.functionStaticCall(\n abi.encodeWithSelector(IERC20(token).balanceOf.selector, account)\n );\n\n return abi.decode(returnedData, (uint256));\n }\n\n /// @notice Returns real balance of a user, taking into consideration all agreements of account\n /// @dev Error thrown if: account or token address is address(0)\n /// @param account = account address\n /// @param token = tokens address\n /// @return available balance of account as int256.\n\n function _getSuperfluidWrappedTokenBalance(address account, address token)\n private\n view\n returns (int256)\n {\n if (account == address(0)) revert AccountZeroAddress(account, token);\n if (token == address(0)) revert TokenZeroAddress(account, token);\n\n bytes memory returnedData = token.functionStaticCall(\n abi.encodeWithSelector(\n ISuperfluidToken(token).realtimeBalanceOfNow.selector,\n account\n )\n );\n\n (int256 availableBalance, , , ) = abi.decode(\n returnedData,\n (int256, uint256, uint256, uint256)\n );\n return availableBalance;\n }\n}\n"
},
"@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluidToken.sol": {
"content": "// SPDX-License-Identifier: AGPLv3\npragma solidity >= 0.8.0;\n\nimport { ISuperAgreement } from \"./ISuperAgreement.sol\";\n\n\n/**\n * @title Superfluid token interface\n * @author Superfluid\n */\ninterface ISuperfluidToken {\n\n /**************************************************************************\n * Basic information\n *************************************************************************/\n\n /**\n * @dev Get superfluid host contract address\n */\n function getHost() external view returns(address host);\n\n /**\n * @dev Encoded liquidation type data mainly used for handling stack to deep errors\n *\n * Note:\n * - version: 1\n * - liquidationType key:\n * - 0 = reward account receives reward (PIC period)\n * - 1 = liquidator account receives reward (Pleb period)\n * - 2 = liquidator account receives reward (Pirate period/bailout)\n */\n struct LiquidationTypeData {\n uint256 version;\n uint8 liquidationType;\n }\n\n /**************************************************************************\n * Real-time balance functions\n *************************************************************************/\n\n /**\n * @dev Calculate the real balance of a user, taking in consideration all agreements of the account\n * @param account for the query\n * @param timestamp Time of balance\n * @return availableBalance Real-time balance\n * @return deposit Account deposit\n * @return owedDeposit Account owed Deposit\n */\n function realtimeBalanceOf(\n address account,\n uint256 timestamp\n )\n external view\n returns (\n int256 availableBalance,\n uint256 deposit,\n uint256 owedDeposit);\n\n /**\n * @notice Calculate the realtime balance given the current host.getNow() value\n * @dev realtimeBalanceOf with timestamp equals to block timestamp\n * @param account for the query\n * @return availableBalance Real-time balance\n * @return deposit Account deposit\n * @return owedDeposit Account owed Deposit\n */\n function realtimeBalanceOfNow(\n address account\n )\n external view\n returns (\n int256 availableBalance,\n uint256 deposit,\n uint256 owedDeposit,\n uint256 timestamp);\n\n /**\n * @notice Check if account is critical\n * @dev A critical account is when availableBalance < 0\n * @param account The account to check\n * @param timestamp The time we'd like to check if the account is critical (should use future)\n * @return isCritical Whether the account is critical\n */\n function isAccountCritical(\n address account,\n uint256 timestamp\n )\n external view\n returns(bool isCritical);\n\n /**\n * @notice Check if account is critical now (current host.getNow())\n * @dev A critical account is when availableBalance < 0\n * @param account The account to check\n * @return isCritical Whether the account is critical\n */\n function isAccountCriticalNow(\n address account\n )\n external view\n returns(bool isCritical);\n\n /**\n * @notice Check if account is solvent\n * @dev An account is insolvent when the sum of deposits for a token can't cover the negative availableBalance\n * @param account The account to check\n * @param timestamp The time we'd like to check if the account is solvent (should use future)\n * @return isSolvent\n */\n function isAccountSolvent(\n address account,\n uint256 timestamp\n )\n external view\n returns(bool isSolvent);\n\n /**\n * @notice Check if account is solvent now\n * @dev An account is insolvent when the sum of deposits for a token can't cover the negative availableBalance\n * @param account The account to check\n * @return isSolvent\n */\n function isAccountSolventNow(\n address account\n )\n external view\n returns(bool isSolvent);\n\n /**\n * @notice Get a list of agreements that is active for the account\n * @dev An active agreement is one that has state for the account\n * @param account Account to query\n * @return activeAgreements List of accounts that have non-zero states for the account\n */\n function getAccountActiveAgreements(address account)\n external view\n returns(ISuperAgreement[] memory activeAgreements);\n\n\n /**************************************************************************\n * Super Agreement hosting functions\n *************************************************************************/\n\n /**\n * @dev Create a new agreement\n * @param id Agreement ID\n * @param data Agreement data\n */\n function createAgreement(\n bytes32 id,\n bytes32[] calldata data\n )\n external;\n /**\n * @dev Agreement created event\n * @param agreementClass Contract address of the agreement\n * @param id Agreement ID\n * @param data Agreement data\n */\n event AgreementCreated(\n address indexed agreementClass,\n bytes32 id,\n bytes32[] data\n );\n\n /**\n * @dev Get data of the agreement\n * @param agreementClass Contract address of the agreement\n * @param id Agreement ID\n * @return data Data of the agreement\n */\n function getAgreementData(\n address agreementClass,\n bytes32 id,\n uint dataLength\n )\n external view\n returns(bytes32[] memory data);\n\n /**\n * @dev Create a new agreement\n * @param id Agreement ID\n * @param data Agreement data\n */\n function updateAgreementData(\n bytes32 id,\n bytes32[] calldata data\n )\n external;\n /**\n * @dev Agreement updated event\n * @param agreementClass Contract address of the agreement\n * @param id Agreement ID\n * @param data Agreement data\n */\n event AgreementUpdated(\n address indexed agreementClass,\n bytes32 id,\n bytes32[] data\n );\n\n /**\n * @dev Close the agreement\n * @param id Agreement ID\n */\n function terminateAgreement(\n bytes32 id,\n uint dataLength\n )\n external;\n /**\n * @dev Agreement terminated event\n * @param agreementClass Contract address of the agreement\n * @param id Agreement ID\n */\n event AgreementTerminated(\n address indexed agreementClass,\n bytes32 id\n );\n\n /**\n * @dev Update agreement state slot\n * @param account Account to be updated\n *\n * NOTE\n * - To clear the storage out, provide zero-ed array of intended length\n */\n function updateAgreementStateSlot(\n address account,\n uint256 slotId,\n bytes32[] calldata slotData\n )\n external;\n /**\n * @dev Agreement account state updated event\n * @param agreementClass Contract address of the agreement\n * @param account Account updated\n * @param slotId slot id of the agreement state\n */\n event AgreementStateUpdated(\n address indexed agreementClass,\n address indexed account,\n uint256 slotId\n );\n\n /**\n * @dev Get data of the slot of the state of an agreement\n * @param agreementClass Contract address of the agreement\n * @param account Account to query\n * @param slotId slot id of the state\n * @param dataLength length of the state data\n */\n function getAgreementStateSlot(\n address agreementClass,\n address account,\n uint256 slotId,\n uint dataLength\n )\n external view\n returns (bytes32[] memory slotData);\n\n /**\n * @notice Settle balance from an account by the agreement\n * @dev The agreement needs to make sure that the balance delta is balanced afterwards\n * @param account Account to query.\n * @param delta Amount of balance delta to be settled\n *\n * Modifiers:\n * - onlyAgreement\n */\n function settleBalance(\n address account,\n int256 delta\n )\n external;\n\n /**\n * @dev Make liquidation payouts (v2)\n * @param id Agreement ID\n * @param liquidationTypeData Data regarding the version of the liquidation schema and the type\n * @param liquidatorAccount Address of the executor of the liquidation\n * @param useDefaultRewardAccount Whether or not the default reward account receives the rewardAmount\n * @param targetAccount Account of the stream sender\n * @param rewardAmount The amount the reward recepient account will receive\n * @param targetAccountBalanceDelta The amount the sender account balance should change by\n *\n * - If a bailout is required (bailoutAmount > 0)\n * - the actual reward (single deposit) goes to the executor,\n * - while the reward account becomes the bailout account\n * - total bailout include: bailout amount + reward amount\n * - the targetAccount will be bailed out\n * - If a bailout is not required\n * - the targetAccount will pay the rewardAmount\n * - the liquidator (reward account in PIC period) will receive the rewardAmount\n *\n * Modifiers:\n * - onlyAgreement\n */\n function makeLiquidationPayoutsV2\n (\n bytes32 id,\n bytes memory liquidationTypeData,\n address liquidatorAccount,\n bool useDefaultRewardAccount,\n address targetAccount,\n uint256 rewardAmount,\n int256 targetAccountBalanceDelta\n ) external;\n /**\n * @dev Agreement liquidation event v2 (including agent account)\n * @param agreementClass Contract address of the agreement\n * @param id Agreement ID\n * @param liquidatorAccount Address of the executor of the liquidation\n * @param targetAccount Account of the stream sender\n * @param rewardAccount Account that collects the reward or bails out insolvent accounts\n * @param rewardAmount The amount the reward recipient account balance should change by\n * @param targetAccountBalanceDelta The amount the sender account balance should change by\n * @param liquidationTypeData The encoded liquidation type data including the version (how to decode)\n *\n * NOTE:\n * Reward account rule:\n * - if the agreement is liquidated during the PIC period\n * - the rewardAccount will get the rewardAmount (remaining deposit), regardless of the liquidatorAccount\n * - the targetAccount will pay for the rewardAmount\n * - if the agreement is liquidated after the PIC period AND the targetAccount is solvent\n * - the liquidatorAccount will get the rewardAmount (remaining deposit)\n * - the targetAccount will pay for the rewardAmount\n * - if the targetAccount is insolvent\n * - the liquidatorAccount will get the rewardAmount (single deposit)\n * - the rewardAccount will pay for both the rewardAmount and bailoutAmount\n * - the targetAccount will receive the bailoutAmount\n */\n event AgreementLiquidatedV2(\n address indexed agreementClass,\n bytes32 id,\n address indexed liquidatorAccount,\n address indexed targetAccount,\n address rewardAccount,\n uint256 rewardAmount,\n int256 targetAccountBalanceDelta,\n bytes liquidationTypeData\n );\n\n /**************************************************************************\n * Function modifiers for access control and parameter validations\n *\n * While they cannot be explicitly stated in function definitions, they are\n * listed in function definition comments instead for clarity.\n *\n * NOTE: solidity-coverage not supporting it\n *************************************************************************/\n\n /// @dev The msg.sender must be host contract\n //modifier onlyHost() virtual;\n\n /// @dev The msg.sender must be a listed agreement.\n //modifier onlyAgreement() virtual;\n\n /**************************************************************************\n * DEPRECATED\n *************************************************************************/\n\n /**\n * @dev Agreement liquidation event (DEPRECATED BY AgreementLiquidatedBy)\n * @param agreementClass Contract address of the agreement\n * @param id Agreement ID\n * @param penaltyAccount Account of the agreement to be penalized\n * @param rewardAccount Account that collect the reward\n * @param rewardAmount Amount of liquidation reward\n *\n * NOTE:\n *\n * [DEPRECATED] Use AgreementLiquidatedV2 instead\n */\n event AgreementLiquidated(\n address indexed agreementClass,\n bytes32 id,\n address indexed penaltyAccount,\n address indexed rewardAccount,\n uint256 rewardAmount\n );\n\n /**\n * @dev System bailout occurred (DEPRECATED BY AgreementLiquidatedBy)\n * @param bailoutAccount Account that bailout the penalty account\n * @param bailoutAmount Amount of account bailout\n *\n * NOTE:\n *\n * [DEPRECATED] Use AgreementLiquidatedV2 instead\n */\n event Bailout(\n address indexed bailoutAccount,\n uint256 bailoutAmount\n );\n\n /**\n * @dev Agreement liquidation event (DEPRECATED BY AgreementLiquidatedV2)\n * @param liquidatorAccount Account of the agent that performed the liquidation.\n * @param agreementClass Contract address of the agreement\n * @param id Agreement ID\n * @param penaltyAccount Account of the agreement to be penalized\n * @param bondAccount Account that collect the reward or bailout accounts\n * @param rewardAmount Amount of liquidation reward\n * @param bailoutAmount Amount of liquidation bailouot\n *\n * NOTE:\n * Reward account rule:\n * - if bailout is equal to 0, then\n * - the bondAccount will get the rewardAmount,\n * - the penaltyAccount will pay for the rewardAmount.\n * - if bailout is larger than 0, then\n * - the liquidatorAccount will get the rewardAmouont,\n * - the bondAccount will pay for both the rewardAmount and bailoutAmount,\n * - the penaltyAccount will pay for the rewardAmount while get the bailoutAmount.\n */\n event AgreementLiquidatedBy(\n address liquidatorAccount,\n address indexed agreementClass,\n bytes32 id,\n address indexed penaltyAccount,\n address indexed bondAccount,\n uint256 rewardAmount,\n uint256 bailoutAmount\n );\n}\n"
},
"@openzeppelin/contracts/interfaces/IERC20.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (interfaces/IERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../token/ERC20/IERC20.sol\";\n"
},
"@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperAgreement.sol": {
"content": "// SPDX-License-Identifier: AGPLv3\npragma solidity >= 0.8.0;\n\nimport { ISuperfluidToken } from \"./ISuperfluidToken.sol\";\n\n/**\n * @title Super agreement interface\n * @author Superfluid\n */\ninterface ISuperAgreement {\n\n /**\n * @dev Get the type of the agreement class\n */\n function agreementType() external view returns (bytes32);\n\n /**\n * @dev Calculate the real-time balance for the account of this agreement class\n * @param account Account the state belongs to\n * @param time Time used for the calculation\n * @return dynamicBalance Dynamic balance portion of real-time balance of this agreement\n * @return deposit Account deposit amount of this agreement\n * @return owedDeposit Account owed deposit amount of this agreement\n */\n function realtimeBalanceOf(\n ISuperfluidToken token,\n address account,\n uint256 time\n )\n external\n view\n returns (\n int256 dynamicBalance,\n uint256 deposit,\n uint256 owedDeposit\n );\n\n}\n"
},
"src/bridges/facets/CBridgeFacet.sol": {
"content": "// SPDX-License-Identifier: MIT\n// solhint-disable-next-line\npragma solidity 0.8.4;\n\n/// @title CBridgeFacet\n/// @author Luke Wickens <luke@pillarproject.io>\n/// @notice cBridge intergration for bridging tokens\n\nimport {ICBridge} from \"../interfaces/ICBridge.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {SafeERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport {ReentrancyGuard} from \"../../common/helpers/DiamondReentrancyGuard.sol\";\nimport {CannotBridgeToSameNetwork, InvalidAmount, InvalidConfig, TokenAddressIsZero, ZeroAddressProvided} from \"../errors/GenericErrors.sol\";\nimport {CBSlippageTooLow} from \"../errors/CBridgeErrors.sol\";\nimport {LibDiamond} from \"../libs/LibDiamond.sol\";\n\ncontract CBridgeFacet is ReentrancyGuard {\n using SafeERC20 for IERC20;\n //////////////////////////////////////////////////////////////\n /////////////////////////// Events ///////////////////////////\n //////////////////////////////////////////////////////////////\n event CBInitialized(address cBridge, uint256 chainId);\n event CBTransferStarted(\n string bridgeUsed,\n address token,\n address from,\n address to,\n uint256 qty,\n uint256 chainIdTo\n );\n event CBUpdatedBridge(address newAddress);\n event CBUpdatedSlippageTolerance(uint256 newSlippage);\n //////////////////////////////////////////////////////////////\n ////////////////////////// Storage ///////////////////////////\n //////////////////////////////////////////////////////////////\n\n bytes32 internal constant NAMESPACE =\n keccak256(\"io.etherspot.facets.cbridge\");\n struct Storage {\n address cbBridge;\n uint256 cbChainId;\n uint32 cbSlippage;\n }\n\n //////////////////////////////////////////////////////////////\n ////////////////////////// Structs ///////////////////////////\n //////////////////////////////////////////////////////////////\n\n struct CBridgeData {\n uint64 dstChainId;\n uint64 nonce;\n uint256 qty;\n address to;\n address token;\n }\n\n /// @notice initializes state variables for the cBridge facet\n /// @param _cbBridge address of the CBridge router contract\n function cbInitialize(address _cbBridge) external {\n LibDiamond.enforceIsContractOwner();\n if (_cbBridge == address(0)) revert ZeroAddressProvided();\n Storage storage s = getStorage();\n s.cbBridge = _cbBridge;\n s.cbChainId = block.chainid;\n s.cbSlippage = 10000; // equates to 1% - has to be > 0.5% (slippage * 1M)\n emit CBInitialized(_cbBridge, block.chainid);\n }\n\n /// @notice initiates token bridging\n /// @param _cbData: provides necessary data for cBridge transfer\n\n function cbBridgeTokens(CBridgeData calldata _cbData)\n external\n payable\n nonReentrant\n {\n if (block.chainid == _cbData.dstChainId)\n revert CannotBridgeToSameNetwork();\n if (_cbData.to == address(0)) revert ZeroAddressProvided();\n if (_cbData.qty <= 0) revert InvalidAmount();\n if (_cbData.token == address(0)) revert TokenAddressIsZero();\n\n Storage storage s = getStorage();\n address bridge = s.cbBridge;\n\n // this contract calls stargate swap()\n IERC20(_cbData.token).safeTransferFrom(\n msg.sender,\n address(this),\n _cbData.qty\n );\n IERC20(_cbData.token).safeApprove(address(bridge), _cbData.qty);\n\n ICBridge(bridge).send(\n _cbData.to,\n _cbData.token,\n _cbData.qty,\n _cbData.dstChainId,\n _cbData.nonce,\n s.cbSlippage\n );\n\n emit CBTransferStarted(\n \"cbridge\",\n _cbData.token,\n msg.sender,\n _cbData.to,\n _cbData.qty,\n _cbData.dstChainId\n );\n }\n\n function cbUpdateSlippageTolerance(uint32 _newSlippage) external {\n // should be > 0.5% (5000)\n if (_newSlippage <= 5000) revert CBSlippageTooLow();\n LibDiamond.enforceIsContractOwner();\n Storage storage s = getStorage();\n s.cbSlippage = _newSlippage;\n emit CBUpdatedSlippageTolerance(_newSlippage);\n }\n\n function cbUpdateBridge(address _newAddress) external {\n LibDiamond.enforceIsContractOwner();\n if (_newAddress == address(0)) revert ZeroAddressProvided();\n Storage storage s = getStorage();\n s.cbBridge = _newAddress;\n emit CBUpdatedBridge(_newAddress);\n }\n\n //////////////////////////////////////////////////////////////\n ////////////////////// Private Functions /////////////////////\n //////////////////////////////////////////////////////////////\n\n /// @dev fetch local storage\n function getStorage() private pure returns (Storage storage s) {\n bytes32 namespace = NAMESPACE;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n s.slot := namespace\n }\n }\n}\n"
},
"src/bridges/interfaces/ICBridge.sol": {
"content": "// SPDX-License-Identifier: MIT\n// solhint-disable-next-line\npragma solidity 0.8.4;\n\ninterface ICBridge {\n function send(\n address _receiver,\n address _token,\n uint256 _amount,\n uint64 _dstChinId,\n uint64 _nonce,\n uint32 _maxSlippage\n ) external;\n\n function sendNative(\n address _receiver,\n uint256 _amount,\n uint64 _dstChinId,\n uint64 _nonce,\n uint32 _maxSlippage\n ) external payable;\n\n function relay(\n bytes calldata _relayRequest,\n bytes[] calldata _sigs,\n address[] calldata _signers,\n uint256[] calldata _powers\n ) external;\n}\n"
},
"src/bridges/errors/CBridgeErrors.sol": {
"content": "// SPDX-License-Identifier: MIT\n// solhint-disable-next-line\npragma solidity 0.8.4;\n\nerror CBSlippageTooLow();\n"
},
"src/bridges/facets/HopFacet.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.4;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IHopBridge } from \"../interfaces/IHopBridge.sol\";\nimport { LibAsset } from \"../libs/LibAsset.sol\";\nimport { LibDiamond } from \"../libs/LibDiamond.sol\";\nimport { ReentrancyGuard } from \"../../common/helpers/DiamondReentrancyGuard.sol\";\nimport {\n InvalidAmount,\n InvalidBridgeConfigLength,\n CannotBridgeToSameNetwork,\n NativeValueWithERC,\n InvalidConfig\n} from \"../errors/GenericErrors.sol\";\n\n/**\n * @title Hop Protocol Integration\n *\n * @notice Contract which provides bridging functionality through Hop Protocol\n *\n */\ncontract HopFacet is ReentrancyGuard {\n // storage\n\n bytes32 internal constant NAMESPACE = keccak256(\"io.etherspot.facets.hop\");\n struct Storage {\n uint256 chainLayerId;\n }\n\n // types\n\n struct HopData {\n address bridge;\n address ammWrapper;\n address asset;\n address recipient;\n uint256 chainId;\n uint256 amount;\n uint256 bonderFee;\n uint256 amountOutMin;\n uint256 deadline;\n uint256 destinationAmountOutMin;\n uint256 destinationDeadline;\n }\n\n // events\n\n /**\n * @dev Emitted when facet initializes\n * @param chainId current chain id\n * @param chainLayerId current chain layer id\n */\n event HopInitialized(\n uint256 chainId,\n uint256 chainLayerId\n );\n\n /**\n * @dev Emitted on token swap\n * @param _destination destination chain id\n * @param _bridge address of the bridge on chain _destination,\n * @param _ammWrapper address of the amm wrapper,\n * @param _recipient recipient\n * @param _asset address of the asset\n * @param _amount amount of assets\n * @param _bonderFee fee\n * @param _amountOutMin The minimum amount received after attempting to\n * swap in the destination\n * @param _deadline The deadline for swapping in the destination AMM market.\n * 0 if no * swap is intended.\n * @param _destinationAmountOutMin The minimum amount of tokens to receive after bridging\n * @param _destinationDeadline The time the transaction must be completed\n */\n event HopTokenSwap(\n uint256 indexed _destination,\n address _bridge,\n address _ammWrapper,\n address indexed _recipient,\n address indexed _asset,\n uint256 _amount,\n uint256 _bonderFee,\n uint256 _amountOutMin,\n uint256 _deadline,\n uint256 _destinationAmountOutMin,\n uint256 _destinationDeadline\n );\n\n\n\n // external functions\n\n /**\n * @notice Initializes local variables for the Connext facet\n */\n function initHop(uint256 _chainLayerId) external {\n LibDiamond.enforceIsContractOwner();\n\n Storage storage s = getStorage();\n s.chainLayerId = _chainLayerId;\n\n emit HopInitialized(\n getChainID(),\n _chainLayerId\n );\n }\n\n /**\n * @notice Bridges tokens via Hop Protocol\n * @param _hopData data specific to Hop Protocol\n */\n function hopTokenTransfer(\n HopData calldata _hopData\n ) external payable nonReentrant {\n LibAsset.depositAsset(_hopData.asset, _hopData.amount);\n\n address bridge;\n if (getLayerId() == 1) {\n bridge = _hopData.bridge;\n } else {\n bridge = _hopData.ammWrapper;\n }\n\n if (getChainID() == _hopData.chainId)\n revert CannotBridgeToSameNetwork();\n\n // Give Hop approval to bridge tokens\n LibAsset.maxApproveERC20(\n IERC20(_hopData.asset),\n bridge,\n _hopData.amount\n );\n\n uint256 value = LibAsset.isNativeAsset(_hopData.asset)\n ? _hopData.amount\n : 0;\n\n if (getLayerId() == 1) {\n // Ethereum L1\n IHopBridge(bridge).sendToL2{value: value}(\n _hopData.chainId,\n _hopData.recipient,\n _hopData.amount,\n _hopData.destinationAmountOutMin,\n _hopData.destinationDeadline,\n address(0),\n 0\n );\n } else {\n // L2\n IHopBridge(bridge).swapAndSend{value: value}(\n _hopData.chainId,\n _hopData.recipient,\n _hopData.amount,\n _hopData.bonderFee,\n _hopData.amountOutMin,\n _hopData.deadline,\n _hopData.destinationAmountOutMin,\n _hopData.destinationDeadline\n );\n }\n emit HopTokenSwap(\n _hopData.chainId,\n _hopData.bridge,\n _hopData.ammWrapper,\n _hopData.recipient,\n _hopData.asset,\n _hopData.amount,\n _hopData.bonderFee,\n _hopData.amountOutMin,\n _hopData.deadline,\n _hopData.destinationAmountOutMin,\n _hopData.destinationDeadline\n );\n }\n\n /// private Methods ///\n\n /**\n * @dev returns local storage\n */\n function getStorage() private pure returns (Storage storage s) {\n bytes32 namespace = NAMESPACE;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n s.slot := namespace\n }\n }\n\n /**\n * @dev returns current chain layer number\n * @return uint256 layer number\n */\n function getLayerId() private view returns (uint256) {\n return getStorage().chainLayerId;\n }\n\n /**\n * @dev fetch chain id\n */\n function getChainID() private view returns (uint256) {\n uint256 id;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n id := chainid()\n }\n return id;\n }\n}\n"
},
"src/bridges/interfaces/IHopBridge.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.4;\n\ninterface IHopBridge {\n function sendToL2(\n uint256 chainId,\n address recipient,\n uint256 amount,\n uint256 amountOutMin,\n uint256 deadline,\n address relayer,\n uint256 relayerFee\n ) external payable;\n\n function swapAndSend(\n uint256 chainId,\n address recipient,\n uint256 amount,\n uint256 bonderFee,\n uint256 amountOutMin,\n uint256 deadline,\n uint256 destinationAmountOutMin,\n uint256 destinationDeadline\n ) external payable;\n}\n"
}
},
"settings": {
"evmVersion": "istanbul",
"metadata": {
"bytecodeHash": "none",
"useLiteralContent": true
},
"optimizer": {
"enabled": false,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers",
"metadata",
"devdoc",
"userdoc",
"storageLayout",
"evm.gasEstimates"
],
"": [
"ast"
]
}
}
}
}