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

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 (49) hide show
  1. package/artifacts/TBTC.json +3 -3
  2. package/artifacts/TBTCToken.json +3 -3
  3. package/artifacts/VendingMachine.json +10 -10
  4. package/artifacts/solcInputs/{f1a50b67569d88ee54efa3e22c6b484e.json → f2c15d3cf1bd9566483f595c5ed30ccc.json} +25 -25
  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 +191 -331
  11. package/build/contracts/bridge/BridgeState.sol/BridgeState.dbg.json +1 -1
  12. package/build/contracts/bridge/BridgeState.sol/BridgeState.json +35 -3
  13. package/build/contracts/bridge/Deposit.sol/Deposit.dbg.json +1 -1
  14. package/build/contracts/bridge/Deposit.sol/Deposit.json +2 -2
  15. package/build/contracts/bridge/EcdsaLib.sol/EcdsaLib.dbg.json +1 -1
  16. package/build/contracts/bridge/EcdsaLib.sol/EcdsaLib.json +2 -2
  17. package/build/contracts/bridge/Fraud.sol/Fraud.dbg.json +4 -0
  18. package/build/contracts/bridge/Fraud.sol/Fraud.json +86 -0
  19. package/build/contracts/bridge/IRelay.sol/IRelay.dbg.json +1 -1
  20. package/build/contracts/bridge/MovingFunds.sol/MovingFunds.dbg.json +1 -1
  21. package/build/contracts/bridge/MovingFunds.sol/MovingFunds.json +4 -22
  22. package/build/contracts/bridge/Redemption.sol/OutboundTx.dbg.json +4 -0
  23. package/build/contracts/bridge/{Redeem.sol → Redemption.sol}/OutboundTx.json +3 -3
  24. package/build/contracts/bridge/Redemption.sol/Redemption.dbg.json +4 -0
  25. package/build/contracts/bridge/Redemption.sol/Redemption.json +92 -0
  26. package/build/contracts/bridge/Sweep.sol/Sweep.dbg.json +1 -1
  27. package/build/contracts/bridge/Sweep.sol/Sweep.json +2 -2
  28. package/build/contracts/bridge/VendingMachine.sol/VendingMachine.dbg.json +1 -1
  29. package/build/contracts/bridge/Wallets.sol/Wallets.dbg.json +1 -1
  30. package/build/contracts/bridge/Wallets.sol/Wallets.json +2 -47
  31. package/build/contracts/token/TBTC.sol/TBTC.dbg.json +1 -1
  32. package/build/contracts/vault/IVault.sol/IVault.dbg.json +1 -1
  33. package/build/contracts/vault/TBTCVault.sol/TBTCVault.dbg.json +1 -1
  34. package/contracts/bridge/BitcoinTx.sol +19 -26
  35. package/contracts/bridge/Bridge.sol +476 -534
  36. package/contracts/bridge/BridgeState.sol +190 -129
  37. package/contracts/bridge/Deposit.sol +23 -4
  38. package/contracts/bridge/EcdsaLib.sol +15 -0
  39. package/contracts/bridge/{Frauds.sol → Fraud.sol} +75 -146
  40. package/contracts/bridge/MovingFunds.sol +15 -9
  41. package/contracts/bridge/{Redeem.sol → Redemption.sol} +19 -17
  42. package/contracts/bridge/Sweep.sol +16 -9
  43. package/contracts/bridge/Wallets.sol +40 -121
  44. package/package.json +1 -1
  45. package/build/contracts/bridge/Frauds.sol/Frauds.dbg.json +0 -4
  46. package/build/contracts/bridge/Frauds.sol/Frauds.json +0 -138
  47. package/build/contracts/bridge/Redeem.sol/OutboundTx.dbg.json +0 -4
  48. package/build/contracts/bridge/Redeem.sol/Redeem.dbg.json +0 -4
  49. package/build/contracts/bridge/Redeem.sol/Redeem.json +0 -110
@@ -18,32 +18,35 @@ pragma solidity ^0.8.9;
18
18
  import {BytesLib} from "@keep-network/bitcoin-spv-sol/contracts/BytesLib.sol";
19
19
  import {BTCUtils} from "@keep-network/bitcoin-spv-sol/contracts/BTCUtils.sol";
20
20
  import {CheckBitcoinSigs} from "@keep-network/bitcoin-spv-sol/contracts/CheckBitcoinSigs.sol";
21
+
21
22
  import "./BitcoinTx.sol";
22
23
  import "./EcdsaLib.sol";
23
- import "./Bridge.sol";
24
-
25
- library Frauds {
24
+ import "./BridgeState.sol";
25
+ import "./Wallets.sol";
26
+
27
+ /// @title Bridge fraud
28
+ /// @notice The library handles the logic for challenging Bridge wallets that
29
+ /// committed fraud.
30
+ /// @dev Anyone can submit a fraud challenge indicating that a UTXO being under
31
+ /// the wallet control was unlocked by the wallet but was not used
32
+ /// according to the protocol rules. That means the wallet signed
33
+ /// a transaction input pointing to that UTXO and there is a unique
34
+ /// sighash and signature pair associated with that input.
35
+ ///
36
+ /// In order to defeat the challenge, the same wallet public key and
37
+ /// signature must be provided as were used to calculate the sighash during
38
+ /// the challenge. The wallet provides the preimage which produces sighash
39
+ /// used to generate the ECDSA signature that is the subject of the fraud
40
+ /// claim. The fraud challenge defeat attempt will only succeed if the
41
+ /// inputs in the preimage are considered honestly spent by the wallet.
42
+ /// Therefore the transaction spending the UTXO must be proven in the
43
+ /// Bridge before a challenge defeat is called.
44
+ library Fraud {
26
45
  using BytesLib for bytes;
27
46
  using BTCUtils for bytes;
28
47
  using BTCUtils for uint32;
29
48
  using EcdsaLib for bytes;
30
49
 
31
- struct Data {
32
- /// The amount of stake slashed from each member of a wallet for a fraud.
33
- uint256 slashingAmount;
34
- /// The percentage of the notifier reward from the staking contract
35
- /// the notifier of a fraud receives. The value is in the range [0, 100].
36
- uint256 notifierRewardMultiplier;
37
- /// The amount of time the wallet has to defeat a fraud challenge.
38
- uint256 challengeDefeatTimeout;
39
- /// The amount of ETH in wei the party challenging the wallet for fraud
40
- /// needs to deposit.
41
- uint256 challengeDepositAmount;
42
- /// Collection of all submitted fraud challenges indexed by challenge
43
- /// key built as keccak256(walletPublicKey|sighash).
44
- mapping(uint256 => FraudChallenge) challenges;
45
- }
46
-
47
50
  struct FraudChallenge {
48
51
  // The address of the party challenging the wallet.
49
52
  address challenger;
@@ -55,20 +58,6 @@ library Frauds {
55
58
  bool resolved;
56
59
  }
57
60
 
58
- event FraudSlashingAmountUpdated(uint256 newFraudSlashingAmount);
59
-
60
- event FraudNotifierRewardMultiplierUpdated(
61
- uint256 newFraudNotifierRewardMultiplier
62
- );
63
-
64
- event FraudChallengeDefeatTimeoutUpdated(
65
- uint256 newFraudChallengeDefeatTimeout
66
- );
67
-
68
- event FraudChallengeDepositAmountUpdated(
69
- uint256 newFraudChallengeDepositAmount
70
- );
71
-
72
61
  event FraudChallengeSubmitted(
73
62
  bytes20 walletPublicKeyHash,
74
63
  bytes32 sighash,
@@ -101,8 +90,6 @@ library Frauds {
101
90
  /// challenge or confiscated otherwise
102
91
  /// @param walletPublicKey The public key of the wallet in the uncompressed
103
92
  /// and unprefixed format (64 bytes)
104
- /// @param walletPubKeyHash 20-byte public key hash (computed using Bitcoin
105
- // HASH160 over the compressed ECDSA public key) of the wallet
106
93
  /// @param sighash The hash that was used to produce the ECDSA signature
107
94
  /// that is the subject of the fraud claim. This hash is constructed
108
95
  /// by applying double SHA-256 over a serialized subset of the
@@ -111,20 +98,21 @@ library Frauds {
111
98
  /// for reference
112
99
  /// @param signature Bitcoin signature in the R/S/V format
113
100
  /// @dev Requirements:
101
+ /// - Wallet behind `walletPublicKey` must be in `Live` or `MovingFunds`
102
+ /// state
114
103
  /// - The challenger must send appropriate amount of ETH used as
115
104
  /// fraud challenge deposit
116
105
  /// - The signature (represented by r, s and v) must be generated by
117
- /// the wallet behind `walletPubKey` during signing of `sighash`
106
+ /// the wallet behind `walletPublicKey` during signing of `sighash`
118
107
  /// - Wallet can be challenged for the given signature only once
119
- function submitChallenge(
120
- Data storage self,
108
+ function submitFraudChallenge(
109
+ BridgeState.Storage storage self,
121
110
  bytes calldata walletPublicKey,
122
- bytes20 walletPubKeyHash,
123
111
  bytes32 sighash,
124
112
  BitcoinTx.RSVSignature calldata signature
125
113
  ) external {
126
114
  require(
127
- msg.value >= self.challengeDepositAmount,
115
+ msg.value >= self.fraudChallengeDepositAmount,
128
116
  "The amount of ETH deposited is too low"
129
117
  );
130
118
 
@@ -139,11 +127,27 @@ library Frauds {
139
127
  "Signature verification failure"
140
128
  );
141
129
 
130
+ bytes memory compressedWalletPublicKey = EcdsaLib.compressPublicKey(
131
+ walletPublicKey.slice32(0),
132
+ walletPublicKey.slice32(32)
133
+ );
134
+ bytes20 walletPubKeyHash = compressedWalletPublicKey.hash160View();
135
+
136
+ Wallets.Wallet storage wallet = self.registeredWallets[
137
+ walletPubKeyHash
138
+ ];
139
+
140
+ require(
141
+ wallet.state == Wallets.WalletState.Live ||
142
+ wallet.state == Wallets.WalletState.MovingFunds,
143
+ "Wallet is neither in Live nor MovingFunds state"
144
+ );
145
+
142
146
  uint256 challengeKey = uint256(
143
147
  keccak256(abi.encodePacked(walletPublicKey, sighash))
144
148
  );
145
149
 
146
- FraudChallenge storage challenge = self.challenges[challengeKey];
150
+ FraudChallenge storage challenge = self.fraudChallenges[challengeKey];
147
151
  require(challenge.reportedAt == 0, "Fraud challenge already exists");
148
152
 
149
153
  challenge.challenger = msg.sender;
@@ -161,8 +165,18 @@ library Frauds {
161
165
  );
162
166
  }
163
167
 
164
- /// @notice Unwraps the fraud challenge by verifying the given challenge
165
- /// and returns the UTXO key extracted from the preimage.
168
+ /// @notice Allows to defeat a pending fraud challenge against a wallet if
169
+ /// the transaction that spends the UTXO follows the protocol rules.
170
+ /// In order to defeat the challenge the same `walletPublicKey` and
171
+ /// signature (represented by `r`, `s` and `v`) must be provided as
172
+ /// were used to calculate the sighash during input signing.
173
+ /// The fraud challenge defeat attempt will only succeed if the
174
+ /// inputs in the preimage are considered honestly spent by the
175
+ /// wallet. Therefore the transaction spending the UTXO must be
176
+ /// proven in the Bridge before a challenge defeat is called.
177
+ /// If successfully defeated, the fraud challenge is marked as
178
+ /// resolved and the amount of ether deposited by the challenger is
179
+ /// sent to the treasury.
166
180
  /// @param walletPublicKey The public key of the wallet in the uncompressed
167
181
  /// and unprefixed format (64 bytes)
168
182
  /// @param preimage The preimage which produces sighash used to generate the
@@ -172,25 +186,26 @@ library Frauds {
172
186
  /// produced for. See BIP-143 for reference
173
187
  /// @param witness Flag indicating whether the preimage was produced for a
174
188
  /// witness input. True for witness, false for non-witness input.
175
- /// @return utxoKey UTXO key that identifies spent input.
176
189
  /// @dev Requirements:
177
190
  /// - `walletPublicKey` and `sighash` calculated as `hash256(preimage)`
178
191
  /// must identify an open fraud challenge
179
192
  /// - the preimage must be a valid preimage of a transaction generated
180
193
  /// according to the protocol rules and already proved in the Bridge
181
- function unwrapChallenge(
182
- Data storage self,
194
+ /// - before a defeat attempt is made the transaction that spends the
195
+ /// given UTXO must be proven in the Bridge
196
+ function defeatFraudChallenge(
197
+ BridgeState.Storage storage self,
183
198
  bytes calldata walletPublicKey,
184
199
  bytes calldata preimage,
185
200
  bool witness
186
- ) external returns (uint256 utxoKey) {
201
+ ) external {
187
202
  bytes32 sighash = preimage.hash256();
188
203
 
189
204
  uint256 challengeKey = uint256(
190
205
  keccak256(abi.encodePacked(walletPublicKey, sighash))
191
206
  );
192
207
 
193
- FraudChallenge storage challenge = self.challenges[challengeKey];
208
+ FraudChallenge storage challenge = self.fraudChallenges[challengeKey];
194
209
 
195
210
  require(challenge.reportedAt > 0, "Fraud challenge does not exist");
196
211
  require(
@@ -202,55 +217,23 @@ library Frauds {
202
217
  // by type value `1`.
203
218
  require(extractSighashType(preimage) == 1, "Wrong sighash type");
204
219
 
205
- return
206
- witness
207
- ? extractUtxoKeyFromWitnessPreimage(preimage)
208
- : extractUtxoKeyFromNonWitnessPreimage(preimage);
209
- }
210
-
211
- /// @notice Finalizes fraud challenge defeat by marking a pending fraud
212
- /// challenge against the wallet as resolved and sending the ether
213
- /// deposited by the challenger to the treasury.
214
- /// In order to finalize the challenge defeat the same
215
- /// `walletPublicKey` must be provided as was used in the fraud
216
- /// challenge. Additionally a preimage must be provided which was
217
- /// used to calculate the sighash during input signing.
218
- /// @param walletPublicKey The public key of the wallet in the uncompressed
219
- /// and unprefixed format (64 bytes)
220
- /// @param preimage The preimage which produces sighash used to generate the
221
- /// ECDSA signature that is the subject of the fraud claim. It is a
222
- /// serialized subset of the transaction. The exact subset used as
223
- /// the preimage depends on the transaction input the signature is
224
- /// produced for. See BIP-143 for reference
225
- /// @param treasury Treasury associated with the Bridge
226
- /// @dev Requirements:
227
- /// - `walletPublicKey` and `sighash` calculated as `hash256(preimage)`
228
- /// must identify an open fraud challenge
229
- /// - the preimage must be a valid preimage of a transaction generated
230
- /// according to the protocol rules and already proved in the Bridge
231
- /// - before a defeat attempt is made the transaction that spends the
232
- /// given UTXO must be proven in the Bridge
233
- function defeatChallenge(
234
- Data storage self,
235
- bytes calldata walletPublicKey,
236
- bytes calldata preimage,
237
- address treasury
238
- ) external {
239
- bytes32 sighash = preimage.hash256();
220
+ uint256 utxoKey = witness
221
+ ? extractUtxoKeyFromWitnessPreimage(preimage)
222
+ : extractUtxoKeyFromNonWitnessPreimage(preimage);
240
223
 
241
- uint256 challengeKey = uint256(
242
- keccak256(abi.encodePacked(walletPublicKey, sighash))
224
+ // Check that the UTXO key identifies a correctly spent UTXO.
225
+ require(
226
+ self.deposits[utxoKey].sweptAt > 0 || self.spentMainUTXOs[utxoKey],
227
+ "Spent UTXO not found among correctly spent UTXOs"
243
228
  );
244
229
 
245
- FraudChallenge storage challenge = self.challenges[challengeKey];
246
-
247
230
  // Mark the challenge as resolved as it was successfully defeated
248
231
  challenge.resolved = true;
249
232
 
250
233
  // Send the ether deposited by the challenger to the treasury
251
234
  /* solhint-disable avoid-low-level-calls */
252
235
  // slither-disable-next-line low-level-calls
253
- treasury.call{gas: 100000, value: challenge.depositAmount}("");
236
+ self.treasury.call{gas: 100000, value: challenge.depositAmount}("");
254
237
  /* solhint-enable avoid-low-level-calls */
255
238
 
256
239
  bytes memory compressedWalletPublicKey = EcdsaLib.compressPublicKey(
@@ -285,8 +268,8 @@ library Frauds {
285
268
  /// challenge
286
269
  /// - the amount of time indicated by `challengeDefeatTimeout` must pass
287
270
  /// after the challenge was reported
288
- function notifyChallengeDefeatTimeout(
289
- Data storage self,
271
+ function notifyFraudChallengeDefeatTimeout(
272
+ BridgeState.Storage storage self,
290
273
  bytes calldata walletPublicKey,
291
274
  bytes32 sighash
292
275
  ) external {
@@ -294,7 +277,7 @@ library Frauds {
294
277
  keccak256(abi.encodePacked(walletPublicKey, sighash))
295
278
  );
296
279
 
297
- FraudChallenge storage challenge = self.challenges[challengeKey];
280
+ FraudChallenge storage challenge = self.fraudChallenges[challengeKey];
298
281
  require(challenge.reportedAt > 0, "Fraud challenge does not exist");
299
282
  require(
300
283
  !challenge.resolved,
@@ -303,7 +286,7 @@ library Frauds {
303
286
  require(
304
287
  /* solhint-disable-next-line not-rely-on-time */
305
288
  block.timestamp >=
306
- challenge.reportedAt + self.challengeDefeatTimeout,
289
+ challenge.reportedAt + self.fraudChallengeDefeatTimeout,
307
290
  "Fraud challenge defeat period did not time out yet"
308
291
  );
309
292
 
@@ -329,60 +312,6 @@ library Frauds {
329
312
  emit FraudChallengeDefeatTimedOut(walletPubKeyHash, sighash);
330
313
  }
331
314
 
332
- /// @notice Sets the new value for the `slashingAmount` parameter.
333
- /// @param _newSlashingAmount the new value for `slashingAmount`
334
- function setSlashingAmount(Data storage self, uint256 _newSlashingAmount)
335
- external
336
- {
337
- self.slashingAmount = _newSlashingAmount;
338
- emit FraudSlashingAmountUpdated(_newSlashingAmount);
339
- }
340
-
341
- /// @notice Sets the new value for the `notifierRewardMultiplier` parameter.
342
- /// @param _newNotifierRewardMultiplier the new value for `notifierRewardMultiplier`
343
- /// @dev The value of `notifierRewardMultiplier` must be <= 100.
344
- function setNotifierRewardMultiplier(
345
- Data storage self,
346
- uint256 _newNotifierRewardMultiplier
347
- ) external {
348
- require(
349
- _newNotifierRewardMultiplier <= 100,
350
- "Fraud notifier reward multiplier must be <= 100"
351
- );
352
- self.notifierRewardMultiplier = _newNotifierRewardMultiplier;
353
- emit FraudNotifierRewardMultiplierUpdated(_newNotifierRewardMultiplier);
354
- }
355
-
356
- /// @notice Sets the new value for the `challengeDefeatTimeout` parameter.
357
- /// @param _newChallengeDefeatTimeout the new value for `challengeDefeatTimeout`
358
- /// @dev The value of `challengeDefeatTimeout` must be > 0.
359
- function setChallengeDefeatTimeout(
360
- Data storage self,
361
- uint256 _newChallengeDefeatTimeout
362
- ) external {
363
- require(
364
- _newChallengeDefeatTimeout > 0,
365
- "Fraud challenge defeat timeout must be > 0"
366
- );
367
- self.challengeDefeatTimeout = _newChallengeDefeatTimeout;
368
- emit FraudChallengeDefeatTimeoutUpdated(_newChallengeDefeatTimeout);
369
- }
370
-
371
- /// @notice Sets the new value for the `challengeDepositAmount` parameter.
372
- /// @param _newChallengeDepositAmount the new value for `challengeDepositAmount`
373
- /// @dev The value of `challengeDepositAmount` must be > 0.
374
- function setChallengeDepositAmount(
375
- Data storage self,
376
- uint256 _newChallengeDepositAmount
377
- ) external {
378
- require(
379
- _newChallengeDepositAmount > 0,
380
- "Fraud challenge deposit amount must be > 0"
381
- );
382
- self.challengeDepositAmount = _newChallengeDepositAmount;
383
- emit FraudChallengeDepositAmountUpdated(_newChallengeDepositAmount);
384
- }
385
-
386
315
  /// @notice Extracts the UTXO keys from the given preimage used during
387
316
  /// signing of a witness input.
388
317
  /// @param preimage The preimage which produces sighash used to generate the
@@ -20,11 +20,20 @@ import {BytesLib} from "@keep-network/bitcoin-spv-sol/contracts/BytesLib.sol";
20
20
 
21
21
  import "./BitcoinTx.sol";
22
22
  import "./BridgeState.sol";
23
- import "./Redeem.sol";
23
+ import "./Redemption.sol";
24
24
 
25
+ /// @title Moving Bridge wallet funds
26
+ /// @notice The library handles the logic for moving Bitcoin between Bridge
27
+ /// wallets.
28
+ /// @dev A wallet that failed a heartbeat, did not process requested redemption
29
+ /// on time, or qualifies to be closed, begins the procedure of moving
30
+ /// funds to other wallets in the Bridge. The wallet needs to commit to
31
+ /// which other Live wallets it is moving the funds to and then, provide an
32
+ /// SPV proof of moving funds to the previously committed wallets.
25
33
  library MovingFunds {
26
34
  using BridgeState for BridgeState.Storage;
27
- using Wallets for Wallets.Data;
35
+ using Wallets for BridgeState.Storage;
36
+ using BitcoinTx for BridgeState.Storage;
28
37
 
29
38
  using BTCUtils for bytes;
30
39
  using BytesLib for bytes;
@@ -81,7 +90,6 @@ library MovingFunds {
81
90
  /// to `movingFundsTxMaxTotalFee` governable parameter.
82
91
  function submitMovingFundsProof(
83
92
  BridgeState.Storage storage self,
84
- Wallets.Data storage wallets,
85
93
  BitcoinTx.Info calldata movingFundsTx,
86
94
  BitcoinTx.Proof calldata movingFundsProof,
87
95
  BitcoinTx.UTXO calldata mainUtxo,
@@ -91,17 +99,15 @@ library MovingFunds {
91
99
  // can assume the transaction happened on Bitcoin chain and has
92
100
  // a sufficient number of confirmations as determined by
93
101
  // `txProofDifficultyFactor` constant.
94
- bytes32 movingFundsTxHash = BitcoinTx.validateProof(
102
+ bytes32 movingFundsTxHash = self.validateProof(
95
103
  movingFundsTx,
96
- movingFundsProof,
97
- self.proofDifficultyContext()
104
+ movingFundsProof
98
105
  );
99
106
 
100
107
  // Process the moving funds transaction input. Specifically, check if
101
108
  // it refers to the expected wallet's main UTXO.
102
109
  OutboundTx.processWalletOutboundTxInput(
103
110
  self,
104
- wallets,
105
111
  movingFundsTx.inputVector,
106
112
  mainUtxo,
107
113
  walletPubKeyHash
@@ -118,7 +124,7 @@ library MovingFunds {
118
124
  "Transaction fee is too high"
119
125
  );
120
126
 
121
- wallets.notifyFundsMoved(walletPubKeyHash, targetWalletsHash);
127
+ self.notifyWalletFundsMoved(walletPubKeyHash, targetWalletsHash);
122
128
 
123
129
  emit MovingFundsCompleted(walletPubKeyHash, movingFundsTxHash);
124
130
  }
@@ -139,7 +145,7 @@ library MovingFunds {
139
145
  /// - The total outputs value must be evenly divided over all outputs.
140
146
  function processMovingFundsTxOutputs(bytes memory movingFundsTxOutputVector)
141
147
  internal
142
- view
148
+ pure
143
149
  returns (bytes32 targetWalletsHash, uint256 outputsTotalValue)
144
150
  {
145
151
  // Determining the total number of Bitcoin transaction outputs in
@@ -47,13 +47,12 @@ library OutboundTx {
47
47
  /// performed the outbound transaction.
48
48
  function processWalletOutboundTxInput(
49
49
  BridgeState.Storage storage self,
50
- Wallets.Data storage wallets,
51
50
  bytes memory walletOutboundTxInputVector,
52
51
  BitcoinTx.UTXO calldata mainUtxo,
53
52
  bytes20 walletPubKeyHash
54
53
  ) internal {
55
54
  // Assert that main UTXO for passed wallet exists in storage.
56
- bytes32 mainUtxoHash = wallets
55
+ bytes32 mainUtxoHash = self
57
56
  .registeredWallets[walletPubKeyHash]
58
57
  .mainUtxoHash;
59
58
  require(mainUtxoHash != bytes32(0), "No main UTXO for given wallet");
@@ -141,10 +140,18 @@ library OutboundTx {
141
140
  }
142
141
  }
143
142
 
144
- // TODO: Rename to Redemption. All library names are nouns.
145
- library Redeem {
143
+ /// @title Bridge redemption
144
+ /// @notice The library handles the logic for redeeming Bitcoin balances from
145
+ /// the Bridge.
146
+ /// @dev To initiate a redemption, a user with a Bank balance supplies
147
+ /// a Bitcoin address. Then, the system calculates the redemption fee, and
148
+ /// releases balance to the provided Bitcoin address. Just like in case of
149
+ /// sweeps of revealed deposits, redemption requests are processed in
150
+ /// batches and require SPV proof to be submitted to the Bridge.
151
+ library Redemption {
146
152
  using BridgeState for BridgeState.Storage;
147
- using Wallets for Wallets.Data;
153
+ using Wallets for BridgeState.Storage;
154
+ using BitcoinTx for BridgeState.Storage;
148
155
 
149
156
  using BTCUtils for bytes;
150
157
  using BytesLib for bytes;
@@ -248,13 +255,12 @@ library Redeem {
248
255
  /// contract can spend the given `amount`.
249
256
  function requestRedemption(
250
257
  BridgeState.Storage storage self,
251
- Wallets.Data storage wallets,
252
258
  bytes20 walletPubKeyHash,
253
259
  BitcoinTx.UTXO calldata mainUtxo,
254
260
  bytes calldata redeemerOutputScript,
255
261
  uint64 amount
256
262
  ) external {
257
- Wallets.Wallet storage wallet = wallets.registeredWallets[
263
+ Wallets.Wallet storage wallet = self.registeredWallets[
258
264
  walletPubKeyHash
259
265
  ];
260
266
 
@@ -419,7 +425,6 @@ library Redeem {
419
425
  /// is identified, that check is omitted in further iterations.
420
426
  function submitRedemptionProof(
421
427
  BridgeState.Storage storage self,
422
- Wallets.Data storage wallets,
423
428
  BitcoinTx.Info calldata redemptionTx,
424
429
  BitcoinTx.Proof calldata redemptionProof,
425
430
  BitcoinTx.UTXO calldata mainUtxo,
@@ -433,23 +438,21 @@ library Redeem {
433
438
  // can assume the transaction happened on Bitcoin chain and has
434
439
  // a sufficient number of confirmations as determined by
435
440
  // `txProofDifficultyFactor` constant.
436
- bytes32 redemptionTxHash = BitcoinTx.validateProof(
441
+ bytes32 redemptionTxHash = self.validateProof(
437
442
  redemptionTx,
438
- redemptionProof,
439
- self.proofDifficultyContext()
443
+ redemptionProof
440
444
  );
441
445
 
442
446
  // Process the redemption transaction input. Specifically, check if it
443
447
  // refers to the expected wallet's main UTXO.
444
448
  OutboundTx.processWalletOutboundTxInput(
445
449
  self,
446
- wallets,
447
450
  redemptionTx.inputVector,
448
451
  mainUtxo,
449
452
  walletPubKeyHash
450
453
  );
451
454
 
452
- Wallets.Wallet storage wallet = wallets.registeredWallets[
455
+ Wallets.Wallet storage wallet = self.registeredWallets[
453
456
  walletPubKeyHash
454
457
  ];
455
458
 
@@ -789,14 +792,13 @@ library Redeem {
789
792
  /// timed-out).
790
793
  function notifyRedemptionTimeout(
791
794
  BridgeState.Storage storage self,
792
- Wallets.Data storage wallets,
793
795
  bytes20 walletPubKeyHash,
794
796
  bytes calldata redeemerOutputScript
795
797
  ) external {
796
798
  uint256 redemptionKey = uint256(
797
799
  keccak256(abi.encodePacked(walletPubKeyHash, redeemerOutputScript))
798
800
  );
799
- Redeem.RedemptionRequest memory request = self.pendingRedemptions[
801
+ Redemption.RedemptionRequest memory request = self.pendingRedemptions[
800
802
  redemptionKey
801
803
  ];
802
804
 
@@ -808,7 +810,7 @@ library Redeem {
808
810
  );
809
811
 
810
812
  // Update the wallet's pending redemptions value
811
- Wallets.Wallet storage wallet = wallets.registeredWallets[
813
+ Wallets.Wallet storage wallet = self.registeredWallets[
812
814
  walletPubKeyHash
813
815
  ];
814
816
  wallet.pendingRedemptionsValue -=
@@ -838,7 +840,7 @@ library Redeem {
838
840
  wallet.state == Wallets.WalletState.MovingFunds
839
841
  ) {
840
842
  // Propagate timeout consequences to the wallet
841
- wallets.notifyRedemptionTimedOut(walletPubKeyHash);
843
+ self.notifyWalletTimedOutRedemption(walletPubKeyHash);
842
844
  }
843
845
 
844
846
  emit RedemptionTimedOut(walletPubKeyHash, redeemerOutputScript);
@@ -23,8 +23,19 @@ import "./Wallets.sol";
23
23
 
24
24
  import "../bank/Bank.sol";
25
25
 
26
+ /// @title Bridge deposit sweep
27
+ /// @notice The library handles the logic for sweeping transactions revealed to
28
+ /// the Bridge
29
+ /// @dev Bridge active wallet periodically signs a transaction that unlocks all
30
+ /// of the valid, revealed deposits above the dust threshold, combines them
31
+ /// into a single UTXO with the existing main wallet UTXO, and relocks
32
+ /// those transactions without a 30-day refund clause to the same wallet.
33
+ /// This has two main effects: it consolidates the UTXO set and it disables
34
+ /// the refund. Balances of depositors in the Bank are increased when the
35
+ /// SPV sweep proof is submitted to the Bridge.
26
36
  library Sweep {
27
37
  using BridgeState for BridgeState.Storage;
38
+ using BitcoinTx for BridgeState.Storage;
28
39
 
29
40
  using BTCUtils for bytes;
30
41
 
@@ -94,7 +105,6 @@ library Sweep {
94
105
  /// If there is no main UTXO, this parameter is ignored.
95
106
  function submitSweepProof(
96
107
  BridgeState.Storage storage self,
97
- Wallets.Data storage wallets,
98
108
  BitcoinTx.Info calldata sweepTx,
99
109
  BitcoinTx.Proof calldata sweepProof,
100
110
  BitcoinTx.UTXO calldata mainUtxo
@@ -106,11 +116,7 @@ library Sweep {
106
116
  // can assume the transaction happened on Bitcoin chain and has
107
117
  // a sufficient number of confirmations as determined by
108
118
  // `txProofDifficultyFactor` constant.
109
- bytes32 sweepTxHash = BitcoinTx.validateProof(
110
- sweepTx,
111
- sweepProof,
112
- self.proofDifficultyContext()
113
- );
119
+ bytes32 sweepTxHash = self.validateProof(sweepTx, sweepProof);
114
120
 
115
121
  // Process sweep transaction output and extract its target wallet
116
122
  // public key hash and value.
@@ -122,7 +128,7 @@ library Sweep {
122
128
  (
123
129
  Wallets.Wallet storage wallet,
124
130
  BitcoinTx.UTXO memory resolvedMainUtxo
125
- ) = resolveSweepingWallet(wallets, walletPubKeyHash, mainUtxo);
131
+ ) = resolveSweepingWallet(self, walletPubKeyHash, mainUtxo);
126
132
 
127
133
  // Process sweep transaction inputs and extract all information needed
128
134
  // to perform deposit bookkeeping.
@@ -208,17 +214,18 @@ library Sweep {
208
214
  /// - If the main UTXO of the sweeping wallet exists in the storage,
209
215
  /// the passed `mainUTXO` parameter must be equal to the stored one.
210
216
  function resolveSweepingWallet(
211
- Wallets.Data storage wallets,
217
+ BridgeState.Storage storage self,
212
218
  bytes20 walletPubKeyHash,
213
219
  BitcoinTx.UTXO calldata mainUtxo
214
220
  )
215
221
  internal
222
+ view
216
223
  returns (
217
224
  Wallets.Wallet storage wallet,
218
225
  BitcoinTx.UTXO memory resolvedMainUtxo
219
226
  )
220
227
  {
221
- wallet = wallets.registeredWallets[walletPubKeyHash];
228
+ wallet = self.registeredWallets[walletPubKeyHash];
222
229
 
223
230
  Wallets.WalletState walletState = wallet.state;
224
231
  require(