@keep-network/tbtc-v2 0.1.1-dev.62 → 0.1.1-dev.65
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.
- package/artifacts/Bank.json +6 -6
- package/artifacts/Bridge.json +153 -119
- package/artifacts/Deposit.json +7 -7
- package/artifacts/DepositSweep.json +14 -13
- package/artifacts/EcdsaDkgValidator.json +1 -1
- package/artifacts/EcdsaInactivity.json +1 -1
- package/artifacts/Fraud.json +20 -10
- package/artifacts/KeepRegistry.json +1 -1
- package/artifacts/KeepStake.json +2 -2
- package/artifacts/KeepToken.json +2 -2
- package/artifacts/KeepTokenStaking.json +1 -1
- package/artifacts/MovingFunds.json +7 -7
- package/artifacts/NuCypherStakingEscrow.json +1 -1
- package/artifacts/NuCypherToken.json +2 -2
- package/artifacts/RandomBeaconStub.json +1 -1
- package/artifacts/Redemption.json +7 -7
- package/artifacts/ReimbursementPool.json +2 -2
- package/artifacts/Relay.json +11 -11
- package/artifacts/SortitionPool.json +2 -2
- package/artifacts/T.json +2 -2
- package/artifacts/TBTC.json +6 -6
- package/artifacts/TBTCToken.json +6 -6
- package/artifacts/TokenStaking.json +1 -1
- package/artifacts/TokenholderGovernor.json +9 -9
- package/artifacts/TokenholderTimelock.json +8 -8
- package/artifacts/VendingMachine.json +13 -13
- package/artifacts/VendingMachineKeep.json +1 -1
- package/artifacts/VendingMachineNuCypher.json +1 -1
- package/artifacts/WalletRegistry.json +2 -2
- package/artifacts/WalletRegistryGovernance.json +2 -2
- package/artifacts/Wallets.json +9 -9
- package/artifacts/solcInputs/{05c98d94f96a77da7702c7818a8cadac.json → a80c9f316a07a9460c9cb236187d2158.json} +11 -11
- package/build/contracts/GovernanceUtils.sol/GovernanceUtils.dbg.json +1 -1
- package/build/contracts/bank/Bank.sol/Bank.dbg.json +1 -1
- package/build/contracts/bridge/BitcoinTx.sol/BitcoinTx.dbg.json +1 -1
- package/build/contracts/bridge/BitcoinTx.sol/BitcoinTx.json +2 -2
- package/build/contracts/bridge/Bridge.sol/Bridge.dbg.json +1 -1
- package/build/contracts/bridge/Bridge.sol/Bridge.json +69 -38
- package/build/contracts/bridge/BridgeState.sol/BridgeState.dbg.json +1 -1
- package/build/contracts/bridge/BridgeState.sol/BridgeState.json +2 -2
- package/build/contracts/bridge/Deposit.sol/Deposit.dbg.json +1 -1
- package/build/contracts/bridge/Deposit.sol/Deposit.json +2 -2
- package/build/contracts/bridge/DepositSweep.sol/DepositSweep.dbg.json +1 -1
- package/build/contracts/bridge/DepositSweep.sol/DepositSweep.json +2 -2
- package/build/contracts/bridge/EcdsaLib.sol/EcdsaLib.dbg.json +1 -1
- package/build/contracts/bridge/Fraud.sol/Fraud.dbg.json +1 -1
- package/build/contracts/bridge/Fraud.sol/Fraud.json +2 -2
- package/build/contracts/bridge/Heartbeat.sol/Heartbeat.dbg.json +1 -1
- package/build/contracts/bridge/Heartbeat.sol/Heartbeat.json +2 -2
- package/build/contracts/bridge/IRelay.sol/IRelay.dbg.json +1 -1
- package/build/contracts/bridge/MovingFunds.sol/MovingFunds.dbg.json +1 -1
- package/build/contracts/bridge/MovingFunds.sol/MovingFunds.json +2 -2
- package/build/contracts/bridge/Redemption.sol/OutboundTx.dbg.json +1 -1
- package/build/contracts/bridge/Redemption.sol/OutboundTx.json +2 -2
- package/build/contracts/bridge/Redemption.sol/Redemption.dbg.json +1 -1
- package/build/contracts/bridge/Redemption.sol/Redemption.json +2 -2
- package/build/contracts/bridge/VendingMachine.sol/VendingMachine.dbg.json +1 -1
- package/build/contracts/bridge/Wallets.sol/Wallets.dbg.json +1 -1
- package/build/contracts/bridge/Wallets.sol/Wallets.json +2 -2
- package/build/contracts/token/TBTC.sol/TBTC.dbg.json +1 -1
- package/build/contracts/vault/DonationVault.sol/DonationVault.dbg.json +1 -1
- package/build/contracts/vault/IVault.sol/IVault.dbg.json +1 -1
- package/build/contracts/vault/TBTCVault.sol/TBTCVault.dbg.json +1 -1
- package/contracts/bridge/Bridge.sol +53 -6
- package/contracts/bridge/BridgeState.sol +15 -7
- package/contracts/bridge/DepositSweep.sol +93 -40
- package/contracts/bridge/Fraud.sol +81 -4
- package/contracts/bridge/Heartbeat.sol +5 -0
- package/contracts/bridge/Redemption.sol +0 -1
- package/export.json +23 -0
- package/package.json +1 -1
|
@@ -39,6 +39,29 @@ library DepositSweep {
|
|
|
39
39
|
|
|
40
40
|
using BTCUtils for bytes;
|
|
41
41
|
|
|
42
|
+
/// @notice Represents temporary information needed during the processing
|
|
43
|
+
/// of the deposit sweep Bitcoin transaction inputs. This structure
|
|
44
|
+
/// is an internal one and should not be exported outside of the
|
|
45
|
+
/// deposit sweep transaction processing code.
|
|
46
|
+
/// @dev Allows to mitigate "stack too deep" errors on EVM.
|
|
47
|
+
struct DepositSweepTxInputsProcessingInfo {
|
|
48
|
+
// Input vector of the deposit sweep Bitcoin transaction. It is
|
|
49
|
+
// assumed the vector's structure is valid so it must be validated
|
|
50
|
+
// using e.g. `BTCUtils.validateVin` function before being used
|
|
51
|
+
// during the processing. The validation is usually done as part
|
|
52
|
+
// of the `BitcoinTx.validateProof` call that checks the SPV proof.
|
|
53
|
+
bytes sweepTxInputVector;
|
|
54
|
+
// Data of the wallet's main UTXO. If no main UTXO exists for the given
|
|
55
|
+
// sweeping wallet, this parameter's fields should be zeroed to bypass
|
|
56
|
+
// the main UTXO validation
|
|
57
|
+
BitcoinTx.UTXO mainUtxo;
|
|
58
|
+
// Address of the vault where all swept deposits should be routed to.
|
|
59
|
+
// It is used to validate whether all swept deposits have been revealed
|
|
60
|
+
// with the same `vault` parameter. It is an optional parameter.
|
|
61
|
+
// Set to zero address if deposits are not routed to a vault.
|
|
62
|
+
address vault;
|
|
63
|
+
}
|
|
64
|
+
|
|
42
65
|
/// @notice Represents an outcome of the sweep Bitcoin transaction
|
|
43
66
|
/// inputs processing.
|
|
44
67
|
struct DepositSweepTxInputsInfo {
|
|
@@ -83,6 +106,15 @@ library DepositSweep {
|
|
|
83
106
|
/// @param mainUtxo Data of the wallet's main UTXO, as currently known on
|
|
84
107
|
/// the Ethereum chain. If no main UTXO exists for the given wallet,
|
|
85
108
|
/// this parameter is ignored
|
|
109
|
+
/// @param vault Optional address of the vault where all swept deposits
|
|
110
|
+
/// should be routed to. All deposits swept as part of the transaction
|
|
111
|
+
/// must have their `vault` parameters set to the same address.
|
|
112
|
+
/// If this parameter is set to an address of a trusted vault, swept
|
|
113
|
+
/// deposits are routed to that vault.
|
|
114
|
+
/// If this parameter is set to the zero address or to an address
|
|
115
|
+
/// of a non-trusted vault, swept deposits are not routed to a
|
|
116
|
+
/// vault but depositors' balances are increased in the Bank
|
|
117
|
+
/// individually.
|
|
86
118
|
/// @dev Requirements:
|
|
87
119
|
/// - `sweepTx` components must match the expected structure. See
|
|
88
120
|
/// `BitcoinTx.Info` docs for reference. Their values must exactly
|
|
@@ -96,6 +128,9 @@ library DepositSweep {
|
|
|
96
128
|
/// revealed deposits UTXOs. That transaction must have only
|
|
97
129
|
/// one P2(W)PKH output locking funds on the 20-byte wallet public
|
|
98
130
|
/// key hash.
|
|
131
|
+
/// - All revealed deposits that are swept by `sweepTx` must have
|
|
132
|
+
/// their `vault` parameters set to the same address as the address
|
|
133
|
+
/// passed in the `vault` function parameter.
|
|
99
134
|
/// - `sweepProof` components must match the expected structure. See
|
|
100
135
|
/// `BitcoinTx.Proof` docs for reference. The `bitcoinHeaders`
|
|
101
136
|
/// field must contain a valid number of block headers, not less
|
|
@@ -107,7 +142,8 @@ library DepositSweep {
|
|
|
107
142
|
BridgeState.Storage storage self,
|
|
108
143
|
BitcoinTx.Info calldata sweepTx,
|
|
109
144
|
BitcoinTx.Proof calldata sweepProof,
|
|
110
|
-
BitcoinTx.UTXO calldata mainUtxo
|
|
145
|
+
BitcoinTx.UTXO calldata mainUtxo,
|
|
146
|
+
address vault
|
|
111
147
|
) external {
|
|
112
148
|
// The actual transaction proof is performed here. After that point, we
|
|
113
149
|
// can assume the transaction happened on Bitcoin chain and has
|
|
@@ -132,8 +168,11 @@ library DepositSweep {
|
|
|
132
168
|
DepositSweepTxInputsInfo
|
|
133
169
|
memory inputsInfo = processDepositSweepTxInputs(
|
|
134
170
|
self,
|
|
135
|
-
|
|
136
|
-
|
|
171
|
+
DepositSweepTxInputsProcessingInfo(
|
|
172
|
+
sweepTx.inputVector,
|
|
173
|
+
resolvedMainUtxo,
|
|
174
|
+
vault
|
|
175
|
+
)
|
|
137
176
|
);
|
|
138
177
|
|
|
139
178
|
// Helper variable that will hold the sum of treasury fees paid by
|
|
@@ -189,15 +228,26 @@ library DepositSweep {
|
|
|
189
228
|
// slither-disable-next-line reentrancy-events
|
|
190
229
|
emit DepositsSwept(walletPubKeyHash, sweepTxHash);
|
|
191
230
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
231
|
+
if (vault != address(0) && self.isVaultTrusted[vault]) {
|
|
232
|
+
// If the `vault` address is not zero and belongs to a trusted
|
|
233
|
+
// vault, route the deposits to that vault.
|
|
234
|
+
self.bank.increaseBalanceAndCall(
|
|
235
|
+
vault,
|
|
236
|
+
inputsInfo.depositors,
|
|
237
|
+
inputsInfo.depositedAmounts
|
|
238
|
+
);
|
|
239
|
+
} else {
|
|
240
|
+
// If the `vault` address is zero or belongs to a non-trusted
|
|
241
|
+
// vault, increase balances in the Bank individually for each
|
|
242
|
+
// depositor.
|
|
243
|
+
self.bank.increaseBalances(
|
|
244
|
+
inputsInfo.depositors,
|
|
245
|
+
inputsInfo.depositedAmounts
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
|
|
197
249
|
// Pass the treasury fee to the treasury address.
|
|
198
250
|
self.bank.increaseBalance(self.treasury, totalTreasuryFee);
|
|
199
|
-
|
|
200
|
-
// TODO: Handle deposits having `vault` set.
|
|
201
251
|
}
|
|
202
252
|
|
|
203
253
|
/// @notice Resolves sweeping wallet based on the provided wallet public key
|
|
@@ -299,32 +349,23 @@ library DepositSweep {
|
|
|
299
349
|
/// if one of the inputs cannot be recognized as a pointer to a
|
|
300
350
|
/// revealed deposit or expected main UTXO.
|
|
301
351
|
/// This function also marks each processed deposit as swept.
|
|
302
|
-
/// @
|
|
303
|
-
/// This function assumes vector's structure is valid so it must be
|
|
304
|
-
/// validated using e.g. `BTCUtils.validateVin` function before
|
|
305
|
-
/// it is passed here
|
|
306
|
-
/// @param mainUtxo Data of the wallet's main UTXO. If no main UTXO
|
|
307
|
-
/// exists for the given the wallet, this parameter's fields should
|
|
308
|
-
/// be zeroed to bypass the main UTXO validation
|
|
309
|
-
/// @return info Outcomes of the processing.
|
|
352
|
+
/// @return resultInfo Outcomes of the processing.
|
|
310
353
|
function processDepositSweepTxInputs(
|
|
311
354
|
BridgeState.Storage storage self,
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
) internal returns (DepositSweepTxInputsInfo memory info) {
|
|
355
|
+
DepositSweepTxInputsProcessingInfo memory processInfo
|
|
356
|
+
) internal returns (DepositSweepTxInputsInfo memory resultInfo) {
|
|
315
357
|
// If the passed `mainUtxo` parameter's values are zeroed, the main UTXO
|
|
316
358
|
// for the given wallet doesn't exist and it is not expected to be
|
|
317
359
|
// included in the sweep transaction input vector.
|
|
318
|
-
bool mainUtxoExpected = mainUtxo.txHash != bytes32(0);
|
|
360
|
+
bool mainUtxoExpected = processInfo.mainUtxo.txHash != bytes32(0);
|
|
319
361
|
bool mainUtxoFound = false;
|
|
320
362
|
|
|
321
363
|
// Determining the total number of sweep transaction inputs in the same
|
|
322
364
|
// way as for number of outputs. See `BitcoinTx.inputVector` docs for
|
|
323
365
|
// more details.
|
|
324
|
-
(
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
) = sweepTxInputVector.parseVarInt();
|
|
366
|
+
(uint256 inputsCompactSizeUintLength, uint256 inputsCount) = processInfo
|
|
367
|
+
.sweepTxInputVector
|
|
368
|
+
.parseVarInt();
|
|
328
369
|
|
|
329
370
|
// To determine the first input starting index, we must jump over
|
|
330
371
|
// the compactSize uint which prepends the input vector. One byte
|
|
@@ -346,11 +387,13 @@ library DepositSweep {
|
|
|
346
387
|
// Determine the swept deposits count. If main UTXO is NOT expected,
|
|
347
388
|
// all inputs should be deposits. If main UTXO is expected, one input
|
|
348
389
|
// should point to that main UTXO.
|
|
349
|
-
|
|
390
|
+
resultInfo.depositors = new address[](
|
|
350
391
|
!mainUtxoExpected ? inputsCount : inputsCount - 1
|
|
351
392
|
);
|
|
352
|
-
|
|
353
|
-
|
|
393
|
+
resultInfo.depositedAmounts = new uint256[](
|
|
394
|
+
resultInfo.depositors.length
|
|
395
|
+
);
|
|
396
|
+
resultInfo.treasuryFees = new uint256[](resultInfo.depositors.length);
|
|
354
397
|
|
|
355
398
|
// Initialize helper variables.
|
|
356
399
|
uint256 processedDepositsCount = 0;
|
|
@@ -362,7 +405,7 @@ library DepositSweep {
|
|
|
362
405
|
uint32 outpointIndex,
|
|
363
406
|
uint256 inputLength
|
|
364
407
|
) = parseDepositSweepTxInputAt(
|
|
365
|
-
sweepTxInputVector,
|
|
408
|
+
processInfo.sweepTxInputVector,
|
|
366
409
|
inputStartingIndex
|
|
367
410
|
);
|
|
368
411
|
|
|
@@ -377,7 +420,12 @@ library DepositSweep {
|
|
|
377
420
|
// a revealed deposit.
|
|
378
421
|
require(deposit.sweptAt == 0, "Deposit already swept");
|
|
379
422
|
|
|
380
|
-
|
|
423
|
+
require(
|
|
424
|
+
deposit.vault == processInfo.vault,
|
|
425
|
+
"Deposit should be routed to another vault"
|
|
426
|
+
);
|
|
427
|
+
|
|
428
|
+
if (processedDepositsCount == resultInfo.depositors.length) {
|
|
381
429
|
// If this condition is true, that means a deposit input
|
|
382
430
|
// took place of an expected main UTXO input.
|
|
383
431
|
// In other words, there is no expected main UTXO
|
|
@@ -390,22 +438,27 @@ library DepositSweep {
|
|
|
390
438
|
/* solhint-disable-next-line not-rely-on-time */
|
|
391
439
|
deposit.sweptAt = uint32(block.timestamp);
|
|
392
440
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
441
|
+
resultInfo.depositors[processedDepositsCount] = deposit
|
|
442
|
+
.depositor;
|
|
443
|
+
resultInfo.depositedAmounts[processedDepositsCount] = deposit
|
|
444
|
+
.amount;
|
|
445
|
+
resultInfo.inputsTotalValue += resultInfo.depositedAmounts[
|
|
396
446
|
processedDepositsCount
|
|
397
447
|
];
|
|
398
|
-
|
|
448
|
+
resultInfo.treasuryFees[processedDepositsCount] = deposit
|
|
449
|
+
.treasuryFee;
|
|
399
450
|
|
|
400
451
|
processedDepositsCount++;
|
|
401
452
|
} else if (
|
|
402
453
|
mainUtxoExpected != mainUtxoFound &&
|
|
403
|
-
mainUtxo.txHash == outpointTxHash &&
|
|
404
|
-
mainUtxo.txOutputIndex == outpointIndex
|
|
454
|
+
processInfo.mainUtxo.txHash == outpointTxHash &&
|
|
455
|
+
processInfo.mainUtxo.txOutputIndex == outpointIndex
|
|
405
456
|
) {
|
|
406
457
|
// If we entered here, that means the input was identified as
|
|
407
458
|
// the expected main UTXO.
|
|
408
|
-
|
|
459
|
+
resultInfo.inputsTotalValue += processInfo
|
|
460
|
+
.mainUtxo
|
|
461
|
+
.txOutputValue;
|
|
409
462
|
mainUtxoFound = true;
|
|
410
463
|
|
|
411
464
|
// Main UTXO used as an input, mark it as spent.
|
|
@@ -426,7 +479,7 @@ library DepositSweep {
|
|
|
426
479
|
}
|
|
427
480
|
|
|
428
481
|
// Construction of the input processing loop guarantees that:
|
|
429
|
-
// `processedDepositsCount ==
|
|
482
|
+
// `processedDepositsCount == resultInfo.depositors.length == resultInfo.depositedAmounts.length`
|
|
430
483
|
// is always true at this point. We just use the first variable
|
|
431
484
|
// to assert the total count of swept deposit is bigger than zero.
|
|
432
485
|
require(
|
|
@@ -441,7 +494,7 @@ library DepositSweep {
|
|
|
441
494
|
"Expected main UTXO not present in sweep transaction inputs"
|
|
442
495
|
);
|
|
443
496
|
|
|
444
|
-
return
|
|
497
|
+
return resultInfo;
|
|
445
498
|
}
|
|
446
499
|
|
|
447
500
|
/// @notice Parses a Bitcoin transaction input starting at the given index.
|
|
@@ -22,6 +22,7 @@ import {CheckBitcoinSigs} from "@keep-network/bitcoin-spv-sol/contracts/CheckBit
|
|
|
22
22
|
import "./BitcoinTx.sol";
|
|
23
23
|
import "./EcdsaLib.sol";
|
|
24
24
|
import "./BridgeState.sol";
|
|
25
|
+
import "./Heartbeat.sol";
|
|
25
26
|
import "./MovingFunds.sol";
|
|
26
27
|
import "./Wallets.sol";
|
|
27
28
|
|
|
@@ -38,10 +39,18 @@ import "./Wallets.sol";
|
|
|
38
39
|
/// signature must be provided as were used to calculate the sighash during
|
|
39
40
|
/// the challenge. The wallet provides the preimage which produces sighash
|
|
40
41
|
/// used to generate the ECDSA signature that is the subject of the fraud
|
|
41
|
-
/// claim.
|
|
42
|
-
///
|
|
43
|
-
///
|
|
44
|
-
///
|
|
42
|
+
/// claim.
|
|
43
|
+
///
|
|
44
|
+
/// The fraud challenge defeat attempt will succeed if the inputs in the
|
|
45
|
+
/// preimage are considered honestly spent by the wallet. Therefore the
|
|
46
|
+
/// transaction spending the UTXO must be proven in the Bridge before
|
|
47
|
+
/// a challenge defeat is called.
|
|
48
|
+
///
|
|
49
|
+
/// Another option is when a malicious wallet member used a signed heartbeat
|
|
50
|
+
/// message periodically produced by the wallet off-chain to challenge the
|
|
51
|
+
/// wallet for a fraud. Anyone from the wallet can defeat the challenge by
|
|
52
|
+
/// proving the sighash and signature were produced for a heartbeat message
|
|
53
|
+
/// following a strict format.
|
|
45
54
|
library Fraud {
|
|
46
55
|
using Wallets for BridgeState.Storage;
|
|
47
56
|
|
|
@@ -73,6 +82,10 @@ library Fraud {
|
|
|
73
82
|
|
|
74
83
|
event FraudChallengeDefeatTimedOut(
|
|
75
84
|
bytes20 walletPubKeyHash,
|
|
85
|
+
// Sighash calculated as a Bitcoin's hash256 (double sha2) of:
|
|
86
|
+
// - a preimage of a transaction spending UTXO according to the protocol
|
|
87
|
+
// rules OR
|
|
88
|
+
// - a valid heartbeat message produced by the wallet off-chain.
|
|
76
89
|
bytes32 sighash
|
|
77
90
|
);
|
|
78
91
|
|
|
@@ -234,6 +247,69 @@ library Fraud {
|
|
|
234
247
|
"Spent UTXO not found among correctly spent UTXOs"
|
|
235
248
|
);
|
|
236
249
|
|
|
250
|
+
resolveFraudChallenge(self, walletPublicKey, challenge, sighash);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/// @notice Allows to defeat a pending fraud challenge against a wallet by
|
|
254
|
+
/// proving the sighash and signature were produced for an off-chain
|
|
255
|
+
/// wallet heartbeat message following a strict format.
|
|
256
|
+
/// In order to defeat the challenge the same `walletPublicKey` and
|
|
257
|
+
/// signature (represented by `r`, `s` and `v`) must be provided as
|
|
258
|
+
/// were used to calculate the sighash during heartbeat message
|
|
259
|
+
/// signing. The fraud challenge defeat attempt will only succeed if
|
|
260
|
+
/// the signed message follows a strict format required for
|
|
261
|
+
/// heartbeat messages. If successfully defeated, the fraud
|
|
262
|
+
/// challenge is marked as resolved and the amount of ether
|
|
263
|
+
/// deposited by the challenger is sent to the treasury.
|
|
264
|
+
/// @param walletPublicKey The public key of the wallet in the uncompressed
|
|
265
|
+
/// and unprefixed format (64 bytes)
|
|
266
|
+
/// @param heartbeatMessage Off-chain heartbeat message meeting the heartbeat
|
|
267
|
+
/// message format requirements which produces sighash used to
|
|
268
|
+
/// generate the ECDSA signature that is the subject of the fraud
|
|
269
|
+
/// claim
|
|
270
|
+
/// @dev Requirements:
|
|
271
|
+
/// - `walletPublicKey` and `sighash` calculated as
|
|
272
|
+
/// `hash256(heartbeatMessage)` must identify an open fraud challenge
|
|
273
|
+
/// - `heartbeatMessage` must follow a strict format of heartbeat
|
|
274
|
+
/// messages
|
|
275
|
+
function defeatFraudChallengeWithHeartbeat(
|
|
276
|
+
BridgeState.Storage storage self,
|
|
277
|
+
bytes calldata walletPublicKey,
|
|
278
|
+
bytes calldata heartbeatMessage
|
|
279
|
+
) external {
|
|
280
|
+
bytes32 sighash = heartbeatMessage.hash256();
|
|
281
|
+
|
|
282
|
+
uint256 challengeKey = uint256(
|
|
283
|
+
keccak256(abi.encodePacked(walletPublicKey, sighash))
|
|
284
|
+
);
|
|
285
|
+
|
|
286
|
+
FraudChallenge storage challenge = self.fraudChallenges[challengeKey];
|
|
287
|
+
|
|
288
|
+
require(challenge.reportedAt > 0, "Fraud challenge does not exist");
|
|
289
|
+
require(
|
|
290
|
+
!challenge.resolved,
|
|
291
|
+
"Fraud challenge has already been resolved"
|
|
292
|
+
);
|
|
293
|
+
|
|
294
|
+
require(
|
|
295
|
+
Heartbeat.isValidHeartbeatMessage(heartbeatMessage),
|
|
296
|
+
"Not a valid heartbeat message"
|
|
297
|
+
);
|
|
298
|
+
|
|
299
|
+
resolveFraudChallenge(self, walletPublicKey, challenge, sighash);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/// @notice Called only for successfully defeated fraud challenges.
|
|
303
|
+
/// The fraud challenge is marked as resolved and the amount of
|
|
304
|
+
/// ether deposited by the challenger is sent to the treasury.
|
|
305
|
+
/// @dev Requirements:
|
|
306
|
+
/// - Must be called only for successfully defeated fraud challenges.
|
|
307
|
+
function resolveFraudChallenge(
|
|
308
|
+
BridgeState.Storage storage self,
|
|
309
|
+
bytes calldata walletPublicKey,
|
|
310
|
+
FraudChallenge storage challenge,
|
|
311
|
+
bytes32 sighash
|
|
312
|
+
) internal {
|
|
237
313
|
// Mark the challenge as resolved as it was successfully defeated
|
|
238
314
|
challenge.resolved = true;
|
|
239
315
|
|
|
@@ -248,6 +324,7 @@ library Fraud {
|
|
|
248
324
|
walletPublicKey.slice32(32)
|
|
249
325
|
);
|
|
250
326
|
bytes20 walletPubKeyHash = compressedWalletPublicKey.hash160View();
|
|
327
|
+
|
|
251
328
|
// slither-disable-next-line reentrancy-events
|
|
252
329
|
emit FraudChallengeDefeated(walletPubKeyHash, sighash);
|
|
253
330
|
}
|
|
@@ -78,6 +78,11 @@ import {BytesLib} from "@keep-network/bitcoin-spv-sol/contracts/BytesLib.sol";
|
|
|
78
78
|
/// message. The first 8 bytes are 0xffffffffffffffff. The last 8 bytes
|
|
79
79
|
/// are for an arbitrary uint64, being a signed heartbeat nonce (for
|
|
80
80
|
/// example, the last Ethereum block hash).
|
|
81
|
+
///
|
|
82
|
+
/// The message being signed by the wallet when executing the heartbeat
|
|
83
|
+
/// protocol should be Bitcoin's hash256 (double SHA-256) of the heartbeat
|
|
84
|
+
/// message:
|
|
85
|
+
/// heartbeat_sighash = hash256(heartbeat_message)
|
|
81
86
|
library Heartbeat {
|
|
82
87
|
using BytesLib for bytes;
|
|
83
88
|
|
|
@@ -825,7 +825,6 @@ library Redemption {
|
|
|
825
825
|
request.treasuryFee;
|
|
826
826
|
|
|
827
827
|
require(
|
|
828
|
-
// TODO: Allow the wallets in `Closing` state when the state is added
|
|
829
828
|
wallet.state == Wallets.WalletState.Live ||
|
|
830
829
|
wallet.state == Wallets.WalletState.MovingFunds ||
|
|
831
830
|
wallet.state == Wallets.WalletState.Terminated,
|
package/export.json
CHANGED
|
@@ -14871,6 +14871,24 @@
|
|
|
14871
14871
|
"stateMutability": "nonpayable",
|
|
14872
14872
|
"type": "function"
|
|
14873
14873
|
},
|
|
14874
|
+
{
|
|
14875
|
+
"inputs": [
|
|
14876
|
+
{
|
|
14877
|
+
"internalType": "bytes",
|
|
14878
|
+
"name": "walletPublicKey",
|
|
14879
|
+
"type": "bytes"
|
|
14880
|
+
},
|
|
14881
|
+
{
|
|
14882
|
+
"internalType": "bytes",
|
|
14883
|
+
"name": "heartbeatMessage",
|
|
14884
|
+
"type": "bytes"
|
|
14885
|
+
}
|
|
14886
|
+
],
|
|
14887
|
+
"name": "defeatFraudChallengeWithHeartbeat",
|
|
14888
|
+
"outputs": [],
|
|
14889
|
+
"stateMutability": "nonpayable",
|
|
14890
|
+
"type": "function"
|
|
14891
|
+
},
|
|
14874
14892
|
{
|
|
14875
14893
|
"inputs": [],
|
|
14876
14894
|
"name": "depositParameters",
|
|
@@ -16019,6 +16037,11 @@
|
|
|
16019
16037
|
"internalType": "struct BitcoinTx.UTXO",
|
|
16020
16038
|
"name": "mainUtxo",
|
|
16021
16039
|
"type": "tuple"
|
|
16040
|
+
},
|
|
16041
|
+
{
|
|
16042
|
+
"internalType": "address",
|
|
16043
|
+
"name": "vault",
|
|
16044
|
+
"type": "address"
|
|
16022
16045
|
}
|
|
16023
16046
|
],
|
|
16024
16047
|
"name": "submitDepositSweepProof",
|