CrossChainBridgeRouter
This contract is our one-stop-shop for accessing all functionality of the cross-chain bridge. It can be used to integrate our bridging and investing functionality into your smart contract or dApp.
We are currently testing this contract. At the moment it is only deployed to BSC testnet. Once we have concluded our testing phase, we will roll out the router contract to all other connected networks.
function addLiquidityERC20(IERC20 token, uint256 amount) external payable override whenNotPaused {
// check bridgeERC20 token balance before deposit
uint256 balanceBefore = token.balanceOf(address(bridgeERC20));
// Transfer token amount from sender to bridgeERC20
token.safeTransferFrom(_msgSender(), address(bridgeERC20), amount);
// check if bridgeERC20 token balance has increased by amount (>> effectively preventing deflationary tokens to be added for now)
if (token.balanceOf(address(bridgeERC20)) != balanceBefore + amount) revert OperationFailed();
// call liquidityManager contract to emit event
ICrossChainBridgeERC20LiquidityManager(liquidityManager).addLiquidityERC20(_msgSender(), token, amount);
}
Name | Type | Description |
---|---|---|
token | IERC20 | the address of the token for which liquidity should be added |
amount | uint256 | the amount of tokens to be added |
function addLiquidityNative(uint256 amount) external payable override whenNotPaused {
ICrossChainBridgeERC20LiquidityManager(liquidityManager).addLiquidityNative{value: msg.value}(_msgSender(), amount);
}
Name | Type | Description |
---|---|---|
amount | uint256 | the amount of native tokens to be added |
Accepts ERC20 token deposits that should be bridged into another network
(effectively starting a new bridge transaction)
function depositERC20TokensToBridge(
IERC20 token,
uint256 amount,
address receiverAddress,
uint256 targetChainId
) external payable override whenNotPaused {
// check token balance before deposit
uint256 balanceBefore = token.balanceOf(bridgeERC20);
// Transfer to-be-deposited tokens from sender to this smart contract
token.safeTransferFrom(_msgSender(), bridgeERC20, amount);
// check if token balance has increased by amount (>> effectively preventing deflationary tokens to be added for now)
if (token.balanceOf(bridgeERC20) != balanceBefore + amount) revert OperationFailed();
// call deposit function in bridgeERC20 contract
ICrossChainBridgeERC20(bridgeERC20).depositERC20(token, amount, receiverAddress, targetChainId);
}
Name | Type | Description |
---|---|---|
token | IERC20 | the ERC20 token that should be deposited |
amount | uint256 | the amount to be deposited |
receiverAddress | address | the address which should receive the bridged funds in the target network |
targetChainId | uint256 | chain ID of the target network |
Accepts ERC721 deposits that should be bridged into another network (effectively starting a bridge transaction). The collection must be whitelisted in order to be accepted for a deposit.
function depositERC721TokenToBridge(
address collectionAddress,
uint256 tokenId,
address receiverAddress,
uint256 targetChainId
) external payable override whenNotPaused {
// check if token was minted from an original collection or minted by this bridge
if (ICrossChainBridgeERC721(bridgeERC721).mintedDeposits(collectionAddress, tokenId)) {
// no whitelist check necessary since token was minted by this bridge
//TODO: to check > will it be a problem that the router will have mint/burn permission instead of the bridges?
//TODO: @CHRIS: pls comment
MintableERC721(collectionAddress).burn(tokenId);
} else {
if (!ICrossChainBridgeERC721(bridgeERC721).officialCollectionWhitelist(collectionAddress)) revert Unauthorized();
// transfer the token into the bridge
IERC721Upgradeable(collectionAddress).safeTransferFrom(_msgSender(), address(bridgeERC721), tokenId);
}
// call bridgeERC721 contract to emit event
ICrossChainBridgeERC721(bridgeERC721).depositERC721(collectionAddress, tokenId, receiverAddress, targetChainId);
}
Name | Type | Description |
---|---|---|
collectionAddress | address | the address of the ERC721 contract the collection was issued with |
tokenId | uint256 | the (native) ID of the ERC721 token that should be bridged |
receiverAddress | address | the address which should receive the bridged token in the target network |
targetChainId | uint256 | chain ID of the target network |
Accepts native token deposits that should be bridged into another network
(effectively starting a new bridge transaction)
function depositNativeTokensToBridge(
uint256 amount,
address receiverAddress,
uint256 targetChainId
) external payable override whenNotPaused {
ICrossChainBridgeERC20(bridgeERC20).depositNative{value: msg.value}(amount, receiverAddress, targetChainId);
}
Name | Type | Description |
---|---|---|
amount | uint256 | the amount to be deposited |
receiverAddress | address | the address which should receive the bridged funds in the target network |
targetChainId | uint256 | chain ID of the target network |
Returns the ID of the network this contract is deployed in
function getChainID() external view override returns (uint256) {
uint256 id;
assembly {
id := chainid()
}
return id;
}
Type | Description |
---|---|
uint256 | chainId of the current network |
Returns the estimated bridging fee for a specific ERC20 token and amount
function getERC20BridgeFeeQuote(address tokenAddress, uint256 amountToBeBridged)
external
view
override
returns (uint256 bridgeFee)
{
uint256 customBridgeFee = ICrossChainBridgeERC20(bridgeERC20).bridgeFees(tokenAddress);
uint256 relativeBridgeFee = customBridgeFee > 0
? customBridgeFee
: ICrossChainBridgeERC20(bridgeERC20).defaultBridgeFee();
return (amountToBeBridged * relativeBridgeFee) / PPM_DIVISOR;
}
Name | Type | Description |
---|---|---|
tokenAddress | address | the address of the token that should be bridged |
amountToBeBridged | uint256 | the amount to be bridged |
Name | Type | Description |
---|---|---|
bridgeFee | uint256 | the estimated bridging fee (in ERC20 tokens) |
Returns the estimated bridge fee in native currency (e.g. ETH, BSC, MATIC, AVAX, FTM) for bridging one token of a specific ERC721 collection
function getERC721BridgeFeeQuote(address collectionAddress) external view override returns (uint256 bridgeFee) {
uint256 customBridgeFee = ICrossChainBridgeERC721(bridgeERC721).bridgeFees(collectionAddress);
return customBridgeFee > 0 ? customBridgeFee : ICrossChainBridgeERC721(bridgeERC721).defaultBridgeFee();
}
Name | Type | Description |
---|---|---|
collectionAddress | address | the address of the collection |
Name | Type | Description |
---|---|---|
bridgeFee | uint256 | the estimated bridging fee (in native tokens) |
Returns the liquidity withdrawal fee amount for the given ERC20 token and amount
function getLiquidityWithdrawalFeeAmount(IERC20 token, uint256 withdrawalAmount)
public
view
override
returns (uint256)
{
return
ICrossChainBridgeERC20LiquidityManager(liquidityManager).getLiquidityWithdrawalFeeAmount(
address(token),
withdrawalAmount
);
}
Name | Type | Description |
---|---|---|
token | IERC20 | the address of the ERC20 token in which liquidity was provided |
withdrawalAmount | uint256 | the amount of tokens to be withdrawn |
Returns the address of the LP token for a given ERC20 token address
function getLPToken(address tokenAddress) public view override returns (address) {
(bool exists, IERC20 lpToken) = ICrossChainBridgeERC20LiquidityManager(liquidityManager).lpTokens(tokenAddress);
return exists ? address(lpToken) : address(0);
}
Name | Type | Description |
---|---|---|
tokenAddress | address | the address of token for which the LP token should be returned |
Type | Description |
---|---|
address | the address of the LP token contract |
function harvestFromMiningPool(address tokenAddress, address stakerAddress) external payable override whenNotPaused {
IPools(liquidityMiningPools).harvest(tokenAddress, stakerAddress);
}
Name | Type | Description |
---|---|---|
token | address | the address of the underlying token of the pool |
stakerAddress | address | the address of the staker for which rewards should be harvested |
function harvestFromRewardPool(address tokenAddress, address stakerAddress) external payable override whenNotPaused {
IRewardPools(rewardPools).harvest(tokenAddress, stakerAddress);
}
Name | Type | Description |
---|---|---|
tokenAddress | address | the address of the underlying token of the pool |
stakerAddress | address | the address of the staker for which rewards should be harvested |
Name | Type | Descriptions |
---|---|---|
farmId | uint256 | The ID of the farm |
user | address | the address of the user |
Type | Description |
---|---|
uint256 |
Returns the amount of tokens that are ready for harvesting for the given user and LiquidityMiningPool
function pendingMiningPoolRewards(address tokenAddress, address stakerAddress)
external
view
override
returns (uint256)
{
return IPools(liquidityMiningPools).pendingReward(tokenAddress, stakerAddress);
}
Name | Type | Description |
---|---|---|
tokenAddress | address | the address of the underlying token of the pool |
stakerAddress | address | the address of the staker for which rewards should be harvested |
Type | Description |
---|---|
uint256 | the unharvested reward amount in ERC20 tokens |
function pendingRewardPoolRewards(address tokenAddress, address stakerAddress)
external
view
override
returns (uint256)
{
return IRewardPools(rewardPools).pendingReward(tokenAddress, stakerAddress);
}
Name | Type | Description |
---|---|---|
tokenAddress | address | the address of the underlying token of the reward pool |
stakerAddress | address | the address of the staker for which pending rewards should be returned |
Type | Description |
---|---|
uint256 | the unharvested reward amount |
Releases ERC20 tokens in this network if a valid deposit was made in another network
(effectively completing a bridge transaction)
function releaseERC20TokenBridgeDeposit(
uint8[] memory sigV,
bytes32[] memory sigR,
bytes32[] memory sigS,
address receiverAddress,
address sourceNetworkTokenAddress,
uint256 amount,
uint256 depositChainId,
uint256 depositNumber
) external payable override whenNotPaused {
ICrossChainBridgeERC20(bridgeERC20).releaseERC20(
sigV,
sigR,
sigS,
receiverAddress,
sourceNetworkTokenAddress,
amount,
depositChainId,
depositNumber
);
}
Name | Type | Description |
---|---|---|
sigV | uint8 | Array of recovery Ids for the signature |
sigR | bytes32 | Array of R values of the signatures |
sigS | bytes32 | Array of S values of the signatures |
receiverAddress | address | the address which should receive the bridged funds in this network |
sourceNetworkTokenAddress | address | the address of the ERC20 contract in the network the deposit was made |
amount | uint256 | The amount of tokens to be released |
depositChainId | uint256 | chain ID of the network in which the deposit was made |
depositNumber | uint256 | The deposit ID of the corresponding deposit |
Releases an ERC721 token in this network after a deposit was made in the source network (effectively completing a bridge transaction)
function releaseERC721TokenDeposit(
uint8[] memory sigV,
bytes32[] memory sigR,
bytes32[] memory sigS,
address receiverAddress,
address sourceNetworkCollectionAddress,
uint256 tokenId,
uint256 depositChainId,
uint256 depositNumber
) external payable override whenNotPaused {
ICrossChainBridgeERC721(bridgeERC721).releaseERC721{value: msg.value}(
sigV,
sigR,
sigS,
receiverAddress,
sourceNetworkCollectionAddress,
tokenId,
depositChainId,
depositNumber
);
}
Name | Type | Description |
---|---|---|
sigV | uint8 | Array of recovery Ids for the signature |
sigR | bytes32 | Array of R values of the signatures |
sigS | bytes32 | Array of S values of the signatures |
receiverAddress | address | the address to which the bridged token should be released to |
sourceNetworkAddress | address | the address of the ERC721 collection in the network the deposit was made |
tokenId | uint256 | The token id to be sent |
depositChainId | uint256 | chain ID of the network in which the deposit was made |
depositNumber | uint256 | The deposit ID of the corresponding deposit |
Releases native tokens in this network that were deposited in another network
(effectively completing a bridge transaction)
function releaseNativeTokenBridgeDeposit(
uint8[] memory sigV,
bytes32[] memory sigR,
bytes32[] memory sigS,
address receiverAddress,
address sourceNetworkTokenAddress,
uint256 amount,
uint256 depositChainId,
uint256 depositNumber
) external payable override whenNotPaused {
ICrossChainBridgeERC20(bridgeERC20).releaseNative(
sigV,
sigR,
sigS,
receiverAddress,
sourceNetworkTokenAddress,
amount,
depositChainId,
depositNumber
);
}
Name | Type | Description |
---|---|---|
sigV | uint8 | Array of recovery Ids for the signature |
sigR | bytes32 | Array of R values of the signatures |
sigS | bytes32 | Array of S values of the signatures |
receiverAddress | address | the address to which the bridged token should be released to |
sourceNetworkTokenAddress | address | the address of the ERC20 contract in the network the deposit was made |
amount | uint256 | The amount of tokens to be released |
depositChainId | uint256 | chain ID of the network in which the deposit was made |
depositNumber | uint256 | The deposit ID of the corresponding deposit |
function rewardPoolWithdrawalFee(address tokenAddress) external view override returns (uint256) {
uint256 customFee = IRewardPools(rewardPools).rewardPoolWithdrawalFees(tokenAddress);
return customFee > 0 ? customFee : IRewardPools(rewardPools).defaultRewardPoolWithdrawalFee();
}
Name | Type | Description |
---|---|---|
tokenAddress | address | the address of the underlying token of the reward pool |
Type | Description |
---|---|
uint256 | the withdrawal fee in ppm |
function stakeBRIDGEInRewardPool(address tokenAddress, uint256 amount) external payable override whenNotPaused {
// call rewardPools contract to update stake info and emit event
IRewardPools(rewardPools).stake(_msgSender(), tokenAddress, amount);
// transfer to-be-staked funds from user to this smart contract (must be done after rewardPools call)
IBridgeChef(bridgeChef).bridgeToken().safeTransferFrom(_msgSender(), address(rewardPools), amount);
}
Name | Type | Description |
---|---|---|
tokenAddress | address | the address of the underlying token of the reward pool |
amount | uint256 | the amount of bridge tokens that should be staked |
Stakes liquidity provider (LP) tokens in the given LiquidityMiningPool for the user to start earning from bridge fees of the given ERC20 token
function stakeLpTokensInMiningPool(address tokenAddress, uint256 amount) external payable override whenNotPaused {
// call liquidityMiningPools contract and update stake information (must be done before token transfer)
IPools(liquidityMiningPools).stake(_msgSender(), tokenAddress, amount);
// transfer to-be-staked funds from user to this smart contract
IERC20(getLPToken(tokenAddress)).safeTransferFrom(_msgSender(), address(liquidityMiningPools), amount);
}
Name | Type | Description |
---|---|---|
tokenAddress | address | the address of the underlying token of the pool |
amount | uint256 | the amount of LP tokens that should be staked |
function unstakeBRIDGEFromRewardPool(address tokenAddress, uint256 amount) external payable override whenNotPaused {
// no approval required for unstaking BRIDGE tokens
IRewardPools(rewardPools).unstake(_msgSender(), tokenAddress, amount);
}
Name | Type | Description |
---|---|---|
tokenAddress | address | the address of the underlying token of the reward pool |
amount | uint256 | the amount of bridge tokens that should be unstaked |
function unstakeLpTokensFromMiningPool(address tokenAddress, uint256 amount) external payable override whenNotPaused {
// no approval needed to burn poolsInterestBearingToken, thus transfer happens in liquidityMiningPools contract
IPools(liquidityMiningPools).unstake(_msgSender(), tokenAddress, amount);
}
Name | Type | Description |
---|---|---|
tokenAddress | address | the address of the underlying token of the liquidity mining pool |
amount | uint256 | the amount of LP tokens that should be unstaked |
function withdrawLiquidityERC20(IERC20 token, uint256 amount) external payable override whenNotPaused {
// burn LP token in the amount of liquidity that should be removed
ERC20Burnable(getLPToken(address(token))).burnFrom(_msgSender(), amount);
// call liquidityManager contract to emit event and transfer liquidity
ICrossChainBridgeERC20LiquidityManager(liquidityManager).withdrawLiquidityERC20(_msgSender(), token, amount);
}
Name | Type | Description |
---|---|---|
token | IERC20 | the token for which liquidity should be removed from this pool |
amount | uint256 | the amount of tokens to be withdrawn |
Burns LP tokens and creates a bridge deposit in the amount of "burnedLPtokens - liquidity withdrawal fee". This function was introduced to allow liquidity withdrawals even if a network's current liquidity is insufficient for a withdrawal.
function withdrawLiquidityInAnotherNetwork(
IERC20 token,
uint256 amount,
address receiverAddress,
uint256 targetChainId
) external payable override whenNotPaused {
// check if withdrawal fee applies and send LP tokens to devAddress
uint256 feeAmount = getLiquidityWithdrawalFeeAmount(token, amount);
uint256 depositAmount = amount;
if (feeAmount > 0) {
// get LP token and transfer amount of withdrawal fee to dev account
IERC20(getLPToken(