@evvm/testnet-contracts 2.1.0 → 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.
@@ -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
- 888b d888 888 .d8888b. 888 888
7
- 8888b d8888 888 d88P Y88b 888 888
8
- 88888b.d88888 888 888 888 888 888
9
- 888Y88888P888 .d88b. .d8888b 888 888 888 .d88b. 88888b. 888888 888d888 8888b. .d8888b 888888
10
- 888 Y888P 888 d88""88b d88P" 888 .88P 888 d88""88b 888 "88b 888 888P" "88b d88P" 888
11
- 888 Y8P 888 888 888 888 888888K 888 888 888 888 888 888 888 888 .d888888 888 888
12
- 888 " 888 Y88..88P Y88b. 888 "88b Y88b d88P Y88..88P 888 888 Y88b. 888 888 888 Y88b. Y88b.
13
- 888 888 "Y88P" "Y8888P 888 888 "Y8888P" "Y88P" 888 888 "Y888 888 "Y888888 "Y8888P "Y888
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
- bytes _options =
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
- 50000,
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
- * @notice Initialize Treasury with EVVM contract address
88
- * @param _evvmAddress Address of the EVVM core contract
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
- function setExternalChainAddress(
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
- * @notice Withdraw ETH or ERC20 tokens
144
- * @param token Token address (address(0) for ETH)
145
- * @param amount Amount to withdraw
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(token, toAddress, amount);
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
- _options,
180
- MessagingFee(fee, 0),
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
- _options,
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
- * @notice Proposes a new admin address with 1-day time delay
361
- * @dev Part of the time-delayed governance system for admin changes
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
- * @notice Cancels a pending admin change proposal
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
- * @notice Accepts a pending admin proposal and becomes the new admin
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 _options;
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) = decodePayload(payload);
698
+ (address token, address from, uint256 amount) = PayloadUtils
699
+ .decodePayload(payload);
474
700
  executerEVVM(true, from, token, amount);
475
701
  }
476
702
 
477
- function encodePayload(
478
- address token,
479
- address toAddress,
480
- uint256 amount
481
- ) internal pure returns (bytes memory payload) {
482
- payload = abi.encode(token, toAddress, amount);
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
  }