@keep-network/tbtc-v2 1.3.0-dev.5 → 1.3.0-dev.7

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.
Files changed (111) hide show
  1. package/artifacts/BLS.json +1 -1
  2. package/artifacts/Bank.json +3 -3
  3. package/artifacts/BeaconAuthorization.json +1 -1
  4. package/artifacts/BeaconDkg.json +6 -6
  5. package/artifacts/BeaconDkgValidator.json +8 -8
  6. package/artifacts/BeaconInactivity.json +8 -8
  7. package/artifacts/BeaconSortitionPool.json +3 -3
  8. package/artifacts/Bridge.json +5 -5
  9. package/artifacts/BridgeGovernance.json +2 -2
  10. package/artifacts/BridgeGovernanceParameters.json +2 -2
  11. package/artifacts/Deposit.json +2 -2
  12. package/artifacts/DepositSweep.json +2 -2
  13. package/artifacts/DonationVault.json +3 -3
  14. package/artifacts/EcdsaDkgValidator.json +6 -6
  15. package/artifacts/EcdsaInactivity.json +8 -8
  16. package/artifacts/EcdsaSortitionPool.json +4 -4
  17. package/artifacts/Fraud.json +2 -2
  18. package/artifacts/KeepRegistry.json +1 -1
  19. package/artifacts/KeepStake.json +2 -2
  20. package/artifacts/KeepToken.json +2 -2
  21. package/artifacts/KeepTokenStaking.json +1 -1
  22. package/artifacts/LightRelay.json +18 -18
  23. package/artifacts/LightRelayMaintainerProxy.json +8 -8
  24. package/artifacts/MaintainerProxy.json +19 -19
  25. package/artifacts/MovingFunds.json +2 -2
  26. package/artifacts/NuCypherStakingEscrow.json +1 -1
  27. package/artifacts/NuCypherToken.json +2 -2
  28. package/artifacts/RandomBeacon.json +109 -109
  29. package/artifacts/RandomBeaconChaosnet.json +4 -4
  30. package/artifacts/RandomBeaconGovernance.json +59 -59
  31. package/artifacts/Redemption.json +2 -2
  32. package/artifacts/ReimbursementPool.json +13 -13
  33. package/artifacts/T.json +2 -2
  34. package/artifacts/TBTC.json +3 -3
  35. package/artifacts/TBTCToken.json +3 -3
  36. package/artifacts/TBTCVault.json +23 -23
  37. package/artifacts/TokenStaking.json +1 -1
  38. package/artifacts/TokenholderGovernor.json +9 -9
  39. package/artifacts/TokenholderTimelock.json +8 -8
  40. package/artifacts/VendingMachine.json +3 -3
  41. package/artifacts/VendingMachineKeep.json +1 -1
  42. package/artifacts/VendingMachineNuCypher.json +1 -1
  43. package/artifacts/VendingMachineV2.json +3 -3
  44. package/artifacts/VendingMachineV3.json +3 -3
  45. package/artifacts/WalletCoordinator.json +154 -143
  46. package/artifacts/WalletRegistry.json +5 -5
  47. package/artifacts/WalletRegistryGovernance.json +50 -50
  48. package/artifacts/Wallets.json +2 -2
  49. package/artifacts/solcInputs/{08bd3c90d7f376263925b4f52b0adff9.json → 113b54a69049e9a4de4a520973971e13.json} +1 -1
  50. package/build/contracts/GovernanceUtils.sol/GovernanceUtils.dbg.json +1 -1
  51. package/build/contracts/bank/Bank.sol/Bank.dbg.json +1 -1
  52. package/build/contracts/bank/IReceiveBalanceApproval.sol/IReceiveBalanceApproval.dbg.json +1 -1
  53. package/build/contracts/bridge/BitcoinTx.sol/BitcoinTx.dbg.json +1 -1
  54. package/build/contracts/bridge/Bridge.sol/Bridge.dbg.json +1 -1
  55. package/build/contracts/bridge/BridgeGovernanceParameters.sol/BridgeGovernanceParameters.dbg.json +1 -1
  56. package/build/contracts/bridge/BridgeState.sol/BridgeState.dbg.json +1 -1
  57. package/build/contracts/bridge/Deposit.sol/Deposit.dbg.json +1 -1
  58. package/build/contracts/bridge/DepositSweep.sol/DepositSweep.dbg.json +1 -1
  59. package/build/contracts/bridge/EcdsaLib.sol/EcdsaLib.dbg.json +1 -1
  60. package/build/contracts/bridge/Fraud.sol/Fraud.dbg.json +1 -1
  61. package/build/contracts/bridge/Heartbeat.sol/Heartbeat.dbg.json +1 -1
  62. package/build/contracts/bridge/IRelay.sol/IRelay.dbg.json +1 -1
  63. package/build/contracts/bridge/MovingFunds.sol/MovingFunds.dbg.json +1 -1
  64. package/build/contracts/bridge/Redemption.sol/OutboundTx.dbg.json +1 -1
  65. package/build/contracts/bridge/Redemption.sol/Redemption.dbg.json +1 -1
  66. package/build/contracts/bridge/VendingMachine.sol/VendingMachine.dbg.json +1 -1
  67. package/build/contracts/bridge/VendingMachineV2.sol/VendingMachineV2.dbg.json +1 -1
  68. package/build/contracts/bridge/VendingMachineV3.sol/VendingMachineV3.dbg.json +1 -1
  69. package/build/contracts/bridge/WalletCoordinator.sol/WalletCoordinator.dbg.json +1 -1
  70. package/build/contracts/bridge/WalletCoordinator.sol/WalletCoordinator.json +143 -132
  71. package/build/contracts/bridge/Wallets.sol/Wallets.dbg.json +1 -1
  72. package/build/contracts/l2/L2TBTC.sol/L2TBTC.dbg.json +1 -1
  73. package/build/contracts/l2/L2WormholeGateway.sol/IWormholeTokenBridge.dbg.json +1 -1
  74. package/build/contracts/l2/L2WormholeGateway.sol/L2WormholeGateway.dbg.json +1 -1
  75. package/build/contracts/maintainer/MaintainerProxy.sol/MaintainerProxy.dbg.json +1 -1
  76. package/build/contracts/relay/LightRelay.sol/ILightRelay.dbg.json +1 -1
  77. package/build/contracts/relay/LightRelay.sol/LightRelay.dbg.json +1 -1
  78. package/build/contracts/relay/LightRelay.sol/RelayUtils.dbg.json +1 -1
  79. package/build/contracts/relay/LightRelayMaintainerProxy.sol/LightRelayMaintainerProxy.dbg.json +1 -1
  80. package/build/contracts/token/TBTC.sol/TBTC.dbg.json +1 -1
  81. package/build/contracts/vault/DonationVault.sol/DonationVault.dbg.json +1 -1
  82. package/build/contracts/vault/IVault.sol/IVault.dbg.json +1 -1
  83. package/build/contracts/vault/TBTCOptimisticMinting.sol/TBTCOptimisticMinting.dbg.json +1 -1
  84. package/build/contracts/vault/TBTCVault.sol/TBTCVault.dbg.json +1 -1
  85. package/contracts/bridge/WalletCoordinator.sol +136 -134
  86. package/export/artifacts/contracts/bridge/Bridge.sol/Bridge.json +22 -22
  87. package/export/artifacts/contracts/bridge/VendingMachine.sol/VendingMachine.json +6 -6
  88. package/export/artifacts/contracts/bridge/VendingMachineV2.sol/VendingMachineV2.json +6 -6
  89. package/export/artifacts/contracts/bridge/VendingMachineV3.sol/VendingMachineV3.json +6 -6
  90. package/export/artifacts/contracts/bridge/WalletCoordinator.sol/WalletCoordinator.json +8745 -8247
  91. package/export/artifacts/contracts/l2/L2TBTC.sol/L2TBTC.json +40 -40
  92. package/export/artifacts/contracts/l2/L2WormholeGateway.sol/L2WormholeGateway.json +47 -47
  93. package/export/artifacts/contracts/maintainer/MaintainerProxy.sol/MaintainerProxy.json +88 -88
  94. package/export/artifacts/contracts/relay/LightRelay.sol/LightRelay.json +57 -57
  95. package/export/artifacts/contracts/relay/LightRelayMaintainerProxy.sol/LightRelayMaintainerProxy.json +31 -31
  96. package/export/artifacts/contracts/test/BankStub.sol/BankStub.json +2 -2
  97. package/export/artifacts/contracts/test/BridgeStub.sol/BridgeStub.json +58 -58
  98. package/export/artifacts/contracts/test/GoerliLightRelay.sol/GoerliLightRelay.json +57 -57
  99. package/export/artifacts/contracts/test/HeartbeatStub.sol/HeartbeatStub.json +2 -2
  100. package/export/artifacts/contracts/test/LightRelayStub.sol/LightRelayStub.json +59 -59
  101. package/export/artifacts/contracts/test/ReceiveApprovalStub.sol/ReceiveApprovalStub.json +7 -7
  102. package/export/artifacts/contracts/test/SystemTestRelay.sol/SystemTestRelay.json +14 -14
  103. package/export/artifacts/contracts/test/TestERC20.sol/TestERC20.json +6 -6
  104. package/export/artifacts/contracts/test/TestERC721.sol/TestERC721.json +8 -8
  105. package/export/artifacts/contracts/test/TestEcdsaLib.sol/TestEcdsaLib.json +2 -2
  106. package/export/artifacts/contracts/test/WormholeBridgeStub.sol/WormholeBridgeStub.json +37 -37
  107. package/export/artifacts/contracts/token/TBTC.sol/TBTC.json +2 -2
  108. package/export/artifacts/contracts/vault/DonationVault.sol/DonationVault.json +11 -11
  109. package/export/artifacts/contracts/vault/TBTCVault.sol/TBTCVault.json +135 -135
  110. package/export/typechain/factories/WalletCoordinator__factory.js +137 -126
  111. package/package.json +3 -3
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "_format": "hh-sol-dbg-1",
3
- "buildInfo": "../../../build-info/4dae352543b4d68232673fef698e9426.json"
3
+ "buildInfo": "../../../build-info/3909615ca5118087c155583cb43fa5d3.json"
4
4
  }
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "_format": "hh-sol-dbg-1",
3
- "buildInfo": "../../../build-info/4dae352543b4d68232673fef698e9426.json"
3
+ "buildInfo": "../../../build-info/3909615ca5118087c155583cb43fa5d3.json"
4
4
  }
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "_format": "hh-sol-dbg-1",
3
- "buildInfo": "../../../build-info/4dae352543b4d68232673fef698e9426.json"
3
+ "buildInfo": "../../../build-info/3909615ca5118087c155583cb43fa5d3.json"
4
4
  }
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "_format": "hh-sol-dbg-1",
3
- "buildInfo": "../../../build-info/4dae352543b4d68232673fef698e9426.json"
3
+ "buildInfo": "../../../build-info/3909615ca5118087c155583cb43fa5d3.json"
4
4
  }
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "_format": "hh-sol-dbg-1",
3
- "buildInfo": "../../../build-info/4dae352543b4d68232673fef698e9426.json"
3
+ "buildInfo": "../../../build-info/3909615ca5118087c155583cb43fa5d3.json"
4
4
  }
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "_format": "hh-sol-dbg-1",
3
- "buildInfo": "../../../build-info/4dae352543b4d68232673fef698e9426.json"
3
+ "buildInfo": "../../../build-info/3909615ca5118087c155583cb43fa5d3.json"
4
4
  }
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "_format": "hh-sol-dbg-1",
3
- "buildInfo": "../../../build-info/4dae352543b4d68232673fef698e9426.json"
3
+ "buildInfo": "../../../build-info/3909615ca5118087c155583cb43fa5d3.json"
4
4
  }
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "_format": "hh-sol-dbg-1",
3
- "buildInfo": "../../../build-info/4dae352543b4d68232673fef698e9426.json"
3
+ "buildInfo": "../../../build-info/3909615ca5118087c155583cb43fa5d3.json"
4
4
  }
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "_format": "hh-sol-dbg-1",
3
- "buildInfo": "../../../build-info/4dae352543b4d68232673fef698e9426.json"
3
+ "buildInfo": "../../../build-info/3909615ca5118087c155583cb43fa5d3.json"
4
4
  }
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "_format": "hh-sol-dbg-1",
3
- "buildInfo": "../../../build-info/4dae352543b4d68232673fef698e9426.json"
3
+ "buildInfo": "../../../build-info/3909615ca5118087c155583cb43fa5d3.json"
4
4
  }
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "_format": "hh-sol-dbg-1",
3
- "buildInfo": "../../../build-info/4dae352543b4d68232673fef698e9426.json"
3
+ "buildInfo": "../../../build-info/3909615ca5118087c155583cb43fa5d3.json"
4
4
  }
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "_format": "hh-sol-dbg-1",
3
- "buildInfo": "../../../build-info/4dae352543b4d68232673fef698e9426.json"
3
+ "buildInfo": "../../../build-info/3909615ca5118087c155583cb43fa5d3.json"
4
4
  }
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "_format": "hh-sol-dbg-1",
3
- "buildInfo": "../../../build-info/4dae352543b4d68232673fef698e9426.json"
3
+ "buildInfo": "../../../build-info/3909615ca5118087c155583cb43fa5d3.json"
4
4
  }
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "_format": "hh-sol-dbg-1",
3
- "buildInfo": "../../../build-info/4dae352543b4d68232673fef698e9426.json"
3
+ "buildInfo": "../../../build-info/3909615ca5118087c155583cb43fa5d3.json"
4
4
  }
@@ -17,7 +17,6 @@ pragma solidity 0.8.17;
17
17
 
18
18
  import {BTCUtils} from "@keep-network/bitcoin-spv-sol/contracts/BTCUtils.sol";
19
19
  import {BytesLib} from "@keep-network/bitcoin-spv-sol/contracts/BytesLib.sol";
20
- import {IWalletRegistry as EcdsaWalletRegistry} from "@keep-network/ecdsa/contracts/api/IWalletRegistry.sol";
21
20
  import "@keep-network/random-beacon/contracts/Reimbursable.sol";
22
21
  import "@keep-network/random-beacon/contracts/ReimbursementPool.sol";
23
22
 
@@ -49,6 +48,8 @@ contract WalletCoordinator is OwnableUpgradeable, Reimbursable {
49
48
  enum WalletAction {
50
49
  /// @dev The wallet does not perform any action.
51
50
  Idle,
51
+ /// @dev The wallet is executing heartbeat.
52
+ Heartbeat,
52
53
  /// @dev The wallet is handling a deposit sweep action.
53
54
  DepositSweep,
54
55
  /// @dev The wallet is handling a redemption action.
@@ -70,13 +71,6 @@ contract WalletCoordinator is OwnableUpgradeable, Reimbursable {
70
71
  WalletAction cause;
71
72
  }
72
73
 
73
- /// @notice Helper structure carrying data necessary to validate the wallet
74
- /// membership of the caller.
75
- struct WalletMemberContext {
76
- uint32[] walletMembersIDs;
77
- uint256 walletMemberIndex;
78
- }
79
-
80
74
  /// @notice Helper structure representing a deposit sweep proposal.
81
75
  struct DepositSweepProposal {
82
76
  // 20-byte public key hash of the target wallet.
@@ -116,8 +110,9 @@ contract WalletCoordinator is OwnableUpgradeable, Reimbursable {
116
110
  bytes4 refundLocktime;
117
111
  }
118
112
 
119
- /// @notice Mapping that holds addresses allowed to submit proposals.
120
- mapping(address => bool) public isProposalSubmitter;
113
+ /// @notice Mapping that holds addresses allowed to submit proposals and
114
+ /// request heartbeats.
115
+ mapping(address => bool) public isCoordinator;
121
116
 
122
117
  /// @notice Mapping that holds wallet time locks. The key is a 20-byte
123
118
  /// wallet public key hash.
@@ -126,8 +121,20 @@ contract WalletCoordinator is OwnableUpgradeable, Reimbursable {
126
121
  /// @notice Handle to the Bridge contract.
127
122
  Bridge public bridge;
128
123
 
129
- /// @notice Handle to the WalletRegistry contract.
130
- EcdsaWalletRegistry public walletRegistry;
124
+ /// @notice Determines the wallet heartbeat request validity time. In other
125
+ /// words, this is the worst-case time for a wallet heartbeat
126
+ /// during which the wallet is busy and canot take other actions.
127
+ /// This is also the duration of the time lock applied to the wallet
128
+ /// once a new heartbeat request is submitted.
129
+ ///
130
+ /// For example, if a deposit sweep proposal was submitted at
131
+ /// 2 pm and heartbeatRequestValidity is 1 hour, the next request or
132
+ /// proposal (of any type) can be submitted after 3 pm.
133
+ uint32 public heartbeatRequestValidity;
134
+
135
+ /// @notice Gas that is meant to balance the heartbeat request overall cost.
136
+ /// Can be updated by the owner based on the current conditions.
137
+ uint32 public heartbeatRequestGasOffset;
131
138
 
132
139
  /// @notice Determines the deposit sweep proposal validity time. In other
133
140
  /// words, this is the worst-case time for a deposit sweep during
@@ -175,61 +182,37 @@ contract WalletCoordinator is OwnableUpgradeable, Reimbursable {
175
182
 
176
183
  /// @notice Gas that is meant to balance the deposit sweep proposal
177
184
  /// submission overall cost. Can be updated by the owner based on
178
- /// the current market conditions.
185
+ /// the current conditions.
179
186
  uint32 public depositSweepProposalSubmissionGasOffset;
180
187
 
181
- event ProposalSubmitterAdded(address indexed proposalSubmitter);
188
+ event CoordinatorAdded(address indexed coordinator);
182
189
 
183
- event ProposalSubmitterRemoved(address indexed proposalSubmitter);
190
+ event CoordinatorRemoved(address indexed coordinator);
184
191
 
185
192
  event WalletManuallyUnlocked(bytes20 indexed walletPubKeyHash);
186
193
 
187
- event DepositSweepProposalValidityUpdated(
188
- uint32 depositSweepProposalValidity
194
+ event HeartbeatRequestParametersUpdated(
195
+ uint32 heartbeatRequestValidity,
196
+ uint32 heartbeatRequestGasOffset
189
197
  );
190
198
 
191
- event DepositMinAgeUpdated(uint32 depositMinAge);
192
-
193
- event DepositRefundSafetyMarginUpdated(uint32 depositRefundSafetyMargin);
194
-
195
- event DepositSweepMaxSizeUpdated(uint16 depositSweepMaxSize);
199
+ event HeartbeatRequestSubmitted(bytes20 walletPubKeyHash, bytes message);
196
200
 
197
- event DepositSweepProposalSubmissionGasOffsetUpdated(
201
+ event DepositSweepProposalParametersUpdated(
202
+ uint32 depositSweepProposalValidity,
203
+ uint32 depositMinAge,
204
+ uint32 depositRefundSafetyMargin,
205
+ uint16 depositSweepMaxSize,
198
206
  uint32 depositSweepProposalSubmissionGasOffset
199
207
  );
200
208
 
201
209
  event DepositSweepProposalSubmitted(
202
210
  DepositSweepProposal proposal,
203
- address indexed proposalSubmitter
211
+ address indexed coordinator
204
212
  );
205
213
 
206
- // TODO: Enhance this modifier by adding the coordinator role check. See:
207
- // https://github.com/keep-network/tbtc-v2/pull/575#discussion_r1151564813
208
- modifier onlyProposalSubmitterOrWalletMember(
209
- bytes20 walletPubKeyHash,
210
- WalletMemberContext calldata walletMemberContext
211
- ) {
212
- bool proposalSubmitter = isProposalSubmitter[msg.sender];
213
- bool walletMember = false;
214
-
215
- if (!proposalSubmitter) {
216
- bytes32 ecdsaWalletID = bridge
217
- .wallets(walletPubKeyHash)
218
- .ecdsaWalletID;
219
-
220
- walletMember = walletRegistry.isWalletMember(
221
- ecdsaWalletID,
222
- walletMemberContext.walletMembersIDs,
223
- msg.sender,
224
- walletMemberContext.walletMemberIndex
225
- );
226
- }
227
-
228
- require(
229
- proposalSubmitter || walletMember,
230
- "Caller is neither a proposal submitter nor a wallet member"
231
- );
232
-
214
+ modifier onlyCoordinator() {
215
+ require(isCoordinator[msg.sender], "Caller is not a coordinator");
233
216
  _;
234
217
  }
235
218
 
@@ -251,49 +234,45 @@ contract WalletCoordinator is OwnableUpgradeable, Reimbursable {
251
234
  __Ownable_init();
252
235
 
253
236
  bridge = _bridge;
254
- // Pre-fetch wallet registry address to save gas on calls protected
255
- // by the onlyProposalSubmitterOrWalletMember modifier.
256
- (, , walletRegistry, reimbursementPool) = _bridge.contractReferences();
237
+ // Pre-fetch addresses to save gas later.
238
+ (, , , reimbursementPool) = _bridge.contractReferences();
239
+
240
+ heartbeatRequestValidity = 1 hours;
241
+ heartbeatRequestGasOffset = 5_000;
257
242
 
258
243
  depositSweepProposalValidity = 4 hours;
259
244
  depositMinAge = 2 hours;
260
245
  depositRefundSafetyMargin = 24 hours;
261
246
  depositSweepMaxSize = 5;
262
- depositSweepProposalSubmissionGasOffset = 25000;
247
+ depositSweepProposalSubmissionGasOffset = 5_000;
263
248
  }
264
249
 
265
- /// @notice Adds the given address to the proposal submitters set.
266
- /// @param proposalSubmitter Address of the new proposal submitter.
250
+ /// @notice Adds the given address to the set of coordinator addresses.
251
+ /// @param coordinator Address of the new coordinator.
267
252
  /// @dev Requirements:
268
253
  /// - The caller must be the owner,
269
- /// - The `proposalSubmitter` must not be an existing proposal submitter.
270
- function addProposalSubmitter(address proposalSubmitter)
271
- external
272
- onlyOwner
273
- {
254
+ /// - The `coordinator` must not be an existing coordinator.
255
+ function addCoordinator(address coordinator) external onlyOwner {
274
256
  require(
275
- !isProposalSubmitter[proposalSubmitter],
276
- "This address is already a proposal submitter"
257
+ !isCoordinator[coordinator],
258
+ "This address is already a coordinator"
277
259
  );
278
- isProposalSubmitter[proposalSubmitter] = true;
279
- emit ProposalSubmitterAdded(proposalSubmitter);
260
+ isCoordinator[coordinator] = true;
261
+ emit CoordinatorAdded(coordinator);
280
262
  }
281
263
 
282
- /// @notice Removes the given address from the proposal submitters set.
283
- /// @param proposalSubmitter Address of the existing proposal submitter.
264
+ /// @notice Removes the given address from the set of coordinator addresses.
265
+ /// @param coordinator Address of the existing coordinator.
284
266
  /// @dev Requirements:
285
267
  /// - The caller must be the owner,
286
- /// - The `proposalSubmitter` must be an existing proposal submitter.
287
- function removeProposalSubmitter(address proposalSubmitter)
288
- external
289
- onlyOwner
290
- {
268
+ /// - The `coordinator` must be an existing coordinator.
269
+ function removeCoordinator(address coordinator) external onlyOwner {
291
270
  require(
292
- isProposalSubmitter[proposalSubmitter],
293
- "This address is not a proposal submitter"
271
+ isCoordinator[coordinator],
272
+ "This address is not a coordinator"
294
273
  );
295
- delete isProposalSubmitter[proposalSubmitter];
296
- emit ProposalSubmitterRemoved(proposalSubmitter);
274
+ delete isCoordinator[coordinator];
275
+ emit CoordinatorRemoved(coordinator);
297
276
  }
298
277
 
299
278
  /// @notice Allows to unlock the given wallet before their time lock expires.
@@ -309,61 +288,96 @@ contract WalletCoordinator is OwnableUpgradeable, Reimbursable {
309
288
  emit WalletManuallyUnlocked(walletPubKeyHash);
310
289
  }
311
290
 
312
- /// @notice Updates the value of the depositSweepProposalValidity parameter.
313
- /// @param _depositSweepProposalValidity New value.
291
+ /// @notice Updates parameters related to heartbeat request.
292
+ /// @param _heartbeatRequestValidity The new value of `heartbeatRequestValidity`.
293
+ /// @param _heartbeatRequestGasOffset The new value of `heartbeatRequestGasOffset`.
314
294
  /// @dev Requirements:
315
295
  /// - The caller must be the owner.
316
- function updateDepositSweepProposalValidity(
317
- uint32 _depositSweepProposalValidity
296
+ function updateHeartbeatRequestParameters(
297
+ uint32 _heartbeatRequestValidity,
298
+ uint32 _heartbeatRequestGasOffset
318
299
  ) external onlyOwner {
319
- depositSweepProposalValidity = _depositSweepProposalValidity;
320
- emit DepositSweepProposalValidityUpdated(_depositSweepProposalValidity);
300
+ heartbeatRequestValidity = _heartbeatRequestValidity;
301
+ heartbeatRequestGasOffset = _heartbeatRequestGasOffset;
302
+ emit HeartbeatRequestParametersUpdated(
303
+ _heartbeatRequestValidity,
304
+ _heartbeatRequestGasOffset
305
+ );
321
306
  }
322
307
 
323
- /// @notice Updates the value of the depositMinAge parameter.
324
- /// @param _depositMinAge New value.
308
+ /// @notice Updates parameters related to deposit sweep proposal.
309
+ /// @param _depositSweepProposalValidity The new value of `depositSweepProposalValidity`.
310
+ /// @param _depositMinAge The new value of `depositMinAge`.
311
+ /// @param _depositRefundSafetyMargin The new value of `depositRefundSafetyMargin`.
312
+ /// @param _depositSweepMaxSize The new value of `depositSweepMaxSize`.
325
313
  /// @dev Requirements:
326
314
  /// - The caller must be the owner.
327
- function updateDepositMinAge(uint32 _depositMinAge) external onlyOwner {
315
+ function updateDepositSweepProposalParameters(
316
+ uint32 _depositSweepProposalValidity,
317
+ uint32 _depositMinAge,
318
+ uint32 _depositRefundSafetyMargin,
319
+ uint16 _depositSweepMaxSize,
320
+ uint32 _depositSweepProposalSubmissionGasOffset
321
+ ) external onlyOwner {
322
+ depositSweepProposalValidity = _depositSweepProposalValidity;
328
323
  depositMinAge = _depositMinAge;
329
- emit DepositMinAgeUpdated(_depositMinAge);
330
- }
331
-
332
- /// @notice Updates the value of the depositRefundSafetyMargin parameter.
333
- /// @param _depositRefundSafetyMargin New value.
334
- /// @dev Requirements:
335
- /// - The caller must be the owner.
336
- function updateDepositRefundSafetyMargin(uint32 _depositRefundSafetyMargin)
337
- external
338
- onlyOwner
339
- {
340
324
  depositRefundSafetyMargin = _depositRefundSafetyMargin;
341
- emit DepositRefundSafetyMarginUpdated(_depositRefundSafetyMargin);
325
+ depositSweepMaxSize = _depositSweepMaxSize;
326
+ depositSweepProposalSubmissionGasOffset = _depositSweepProposalSubmissionGasOffset;
327
+
328
+ emit DepositSweepProposalParametersUpdated(
329
+ _depositSweepProposalValidity,
330
+ _depositMinAge,
331
+ _depositRefundSafetyMargin,
332
+ _depositSweepMaxSize,
333
+ _depositSweepProposalSubmissionGasOffset
334
+ );
342
335
  }
343
336
 
344
- /// @notice Updates the value of the depositSweepMaxSize parameter.
345
- /// @param _depositSweepMaxSize New value.
337
+ /// @notice Submits a heartbeat request from the wallet. Locks the wallet
338
+ /// for a specific time, equal to the request validity period.
339
+ /// This function validates the proposed heartbeat messge to see
340
+ /// if it matches the heartbeat format expected by the Bridge.
341
+ /// @param walletPubKeyHash 20-byte public key hash of the wallet that is
342
+ /// supposed to execute the heartbeat.
343
+ /// @param message The proposed heartbeat message for the wallet to sign.
346
344
  /// @dev Requirements:
347
- /// - The caller must be the owner.
348
- function updateDepositSweepMaxSize(uint16 _depositSweepMaxSize)
349
- external
350
- onlyOwner
345
+ /// - The caller is a coordinator,
346
+ /// - The wallet is not time-locked,
347
+ /// - The message to sign is a valid heartbeat message.
348
+ function requestHeartbeat(bytes20 walletPubKeyHash, bytes calldata message)
349
+ public
350
+ onlyCoordinator
351
+ onlyAfterWalletLock(walletPubKeyHash)
351
352
  {
352
- depositSweepMaxSize = _depositSweepMaxSize;
353
- emit DepositSweepMaxSizeUpdated(_depositSweepMaxSize);
353
+ require(
354
+ Heartbeat.isValidHeartbeatMessage(message),
355
+ "Not a valid heartbeat message"
356
+ );
357
+
358
+ walletLock[walletPubKeyHash] = WalletLock(
359
+ /* solhint-disable-next-line not-rely-on-time */
360
+ uint32(block.timestamp) + heartbeatRequestValidity,
361
+ WalletAction.Heartbeat
362
+ );
363
+
364
+ emit HeartbeatRequestSubmitted(walletPubKeyHash, message);
354
365
  }
355
366
 
356
- /// @notice Updates the value of the depositSweepProposalSubmissionGasOffset
357
- /// parameter.
358
- /// @param _depositSweepProposalSubmissionGasOffset New value.
359
- /// @dev Requirements:
360
- /// - The caller must be the owner.
361
- function updateDepositSweepProposalSubmissionGasOffset(
362
- uint32 _depositSweepProposalSubmissionGasOffset
363
- ) external onlyOwner {
364
- depositSweepProposalSubmissionGasOffset = _depositSweepProposalSubmissionGasOffset;
365
- emit DepositSweepProposalSubmissionGasOffsetUpdated(
366
- _depositSweepProposalSubmissionGasOffset
367
+ /// @notice Wraps `requestHeartbeat` call and reimburses the caller's
368
+ /// transaction cost.
369
+ /// @dev See `requestHeartbeat` function documentation.
370
+ function requestHeartbeatWithReimbursement(
371
+ bytes20 walletPubKeyHash,
372
+ bytes calldata message
373
+ ) external {
374
+ uint256 gasStart = gasleft();
375
+
376
+ requestHeartbeat(walletPubKeyHash, message);
377
+
378
+ reimbursementPool.refund(
379
+ (gasStart - gasleft()) + heartbeatRequestGasOffset,
380
+ msg.sender
367
381
  );
368
382
  }
369
383
 
@@ -374,23 +388,12 @@ contract WalletCoordinator is OwnableUpgradeable, Reimbursable {
374
388
  /// off-chain members. Wallet members are supposed to validate
375
389
  /// the proposal on their own, before taking any action.
376
390
  /// @param proposal The deposit sweep proposal
377
- /// @param walletMemberContext Optional parameter holding some data allowing
378
- /// to confirm the wallet membership of the caller. This parameter is
379
- /// relevant only when the caller is not a registered proposal
380
- /// submitter but claims to be a member of the target wallet.
381
391
  /// @dev Requirements:
382
- /// - The caller is either a proposal submitter or a member of the
383
- /// target wallet,
392
+ /// - The caller is a coordinator,
384
393
  /// - The wallet is not time-locked.
385
- function submitDepositSweepProposal(
386
- DepositSweepProposal calldata proposal,
387
- WalletMemberContext calldata walletMemberContext
388
- )
394
+ function submitDepositSweepProposal(DepositSweepProposal calldata proposal)
389
395
  public
390
- onlyProposalSubmitterOrWalletMember(
391
- proposal.walletPubKeyHash,
392
- walletMemberContext
393
- )
396
+ onlyCoordinator
394
397
  onlyAfterWalletLock(proposal.walletPubKeyHash)
395
398
  {
396
399
  walletLock[proposal.walletPubKeyHash] = WalletLock(
@@ -406,12 +409,11 @@ contract WalletCoordinator is OwnableUpgradeable, Reimbursable {
406
409
  /// caller's transaction cost.
407
410
  /// @dev See `submitDepositSweepProposal` function documentation.
408
411
  function submitDepositSweepProposalWithReimbursement(
409
- DepositSweepProposal calldata proposal,
410
- WalletMemberContext calldata walletMemberContext
412
+ DepositSweepProposal calldata proposal
411
413
  ) external {
412
414
  uint256 gasStart = gasleft();
413
415
 
414
- submitDepositSweepProposal(proposal, walletMemberContext);
416
+ submitDepositSweepProposal(proposal);
415
417
 
416
418
  reimbursementPool.refund(
417
419
  (gasStart - gasleft()) + depositSweepProposalSubmissionGasOffset,