-
Notifications
You must be signed in to change notification settings - Fork 23
Expand file tree
/
Copy pathTokenBridge.sol
More file actions
96 lines (77 loc) · 3.83 KB
/
TokenBridge.sol
File metadata and controls
96 lines (77 loc) · 3.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import {ITokenBridge} from "./interfaces/ITokenBridge.sol";
import {Auth} from "../misc/Auth.sol";
import {IERC20} from "../misc/interfaces/IERC20.sol";
import {SafeTransferLib} from "../misc/libraries/SafeTransferLib.sol";
import {PoolId} from "../core/types/PoolId.sol";
import {ISpoke} from "../core/spoke/interfaces/ISpoke.sol";
import {ShareClassId} from "../core/types/ShareClassId.sol";
import {ITrustedContractUpdate} from "../core/utils/interfaces/IContractUpdate.sol";
/// @title TokenBridge
/// @notice Wrapper contract for cross-chain token transfers compatible with Glacis Airlift
contract TokenBridge is Auth, ITokenBridge {
ISpoke public immutable spoke;
address public relayer;
mapping(PoolId => mapping(ShareClassId => GasLimits)) public gasLimits;
mapping(uint256 evmChainId => uint16 centrifugeId) public chainIdToCentrifugeId;
constructor(ISpoke spoke_, address deployer) Auth(deployer) {
spoke = spoke_;
}
//----------------------------------------------------------------------------------------------
// Administration
//----------------------------------------------------------------------------------------------
/// @inheritdoc ITokenBridge
function file(bytes32 what, address data) external auth {
if (what == "relayer") relayer = data;
else revert FileUnrecognizedParam();
emit File(what, data);
}
/// @inheritdoc ITokenBridge
function file(bytes32 what, uint256 evmChainId, uint16 centrifugeId) external auth {
if (what == "centrifugeId") chainIdToCentrifugeId[evmChainId] = centrifugeId;
else revert FileUnrecognizedParam();
emit File(what, evmChainId, centrifugeId);
}
/// @inheritdoc ITrustedContractUpdate
function trustedCall(PoolId poolId, ShareClassId scId, bytes memory payload) external auth {
uint8 kindValue = abi.decode(payload, (uint8));
require(kindValue <= uint8(type(TrustedCall).max), UnknownTrustedCall());
TrustedCall kind = TrustedCall(kindValue);
if (kind == TrustedCall.SetGasLimits) {
(, uint128 extraGasLimit, uint128 remoteExtraGasLimit) = abi.decode(payload, (uint8, uint128, uint128));
require(address(spoke.shareToken(poolId, scId)) != address(0), ShareTokenDoesNotExist());
gasLimits[poolId][scId] = GasLimits(extraGasLimit, remoteExtraGasLimit);
emit UpdateGasLimits(poolId, scId, extraGasLimit, remoteExtraGasLimit);
}
}
//----------------------------------------------------------------------------------------------
// Bridging
//----------------------------------------------------------------------------------------------
/// @inheritdoc ITokenBridge
function send(address token, uint256 amount, bytes32 receiver, uint256 destinationChainId, address refundAddress)
public
payable
returns (bytes memory)
{
uint16 centrifugeId = chainIdToCentrifugeId[destinationChainId];
require(centrifugeId != 0, InvalidChainId());
SafeTransferLib.safeTransferFrom(token, msg.sender, address(this), amount);
if (IERC20(token).allowance(address(this), address(spoke)) == 0) {
SafeTransferLib.safeApprove(token, address(spoke), type(uint256).max);
}
(PoolId poolId, ShareClassId scId) = spoke.shareTokenDetails(token);
GasLimits memory limits = gasLimits[poolId][scId];
spoke.crosschainTransferShares{value: msg.value}(
centrifugeId,
poolId,
scId,
receiver,
uint128(amount),
limits.extraGasLimit,
limits.remoteExtraGasLimit,
relayer != address(0) ? relayer : refundAddress // Transfer remaining ETH to relayer if set
);
return bytes("");
}
}