Proof of Concept Cross-Chain Bridge Secured by EigenLayer

Build Status License Docs

Developer Documentation

For detailed developer documentation, please visit our GitHub Pages site. This site is autogenerated from the code and provides comprehensive information about the project's structure, functions, and usage.

Overview

This project is a proof of concept for a decentralized bridge secured with attestations by EigenLayer's AVS operators. The goal is to demonstrate how EigenLayer can be used to secure cross-chain token transfers without direct communication between chains. Arbitrary message passing allows not only instantaneous settlement but also the ability to transfer between non VM-compatible chains such as Ethereum and Solana, or Bitcoin.

What is EigenLayer?

EigenLayer is a protocol that allows operators to receive delegated stake in order to secure various applications (such as applications relying on off-chain state). Operators are incentivized through application rewards and penalized through stake slashing if they act maliciously.

EigenLayer relies on at least one smart contract interacting with the EigenLayer protocol, that registers and tracks operators and their stake, as well as defines the rules for rewards and penalties.

Objective

This proof of concept aims to showcase the potential of EigenLayer in securing decentralized bridges. It includes smart contracts that handle bridging operations, attestation verification, and slashing mechanisms.

Project Structure

  • Contracts:

    • ECDSAUtils.sol: Provides ECDSA signature utilities.
    • BridgeServiceManager.sol: Manages bridge operations and attestation validations.
    • PermissionedBridge.sol: Manages bridge operations with manually set operator weights.
    • Events.sol: Contains event definitions for bridge operations.
    • Structs.sol: Defines structs and related functions for bridge operations.
    • Vault.sol: Abstract contract providing common vault functionality for bridge contracts.
  • Tests:

    • EigenLayerBridge.t.sol: Tests for BridgeServiceManager.sol.
    • PermissionedBridge.t.sol: Tests for PermissionedBridge.sol.

Getting Started

Prerequisites

Installation

  1. Clone the repository:

    git clone https://github.com/your-repo/eigenlayer-bridge.git
    cd eigenlayer-bridge
    
  2. Install Foundry:

    curl -L https://foundry.paradigm.xyz | bash
    foundryup
    

Running Tests

To run the tests, use the Foundry framework. Running the tests requires an HTTP endpoint to Ethereum mainnet.

The tests use an anvil fork-test from latest Ethereum mainnet state in order to simulate a realistic environment and test against the EigenLayer contracts deployed there.

forge test --rpc-url <RPC_URL>

Detailed Explanations

ECDSA Signature Verification

The ECDSAUtils contract provides utilities for verifying ECDSA signatures. These utilities are essential for ensuring the authenticity and integrity of the bridge request data. The process involves two main functions:

  1. getDigest: Computes the EIP712 digest of the bridge request data, which is used for signing.
  2. getSigner: Recovers the signer's address from the given bridge request data and signature.

Example Function: getDigest

This function computes the EIP712 digest for the given bridge request data, ensuring that the data can be signed in a standardized and secure way.

function getDigest(Structs.BridgeRequestData memory data) public view returns (bytes32) {
    return _hashTypedDataV4(
        keccak256(
            abi.encode(
                keccak256(
                    "BridgeRequestData(address user,address tokenAddress,uint256 amountIn,uint256 amountOut,address destinationVault,address destinationAddress,uint256 transferIndex)"
                ),
                data.user,
                data.tokenAddress,
                data.amountIn,
                data.amountOut,
                data.destinationVault,
                data.destinationAddress,
                data.transferIndex
            )
        )
    );
}

Attestation Mechanism

The attestation mechanism leverages EigenLayer's AVS operators to secure the bridge. Here's a detailed explanation of the process:

  1. Bridge Request Creation: A user creates a bridge request, which is stored on-chain and emits an event for operators to observe.
  2. Signature Collection: AVS operators observe the bridge request event and sign the request data using their private keys. These signatures are then submitted back to the bridge contract.
  3. Attestation Verification: The bridge contract verifies these signatures to ensure they are from valid operators with sufficient stake.
  4. Fund Release: Once the contract verifies that enough valid signatures (attestations) have been collected, it releases the funds to the destination address.

Example Function: publishAttestation

This function allows an AVS operator to publish an attestation for a bridge request. It verifies the operator's weight and ensures no double attestations for the same request.

function publishAttestation(bytes memory attestation, uint256 _bridgeRequestId) public nonReentrant onlyOperator {
    require(operatorHasMinimumWeight(msg.sender), "Operator does not have minimum weight");
    require(!operatorResponses[msg.sender][_bridgeRequestId], "Operator has already responded to the task");
    require(msg.sender == getSigner(bridgeRequests[_bridgeRequestId], attestation), "Invalid attestation signature");

    uint256 operatorWeight = getOperatorWeight(msg.sender);
    bridgeRequestWeights[_bridgeRequestId] += operatorWeight;

    rewardAttestation(msg.sender);

    emit AVSAttestation(attestation, _bridgeRequestId, operatorWeight);
}

Fund Release Process

The fund release process is critical to ensuring that the bridge operates securely and efficiently. The process involves the following steps:

  1. Signature Verification: The contract verifies that the submitted signatures are valid and from authorized operators.
  2. Weight Calculation: It sums the weights of the valid signatures to ensure that the total weight meets or exceeds the required threshold.
  3. Fund Transfer: If the total weight is sufficient, the contract transfers the funds to the destination address.
  4. Incentivizing Validators: The contract pays out gas costs and a small incentive to the caller who initiates the fund release, encouraging users to participate in this final step.

Example Function: releaseFunds

This function releases the funds to the destination address once the required attestations are verified. It ensures the transaction's economic security by checking the total attested weight.

function releaseFunds(bytes[] memory signatures, Structs.BridgeRequestData memory data) public nonReentrant {
    uint256 totalWeight = 0;
    for (uint256 i = 0; i < signatures.length; i++) {
        address signer = getSigner(data, signatures[i]);
        require(operatorResponses[signer][data.transferIndex], "Invalid signature");
        totalWeight += getOperatorWeight(signer);
    }

    require(totalWeight >= data.amountOut, "Insufficient total weight to cover swap");
    IERC20(data.tokenAddress).transfer(data.destinationAddress, data.amountOut);

    payoutCrankGasCost();

    emit FundsReleased(data.tokenAddress, data.destinationAddress, data.amountOut);
}

AVS Interactions

EigenLayer's AVS operators play a crucial role in the security of the bridge. These operators:

  1. Monitor: Observe events emitted by the bridge contract to detect new bridge requests.
  2. Sign: Validate the bridge request and provide their signature as an attestation.
  3. Submit: Send their attestations back to the bridge contract.
  4. Get Rewarded: Receive rewards for valid attestations and get penalized for any malicious activities through slashing.

These interactions ensure that the bridge is both secure and decentralized, relying on the collective security provided by the EigenLayer's staked operators.

Testing

Introduction

This section covers the testing of our smart contracts using the Forge test framework. The tests are written in Solidity and simulate various scenarios to ensure the correctness of the bridge operations and attestation mechanisms.

Setting Up the Test Environment

The test environment is set up using the setUp function in each test contract. This function initializes the contract instances, allocates initial balances, and configures the necessary parameters.

Example Setup Function

function setUp() public {
    (operator, operatorPrivateKey) = makeAddrAndKey("operator");

    localVault = new BridgeServiceManager(
        aVSDirectory, stakeRegistry, rewardsCoordinator, delegationManager,
        crankGasCost, 0, bridgeFee, "PermissionedBridge", "1"
    );
    localVault.initialize();

    remoteVault = new BridgeServiceManager(
        aVSDirectory, stakeRegistry, rewardsCoordinator, delegationManager,
        crankGasCost, 0, bridgeFee, "PermissionedBridge", "1"
    );
    remoteVault.initialize();

    deal(bob, 1 ether);
    deal(usdc, bob, 1000 * 10**6);
    deal(usdc, address(remoteVault), 1000 * 10**6);
    deal(operator, 1 ether);
}

Test Cases

Test Case 1: Bridge Request Emission

This test case ensures that a bridge request emits the correct events when created.

function testBridgeRequestEmitEvents() public returns (Structs.BridgeRequestData memory) {
    vm.startPrank(bob);

    IERC20(usdc).approve(address(localVault), 1000 * 10**6);

    vm.expectEmit(true, true, true, true);
    emit Events.BridgeRequest(bob, usdc, 0, 1000 * 10**6, 1000 * 10**6, address(remote

Vault), alice, 0);

    localVault.bridge{value: bridgeFee}(usdc, 1000 * 10**6, 1000 * 10**6, address(remoteVault), alice);

    vm.stopPrank();

    return Structs.BridgeRequestData(
        bob,
        usdc,
        1000 * 10**6,
        1000 * 10**6,
        address(remoteVault),
        alice,
        0
    );
}

Test Case 2: Operator Attestation Submission

This test case verifies that an operator can submit an attestation for a bridge request.

function testOperatorCanSubmitAttestation() public {
    testBridgeRequestEmitEvents();

    (
    address user,
    address tokenAddress,
    uint256 amountIn,
    uint256 amountOut,
    address destinationVault,
    address destinationAddress,
    uint256 transferIndex
    ) = localVault.bridgeRequests(0);

    Structs.BridgeRequestData memory bridgeRequest = Structs.BridgeRequestData(
        user,
        tokenAddress,
        amountIn,
        amountOut,
        destinationVault,
        destinationAddress,
        transferIndex
    );

    bytes memory attestation = signBridgeRequestData(localVault, bridgeRequest, operatorPrivateKey);

    vm.prank(operator);
    vm.expectEmit(true, true, true, true);
    emit Events.AVSAttestation(attestation, 0, 1000 ether);

    localVault.publishAttestation(attestation, 0);
}

Test Case 3: Fund Release Completion

This test case ensures that the bridge completes and releases funds correctly.

function testBridgeCompletesReleaseFunds() public {
    testBridgeRequestEmitEvents();

    (
        address user,
        address tokenAddress,
        uint256 amountIn,
        uint256 amountOut,
        address destinationVault,
        address destinationAddress,
        uint256 transferIndex
    ) = localVault.bridgeRequests(0);

    Structs.BridgeRequestData memory bridgeRequest = Structs.BridgeRequestData(
        user,
        tokenAddress,
        amountIn,
        amountOut,
        destinationVault,
        destinationAddress,
        transferIndex
    );

    bytes memory attestation = signBridgeRequestData(remoteVault, bridgeRequest, operatorPrivateKey);
    bytes[] memory bridgeRequestSignatures = new bytes[](1);
    bridgeRequestSignatures[0] = attestation;

    assertEq(IERC20(usdc).balanceOf(address(remoteVault)), 1000 * 10**6);
    assertEq(IERC20(usdc).balanceOf(alice), 0);

    vm.prank(alice);
    remoteVault.releaseFunds(bridgeRequestSignatures, bridgeRequest);

    assertEq(IERC20(usdc).balanceOf(address(remoteVault)), 0);
    assertEq(IERC20(usdc).balanceOf(alice), 1000 * 10**6);
}

License

This project is licensed under the UNLICENSED License.

Disclaimer

This project is provided "as is" with no guarantees or warranties. It is intended as a proof of concept only and should not be used in production environments. Use at your own risk.

BridgeServiceManager

Git Source

Inherits: ECDSAServiceManagerBase, Vault

Manages bridge operations and attestation validations

Extends ECDSAServiceManagerBase and Vault for bridging and staking functionality

State Variables

operatorResponses

Tracks bridge requests that this operator has responded to once to avoid duplications

Double attestations would technically be valid and allow operators to recursively call until funds are released

mapping(address => mapping(uint256 => bool)) public operatorResponses;

bridgeRequestWeights

Tracks the total operator weight attested to a bridge request

Helpful for determining when enough attestations have been collected to release funds.

mapping(uint256 => uint256) public bridgeRequestWeights;

Functions

constructor

Initializes the contract with the necessary addresses and parameters

constructor(
    address _avsDirectory,
    address _stakeRegistry,
    address _rewardsCoordinator,
    address _delegationManager,
    uint256 _crankGasCost,
    uint256 _AVSReward,
    uint256 _bridgeFee,
    string memory _name,
    string memory _version
)
    ECDSAServiceManagerBase(_avsDirectory, _stakeRegistry, _rewardsCoordinator, _delegationManager)
    Vault(_crankGasCost, _AVSReward, _bridgeFee, _name, _version);

Parameters

NameTypeDescription
_avsDirectoryaddressThe address of the AVS directory contract, managing AVS-related data for registered operators
_stakeRegistryaddressThe address of the stake registry contract, managing registration and stake recording
_rewardsCoordinatoraddressThe address of the rewards coordinator contract, handling rewards distributions
_delegationManageraddressThe address of the delegation manager contract, managing staker delegations to operators
_crankGasCostuint256The estimated gas cost for calling release funds, used to calculate rebate and incentivize users to call
_AVSRewarduint256The total reward for AVS attestation
_bridgeFeeuint256The total fee charged to the user for bridging
_namestringThe name of the contract, used for EIP-712 domain construction
_versionstringThe version of the contract, used for EIP-712 domain construction

onlyOperator

Ensures that only registered operators can call the function

modifier onlyOperator();

rewardAttestation

Rewards the operator for providing a valid attestation

Placeholder for actual AVS reward distribution pending Eigen M2 implementation

function rewardAttestation(address operator) internal;

Parameters

NameTypeDescription
operatoraddressThe address of the operator to be rewarded

publishAttestation

Publishes an attestation for a bridge request

function publishAttestation(bytes memory attestation, uint256 _bridgeRequestId) public nonReentrant onlyOperator;

Parameters

NameTypeDescription
attestationbytesThe signed attestation
_bridgeRequestIduint256The ID of the bridge request

slashMaliciousAttestor

Slashes a malicious attestor's stake

Placeholder for slashing logic pending Eigen implementations

function slashMaliciousAttestor(address operator, uint256 penalty) internal;

Parameters

NameTypeDescription
operatoraddressThe address of the operator to be slashed
penaltyuint256The penalty amount to be slashed

challengeAttestation

Challenges a potentially fraudulent attestation

function challengeAttestation(
    bytes memory fraudulentSignature,
    Structs.BridgeRequestData memory fraudulentBridgeRequest
) public nonReentrant;

Parameters

NameTypeDescription
fraudulentSignaturebytesThe signature of the fraudulent attestation
fraudulentBridgeRequestStructs.BridgeRequestDataThe data of the fraudulent bridge request

payoutCrankGasCost

Payouts the crank gas cost to the caller

function payoutCrankGasCost() internal;

_releaseFunds

Releases funds to the destination address

function _releaseFunds(bytes memory data) public override nonReentrant;

Parameters

NameTypeDescription
databytesThe bridge request data and signatures

releaseFunds

Releases funds to the destination address with typed data for ABI construction

function releaseFunds(bytes[] memory signatures, Structs.BridgeRequestData memory data) public nonReentrant;

Parameters

NameTypeDescription
signaturesbytes[]The signatures of the operators attesting to the bridge request
dataStructs.BridgeRequestDataThe bridge request data

operatorHasMinimumWeight

Checks if the operator has the minimum required weight

function operatorHasMinimumWeight(address operator) public view returns (bool);

Parameters

NameTypeDescription
operatoraddressThe address of the operator

Returns

NameTypeDescription
<none>boolTrue if the operator has the minimum weight, false otherwise

getOperatorWeight

Gets the weight of an operator

function getOperatorWeight(address operator) public view returns (uint256);

Parameters

NameTypeDescription
operatoraddressThe address of the operator

Returns

NameTypeDescription
<none>uint256The weight of the operator

receive

Fallback function to receive ether

receive() external payable;

ECDSAUtils

Git Source

Inherits: EIP712

Provides ECDSA signature utilities for verifying bridge request data

Functions

constructor

Initializes the EIP712 domain with the given name and version

constructor(string memory name, string memory version) EIP712(name, version);

Parameters

NameTypeDescription
namestringThe user-readable name of the signing domain
versionstringThe current major version of the signing domain

getDigest

Computes the EIP712 digest for the given bridge request data

function getDigest(Structs.BridgeRequestData memory data) public view returns (bytes32);

Parameters

NameTypeDescription
dataStructs.BridgeRequestDataThe bridge request data to be hashed

Returns

NameTypeDescription
<none>bytes32The EIP712 hash of the given bridge request data

getSigner

Recovers the signer address from the given bridge request data and signature

function getSigner(Structs.BridgeRequestData memory data, bytes memory signature) public view returns (address);

Parameters

NameTypeDescription
dataStructs.BridgeRequestDataThe bridge request data that was signed
signaturebytesThe ECDSA signature

Returns

NameTypeDescription
<none>addressThe address of the signer

Events

Git Source

Contains event definitions for bridge operations

Events

BridgeRequest

Emitted when a new bridge request is created

event BridgeRequest(
    address indexed user,
    address indexed tokenAddress,
    uint256 indexed bridgeRequestId,
    uint256 amountIn,
    uint256 amountOut,
    address destinationVault,
    address destinationAddress,
    uint256 transferIndex
);

Parameters

NameTypeDescription
useraddressThe address of the user initiating the bridge request
tokenAddressaddressThe address of the token to be bridged
bridgeRequestIduint256The unique ID of the bridge request
amountInuint256The amount of tokens to be bridged
amountOutuint256The amount of tokens expected at the destination
destinationVaultaddressThe address of the destination vault
destinationAddressaddressThe address of the recipient at the destination
transferIndexuint256The transfer index for unique tracking

AVSAttestation

Emitted when an attestation is published by an AVS operator

event AVSAttestation(bytes indexed attestation, uint256 indexed bridgeRequestId, uint256 indexed operatorWeight);

Parameters

NameTypeDescription
attestationbytesThe attestation data
bridgeRequestIduint256The ID of the bridge request
operatorWeightuint256The weight of the operator attesting

FundsReleased

Emitted when funds are released to the destination address

event FundsReleased(address indexed destinationVault, address indexed destinationAddress, uint256 indexed amountOut);

Parameters

NameTypeDescription
destinationVaultaddressThe address of the destination vault
destinationAddressaddressThe address of the recipient at the destination
amountOutuint256The amount of tokens released

PermissionedBridge

Git Source

Inherits: Vault

Manages bridge operations with manually set operator weights

Extends Vault for bridging functionality

State Variables

operatorResponses

Tracks bridge requests that this operator has responded to once to avoid duplications

Double attestations would technically be valid and allow operators to recursively call until funds are released

mapping(address => mapping(uint256 => bool)) public operatorResponses;

bridgeRequestWeights

Tracks the total operator weight attested to a bridge request

Helpful for determining when enough attestations have been collected to release funds.

mapping(uint256 => uint256) public bridgeRequestWeights;

operatorWeights

Maps operator addresses to their respective weights

Temporary solution for illustrative purposes on non-mainnet chains

mapping(address => uint256) public operatorWeights;

Functions

constructor

Initializes the contract with the necessary parameters

constructor(uint256 _crankGasCost, uint256 _AVSReward, uint256 _bridgeFee, string memory _name, string memory _version)
    Vault(_crankGasCost, _AVSReward, _bridgeFee, _name, _version);

Parameters

NameTypeDescription
_crankGasCostuint256The estimated gas cost for calling release funds, used to calculate rebate and incentivize users to call
_AVSRewarduint256The total reward for AVS attestation
_bridgeFeeuint256The total fee charged to the user for bridging
_namestringThe name of the contract, used for EIP-712 domain construction
_versionstringThe version of the contract, used for EIP-712 domain construction

onlyOperator

Ensures that only operators with non-zero weight can call the function

modifier onlyOperator();

publishAttestation

Publishes an attestation for a bridge request

function publishAttestation(bytes memory attestation, uint256 _bridgeRequestId) public nonReentrant onlyOperator;

Parameters

NameTypeDescription
attestationbytesThe signed attestation
_bridgeRequestIduint256The ID of the bridge request

_releaseFunds

Releases funds to the destination address

function _releaseFunds(bytes memory data) public override nonReentrant;

Parameters

NameTypeDescription
databytesThe bridge request data and signatures

releaseFunds

Releases funds to the destination address with typed data for ABI construction

function releaseFunds(bytes[] memory signatures, Structs.BridgeRequestData memory data) public nonReentrant;

Parameters

NameTypeDescription
signaturesbytes[]The signatures of the operators attesting to the bridge request
dataStructs.BridgeRequestDataThe bridge request data

operatorHasMinimumWeight

Checks if the operator has the minimum required weight

function operatorHasMinimumWeight(address operator) public view returns (bool);

Parameters

NameTypeDescription
operatoraddressThe address of the operator

Returns

NameTypeDescription
<none>boolTrue if the operator has the minimum weight, false otherwise

getOperatorWeight

Gets the weight of an operator

function getOperatorWeight(address operator) public view returns (uint256);

Parameters

NameTypeDescription
operatoraddressThe address of the operator

Returns

NameTypeDescription
<none>uint256The weight of the operator

setOperatorWeight

Sets the weight of an operator

function setOperatorWeight(address operator, uint256 weight) public onlyOwner;

Parameters

NameTypeDescription
operatoraddressThe address of the operator
weightuint256The new weight of the operator

receive

Fallback function to receive ether

receive() external payable;

Structs

Git Source

Contains struct definitions and related functions for bridge operations

Functions

hash

Computes the hash of the bridge request data

function hash(BridgeRequestData memory data) internal pure returns (bytes32);

Parameters

NameTypeDescription
dataBridgeRequestDataThe bridge request data to be hashed

Returns

NameTypeDescription
<none>bytes32The hash of the given bridge request data

Structs

BridgeRequestData

Structure representing bridge request data

struct BridgeRequestData {
    address user;
    address tokenAddress;
    uint256 amountIn;
    uint256 amountOut;
    address destinationVault;
    address destinationAddress;
    uint256 transferIndex;
}

Properties

NameTypeDescription
useraddressThe address of the user initiating the bridge request
tokenAddressaddressThe address of the token to be bridged
amountInuint256The amount of tokens to be bridged
amountOutuint256The amount of tokens expected at the destination
destinationVaultaddressThe address of the destination vault
destinationAddressaddressThe address of the recipient at the destination
transferIndexuint256The transfer index for unique tracking

Vault

Git Source

Inherits: ECDSAUtils, Events, ReentrancyGuard, OwnableUpgradeable

Abstract contract providing common vault functionality for bridge contracts

State Variables

nextUserTransferIndexes

Stores the transfer index for each user for unique transfer tracking

mapping(address => uint256) public nextUserTransferIndexes;

currentBridgeRequestId

Global unique bridge request ID

uint256 public currentBridgeRequestId;

bridgeRequests

Stores history of bridge requests

mapping(uint256 => Structs.BridgeRequestData) public bridgeRequests;

bridgeFee

Total fee charged to the user for bridging

uint256 public bridgeFee;

AVSReward

Total reward for AVS attestation

uint256 public AVSReward;

crankGasCost

Estimated gas cost for calling release funds, used to calculate rebate and incentivize users to call

uint256 public crankGasCost;

deployer

Address of the contract deployer

address deployer;

Functions

constructor

Initializes the contract with the necessary parameters

constructor(uint256 _crankGasCost, uint256 _AVSReward, uint256 _bridgeFee, string memory _name, string memory _version)
    ECDSAUtils(_name, _version);

Parameters

NameTypeDescription
_crankGasCostuint256The estimated gas cost for calling release funds, used to calculate rebate and incentivize users to call
_AVSRewarduint256The total reward for AVS attestation
_bridgeFeeuint256The total fee charged to the user for bridging
_namestringThe name of the contract, used for EIP-712 domain construction
_versionstringThe version of the contract, used for EIP-712 domain construction

initialize

Initializes the contract and transfers ownership to the deployer

function initialize() public initializer;

setBridgeFee

Sets the bridge fee

function setBridgeFee(uint256 _bridgeFee) external onlyOwner;

Parameters

NameTypeDescription
_bridgeFeeuint256The new bridge fee

setAVSReward

Sets the AVS reward

function setAVSReward(uint256 _AVSReward) external onlyOwner;

Parameters

NameTypeDescription
_AVSRewarduint256The new AVS reward

setCrankGasCost

Sets the crank gas cost

function setCrankGasCost(uint256 _crankGasCost) external onlyOwner;

Parameters

NameTypeDescription
_crankGasCostuint256The new crank gas cost

bridgeERC20

Internal function to transfer ERC20 tokens for bridging

function bridgeERC20(address tokenAddress, uint256 amountIn) internal;

Parameters

NameTypeDescription
tokenAddressaddressThe address of the token to be transferred
amountInuint256The amount of tokens to be transferred

bridge

Initiates a bridge request

function bridge(
    address tokenAddress,
    uint256 amountIn,
    uint256 amountOut,
    address destinationVault,
    address destinationAddress
) public payable nonReentrant;

Parameters

NameTypeDescription
tokenAddressaddressThe address of the token to be bridged
amountInuint256The amount of tokens to be bridged
amountOutuint256The amount of tokens expected at the destination
destinationVaultaddressThe address of the destination vault
destinationAddressaddressThe address of the recipient at the destination

_releaseFunds

Abstract function to release funds, to be implemented by inheriting contracts

function _releaseFunds(bytes memory data) public virtual;

Parameters

NameTypeDescription
databytesThe bridge request data and signatures