Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions script/deploy/facets/DeployGasZipPeriphery.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ contract DeployScript is DeployScriptBase {
string.concat(".gasZipRouters.", network)
);

// get LiFiDEXAggregator address
// get LiFiDiamond address
path = string.concat(
root,
"/deployments/",
Expand All @@ -38,10 +38,7 @@ contract DeployScript is DeployScriptBase {
"json"
);

address liFiDEXAggregator = _getConfigContractAddress(
path,
".LiFiDEXAggregator"
);
address liFiDiamond = _getConfigContractAddress(path, ".LiFiDiamond");

// get network's SAFE address to become contract owner for potential fund withdrawals
path = string.concat(root, "/config/networks.json");
Expand All @@ -51,6 +48,6 @@ contract DeployScript is DeployScriptBase {
string.concat(".", network, ".safeAddress")
);

return abi.encode(gasZipRouter, liFiDEXAggregator, safeAddress);
return abi.encode(gasZipRouter, liFiDiamond, safeAddress);
}
}
7 changes: 2 additions & 5 deletions script/deploy/zksync/DeployGasZipPeriphery.zksync.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,7 @@ contract DeployScript is DeployScriptBase {
"json"
);

address liFiDEXAggregator = _getConfigContractAddress(
path,
".LiFiDEXAggregator"
);
address liFiDiamond = _getConfigContractAddress(path, ".LiFiDiamond");

// get network's SAFE address to become contract owner for potential fund withdrawals
path = string.concat(root, "/config/networks.json");
Expand All @@ -51,6 +48,6 @@ contract DeployScript is DeployScriptBase {
string.concat(".", network, ".safeAddress")
);

return abi.encode(gasZipRouter, liFiDEXAggregator, safeAddress);
return abi.encode(gasZipRouter, liFiDiamond, safeAddress);
}
}
67 changes: 48 additions & 19 deletions src/Periphery/GasZipPeriphery.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,69 +3,98 @@ pragma solidity ^0.8.17;

import { ILiFi } from "../Interfaces/ILiFi.sol";
import { IGasZip } from "../Interfaces/IGasZip.sol";
import { IWhitelistManagerFacet } from "../Interfaces/IWhitelistManagerFacet.sol";
import { LibSwap } from "../Libraries/LibSwap.sol";
import { LibAsset, IERC20 } from "../Libraries/LibAsset.sol";
import { LibUtil } from "../Libraries/LibUtil.sol";
import { WithdrawablePeriphery } from "../Helpers/WithdrawablePeriphery.sol";
import { SafeTransferLib } from "solady/utils/SafeTransferLib.sol";
import { InvalidCallData } from "../Errors/GenericErrors.sol";
import { InvalidCallData, ContractCallNotAllowed, InvalidConfig } from "../Errors/GenericErrors.sol";

/// @title GasZipPeriphery
/// @author LI.FI (https://li.fi)
/// @notice Provides functionality to swap ERC20 tokens to use the gas.zip protocol as a pre-bridge step (https://www.gas.zip/)
/// @custom:version 1.0.1
/// @custom:version 1.0.2
contract GasZipPeriphery is ILiFi, WithdrawablePeriphery {
using SafeTransferLib for address;

/// State ///
// solhint-disable-next-line immutable-vars-naming
IGasZip public immutable gasZipRouter;
// solhint-disable-next-line immutable-vars-naming
address public immutable liFiDEXAggregator;
uint256 internal constant MAX_CHAINID_LENGTH_ALLOWED = 32;
IGasZip public immutable GAS_ZIP_ROUTER;
address public immutable LIFI_DIAMOND;
uint256 internal constant MAX_CHAINID_LENGTH_ALLOWED = 16;

/// Errors ///
error TooManyChainIds();
error SwapOutputMustBeNative();

/// Constructor ///
constructor(
address _gasZipRouter,
address _liFiDEXAggregator,
address _liFiDiamond,
address _owner
) WithdrawablePeriphery(_owner) {
gasZipRouter = IGasZip(_gasZipRouter);
liFiDEXAggregator = _liFiDEXAggregator;
if (
_gasZipRouter == address(0) ||
_liFiDiamond == address(0) ||
_owner == address(0)
) {
revert InvalidConfig();
}
GAS_ZIP_ROUTER = IGasZip(_gasZipRouter);
LIFI_DIAMOND = _liFiDiamond;
}

/// @notice Swaps ERC20 tokens to native and deposits these native tokens in the GasZip router contract
/// Swaps are only allowed via the LiFiDEXAggregator
/// Swaps are allowed via any whitelisted contract from the Diamond's WhitelistManagerFacet
/// @dev this function can be used as a LibSwap.SwapData protocol step to combine it with any other bridge
/// @param _swapData The swap data that executes the swap from ERC20 to native
/// @param _gasZipData contains information about which chains gas should be sent to
function depositToGasZipERC20(
LibSwap.SwapData calldata _swapData,
IGasZip.GasZipData calldata _gasZipData
) public {
if (_swapData.receivingAssetId != address(0)) {
revert SwapOutputMustBeNative();
}

IWhitelistManagerFacet whitelistManager = IWhitelistManagerFacet(
LIFI_DIAMOND
);

if (
!whitelistManager.isAddressWhitelisted(_swapData.callTo) ||
!whitelistManager.isFunctionApproved(
bytes4(_swapData.callData[:4])
)
) {
revert ContractCallNotAllowed();
}

// deposit ERC20 asset from diamond
LibAsset.depositAsset(_swapData.sendingAssetId, _swapData.fromAmount);

// max approve to DEX, if not already done
LibAsset.maxApproveERC20(
IERC20(_swapData.sendingAssetId),
liFiDEXAggregator,
_swapData.approveTo,
_swapData.fromAmount
);

// execute swap using LiFiDEXAggregator
uint256 preSwapBal = address(this).balance;

// execute swap using the whitelisted DEX
// Note on slippage protection:
// 1. Individual swap slippage is protected via minAmountOut parameter in _swapData.callData
// 2. Final output amount slippage is checked at diamond contract level in SwapperV2._depositAndSwap()
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory res) = liFiDEXAggregator.call(
(bool success, bytes memory res) = _swapData.callTo.call(
_swapData.callData
);
if (!success) {
LibUtil.revertWith(res);
}
// extract the swap output amount from the call return value
uint256 swapOutputAmount = abi.decode(res, (uint256));

uint256 swapOutputAmount = address(this).balance - preSwapBal;

// deposit native tokens to Gas.zip protocol
depositToGasZipNative(_gasZipData, swapOutputAmount);
Expand All @@ -84,7 +113,7 @@ contract GasZipPeriphery is ILiFi, WithdrawablePeriphery {
revert InvalidCallData();

// We are depositing to a new contract that supports deposits for EVM chains + Solana (therefore 'receiver' address is bytes32)
gasZipRouter.deposit{ value: _amount }(
GAS_ZIP_ROUTER.deposit{ value: _amount }(
_gasZipData.destinationChains,
_gasZipData.receiverAddress
);
Expand All @@ -107,9 +136,9 @@ contract GasZipPeriphery is ILiFi, WithdrawablePeriphery {
if (length > MAX_CHAINID_LENGTH_ALLOWED) revert TooManyChainIds();

for (uint256 i; i < length; ++i) {
// Shift destinationChains left by 8 bits and add the next chainID
// Shift destinationChains left by 16 bits and add the next chainID
destinationChains =
(destinationChains << 8) |
(destinationChains << 16) |
uint256(_chainIds[i]);
}
}
Expand Down
Loading
Loading