-
Notifications
You must be signed in to change notification settings - Fork 105
Expand file tree
/
Copy pathMessageBusSender.sol
More file actions
148 lines (130 loc) · 5.8 KB
/
MessageBusSender.sol
File metadata and controls
148 lines (130 loc) · 5.8 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
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity 0.8.9;
import "../../safeguard/Ownable.sol";
import "../../interfaces/ISigsVerifier.sol";
contract MessageBusSender is Ownable {
ISigsVerifier public immutable sigsVerifier;
uint256 public feeBase;
uint256 public feePerByte;
mapping(address => uint256) public withdrawnFees;
event Message(address indexed sender, address receiver, uint256 dstChainId, bytes message, uint256 fee);
// message to non-evm chain with >20 bytes addr
event Message2(address indexed sender, bytes receiver, uint256 dstChainId, bytes message, uint256 fee);
event MessageWithTransfer(
address indexed sender,
address receiver,
uint256 dstChainId,
address bridge,
bytes32 srcTransferId,
bytes message,
uint256 fee
);
event FeeWithdrawn(address receiver, uint256 amount);
event FeeBaseUpdated(uint256 feeBase);
event FeePerByteUpdated(uint256 feePerByte);
constructor(ISigsVerifier _sigsVerifier) {
sigsVerifier = _sigsVerifier;
}
/**
* @notice Sends a message to a contract on another chain.
* Sender needs to make sure the uniqueness of the message Id, which is computed as
* hash(type.MessageOnly, sender, receiver, srcChainId, srcTxHash, dstChainId, message).
* If messages with the same Id are sent, only one of them will succeed at dst chain.
* A fee is charged in the native gas token.
* @param _receiver The address of the destination app contract.
* @param _dstChainId The destination chain ID.
* @param _message Arbitrary message bytes to be decoded by the destination app contract.
*/
function sendMessage(
address _receiver,
uint256 _dstChainId,
bytes calldata _message
) external payable {
_sendMessage(_dstChainId, _message);
emit Message(msg.sender, _receiver, _dstChainId, _message, msg.value);
}
// Send message to non-evm chain with bytes for receiver address,
// otherwise same as above.
function sendMessage(
bytes calldata _receiver,
uint256 _dstChainId,
bytes calldata _message
) external payable {
_sendMessage(_dstChainId, _message);
emit Message2(msg.sender, _receiver, _dstChainId, _message, msg.value);
}
function _sendMessage(uint256 _dstChainId, bytes calldata _message) private {
require(_dstChainId != block.chainid, "Invalid chainId");
uint256 minFee = calcFee(_message);
require(msg.value >= minFee, "Insufficient fee");
}
/**
* @notice Sends a message associated with a transfer to a contract on another chain.
* If messages with the same srcTransferId are sent, only one of them will succeed.
* A fee is charged in the native token.
* @param _receiver The address of the destination app contract.
* @param _dstChainId The destination chain ID.
* @param _srcBridge The bridge contract to send the transfer with.
* @param _srcTransferId The transfer ID.
* @param _dstChainId The destination chain ID.
* @param _message Arbitrary message bytes to be decoded by the destination app contract.
*/
function sendMessageWithTransfer(
address _receiver,
uint256 _dstChainId,
address _srcBridge,
bytes32 _srcTransferId,
bytes calldata _message
) external payable {
require(_dstChainId != block.chainid, "Invalid chainId");
uint256 minFee = calcFee(_message);
require(msg.value >= minFee, "Insufficient fee");
// SGN needs to verify
// 1. msg.sender matches sender of the src transfer
// 2. dstChainId matches dstChainId of the src transfer
// 3. bridge is either liquidity bridge, peg src vault, or peg dst bridge
emit MessageWithTransfer(msg.sender, _receiver, _dstChainId, _srcBridge, _srcTransferId, _message, msg.value);
}
/**
* @notice Withdraws message fee in the form of native gas token.
* @param _account The address receiving the fee.
* @param _cumulativeFee The cumulative fee credited to the account. Tracked by SGN.
* @param _sigs The list of signatures sorted by signing addresses in ascending order. A withdrawal must be
* signed-off by +2/3 of the sigsVerifier's current signing power to be delivered.
* @param _signers The sorted list of signers.
* @param _powers The signing powers of the signers.
*/
function withdrawFee(
address _account,
uint256 _cumulativeFee,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers
) external {
bytes32 domain = keccak256(abi.encodePacked(block.chainid, address(this), "withdrawFee"));
sigsVerifier.verifySigs(abi.encodePacked(domain, _account, _cumulativeFee), _sigs, _signers, _powers);
uint256 amount = _cumulativeFee - withdrawnFees[_account];
require(amount > 0, "No new amount to withdraw");
withdrawnFees[_account] = _cumulativeFee;
(bool sent, ) = _account.call{value: amount, gas: 50000}("");
require(sent, "failed to withdraw fee");
emit FeeWithdrawn(_account, amount);
}
/**
* @notice Calculates the required fee for the message.
* @param _message Arbitrary message bytes to be decoded by the destination app contract.
@ @return The required fee.
*/
function calcFee(bytes calldata _message) public view returns (uint256) {
return feeBase + _message.length * feePerByte;
}
// -------------------- Admin --------------------
function setFeePerByte(uint256 _fee) external onlyOwner {
feePerByte = _fee;
emit FeePerByteUpdated(feePerByte);
}
function setFeeBase(uint256 _fee) external onlyOwner {
feeBase = _fee;
emit FeeBaseUpdated(feeBase);
}
}