@keep-network/tbtc-v2 0.1.1-dev.97 → 0.1.1-dev.98

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 (70) hide show
  1. package/artifacts/Bank.json +8 -8
  2. package/artifacts/Bridge.json +25 -25
  3. package/artifacts/Deposit.json +9 -9
  4. package/artifacts/DepositSweep.json +9 -9
  5. package/artifacts/EcdsaDkgValidator.json +1 -1
  6. package/artifacts/EcdsaInactivity.json +1 -1
  7. package/artifacts/EcdsaSortitionPool.json +2 -2
  8. package/artifacts/Fraud.json +9 -9
  9. package/artifacts/KeepRegistry.json +1 -1
  10. package/artifacts/KeepStake.json +2 -2
  11. package/artifacts/KeepToken.json +2 -2
  12. package/artifacts/KeepTokenStaking.json +1 -1
  13. package/artifacts/MovingFunds.json +9 -9
  14. package/artifacts/NuCypherStakingEscrow.json +1 -1
  15. package/artifacts/NuCypherToken.json +2 -2
  16. package/artifacts/RandomBeaconStub.json +1 -1
  17. package/artifacts/Redemption.json +9 -9
  18. package/artifacts/ReimbursementPool.json +2 -2
  19. package/artifacts/Relay.json +9 -9
  20. package/artifacts/T.json +2 -2
  21. package/artifacts/TBTC.json +10 -10
  22. package/artifacts/TBTCToken.json +10 -10
  23. package/artifacts/TBTCVault.json +15 -15
  24. package/artifacts/TokenStaking.json +1 -1
  25. package/artifacts/TokenholderGovernor.json +9 -9
  26. package/artifacts/TokenholderTimelock.json +8 -8
  27. package/artifacts/VendingMachine.json +11 -11
  28. package/artifacts/VendingMachineKeep.json +1 -1
  29. package/artifacts/VendingMachineNuCypher.json +1 -1
  30. package/artifacts/WalletRegistry.json +5 -5
  31. package/artifacts/WalletRegistryGovernance.json +2 -2
  32. package/artifacts/Wallets.json +7 -7
  33. package/artifacts/solcInputs/{5e62cff1ead0900b07facca4b559e818.json → becdd5668a2170e95004d124119e4fcb.json} +6 -6
  34. package/build/contracts/GovernanceUtils.sol/GovernanceUtils.dbg.json +1 -1
  35. package/build/contracts/bank/Bank.sol/Bank.dbg.json +1 -1
  36. package/build/contracts/bank/IReceiveBalanceApproval.sol/IReceiveBalanceApproval.dbg.json +1 -1
  37. package/build/contracts/bridge/BitcoinTx.sol/BitcoinTx.dbg.json +1 -1
  38. package/build/contracts/bridge/BitcoinTx.sol/BitcoinTx.json +2 -2
  39. package/build/contracts/bridge/Bridge.sol/Bridge.dbg.json +1 -1
  40. package/build/contracts/bridge/Bridge.sol/Bridge.json +68 -68
  41. package/build/contracts/bridge/BridgeState.sol/BridgeState.dbg.json +1 -1
  42. package/build/contracts/bridge/BridgeState.sol/BridgeState.json +2 -2
  43. package/build/contracts/bridge/Deposit.sol/Deposit.dbg.json +1 -1
  44. package/build/contracts/bridge/Deposit.sol/Deposit.json +2 -2
  45. package/build/contracts/bridge/DepositSweep.sol/DepositSweep.dbg.json +1 -1
  46. package/build/contracts/bridge/DepositSweep.sol/DepositSweep.json +2 -2
  47. package/build/contracts/bridge/EcdsaLib.sol/EcdsaLib.dbg.json +1 -1
  48. package/build/contracts/bridge/Fraud.sol/Fraud.dbg.json +1 -1
  49. package/build/contracts/bridge/Fraud.sol/Fraud.json +2 -2
  50. package/build/contracts/bridge/Heartbeat.sol/Heartbeat.dbg.json +1 -1
  51. package/build/contracts/bridge/IRelay.sol/IRelay.dbg.json +1 -1
  52. package/build/contracts/bridge/MovingFunds.sol/MovingFunds.dbg.json +1 -1
  53. package/build/contracts/bridge/MovingFunds.sol/MovingFunds.json +2 -2
  54. package/build/contracts/bridge/Redemption.sol/OutboundTx.dbg.json +1 -1
  55. package/build/contracts/bridge/Redemption.sol/OutboundTx.json +2 -2
  56. package/build/contracts/bridge/Redemption.sol/Redemption.dbg.json +1 -1
  57. package/build/contracts/bridge/Redemption.sol/Redemption.json +2 -2
  58. package/build/contracts/bridge/VendingMachine.sol/VendingMachine.dbg.json +1 -1
  59. package/build/contracts/bridge/Wallets.sol/Wallets.dbg.json +1 -1
  60. package/build/contracts/bridge/Wallets.sol/Wallets.json +2 -2
  61. package/build/contracts/token/TBTC.sol/TBTC.dbg.json +1 -1
  62. package/build/contracts/vault/DonationVault.sol/DonationVault.dbg.json +1 -1
  63. package/build/contracts/vault/IVault.sol/IVault.dbg.json +1 -1
  64. package/build/contracts/vault/TBTCVault.sol/TBTCVault.dbg.json +1 -1
  65. package/contracts/bridge/BitcoinTx.sol +72 -39
  66. package/contracts/bridge/Bridge.sol +12 -12
  67. package/contracts/bridge/BridgeState.sol +83 -75
  68. package/contracts/bridge/Redemption.sol +84 -48
  69. package/export.json +12 -12
  70. package/package.json +2 -2
@@ -239,7 +239,7 @@ contract Bridge is
239
239
  address _relay,
240
240
  address _treasury,
241
241
  address _ecdsaWalletRegistry,
242
- uint256 _txProofDifficultyFactor
242
+ uint96 _txProofDifficultyFactor
243
243
  ) external initializer {
244
244
  require(_bank != address(0), "Bank address cannot be zero");
245
245
  self.bank = Bank(_bank);
@@ -1228,9 +1228,9 @@ contract Bridge is
1228
1228
  uint64 redemptionDustThreshold,
1229
1229
  uint64 redemptionTreasuryFeeDivisor,
1230
1230
  uint64 redemptionTxMaxFee,
1231
- uint256 redemptionTimeout,
1231
+ uint64 redemptionTimeout,
1232
1232
  uint96 redemptionTimeoutSlashingAmount,
1233
- uint256 redemptionTimeoutNotifierRewardMultiplier
1233
+ uint64 redemptionTimeoutNotifierRewardMultiplier
1234
1234
  ) external onlyGovernance {
1235
1235
  self.updateRedemptionParameters(
1236
1236
  redemptionDustThreshold,
@@ -1315,7 +1315,7 @@ contract Bridge is
1315
1315
  uint64 movedFundsSweepTxMaxTotalFee,
1316
1316
  uint32 movedFundsSweepTimeout,
1317
1317
  uint96 movedFundsSweepTimeoutSlashingAmount,
1318
- uint256 movedFundsSweepTimeoutNotifierRewardMultiplier
1318
+ uint64 movedFundsSweepTimeoutNotifierRewardMultiplier
1319
1319
  ) external onlyGovernance {
1320
1320
  self.updateMovingFundsParameters(
1321
1321
  movingFundsTxMaxTotalFee,
@@ -1395,10 +1395,10 @@ contract Bridge is
1395
1395
  /// - Fraud challenge defeat timeout must be greater than 0,
1396
1396
  /// - Fraud notifier reward multiplier must be in the range [0, 100].
1397
1397
  function updateFraudParameters(
1398
- uint256 fraudChallengeDepositAmount,
1399
- uint256 fraudChallengeDefeatTimeout,
1398
+ uint96 fraudChallengeDepositAmount,
1399
+ uint32 fraudChallengeDefeatTimeout,
1400
1400
  uint96 fraudSlashingAmount,
1401
- uint256 fraudNotifierRewardMultiplier
1401
+ uint32 fraudNotifierRewardMultiplier
1402
1402
  ) external onlyGovernance {
1403
1403
  self.updateFraudParameters(
1404
1404
  fraudChallengeDepositAmount,
@@ -1607,9 +1607,9 @@ contract Bridge is
1607
1607
  uint64 redemptionDustThreshold,
1608
1608
  uint64 redemptionTreasuryFeeDivisor,
1609
1609
  uint64 redemptionTxMaxFee,
1610
- uint256 redemptionTimeout,
1610
+ uint64 redemptionTimeout,
1611
1611
  uint96 redemptionTimeoutSlashingAmount,
1612
- uint256 redemptionTimeoutNotifierRewardMultiplier
1612
+ uint64 redemptionTimeoutNotifierRewardMultiplier
1613
1613
  )
1614
1614
  {
1615
1615
  redemptionDustThreshold = self.redemptionDustThreshold;
@@ -1748,10 +1748,10 @@ contract Bridge is
1748
1748
  external
1749
1749
  view
1750
1750
  returns (
1751
- uint256 fraudChallengeDepositAmount,
1752
- uint256 fraudChallengeDefeatTimeout,
1751
+ uint96 fraudChallengeDepositAmount,
1752
+ uint32 fraudChallengeDefeatTimeout,
1753
1753
  uint96 fraudSlashingAmount,
1754
- uint256 fraudNotifierRewardMultiplier
1754
+ uint32 fraudNotifierRewardMultiplier
1755
1755
  )
1756
1756
  {
1757
1757
  fraudChallengeDepositAmount = self.fraudChallengeDepositAmount;
@@ -32,11 +32,11 @@ library BridgeState {
32
32
  Bank bank;
33
33
  // Bitcoin relay providing the current Bitcoin network difficulty.
34
34
  IRelay relay;
35
- // ECDSA Wallet Registry contract handle.
36
- EcdsaWalletRegistry ecdsaWalletRegistry;
37
35
  // The number of confirmations on the Bitcoin chain required to
38
36
  // successfully evaluate an SPV proof.
39
- uint256 txProofDifficultyFactor;
37
+ uint96 txProofDifficultyFactor;
38
+ // ECDSA Wallet Registry contract handle.
39
+ EcdsaWalletRegistry ecdsaWalletRegistry;
40
40
  // Address where the deposit and redemption treasury fees will be sent
41
41
  // to. Treasury takes part in the operators rewarding process.
42
42
  address treasury;
@@ -61,20 +61,10 @@ library BridgeState {
61
61
  //
62
62
  // This is a per-deposit input max fee for the sweep transaction.
63
63
  uint64 depositTxMaxFee;
64
- // Collection of all revealed deposits indexed by
65
- // `keccak256(fundingTxHash | fundingOutputIndex)`.
66
- // The `fundingTxHash` is `bytes32` (ordered as in Bitcoin internally)
67
- // and `fundingOutputIndex` an `uint32`. This mapping may contain valid
68
- // and invalid deposits and the wallet is responsible for validating
69
- // them before attempting to execute a sweep.
70
- mapping(uint256 => Deposit.DepositRequest) deposits;
71
- // Indicates if the vault with the given address is trusted or not.
72
- // Depositors can route their revealed deposits only to trusted vaults
73
- // and have trusted vaults notified about new deposits as soon as these
74
- // deposits get swept. Vaults not trusted by the Bridge can still be
75
- // used by Bank balance owners on their own responsibility - anyone can
76
- // approve their Bank balance to any address.
77
- mapping(address => bool) isVaultTrusted;
64
+ // Move movingFundsTxMaxTotalFee to the next storage slot for a more
65
+ // efficient variable layout
66
+ // slither-disable-next-line unused-state
67
+ bytes8 __depositAlignmentGap;
78
68
  // Maximum amount of the total BTC transaction fee that is acceptable in
79
69
  // a single moving funds transaction.
80
70
  //
@@ -129,14 +119,7 @@ library BridgeState {
129
119
  // The percentage of the notifier reward from the staking contract
130
120
  // the notifier of a moved funds sweep timeout receives. The value is
131
121
  // in the range [0, 100].
132
- uint256 movedFundsSweepTimeoutNotifierRewardMultiplier;
133
- // Collection of all moved funds sweep requests indexed by
134
- // `keccak256(movingFundsTxHash | movingFundsOutputIndex)`.
135
- // The `movingFundsTxHash` is `bytes32` (ordered as in Bitcoin
136
- // internally) and `movingFundsOutputIndex` an `uint32`. Each entry
137
- // is actually an UTXO representing the moved funds and is supposed
138
- // to be swept with the current main UTXO of the recipient wallet.
139
- mapping(uint256 => MovingFunds.MovedFundsSweepRequest) movedFundsSweepRequests;
122
+ uint64 movedFundsSweepTimeoutNotifierRewardMultiplier;
140
123
  // The minimal amount that can be requested for redemption.
141
124
  // Value of this parameter must take into account the value of
142
125
  // `redemptionTreasuryFeeDivisor` and `redemptionTxMaxFee`
@@ -162,68 +145,33 @@ library BridgeState {
162
145
  // This is a per-redemption output max fee for the redemption
163
146
  // transaction.
164
147
  uint64 redemptionTxMaxFee;
148
+ // Move redemptionTimeout to the next storage slot for a more efficient
149
+ // variable layout
150
+ // slither-disable-next-line unused-state
151
+ bytes8 __redemptionAlignmentGap;
165
152
  // Time after which the redemption request can be reported as
166
153
  // timed out. It is counted from the moment when the redemption
167
154
  // request was created via `requestRedemption` call. Reported
168
155
  // timed out requests are cancelled and locked TBTC is returned
169
156
  // to the redeemer in full amount.
170
- uint256 redemptionTimeout;
157
+ uint64 redemptionTimeout;
171
158
  // The amount of stake slashed from each member of a wallet for a
172
159
  // redemption timeout.
173
160
  uint96 redemptionTimeoutSlashingAmount;
174
161
  // The percentage of the notifier reward from the staking contract
175
162
  // the notifier of a redemption timeout receives. The value is in the
176
163
  // range [0, 100].
177
- uint256 redemptionTimeoutNotifierRewardMultiplier;
178
- // Collection of all pending redemption requests indexed by
179
- // redemption key built as
180
- // `keccak256(walletPubKeyHash | redeemerOutputScript)`.
181
- // The `walletPubKeyHash` is the 20-byte wallet's public key hash
182
- // (computed using Bitcoin HASH160 over the compressed ECDSA
183
- // public key) and `redeemerOutputScript` is a Bitcoin script
184
- // (P2PKH, P2WPKH, P2SH or P2WSH) that will be used to lock
185
- // redeemed BTC as requested by the redeemer. Requests are added
186
- // to this mapping by the `requestRedemption` method (duplicates
187
- // not allowed) and are removed by one of the following methods:
188
- // - `submitRedemptionProof` in case the request was handled
189
- // successfully,
190
- // - `notifyRedemptionTimeout` in case the request was reported
191
- // to be timed out.
192
- mapping(uint256 => Redemption.RedemptionRequest) pendingRedemptions;
193
- // Collection of all timed out redemptions requests indexed by
194
- // redemption key built as
195
- // `keccak256(walletPubKeyHash | redeemerOutputScript)`. The
196
- // `walletPubKeyHash` is the 20-byte wallet's public key hash
197
- // (computed using Bitcoin HASH160 over the compressed ECDSA
198
- // public key) and `redeemerOutputScript` is the Bitcoin script
199
- // (P2PKH, P2WPKH, P2SH or P2WSH) that is involved in the timed
200
- // out request. Timed out requests are stored in this mapping to
201
- // avoid slashing the wallets multiple times for the same timeout.
202
- // Only one method can add to this mapping:
203
- // - `notifyRedemptionTimeout` which puts the redemption key to this
204
- // mapping basing on a timed out request stored previously in
205
- // `pendingRedemptions` mapping.
206
- mapping(uint256 => Redemption.RedemptionRequest) timedOutRedemptions;
164
+ uint64 redemptionTimeoutNotifierRewardMultiplier;
207
165
  // The amount of ETH in wei the party challenging the wallet for fraud
208
166
  // needs to deposit.
209
- uint256 fraudChallengeDepositAmount;
167
+ uint96 fraudChallengeDepositAmount;
210
168
  // The amount of time the wallet has to defeat a fraud challenge.
211
- uint256 fraudChallengeDefeatTimeout;
169
+ uint32 fraudChallengeDefeatTimeout;
212
170
  // The amount of stake slashed from each member of a wallet for a fraud.
213
171
  uint96 fraudSlashingAmount;
214
172
  // The percentage of the notifier reward from the staking contract
215
173
  // the notifier of a fraud receives. The value is in the range [0, 100].
216
- uint256 fraudNotifierRewardMultiplier;
217
- // Collection of all submitted fraud challenges indexed by challenge
218
- // key built as `keccak256(walletPublicKey|sighash)`.
219
- mapping(uint256 => Fraud.FraudChallenge) fraudChallenges;
220
- // Collection of main UTXOs that are honestly spent indexed by
221
- // `keccak256(fundingTxHash | fundingOutputIndex)`. The `fundingTxHash`
222
- // is `bytes32` (ordered as in Bitcoin internally) and
223
- // `fundingOutputIndex` an `uint32`. A main UTXO is considered honestly
224
- // spent if it was used as an input of a transaction that have been
225
- // proven in the Bridge.
226
- mapping(uint256 => bool) spentMainUTXOs;
174
+ uint32 fraudNotifierRewardMultiplier;
227
175
  // Determines how frequently a new wallet creation can be requested.
228
176
  // Value in seconds.
229
177
  uint32 walletCreationPeriod;
@@ -259,6 +207,66 @@ library BridgeState {
259
207
  // of deposit fraud challenges. This value is in seconds and should be
260
208
  // greater than the deposit refund time plus some time margin.
261
209
  uint32 walletClosingPeriod;
210
+ // Collection of all revealed deposits indexed by
211
+ // `keccak256(fundingTxHash | fundingOutputIndex)`.
212
+ // The `fundingTxHash` is `bytes32` (ordered as in Bitcoin internally)
213
+ // and `fundingOutputIndex` an `uint32`. This mapping may contain valid
214
+ // and invalid deposits and the wallet is responsible for validating
215
+ // them before attempting to execute a sweep.
216
+ mapping(uint256 => Deposit.DepositRequest) deposits;
217
+ // Indicates if the vault with the given address is trusted or not.
218
+ // Depositors can route their revealed deposits only to trusted vaults
219
+ // and have trusted vaults notified about new deposits as soon as these
220
+ // deposits get swept. Vaults not trusted by the Bridge can still be
221
+ // used by Bank balance owners on their own responsibility - anyone can
222
+ // approve their Bank balance to any address.
223
+ mapping(address => bool) isVaultTrusted;
224
+ // Collection of all moved funds sweep requests indexed by
225
+ // `keccak256(movingFundsTxHash | movingFundsOutputIndex)`.
226
+ // The `movingFundsTxHash` is `bytes32` (ordered as in Bitcoin
227
+ // internally) and `movingFundsOutputIndex` an `uint32`. Each entry
228
+ // is actually an UTXO representing the moved funds and is supposed
229
+ // to be swept with the current main UTXO of the recipient wallet.
230
+ mapping(uint256 => MovingFunds.MovedFundsSweepRequest) movedFundsSweepRequests;
231
+ // Collection of all pending redemption requests indexed by
232
+ // redemption key built as
233
+ // `keccak256(walletPubKeyHash | redeemerOutputScript)`.
234
+ // The `walletPubKeyHash` is the 20-byte wallet's public key hash
235
+ // (computed using Bitcoin HASH160 over the compressed ECDSA
236
+ // public key) and `redeemerOutputScript` is a Bitcoin script
237
+ // (P2PKH, P2WPKH, P2SH or P2WSH) that will be used to lock
238
+ // redeemed BTC as requested by the redeemer. Requests are added
239
+ // to this mapping by the `requestRedemption` method (duplicates
240
+ // not allowed) and are removed by one of the following methods:
241
+ // - `submitRedemptionProof` in case the request was handled
242
+ // successfully,
243
+ // - `notifyRedemptionTimeout` in case the request was reported
244
+ // to be timed out.
245
+ mapping(uint256 => Redemption.RedemptionRequest) pendingRedemptions;
246
+ // Collection of all timed out redemptions requests indexed by
247
+ // redemption key built as
248
+ // `keccak256(walletPubKeyHash | redeemerOutputScript)`. The
249
+ // `walletPubKeyHash` is the 20-byte wallet's public key hash
250
+ // (computed using Bitcoin HASH160 over the compressed ECDSA
251
+ // public key) and `redeemerOutputScript` is the Bitcoin script
252
+ // (P2PKH, P2WPKH, P2SH or P2WSH) that is involved in the timed
253
+ // out request. Timed out requests are stored in this mapping to
254
+ // avoid slashing the wallets multiple times for the same timeout.
255
+ // Only one method can add to this mapping:
256
+ // - `notifyRedemptionTimeout` which puts the redemption key to this
257
+ // mapping basing on a timed out request stored previously in
258
+ // `pendingRedemptions` mapping.
259
+ mapping(uint256 => Redemption.RedemptionRequest) timedOutRedemptions;
260
+ // Collection of all submitted fraud challenges indexed by challenge
261
+ // key built as `keccak256(walletPublicKey|sighash)`.
262
+ mapping(uint256 => Fraud.FraudChallenge) fraudChallenges;
263
+ // Collection of main UTXOs that are honestly spent indexed by
264
+ // `keccak256(fundingTxHash | fundingOutputIndex)`. The `fundingTxHash`
265
+ // is `bytes32` (ordered as in Bitcoin internally) and
266
+ // `fundingOutputIndex` an `uint32`. A main UTXO is considered honestly
267
+ // spent if it was used as an input of a transaction that have been
268
+ // proven in the Bridge.
269
+ mapping(uint256 => bool) spentMainUTXOs;
262
270
  // Maps the 20-byte wallet public key hash (computed using Bitcoin
263
271
  // HASH160 over the compressed ECDSA public key) to the basic wallet
264
272
  // information like state and pending redemptions value.
@@ -425,9 +433,9 @@ library BridgeState {
425
433
  uint64 _redemptionDustThreshold,
426
434
  uint64 _redemptionTreasuryFeeDivisor,
427
435
  uint64 _redemptionTxMaxFee,
428
- uint256 _redemptionTimeout,
436
+ uint64 _redemptionTimeout,
429
437
  uint96 _redemptionTimeoutSlashingAmount,
430
- uint256 _redemptionTimeoutNotifierRewardMultiplier
438
+ uint64 _redemptionTimeoutNotifierRewardMultiplier
431
439
  ) internal {
432
440
  require(
433
441
  _redemptionDustThreshold > self.movingFundsDustThreshold,
@@ -546,7 +554,7 @@ library BridgeState {
546
554
  uint64 _movedFundsSweepTxMaxTotalFee,
547
555
  uint32 _movedFundsSweepTimeout,
548
556
  uint96 _movedFundsSweepTimeoutSlashingAmount,
549
- uint256 _movedFundsSweepTimeoutNotifierRewardMultiplier
557
+ uint64 _movedFundsSweepTimeoutNotifierRewardMultiplier
550
558
  ) internal {
551
559
  require(
552
560
  _movingFundsTxMaxTotalFee > 0,
@@ -709,10 +717,10 @@ library BridgeState {
709
717
  /// - Fraud notifier reward multiplier must be in the range [0, 100].
710
718
  function updateFraudParameters(
711
719
  Storage storage self,
712
- uint256 _fraudChallengeDepositAmount,
713
- uint256 _fraudChallengeDefeatTimeout,
720
+ uint96 _fraudChallengeDepositAmount,
721
+ uint32 _fraudChallengeDefeatTimeout,
714
722
  uint96 _fraudSlashingAmount,
715
- uint256 _fraudNotifierRewardMultiplier
723
+ uint32 _fraudNotifierRewardMultiplier
716
724
  ) internal {
717
725
  require(
718
726
  _fraudChallengeDefeatTimeout > 0,
@@ -424,16 +424,14 @@ library Redemption {
424
424
  );
425
425
 
426
426
  // Validate if redeemer output script is a correct standard type
427
- // (P2PKH, P2WPKH, P2SH or P2WSH). This is done by building a stub
428
- // output with 0 as value and using `BTCUtils.extractHash` on it. Such
429
- // a function extracts the payload properly only from standard outputs
430
- // so if it succeeds, we have a guarantee the redeemer output script
431
- // is proper. Worth to note `extractHash` ignores the value at all
432
- // so this is why we can use 0 safely. This way of validation is the
433
- // same as in tBTC v1.
434
- bytes memory redeemerOutputScriptPayload = abi
435
- .encodePacked(bytes8(0), redeemerOutputScript)
436
- .extractHash();
427
+ // (P2PKH, P2WPKH, P2SH or P2WSH). This is done by using
428
+ // `BTCUtils.extractHashAt` on it. Such a function extracts the payload
429
+ // properly only from standard outputs so if it succeeds, we have a
430
+ // guarantee the redeemer output script is proper. The underlying way
431
+ // of validation is the same as in tBTC v1.
432
+ bytes memory redeemerOutputScriptPayload = redeemerOutputScript
433
+ .extractHashAt(0, redeemerOutputScript.length);
434
+
437
435
  require(
438
436
  redeemerOutputScriptPayload.length > 0,
439
437
  "Redeemer output script must be a standard type"
@@ -441,8 +439,8 @@ library Redemption {
441
439
  // Check if the redeemer output script payload does not point to the
442
440
  // wallet public key hash.
443
441
  require(
444
- keccak256(abi.encodePacked(walletPubKeyHash)) !=
445
- keccak256(redeemerOutputScriptPayload),
442
+ redeemerOutputScriptPayload.length != 20 ||
443
+ walletPubKeyHash != redeemerOutputScriptPayload.slice20(0),
446
444
  "Redeemer output script must not point to the wallet PKH"
447
445
  );
448
446
 
@@ -455,8 +453,9 @@ library Redemption {
455
453
  // and redeemer output script pair. That means there can be only one
456
454
  // request asking for redemption from the given wallet to the given
457
455
  // BTC script at the same time.
458
- uint256 redemptionKey = uint256(
459
- keccak256(abi.encodePacked(walletPubKeyHash, redeemerOutputScript))
456
+ uint256 redemptionKey = getRedemptionKey(
457
+ walletPubKeyHash,
458
+ redeemerOutputScript
460
459
  );
461
460
 
462
461
  // Check if given redemption key is not used by a pending redemption.
@@ -497,6 +496,7 @@ library Redemption {
497
496
  uint32(block.timestamp)
498
497
  );
499
498
 
499
+ // slither-disable-next-line reentrancy-events
500
500
  emit RedemptionRequested(
501
501
  walletPubKeyHash,
502
502
  redeemerOutputScript,
@@ -674,7 +674,7 @@ library Redemption {
674
674
  /// must be validated using e.g. `BTCUtils.validateVout` function
675
675
  /// before it is passed here.
676
676
  /// @param walletPubKeyHash 20-byte public key hash (computed using Bitcoin
677
- // HASH160 over the compressed ECDSA public key) of the wallet which
677
+ /// HASH160 over the compressed ECDSA public key) of the wallet which
678
678
  /// performed the redemption transaction.
679
679
  /// @return info Outcomes of the processing.
680
680
  function processRedemptionTxOutputs(
@@ -722,7 +722,7 @@ library Redemption {
722
722
  // which matches the P2PKH structure as per:
723
723
  // https://en.bitcoin.it/wiki/Transaction#Pay-to-PubkeyHash
724
724
  bytes32 walletP2PKHScriptKeccak = keccak256(
725
- abi.encodePacked(hex"1976a914", walletPubKeyHash, hex"88ac")
725
+ abi.encodePacked(BitcoinTx.makeP2PKHScript(walletPubKeyHash))
726
726
  );
727
727
  // The P2WPKH script has the byte format: <0x160014> <20-byte PKH>.
728
728
  // According to https://en.bitcoin.it/wiki/Script#Opcodes this translates to:
@@ -732,7 +732,7 @@ library Redemption {
732
732
  // which matches the P2WPKH structure as per:
733
733
  // https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#P2WPKH
734
734
  bytes32 walletP2WPKHScriptKeccak = keccak256(
735
- abi.encodePacked(hex"160014", walletPubKeyHash)
735
+ abi.encodePacked(BitcoinTx.makeP2WPKHScript(walletPubKeyHash))
736
736
  );
737
737
 
738
738
  return
@@ -751,7 +751,7 @@ library Redemption {
751
751
 
752
752
  /// @notice Processes all outputs from the redemption transaction. Tries to
753
753
  /// identify output as a change output, pending redemption request
754
- // or reported redemption. Reverts if one of the outputs cannot be
754
+ /// or reported redemption. Reverts if one of the outputs cannot be
755
755
  /// recognized properly. Marks each request as processed by removing
756
756
  /// them from `pendingRedemptions` mapping.
757
757
  /// @param redemptionTxOutputVector Bitcoin redemption transaction output
@@ -759,7 +759,7 @@ library Redemption {
759
759
  /// must be validated using e.g. `BTCUtils.validateVout` function
760
760
  /// before it is passed here.
761
761
  /// @param walletPubKeyHash 20-byte public key hash (computed using Bitcoin
762
- // HASH160 over the compressed ECDSA public key) of the wallet which
762
+ /// HASH160 over the compressed ECDSA public key) of the wallet which
763
763
  /// performed the redemption transaction.
764
764
  /// @param processInfo RedemptionTxOutputsProcessingInfo identifying output
765
765
  /// starting index, the number of outputs and possible wallet change
@@ -783,24 +783,33 @@ library Redemption {
783
783
  // https://github.com/keep-network/tbtc-v2/issues/257
784
784
  uint256 outputLength = redemptionTxOutputVector
785
785
  .determineOutputLengthAt(processInfo.outputStartingIndex);
786
- bytes memory output = redemptionTxOutputVector.slice(
787
- processInfo.outputStartingIndex,
788
- outputLength
789
- );
790
786
 
791
787
  // Extract the value from given output.
792
- uint64 outputValue = output.extractValue();
788
+ uint64 outputValue = redemptionTxOutputVector.extractValueAt(
789
+ processInfo.outputStartingIndex
790
+ );
791
+
792
+ uint256 scriptLength = outputLength - 8;
793
+
793
794
  // The output consists of an 8-byte value and a variable length
794
- // script. To extract that script we slice the output starting from
795
+ // script. To hash that script we slice the output starting from
795
796
  // 9th byte until the end.
796
- bytes memory outputScript = output.slice(8, output.length - 8);
797
+
798
+ uint256 outputScriptStart = processInfo.outputStartingIndex + 8;
799
+
800
+ bytes32 outputScriptHash;
801
+ /* solhint-disable-next-line no-inline-assembly */
802
+ assembly {
803
+ outputScriptHash := keccak256(
804
+ add(redemptionTxOutputVector, add(outputScriptStart, 32)),
805
+ scriptLength
806
+ )
807
+ }
797
808
 
798
809
  if (
799
810
  resultInfo.changeValue == 0 &&
800
- (keccak256(outputScript) ==
801
- processInfo.walletP2PKHScriptKeccak ||
802
- keccak256(outputScript) ==
803
- processInfo.walletP2WPKHScriptKeccak) &&
811
+ (outputScriptHash == processInfo.walletP2PKHScriptKeccak ||
812
+ outputScriptHash == processInfo.walletP2WPKHScriptKeccak) &&
804
813
  outputValue > 0
805
814
  ) {
806
815
  // If we entered here, that means the change output with a
@@ -815,8 +824,7 @@ library Redemption {
815
824
  uint64 treasuryFee
816
825
  ) = processNonChangeRedemptionTxOutput(
817
826
  self,
818
- walletPubKeyHash,
819
- outputScript,
827
+ _getRedemptionKey(walletPubKeyHash, outputScriptHash),
820
828
  outputValue
821
829
  );
822
830
  resultInfo.totalBurnableValue += burnableValue;
@@ -847,10 +855,7 @@ library Redemption {
847
855
  /// requested and reported timed-out redemption.
848
856
  /// This function also marks each pending request as processed by
849
857
  /// removing them from `pendingRedemptions` mapping.
850
- /// @param walletPubKeyHash 20-byte public key hash (computed using Bitcoin
851
- // HASH160 over the compressed ECDSA public key) of the wallet which
852
- /// performed the redemption transaction.
853
- /// @param outputScript Non-change output script to be processed.
858
+ /// @param redemptionKey Redemption key of the output being processed.
854
859
  /// @param outputValue Value of the output being processed.
855
860
  /// @return burnableValue The value burnable as a result of processing this
856
861
  /// single redemption output. This value needs to be summed up with
@@ -864,17 +869,9 @@ library Redemption {
864
869
  /// redemption request.
865
870
  function processNonChangeRedemptionTxOutput(
866
871
  BridgeState.Storage storage self,
867
- bytes20 walletPubKeyHash,
868
- bytes memory outputScript,
872
+ uint256 redemptionKey,
869
873
  uint64 outputValue
870
874
  ) internal returns (uint64 burnableValue, uint64 treasuryFee) {
871
- // This function should be called only if the given output is
872
- // supposed to represent a redemption. Build the redemption key
873
- // to perform that check.
874
- uint256 redemptionKey = uint256(
875
- keccak256(abi.encodePacked(walletPubKeyHash, outputScript))
876
- );
877
-
878
875
  if (self.pendingRedemptions[redemptionKey].requestedAt != 0) {
879
876
  // If we entered here, that means the output was identified
880
877
  // as a pending redemption request.
@@ -975,9 +972,9 @@ library Redemption {
975
972
  bytes calldata redeemerOutputScript
976
973
  ) external {
977
974
  // Wallet state is validated in `notifyWalletRedemptionTimeout`.
978
-
979
- uint256 redemptionKey = uint256(
980
- keccak256(abi.encodePacked(walletPubKeyHash, redeemerOutputScript))
975
+ uint256 redemptionKey = getRedemptionKey(
976
+ walletPubKeyHash,
977
+ redeemerOutputScript
981
978
  );
982
979
  Redemption.RedemptionRequest memory request = self.pendingRedemptions[
983
980
  redemptionKey
@@ -1017,4 +1014,43 @@ library Redemption {
1017
1014
  // Return the requested amount of tokens to the redeemer
1018
1015
  self.bank.transferBalance(request.redeemer, request.requestedAmount);
1019
1016
  }
1017
+
1018
+ /// @notice Calculate redemption key without allocations.
1019
+ /// @param walletPubKeyHash the pubkey hash of the wallet.
1020
+ /// @param script the output script of the redemption.
1021
+ /// @return The key = keccak256(keccak256(script), walletPubKeyHash).
1022
+ function getRedemptionKey(bytes20 walletPubKeyHash, bytes memory script)
1023
+ internal
1024
+ pure
1025
+ returns (uint256)
1026
+ {
1027
+ bytes32 scriptHash = keccak256(script);
1028
+ uint256 key;
1029
+ /* solhint-disable-next-line no-inline-assembly */
1030
+ assembly {
1031
+ mstore(0, scriptHash)
1032
+ mstore(32, walletPubKeyHash)
1033
+ key := keccak256(0, 52)
1034
+ }
1035
+ return key;
1036
+ }
1037
+
1038
+ /// @notice Finish calculating redemption key without allocations.
1039
+ /// @param walletPubKeyHash the pubkey hash of the wallet.
1040
+ /// @param scriptHash the output script hash of the redemption.
1041
+ /// @return The key = keccak256(scriptHash, walletPubKeyHash).
1042
+ function _getRedemptionKey(bytes20 walletPubKeyHash, bytes32 scriptHash)
1043
+ internal
1044
+ pure
1045
+ returns (uint256)
1046
+ {
1047
+ uint256 key;
1048
+ /* solhint-disable-next-line no-inline-assembly */
1049
+ assembly {
1050
+ mstore(0, scriptHash)
1051
+ mstore(32, walletPubKeyHash)
1052
+ key := keccak256(0, 52)
1053
+ }
1054
+ return key;
1055
+ }
1020
1056
  }
package/export.json CHANGED
@@ -15085,11 +15085,11 @@
15085
15085
  "inputs": [],
15086
15086
  "outputs": [
15087
15087
  {
15088
- "type": "uint256",
15088
+ "type": "uint96",
15089
15089
  "name": "fraudChallengeDepositAmount"
15090
15090
  },
15091
15091
  {
15092
- "type": "uint256",
15092
+ "type": "uint32",
15093
15093
  "name": "fraudChallengeDefeatTimeout"
15094
15094
  },
15095
15095
  {
@@ -15097,7 +15097,7 @@
15097
15097
  "name": "fraudSlashingAmount"
15098
15098
  },
15099
15099
  {
15100
- "type": "uint256",
15100
+ "type": "uint32",
15101
15101
  "name": "fraudNotifierRewardMultiplier"
15102
15102
  }
15103
15103
  ]
@@ -15140,7 +15140,7 @@
15140
15140
  "name": "_ecdsaWalletRegistry"
15141
15141
  },
15142
15142
  {
15143
- "type": "uint256",
15143
+ "type": "uint96",
15144
15144
  "name": "_txProofDifficultyFactor"
15145
15145
  }
15146
15146
  ],
@@ -15514,7 +15514,7 @@
15514
15514
  "name": "redemptionTxMaxFee"
15515
15515
  },
15516
15516
  {
15517
- "type": "uint256",
15517
+ "type": "uint64",
15518
15518
  "name": "redemptionTimeout"
15519
15519
  },
15520
15520
  {
@@ -15522,7 +15522,7 @@
15522
15522
  "name": "redemptionTimeoutSlashingAmount"
15523
15523
  },
15524
15524
  {
15525
- "type": "uint256",
15525
+ "type": "uint64",
15526
15526
  "name": "redemptionTimeoutNotifierRewardMultiplier"
15527
15527
  }
15528
15528
  ]
@@ -16190,11 +16190,11 @@
16190
16190
  "gas": 29000000,
16191
16191
  "inputs": [
16192
16192
  {
16193
- "type": "uint256",
16193
+ "type": "uint96",
16194
16194
  "name": "fraudChallengeDepositAmount"
16195
16195
  },
16196
16196
  {
16197
- "type": "uint256",
16197
+ "type": "uint32",
16198
16198
  "name": "fraudChallengeDefeatTimeout"
16199
16199
  },
16200
16200
  {
@@ -16202,7 +16202,7 @@
16202
16202
  "name": "fraudSlashingAmount"
16203
16203
  },
16204
16204
  {
16205
- "type": "uint256",
16205
+ "type": "uint32",
16206
16206
  "name": "fraudNotifierRewardMultiplier"
16207
16207
  }
16208
16208
  ],
@@ -16252,7 +16252,7 @@
16252
16252
  "name": "movedFundsSweepTimeoutSlashingAmount"
16253
16253
  },
16254
16254
  {
16255
- "type": "uint256",
16255
+ "type": "uint64",
16256
16256
  "name": "movedFundsSweepTimeoutNotifierRewardMultiplier"
16257
16257
  }
16258
16258
  ],
@@ -16278,7 +16278,7 @@
16278
16278
  "name": "redemptionTxMaxFee"
16279
16279
  },
16280
16280
  {
16281
- "type": "uint256",
16281
+ "type": "uint64",
16282
16282
  "name": "redemptionTimeout"
16283
16283
  },
16284
16284
  {
@@ -16286,7 +16286,7 @@
16286
16286
  "name": "redemptionTimeoutSlashingAmount"
16287
16287
  },
16288
16288
  {
16289
- "type": "uint256",
16289
+ "type": "uint64",
16290
16290
  "name": "redemptionTimeoutNotifierRewardMultiplier"
16291
16291
  }
16292
16292
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@keep-network/tbtc-v2",
3
- "version": "0.1.1-dev.97+main.a22deeca0ba51d31473ab19c2cfd708912cd27e8",
3
+ "version": "0.1.1-dev.98+main.f6402ddc3a00709426dc87405c889b433f8aef6b",
4
4
  "license": "MIT",
5
5
  "files": [
6
6
  "artifacts/",
@@ -27,7 +27,7 @@
27
27
  "prepublishOnly": "./scripts/prepare-artifacts.sh --network $npm_config_network"
28
28
  },
29
29
  "dependencies": {
30
- "@keep-network/bitcoin-spv-sol": "3.3.0-solc-0.8",
30
+ "@keep-network/bitcoin-spv-sol": "3.4.0-solc-0.8",
31
31
  "@keep-network/ecdsa": "development",
32
32
  "@keep-network/random-beacon": "development",
33
33
  "@keep-network/tbtc": ">1.1.2-dev <1.1.2-pre",