@keep-network/tbtc-v2 0.1.1-dev.4 → 0.1.1-dev.42

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 (60) hide show
  1. package/README.adoc +12 -0
  2. package/artifacts/TBTC.json +19 -18
  3. package/artifacts/TBTCToken.json +19 -18
  4. package/artifacts/VendingMachine.json +20 -19
  5. package/artifacts/solcInputs/002940e9cc8128f6629e90620c66cba5.json +215 -0
  6. package/build/contracts/GovernanceUtils.sol/GovernanceUtils.dbg.json +1 -1
  7. package/build/contracts/GovernanceUtils.sol/GovernanceUtils.json +2 -2
  8. package/build/contracts/bank/Bank.sol/Bank.dbg.json +1 -1
  9. package/build/contracts/bank/Bank.sol/Bank.json +20 -2
  10. package/build/contracts/bridge/BitcoinTx.sol/BitcoinTx.dbg.json +4 -0
  11. package/build/contracts/bridge/BitcoinTx.sol/BitcoinTx.json +10 -0
  12. package/build/contracts/bridge/Bridge.sol/Bridge.dbg.json +1 -1
  13. package/build/contracts/bridge/Bridge.sol/Bridge.json +1664 -63
  14. package/build/contracts/bridge/BridgeState.sol/BridgeState.dbg.json +4 -0
  15. package/build/contracts/bridge/BridgeState.sol/BridgeState.json +42 -0
  16. package/build/contracts/bridge/Deposit.sol/Deposit.dbg.json +4 -0
  17. package/build/contracts/bridge/Deposit.sol/Deposit.json +72 -0
  18. package/build/contracts/bridge/EcdsaLib.sol/EcdsaLib.dbg.json +4 -0
  19. package/build/contracts/bridge/EcdsaLib.sol/EcdsaLib.json +10 -0
  20. package/build/contracts/bridge/Fraud.sol/Fraud.dbg.json +4 -0
  21. package/build/contracts/bridge/Fraud.sol/Fraud.json +138 -0
  22. package/build/contracts/bridge/IRelay.sol/IRelay.dbg.json +4 -0
  23. package/build/contracts/bridge/IRelay.sol/IRelay.json +37 -0
  24. package/build/contracts/bridge/MovingFunds.sol/MovingFunds.dbg.json +4 -0
  25. package/build/contracts/bridge/MovingFunds.sol/MovingFunds.json +30 -0
  26. package/build/contracts/bridge/Redeem.sol/OutboundTx.dbg.json +4 -0
  27. package/build/contracts/bridge/Redeem.sol/OutboundTx.json +10 -0
  28. package/build/contracts/bridge/Redeem.sol/Redeem.dbg.json +4 -0
  29. package/build/contracts/bridge/Redeem.sol/Redeem.json +92 -0
  30. package/build/contracts/bridge/Sweep.sol/Sweep.dbg.json +4 -0
  31. package/build/contracts/bridge/Sweep.sol/Sweep.json +30 -0
  32. package/build/contracts/bridge/VendingMachine.sol/VendingMachine.dbg.json +1 -1
  33. package/build/contracts/bridge/VendingMachine.sol/VendingMachine.json +2 -2
  34. package/build/contracts/bridge/Wallets.sol/Wallets.dbg.json +4 -0
  35. package/build/contracts/bridge/Wallets.sol/Wallets.json +93 -0
  36. package/build/contracts/token/TBTC.sol/TBTC.dbg.json +1 -1
  37. package/build/contracts/token/TBTC.sol/TBTC.json +2 -2
  38. package/build/contracts/vault/IVault.sol/IVault.dbg.json +1 -1
  39. package/build/contracts/vault/IVault.sol/IVault.json +19 -1
  40. package/build/contracts/vault/TBTCVault.sol/TBTCVault.dbg.json +1 -1
  41. package/build/contracts/vault/TBTCVault.sol/TBTCVault.json +36 -18
  42. package/contracts/GovernanceUtils.sol +1 -1
  43. package/contracts/bank/Bank.sol +34 -18
  44. package/contracts/bridge/BitcoinTx.sol +241 -0
  45. package/contracts/bridge/Bridge.sol +942 -123
  46. package/contracts/bridge/BridgeState.sol +251 -0
  47. package/contracts/bridge/Deposit.sol +244 -0
  48. package/contracts/bridge/EcdsaLib.sol +30 -0
  49. package/contracts/bridge/Fraud.sol +455 -0
  50. package/contracts/bridge/IRelay.sol +28 -0
  51. package/contracts/bridge/MovingFunds.sol +278 -0
  52. package/contracts/bridge/Redeem.sol +844 -0
  53. package/contracts/bridge/Sweep.sol +509 -0
  54. package/contracts/bridge/VendingMachine.sol +1 -1
  55. package/contracts/bridge/Wallets.sol +510 -0
  56. package/contracts/token/TBTC.sol +1 -1
  57. package/contracts/vault/IVault.sol +32 -10
  58. package/contracts/vault/TBTCVault.sol +20 -2
  59. package/package.json +28 -24
  60. package/artifacts/solcInputs/d71966212a658480bad5748ad85b1396.json +0 -116
@@ -0,0 +1,455 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ // ██████████████ ▐████▌ ██████████████
4
+ // ██████████████ ▐████▌ ██████████████
5
+ // ▐████▌ ▐████▌
6
+ // ▐████▌ ▐████▌
7
+ // ██████████████ ▐████▌ ██████████████
8
+ // ██████████████ ▐████▌ ██████████████
9
+ // ▐████▌ ▐████▌
10
+ // ▐████▌ ▐████▌
11
+ // ▐████▌ ▐████▌
12
+ // ▐████▌ ▐████▌
13
+ // ▐████▌ ▐████▌
14
+ // ▐████▌ ▐████▌
15
+
16
+ pragma solidity ^0.8.9;
17
+
18
+ import {BytesLib} from "@keep-network/bitcoin-spv-sol/contracts/BytesLib.sol";
19
+ import {BTCUtils} from "@keep-network/bitcoin-spv-sol/contracts/BTCUtils.sol";
20
+ import {CheckBitcoinSigs} from "@keep-network/bitcoin-spv-sol/contracts/CheckBitcoinSigs.sol";
21
+
22
+ import "./BitcoinTx.sol";
23
+ import "./EcdsaLib.sol";
24
+ import "./BridgeState.sol";
25
+ import "./Wallets.sol";
26
+
27
+ library Fraud {
28
+ using BytesLib for bytes;
29
+ using BTCUtils for bytes;
30
+ using BTCUtils for uint32;
31
+ using EcdsaLib for bytes;
32
+
33
+ struct FraudChallenge {
34
+ // The address of the party challenging the wallet.
35
+ address challenger;
36
+ // The amount of ETH the challenger deposited.
37
+ uint256 depositAmount;
38
+ // The timestamp the challenge was submitted at.
39
+ uint32 reportedAt;
40
+ // The flag indicating whether the challenge has been resolved.
41
+ bool resolved;
42
+ }
43
+
44
+ event FraudSlashingAmountUpdated(uint256 newFraudSlashingAmount);
45
+
46
+ event FraudNotifierRewardMultiplierUpdated(
47
+ uint256 newFraudNotifierRewardMultiplier
48
+ );
49
+
50
+ event FraudChallengeDefeatTimeoutUpdated(
51
+ uint256 newFraudChallengeDefeatTimeout
52
+ );
53
+
54
+ event FraudChallengeDepositAmountUpdated(
55
+ uint256 newFraudChallengeDepositAmount
56
+ );
57
+
58
+ event FraudChallengeSubmitted(
59
+ bytes20 walletPublicKeyHash,
60
+ bytes32 sighash,
61
+ uint8 v,
62
+ bytes32 r,
63
+ bytes32 s
64
+ );
65
+
66
+ event FraudChallengeDefeated(bytes20 walletPublicKeyHash, bytes32 sighash);
67
+
68
+ event FraudChallengeDefeatTimedOut(
69
+ bytes20 walletPublicKeyHash,
70
+ bytes32 sighash
71
+ );
72
+
73
+ /// @notice Submits a fraud challenge indicating that a UTXO being under
74
+ /// wallet control was unlocked by the wallet but was not used
75
+ /// according to the protocol rules. That means the wallet signed
76
+ /// a transaction input pointing to that UTXO and there is a unique
77
+ /// sighash and signature pair associated with that input. This
78
+ /// function uses those parameters to create a fraud accusation that
79
+ /// proves a given transaction input unlocking the given UTXO was
80
+ /// actually signed by the wallet. This function cannot determine
81
+ /// whether the transaction was actually broadcast and the input was
82
+ /// consumed in a fraudulent way so it just opens a challenge period
83
+ /// during which the wallet can defeat the challenge by submitting
84
+ /// proof of a transaction that consumes the given input according
85
+ /// to protocol rules. To prevent spurious allegations, the caller
86
+ /// must deposit ETH that is returned back upon justified fraud
87
+ /// challenge or confiscated otherwise
88
+ /// @param walletPublicKey The public key of the wallet in the uncompressed
89
+ /// and unprefixed format (64 bytes)
90
+ /// @param sighash The hash that was used to produce the ECDSA signature
91
+ /// that is the subject of the fraud claim. This hash is constructed
92
+ /// by applying double SHA-256 over a serialized subset of the
93
+ /// transaction. The exact subset used as hash preimage depends on
94
+ /// the transaction input the signature is produced for. See BIP-143
95
+ /// for reference
96
+ /// @param signature Bitcoin signature in the R/S/V format
97
+ /// @dev Requirements:
98
+ /// - Wallet behind `walletPublicKey` must be in `Live` or `MovingFunds`
99
+ /// state
100
+ /// - The challenger must send appropriate amount of ETH used as
101
+ /// fraud challenge deposit
102
+ /// - The signature (represented by r, s and v) must be generated by
103
+ /// the wallet behind `walletPublicKey` during signing of `sighash`
104
+ /// - Wallet can be challenged for the given signature only once
105
+ function submitFraudChallenge(
106
+ BridgeState.Storage storage self,
107
+ bytes calldata walletPublicKey,
108
+ bytes32 sighash,
109
+ BitcoinTx.RSVSignature calldata signature
110
+ ) external {
111
+ require(
112
+ msg.value >= self.fraudChallengeDepositAmount,
113
+ "The amount of ETH deposited is too low"
114
+ );
115
+
116
+ require(
117
+ CheckBitcoinSigs.checkSig(
118
+ walletPublicKey,
119
+ sighash,
120
+ signature.v,
121
+ signature.r,
122
+ signature.s
123
+ ),
124
+ "Signature verification failure"
125
+ );
126
+
127
+ bytes memory compressedWalletPublicKey = EcdsaLib.compressPublicKey(
128
+ walletPublicKey.slice32(0),
129
+ walletPublicKey.slice32(32)
130
+ );
131
+ bytes20 walletPubKeyHash = compressedWalletPublicKey.hash160View();
132
+
133
+ Wallets.Wallet storage wallet = self.registeredWallets[
134
+ walletPubKeyHash
135
+ ];
136
+
137
+ require(
138
+ wallet.state == Wallets.WalletState.Live ||
139
+ wallet.state == Wallets.WalletState.MovingFunds,
140
+ "Wallet is neither in Live nor MovingFunds state"
141
+ );
142
+
143
+ uint256 challengeKey = uint256(
144
+ keccak256(abi.encodePacked(walletPublicKey, sighash))
145
+ );
146
+
147
+ FraudChallenge storage challenge = self.fraudChallenges[challengeKey];
148
+ require(challenge.reportedAt == 0, "Fraud challenge already exists");
149
+
150
+ challenge.challenger = msg.sender;
151
+ challenge.depositAmount = msg.value;
152
+ /* solhint-disable-next-line not-rely-on-time */
153
+ challenge.reportedAt = uint32(block.timestamp);
154
+ challenge.resolved = false;
155
+
156
+ emit FraudChallengeSubmitted(
157
+ walletPubKeyHash,
158
+ sighash,
159
+ signature.v,
160
+ signature.r,
161
+ signature.s
162
+ );
163
+ }
164
+
165
+ /// @notice Allows to defeat a pending fraud challenge against a wallet if
166
+ /// the transaction that spends the UTXO follows the protocol rules.
167
+ /// In order to defeat the challenge the same `walletPublicKey` and
168
+ /// signature (represented by `r`, `s` and `v`) must be provided as
169
+ /// were used to calculate the sighash during input signing.
170
+ /// The fraud challenge defeat attempt will only succeed if the
171
+ /// inputs in the preimage are considered honestly spent by the
172
+ /// wallet. Therefore the transaction spending the UTXO must be
173
+ /// proven in the Bridge before a challenge defeat is called.
174
+ /// If successfully defeated, the fraud challenge is marked as
175
+ /// resolved and the amount of ether deposited by the challenger is
176
+ /// sent to the treasury.
177
+ /// @param walletPublicKey The public key of the wallet in the uncompressed
178
+ /// and unprefixed format (64 bytes)
179
+ /// @param preimage The preimage which produces sighash used to generate the
180
+ /// ECDSA signature that is the subject of the fraud claim. It is a
181
+ /// serialized subset of the transaction. The exact subset used as
182
+ /// the preimage depends on the transaction input the signature is
183
+ /// produced for. See BIP-143 for reference
184
+ /// @param witness Flag indicating whether the preimage was produced for a
185
+ /// witness input. True for witness, false for non-witness input.
186
+ /// @dev Requirements:
187
+ /// - `walletPublicKey` and `sighash` calculated as `hash256(preimage)`
188
+ /// must identify an open fraud challenge
189
+ /// - the preimage must be a valid preimage of a transaction generated
190
+ /// according to the protocol rules and already proved in the Bridge
191
+ /// - before a defeat attempt is made the transaction that spends the
192
+ /// given UTXO must be proven in the Bridge
193
+ function defeatFraudChallenge(
194
+ BridgeState.Storage storage self,
195
+ bytes calldata walletPublicKey,
196
+ bytes calldata preimage,
197
+ bool witness
198
+ ) external {
199
+ bytes32 sighash = preimage.hash256();
200
+
201
+ uint256 challengeKey = uint256(
202
+ keccak256(abi.encodePacked(walletPublicKey, sighash))
203
+ );
204
+
205
+ FraudChallenge storage challenge = self.fraudChallenges[challengeKey];
206
+
207
+ require(challenge.reportedAt > 0, "Fraud challenge does not exist");
208
+ require(
209
+ !challenge.resolved,
210
+ "Fraud challenge has already been resolved"
211
+ );
212
+
213
+ // Ensure SIGHASH_ALL type was used during signing, which is represented
214
+ // by type value `1`.
215
+ require(extractSighashType(preimage) == 1, "Wrong sighash type");
216
+
217
+ uint256 utxoKey = witness
218
+ ? extractUtxoKeyFromWitnessPreimage(preimage)
219
+ : extractUtxoKeyFromNonWitnessPreimage(preimage);
220
+
221
+ // Check that the UTXO key identifies a correctly spent UTXO.
222
+ require(
223
+ self.deposits[utxoKey].sweptAt > 0 || self.spentMainUTXOs[utxoKey],
224
+ "Spent UTXO not found among correctly spent UTXOs"
225
+ );
226
+
227
+ // Mark the challenge as resolved as it was successfully defeated
228
+ challenge.resolved = true;
229
+
230
+ // Send the ether deposited by the challenger to the treasury
231
+ /* solhint-disable avoid-low-level-calls */
232
+ // slither-disable-next-line low-level-calls
233
+ self.treasury.call{gas: 100000, value: challenge.depositAmount}("");
234
+ /* solhint-enable avoid-low-level-calls */
235
+
236
+ bytes memory compressedWalletPublicKey = EcdsaLib.compressPublicKey(
237
+ walletPublicKey.slice32(0),
238
+ walletPublicKey.slice32(32)
239
+ );
240
+ bytes20 walletPubKeyHash = compressedWalletPublicKey.hash160View();
241
+
242
+ emit FraudChallengeDefeated(walletPubKeyHash, sighash);
243
+ }
244
+
245
+ /// @notice Notifies about defeat timeout for the given fraud challenge.
246
+ /// Can be called only if there was a fraud challenge identified by
247
+ /// the provided `walletPublicKey` and `sighash` and it was not
248
+ /// defeated on time. The amount of time that needs to pass after a
249
+ /// fraud challenge is reported is indicated by the
250
+ /// `challengeDefeatTimeout`. After a successful fraud challenge
251
+ /// defeat timeout notification the fraud challenge is marked as
252
+ /// resolved, the stake of each operator is slashed, the ether
253
+ /// deposited is returned to the challenger and the challenger is
254
+ /// rewarded.
255
+ /// @param walletPublicKey The public key of the wallet in the uncompressed
256
+ /// and unprefixed format (64 bytes)
257
+ /// @param sighash The hash that was used to produce the ECDSA signature
258
+ /// that is the subject of the fraud claim. This hash is constructed
259
+ /// by applying double SHA-256 over a serialized subset of the
260
+ /// transaction. The exact subset used as hash preimage depends on
261
+ /// the transaction input the signature is produced for. See BIP-143
262
+ /// for reference
263
+ /// @dev Requirements:
264
+ /// - `walletPublicKey` and `sighash` must identify an open fraud
265
+ /// challenge
266
+ /// - the amount of time indicated by `challengeDefeatTimeout` must pass
267
+ /// after the challenge was reported
268
+ function notifyFraudChallengeDefeatTimeout(
269
+ BridgeState.Storage storage self,
270
+ bytes calldata walletPublicKey,
271
+ bytes32 sighash
272
+ ) external {
273
+ uint256 challengeKey = uint256(
274
+ keccak256(abi.encodePacked(walletPublicKey, sighash))
275
+ );
276
+
277
+ FraudChallenge storage challenge = self.fraudChallenges[challengeKey];
278
+ require(challenge.reportedAt > 0, "Fraud challenge does not exist");
279
+ require(
280
+ !challenge.resolved,
281
+ "Fraud challenge has already been resolved"
282
+ );
283
+ require(
284
+ /* solhint-disable-next-line not-rely-on-time */
285
+ block.timestamp >=
286
+ challenge.reportedAt + self.fraudChallengeDefeatTimeout,
287
+ "Fraud challenge defeat period did not time out yet"
288
+ );
289
+
290
+ // TODO: Call notifyFraud from Wallets library
291
+ // TODO: Reward the challenger
292
+
293
+ challenge.resolved = true;
294
+
295
+ // Return the ether deposited by the challenger
296
+ /* solhint-disable avoid-low-level-calls */
297
+ // slither-disable-next-line low-level-calls
298
+ challenge.challenger.call{gas: 100000, value: challenge.depositAmount}(
299
+ ""
300
+ );
301
+ /* solhint-enable avoid-low-level-calls */
302
+
303
+ bytes memory compressedWalletPublicKey = EcdsaLib.compressPublicKey(
304
+ walletPublicKey.slice32(0),
305
+ walletPublicKey.slice32(32)
306
+ );
307
+ bytes20 walletPubKeyHash = compressedWalletPublicKey.hash160View();
308
+
309
+ emit FraudChallengeDefeatTimedOut(walletPubKeyHash, sighash);
310
+ }
311
+
312
+ /// @notice Extracts the UTXO keys from the given preimage used during
313
+ /// signing of a witness input.
314
+ /// @param preimage The preimage which produces sighash used to generate the
315
+ /// ECDSA signature that is the subject of the fraud claim. It is a
316
+ /// serialized subset of the transaction. The exact subset used as
317
+ /// the preimage depends on the transaction input the signature is
318
+ /// produced for. See BIP-143 for reference
319
+ /// @return utxoKey UTXO key that identifies spent input.
320
+ function extractUtxoKeyFromWitnessPreimage(bytes calldata preimage)
321
+ internal
322
+ pure
323
+ returns (uint256 utxoKey)
324
+ {
325
+ // The expected structure of the preimage created during signing of a
326
+ // witness input:
327
+ // - transaction version (4 bytes)
328
+ // - hash of previous outpoints of all inputs (32 bytes)
329
+ // - hash of sequences of all inputs (32 bytes)
330
+ // - outpoint (hash + index) of the input being signed (36 bytes)
331
+ // - the unlocking script of the input (variable length)
332
+ // - value of the outpoint (8 bytes)
333
+ // - sequence of the input being signed (4 bytes)
334
+ // - hash of all outputs (32 bytes)
335
+ // - transaction locktime (4 bytes)
336
+ // - sighash type (4 bytes)
337
+
338
+ // See Bitcoin's BIP-143 for reference:
339
+ // https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki.
340
+
341
+ // The outpoint (hash and index) is located at the constant offset of
342
+ // 68 (4 + 32 + 32).
343
+ bytes32 outpointTxHash = preimage.extractInputTxIdLeAt(68);
344
+ uint32 outpointIndex = BTCUtils.reverseUint32(
345
+ uint32(preimage.extractTxIndexLeAt(68))
346
+ );
347
+
348
+ return
349
+ uint256(keccak256(abi.encodePacked(outpointTxHash, outpointIndex)));
350
+ }
351
+
352
+ /// @notice Extracts the UTXO key from the given preimage used during
353
+ /// signing of a non-witness input.
354
+ /// @param preimage The preimage which produces sighash used to generate the
355
+ /// ECDSA signature that is the subject of the fraud claim. It is a
356
+ /// serialized subset of the transaction. The exact subset used as
357
+ /// the preimage depends on the transaction input the signature is
358
+ /// produced for. See BIP-143 for reference
359
+ /// @return utxoKey UTXO key that identifies spent input.
360
+ function extractUtxoKeyFromNonWitnessPreimage(bytes calldata preimage)
361
+ internal
362
+ pure
363
+ returns (uint256 utxoKey)
364
+ {
365
+ // The expected structure of the preimage created during signing of a
366
+ // non-witness input:
367
+ // - transaction version (4 bytes)
368
+ // - number of inputs written as compactSize uint (1 byte, 3 bytes,
369
+ // 5 bytes or 9 bytes)
370
+ // - for each input
371
+ // - outpoint (hash and index) (36 bytes)
372
+ // - unlocking script for the input being signed (variable length)
373
+ // or `00` for all other inputs (1 byte)
374
+ // - input sequence (4 bytes)
375
+ // - number of outputs written as compactSize uint (1 byte, 3 bytes,
376
+ // 5 bytes or 9 bytes)
377
+ // - outputs (variable length)
378
+ // - transaction locktime (4 bytes)
379
+ // - sighash type (4 bytes)
380
+
381
+ // See example for reference:
382
+ // https://en.bitcoin.it/wiki/OP_CHECKSIG#Code_samples_and_raw_dumps.
383
+
384
+ // The input data begins at the constant offset of 4 (the first 4 bytes
385
+ // are for the transaction version).
386
+ (uint256 inputsCompactSizeUintLength, uint256 inputsCount) = preimage
387
+ .parseVarIntAt(4);
388
+
389
+ // To determine the first input starting index, we must jump 4 bytes
390
+ // over the transaction version length and the compactSize uint which
391
+ // prepends the input vector. One byte must be added because
392
+ // `BtcUtils.parseVarInt` does not include compactSize uint tag in the
393
+ // returned length.
394
+ //
395
+ // For >= 0 && <= 252, `BTCUtils.determineVarIntDataLengthAt`
396
+ // returns `0`, so we jump over one byte of compactSize uint.
397
+ //
398
+ // For >= 253 && <= 0xffff there is `0xfd` tag,
399
+ // `BTCUtils.determineVarIntDataLengthAt` returns `2` (no
400
+ // tag byte included) so we need to jump over 1+2 bytes of
401
+ // compactSize uint.
402
+ //
403
+ // Please refer `BTCUtils` library and compactSize uint
404
+ // docs in `BitcoinTx` library for more details.
405
+ uint256 inputStartingIndex = 4 + 1 + inputsCompactSizeUintLength;
406
+
407
+ for (uint256 i = 0; i < inputsCount; i++) {
408
+ uint256 inputLength = preimage.determineInputLengthAt(
409
+ inputStartingIndex
410
+ );
411
+
412
+ (, uint256 scriptSigLength) = preimage.extractScriptSigLenAt(
413
+ inputStartingIndex
414
+ );
415
+
416
+ if (scriptSigLength > 0) {
417
+ // The input this preimage was generated for was found.
418
+ // All the other inputs in the preimage are marked with a null
419
+ // scriptSig ("00") which has length of 1.
420
+ bytes32 outpointTxHash = preimage.extractInputTxIdLeAt(
421
+ inputStartingIndex
422
+ );
423
+ uint32 outpointIndex = BTCUtils.reverseUint32(
424
+ uint32(preimage.extractTxIndexLeAt(inputStartingIndex))
425
+ );
426
+
427
+ utxoKey = uint256(
428
+ keccak256(abi.encodePacked(outpointTxHash, outpointIndex))
429
+ );
430
+
431
+ break;
432
+ }
433
+
434
+ inputStartingIndex += inputLength;
435
+ }
436
+
437
+ return utxoKey;
438
+ }
439
+
440
+ /// @notice Extracts the sighash type from the given preimage.
441
+ /// @param preimage Serialized subset of the transaction. See BIP-143 for
442
+ /// reference
443
+ /// @dev Sighash type is stored as the last 4 bytes in the preimage (little
444
+ /// endian).
445
+ /// @return sighashType Sighash type as a 32-bit integer.
446
+ function extractSighashType(bytes calldata preimage)
447
+ internal
448
+ pure
449
+ returns (uint32 sighashType)
450
+ {
451
+ bytes4 sighashTypeBytes = preimage.slice4(preimage.length - 4);
452
+ uint32 sighashTypeLE = uint32(sighashTypeBytes);
453
+ return sighashTypeLE.reverseUint32();
454
+ }
455
+ }
@@ -0,0 +1,28 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ // ██████████████ ▐████▌ ██████████████
4
+ // ██████████████ ▐████▌ ██████████████
5
+ // ▐████▌ ▐████▌
6
+ // ▐████▌ ▐████▌
7
+ // ██████████████ ▐████▌ ██████████████
8
+ // ██████████████ ▐████▌ ██████████████
9
+ // ▐████▌ ▐████▌
10
+ // ▐████▌ ▐████▌
11
+ // ▐████▌ ▐████▌
12
+ // ▐████▌ ▐████▌
13
+ // ▐████▌ ▐████▌
14
+ // ▐████▌ ▐████▌
15
+
16
+ pragma solidity ^0.8.9;
17
+
18
+ /// @title Interface for the Bitcoin relay
19
+ /// @notice Contains only the methods needed by tBTC v2. The Bitcoin relay
20
+ /// provides the difficulty of the previous and current epoch. One
21
+ /// difficulty epoch spans 2016 blocks.
22
+ interface IRelay {
23
+ /// @notice Returns the difficulty of the current epoch.
24
+ function getCurrentEpochDifficulty() external view returns (uint256);
25
+
26
+ /// @notice Returns the difficulty of the previous epoch.
27
+ function getPrevEpochDifficulty() external view returns (uint256);
28
+ }