Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LF-11761 - Implement glacis [GlacisFacet v1.0.0,IGlacisAirlift v1.0.0] #945

Open
wants to merge 45 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
5446cc2
deploy log fixed
0xDEnYO Jan 16, 2025
fda004f
Added GlacisFacet files
mirooon Jan 16, 2025
e4ffcb8
Removed OPTIMISM addresses
mirooon Jan 16, 2025
22d242a
Removed OPTIMISM addresses
mirooon Jan 16, 2025
76e1167
Added GlacisFacet tests
mirooon Jan 17, 2025
4648dd4
Added GlacisFacet tests
mirooon Jan 17, 2025
c7155e3
Take nativeFee offchain
mirooon Jan 17, 2025
aeb0b78
GlacisFacet updated. Desc adjustments. Removed handling of native assets
mirooon Jan 18, 2025
2550324
Updated deploy, update scripts, config, docs
mirooon Jan 18, 2025
b476777
Added demoScript
mirooon Jan 20, 2025
d1b49e0
Updates
mirooon Jan 21, 2025
4ee8ed2
Merge branch 'fix-deploy-log' into implement-glacis-LF-11761
mirooon Jan 21, 2025
ec862d8
Updates
mirooon Jan 21, 2025
804d097
Updated GlacisFacet onchain
mirooon Jan 22, 2025
1667306
Updates proposed by coderabbit
mirooon Jan 22, 2025
064233d
Update script/demoScripts/demoGlacisAirlift.ts
mirooon Jan 22, 2025
894a94b
Merge branch 'main' into implement-glacis-LF-11761
mirooon Jan 22, 2025
b52931c
Removed TODOs
mirooon Jan 22, 2025
e9d721b
added docs description, variables naming, blank lines, added comments
mirooon Jan 23, 2025
925fb97
Added logs after staging deployment
mirooon Jan 23, 2025
ae8720c
Added BASE contracts
mirooon Jan 23, 2025
5cc0d08
Added LINK tests, refactoring
mirooon Jan 23, 2025
033d61f
Merge branch 'main' into implement-glacis-LF-11761
mirooon Jan 24, 2025
5ada8c2
Small improvements
mirooon Jan 27, 2025
9a82d83
Removed dot
mirooon Jan 27, 2025
b18d916
Added native reserve
mirooon Jan 27, 2025
dc333c4
Merge branch 'main' into implement-glacis-LF-11761
mirooon Jan 27, 2025
1bbfb93
Added explanation for quoteSend and payableAmount
mirooon Jan 28, 2025
c63510b
Added explanation for quoteSend and payableAmount
mirooon Jan 28, 2025
a448bc3
Merge branch 'main' into implement-glacis-LF-11761
mirooon Jan 28, 2025
2695efd
Merge branch 'main' into implement-glacis-LF-11761
mirooon Jan 30, 2025
ba636f1
Updated demoScript for viem. Updated facetDemoScript template
mirooon Jan 30, 2025
bccacb3
Added semicolons
mirooon Jan 30, 2025
b58f7bf
Template adjustments
mirooon Jan 30, 2025
dbb3852
Added customed fuzzing amounts
mirooon Jan 30, 2025
9e3f885
Merge branch 'main' into implement-glacis-LF-11761
0xDEnYO Feb 6, 2025
f6f3f9e
Adjusments, changed to _getConfigContractAddress, removed addSelector…
mirooon Feb 7, 2025
1a77677
Updated demo script
mirooon Feb 7, 2025
af8ac60
modified demo script template
mirooon Feb 7, 2025
394087f
Updated airlift contracts, changed safeTransfer to maxApprove. Update…
mirooon Feb 7, 2025
9e623bc
Updated tests addresses
mirooon Feb 7, 2025
dad7806
removed unused SafeERC20 (audit issue #1)
mirooon Feb 12, 2025
f5cdbc2
Validate GlacisData.refundAddress is non zero (audit issue #4)
mirooon Feb 12, 2025
f9276e3
Add noNativeAsset modifier (audit issue #3)
mirooon Feb 12, 2025
6914042
Fixed description - refunds on source chain
mirooon Feb 17, 2025
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
Prev Previous commit
Next Next commit
Added GlacisFacet tests
mirooon committed Jan 17, 2025

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
commit 4648dd44dd303832f52e2b658d3287b6662a4a2f
128 changes: 55 additions & 73 deletions test/solidity/Facets/GlacisFacet.t.sol
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
// SPDX-License-Identifier: Unlicense
pragma solidity 0.8.17;

import { LibAllowList, TestBaseFacet, console, ERC20 } from "../utils/TestBaseFacet.sol";
import { LibAllowList, TestBaseFacet, ERC20 } from "../utils/TestBaseFacet.sol";
import { LibSwap } from "lifi/Libraries/LibSwap.sol";
import { GlacisFacet } from "lifi/Facets/GlacisFacet.sol";
import { IGlacisAirlift, QuoteSendInfo } from "lifi/Interfaces/IGlacisAirlift.sol";
import { InsufficientBalance } from "lifi/Errors/GenericErrors.sol";

// Stub GlacisFacet Contract
contract TestGlacisFacet is GlacisFacet {
@@ -22,33 +23,35 @@ contract TestGlacisFacet is GlacisFacet {
contract GlacisFacetTest is TestBaseFacet {
GlacisFacet.GlacisData internal validGlacisData;
TestGlacisFacet internal glacisFacet;
ERC20 internal wormhole;
0xDEnYO marked this conversation as resolved.
Show resolved Hide resolved
uint256 internal defaultWORMHOLEAmount;
uint256 internal tokenFee;

IGlacisAirlift internal constant airlift =
IGlacisAirlift(0xE0A049955E18CFfd09C826C2c2e965439B6Ab272);
address internal ADDRESS_WORMHOLE_TOKEN =
0xB0fFa8000886e57F86dd5264b9582b2Ad87b2b91;

uint256 internal payableAmount = 1 ether;

function setUp() public {
customRpcUrlForForking = "ETH_NODE_URI_ARBITRUM";
customBlockNumberForForking = 295706031;
initTestBase();

defaultWORMHOLEAmount =
1_000 *
10 ** ERC20(ADDRESS_WORMHOLE_TOKEN).decimals();
wormhole = ERC20(ADDRESS_WORMHOLE_TOKEN);

defaultWORMHOLEAmount = 1_000 * 10 ** wormhole.decimals();

deal(
ADDRESS_WORMHOLE_TOKEN,
USER_SENDER,
100_000 * 10 ** ERC20(ADDRESS_WORMHOLE_TOKEN).decimals()
100_000 * 10 ** wormhole.decimals()
);
deal(
ADDRESS_WORMHOLE_TOKEN,
address(airlift),
100_000 * 10 ** ERC20(ADDRESS_WORMHOLE_TOKEN).decimals()
100_000 * 10 ** wormhole.decimals()
);

glacisFacet = new TestGlacisFacet(airlift);
@@ -64,7 +67,7 @@ contract GlacisFacetTest is TestBaseFacet {

addFacet(diamond, address(glacisFacet), functionSelectors);
glacisFacet = TestGlacisFacet(address(diamond));
glacisFacet.addDex(ADDRESS_UNISWAP_ARB);
glacisFacet.addDex(ADDRESS_UNISWAP);
glacisFacet.setFunctionApprovalBySignature(
uniswap.swapExactTokensForTokens.selector
);
@@ -86,21 +89,6 @@ contract GlacisFacetTest is TestBaseFacet {
// produce valid GlacisData
validGlacisData = GlacisFacet.GlacisData({ refund: REFUND_WALLET });

console.log(
"============================ here0.1 ========================"
);
// (bool ok, bytes memory result) = address(airlift).staticcall(
// abi.encodeWithSignature(
// "quoteSend(address,uint256,bytes32,uint256,address,uint256)",
// bridgeData.sendingAssetId,
// bridgeData.minAmount,
// bytes32(uint256(uint160(bridgeData.receiver))),
// bridgeData.destinationChainId,
// REFUND_WALLET,
// payableAmount // TODO
// )
// );
// require(ok);
QuoteSendInfo memory quoteSendInfo = IGlacisAirlift(address(airlift))
0xDEnYO marked this conversation as resolved.
Show resolved Hide resolved
.quoteSend(
bridgeData.sendingAssetId,
@@ -147,10 +135,7 @@ contract GlacisFacetTest is TestBaseFacet {
vm.startPrank(USER_SENDER);

// approval
ERC20(ADDRESS_WORMHOLE_TOKEN).approve(
address(glacisFacet),
bridgeData.minAmount
);
wormhole.approve(address(glacisFacet), bridgeData.minAmount);

//prepare check for events
vm.expectEmit(true, true, true, true, address(glacisFacet));
@@ -163,11 +148,11 @@ contract GlacisFacetTest is TestBaseFacet {
// TODO
function testBase_CanBridgeTokens_fuzzed(uint256 amount) public override {
// // TODO can be related to this issue: https://github.com/glacislabs/airlift-evm/blob/main/test/tokens/MIM.t.sol#L23-L31
// vm.assume(amount > 1_000 * 10 ** ERC20(ADDRESS_WORMHOLE_TOKEN).decimals() && amount < 100_000 * 10 ** ERC20(ADDRESS_WORMHOLE_TOKEN).decimals());
// vm.assume(amount > 1_000 * 10 ** wormhole.decimals() && amount < 100_000 * 10 ** wormhole.decimals());
// vm.startPrank(USER_SENDER);
// bridgeData.minAmount = amount;
// // approval
// ERC20(ADDRESS_WORMHOLE_TOKEN).approve(address(glacisFacet), bridgeData.minAmount);
// wormhole.approve(address(glacisFacet), bridgeData.minAmount);
// QuoteSendInfo memory quoteSendInfo = IGlacisAirlift(address(airlift)).quoteSend(
// bridgeData.sendingAssetId,
// bridgeData.minAmount,
@@ -192,12 +177,12 @@ contract GlacisFacetTest is TestBaseFacet {

function setDefaultSwapDataSingleDAItoWORMHOLE() internal virtual {
delete swapData;
// Swap DAI -> USDC
// Swap DAI -> WORMHOLE
address[] memory path = new address[](2);
path[0] = ADDRESS_DAI;
path[1] = ADDRESS_WORMHOLE_TOKEN;

uint256 amountOut = defaultUSDCAmount;
uint256 amountOut = defaultWORMHOLEAmount;

// Calculate DAI amount
uint256[] memory amounts = uniswap.getAmountsIn(amountOut, path);
@@ -225,22 +210,23 @@ contract GlacisFacetTest is TestBaseFacet {

function testBase_CanSwapAndBridgeTokens()
public
virtual
override
assertBalanceChange(
ADDRESS_DAI,
USER_SENDER,
-int256(swapData[0].fromAmount)
)
assertBalanceChange(ADDRESS_DAI, USER_RECEIVER, 0)
assertBalanceChange(ADDRESS_WORMHOLE_TOKEN, USER_SENDER, 0)
assertBalanceChange(ADDRESS_WORMHOLE_TOKEN, USER_RECEIVER, 0)
{
vm.startPrank(USER_SENDER);
// add liquidity for dex pair
0xDEnYO marked this conversation as resolved.
Show resolved Hide resolved
addLiquidity(
ADDRESS_DAI,
ADDRESS_WORMHOLE_TOKEN,
100_000 * 10 ** ERC20(ADDRESS_DAI).decimals(),
100_000 * 10 ** wormhole.decimals()
);

uint256 initialDAIBalance = dai.balanceOf(USER_SENDER);
vm.startPrank(USER_SENDER);
// prepare bridgeData
bridgeData.hasSourceSwaps = true;
0xDEnYO marked this conversation as resolved.
Show resolved Hide resolved

// reset swap data
setDefaultSwapDataSingleDAItoWORMHOLE();

@@ -251,7 +237,7 @@ contract GlacisFacetTest is TestBaseFacet {
vm.expectEmit(true, true, true, true, _facetTestContractAddress);
emit AssetSwapped(
bridgeData.transactionId,
ADDRESS_UNISWAP_ARB,
address(uniswap),
ADDRESS_DAI,
ADDRESS_WORMHOLE_TOKEN,
swapData[0].fromAmount,
@@ -261,10 +247,15 @@ contract GlacisFacetTest is TestBaseFacet {

vm.expectEmit(true, true, true, true, _facetTestContractAddress);
emit LiFiTransferStarted(bridgeData);
0xDEnYO marked this conversation as resolved.
Show resolved Hide resolved

// execute call in child contract
// TODO because there isnt any WORMHOLE pair on sushiswap
uint256 initialETHBalance = USER_SENDER.balance;
initiateSwapAndBridgeTxWithFacet(false);

// check balances after call
assertEq(
dai.balanceOf(USER_SENDER),
initialDAIBalance - swapData[0].fromAmount
);
assertEq(USER_SENDER.balance, initialETHBalance - addToMessageValue);
}

function initiateSwapAndBridgeTxWithFacet(bool) internal override {
@@ -277,35 +268,26 @@ contract GlacisFacetTest is TestBaseFacet {

function test_CanSwapAndBridgeAndPayFeeWithBridgedToken() public {}

// All facet test files inherit from `utils/TestBaseFacet.sol` and require the following method overrides:
// - function initiateBridgeTxWithFacet(bool isNative)
// - function initiateSwapAndBridgeTxWithFacet(bool isNative)
//
// These methods are used to run the following tests which must pass:
// - testBase_CanBridgeNativeTokens()
// - testBase_CanBridgeTokens()
// - testBase_CanBridgeTokens_fuzzed(uint256)
// - testBase_CanSwapAndBridgeNativeTokens()
// - testBase_CanSwapAndBridgeTokens()
// - testBase_Revert_BridgeAndSwapWithInvalidReceiverAddress()
// - testBase_Revert_BridgeToSameChainId()
// - testBase_Revert_BridgeWithInvalidAmount()
// - testBase_Revert_BridgeWithInvalidDestinationCallFlag()
// - testBase_Revert_BridgeWithInvalidReceiverAddress()
// - testBase_Revert_CallBridgeOnlyFunctionWithSourceSwapFlag()
// - testBase_Revert_CallerHasInsufficientFunds()
// - testBase_Revert_SwapAndBridgeToSameChainId()
// - testBase_Revert_SwapAndBridgeWithInvalidAmount()
// - testBase_Revert_SwapAndBridgeWithInvalidSwapData()
//
// In some cases it doesn't make sense to have all tests. For example the bridge may not support native tokens.
// In that case you can override the test method and leave it empty. For example:
//
// function testBase_CanBridgeNativeTokens() public override {
// // facet does not support bridging of native assets
// }
//
// function testBase_CanSwapAndBridgeNativeTokens() public override {
// // facet does not support bridging of native assets
// }
function testBase_Revert_CallerHasInsufficientFunds() public override {
vm.startPrank(USER_SENDER);

wormhole.approve(
address(_facetTestContractAddress),
defaultWORMHOLEAmount
);

// send all available W balance to different account to ensure sending wallet has no W funds
wormhole.transfer(USER_RECEIVER, wormhole.balanceOf(USER_SENDER));

vm.expectRevert(
abi.encodeWithSelector(
InsufficientBalance.selector,
bridgeData.minAmount,
0
)
);

initiateBridgeTxWithFacet(false);
vm.stopPrank();
}
}
11 changes: 11 additions & 0 deletions test/solidity/utils/Interfaces.sol
Original file line number Diff line number Diff line change
@@ -57,4 +57,15 @@ interface UniswapV2Router02 {
uint256 amountIn,
address[] calldata path
) external view returns (uint256[] memory amounts);

function addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB, uint liquidity);
}
26 changes: 26 additions & 0 deletions test/solidity/utils/TestBase.sol
Original file line number Diff line number Diff line change
@@ -443,6 +443,32 @@ abstract contract TestBase is Test, DiamondTest, ILiFi {
);
}

function addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired
) internal returns (uint amountA, uint amountB, uint liquidity) {
deal(tokenA, address(this), amountADesired);
deal(tokenB, address(this), amountBDesired);

ERC20(tokenA).approve(address(uniswap), amountADesired);
ERC20(tokenB).approve(address(uniswap), amountBDesired);

(amountA, amountB, liquidity) = uniswap.addLiquidity(
tokenA,
tokenB,
amountADesired,
amountBDesired,
0,
0,
address(this),
block.timestamp
);

return (amountA, amountB, liquidity);
}
mirooon marked this conversation as resolved.
Show resolved Hide resolved

//#region Utility Functions (may be used in tests)

function printBridgeData(ILiFi.BridgeData memory _bridgeData) internal {