@keep-network/tbtc-v2 0.1.1-dev.24 → 0.1.1-dev.27

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 (25) hide show
  1. package/artifacts/TBTC.json +10 -10
  2. package/artifacts/TBTCToken.json +10 -10
  3. package/artifacts/VendingMachine.json +11 -11
  4. package/artifacts/solcInputs/{2676c70e1dffa939dbf0519ef3304b34.json → e103ea0f293e8ca60f7bd00f669fc831.json} +10 -4
  5. package/build/contracts/GovernanceUtils.sol/GovernanceUtils.dbg.json +1 -1
  6. package/build/contracts/bank/Bank.sol/Bank.dbg.json +1 -1
  7. package/build/contracts/bridge/BitcoinTx.sol/BitcoinTx.dbg.json +1 -1
  8. package/build/contracts/bridge/BitcoinTx.sol/BitcoinTx.json +2 -2
  9. package/build/contracts/bridge/Bridge.sol/Bridge.dbg.json +1 -1
  10. package/build/contracts/bridge/Bridge.sol/Bridge.json +499 -18
  11. package/build/contracts/bridge/Bridge.sol/IRelay.dbg.json +1 -1
  12. package/build/contracts/bridge/EcdsaLib.sol/EcdsaLib.dbg.json +1 -1
  13. package/build/contracts/bridge/Frauds.sol/Frauds.dbg.json +4 -0
  14. package/build/contracts/bridge/Frauds.sol/Frauds.json +138 -0
  15. package/build/contracts/bridge/VendingMachine.sol/VendingMachine.dbg.json +1 -1
  16. package/build/contracts/bridge/Wallets.sol/Wallets.dbg.json +1 -1
  17. package/build/contracts/bridge/Wallets.sol/Wallets.json +53 -2
  18. package/build/contracts/token/TBTC.sol/TBTC.dbg.json +1 -1
  19. package/build/contracts/vault/IVault.sol/IVault.dbg.json +1 -1
  20. package/build/contracts/vault/TBTCVault.sol/TBTCVault.dbg.json +1 -1
  21. package/contracts/bridge/BitcoinTx.sol +10 -0
  22. package/contracts/bridge/Bridge.sol +304 -88
  23. package/contracts/bridge/Frauds.sol +531 -0
  24. package/contracts/bridge/Wallets.sol +173 -5
  25. package/package.json +1 -1
@@ -41,10 +41,9 @@ library Wallets {
41
41
  // The maximum BTC threshold in satoshi that is used to decide about
42
42
  // wallet creation.
43
43
  uint64 maxBtcBalance;
44
- // TODO: Make sure the `activeWalletPubKeyHash` is zeroed in case
45
- // the active wallet becomes non-Live. This will be implemented
46
- // soon, along with the code for closing wallets.
47
- //
44
+ // The maximum age of a wallet in seconds, after which the wallet
45
+ // moving funds process can be requested.
46
+ uint32 maxAge;
48
47
  // 20-byte wallet public key hash being reference to the currently
49
48
  // active wallet. Can be unset to the zero value under certain
50
49
  // circumstances.
@@ -91,6 +90,9 @@ library Wallets {
91
90
  uint64 pendingRedemptionsValue;
92
91
  // UNIX timestamp the wallet was created at.
93
92
  uint32 createdAt;
93
+ // UNIX timestamp indicating the moment the wallet was requested to
94
+ // move their funds.
95
+ uint32 moveFundsRequestedAt;
94
96
  // Current state of the wallet.
95
97
  WalletState state;
96
98
  }
@@ -102,6 +104,8 @@ library Wallets {
102
104
  uint64 newMaxBtcBalance
103
105
  );
104
106
 
107
+ event WalletMaxAgeUpdated(uint32 newMaxAge);
108
+
105
109
  event NewWalletRequested();
106
110
 
107
111
  event NewWalletRegistered(
@@ -109,6 +113,16 @@ library Wallets {
109
113
  bytes20 indexed walletPubKeyHash
110
114
  );
111
115
 
116
+ event WalletMovingFunds(
117
+ bytes32 indexed ecdsaWalletID,
118
+ bytes20 indexed walletPubKeyHash
119
+ );
120
+
121
+ event WalletClosed(
122
+ bytes32 indexed ecdsaWalletID,
123
+ bytes20 indexed walletPubKeyHash
124
+ );
125
+
112
126
  event WalletTerminated(
113
127
  bytes32 indexed ecdsaWalletID,
114
128
  bytes20 indexed walletPubKeyHash
@@ -164,6 +178,14 @@ library Wallets {
164
178
  emit WalletBtcBalanceRangeUpdated(minBtcBalance, maxBtcBalance);
165
179
  }
166
180
 
181
+ /// @notice Sets the wallet maximum age.
182
+ /// @param maxAge New value of the wallet maximum age
183
+ function setMaxAge(Data storage self, uint32 maxAge) external {
184
+ self.maxAge = maxAge;
185
+
186
+ emit WalletMaxAgeUpdated(maxAge);
187
+ }
188
+
167
189
  /// @notice Requests creation of a new wallet. This function just
168
190
  /// forms a request and the creation process is performed
169
191
  /// asynchronously. Outcome of that process should be delivered
@@ -305,6 +327,152 @@ library Wallets {
305
327
  emit NewWalletRegistered(ecdsaWalletID, walletPubKeyHash);
306
328
  }
307
329
 
330
+ /// @notice Handles a notification about a wallet heartbeat failure and
331
+ /// triggers the wallet moving funds process.
332
+ /// @param publicKeyX Wallet's public key's X coordinate.
333
+ /// @param publicKeyY Wallet's public key's Y coordinate.
334
+ /// @dev Requirements:
335
+ /// - The only caller authorized to call this function is `registry`
336
+ /// - Wallet must be in Live state
337
+ function notifyWalletHeartbeatFailed(
338
+ Data storage self,
339
+ bytes32 publicKeyX,
340
+ bytes32 publicKeyY
341
+ ) external {
342
+ require(
343
+ msg.sender == address(self.registry),
344
+ "Caller is not the ECDSA Wallet Registry"
345
+ );
346
+
347
+ // Compress wallet's public key and calculate Bitcoin's hash160 of it.
348
+ bytes20 walletPubKeyHash = bytes20(
349
+ EcdsaLib.compressPublicKey(publicKeyX, publicKeyY).hash160()
350
+ );
351
+
352
+ require(
353
+ self.registeredWallets[walletPubKeyHash].state == WalletState.Live,
354
+ "ECDSA wallet must be in Live state"
355
+ );
356
+
357
+ moveFunds(self, walletPubKeyHash);
358
+ }
359
+
360
+ /// @notice Handles a notification about a wallet redemption timeout
361
+ /// and requests slashing of the wallet operators. Triggers the
362
+ /// wallet moving funds process only if the wallet is still in the
363
+ /// Live state. That means multiple action timeouts can be reported
364
+ /// for the same wallet but only the first report requests the
365
+ /// wallet to move their funds.
366
+ /// @param walletPubKeyHash 20-byte public key hash of the wallet
367
+ /// @dev Requirements:
368
+ /// - Wallet must be in Live or MovingFunds state
369
+ function notifyRedemptionTimedOut(
370
+ Data storage self,
371
+ bytes20 walletPubKeyHash
372
+ ) external {
373
+ WalletState walletState = self
374
+ .registeredWallets[walletPubKeyHash]
375
+ .state;
376
+
377
+ require(
378
+ walletState == WalletState.Live ||
379
+ walletState == WalletState.MovingFunds,
380
+ "ECDSA wallet must be in Live or MovingFunds state"
381
+ );
382
+
383
+ if (walletState == WalletState.Live) {
384
+ moveFunds(self, walletPubKeyHash);
385
+ }
386
+
387
+ // TODO: Perform slashing of wallet operators.
388
+ }
389
+
390
+ /// @notice Notifies that the wallet is either old enough or has too few
391
+ /// satoshis left and qualifies to be closed.
392
+ /// @param walletPubKeyHash 20-byte public key hash of the wallet
393
+ /// @param walletMainUtxo Data of the wallet's main UTXO, as currently
394
+ /// known on the Ethereum chain.
395
+ /// @dev Requirements:
396
+ /// - Wallet must not be set as the current active wallet
397
+ /// - Wallet must exceed the wallet maximum age OR the wallet BTC
398
+ /// balance must be lesser than the minimum threshold. If the latter
399
+ /// case is true, the `walletMainUtxo` components must point to the
400
+ /// recent main UTXO of the given wallet, as currently known on the
401
+ /// Ethereum chain. If the wallet has no main UTXO, this parameter
402
+ /// can be empty as it is ignored since the wallet balance is
403
+ /// assumed to be zero.
404
+ /// - Wallet must be in Live state
405
+ function notifyCloseableWallet(
406
+ Data storage self,
407
+ bytes20 walletPubKeyHash,
408
+ BitcoinTx.UTXO calldata walletMainUtxo
409
+ ) external {
410
+ require(
411
+ self.activeWalletPubKeyHash != walletPubKeyHash,
412
+ "Active wallet cannot be considered closeable"
413
+ );
414
+
415
+ Wallet storage wallet = self.registeredWallets[walletPubKeyHash];
416
+ require(
417
+ wallet.state == WalletState.Live,
418
+ "ECDSA wallet must be in Live state"
419
+ );
420
+
421
+ /* solhint-disable-next-line not-rely-on-time */
422
+ bool walletOldEnough = block.timestamp >=
423
+ wallet.createdAt + self.maxAge;
424
+
425
+ require(
426
+ walletOldEnough ||
427
+ getWalletBtcBalance(self, walletPubKeyHash, walletMainUtxo) <
428
+ self.minBtcBalance,
429
+ "Wallet needs to be old enough or have too few satoshis"
430
+ );
431
+
432
+ moveFunds(self, walletPubKeyHash);
433
+ }
434
+
435
+ /// @notice Requests a wallet to move their funds. If the wallet balance
436
+ /// is zero, the wallet is closed immediately and the ECDSA
437
+ /// registry is notified about this fact. If the move funds
438
+ /// request refers to the current active wallet, such a wallet
439
+ /// is no longer considered active and the active wallet slot
440
+ /// is unset allowing to trigger a new wallet creation immediately.
441
+ /// @param walletPubKeyHash 20-byte public key hash of the wallet
442
+ /// @dev Requirements:
443
+ /// - The caller must make sure that the wallet is in the Live state
444
+ function moveFunds(Data storage self, bytes20 walletPubKeyHash) internal {
445
+ Wallet storage wallet = self.registeredWallets[walletPubKeyHash];
446
+
447
+ if (wallet.mainUtxoHash == bytes32(0)) {
448
+ // If the wallet has no main UTXO, that means its BTC balance
449
+ // is zero and it should be closed immediately.
450
+ wallet.state = WalletState.Closed;
451
+
452
+ emit WalletClosed(wallet.ecdsaWalletID, walletPubKeyHash);
453
+
454
+ self.registry.closeWallet(wallet.ecdsaWalletID);
455
+ } else {
456
+ // Otherwise, initialize the moving funds process.
457
+ wallet.state = WalletState.MovingFunds;
458
+ /* solhint-disable-next-line not-rely-on-time */
459
+ wallet.moveFundsRequestedAt = uint32(block.timestamp);
460
+
461
+ emit WalletMovingFunds(wallet.ecdsaWalletID, walletPubKeyHash);
462
+ }
463
+
464
+ if (self.activeWalletPubKeyHash == walletPubKeyHash) {
465
+ // If the move funds request refers to the current active wallet,
466
+ // unset the active wallet and make the wallet creation process
467
+ // possible in order to get a new healthy active wallet.
468
+ delete self.activeWalletPubKeyHash;
469
+ }
470
+ }
471
+
472
+ // TODO: Implement functions that will be called upon moving funds process
473
+ // end. Remember the moving funds process ends up with a successful
474
+ // proof or a timeout.
475
+
308
476
  /// @notice Reports about a fraud committed by the given wallet. This
309
477
  /// function performs slashing and wallet termination in reaction
310
478
  /// to a proven fraud and it should only be called when the fraud
@@ -347,6 +515,6 @@ library Wallets {
347
515
  delete self.activeWalletPubKeyHash;
348
516
  }
349
517
 
350
- self.registry.closeWallet(walletPubKeyHash);
518
+ self.registry.closeWallet(wallet.ecdsaWalletID);
351
519
  }
352
520
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@keep-network/tbtc-v2",
3
- "version": "0.1.1-dev.24+main.50617ecfbbb2c15796c627b2acc6daabc61da166",
3
+ "version": "0.1.1-dev.27+main.2406ba079afc1f3e0e5a6cb0add2bfd7914b7650",
4
4
  "license": "MIT",
5
5
  "files": [
6
6
  "artifacts/",