@evvm/testnet-contracts 2.1.1 → 2.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/contracts/treasuryTwoChains/TreasuryExternalChainStation.sol +300 -50
- package/contracts/treasuryTwoChains/TreasuryHostChainStation.sol +286 -61
- package/contracts/treasuryTwoChains/lib/ErrorsLib.sol +31 -0
- package/contracts/treasuryTwoChains/lib/ExternalChainStationStructs.sol +50 -0
- package/contracts/treasuryTwoChains/lib/HostChainStationStructs.sol +47 -8
- package/contracts/treasuryTwoChains/lib/PayloadUtils.sol +42 -0
- package/contracts/treasuryTwoChains/lib/SignatureUtils.sol +41 -7
- package/interfaces/ITreasuryExternalChainStation.sol +34 -130
- package/interfaces/ITreasuryHostChainStation.sol +35 -124
- package/package.json +1 -1
|
@@ -2,15 +2,33 @@
|
|
|
2
2
|
// Full license terms available at: https://www.evvm.info/docs/EVVMNoncommercialLicense
|
|
3
3
|
|
|
4
4
|
pragma solidity ^0.8.0;
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
+
* @title Treasury Cross-Chain Host Station Contract
|
|
31
|
+
* @author Mate labs
|
|
14
32
|
*/
|
|
15
33
|
|
|
16
34
|
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
@@ -19,9 +37,11 @@ import {ErrorsLib} from "@evvm/testnet-contracts/contracts/treasuryTwoChains/lib
|
|
|
19
37
|
import {HostChainStationStructs} from "@evvm/testnet-contracts/contracts/treasuryTwoChains/lib/HostChainStationStructs.sol";
|
|
20
38
|
|
|
21
39
|
import {SignatureUtils} from "@evvm/testnet-contracts/contracts/treasuryTwoChains/lib/SignatureUtils.sol";
|
|
40
|
+
import {PayloadUtils} from "@evvm/testnet-contracts/contracts/treasuryTwoChains/lib/PayloadUtils.sol";
|
|
22
41
|
|
|
23
42
|
import {IMailbox} from "@hyperlane-xyz/core/contracts/interfaces/IMailbox.sol";
|
|
24
43
|
|
|
44
|
+
import {MessagingParams, MessagingReceipt} from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol";
|
|
25
45
|
import {OApp, Origin, MessagingFee} from "@layerzerolabs/oapp-evm/contracts/oapp/OApp.sol";
|
|
26
46
|
import {OAppOptionsType3} from "@layerzerolabs/oapp-evm/contracts/oapp/libs/OAppOptionsType3.sol";
|
|
27
47
|
import {OptionsBuilder} from "@layerzerolabs/oapp-evm/contracts/oapp/libs/OptionsBuilder.sol";
|
|
@@ -38,28 +58,58 @@ contract TreasuryHostChainStation is
|
|
|
38
58
|
OAppOptionsType3,
|
|
39
59
|
AxelarExecutable
|
|
40
60
|
{
|
|
41
|
-
/// @notice Address of the EVVM core contract
|
|
61
|
+
/// @notice Address of the EVVM core contract for balance operations
|
|
62
|
+
/// @dev Used to integrate with EVVM's balance management and token operations
|
|
42
63
|
address evvmAddress;
|
|
43
64
|
|
|
65
|
+
/// @notice Admin address management with time-delayed proposals
|
|
66
|
+
/// @dev Stores current admin, proposed admin, and acceptance timestamp
|
|
44
67
|
AddressTypeProposal admin;
|
|
45
68
|
|
|
69
|
+
/// @notice Fisher executor address management with time-delayed proposals
|
|
70
|
+
/// @dev Fisher executor can process cross-chain bridge transactions
|
|
46
71
|
AddressTypeProposal fisherExecutor;
|
|
47
72
|
|
|
73
|
+
/// @notice Hyperlane protocol configuration for cross-chain messaging
|
|
74
|
+
/// @dev Contains domain ID, external chain address, and mailbox contract address
|
|
48
75
|
HyperlaneConfig hyperlane;
|
|
49
76
|
|
|
77
|
+
/// @notice LayerZero protocol configuration for omnichain messaging
|
|
78
|
+
/// @dev Contains endpoint ID, external chain address, and endpoint contract address
|
|
50
79
|
LayerZeroConfig layerZero;
|
|
51
80
|
|
|
81
|
+
/// @notice Axelar protocol configuration for cross-chain communication
|
|
82
|
+
/// @dev Contains chain name, external chain address, gas service, and gateway addresses
|
|
52
83
|
AxelarConfig axelar;
|
|
53
84
|
|
|
85
|
+
/// @notice Pending proposal for changing external chain addresses across all protocols
|
|
86
|
+
/// @dev Used for coordinated updates to external chain addresses with time delay
|
|
87
|
+
ChangeExternalChainAddressParams externalChainAddressChangeProposal;
|
|
88
|
+
|
|
89
|
+
/// @notice Tracks the next nonce for Fisher bridge operations per user address
|
|
90
|
+
/// @dev Prevents replay attacks in Fisher bridge transactions
|
|
54
91
|
mapping(address => uint256) nextFisherExecutionNonce;
|
|
55
92
|
|
|
56
|
-
|
|
93
|
+
/// @notice LayerZero execution options with gas limit configuration
|
|
94
|
+
/// @dev Pre-built options for LayerZero message execution (200k gas limit)
|
|
95
|
+
bytes options =
|
|
57
96
|
OptionsBuilder.addExecutorLzReceiveOption(
|
|
58
97
|
OptionsBuilder.newOptions(),
|
|
59
|
-
|
|
98
|
+
200_000,
|
|
60
99
|
0
|
|
61
100
|
);
|
|
62
101
|
|
|
102
|
+
/// @notice One-time fuse for setting initial external chain addresses
|
|
103
|
+
/// @dev Prevents multiple calls to _setExternalChainAddress after initial setup
|
|
104
|
+
bytes1 fuseSetExternalChainAddress = 0x01;
|
|
105
|
+
|
|
106
|
+
/// @notice Emitted when Fisher bridge sends tokens from host to external chain
|
|
107
|
+
/// @param from Original sender address on host chain
|
|
108
|
+
/// @param addressToReceive Recipient address on external chain
|
|
109
|
+
/// @param tokenAddress Token contract address (address(0) for ETH)
|
|
110
|
+
/// @param priorityFee Fee paid for priority processing
|
|
111
|
+
/// @param amount Amount of tokens transferred
|
|
112
|
+
/// @param nonce Sequential nonce for the Fisher bridge operation
|
|
63
113
|
event FisherBridgeSend(
|
|
64
114
|
address indexed from,
|
|
65
115
|
address indexed addressToReceive,
|
|
@@ -69,6 +119,8 @@ contract TreasuryHostChainStation is
|
|
|
69
119
|
uint256 nonce
|
|
70
120
|
);
|
|
71
121
|
|
|
122
|
+
/// @notice Restricts function access to the current admin only
|
|
123
|
+
/// @dev Validates caller against admin.current address
|
|
72
124
|
modifier onlyAdmin() {
|
|
73
125
|
if (msg.sender != admin.current) {
|
|
74
126
|
revert();
|
|
@@ -76,6 +128,8 @@ contract TreasuryHostChainStation is
|
|
|
76
128
|
_;
|
|
77
129
|
}
|
|
78
130
|
|
|
131
|
+
/// @notice Restricts function access to the current Fisher executor only
|
|
132
|
+
/// @dev Validates caller against fisherExecutor.current address for bridge operations
|
|
79
133
|
modifier onlyFisherExecutor() {
|
|
80
134
|
if (msg.sender != fisherExecutor.current) {
|
|
81
135
|
revert();
|
|
@@ -83,10 +137,11 @@ contract TreasuryHostChainStation is
|
|
|
83
137
|
_;
|
|
84
138
|
}
|
|
85
139
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
140
|
+
/// @notice Initializes the Host Chain Station with EVVM integration and cross-chain protocols
|
|
141
|
+
/// @dev Sets up Hyperlane, LayerZero, and Axelar configurations for multi-protocol support
|
|
142
|
+
/// @param _evvmAddress Address of the EVVM core contract for balance operations
|
|
143
|
+
/// @param _admin Initial admin address with full administrative privileges
|
|
144
|
+
/// @param _crosschainConfig Configuration struct containing all cross-chain protocol settings
|
|
90
145
|
constructor(
|
|
91
146
|
address _evvmAddress,
|
|
92
147
|
address _admin,
|
|
@@ -122,10 +177,16 @@ contract TreasuryHostChainStation is
|
|
|
122
177
|
});
|
|
123
178
|
}
|
|
124
179
|
|
|
125
|
-
|
|
180
|
+
/// @notice One-time setup of external chain station address across all protocols
|
|
181
|
+
/// @dev Can only be called once (protected by fuseSetExternalChainAddress)
|
|
182
|
+
/// @param externalChainStationAddress Address-type representation for Hyperlane and LayerZero
|
|
183
|
+
/// @param externalChainStationAddressString String representation for Axelar protocol
|
|
184
|
+
function _setExternalChainAddress(
|
|
126
185
|
address externalChainStationAddress,
|
|
127
186
|
string memory externalChainStationAddressString
|
|
128
187
|
) external onlyAdmin {
|
|
188
|
+
if (fuseSetExternalChainAddress != 0x01) revert();
|
|
189
|
+
|
|
129
190
|
hyperlane.externalChainStationAddress = bytes32(
|
|
130
191
|
uint256(uint160(externalChainStationAddress))
|
|
131
192
|
);
|
|
@@ -137,13 +198,16 @@ contract TreasuryHostChainStation is
|
|
|
137
198
|
layerZero.externalChainStationEid,
|
|
138
199
|
layerZero.externalChainStationAddress
|
|
139
200
|
);
|
|
201
|
+
|
|
202
|
+
fuseSetExternalChainAddress = 0x00;
|
|
140
203
|
}
|
|
141
204
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
205
|
+
/// @notice Withdraws tokens from EVVM balance and sends to external chain via selected protocol
|
|
206
|
+
/// @dev Validates balance, deducts from EVVM, and bridges via Hyperlane/LayerZero/Axelar
|
|
207
|
+
/// @param toAddress Recipient address on the external chain
|
|
208
|
+
/// @param token Token contract address (cannot be Principal Token)
|
|
209
|
+
/// @param amount Amount to withdraw and send to external chain
|
|
210
|
+
/// @param protocolToExecute Protocol selector: 0x01=Hyperlane, 0x02=LayerZero, 0x03=Axelar
|
|
147
211
|
function withdraw(
|
|
148
212
|
address toAddress,
|
|
149
213
|
address token,
|
|
@@ -158,7 +222,11 @@ contract TreasuryHostChainStation is
|
|
|
158
222
|
|
|
159
223
|
executerEVVM(false, msg.sender, token, amount);
|
|
160
224
|
|
|
161
|
-
bytes memory payload = encodePayload(
|
|
225
|
+
bytes memory payload = PayloadUtils.encodePayload(
|
|
226
|
+
token,
|
|
227
|
+
toAddress,
|
|
228
|
+
amount
|
|
229
|
+
);
|
|
162
230
|
|
|
163
231
|
if (protocolToExecute == 0x01) {
|
|
164
232
|
// 0x01 = Hyperlane
|
|
@@ -172,12 +240,11 @@ contract TreasuryHostChainStation is
|
|
|
172
240
|
);
|
|
173
241
|
} else if (protocolToExecute == 0x02) {
|
|
174
242
|
// 0x02 = LayerZero
|
|
175
|
-
uint256 fee = quoteLayerZero(toAddress, token, amount);
|
|
176
243
|
_lzSend(
|
|
177
244
|
layerZero.externalChainStationEid,
|
|
178
245
|
payload,
|
|
179
|
-
|
|
180
|
-
MessagingFee(
|
|
246
|
+
options,
|
|
247
|
+
MessagingFee(msg.value, 0),
|
|
181
248
|
msg.sender // Refund any excess fees to the sender.
|
|
182
249
|
);
|
|
183
250
|
} else if (protocolToExecute == 0x03) {
|
|
@@ -200,6 +267,14 @@ contract TreasuryHostChainStation is
|
|
|
200
267
|
}
|
|
201
268
|
}
|
|
202
269
|
|
|
270
|
+
/// @notice Receives Fisher bridge transactions from external chain and credits EVVM balances
|
|
271
|
+
/// @dev Verifies signature, increments nonce, and adds balance to recipient and executor
|
|
272
|
+
/// @param from Original sender address from external chain
|
|
273
|
+
/// @param addressToReceive Recipient address on this host chain
|
|
274
|
+
/// @param tokenAddress Token contract address (address(0) for ETH)
|
|
275
|
+
/// @param priorityFee Fee amount paid to Fisher executor
|
|
276
|
+
/// @param amount Amount of tokens being received
|
|
277
|
+
/// @param signature ECDSA signature proving transaction authorization
|
|
203
278
|
function fisherBridgeReceive(
|
|
204
279
|
address from,
|
|
205
280
|
address addressToReceive,
|
|
@@ -229,6 +304,14 @@ contract TreasuryHostChainStation is
|
|
|
229
304
|
executerEVVM(true, msg.sender, tokenAddress, priorityFee);
|
|
230
305
|
}
|
|
231
306
|
|
|
307
|
+
/// @notice Processes Fisher bridge token transfers from host to external chain
|
|
308
|
+
/// @dev Validates balance and signature, deducts from sender, pays executor fee
|
|
309
|
+
/// @param from Sender address initiating the bridge transaction
|
|
310
|
+
/// @param addressToReceive Recipient address on the external chain
|
|
311
|
+
/// @param tokenAddress Token contract address (cannot be Principal Token)
|
|
312
|
+
/// @param priorityFee Fee amount paid to Fisher executor
|
|
313
|
+
/// @param amount Amount of tokens to bridge to external chain
|
|
314
|
+
/// @param signature ECDSA signature proving transaction authorization
|
|
232
315
|
function fisherBridgeSend(
|
|
233
316
|
address from,
|
|
234
317
|
address addressToReceive,
|
|
@@ -276,6 +359,13 @@ contract TreasuryHostChainStation is
|
|
|
276
359
|
}
|
|
277
360
|
|
|
278
361
|
// Hyperlane Specific Functions //
|
|
362
|
+
|
|
363
|
+
/// @notice Calculates the fee required for Hyperlane cross-chain message dispatch
|
|
364
|
+
/// @dev Queries the Hyperlane mailbox for accurate fee estimation
|
|
365
|
+
/// @param toAddress Recipient address on the destination chain
|
|
366
|
+
/// @param token Token contract address being transferred
|
|
367
|
+
/// @param amount Amount of tokens being transferred
|
|
368
|
+
/// @return Fee amount in native currency required for the Hyperlane message
|
|
279
369
|
function getQuoteHyperlane(
|
|
280
370
|
address toAddress,
|
|
281
371
|
address token,
|
|
@@ -285,10 +375,15 @@ contract TreasuryHostChainStation is
|
|
|
285
375
|
IMailbox(hyperlane.mailboxAddress).quoteDispatch(
|
|
286
376
|
hyperlane.externalChainStationDomainId,
|
|
287
377
|
hyperlane.externalChainStationAddress,
|
|
288
|
-
encodePayload(token, toAddress, amount)
|
|
378
|
+
PayloadUtils.encodePayload(token, toAddress, amount)
|
|
289
379
|
);
|
|
290
380
|
}
|
|
291
381
|
|
|
382
|
+
/// @notice Handles incoming Hyperlane messages from the external chain
|
|
383
|
+
/// @dev Validates origin, sender authorization, and processes deposit to EVVM
|
|
384
|
+
/// @param _origin Source chain domain ID where the message originated
|
|
385
|
+
/// @param _sender Address of the message sender (must be external chain station)
|
|
386
|
+
/// @param _data Encoded payload containing deposit instructions
|
|
292
387
|
function handle(
|
|
293
388
|
uint32 _origin,
|
|
294
389
|
bytes32 _sender,
|
|
@@ -308,6 +403,12 @@ contract TreasuryHostChainStation is
|
|
|
308
403
|
|
|
309
404
|
// LayerZero Specific Functions //
|
|
310
405
|
|
|
406
|
+
/// @notice Calculates the fee required for LayerZero cross-chain message
|
|
407
|
+
/// @dev Queries LayerZero endpoint for accurate native fee estimation
|
|
408
|
+
/// @param toAddress Recipient address on the destination chain
|
|
409
|
+
/// @param token Token contract address being transferred
|
|
410
|
+
/// @param amount Amount of tokens being transferred
|
|
411
|
+
/// @return Native fee amount required for the LayerZero message
|
|
311
412
|
function quoteLayerZero(
|
|
312
413
|
address toAddress,
|
|
313
414
|
address token,
|
|
@@ -315,13 +416,17 @@ contract TreasuryHostChainStation is
|
|
|
315
416
|
) public view returns (uint256) {
|
|
316
417
|
MessagingFee memory fee = _quote(
|
|
317
418
|
layerZero.externalChainStationEid,
|
|
318
|
-
encodePayload(token, toAddress, amount),
|
|
319
|
-
|
|
419
|
+
PayloadUtils.encodePayload(token, toAddress, amount),
|
|
420
|
+
options,
|
|
320
421
|
false
|
|
321
422
|
);
|
|
322
423
|
return fee.nativeFee;
|
|
323
424
|
}
|
|
324
425
|
|
|
426
|
+
/// @notice Handles incoming LayerZero messages from the external chain
|
|
427
|
+
/// @dev Validates origin chain and sender, then processes deposit to EVVM
|
|
428
|
+
/// @param _origin Origin information containing source endpoint ID and sender
|
|
429
|
+
/// @param message Encoded payload containing deposit instructions
|
|
325
430
|
function _lzReceive(
|
|
326
431
|
Origin calldata _origin,
|
|
327
432
|
bytes32 /*_guid*/,
|
|
@@ -339,8 +444,46 @@ contract TreasuryHostChainStation is
|
|
|
339
444
|
decodeAndDeposit(message);
|
|
340
445
|
}
|
|
341
446
|
|
|
447
|
+
/// @notice Sends LayerZero messages to the destination chain
|
|
448
|
+
/// @dev Handles fee payment and message dispatch through LayerZero endpoint
|
|
449
|
+
/// @param _dstEid Destination endpoint ID (target chain)
|
|
450
|
+
/// @param _message Encoded message payload to send
|
|
451
|
+
/// @param _options Execution options for the destination chain
|
|
452
|
+
/// @param _fee Messaging fee structure (native + LZ token fees)
|
|
453
|
+
/// @param _refundAddress Address to receive excess fees
|
|
454
|
+
/// @return receipt Messaging receipt with transaction details
|
|
455
|
+
function _lzSend(
|
|
456
|
+
uint32 _dstEid,
|
|
457
|
+
bytes memory _message,
|
|
458
|
+
bytes memory _options,
|
|
459
|
+
MessagingFee memory _fee,
|
|
460
|
+
address _refundAddress
|
|
461
|
+
) internal override returns (MessagingReceipt memory receipt) {
|
|
462
|
+
// @dev Push corresponding fees to the endpoint, any excess is sent back to the _refundAddress from the endpoint.
|
|
463
|
+
uint256 messageValue = _fee.nativeFee;
|
|
464
|
+
if (_fee.lzTokenFee > 0) _payLzToken(_fee.lzTokenFee);
|
|
465
|
+
|
|
466
|
+
return
|
|
467
|
+
// solhint-disable-next-line check-send-result
|
|
468
|
+
endpoint.send{value: messageValue}(
|
|
469
|
+
MessagingParams(
|
|
470
|
+
_dstEid,
|
|
471
|
+
_getPeerOrRevert(_dstEid),
|
|
472
|
+
_message,
|
|
473
|
+
_options,
|
|
474
|
+
_fee.lzTokenFee > 0
|
|
475
|
+
),
|
|
476
|
+
_refundAddress
|
|
477
|
+
);
|
|
478
|
+
}
|
|
479
|
+
|
|
342
480
|
// Axelar Specific Functions //
|
|
343
481
|
|
|
482
|
+
/// @notice Handles incoming Axelar messages from the external chain
|
|
483
|
+
/// @dev Validates source chain and address, then processes deposit to EVVM
|
|
484
|
+
/// @param _sourceChain Source blockchain name (must match configured external chain)
|
|
485
|
+
/// @param _sourceAddress Source contract address (must match external chain station)
|
|
486
|
+
/// @param _payload Encoded payload containing deposit instructions
|
|
344
487
|
function _execute(
|
|
345
488
|
bytes32 /*commandId*/,
|
|
346
489
|
string calldata _sourceChain,
|
|
@@ -356,11 +499,9 @@ contract TreasuryHostChainStation is
|
|
|
356
499
|
decodeAndDeposit(_payload);
|
|
357
500
|
}
|
|
358
501
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
* @param _newOwner Address of the proposed new admin
|
|
363
|
-
*/
|
|
502
|
+
/// @notice Proposes a new admin address with 1-day time delay
|
|
503
|
+
/// @dev Part of the time-delayed governance system for admin changes
|
|
504
|
+
/// @param _newOwner Address of the proposed new admin (cannot be zero or current admin)
|
|
364
505
|
function proposeAdmin(address _newOwner) external onlyAdmin {
|
|
365
506
|
if (_newOwner == address(0) || _newOwner == admin.current) revert();
|
|
366
507
|
|
|
@@ -368,19 +509,15 @@ contract TreasuryHostChainStation is
|
|
|
368
509
|
admin.timeToAccept = block.timestamp + 1 days;
|
|
369
510
|
}
|
|
370
511
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
* @dev Allows current admin to reject proposed admin changes
|
|
374
|
-
*/
|
|
512
|
+
/// @notice Cancels a pending admin change proposal
|
|
513
|
+
/// @dev Allows current admin to reject proposed admin changes and reset proposal state
|
|
375
514
|
function rejectProposalAdmin() external onlyAdmin {
|
|
376
515
|
admin.proposal = address(0);
|
|
377
516
|
admin.timeToAccept = 0;
|
|
378
517
|
}
|
|
379
518
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
* @dev Can only be called by the proposed admin after the time delay
|
|
383
|
-
*/
|
|
519
|
+
/// @notice Accepts a pending admin proposal and becomes the new admin
|
|
520
|
+
/// @dev Can only be called by the proposed admin after the 1-day time delay
|
|
384
521
|
function acceptAdmin() external {
|
|
385
522
|
if (block.timestamp < admin.timeToAccept) revert();
|
|
386
523
|
|
|
@@ -390,8 +527,13 @@ contract TreasuryHostChainStation is
|
|
|
390
527
|
|
|
391
528
|
admin.proposal = address(0);
|
|
392
529
|
admin.timeToAccept = 0;
|
|
530
|
+
|
|
531
|
+
_transferOwnership(admin.current);
|
|
393
532
|
}
|
|
394
533
|
|
|
534
|
+
/// @notice Proposes a new Fisher executor address with 1-day time delay
|
|
535
|
+
/// @dev Fisher executor handles cross-chain bridge transaction processing
|
|
536
|
+
/// @param _newFisherExecutor Address of the proposed new Fisher executor
|
|
395
537
|
function proposeFisherExecutor(
|
|
396
538
|
address _newFisherExecutor
|
|
397
539
|
) external onlyAdmin {
|
|
@@ -404,11 +546,15 @@ contract TreasuryHostChainStation is
|
|
|
404
546
|
fisherExecutor.timeToAccept = block.timestamp + 1 days;
|
|
405
547
|
}
|
|
406
548
|
|
|
549
|
+
/// @notice Cancels a pending Fisher executor change proposal
|
|
550
|
+
/// @dev Allows current admin to reject Fisher executor changes and reset proposal state
|
|
407
551
|
function rejectProposalFisherExecutor() external onlyAdmin {
|
|
408
552
|
fisherExecutor.proposal = address(0);
|
|
409
553
|
fisherExecutor.timeToAccept = 0;
|
|
410
554
|
}
|
|
411
555
|
|
|
556
|
+
/// @notice Accepts a pending Fisher executor proposal
|
|
557
|
+
/// @dev Can only be called by the proposed Fisher executor after the 1-day time delay
|
|
412
558
|
function acceptFisherExecutor() external {
|
|
413
559
|
if (block.timestamp < fisherExecutor.timeToAccept) revert();
|
|
414
560
|
|
|
@@ -420,11 +566,73 @@ contract TreasuryHostChainStation is
|
|
|
420
566
|
fisherExecutor.timeToAccept = 0;
|
|
421
567
|
}
|
|
422
568
|
|
|
569
|
+
/// @notice Proposes new external chain addresses for all protocols with 1-day time delay
|
|
570
|
+
/// @dev Updates addresses across Hyperlane, LayerZero, and Axelar simultaneously
|
|
571
|
+
/// @param externalChainStationAddress Address-type representation for Hyperlane and LayerZero
|
|
572
|
+
/// @param externalChainStationAddressString String representation for Axelar protocol
|
|
573
|
+
function proposeExternalChainAddress(
|
|
574
|
+
address externalChainStationAddress,
|
|
575
|
+
string memory externalChainStationAddressString
|
|
576
|
+
) external onlyAdmin {
|
|
577
|
+
if (fuseSetExternalChainAddress == 0x01) revert();
|
|
578
|
+
|
|
579
|
+
externalChainAddressChangeProposal = ChangeExternalChainAddressParams({
|
|
580
|
+
porposeAddress_AddressType: externalChainStationAddress,
|
|
581
|
+
porposeAddress_StringType: externalChainStationAddressString,
|
|
582
|
+
timeToAccept: block.timestamp + 1 days
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
/// @notice Cancels a pending external chain address change proposal
|
|
587
|
+
/// @dev Resets the external chain address proposal to default state
|
|
588
|
+
function rejectProposalExternalChainAddress() external onlyAdmin {
|
|
589
|
+
externalChainAddressChangeProposal = ChangeExternalChainAddressParams({
|
|
590
|
+
porposeAddress_AddressType: address(0),
|
|
591
|
+
porposeAddress_StringType: "",
|
|
592
|
+
timeToAccept: 0
|
|
593
|
+
});
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
/// @notice Accepts pending external chain address changes across all protocols
|
|
597
|
+
/// @dev Updates Hyperlane, LayerZero, and Axelar configurations simultaneously
|
|
598
|
+
function acceptExternalChainAddress() external {
|
|
599
|
+
if (block.timestamp < externalChainAddressChangeProposal.timeToAccept)
|
|
600
|
+
revert();
|
|
601
|
+
|
|
602
|
+
hyperlane.externalChainStationAddress = bytes32(
|
|
603
|
+
uint256(
|
|
604
|
+
uint160(
|
|
605
|
+
externalChainAddressChangeProposal
|
|
606
|
+
.porposeAddress_AddressType
|
|
607
|
+
)
|
|
608
|
+
)
|
|
609
|
+
);
|
|
610
|
+
layerZero.externalChainStationAddress = bytes32(
|
|
611
|
+
uint256(
|
|
612
|
+
uint160(
|
|
613
|
+
externalChainAddressChangeProposal
|
|
614
|
+
.porposeAddress_AddressType
|
|
615
|
+
)
|
|
616
|
+
)
|
|
617
|
+
);
|
|
618
|
+
axelar.externalChainStationAddress = externalChainAddressChangeProposal
|
|
619
|
+
.porposeAddress_StringType;
|
|
620
|
+
_setPeer(
|
|
621
|
+
layerZero.externalChainStationEid,
|
|
622
|
+
layerZero.externalChainStationAddress
|
|
623
|
+
);
|
|
624
|
+
}
|
|
625
|
+
|
|
423
626
|
// Getter functions //
|
|
627
|
+
|
|
628
|
+
/// @notice Returns the complete admin configuration including proposals and timelock
|
|
629
|
+
/// @return Current admin address, proposed admin, and acceptance timestamp
|
|
424
630
|
function getAdmin() external view returns (AddressTypeProposal memory) {
|
|
425
631
|
return admin;
|
|
426
632
|
}
|
|
427
633
|
|
|
634
|
+
/// @notice Returns the complete Fisher executor configuration including proposals
|
|
635
|
+
/// @return Current Fisher executor, proposed executor, and acceptance timestamp
|
|
428
636
|
function getFisherExecutor()
|
|
429
637
|
external
|
|
430
638
|
view
|
|
@@ -433,16 +641,24 @@ contract TreasuryHostChainStation is
|
|
|
433
641
|
return fisherExecutor;
|
|
434
642
|
}
|
|
435
643
|
|
|
644
|
+
/// @notice Returns the next nonce for Fisher bridge operations for a specific user
|
|
645
|
+
/// @dev Used to prevent replay attacks in cross-chain bridge transactions
|
|
646
|
+
/// @param user Address to query the next Fisher execution nonce for
|
|
647
|
+
/// @return Next sequential nonce value for the user's Fisher bridge operations
|
|
436
648
|
function getNextFisherExecutionNonce(
|
|
437
649
|
address user
|
|
438
650
|
) external view returns (uint256) {
|
|
439
651
|
return nextFisherExecutionNonce[user];
|
|
440
652
|
}
|
|
441
653
|
|
|
654
|
+
/// @notice Returns the EVVM core contract address
|
|
655
|
+
/// @return Address of the EVVM contract used for balance operations
|
|
442
656
|
function getEvvmAddress() external view returns (address) {
|
|
443
657
|
return evvmAddress;
|
|
444
658
|
}
|
|
445
659
|
|
|
660
|
+
/// @notice Returns the complete Hyperlane protocol configuration
|
|
661
|
+
/// @return Hyperlane configuration including domain ID, external chain address, and mailbox
|
|
446
662
|
function getHyperlaneConfig()
|
|
447
663
|
external
|
|
448
664
|
view
|
|
@@ -451,6 +667,8 @@ contract TreasuryHostChainStation is
|
|
|
451
667
|
return hyperlane;
|
|
452
668
|
}
|
|
453
669
|
|
|
670
|
+
/// @notice Returns the complete LayerZero protocol configuration
|
|
671
|
+
/// @return LayerZero configuration including endpoint ID, external chain address, and endpoint
|
|
454
672
|
function getLayerZeroConfig()
|
|
455
673
|
external
|
|
456
674
|
view
|
|
@@ -459,38 +677,35 @@ contract TreasuryHostChainStation is
|
|
|
459
677
|
return layerZero;
|
|
460
678
|
}
|
|
461
679
|
|
|
680
|
+
/// @notice Returns the complete Axelar protocol configuration
|
|
681
|
+
/// @return Axelar configuration including chain name, addresses, gas service, and gateway
|
|
462
682
|
function getAxelarConfig() external view returns (AxelarConfig memory) {
|
|
463
683
|
return axelar;
|
|
464
684
|
}
|
|
465
685
|
|
|
686
|
+
/// @notice Returns the LayerZero execution options configuration
|
|
687
|
+
/// @return Encoded options bytes for LayerZero message execution (200k gas limit)
|
|
466
688
|
function getOptions() external view returns (bytes memory) {
|
|
467
|
-
return
|
|
689
|
+
return options;
|
|
468
690
|
}
|
|
469
691
|
|
|
470
692
|
// Internal Functions //
|
|
471
693
|
|
|
694
|
+
/// @notice Decodes cross-chain payload and credits EVVM balance
|
|
695
|
+
/// @dev Extracts token, recipient, and amount from payload and adds to EVVM balance
|
|
696
|
+
/// @param payload Encoded transfer data containing token, recipient, and amount
|
|
472
697
|
function decodeAndDeposit(bytes memory payload) internal {
|
|
473
|
-
(address token, address from, uint256 amount) =
|
|
698
|
+
(address token, address from, uint256 amount) = PayloadUtils
|
|
699
|
+
.decodePayload(payload);
|
|
474
700
|
executerEVVM(true, from, token, amount);
|
|
475
701
|
}
|
|
476
702
|
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
function decodePayload(
|
|
486
|
-
bytes memory payload
|
|
487
|
-
) internal pure returns (address token, address toAddress, uint256 amount) {
|
|
488
|
-
(token, toAddress, amount) = abi.decode(
|
|
489
|
-
payload,
|
|
490
|
-
(address, address, uint256)
|
|
491
|
-
);
|
|
492
|
-
}
|
|
493
|
-
|
|
703
|
+
/// @notice Executes EVVM balance operations (add or remove)
|
|
704
|
+
/// @dev Interface to EVVM's addAmountToUser and removeAmountFromUser functions
|
|
705
|
+
/// @param typeOfExecution True to add balance, false to remove balance
|
|
706
|
+
/// @param userToExecute Address whose balance will be modified
|
|
707
|
+
/// @param token Token contract address for the balance operation
|
|
708
|
+
/// @param amount Amount to add or remove from the user's balance
|
|
494
709
|
function executerEVVM(
|
|
495
710
|
bool typeOfExecution,
|
|
496
711
|
address userToExecute,
|
|
@@ -509,4 +724,14 @@ contract TreasuryHostChainStation is
|
|
|
509
724
|
);
|
|
510
725
|
}
|
|
511
726
|
}
|
|
727
|
+
|
|
728
|
+
/// @notice Disabled ownership transfer function for security
|
|
729
|
+
/// @dev Ownership changes must go through the time-delayed admin proposal system
|
|
730
|
+
function transferOwnership(
|
|
731
|
+
address newOwner
|
|
732
|
+
) public virtual override onlyOwner {}
|
|
733
|
+
|
|
734
|
+
/// @notice Disabled ownership renouncement function for security
|
|
735
|
+
/// @dev Prevents accidental loss of administrative control over the contract
|
|
736
|
+
function renounceOwnership() public virtual override onlyOwner {}
|
|
512
737
|
}
|
|
@@ -3,13 +3,44 @@
|
|
|
3
3
|
|
|
4
4
|
pragma solidity ^0.8.0;
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* @title ErrorsLib
|
|
8
|
+
* @author Mate labs
|
|
9
|
+
* @notice Custom error definitions for Treasury Cross-Chain operations
|
|
10
|
+
* @dev Centralized error library for both TreasuryHostChainStation and TreasuryExternalChainStation
|
|
11
|
+
* Provides gas-efficient custom errors with descriptive names for better debugging
|
|
12
|
+
* and user experience across all cross-chain treasury operations
|
|
13
|
+
*/
|
|
6
14
|
library ErrorsLib {
|
|
15
|
+
/// @notice Thrown when a user has insufficient balance for the requested operation
|
|
16
|
+
/// @dev Used in withdraw operations and Fisher bridge transfers when EVVM balance is too low
|
|
7
17
|
error InsufficientBalance();
|
|
18
|
+
|
|
19
|
+
/// @notice Thrown when attempting to withdraw or bridge the Principal Token (MATE)
|
|
20
|
+
/// @dev Principal Token is reserved for EVVM ecosystem operations and cannot be withdrawn cross-chain
|
|
8
21
|
error PrincipalTokenIsNotWithdrawable();
|
|
22
|
+
|
|
23
|
+
/// @notice Thrown when deposit amount validation fails
|
|
24
|
+
/// @dev Generic validation error for deposit amount issues beyond zero checks
|
|
9
25
|
error InvalidDepositAmount();
|
|
26
|
+
|
|
27
|
+
/// @notice Thrown when deposit or transfer amount is zero or negative
|
|
28
|
+
/// @dev Prevents meaningless transactions and ensures positive value transfers
|
|
10
29
|
error DepositAmountMustBeGreaterThanZero();
|
|
30
|
+
|
|
31
|
+
/// @notice Thrown when Hyperlane message sender is not the authorized mailbox contract
|
|
32
|
+
/// @dev Security check to prevent unauthorized cross-chain message execution via Hyperlane
|
|
11
33
|
error MailboxNotAuthorized();
|
|
34
|
+
|
|
35
|
+
/// @notice Thrown when cross-chain message sender is not the authorized counterpart station
|
|
36
|
+
/// @dev Security check across all protocols (Hyperlane, LayerZero, Axelar) to prevent impersonation
|
|
12
37
|
error SenderNotAuthorized();
|
|
38
|
+
|
|
39
|
+
/// @notice Thrown when cross-chain message originates from non-authorized chain
|
|
40
|
+
/// @dev Prevents cross-chain attacks from unauthorized chains or wrong network configurations
|
|
13
41
|
error ChainIdNotAuthorized();
|
|
42
|
+
|
|
43
|
+
/// @notice Thrown when Fisher bridge signature verification fails
|
|
44
|
+
/// @dev Security check for Fisher bridge operations to ensure transaction authenticity and prevent replay attacks
|
|
14
45
|
error InvalidSignature();
|
|
15
46
|
}
|