-
Notifications
You must be signed in to change notification settings - Fork 97
Expand file tree
/
Copy pathWormholeTransceiver.sol
More file actions
178 lines (151 loc) · 6.25 KB
/
Copy pathWormholeTransceiver.sol
File metadata and controls
178 lines (151 loc) · 6.25 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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
// SPDX-License-Identifier: Apache 2
pragma solidity >=0.8.8 <0.9.0;
import "wormhole-solidity-sdk/libraries/BytesParsing.sol";
import "wormhole-solidity-sdk/interfaces/IWormhole.sol";
import "../../libraries/TransceiverHelpers.sol";
import "../../libraries/TransceiverStructs.sol";
import "../../libraries/ConfigMakers.sol";
import "../../interfaces/IWormholeTransceiver.sol";
import "../../interfaces/INttManager.sol";
import "../../interfaces/ICustomConsistencyLevel.sol";
import "./WormholeTransceiverState.sol";
/// @title WormholeTransceiver
/// @author Wormhole Project Contributors.
/// @notice Transceiver implementation for Wormhole.
///
/// @dev This contract is responsible for sending and receiving NTT messages
/// that are authenticated through Wormhole Core.
///
/// @dev Messages are delivered manually via the core layer or through
/// external relayers/executors that call receiveMessage directly.
///
/// @dev Once a message is received, it is delivered to its corresponding
/// NttManager contract.
contract WormholeTransceiver is IWormholeTransceiver, WormholeTransceiverState {
using BytesParsing for bytes;
string public constant WORMHOLE_TRANSCEIVER_VERSION = "2.0.1";
constructor(
address nttManager,
address wormholeCoreBridge,
uint8 _consistencyLevel,
uint8 _customConsistencyLevel,
uint16 _additionalBlocks,
address _customConsistencyLevelAddress
)
WormholeTransceiverState(
nttManager,
wormholeCoreBridge,
_consistencyLevel,
_customConsistencyLevel,
_additionalBlocks,
_customConsistencyLevelAddress
)
{}
// ==================== External Interface ===============================================
function getTransceiverType() external pure override returns (string memory) {
return "wormhole";
}
/// @inheritdoc IWormholeTransceiver
function receiveMessage(
bytes memory encodedMessage
) external {
uint16 sourceChainId;
bytes memory payload;
(sourceChainId, payload) = _verifyMessage(encodedMessage);
// parse the encoded Transceiver payload
TransceiverStructs.TransceiverMessage memory parsedTransceiverMessage;
TransceiverStructs.NttManagerMessage memory parsedNttManagerMessage;
(parsedTransceiverMessage, parsedNttManagerMessage) =
TransceiverStructs.parseTransceiverAndNttManagerMessage(
WH_TRANSCEIVER_PAYLOAD_PREFIX, payload
);
_deliverToNttManager(
sourceChainId,
parsedTransceiverMessage.sourceNttManagerAddress,
parsedTransceiverMessage.recipientNttManagerAddress,
parsedNttManagerMessage
);
}
/// @inheritdoc IWormholeTransceiver
function parseWormholeTransceiverInstruction(
bytes memory encoded
) public pure returns (WormholeTransceiverInstruction memory instruction) {
// If the user doesn't pass in any transceiver instructions then the default is false
if (encoded.length == 0) {
instruction.shouldSkipRelayerSend = false;
return instruction;
}
uint256 offset = 0;
(instruction.shouldSkipRelayerSend, offset) = encoded.asBoolUnchecked(offset);
encoded.checkLength(offset);
}
/// @inheritdoc IWormholeTransceiver
function encodeWormholeTransceiverInstruction(
WormholeTransceiverInstruction memory instruction
) public pure returns (bytes memory) {
return abi.encodePacked(instruction.shouldSkipRelayerSend);
}
// ==================== Internal ========================================================
function _quoteDeliveryPrice(
uint16, /* targetChain */
TransceiverStructs.TransceiverInstruction memory /* instruction */
) internal view override returns (uint256 nativePriceQuote) {
return wormhole.messageFee();
}
function _sendMessage(
uint16 recipientChain,
uint256 deliveryPayment,
address caller,
bytes32 recipientNttManagerAddress,
bytes32, /* refundAddress */
TransceiverStructs.TransceiverInstruction memory, /* instruction */
bytes memory nttManagerMessage
) internal override {
(
TransceiverStructs.TransceiverMessage memory transceiverMessage,
bytes memory encodedTransceiverPayload
) = TransceiverStructs.buildAndEncodeTransceiverMessage(
WH_TRANSCEIVER_PAYLOAD_PREFIX,
toWormholeFormat(caller),
recipientNttManagerAddress,
nttManagerMessage,
new bytes(0)
);
wormhole.publishMessage{value: deliveryPayment}(
0, encodedTransceiverPayload, consistencyLevel
);
// NOTE: manual relaying does not currently support refunds. The zero address
// is used as refundAddress.
emit RelayingInfo(uint8(RelayingType.Manual), bytes32(0), deliveryPayment);
emit SendTransceiverMessage(recipientChain, transceiverMessage);
}
function _verifyMessage(
bytes memory encodedMessage
) internal returns (uint16, bytes memory) {
// verify VAA against Wormhole Core Bridge contract
(IWormhole.VM memory vm, bool valid, string memory reason) =
wormhole.parseAndVerifyVM(encodedMessage);
// ensure that the VAA is valid
if (!valid) {
revert InvalidVaa(reason);
}
// ensure that the message came from a registered peer contract
if (!_verifyBridgeVM(vm)) {
revert InvalidWormholePeer(vm.emitterChainId, vm.emitterAddress);
}
// save the VAA hash in storage to protect against replay attacks.
if (isVAAConsumed(vm.hash)) {
revert TransferAlreadyCompleted(vm.hash);
}
_setVAAConsumed(vm.hash);
// emit `ReceivedMessage` event
emit ReceivedMessage(vm.hash, vm.emitterChainId, vm.emitterAddress, vm.sequence);
return (vm.emitterChainId, vm.payload);
}
function _verifyBridgeVM(
IWormhole.VM memory vm
) internal view returns (bool) {
checkFork(wormholeTransceiver_evmChainId);
return getWormholePeer(vm.emitterChainId) == vm.emitterAddress;
}
}