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

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/f1a50b67569d88ee54efa3e22c6b484e.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 +1743 -64
  14. package/build/contracts/bridge/BridgeState.sol/BridgeState.dbg.json +4 -0
  15. package/build/contracts/bridge/BridgeState.sol/BridgeState.json +10 -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/Frauds.sol/Frauds.dbg.json +4 -0
  21. package/build/contracts/bridge/Frauds.sol/Frauds.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 +48 -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 +110 -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 +138 -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 +980 -123
  46. package/contracts/bridge/BridgeState.sol +172 -0
  47. package/contracts/bridge/Deposit.sol +247 -0
  48. package/contracts/bridge/EcdsaLib.sol +30 -0
  49. package/contracts/bridge/Frauds.sol +529 -0
  50. package/contracts/bridge/IRelay.sol +28 -0
  51. package/contracts/bridge/MovingFunds.sol +280 -0
  52. package/contracts/bridge/Redeem.sol +849 -0
  53. package/contracts/bridge/Sweep.sol +510 -0
  54. package/contracts/bridge/VendingMachine.sol +1 -1
  55. package/contracts/bridge/Wallets.sol +591 -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,280 @@
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 {BTCUtils} from "@keep-network/bitcoin-spv-sol/contracts/BTCUtils.sol";
19
+ import {BytesLib} from "@keep-network/bitcoin-spv-sol/contracts/BytesLib.sol";
20
+
21
+ import "./BitcoinTx.sol";
22
+ import "./BridgeState.sol";
23
+ import "./Redeem.sol";
24
+
25
+ library MovingFunds {
26
+ using BridgeState for BridgeState.Storage;
27
+ using Wallets for Wallets.Data;
28
+
29
+ using BTCUtils for bytes;
30
+ using BytesLib for bytes;
31
+
32
+ event MovingFundsCompleted(
33
+ bytes20 walletPubKeyHash,
34
+ bytes32 movingFundsTxHash
35
+ );
36
+
37
+ /// @notice Used by the wallet to prove the BTC moving funds transaction
38
+ /// and to make the necessary state changes. Moving funds is only
39
+ /// accepted if it satisfies SPV proof.
40
+ ///
41
+ /// The function validates the moving funds transaction structure
42
+ /// by checking if it actually spends the main UTXO of the declared
43
+ /// wallet and locks the value on the pre-committed target wallets
44
+ /// using a reasonable transaction fee. If all preconditions are
45
+ /// met, this functions closes the source wallet.
46
+ ///
47
+ /// It is possible to prove the given moving funds transaction only
48
+ /// one time.
49
+ /// @param movingFundsTx Bitcoin moving funds transaction data
50
+ /// @param movingFundsProof Bitcoin moving funds proof data
51
+ /// @param mainUtxo Data of the wallet's main UTXO, as currently known on
52
+ /// the Ethereum chain
53
+ /// @param walletPubKeyHash 20-byte public key hash (computed using Bitcoin
54
+ /// HASH160 over the compressed ECDSA public key) of the wallet
55
+ /// which performed the moving funds transaction
56
+ /// @dev Requirements:
57
+ /// - `movingFundsTx` components must match the expected structure. See
58
+ /// `BitcoinTx.Info` docs for reference. Their values must exactly
59
+ /// correspond to appropriate Bitcoin transaction fields to produce
60
+ /// a provable transaction hash.
61
+ /// - The `movingFundsTx` should represent a Bitcoin transaction with
62
+ /// exactly 1 input that refers to the wallet's main UTXO. That
63
+ /// transaction should have 1..n outputs corresponding to the
64
+ /// pre-committed target wallets. Outputs must be ordered in the
65
+ /// same way as their corresponding target wallets are ordered
66
+ /// within the target wallets commitment.
67
+ /// - `movingFundsProof` components must match the expected structure.
68
+ /// See `BitcoinTx.Proof` docs for reference. The `bitcoinHeaders`
69
+ /// field must contain a valid number of block headers, not less
70
+ /// than the `txProofDifficultyFactor` contract constant.
71
+ /// - `mainUtxo` components must point to the recent main UTXO
72
+ /// of the given wallet, as currently known on the Ethereum chain.
73
+ /// Additionally, the recent main UTXO on Ethereum must be set.
74
+ /// - `walletPubKeyHash` must be connected with the main UTXO used
75
+ /// as transaction single input.
76
+ /// - The wallet that `walletPubKeyHash` points to must be in the
77
+ /// MovingFunds state.
78
+ /// - The target wallets commitment must be submitted by the wallet
79
+ /// that `walletPubKeyHash` points to.
80
+ /// - The total Bitcoin transaction fee must be lesser or equal
81
+ /// to `movingFundsTxMaxTotalFee` governable parameter.
82
+ function submitMovingFundsProof(
83
+ BridgeState.Storage storage self,
84
+ Wallets.Data storage wallets,
85
+ BitcoinTx.Info calldata movingFundsTx,
86
+ BitcoinTx.Proof calldata movingFundsProof,
87
+ BitcoinTx.UTXO calldata mainUtxo,
88
+ bytes20 walletPubKeyHash
89
+ ) external {
90
+ // The actual transaction proof is performed here. After that point, we
91
+ // can assume the transaction happened on Bitcoin chain and has
92
+ // a sufficient number of confirmations as determined by
93
+ // `txProofDifficultyFactor` constant.
94
+ bytes32 movingFundsTxHash = BitcoinTx.validateProof(
95
+ movingFundsTx,
96
+ movingFundsProof,
97
+ self.proofDifficultyContext()
98
+ );
99
+
100
+ // Process the moving funds transaction input. Specifically, check if
101
+ // it refers to the expected wallet's main UTXO.
102
+ OutboundTx.processWalletOutboundTxInput(
103
+ self,
104
+ wallets,
105
+ movingFundsTx.inputVector,
106
+ mainUtxo,
107
+ walletPubKeyHash
108
+ );
109
+
110
+ (
111
+ bytes32 targetWalletsHash,
112
+ uint256 outputsTotalValue
113
+ ) = processMovingFundsTxOutputs(movingFundsTx.outputVector);
114
+
115
+ require(
116
+ mainUtxo.txOutputValue - outputsTotalValue <=
117
+ self.movingFundsTxMaxTotalFee,
118
+ "Transaction fee is too high"
119
+ );
120
+
121
+ wallets.notifyFundsMoved(walletPubKeyHash, targetWalletsHash);
122
+
123
+ emit MovingFundsCompleted(walletPubKeyHash, movingFundsTxHash);
124
+ }
125
+
126
+ /// @notice Processes the moving funds Bitcoin transaction output vector
127
+ /// and extracts information required for further processing.
128
+ /// @param movingFundsTxOutputVector Bitcoin moving funds transaction output
129
+ /// vector. This function assumes vector's structure is valid so it
130
+ /// must be validated using e.g. `BTCUtils.validateVout` function
131
+ /// before it is passed here
132
+ /// @return targetWalletsHash keccak256 hash over the list of actual
133
+ /// target wallets used in the transaction.
134
+ /// @return outputsTotalValue Sum of all outputs values.
135
+ /// @dev Requirements:
136
+ /// - The `movingFundsTxOutputVector` must be parseable, i.e. must
137
+ /// be validated by the caller as stated in their parameter doc.
138
+ /// - Each output must refer to a 20-byte public key hash.
139
+ /// - The total outputs value must be evenly divided over all outputs.
140
+ function processMovingFundsTxOutputs(bytes memory movingFundsTxOutputVector)
141
+ internal
142
+ view
143
+ returns (bytes32 targetWalletsHash, uint256 outputsTotalValue)
144
+ {
145
+ // Determining the total number of Bitcoin transaction outputs in
146
+ // the same way as for number of inputs. See `BitcoinTx.outputVector`
147
+ // docs for more details.
148
+ (
149
+ uint256 outputsCompactSizeUintLength,
150
+ uint256 outputsCount
151
+ ) = movingFundsTxOutputVector.parseVarInt();
152
+
153
+ // To determine the first output starting index, we must jump over
154
+ // the compactSize uint which prepends the output vector. One byte
155
+ // must be added because `BtcUtils.parseVarInt` does not include
156
+ // compactSize uint tag in the returned length.
157
+ //
158
+ // For >= 0 && <= 252, `BTCUtils.determineVarIntDataLengthAt`
159
+ // returns `0`, so we jump over one byte of compactSize uint.
160
+ //
161
+ // For >= 253 && <= 0xffff there is `0xfd` tag,
162
+ // `BTCUtils.determineVarIntDataLengthAt` returns `2` (no
163
+ // tag byte included) so we need to jump over 1+2 bytes of
164
+ // compactSize uint.
165
+ //
166
+ // Please refer `BTCUtils` library and compactSize uint
167
+ // docs in `BitcoinTx` library for more details.
168
+ uint256 outputStartingIndex = 1 + outputsCompactSizeUintLength;
169
+
170
+ bytes20[] memory targetWallets = new bytes20[](outputsCount);
171
+ uint64[] memory outputsValues = new uint64[](outputsCount);
172
+
173
+ // Outputs processing loop.
174
+ for (uint256 i = 0; i < outputsCount; i++) {
175
+ uint256 outputLength = movingFundsTxOutputVector
176
+ .determineOutputLengthAt(outputStartingIndex);
177
+
178
+ bytes memory output = movingFundsTxOutputVector.slice(
179
+ outputStartingIndex,
180
+ outputLength
181
+ );
182
+
183
+ // Extract the output script payload.
184
+ bytes memory targetWalletPubKeyHashBytes = output.extractHash();
185
+ // Output script payload must refer to a known wallet public key
186
+ // hash which is always 20-byte.
187
+ require(
188
+ targetWalletPubKeyHashBytes.length == 20,
189
+ "Target wallet public key hash must have 20 bytes"
190
+ );
191
+
192
+ bytes20 targetWalletPubKeyHash = targetWalletPubKeyHashBytes
193
+ .slice20(0);
194
+
195
+ // The next step is making sure that the 20-byte public key hash
196
+ // is actually used in the right context of a P2PKH or P2WPKH
197
+ // output. To do so, we must extract the full script from the output
198
+ // and compare with the expected P2PKH and P2WPKH scripts
199
+ // referring to that 20-byte public key hash. The output consists
200
+ // of an 8-byte value and a variable length script. To extract the
201
+ // script we slice the output starting from 9th byte until the end.
202
+ bytes32 outputScriptKeccak = keccak256(
203
+ output.slice(8, output.length - 8)
204
+ );
205
+ // Build the expected P2PKH script which has the following byte
206
+ // format: <0x1976a914> <20-byte PKH> <0x88ac>. According to
207
+ // https://en.bitcoin.it/wiki/Script#Opcodes this translates to:
208
+ // - 0x19: Byte length of the entire script
209
+ // - 0x76: OP_DUP
210
+ // - 0xa9: OP_HASH160
211
+ // - 0x14: Byte length of the public key hash
212
+ // - 0x88: OP_EQUALVERIFY
213
+ // - 0xac: OP_CHECKSIG
214
+ // which matches the P2PKH structure as per:
215
+ // https://en.bitcoin.it/wiki/Transaction#Pay-to-PubkeyHash
216
+ bytes32 targetWalletP2PKHScriptKeccak = keccak256(
217
+ abi.encodePacked(
218
+ hex"1976a914",
219
+ targetWalletPubKeyHash,
220
+ hex"88ac"
221
+ )
222
+ );
223
+ // Build the expected P2WPKH script which has the following format:
224
+ // <0x160014> <20-byte PKH>. According to
225
+ // https://en.bitcoin.it/wiki/Script#Opcodes this translates to:
226
+ // - 0x16: Byte length of the entire script
227
+ // - 0x00: OP_0
228
+ // - 0x14: Byte length of the public key hash
229
+ // which matches the P2WPKH structure as per:
230
+ // https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#P2WPKH
231
+ bytes32 targetWalletP2WPKHScriptKeccak = keccak256(
232
+ abi.encodePacked(hex"160014", targetWalletPubKeyHash)
233
+ );
234
+ // Make sure the actual output script matches either the P2PKH
235
+ // or P2WPKH format.
236
+ require(
237
+ outputScriptKeccak == targetWalletP2PKHScriptKeccak ||
238
+ outputScriptKeccak == targetWalletP2WPKHScriptKeccak,
239
+ "Output must be P2PKH or P2WPKH"
240
+ );
241
+
242
+ // Add the wallet public key hash to the list that will be used
243
+ // to build the result list hash. There is no need to check if
244
+ // given output is a change here because the actual target wallet
245
+ // list must be exactly the same as the pre-committed target wallet
246
+ // list which is guaranteed to be valid.
247
+ targetWallets[i] = targetWalletPubKeyHash;
248
+
249
+ // Extract the value from given output.
250
+ outputsValues[i] = output.extractValue();
251
+ outputsTotalValue += outputsValues[i];
252
+
253
+ // Make the `outputStartingIndex` pointing to the next output by
254
+ // increasing it by current output's length.
255
+ outputStartingIndex += outputLength;
256
+ }
257
+
258
+ // Compute the indivisible remainder that remains after dividing the
259
+ // outputs total value over all outputs evenly.
260
+ uint256 outputsTotalValueRemainder = outputsTotalValue % outputsCount;
261
+ // Compute the minimum allowed output value by dividing the outputs
262
+ // total value (reduced by the remainder) by the number of outputs.
263
+ uint256 minOutputValue = (outputsTotalValue -
264
+ outputsTotalValueRemainder) / outputsCount;
265
+ // Maximum possible value is the minimum value with the remainder included.
266
+ uint256 maxOutputValue = minOutputValue + outputsTotalValueRemainder;
267
+
268
+ for (uint256 i = 0; i < outputsCount; i++) {
269
+ require(
270
+ minOutputValue <= outputsValues[i] &&
271
+ outputsValues[i] <= maxOutputValue,
272
+ "Transaction amount is not distributed evenly"
273
+ );
274
+ }
275
+
276
+ targetWalletsHash = keccak256(abi.encodePacked(targetWallets));
277
+
278
+ return (targetWalletsHash, outputsTotalValue);
279
+ }
280
+ }