Skip to content

Chainbridge working

Nithin Krishna edited this page May 11, 2021 · 5 revisions

Chainbridge Setup

The chain bridge contracts (Bridge.sol, GenericHandler.sol ..) are deployed on all of the connected chains. The off chain relayer is configured to listen to Deposit events from these contracts and relays them to other chains.

Each instance of Bridge.sol deployed on a particular chain is created with a chainID (This is not to be confused with the blockchain's chainID). The chainID is an identifier at the chain bridge system level and can be set by the Bridge admin at the time of contract deployment. It's used by the offchain relayer to keep track of messages between chains (sourceChainID and destinationChainID).

When a user triggers a cross-chain transaction through chain bridge, they invoke Bridge.deposit with a destinaitonChainID, resourceID and data (data contains the transaction information abi encoded and packed).

The Bridge contract is pre-configured by the Bridge administrator to map all deposits with a particular resourceID to the invoke a specific contract and function selector on transaction initiation and completion. In our case we've preconfigured the bridge as follows:

resourceID chain initiation completion
reportRebaseResourceID base-chain AMPLChainBridgeGateway validateRebaseReport -
reportRebaseResourceID satellite-chain - ChainBridgeXCAmpleGateway reportRebase
transferResourceID base-chain AMPLChainBridgeGateway validateAndLock AMPLChainBridgeGateway unlock
transferResourceID satellite-chain ChainBridgeXCAmpleGateway validateAndBurn ChainBridgeXCAmpleGateway mint

Data packing

The data packing logic can be found as part of the SDK.

const createGenericDepositData = (hexMetaData) => {
  if (hexMetaData === null) {
    return '0x' + toHex(0, 32).substr(2);
  }
  const hexMetaDataLength = hexMetaData.substr(2).length / 2;
  return '0x' + toHex(hexMetaDataLength, 32).substr(2) + hexMetaData.substr(2);
};

const packXCRebaseData = (epoch, totalSupply) => {
  return createGenericDepositData(
    AbiCoder.encode(['uint256', 'uint256'], [epoch, totalSupply]),
  );
};

const packXCTransferData = (depositor, recipient, amount, totalSupply) => {
  return createGenericDepositData(
    AbiCoder.encode(
      ['address', 'address', 'uint256', 'uint256'],
      [depositor, recipient, amount, totalSupply],
    ),
  );
};

Report Rebase

It can be triggered by any user on the base chain (ethereum).

User invokes Bridge.deposit with:

  • reportRebaseResourceID
  • destinationChainID
  • data: The current epoch and totalSupply abi encoded and packed.

The validateRebaseReport function performs a data integrity check if the reported rebase information (epoch and supply) as part of the deposit transaction is the same as the current value on chain. If successful it emits a Deposit event which relayers pick up and transmit to the satellite chain.

NOTE: For a n-way bridge between a base chain and n-1 sat chains. reportRebase needs to be triggered n-1 times with every destinationChainID. The ChainBridgeBatchRebaseReport utility performs this in 1 transaction.

On the satellite chain the reportRebase function updates the new totalSupply and epoch on the XCAmpleController contract, after which rebase can be executed on the sat chain.

Execution flow

BaseChain (initiation):

user -> Bridge.deposit(destinationChainID, transferResourceID, data) -> GenericHandler.deposit -> AMPLChainBridgeGateway.validateRebaseReport

SatelliteChain (completion):

relayer -> Bridge.executeProposal(chainID, data, resourceID) -> GenericHandler.deposit -> ChainBridgeXCAmpleGateway.reportRebase -> XCAmpleController.reportRebase

Transfer

It can be triggered by any user on either the base chain (ethereum) or any satellite chain.

User invokes Bridge.deposit with:

  • transferResourceID
  • destinationChainID
  • data: The depositor, recipient amount and totalSupply abi encoded and packed.

Execution flow

BaseChain (initiation):

user -> approves TokenVault contract

user -> Bridge.deposit(destinationChainID, transferResourceID, data) -> GenericHandler.deposit -> AMPLChainBridgeGateway.validateAndLock -> TokenVault.lock

SatelliteChain (completion):

relayer -> Bridge.executeProposal(chainID, data, resourceID) -> GenericHandler.deposit -> ChainBridgeXCAmpleGateway.mint -> XCAmpleController.mint -> XCAmple.mint

SatelliteChain (initiation):

user -> approves XCAmpleController contract

user -> Bridge.deposit(destinationChainID, transferResourceID, data) -> GenericHandler.deposit -> ChainBridgeXCAmpleGateway.validateAndBurn -> XCAmpleController.burn -> XCAmple.burn

BaseChain (completion):

relayer -> Bridge.executeProposal(chainID, data, resourceID) -> GenericHandler.deposit -> AMPLChainBridgeGateway.unlock -> TokenVault.unlock