CrossChainBridgeERC20
Manages deposits and releases for ERC20 bridge transactions

Functions

burnLpTokenForWithdrawalInOtherNetwork

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.
1
function burnLpTokenForWithdrawalInOtherNetwork(
2
IERC20 token,
3
uint256 amount,
4
address receiverAddress,
5
uint256 targetChainId
6
) public nonReentrant deactivateSwitch returns (uint256 depositAmount) {
7
// get LP token for token address provided
8
(, IERC20 lpToken) = liquidityManager.lpTokens(address(token));
9
10
// calculate withdrawal fee and deposit amount
11
// determine the fee rate to be used for this transaction (usually default liquidity withdrawal fee)
12
uint256 liquidityWithdrawalFee = liquidityManager.defaultLiquidityWithdrawalFee();
13
// if a specific fee rate is stored for this particular release token then we use this rate instead
14
if (liquidityManager.liquidityWithdrawalFees(address(token)) > 0) {
15
liquidityWithdrawalFee = liquidityManager.liquidityWithdrawalFees(address(token));
16
}
17
18
// calculate deposit amount
19
depositAmount = amount;
20
if (liquidityWithdrawalFee > 0) {
21
uint256 withdrawalFeeAmount = (amount * liquidityWithdrawalFee) / 1000000;
22
depositAmount = amount - withdrawalFeeAmount;
23
// transfer developer account fee, if applicable
24
if (withdrawalFeeAmount > 0) {
25
// transfer LP token in amount of withdrawal fee to dev account
26
lpToken.safeTransferFrom(_msgSender(), liquidityManager.devAddr(), withdrawalFeeAmount);
27
}
28
}
29
30
// burn LP token from user (must have approval from user)
31
ERC20Burnable(address(lpToken)).burnFrom(_msgSender(), depositAmount);
32
33
// call internal deposit function to check parameters and create event
34
_depositERC20(token, depositAmount, receiverAddress, targetChainId);
35
36
// emit event
37
emit LiquidityDeposited(address(token), depositAmount, receiverAddress, _getChainID(), targetChainId, depositCount);
38
39
return depositAmount;
40
}
41
42
// returns the ID of the network this contract is deployed in
43
function _getChainID() private view returns (uint256) {
44
uint256 id;
45
assembly {
46
id := chainid()
47
}
48
return id;
49
}
Copied!

Parameters:

Name
Type
Description
token
IERC20
the ERC20 token in which liquidity was provided
amount
uint256
the amount to be withdrawn
receiverAddress
address
the address which should receive the bridged funds in the target network
targetChainId
uint256
chain ID of the target network

Return value:

Name
Type
Description
depositAmount
uint256
the amount that was deposited (= withdrawalAmount - fee)

depositERC20

Accepts ERC20 token deposits that should be bridged into another network (effectively starting a new bridge transaction)
1
function depositERC20(
2
IERC20 token,
3
uint256 amount,
4
address receiverAddress,
5
uint256 targetChainId
6
) public nonReentrant {
7
// check token balance before deposit
8
uint256 balanceBefore = token.balanceOf(address(this));
9
10
// Transfer to-be-deposited tokens from sender to this smart contract
11
token.safeTransferFrom(_msgSender(), address(this), amount);
12
13
// check if token balance has increased by amount (>> effectively preventing deflationary tokens to be added for now)
14
if (token.balanceOf(address(this)) != balanceBefore + amount) revert OperationFailed();
15
16
// call internal function that assigns depositID and emits event
17
_depositERC20(token, amount, receiverAddress, targetChainId);
18
}
Copied!

Parameters:

Name
Type
Description
token
IERC20
the ERC20 token that should be deposited
amount
uin256
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

depositNative

Accepts native token (e.g. ETH, BNB, MATIC) deposits that should be bridged into another network (effectively starting a new bridge transaction)
1
function depositNative(
2
uint256 amount,
3
address receiverAddress,
4
uint256 targetChainId
5
) external payable nonReentrant {
6
// check input parameters
7
if (amount != msg.value) revert InvalidMessageValue(msg.value, amount);
8
9
// check native token balance before swap
10
uint256 contractBalance = wrappedNative.balanceOf(address(this));
11
12
// swap native to wrapped native ERC20 token
13
wrappedNative.deposit{value: msg.value}();
14
15
// check if wrapped native token balance has increased by deposit amount
16
if (wrappedNative.balanceOf(address(this)) != contractBalance + amount) revert OperationFailed();
17
18
// call depositERC20 function with wrapped native token to complete the deposit
19
_depositERC20(wrappedNative, amount, receiverAddress, targetChainId);
20
}
Copied!

Parameters:

Name
Type
Description
amount
uint256
the amount that is being deposited
receiverAddress
address
the address which should receive the bridged funds in the target network
targetChainId
uint256
chain ID of the target network

forwardCollectedFees

In order to save gas, we introduced periodically fee transfers. This means that our bridge will collect fees (which should be sent to other contracts) and only periodically forwards them to their owners. Fees collected for RewardPools and LiquidityMiningPools are roughly forwarded every 24/48hrs and fees collected for BuyBackAndBurn are only forwarded on-demand (when a buyBackAndBurn is triggered). This function allows to trigger an immediate transfer of these fees.
1
function forwardCollectedFees(
2
IERC20 token,
3
bool _buyBackAndBurn,
4
bool _miningPools,
5
bool _rewardPools
6
) public nonReentrant {
7
if (token.balanceOf(address(this)) > 0) {
8
if (_buyBackAndBurn) {
9
buyBackAndBurn.depositERC20(token, collectedUnsentFees[address(token)][address(buyBackAndBurn)]);
10
collectedUnsentFees[address(token)][address(buyBackAndBurn)] = 0;
11
}
12
if (_miningPools) {
13
liquidityMiningPools.addRewards(token, collectedUnsentFees[address(token)][address(liquidityMiningPools)]);
14
collectedUnsentFees[address(token)][address(liquidityMiningPools)] = 0;
15
}
16
if (_rewardPools) {
17
rewardPools.addRewards(token, collectedUnsentFees[address(token)][address(rewardPools)]);
18
collectedUnsentFees[address(token)][address(rewardPools)] = 0;
19
}
20
}
21
}
Copied!

Parameters:

Name
Type
Description
token
IERC20
the token in which fees were collected
_buyBackAndBurn
bool
true if collected fees should be sent to BuyBackAndBurn
_miningPools
bool
true if collected fees should be sent to LiquidityMiningPools
_rewardPools
bool
true if collected fees should be sent to RewardPools

releaseERC20

Releases ERC20 tokens in this network if a valid deposit was made in another network (effectively completing a bridge transaction)
1
function releaseERC20(
2
uint8[] memory sigV,
3
bytes32[] memory sigR,
4
bytes32[] memory sigS,
5
address receiverAddress,
6
address sourceNetworkTokenAddress,
7
uint256 amount,
8
uint256 depositChainId,
9
uint256 depositNumber
10
) external nonReentrant {
11
// forward call internally to private function with "false" parameter (=send ERC20 tokens to _msgSender())
12
_releaseERC20(
13
sigV,
14
sigR,
15
sigS,
16
receiverAddress,
17
sourceNetworkTokenAddress,
18
amount,
19
depositChainId,
20
depositNumber,
21
false
22
);
23
}
Copied!

Parameters:

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