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

Add new function selectors to MayanFacet [MayanFacet v1.1.0] #1032

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
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
10 changes: 10 additions & 0 deletions audit/auditLog.json
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,13 @@
"auditorGitHandle": "sujithsomraaj",
"auditReportPath": "./audit/reports/2025.02.20_CalldataVerificationFacet(v1.3.0).pdf",
"auditCommitHash": "48427d21160585f276d206f0e103ce6bd42c4c03"
},
"audit20250228": {
"auditCompletedOn": "28.02.2025",
"auditedBy": "Sujith Somraaj (individual security researcher)",
"auditorGitHandle": "sujithsomraaj",
"auditReportPath": "./audit/reports/2025.02.28_MayanFacet(v1.1.0).pdf",
"auditCommitHash": "be250763f57596d53d19a1af0988ed3ea351148e"
}
},
"auditedContracts": {
Expand Down Expand Up @@ -232,6 +239,9 @@
"LiFuelFeeCollector": {
"1.0.2": ["audit20250109_3"]
},
"MayanFacet": {
"1.1.0": ["audit20250228"]
},
"Permit2Proxy": {
"1.0.0": ["audit20241122"],
"1.0.1": ["audit20250110_1"],
Expand Down
Binary file added audit/reports/2025.02.28_MayanFacet(v1.1.0).pdf
Binary file not shown.
10 changes: 10 additions & 0 deletions deployments/_deployments_log_file.json
Original file line number Diff line number Diff line change
Expand Up @@ -24264,6 +24264,16 @@
"SALT": "",
"VERIFIED": "false"
}
],
"1.1.0": [
{
"ADDRESS": "0x6C96d5C36d9aDBD3F4e0337D2d1E133A59288D1A",
"OPTIMIZER_RUNS": "1000000",
"TIMESTAMP": "2025-02-28 09:07:01",
"CONSTRUCTOR_ARGS": "0x0000000000000000000000000654874eb7f59c6f5b39931fc45dc45337c967c3",
"SALT": "",
"VERIFIED": "true"
}
]
}
},
Expand Down
19 changes: 15 additions & 4 deletions deployments/arbitrum.diamond.staging.json
Original file line number Diff line number Diff line change
Expand Up @@ -138,12 +138,24 @@
"Version": "1.0.0"
},
"0xE15C7585636e62b88bA47A40621287086E0c2E33": {
"Name": "",
"Version": ""
"Name": "DeBridgeDlnFacet",
"Version": "1.0.0"
},
"0x08BfAc22A3B41637edB8A7920754fDb30B18f740": {
"Name": "AcrossFacetV3",
"Version": "1.1.0"
},
"0xF82830B952Bc60b93206FA22f1cD4770cedb2840": {
"Name": "",
"Version": ""
},
"0xDd661337B48BEA5194F6d26F2C59fF0855E15289": {
"Name": "",
"Version": ""
},
"0x6C96d5C36d9aDBD3F4e0337D2d1E133A59288D1A": {
"Name": "MayanFacet",
"Version": "1.1.0"
}
},
"Periphery": {
Expand All @@ -153,9 +165,8 @@
"GasZipPeriphery": "",
"LiFiDEXAggregator": "",
"LiFuelFeeCollector": "0x94EA56D8049e93E0308B9c7d1418Baf6A7C68280",
"Permit2Proxy": "0x6FC01BC9Ff6Cdab694Ec8Ca41B21a2F04C8c37E5",
"Permit2Proxy": "0xb33Fe241BEd9bf5F694101D7498F63a0d060F999",
"ReceiverAcrossV3": "0xe4F3DEF14D61e47c696374453CD64d438FD277F8",
"Receiver": "0x36E9B2E8A627474683eF3b1E9Df26D2bF04396f3",
"ReceiverStargateV2": "",
"RelayerCelerIM": "0xa1Ed8783AC96385482092b82eb952153998e9b70",
"TokenWrapper": "0xF63b27AE2Dc887b88f82E2Cc597d07fBB2E78E70"
Expand Down
3 changes: 1 addition & 2 deletions deployments/arbitrum.staging.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,8 @@
"WormholeFacet": "0x7260Fd3F8D0bEb06fF5935C6eadE9f406107c270",
"SymbiosisFacet": "0x21571D628B0bCBeb954D5933A604eCac35bAF2c7",
"DeBridgeDlnFacet": "0xE15C7585636e62b88bA47A40621287086E0c2E33",
"MayanFacet": "0xd596C903d78870786c5DB0E448ce7F87A65A0daD",
"MayanFacet": "0x6C96d5C36d9aDBD3F4e0337D2d1E133A59288D1A",
"StandardizedCallFacet": "0xA7ffe57ee70Ac4998e9E9fC6f17341173E081A8f",
"MayanFacet": "0xd596C903d78870786c5DB0E448ce7F87A65A0daD",
"GenericSwapFacetV3": "0xFf6Fa203573Baaaa4AE375EB7ac2819d539e16FF",
"CalldataVerificationFacet": "0x90B5b319cA20D9E466cB5b843952363C34d1b54E",
"AcrossFacetPacked": "0x7A3770a9504924d99D38BBba4F0116B756393Eb3",
Expand Down
16 changes: 13 additions & 3 deletions src/Facets/MayanFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,18 @@
pragma solidity ^0.8.17;

import { ILiFi } from "../Interfaces/ILiFi.sol";
import { LibDiamond } from "../Libraries/LibDiamond.sol";
import { LibAsset, IERC20 } from "../Libraries/LibAsset.sol";
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import { LibSwap } from "../Libraries/LibSwap.sol";
import { ReentrancyGuard } from "../Helpers/ReentrancyGuard.sol";
import { SwapperV2 } from "../Helpers/SwapperV2.sol";
import { Validatable } from "../Helpers/Validatable.sol";
import { IMayan } from "../Interfaces/IMayan.sol";
import { UnsupportedChainId } from "../Errors/GenericErrors.sol";

/// @title Mayan Facet
/// @author LI.FI (https://li.fi)
/// @notice Provides functionality for bridging through Mayan Bridge
/// @custom:version 1.0.0
/// @custom:version 1.1.0
contract MayanFacet is ILiFi, ReentrancyGuard, SwapperV2, Validatable {
/// Storage ///

Expand Down Expand Up @@ -244,6 +242,18 @@ contract MayanFacet is ILiFi, ReentrancyGuard, SwapperV2, Validatable {
// 0x8e8d142b createOrderWithToken(address,uint256,(bytes32,bytes32,uint64,uint64,uint64,uint64,uint64,[*bytes32*],uint16,bytes32,uint8,uint8,bytes32))
receiver := mload(add(protocolData, 0x144)) // MayanSwift::createOrderWithToken()
}
case 0x1c59b7fc {
// 0x1c59b7fc MayanCircle::createOrder((address,uint256,uint64,bytes32,uint16,bytes32,uint64,uint64,uint64,bytes32,uint8))
receiver := mload(add(protocolData, 0x84))
}
case 0x9be95bb4 {
// 0x9be95bb4 MayanCircle::bridgeWithLockedFee(address,uint256,uint64,uint256,uint32,bytes32)
receiver := mload(add(protocolData, 0xc4))
}
case 0x2072197f {
// 0x2072197f MayanCircle::bridgeWithFee(address,uint256,uint64,uint64,bytes32,uint32,uint8,bytes)
receiver := mload(add(protocolData, 0xa4))
}
default {
receiver := 0x0
}
Expand Down
164 changes: 162 additions & 2 deletions test/solidity/Facets/MayanFacet.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@ contract TestMayanFacet is MayanFacet {
}
}

/// @notice This contract exposes _parseReceiver for testing purposes.
contract TestMayanFacetExposed is MayanFacet {
constructor(IMayan _mayan) MayanFacet(_mayan) {}

/// @dev Exposes the internal _parseReceiver function.
function testParseReceiver(
bytes memory protocolData
) public pure returns (bytes32) {
return _parseReceiver(protocolData);
}
}

contract MayanFacetTest is TestBaseFacet {
MayanFacet.MayanData internal validMayanData;
MayanFacet.MayanData internal validMayanDataNative;
Expand All @@ -28,11 +40,22 @@ contract MayanFacetTest is TestBaseFacet {
IMayan(0x0654874eb7F59C6f5b39931FC45dC45337c967c3);
address internal POLYGON_USDT = 0xc2132D05D31c914a87C6611C10748AEb04B58e8F;
address DEV_WALLET = 0x29DaCdF7cCaDf4eE67c923b4C22255A4B2494eD7;
address internal NON_EVM_ADDRESS =
0x11f111f111f111F111f111f111F111f111f111F1;

bytes32 ACTUAL_SOL_ADDR =
hex"4cb7c5f1632114c376c0e7a9a1fd1fbd562699fbd9a0c9f4f26ba8cf6e23df0d"; // [pre-commit-checker: not a secret]
bytes32 EXPECTED_SOL_ADDR = bytes32("EXPECTED ADDRESS");

error InvalidReceiver(address expected, address actual);
error InvalidNonEVMReceiver(bytes32 expected, bytes32 actual);

event BridgeToNonEVMChain(
bytes32 indexed transactionId,
uint256 indexed destinationChainId,
bytes32 receiver
);

function setUp() public {
customBlockNumberForForking = 19968172;
initTestBase();
Expand Down Expand Up @@ -286,8 +309,8 @@ contract MayanFacetTest is TestBaseFacet {
super.testBase_CanBridgeTokens_fuzzed(amount);
}

function test_RevertsIfNonEVMReceiverIsIncorrect() public {
bridgeData.receiver = 0x11f111f111f111F111f111f111F111f111f111F1;
function testRevert_FailsIfNonEVMReceiverIsIncorrect() public {
bridgeData.receiver = NON_EVM_ADDRESS;
validMayanData = invalidMayanDataEVM2Solana;
vm.startPrank(USER_SENDER);

Expand Down Expand Up @@ -383,4 +406,141 @@ contract MayanFacetTest is TestBaseFacet {
defaultNativeAmount += 0.123456789 ether;
testBase_CanSwapAndBridgeNativeTokens();
}

function test_CanBridgeNativeTokens2() public {
vm.startPrank(USER_SENDER);
// store initial balances
uint256 initialBalance = USER_SENDER.balance;

// prepare bridgeData
bridgeData.receiver = NON_EVM_ADDRESS;
bridgeData.sendingAssetId = address(0);
bridgeData.minAmount = 1 ether;

validMayanDataNative = MayanFacet.MayanData(
bytes32(
0x0000000000000000000000000000000000000000000000000000000abc654321
),
0xBF5f3f65102aE745A48BD521d10BaB5BF02A9eF4, // mayanProtocol address
// Calldata generated from Mayan SDK 1 ETH -> USDT on Polygon
hex"1eb1cff00000000000000000000000000000000000000000000000000000000000013e0b0000000000000000000000000000000000000000000000000000000000004df200000000000000000000000000000000000000000000000000000000000a42dfcb617b639c537bd08846f61be4481c34f9391f1b8f53d082de024e232508113e00000000000000000000000000000000000000000000000000000000000000016dfa43f824c3b8b61e715fe8bf447f2aba63e59ab537f186cf665152c2114c390000000000000000000000000000000000000000000000000000000abC654321000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000abC654321000000000000000000000000c2132d05d31c914a87c6611c10748aeb04b58e8f000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000006655d880000000000000000000000000000000000000000000000000000000006655d88000000000000000000000000000000000000000000000000000000000e16ffab40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000000"
);

vm.expectEmit(true, true, true, true, _facetTestContractAddress);
emit BridgeToNonEVMChain(
bridgeData.transactionId,
bridgeData.destinationChainId,
validMayanDataNative.nonEVMReceiver
);

// execute call in child contract
initiateBridgeTxWithFacet(true);

// check balances after call
assertEq(USER_SENDER.balance, initialBalance - 1 ether);
}

function testRevert_FailsWhenNonEVMChainIntentionAndNonEVMReceiverIsEmpty()
public
{
vm.startPrank(USER_SENDER);

usdc.approve(_facetTestContractAddress, type(uint256).max);

bridgeData.receiver = NON_EVM_ADDRESS; // nonEVMAddress

vm.expectRevert(
abi.encodeWithSelector(
InvalidNonEVMReceiver.selector,
bytes32(0),
bytes32(0)
)
);

initiateBridgeTxWithFacet(false);

vm.stopPrank();
}

function testRevert_FailsWhenBridgeDataReceiverDoesNotMatchMayanProtocolReceiver()
public
{
vm.startPrank(USER_SENDER);

usdc.approve(_facetTestContractAddress, type(uint256).max);

bridgeData.receiver = DEV_WALLET;

validMayanData = MayanFacet.MayanData(
"",
0xBF5f3f65102aE745A48BD521d10BaB5BF02A9eF4, // mayanProtocol address
// Calldata generated from Mayan SDK 4.12312312 USDC on Mainnet -> Arbitrum
hex"6222ad25000000000000000000000000000000000000000000000000000000000f52ae0e000000000000000000000000000000000000000000000000000000000000f2d000000000000000000000000000000000000000000000000000000000018eb30afc7fcf68097cd0584877939477347b5b8fa10efee2e29805370a35fd2a22ee9500000000000000000000000000000000000000000000000000000000000000016dfa43f824c3b8b61e715fe8bf447f2aba63e59ab537f186cf665152c2114c3900000000000000000000000029dacdf7ccadf4ee67c923b4c22255a4b2494ed700000000000000000000000000000000000000000000000000000000000000171e8c4fab8994494c8f1e5c1287445b2917d60c43c79aa959162f5d6000598d3200000000000000000000000029dacdf7ccadf4ee67c923b4c22255a4b2494ed7000000000000000000000000af88d065e77c8cc2239327c5edb3a432268e5831000000000000000000000000000000000000000000000000000000000000001700000000000000000000000000000000000000000000000000000000000001e00000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d000000000000000000000000000000000000000000000000393846a1e4cce00000000000000000000000000000000000000000000000000000000000667d7a7a00000000000000000000000000000000000000000000000000000000667d7a7a0000000000000000000000000000000000000000000000000000000000177f850000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000000"
);
// invalid protocolData that produces wrong receiver for payload

vm.expectRevert(
abi.encodeWithSelector(
InvalidReceiver.selector,
DEV_WALLET,
address(0)
)
);

initiateBridgeTxWithFacet(false);

vm.stopPrank();
}

function test_ParseReceiver() public {
TestMayanFacetExposed testFacet = new TestMayanFacetExposed(
IMayan(address(0))
);

address expectedReceiver = 0x1eB6638dE8c571c787D7bC24F98bFA735425731C;

// test for 0x94454a5d bridgeWithFee(address,uint256,uint64,uint64,[*bytes32*],(uint32,bytes32,bytes32))
// test for 0x32ad465f bridgeWithLockedFee(address,uint256,uint64,uint256,(uint32,[*bytes32*],bytes32))
// test for 0xafd9b706 createOrder((address,uint256,uint64,[*bytes32*],uint16,bytes32,uint64,uint64,uint64,bytes32,uint8),(uint32,bytes32,bytes32))
// test for 0x6111ad25 swap((uint64,uint64,uint64),(bytes32,uint16,bytes32,[*bytes32*],uint16,bytes32,bytes32),bytes32,uint16,(uint256,uint64,uint64,bool,uint64,bytes),address,uint256)
// test for 0x1eb1cff0 wrapAndSwapETH((uint64,uint64,uint64),(bytes32,uint16,bytes32,[*bytes32*],uint16,bytes32,bytes32),bytes32,uint16,(uint256,uint64,uint64,bool,uint64,bytes))
// test for 0xb866e173 createOrderWithEth((bytes32,bytes32,uint64,uint64,uint64,uint64,uint64,[*bytes32*],uint16,bytes32,uint8,uint8,bytes32))
// test for 0x8e8d142b createOrderWithToken(address,uint256,(bytes32,bytes32,uint64,uint64,uint64,uint64,uint64,[*bytes32*],uint16,bytes32,uint8,uint8,bytes32))

// test for 0x1c59b7fc MayanCircle::createOrder((address,uint256,uint64,bytes32,uint16,bytes32,uint64,uint64,uint64,bytes32,uint8))
// example tenderly: https://dashboard.tenderly.co/tx/arbitrum/0x3bffa9aa20062cd21e0f4d40333214ce23e382d308180fc20ddd6c405bff2649/debugger?trace=0.3.0
bytes memory protocolData = vm.parseBytes(
"0x1c59b7fc000000000000000000000000af88d065e77c8cc2239327c5edb3a432268e583100000000000000000000000000000000000000000000000000000000004c4b4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001eb6638de8c571c787d7bc24f98bfa735425731c000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023e290000000000000000000000000000000000000000000000000000000067c1b1f500000000000000000000000000000000000000000000000000000000001c497b000000000000000000000000a5aa6e2171b416e1d27ec53ca8c13db3f91a89cd0000000000000000000000000000000000000000000000000000000000000000"
);
bytes32 receiver = testFacet.testParseReceiver(protocolData);
assertEq(
address(uint160(uint256(receiver))),
expectedReceiver,
"parse receiver test failure for 0x1c59b7fc MayanCircle::createOrder((address,uint256,uint64,bytes32,uint16,bytes32,uint64,uint64,uint64,bytes32,uint8))"
);

// test for 0x9be95bb4 MayanCircle::bridgeWithLockedFee(address,uint256,uint64,uint256,uint32,bytes32)
// example tenderly: https://dashboard.tenderly.co/tx/arbitrum/0x8ad553f8059efcb7fd84130e5625e4b2fdc3ea34461227e1e4a983053e12790c/debugger?trace=0.3
protocolData = vm.parseBytes(
"0x9be95bb4000000000000000000000000af88d065e77c8cc2239327c5edb3a432268e583100000000000000000000000000000000000000000000000000000000004c4b40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000df8e600000000000000000000000000000000000000000000000000000000000000000000000000000000000000001eb6638de8c571c787d7bc24f98bfa735425731c"
);
receiver = testFacet.testParseReceiver(protocolData);
assertEq(
address(uint160(uint256(receiver))),
expectedReceiver,
"parse receiver test failure for 0x9be95bb4 MayanCircle::bridgeWithLockedFee(address,uint256,uint64,uint256,uint32,bytes32)"
);

// test for 0x2072197f MayanCircle::bridgeWithFee(address,uint256,uint64,uint64,bytes32,uint32,uint8,bytes)
// example tenderly: https://dashboard.tenderly.co/tx/arbitrum/0xa12ac33dcc79c4185a484095764772f8169fee8228c614892843e2f8df685a98/debugger?trace=0
protocolData = vm.parseBytes(
"0x2072197f000000000000000000000000af88d065e77c8cc2239327c5edb3a432268e583100000000000000000000000000000000000000000000000000000000004c4b400000000000000000000000000000000000000000000000000000000000000b4400000000000000000000000000000000000000000000000000000000000000000000000000000000000000001eb6638de8c571c787d7bc24f98bfa735425731c0000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000"
);
receiver = testFacet.testParseReceiver(protocolData);
assertEq(
address(uint160(uint256(receiver))),
expectedReceiver,
"parse receiver test failure for 0x2072197f MayanCircle::bridgeWithFee(address,uint256,uint64,uint64,bytes32,uint32,uint8,bytes)"
);
}
}
Loading