-
Notifications
You must be signed in to change notification settings - Fork 32
/
BaseClient.sol
102 lines (93 loc) · 5.65 KB
/
BaseClient.sol
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
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
// ══════════════════════════════ LIBRARY IMPORTS ══════════════════════════════
import {BaseClientOptimisticPeriod, IncorrectSender} from "../libs/Errors.sol";
// ═════════════════════════════ INTERNAL IMPORTS ══════════════════════════════
import {MessageRecipient} from "./MessageRecipient.sol";
/**
* @dev Implementation of IMessageRecipient interface, to be used as the recipient of
* base messages passed by the Destination contract.
* BaseClient could be used as a backbone for cross-chain apps:
* - A single BaseClient contract per chain (aka trusted sender)
* - Only BaseClient instances from other chains are able to send messages to this contract
* - BaseClient enforces a common optimistic period for all types of messages
* Note: BaseClient is forever stateless, meaning it can be potentially used as a parent
* for the upgradeable contract without worrying about storage collision.
*/
abstract contract BaseClient is MessageRecipient {
// solhint-disable-next-line no-empty-blocks
constructor(address origin_, address destination_) MessageRecipient(origin_, destination_) {}
// ═══════════════════════════════════════════════════ VIEWS ═══════════════════════════════════════════════════════
/**
* @notice Period of time since the root was submitted to Destination. Once this period is over,
* root can be used for proving and executing a message though this Client.
*/
function optimisticPeriod() public view virtual returns (uint32);
/**
* @notice Address of the trusted sender on the destination chain. The trusted sender will be able to:
* - Send messages to this contract from other chains.
* - Receive messages from this contract on other chains.
*/
function trustedSender(uint32 destination) public view virtual returns (bytes32);
// ══════════════════════════════════════════════ INTERNAL LOGIC ═══════════════════════════════════════════════════
/**
* @dev Child contracts should implement the logic for receiving a Base Message in an "unsafe way".
* Following checks HAVE been performed:
* - receiveBaseMessage() was called by Destination (i.e. this is a legit base message).
* - Nonce is not zero.
* - Message sender on origin chain is not a zero address.
* - Proof maturity is not zero.
* Following checks HAVE NOT been performed (thus "unsafe"):
* - Message sender on origin chain could be anything non-zero at this point.
* - Proof maturity could be anything non-zero at this point.
*/
function _receiveBaseMessageUnsafe(
uint32 origin_,
uint32 nonce,
bytes32 sender,
uint256 proofMaturity,
uint32 version,
bytes memory content
) internal override {
if (sender != trustedSender(origin_)) revert IncorrectSender();
if (proofMaturity < optimisticPeriod()) revert BaseClientOptimisticPeriod();
_receiveBaseMessage(origin_, nonce, version, content);
}
/**
* @dev Child contracts should implement the logic for receiving a Base Message.
* Following checks HAVE been performed:
* - receiveBaseMessage() was called by Destination (i.e. this is a legit base message).
* - Nonce is not zero.
* - Message sender on origin chain is a trusted sender (and is not zero).
* - Optimistic period for the message have passed (and is not zero).
*/
function _receiveBaseMessage(uint32 origin_, uint32 nonce, uint32 version, bytes memory content) internal virtual;
/**
* @dev Sends a message to given destination chain. Full `msg.value` is used to pay for the message tips.
* `_getMinimumTipsValue()` could be used to calculate the minimum required tips value, and should be also
* exposed as a public view function to estimate the tips value before sending a message off-chain.
* This function is not exposed in BaseClient, as the message encoding is implemented by the child contract.
* > Will revert if the trusted sender is not set for the destination domain.
* @param destination_ Domain of the destination chain
* @param tipsValue Tips to be paid for sending the message
* @param request Encoded message execution request on destination chain
* @param content The message content
*/
function _sendBaseMessage(
uint32 destination_,
uint256 tipsValue,
MessageRequest memory request,
bytes memory content
) internal returns (uint32 messageNonce, bytes32 messageHash) {
// Send message to the trusted sender on destination chain with the defined optimistic period.
// Note: this will revert if the trusted sender is not set for the destination domain.
return _sendBaseMessage({
destination_: destination_,
recipient: trustedSender(destination_),
optimisticPeriod: optimisticPeriod(),
tipsValue: tipsValue,
request: request,
content: content
});
}
}