@keep-network/tbtc-v2 0.1.1-dev.43 → 0.1.1-dev.46

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 (75) hide show
  1. package/artifacts/Bank.json +742 -0
  2. package/artifacts/Bridge.json +2961 -0
  3. package/artifacts/Deposit.json +117 -0
  4. package/artifacts/EcdsaDkgValidator.json +532 -0
  5. package/artifacts/EcdsaInactivity.json +156 -0
  6. package/artifacts/Fraud.json +153 -0
  7. package/artifacts/KeepRegistry.json +99 -0
  8. package/artifacts/KeepStake.json +286 -0
  9. package/artifacts/KeepToken.json +711 -0
  10. package/artifacts/KeepTokenStaking.json +483 -0
  11. package/artifacts/MovingFunds.json +137 -0
  12. package/artifacts/NuCypherStakingEscrow.json +256 -0
  13. package/artifacts/NuCypherToken.json +711 -0
  14. package/artifacts/RandomBeaconStub.json +141 -0
  15. package/artifacts/Redemption.json +161 -0
  16. package/artifacts/ReimbursementPool.json +509 -0
  17. package/artifacts/Relay.json +123 -0
  18. package/artifacts/SortitionPool.json +944 -0
  19. package/artifacts/Sweep.json +76 -0
  20. package/artifacts/T.json +1148 -0
  21. package/artifacts/TBTC.json +21 -21
  22. package/artifacts/TBTCToken.json +21 -21
  23. package/artifacts/TokenStaking.json +2288 -0
  24. package/artifacts/TokenholderGovernor.json +1795 -0
  25. package/artifacts/TokenholderTimelock.json +1058 -0
  26. package/artifacts/VendingMachine.json +24 -24
  27. package/artifacts/VendingMachineKeep.json +400 -0
  28. package/artifacts/VendingMachineNuCypher.json +400 -0
  29. package/artifacts/WalletRegistry.json +2709 -0
  30. package/artifacts/WalletRegistryGovernance.json +2364 -0
  31. package/artifacts/Wallets.json +186 -0
  32. package/artifacts/solcInputs/{f2c15d3cf1bd9566483f595c5ed30ccc.json → 75d54bcf8c4f0b65acb7ec6a1fb9af9d.json} +19 -19
  33. package/build/contracts/GovernanceUtils.sol/GovernanceUtils.dbg.json +1 -1
  34. package/build/contracts/bank/Bank.sol/Bank.dbg.json +1 -1
  35. package/build/contracts/bridge/BitcoinTx.sol/BitcoinTx.dbg.json +1 -1
  36. package/build/contracts/bridge/BitcoinTx.sol/BitcoinTx.json +2 -2
  37. package/build/contracts/bridge/Bridge.sol/Bridge.dbg.json +1 -1
  38. package/build/contracts/bridge/Bridge.sol/Bridge.json +438 -31
  39. package/build/contracts/bridge/BridgeState.sol/BridgeState.dbg.json +1 -1
  40. package/build/contracts/bridge/BridgeState.sol/BridgeState.json +120 -2
  41. package/build/contracts/bridge/Deposit.sol/Deposit.dbg.json +1 -1
  42. package/build/contracts/bridge/Deposit.sol/Deposit.json +2 -2
  43. package/build/contracts/bridge/EcdsaLib.sol/EcdsaLib.dbg.json +1 -1
  44. package/build/contracts/bridge/Fraud.sol/Fraud.dbg.json +1 -1
  45. package/build/contracts/bridge/Fraud.sol/Fraud.json +5 -5
  46. package/build/contracts/bridge/IRelay.sol/IRelay.dbg.json +1 -1
  47. package/build/contracts/bridge/MovingFunds.sol/MovingFunds.dbg.json +1 -1
  48. package/build/contracts/bridge/MovingFunds.sol/MovingFunds.json +40 -2
  49. package/build/contracts/bridge/Redemption.sol/OutboundTx.dbg.json +1 -1
  50. package/build/contracts/bridge/Redemption.sol/OutboundTx.json +2 -2
  51. package/build/contracts/bridge/Redemption.sol/Redemption.dbg.json +1 -1
  52. package/build/contracts/bridge/Redemption.sol/Redemption.json +2 -2
  53. package/build/contracts/bridge/Sweep.sol/Sweep.dbg.json +1 -1
  54. package/build/contracts/bridge/Sweep.sol/Sweep.json +2 -2
  55. package/build/contracts/bridge/VendingMachine.sol/VendingMachine.dbg.json +1 -1
  56. package/build/contracts/bridge/Wallets.sol/Wallets.dbg.json +1 -1
  57. package/build/contracts/bridge/Wallets.sol/Wallets.json +21 -2
  58. package/build/contracts/token/TBTC.sol/TBTC.dbg.json +1 -1
  59. package/build/contracts/vault/IVault.sol/IVault.dbg.json +1 -1
  60. package/build/contracts/vault/TBTCVault.sol/TBTCVault.dbg.json +1 -1
  61. package/contracts/bridge/Bridge.sol +313 -18
  62. package/contracts/bridge/BridgeState.sol +288 -5
  63. package/contracts/bridge/Deposit.sol +2 -2
  64. package/contracts/bridge/Fraud.sol +47 -17
  65. package/contracts/bridge/MovingFunds.sol +181 -1
  66. package/contracts/bridge/Redemption.sol +7 -12
  67. package/contracts/bridge/Sweep.sol +0 -3
  68. package/contracts/bridge/Wallets.sol +74 -33
  69. package/deploy/00_resolve_relay.ts +28 -0
  70. package/deploy/04_deploy_bank.ts +25 -0
  71. package/deploy/05_deploy_bridge.ts +60 -0
  72. package/deploy/06_bank_update_bridge.ts +19 -0
  73. package/deploy/07_transfer_ownership.ts +17 -0
  74. package/export.json +14827 -460
  75. package/package.json +2 -2
@@ -15,6 +15,8 @@
15
15
 
16
16
  pragma solidity ^0.8.9;
17
17
 
18
+ import {IWalletRegistry as EcdsaWalletRegistry} from "@keep-network/ecdsa/contracts/api/IWalletRegistry.sol";
19
+
18
20
  import "./IRelay.sol";
19
21
  import "./Deposit.sol";
20
22
  import "./Redemption.sol";
@@ -81,6 +83,11 @@ library BridgeState {
81
83
  // if per single redemption. `movingFundsTxMaxTotalFee` is a total
82
84
  // fee for the entire transaction.
83
85
  uint64 movingFundsTxMaxTotalFee;
86
+ // Time after which the moving funds process can be reported as
87
+ // timed out. It is counted from the moment when the wallet
88
+ // was requested to move their funds and switched to the MovingFunds
89
+ // state. Value in seconds.
90
+ uint32 movingFundsTimeout;
84
91
  // The minimal amount that can be requested for redemption.
85
92
  // Value of this parameter must take into account the value of
86
93
  // `redemptionTreasuryFeeDivisor` and `redemptionTxMaxFee`
@@ -174,40 +181,257 @@ library BridgeState {
174
181
  // active wallet. Can be unset to the zero value under certain
175
182
  // circumstances.
176
183
  bytes20 activeWalletPubKeyHash;
184
+ // The current number of wallets in the Live state.
185
+ uint32 liveWalletsCount;
186
+ // The maximum BTC amount in satoshi than can be transferred to a single
187
+ // target wallet during the moving funds process.
188
+ uint64 walletMaxBtcTransfer;
189
+ // Determines the length of the wallet closing period, i.e. the period
190
+ // when the wallet remains in the Closing state and can be subject
191
+ // of deposit fraud challenges. This value is in seconds and should be
192
+ // greater than the deposit refund time plus some time margin.
193
+ uint32 walletClosingPeriod;
177
194
  // Maps the 20-byte wallet public key hash (computed using Bitcoin
178
195
  // HASH160 over the compressed ECDSA public key) to the basic wallet
179
196
  // information like state and pending redemptions value.
180
197
  mapping(bytes20 => Wallets.Wallet) registeredWallets;
181
198
  }
182
199
 
200
+ event DepositParametersUpdated(
201
+ uint64 depositDustThreshold,
202
+ uint64 depositTreasuryFeeDivisor,
203
+ uint64 depositTxMaxFee
204
+ );
205
+
206
+ event RedemptionParametersUpdated(
207
+ uint64 redemptionDustThreshold,
208
+ uint64 redemptionTreasuryFeeDivisor,
209
+ uint64 redemptionTxMaxFee,
210
+ uint256 redemptionTimeout
211
+ );
212
+
213
+ event MovingFundsParametersUpdated(
214
+ uint64 movingFundsTxMaxTotalFee,
215
+ uint32 movingFundsTimeout
216
+ );
217
+
183
218
  event WalletParametersUpdated(
184
219
  uint32 walletCreationPeriod,
185
220
  uint64 walletMinBtcBalance,
186
221
  uint64 walletMaxBtcBalance,
187
- uint32 walletMaxAge
222
+ uint32 walletMaxAge,
223
+ uint64 walletMaxBtcTransfer,
224
+ uint32 walletClosingPeriod
188
225
  );
189
226
 
227
+ event FraudParametersUpdated(
228
+ uint256 fraudSlashingAmount,
229
+ uint256 fraudNotifierRewardMultiplier,
230
+ uint256 fraudChallengeDefeatTimeout,
231
+ uint256 fraudChallengeDepositAmount
232
+ );
233
+
234
+ /// @notice Updates parameters of deposits.
235
+ /// @param _depositDustThreshold New value of the deposit dust threshold in
236
+ /// satoshis. It is the minimal amount that can be requested to
237
+ //// deposit. Value of this parameter must take into account the value
238
+ /// of `depositTreasuryFeeDivisor` and `depositTxMaxFee` parameters
239
+ /// in order to make requests that can incur the treasury and
240
+ /// transaction fee and still satisfy the depositor
241
+ /// @param _depositTreasuryFeeDivisor New value of the treasury fee divisor.
242
+ /// It is the divisor used to compute the treasury fee taken from
243
+ /// each deposit and transferred to the treasury upon sweep proof
244
+ /// submission. That fee is computed as follows:
245
+ /// `treasuryFee = depositedAmount / depositTreasuryFeeDivisor`
246
+ /// For example, if the treasury fee needs to be 2% of each deposit,
247
+ /// the `depositTreasuryFeeDivisor` should be set to `50`
248
+ /// because `1/50 = 0.02 = 2%`
249
+ /// @param _depositTxMaxFee New value of the deposit tx max fee in satoshis.
250
+ /// It is the maximum amount of BTC transaction fee that can
251
+ /// be incurred by each swept deposit being part of the given sweep
252
+ /// transaction. If the maximum BTC transaction fee is exceeded,
253
+ /// such transaction is considered a fraud
254
+ /// @dev Requirements:
255
+ /// - Deposit dust threshold must be greater than zero
256
+ /// - Deposit treasury fee divisor must be greater than zero
257
+ /// - Deposit transaction max fee must be greater than zero
258
+ function updateDepositParameters(
259
+ Storage storage self,
260
+ uint64 _depositDustThreshold,
261
+ uint64 _depositTreasuryFeeDivisor,
262
+ uint64 _depositTxMaxFee
263
+ ) internal {
264
+ require(
265
+ _depositDustThreshold > 0,
266
+ "Deposit dust threshold must be greater than zero"
267
+ );
268
+
269
+ require(
270
+ _depositTreasuryFeeDivisor > 0,
271
+ "Deposit treasury fee divisor must be greater than zero"
272
+ );
273
+
274
+ require(
275
+ _depositTxMaxFee > 0,
276
+ "Deposit transaction max fee must be greater than zero"
277
+ );
278
+
279
+ self.depositDustThreshold = _depositDustThreshold;
280
+ self.depositTreasuryFeeDivisor = _depositTreasuryFeeDivisor;
281
+ self.depositTxMaxFee = _depositTxMaxFee;
282
+
283
+ emit DepositParametersUpdated(
284
+ _depositDustThreshold,
285
+ _depositTreasuryFeeDivisor,
286
+ _depositTxMaxFee
287
+ );
288
+ }
289
+
290
+ /// @notice Updates parameters of redemptions.
291
+ /// @param _redemptionDustThreshold New value of the redemption dust
292
+ /// threshold in satoshis. It is the minimal amount that can be
293
+ /// requested for redemption. Value of this parameter must take into
294
+ /// account the value of `redemptionTreasuryFeeDivisor` and
295
+ /// `redemptionTxMaxFee` parameters in order to make requests that
296
+ /// can incur the treasury and transaction fee and still satisfy the
297
+ /// redeemer.
298
+ /// @param _redemptionTreasuryFeeDivisor New value of the redemption
299
+ /// treasury fee divisor. It is the divisor used to compute the
300
+ /// treasury fee taken from each redemption request and transferred
301
+ /// to the treasury upon successful request finalization. That fee is
302
+ /// computed as follows:
303
+ /// `treasuryFee = requestedAmount / redemptionTreasuryFeeDivisor`
304
+ /// For example, if the treasury fee needs to be 2% of each
305
+ /// redemption request, the `redemptionTreasuryFeeDivisor` should
306
+ /// be set to `50` because `1/50 = 0.02 = 2%`.
307
+ /// @param _redemptionTxMaxFee New value of the redemption transaction max
308
+ /// fee in satoshis. It is the maximum amount of BTC transaction fee
309
+ /// that can be incurred by each redemption request being part of the
310
+ /// given redemption transaction. If the maximum BTC transaction fee
311
+ /// is exceeded, such transaction is considered a fraud.
312
+ /// This is a per-redemption output max fee for the redemption
313
+ /// transaction.
314
+ /// @param _redemptionTimeout New value of the redemption timeout in seconds.
315
+ /// It is the time after which the redemption request can be reported
316
+ /// as timed out. It is counted from the moment when the redemption
317
+ /// request was created via `requestRedemption` call. Reported timed
318
+ /// out requests are cancelled and locked TBTC is returned to the
319
+ /// redeemer in full amount.
320
+ /// @dev Requirements:
321
+ /// - Redemption dust threshold must be greater than zero
322
+ /// - Redemption treasury fee divisor must be greater than zero
323
+ /// - Redemption transaction max fee must be greater than zero
324
+ /// - Redemption timeout must be greater than zero
325
+ function updateRedemptionParameters(
326
+ Storage storage self,
327
+ uint64 _redemptionDustThreshold,
328
+ uint64 _redemptionTreasuryFeeDivisor,
329
+ uint64 _redemptionTxMaxFee,
330
+ uint256 _redemptionTimeout
331
+ ) internal {
332
+ require(
333
+ _redemptionDustThreshold > 0,
334
+ "Redemption dust threshold must be greater than zero"
335
+ );
336
+
337
+ require(
338
+ _redemptionTreasuryFeeDivisor > 0,
339
+ "Redemption treasury fee divisor must be greater than zero"
340
+ );
341
+
342
+ require(
343
+ _redemptionTxMaxFee > 0,
344
+ "Redemption transaction max fee must be greater than zero"
345
+ );
346
+
347
+ require(
348
+ _redemptionTimeout > 0,
349
+ "Redemption timeout must be greater than zero"
350
+ );
351
+
352
+ self.redemptionDustThreshold = _redemptionDustThreshold;
353
+ self.redemptionTreasuryFeeDivisor = _redemptionTreasuryFeeDivisor;
354
+ self.redemptionTxMaxFee = _redemptionTxMaxFee;
355
+ self.redemptionTimeout = _redemptionTimeout;
356
+
357
+ emit RedemptionParametersUpdated(
358
+ _redemptionDustThreshold,
359
+ _redemptionTreasuryFeeDivisor,
360
+ _redemptionTxMaxFee,
361
+ _redemptionTimeout
362
+ );
363
+ }
364
+
365
+ /// @notice Updates parameters of moving funds.
366
+ /// @param _movingFundsTxMaxTotalFee New value of the moving funds transaction
367
+ /// max total fee in satoshis. It is the maximum amount of the total
368
+ /// BTC transaction fee that is acceptable in a single moving funds
369
+ /// transaction. This is a _total_ max fee for the entire moving
370
+ /// funds transaction.
371
+ /// @param _movingFundsTimeout New value of the moving funds timeout in
372
+ /// seconds. It is the time after which the moving funds process can
373
+ /// be reported as timed out. It is counted from the moment when the
374
+ /// wallet was requested to move their funds and switched to the
375
+ /// MovingFunds state.
376
+ /// @dev Requirements:
377
+ /// - Moving funds transaction max total fee must be greater than zero
378
+ /// - Moving funds timeout must be greater than zero
379
+ function updateMovingFundsParameters(
380
+ Storage storage self,
381
+ uint64 _movingFundsTxMaxTotalFee,
382
+ uint32 _movingFundsTimeout
383
+ ) internal {
384
+ require(
385
+ _movingFundsTxMaxTotalFee > 0,
386
+ "Moving funds transaction max total fee must be greater than zero"
387
+ );
388
+
389
+ require(
390
+ _movingFundsTimeout > 0,
391
+ "Moving funds timeout must be greater than zero"
392
+ );
393
+
394
+ self.movingFundsTxMaxTotalFee = _movingFundsTxMaxTotalFee;
395
+ self.movingFundsTimeout = _movingFundsTimeout;
396
+
397
+ emit MovingFundsParametersUpdated(
398
+ _movingFundsTxMaxTotalFee,
399
+ _movingFundsTimeout
400
+ );
401
+ }
402
+
190
403
  /// @notice Updates parameters of wallets.
191
404
  /// @param _walletCreationPeriod New value of the wallet creation period in
192
405
  /// seconds, determines how frequently a new wallet creation can be
193
406
  /// requested
194
407
  /// @param _walletMinBtcBalance New value of the wallet minimum BTC balance
195
- /// in satoshis, used to decide about wallet creation or closing
408
+ /// in satoshi, used to decide about wallet creation or closing
196
409
  /// @param _walletMaxBtcBalance New value of the wallet maximum BTC balance
197
- /// in satoshis, used to decide about wallet creation
410
+ /// in satoshi, used to decide about wallet creation
198
411
  /// @param _walletMaxAge New value of the wallet maximum age in seconds,
199
412
  /// indicates the maximum age of a wallet in seconds, after which
200
413
  /// the wallet moving funds process can be requested
414
+ /// @param _walletMaxBtcTransfer New value of the wallet maximum BTC transfer
415
+ /// in satoshi, determines the maximum amount that can be transferred
416
+ /// to a single target wallet during the moving funds process
417
+ /// @param _walletClosingPeriod New value of the wallet closing period in
418
+ /// seconds, determines the length of the wallet closing period,
419
+ // i.e. the period when the wallet remains in the Closing state
420
+ // and can be subject of deposit fraud challenges
201
421
  /// @dev Requirements:
202
422
  /// - Wallet minimum BTC balance must be greater than zero
203
423
  /// - Wallet maximum BTC balance must be greater than the wallet
204
424
  /// minimum BTC balance
425
+ /// - Wallet maximum BTC transfer must be greater than zero
426
+ /// - Wallet closing period must be greater than zero
205
427
  function updateWalletParameters(
206
428
  Storage storage self,
207
429
  uint32 _walletCreationPeriod,
208
430
  uint64 _walletMinBtcBalance,
209
431
  uint64 _walletMaxBtcBalance,
210
- uint32 _walletMaxAge
432
+ uint32 _walletMaxAge,
433
+ uint64 _walletMaxBtcTransfer,
434
+ uint32 _walletClosingPeriod
211
435
  ) internal {
212
436
  require(
213
437
  _walletMinBtcBalance > 0,
@@ -217,17 +441,76 @@ library BridgeState {
217
441
  _walletMaxBtcBalance > _walletMinBtcBalance,
218
442
  "Wallet maximum BTC balance must be greater than the minimum"
219
443
  );
444
+ require(
445
+ _walletMaxBtcTransfer > 0,
446
+ "Wallet maximum BTC transfer must be greater than zero"
447
+ );
448
+ require(
449
+ _walletClosingPeriod > 0,
450
+ "Wallet closing period must be greater than zero"
451
+ );
220
452
 
221
453
  self.walletCreationPeriod = _walletCreationPeriod;
222
454
  self.walletMinBtcBalance = _walletMinBtcBalance;
223
455
  self.walletMaxBtcBalance = _walletMaxBtcBalance;
224
456
  self.walletMaxAge = _walletMaxAge;
457
+ self.walletMaxBtcTransfer = _walletMaxBtcTransfer;
458
+ self.walletClosingPeriod = _walletClosingPeriod;
225
459
 
226
460
  emit WalletParametersUpdated(
227
461
  _walletCreationPeriod,
228
462
  _walletMinBtcBalance,
229
463
  _walletMaxBtcBalance,
230
- _walletMaxAge
464
+ _walletMaxAge,
465
+ _walletMaxBtcTransfer,
466
+ _walletClosingPeriod
467
+ );
468
+ }
469
+
470
+ /// @notice Updates parameters related to frauds.
471
+ /// @param _fraudSlashingAmount New value of the fraud slashing amount in T,
472
+ /// it is the amount slashed from each wallet member for committing
473
+ /// a fraud
474
+ /// @param _fraudNotifierRewardMultiplier New value of the fraud notifier
475
+ /// reward multiplier as percentage, it determines the percentage of
476
+ /// the notifier reward from the staking contact the notifier of
477
+ /// a fraud receives. The value must be in the range [0, 100]
478
+ /// @param _fraudChallengeDefeatTimeout New value of the challenge defeat
479
+ /// timeout in seconds, it is the amount of time the wallet has to
480
+ /// defeat a fraud challenge. The value must be greater than zero
481
+ /// @param _fraudChallengeDepositAmount New value of the fraud challenge
482
+ /// deposit amount in wei, it is the amount of ETH the party
483
+ /// challenging the wallet for fraud needs to deposit
484
+ /// @dev Requirements:
485
+ /// - Fraud notifier reward multiplier must be in the range [0, 100]
486
+ /// - Fraud challenge defeat timeout must be greater than 0
487
+ function updateFraudParameters(
488
+ Storage storage self,
489
+ uint256 _fraudSlashingAmount,
490
+ uint256 _fraudNotifierRewardMultiplier,
491
+ uint256 _fraudChallengeDefeatTimeout,
492
+ uint256 _fraudChallengeDepositAmount
493
+ ) internal {
494
+ require(
495
+ _fraudNotifierRewardMultiplier <= 100,
496
+ "Fraud notifier reward multiplier must be in the range [0, 100]"
497
+ );
498
+
499
+ require(
500
+ _fraudChallengeDefeatTimeout > 0,
501
+ "Fraud challenge defeat timeout must be greater than zero"
502
+ );
503
+
504
+ self.fraudSlashingAmount = _fraudSlashingAmount;
505
+ self.fraudNotifierRewardMultiplier = _fraudNotifierRewardMultiplier;
506
+ self.fraudChallengeDefeatTimeout = _fraudChallengeDefeatTimeout;
507
+ self.fraudChallengeDepositAmount = _fraudChallengeDepositAmount;
508
+
509
+ emit FraudParametersUpdated(
510
+ _fraudSlashingAmount,
511
+ _fraudNotifierRewardMultiplier,
512
+ _fraudChallengeDefeatTimeout,
513
+ _fraudChallengeDepositAmount
231
514
  );
232
515
  }
233
516
  }
@@ -149,7 +149,7 @@ library Deposit {
149
149
  require(
150
150
  self.registeredWallets[reveal.walletPubKeyHash].state ==
151
151
  Wallets.WalletState.Live,
152
- "Wallet is not in Live state"
152
+ "Wallet must be in Live state"
153
153
  );
154
154
 
155
155
  require(
@@ -250,7 +250,7 @@ library Deposit {
250
250
  deposit.treasuryFee = self.depositTreasuryFeeDivisor > 0
251
251
  ? fundingOutputAmount / self.depositTreasuryFeeDivisor
252
252
  : 0;
253
-
253
+ // slither-disable-next-line reentrancy-events
254
254
  emit DepositRevealed(
255
255
  fundingTxHash,
256
256
  reveal.fundingOutputIndex,
@@ -42,6 +42,8 @@ import "./Wallets.sol";
42
42
  /// Therefore the transaction spending the UTXO must be proven in the
43
43
  /// Bridge before a challenge defeat is called.
44
44
  library Fraud {
45
+ using Wallets for BridgeState.Storage;
46
+
45
47
  using BytesLib for bytes;
46
48
  using BTCUtils for bytes;
47
49
  using BTCUtils for uint32;
@@ -59,17 +61,17 @@ library Fraud {
59
61
  }
60
62
 
61
63
  event FraudChallengeSubmitted(
62
- bytes20 walletPublicKeyHash,
64
+ bytes20 walletPubKeyHash,
63
65
  bytes32 sighash,
64
66
  uint8 v,
65
67
  bytes32 r,
66
68
  bytes32 s
67
69
  );
68
70
 
69
- event FraudChallengeDefeated(bytes20 walletPublicKeyHash, bytes32 sighash);
71
+ event FraudChallengeDefeated(bytes20 walletPubKeyHash, bytes32 sighash);
70
72
 
71
73
  event FraudChallengeDefeatTimedOut(
72
- bytes20 walletPublicKeyHash,
74
+ bytes20 walletPubKeyHash,
73
75
  bytes32 sighash
74
76
  );
75
77
 
@@ -98,8 +100,8 @@ library Fraud {
98
100
  /// for reference
99
101
  /// @param signature Bitcoin signature in the R/S/V format
100
102
  /// @dev Requirements:
101
- /// - Wallet behind `walletPublicKey` must be in `Live` or `MovingFunds`
102
- /// state
103
+ /// - Wallet behind `walletPublicKey` must be in Live or MovingFunds
104
+ /// or Closing state
103
105
  /// - The challenger must send appropriate amount of ETH used as
104
106
  /// fraud challenge deposit
105
107
  /// - The signature (represented by r, s and v) must be generated by
@@ -139,8 +141,9 @@ library Fraud {
139
141
 
140
142
  require(
141
143
  wallet.state == Wallets.WalletState.Live ||
142
- wallet.state == Wallets.WalletState.MovingFunds,
143
- "Wallet is neither in Live nor MovingFunds state"
144
+ wallet.state == Wallets.WalletState.MovingFunds ||
145
+ wallet.state == Wallets.WalletState.Closing,
146
+ "Wallet must be in Live or MovingFunds or Closing state"
144
147
  );
145
148
 
146
149
  uint256 challengeKey = uint256(
@@ -155,7 +158,7 @@ library Fraud {
155
158
  /* solhint-disable-next-line not-rely-on-time */
156
159
  challenge.reportedAt = uint32(block.timestamp);
157
160
  challenge.resolved = false;
158
-
161
+ // slither-disable-next-line reentrancy-events
159
162
  emit FraudChallengeSubmitted(
160
163
  walletPubKeyHash,
161
164
  sighash,
@@ -232,7 +235,7 @@ library Fraud {
232
235
 
233
236
  // Send the ether deposited by the challenger to the treasury
234
237
  /* solhint-disable avoid-low-level-calls */
235
- // slither-disable-next-line low-level-calls
238
+ // slither-disable-next-line low-level-calls,unchecked-lowlevel,arbitrary-send
236
239
  self.treasury.call{gas: 100000, value: challenge.depositAmount}("");
237
240
  /* solhint-enable avoid-low-level-calls */
238
241
 
@@ -241,7 +244,7 @@ library Fraud {
241
244
  walletPublicKey.slice32(32)
242
245
  );
243
246
  bytes20 walletPubKeyHash = compressedWalletPublicKey.hash160View();
244
-
247
+ // slither-disable-next-line reentrancy-events
245
248
  emit FraudChallengeDefeated(walletPubKeyHash, sighash);
246
249
  }
247
250
 
@@ -264,9 +267,11 @@ library Fraud {
264
267
  /// the transaction input the signature is produced for. See BIP-143
265
268
  /// for reference
266
269
  /// @dev Requirements:
267
- /// - `walletPublicKey` and `sighash` must identify an open fraud
270
+ /// - The wallet must be in the Live or MovingFunds or Closing or
271
+ /// Terminated state
272
+ /// - The `walletPublicKey` and `sighash` must identify an open fraud
268
273
  /// challenge
269
- /// - the amount of time indicated by `challengeDefeatTimeout` must pass
274
+ /// - The amount of time indicated by `challengeDefeatTimeout` must pass
270
275
  /// after the challenge was reported
271
276
  function notifyFraudChallengeDefeatTimeout(
272
277
  BridgeState.Storage storage self,
@@ -278,11 +283,14 @@ library Fraud {
278
283
  );
279
284
 
280
285
  FraudChallenge storage challenge = self.fraudChallenges[challengeKey];
286
+
281
287
  require(challenge.reportedAt > 0, "Fraud challenge does not exist");
288
+
282
289
  require(
283
290
  !challenge.resolved,
284
291
  "Fraud challenge has already been resolved"
285
292
  );
293
+
286
294
  require(
287
295
  /* solhint-disable-next-line not-rely-on-time */
288
296
  block.timestamp >=
@@ -290,14 +298,10 @@ library Fraud {
290
298
  "Fraud challenge defeat period did not time out yet"
291
299
  );
292
300
 
293
- // TODO: Call notifyFraud from Wallets library
294
- // TODO: Reward the challenger
295
-
296
301
  challenge.resolved = true;
297
-
298
302
  // Return the ether deposited by the challenger
299
303
  /* solhint-disable avoid-low-level-calls */
300
- // slither-disable-next-line low-level-calls
304
+ // slither-disable-next-line low-level-calls,unchecked-lowlevel
301
305
  challenge.challenger.call{gas: 100000, value: challenge.depositAmount}(
302
306
  ""
303
307
  );
@@ -308,7 +312,33 @@ library Fraud {
308
312
  walletPublicKey.slice32(32)
309
313
  );
310
314
  bytes20 walletPubKeyHash = compressedWalletPublicKey.hash160View();
315
+ Wallets.WalletState walletState = self
316
+ .registeredWallets[walletPubKeyHash]
317
+ .state;
318
+
319
+ if (
320
+ walletState == Wallets.WalletState.Live ||
321
+ walletState == Wallets.WalletState.MovingFunds ||
322
+ walletState == Wallets.WalletState.Closing
323
+ ) {
324
+ self.terminateWallet(walletPubKeyHash);
325
+
326
+ // TODO: Perform slashing of the wallet operators, reward the
327
+ // challenger, and add unit tests for that.
328
+ } else if (walletState == Wallets.WalletState.Terminated) {
329
+ // This is a special case when the wallet was already terminated
330
+ // due to a previous deliberate protocol violation. In that
331
+ // case, this function should be still callable for other fraud
332
+ // challenges timeouts in order to let the challenger unlock its
333
+ // ETH deposit back. However, the wallet termination logic is
334
+ // not called and the challenger is not rewarded.
335
+ } else {
336
+ revert(
337
+ "Wallet must be in Live or MovingFunds or Closing or Terminated state"
338
+ );
339
+ }
311
340
 
341
+ // slither-disable-next-line reentrancy-events
312
342
  emit FraudChallengeDefeatTimedOut(walletPubKeyHash, sighash);
313
343
  }
314
344