@keep-network/tbtc-v2 0.1.1-dev.41 → 0.1.1-dev.44
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 +742 -0
- package/artifacts/Bridge.json +2914 -0
- package/artifacts/Deposit.json +117 -0
- package/artifacts/EcdsaDkgValidator.json +532 -0
- package/artifacts/EcdsaInactivity.json +156 -0
- package/artifacts/Fraud.json +153 -0
- package/artifacts/KeepRegistry.json +99 -0
- package/artifacts/KeepStake.json +286 -0
- package/artifacts/KeepToken.json +711 -0
- package/artifacts/KeepTokenStaking.json +483 -0
- package/artifacts/MovingFunds.json +137 -0
- package/artifacts/NuCypherStakingEscrow.json +256 -0
- package/artifacts/NuCypherToken.json +711 -0
- package/artifacts/RandomBeaconStub.json +141 -0
- package/artifacts/Redemption.json +161 -0
- package/artifacts/ReimbursementPool.json +509 -0
- package/artifacts/Relay.json +123 -0
- package/artifacts/SortitionPool.json +944 -0
- package/artifacts/Sweep.json +76 -0
- package/artifacts/T.json +1148 -0
- package/artifacts/TBTC.json +21 -21
- package/artifacts/TBTCToken.json +21 -21
- package/artifacts/TokenStaking.json +2288 -0
- package/artifacts/TokenholderGovernor.json +1795 -0
- package/artifacts/TokenholderTimelock.json +1058 -0
- package/artifacts/VendingMachine.json +24 -24
- package/artifacts/VendingMachineKeep.json +400 -0
- package/artifacts/VendingMachineNuCypher.json +400 -0
- package/artifacts/WalletRegistry.json +2709 -0
- package/artifacts/WalletRegistryGovernance.json +2364 -0
- package/artifacts/Wallets.json +186 -0
- package/artifacts/solcInputs/{e9b173393b9fd7287a0bfaa6d4eb4b71.json → bbe44823ec28554a9429cce5cafee035.json} +34 -34
- 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 +535 -273
- package/build/contracts/bridge/BridgeState.sol/BridgeState.dbg.json +1 -1
- package/build/contracts/bridge/BridgeState.sol/BridgeState.json +147 -3
- 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/EcdsaLib.sol/EcdsaLib.dbg.json +1 -1
- package/build/contracts/bridge/EcdsaLib.sol/EcdsaLib.json +2 -2
- package/build/contracts/bridge/Fraud.sol/Fraud.dbg.json +1 -1
- package/build/contracts/bridge/Fraud.sol/Fraud.json +5 -57
- 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 +41 -21
- package/build/contracts/bridge/Redemption.sol/OutboundTx.dbg.json +4 -0
- package/build/contracts/bridge/{Redeem.sol → Redemption.sol}/OutboundTx.json +3 -3
- package/build/contracts/bridge/Redemption.sol/Redemption.dbg.json +4 -0
- package/build/contracts/bridge/Redemption.sol/Redemption.json +92 -0
- package/build/contracts/bridge/Sweep.sol/Sweep.dbg.json +1 -1
- package/build/contracts/bridge/Sweep.sol/Sweep.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 +12 -38
- package/build/contracts/token/TBTC.sol/TBTC.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/BitcoinTx.sol +19 -26
- package/contracts/bridge/Bridge.sol +765 -524
- package/contracts/bridge/BridgeState.sol +312 -23
- package/contracts/bridge/Deposit.sol +25 -6
- package/contracts/bridge/EcdsaLib.sol +15 -0
- package/contracts/bridge/Fraud.sol +65 -33
- package/contracts/bridge/MovingFunds.sol +196 -10
- package/contracts/bridge/{Redeem.sol → Redemption.sol} +26 -29
- package/contracts/bridge/Sweep.sol +16 -12
- package/contracts/bridge/Wallets.sol +90 -153
- package/deploy/00_resolve_relay.ts +28 -0
- package/deploy/04_deploy_bank.ts +25 -0
- package/deploy/05_deploy_bridge.ts +60 -0
- package/deploy/06_bank_update_bridge.ts +19 -0
- package/deploy/07_transfer_ownership.ts +17 -0
- package/export.json +14797 -459
- package/package.json +2 -2
- package/build/contracts/bridge/Redeem.sol/OutboundTx.dbg.json +0 -4
- package/build/contracts/bridge/Redeem.sol/Redeem.dbg.json +0 -4
- package/build/contracts/bridge/Redeem.sol/Redeem.json +0 -110
|
@@ -20,20 +20,174 @@ import {BytesLib} from "@keep-network/bitcoin-spv-sol/contracts/BytesLib.sol";
|
|
|
20
20
|
|
|
21
21
|
import "./BitcoinTx.sol";
|
|
22
22
|
import "./BridgeState.sol";
|
|
23
|
-
import "./
|
|
23
|
+
import "./Redemption.sol";
|
|
24
|
+
import "./Wallets.sol";
|
|
24
25
|
|
|
26
|
+
/// @title Moving Bridge wallet funds
|
|
27
|
+
/// @notice The library handles the logic for moving Bitcoin between Bridge
|
|
28
|
+
/// wallets.
|
|
29
|
+
/// @dev A wallet that failed a heartbeat, did not process requested redemption
|
|
30
|
+
/// on time, or qualifies to be closed, begins the procedure of moving
|
|
31
|
+
/// funds to other wallets in the Bridge. The wallet needs to commit to
|
|
32
|
+
/// which other Live wallets it is moving the funds to and then, provide an
|
|
33
|
+
/// SPV proof of moving funds to the previously committed wallets.
|
|
25
34
|
library MovingFunds {
|
|
26
35
|
using BridgeState for BridgeState.Storage;
|
|
27
|
-
using Wallets for
|
|
36
|
+
using Wallets for BridgeState.Storage;
|
|
37
|
+
using BitcoinTx for BridgeState.Storage;
|
|
28
38
|
|
|
29
39
|
using BTCUtils for bytes;
|
|
30
40
|
using BytesLib for bytes;
|
|
31
41
|
|
|
42
|
+
event MovingFundsCommitmentSubmitted(
|
|
43
|
+
bytes20 walletPubKeyHash,
|
|
44
|
+
bytes20[] targetWallets,
|
|
45
|
+
address submitter
|
|
46
|
+
);
|
|
47
|
+
|
|
32
48
|
event MovingFundsCompleted(
|
|
33
49
|
bytes20 walletPubKeyHash,
|
|
34
50
|
bytes32 movingFundsTxHash
|
|
35
51
|
);
|
|
36
52
|
|
|
53
|
+
event MovingFundsTimedOut(bytes20 walletPubKeyHash);
|
|
54
|
+
|
|
55
|
+
/// @notice Submits the moving funds target wallets commitment.
|
|
56
|
+
/// Once all requirements are met, that function registers the
|
|
57
|
+
/// target wallets commitment and opens the way for moving funds
|
|
58
|
+
/// proof submission.
|
|
59
|
+
/// @param walletPubKeyHash 20-byte public key hash of the source wallet
|
|
60
|
+
/// @param walletMainUtxo Data of the source wallet's main UTXO, as
|
|
61
|
+
/// currently known on the Ethereum chain
|
|
62
|
+
/// @param walletMembersIDs Identifiers of the source wallet signing group
|
|
63
|
+
/// members
|
|
64
|
+
/// @param walletMemberIndex Position of the caller in the source wallet
|
|
65
|
+
/// signing group members list
|
|
66
|
+
/// @param targetWallets List of 20-byte public key hashes of the target
|
|
67
|
+
/// wallets that the source wallet commits to move the funds to
|
|
68
|
+
/// @dev Requirements:
|
|
69
|
+
/// - The source wallet must be in the MovingFunds state
|
|
70
|
+
/// - The source wallet must not have pending redemption requests
|
|
71
|
+
/// - The source wallet must not have submitted its commitment already
|
|
72
|
+
/// - The expression `keccak256(abi.encode(walletMembersIDs))` must
|
|
73
|
+
/// be exactly the same as the hash stored under `membersIdsHash`
|
|
74
|
+
/// for the given source wallet in the ECDSA registry. Those IDs are
|
|
75
|
+
/// not directly stored in the contract for gas efficiency purposes
|
|
76
|
+
/// but they can be read from appropriate `DkgResultSubmitted`
|
|
77
|
+
/// and `DkgResultApproved` events.
|
|
78
|
+
/// - The `walletMemberIndex` must be in range [1, walletMembersIDs.length]
|
|
79
|
+
/// - The caller must be the member of the source wallet signing group
|
|
80
|
+
/// at the position indicated by `walletMemberIndex` parameter
|
|
81
|
+
/// - The `walletMainUtxo` components must point to the recent main
|
|
82
|
+
/// UTXO of the source wallet, as currently known on the Ethereum
|
|
83
|
+
/// chain.
|
|
84
|
+
/// - Source wallet BTC balance must be greater than zero
|
|
85
|
+
/// - At least one Live wallet must exist in the system
|
|
86
|
+
/// - Submitted target wallets count must match the expected count
|
|
87
|
+
/// `N = min(liveWalletsCount, ceil(walletBtcBalance / walletMaxBtcTransfer))`
|
|
88
|
+
/// where `N > 0`
|
|
89
|
+
/// - Each target wallet must be not equal to the source wallet
|
|
90
|
+
/// - Each target wallet must follow the expected order i.e. all
|
|
91
|
+
/// target wallets 20-byte public key hashes represented as numbers
|
|
92
|
+
/// must form a strictly increasing sequence without duplicates.
|
|
93
|
+
/// - Each target wallet must be in Live state
|
|
94
|
+
function submitMovingFundsCommitment(
|
|
95
|
+
BridgeState.Storage storage self,
|
|
96
|
+
bytes20 walletPubKeyHash,
|
|
97
|
+
BitcoinTx.UTXO calldata walletMainUtxo,
|
|
98
|
+
uint32[] calldata walletMembersIDs,
|
|
99
|
+
uint256 walletMemberIndex,
|
|
100
|
+
bytes20[] calldata targetWallets
|
|
101
|
+
) external {
|
|
102
|
+
Wallets.Wallet storage wallet = self.registeredWallets[
|
|
103
|
+
walletPubKeyHash
|
|
104
|
+
];
|
|
105
|
+
|
|
106
|
+
require(
|
|
107
|
+
wallet.state == Wallets.WalletState.MovingFunds,
|
|
108
|
+
"Source wallet must be in MovingFunds state"
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
require(
|
|
112
|
+
wallet.pendingRedemptionsValue == 0,
|
|
113
|
+
"Source wallet must handle all pending redemptions first"
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
require(
|
|
117
|
+
wallet.movingFundsTargetWalletsCommitmentHash == bytes32(0),
|
|
118
|
+
"Target wallets commitment already submitted"
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
require(
|
|
122
|
+
self.ecdsaWalletRegistry.isWalletMember(
|
|
123
|
+
wallet.ecdsaWalletID,
|
|
124
|
+
walletMembersIDs,
|
|
125
|
+
msg.sender,
|
|
126
|
+
walletMemberIndex
|
|
127
|
+
),
|
|
128
|
+
"Caller is not a member of the source wallet"
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
uint64 walletBtcBalance = self.getWalletBtcBalance(
|
|
132
|
+
walletPubKeyHash,
|
|
133
|
+
walletMainUtxo
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
require(walletBtcBalance > 0, "Wallet BTC balance is zero");
|
|
137
|
+
|
|
138
|
+
uint256 expectedTargetWalletsCount = Math.min(
|
|
139
|
+
self.liveWalletsCount,
|
|
140
|
+
Math.ceilDiv(walletBtcBalance, self.walletMaxBtcTransfer)
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
// This requirement fails only when `liveWalletsCount` is zero. In
|
|
144
|
+
// that case, the system cannot accept the commitment and must provide
|
|
145
|
+
// new wallets first.
|
|
146
|
+
//
|
|
147
|
+
// TODO: Expose separate function to reset the moving funds timeout
|
|
148
|
+
// if no Live wallets exist in the system.
|
|
149
|
+
require(expectedTargetWalletsCount > 0, "No target wallets available");
|
|
150
|
+
|
|
151
|
+
require(
|
|
152
|
+
targetWallets.length == expectedTargetWalletsCount,
|
|
153
|
+
"Submitted target wallets count is other than expected"
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
uint160 lastProcessedTargetWallet = 0;
|
|
157
|
+
|
|
158
|
+
for (uint256 i = 0; i < targetWallets.length; i++) {
|
|
159
|
+
bytes20 targetWallet = targetWallets[i];
|
|
160
|
+
|
|
161
|
+
require(
|
|
162
|
+
targetWallet != walletPubKeyHash,
|
|
163
|
+
"Submitted target wallet cannot be equal to the source wallet"
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
require(
|
|
167
|
+
uint160(targetWallet) > lastProcessedTargetWallet,
|
|
168
|
+
"Submitted target wallet breaks the expected order"
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
require(
|
|
172
|
+
self.registeredWallets[targetWallet].state ==
|
|
173
|
+
Wallets.WalletState.Live,
|
|
174
|
+
"Submitted target wallet must be in Live state"
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
lastProcessedTargetWallet = uint160(targetWallet);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
wallet.movingFundsTargetWalletsCommitmentHash = keccak256(
|
|
181
|
+
abi.encodePacked(targetWallets)
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
emit MovingFundsCommitmentSubmitted(
|
|
185
|
+
walletPubKeyHash,
|
|
186
|
+
targetWallets,
|
|
187
|
+
msg.sender
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
|
|
37
191
|
/// @notice Used by the wallet to prove the BTC moving funds transaction
|
|
38
192
|
/// and to make the necessary state changes. Moving funds is only
|
|
39
193
|
/// accepted if it satisfies SPV proof.
|
|
@@ -81,7 +235,6 @@ library MovingFunds {
|
|
|
81
235
|
/// to `movingFundsTxMaxTotalFee` governable parameter.
|
|
82
236
|
function submitMovingFundsProof(
|
|
83
237
|
BridgeState.Storage storage self,
|
|
84
|
-
Wallets.Data storage wallets,
|
|
85
238
|
BitcoinTx.Info calldata movingFundsTx,
|
|
86
239
|
BitcoinTx.Proof calldata movingFundsProof,
|
|
87
240
|
BitcoinTx.UTXO calldata mainUtxo,
|
|
@@ -91,17 +244,15 @@ library MovingFunds {
|
|
|
91
244
|
// can assume the transaction happened on Bitcoin chain and has
|
|
92
245
|
// a sufficient number of confirmations as determined by
|
|
93
246
|
// `txProofDifficultyFactor` constant.
|
|
94
|
-
bytes32 movingFundsTxHash =
|
|
247
|
+
bytes32 movingFundsTxHash = self.validateProof(
|
|
95
248
|
movingFundsTx,
|
|
96
|
-
movingFundsProof
|
|
97
|
-
self.proofDifficultyContext()
|
|
249
|
+
movingFundsProof
|
|
98
250
|
);
|
|
99
251
|
|
|
100
252
|
// Process the moving funds transaction input. Specifically, check if
|
|
101
253
|
// it refers to the expected wallet's main UTXO.
|
|
102
254
|
OutboundTx.processWalletOutboundTxInput(
|
|
103
255
|
self,
|
|
104
|
-
wallets,
|
|
105
256
|
movingFundsTx.inputVector,
|
|
106
257
|
mainUtxo,
|
|
107
258
|
walletPubKeyHash
|
|
@@ -118,8 +269,8 @@ library MovingFunds {
|
|
|
118
269
|
"Transaction fee is too high"
|
|
119
270
|
);
|
|
120
271
|
|
|
121
|
-
|
|
122
|
-
|
|
272
|
+
self.notifyWalletFundsMoved(walletPubKeyHash, targetWalletsHash);
|
|
273
|
+
// slither-disable-next-line reentrancy-events
|
|
123
274
|
emit MovingFundsCompleted(walletPubKeyHash, movingFundsTxHash);
|
|
124
275
|
}
|
|
125
276
|
|
|
@@ -139,7 +290,7 @@ library MovingFunds {
|
|
|
139
290
|
/// - The total outputs value must be evenly divided over all outputs.
|
|
140
291
|
function processMovingFundsTxOutputs(bytes memory movingFundsTxOutputVector)
|
|
141
292
|
internal
|
|
142
|
-
|
|
293
|
+
pure
|
|
143
294
|
returns (bytes32 targetWalletsHash, uint256 outputsTotalValue)
|
|
144
295
|
{
|
|
145
296
|
// Determining the total number of Bitcoin transaction outputs in
|
|
@@ -277,4 +428,39 @@ library MovingFunds {
|
|
|
277
428
|
|
|
278
429
|
return (targetWalletsHash, outputsTotalValue);
|
|
279
430
|
}
|
|
431
|
+
|
|
432
|
+
/// @notice Notifies about a timed out moving funds process. Terminates
|
|
433
|
+
/// the wallet and slashes signing group members as a result.
|
|
434
|
+
/// @param walletPubKeyHash 20-byte public key hash of the wallet
|
|
435
|
+
/// @dev Requirements:
|
|
436
|
+
/// - The wallet must be in the MovingFunds state
|
|
437
|
+
/// - The moving funds timeout must be actually exceeded
|
|
438
|
+
function notifyMovingFundsTimeout(
|
|
439
|
+
BridgeState.Storage storage self,
|
|
440
|
+
bytes20 walletPubKeyHash
|
|
441
|
+
) external {
|
|
442
|
+
Wallets.Wallet storage wallet = self.registeredWallets[
|
|
443
|
+
walletPubKeyHash
|
|
444
|
+
];
|
|
445
|
+
|
|
446
|
+
require(
|
|
447
|
+
wallet.state == Wallets.WalletState.MovingFunds,
|
|
448
|
+
"ECDSA wallet must be in MovingFunds state"
|
|
449
|
+
);
|
|
450
|
+
|
|
451
|
+
require(
|
|
452
|
+
/* solhint-disable-next-line not-rely-on-time */
|
|
453
|
+
block.timestamp >
|
|
454
|
+
wallet.movingFundsRequestedAt + self.movingFundsTimeout,
|
|
455
|
+
"Moving funds has not timed out yet"
|
|
456
|
+
);
|
|
457
|
+
|
|
458
|
+
self.terminateWallet(walletPubKeyHash);
|
|
459
|
+
|
|
460
|
+
// TODO: Perform slashing of wallet operators, reward the notifier
|
|
461
|
+
// using seized amount, and add unit tests for that.
|
|
462
|
+
|
|
463
|
+
// slither-disable-next-line reentrancy-events
|
|
464
|
+
emit MovingFundsTimedOut(walletPubKeyHash);
|
|
465
|
+
}
|
|
280
466
|
}
|
|
@@ -47,13 +47,12 @@ library OutboundTx {
|
|
|
47
47
|
/// performed the outbound transaction.
|
|
48
48
|
function processWalletOutboundTxInput(
|
|
49
49
|
BridgeState.Storage storage self,
|
|
50
|
-
Wallets.Data storage wallets,
|
|
51
50
|
bytes memory walletOutboundTxInputVector,
|
|
52
51
|
BitcoinTx.UTXO calldata mainUtxo,
|
|
53
52
|
bytes20 walletPubKeyHash
|
|
54
53
|
) internal {
|
|
55
54
|
// Assert that main UTXO for passed wallet exists in storage.
|
|
56
|
-
bytes32 mainUtxoHash =
|
|
55
|
+
bytes32 mainUtxoHash = self
|
|
57
56
|
.registeredWallets[walletPubKeyHash]
|
|
58
57
|
.mainUtxoHash;
|
|
59
58
|
require(mainUtxoHash != bytes32(0), "No main UTXO for given wallet");
|
|
@@ -141,10 +140,18 @@ library OutboundTx {
|
|
|
141
140
|
}
|
|
142
141
|
}
|
|
143
142
|
|
|
144
|
-
|
|
145
|
-
library
|
|
143
|
+
/// @title Bridge redemption
|
|
144
|
+
/// @notice The library handles the logic for redeeming Bitcoin balances from
|
|
145
|
+
/// the Bridge.
|
|
146
|
+
/// @dev To initiate a redemption, a user with a Bank balance supplies
|
|
147
|
+
/// a Bitcoin address. Then, the system calculates the redemption fee, and
|
|
148
|
+
/// releases balance to the provided Bitcoin address. Just like in case of
|
|
149
|
+
/// sweeps of revealed deposits, redemption requests are processed in
|
|
150
|
+
/// batches and require SPV proof to be submitted to the Bridge.
|
|
151
|
+
library Redemption {
|
|
146
152
|
using BridgeState for BridgeState.Storage;
|
|
147
|
-
using Wallets for
|
|
153
|
+
using Wallets for BridgeState.Storage;
|
|
154
|
+
using BitcoinTx for BridgeState.Storage;
|
|
148
155
|
|
|
149
156
|
using BTCUtils for bytes;
|
|
150
157
|
using BytesLib for bytes;
|
|
@@ -248,13 +255,12 @@ library Redeem {
|
|
|
248
255
|
/// contract can spend the given `amount`.
|
|
249
256
|
function requestRedemption(
|
|
250
257
|
BridgeState.Storage storage self,
|
|
251
|
-
Wallets.Data storage wallets,
|
|
252
258
|
bytes20 walletPubKeyHash,
|
|
253
259
|
BitcoinTx.UTXO calldata mainUtxo,
|
|
254
260
|
bytes calldata redeemerOutputScript,
|
|
255
261
|
uint64 amount
|
|
256
262
|
) external {
|
|
257
|
-
Wallets.Wallet storage wallet =
|
|
263
|
+
Wallets.Wallet storage wallet = self.registeredWallets[
|
|
258
264
|
walletPubKeyHash
|
|
259
265
|
];
|
|
260
266
|
|
|
@@ -419,37 +425,30 @@ library Redeem {
|
|
|
419
425
|
/// is identified, that check is omitted in further iterations.
|
|
420
426
|
function submitRedemptionProof(
|
|
421
427
|
BridgeState.Storage storage self,
|
|
422
|
-
Wallets.Data storage wallets,
|
|
423
428
|
BitcoinTx.Info calldata redemptionTx,
|
|
424
429
|
BitcoinTx.Proof calldata redemptionProof,
|
|
425
430
|
BitcoinTx.UTXO calldata mainUtxo,
|
|
426
431
|
bytes20 walletPubKeyHash
|
|
427
432
|
) external {
|
|
428
|
-
// TODO: Just as for `submitSweepProof`, fail early if the function
|
|
429
|
-
// call gets frontrunned. See discussion:
|
|
430
|
-
// https://github.com/keep-network/tbtc-v2/pull/106#discussion_r801745204
|
|
431
|
-
|
|
432
433
|
// The actual transaction proof is performed here. After that point, we
|
|
433
434
|
// can assume the transaction happened on Bitcoin chain and has
|
|
434
435
|
// a sufficient number of confirmations as determined by
|
|
435
436
|
// `txProofDifficultyFactor` constant.
|
|
436
|
-
bytes32 redemptionTxHash =
|
|
437
|
+
bytes32 redemptionTxHash = self.validateProof(
|
|
437
438
|
redemptionTx,
|
|
438
|
-
redemptionProof
|
|
439
|
-
self.proofDifficultyContext()
|
|
439
|
+
redemptionProof
|
|
440
440
|
);
|
|
441
441
|
|
|
442
442
|
// Process the redemption transaction input. Specifically, check if it
|
|
443
443
|
// refers to the expected wallet's main UTXO.
|
|
444
444
|
OutboundTx.processWalletOutboundTxInput(
|
|
445
445
|
self,
|
|
446
|
-
wallets,
|
|
447
446
|
redemptionTx.inputVector,
|
|
448
447
|
mainUtxo,
|
|
449
448
|
walletPubKeyHash
|
|
450
449
|
);
|
|
451
450
|
|
|
452
|
-
Wallets.Wallet storage wallet =
|
|
451
|
+
Wallets.Wallet storage wallet = self.registeredWallets[
|
|
453
452
|
walletPubKeyHash
|
|
454
453
|
];
|
|
455
454
|
|
|
@@ -600,11 +599,10 @@ library Redeem {
|
|
|
600
599
|
bytes20 walletPubKeyHash,
|
|
601
600
|
RedemptionTxOutputsProcessingInfo memory processInfo
|
|
602
601
|
) internal returns (RedemptionTxOutputsInfo memory resultInfo) {
|
|
603
|
-
// Helper
|
|
604
|
-
//
|
|
605
|
-
//
|
|
606
|
-
|
|
607
|
-
uint256 processedRedemptionsCount = 0;
|
|
602
|
+
// Helper flag indicating whether there was at least one redemption
|
|
603
|
+
// output present (redemption must be either pending or reported as
|
|
604
|
+
// timed out).
|
|
605
|
+
bool redemptionPresent = false;
|
|
608
606
|
|
|
609
607
|
// Outputs processing loop.
|
|
610
608
|
for (uint256 i = 0; i < processInfo.outputsCount; i++) {
|
|
@@ -651,7 +649,7 @@ library Redeem {
|
|
|
651
649
|
);
|
|
652
650
|
resultInfo.totalBurnableValue += burnableValue;
|
|
653
651
|
resultInfo.totalTreasuryFee += treasuryFee;
|
|
654
|
-
|
|
652
|
+
redemptionPresent = true;
|
|
655
653
|
}
|
|
656
654
|
|
|
657
655
|
// Make the `outputStartingIndex` pointing to the next output by
|
|
@@ -663,7 +661,7 @@ library Redeem {
|
|
|
663
661
|
// referring back to the wallet PKH and just burning main UTXO value
|
|
664
662
|
// for transaction fees.
|
|
665
663
|
require(
|
|
666
|
-
|
|
664
|
+
redemptionPresent,
|
|
667
665
|
"Redemption transaction must process at least one redemption"
|
|
668
666
|
);
|
|
669
667
|
}
|
|
@@ -789,14 +787,13 @@ library Redeem {
|
|
|
789
787
|
/// timed-out).
|
|
790
788
|
function notifyRedemptionTimeout(
|
|
791
789
|
BridgeState.Storage storage self,
|
|
792
|
-
Wallets.Data storage wallets,
|
|
793
790
|
bytes20 walletPubKeyHash,
|
|
794
791
|
bytes calldata redeemerOutputScript
|
|
795
792
|
) external {
|
|
796
793
|
uint256 redemptionKey = uint256(
|
|
797
794
|
keccak256(abi.encodePacked(walletPubKeyHash, redeemerOutputScript))
|
|
798
795
|
);
|
|
799
|
-
|
|
796
|
+
Redemption.RedemptionRequest memory request = self.pendingRedemptions[
|
|
800
797
|
redemptionKey
|
|
801
798
|
];
|
|
802
799
|
|
|
@@ -808,7 +805,7 @@ library Redeem {
|
|
|
808
805
|
);
|
|
809
806
|
|
|
810
807
|
// Update the wallet's pending redemptions value
|
|
811
|
-
Wallets.Wallet storage wallet =
|
|
808
|
+
Wallets.Wallet storage wallet = self.registeredWallets[
|
|
812
809
|
walletPubKeyHash
|
|
813
810
|
];
|
|
814
811
|
wallet.pendingRedemptionsValue -=
|
|
@@ -838,9 +835,9 @@ library Redeem {
|
|
|
838
835
|
wallet.state == Wallets.WalletState.MovingFunds
|
|
839
836
|
) {
|
|
840
837
|
// Propagate timeout consequences to the wallet
|
|
841
|
-
|
|
838
|
+
self.notifyWalletTimedOutRedemption(walletPubKeyHash);
|
|
842
839
|
}
|
|
843
|
-
|
|
840
|
+
// slither-disable-next-line reentrancy-events
|
|
844
841
|
emit RedemptionTimedOut(walletPubKeyHash, redeemerOutputScript);
|
|
845
842
|
|
|
846
843
|
// Return the requested amount of tokens to the redeemer
|
|
@@ -23,8 +23,19 @@ import "./Wallets.sol";
|
|
|
23
23
|
|
|
24
24
|
import "../bank/Bank.sol";
|
|
25
25
|
|
|
26
|
+
/// @title Bridge deposit sweep
|
|
27
|
+
/// @notice The library handles the logic for sweeping transactions revealed to
|
|
28
|
+
/// the Bridge
|
|
29
|
+
/// @dev Bridge active wallet periodically signs a transaction that unlocks all
|
|
30
|
+
/// of the valid, revealed deposits above the dust threshold, combines them
|
|
31
|
+
/// into a single UTXO with the existing main wallet UTXO, and relocks
|
|
32
|
+
/// those transactions without a 30-day refund clause to the same wallet.
|
|
33
|
+
/// This has two main effects: it consolidates the UTXO set and it disables
|
|
34
|
+
/// the refund. Balances of depositors in the Bank are increased when the
|
|
35
|
+
/// SPV sweep proof is submitted to the Bridge.
|
|
26
36
|
library Sweep {
|
|
27
37
|
using BridgeState for BridgeState.Storage;
|
|
38
|
+
using BitcoinTx for BridgeState.Storage;
|
|
28
39
|
|
|
29
40
|
using BTCUtils for bytes;
|
|
30
41
|
|
|
@@ -94,23 +105,15 @@ library Sweep {
|
|
|
94
105
|
/// If there is no main UTXO, this parameter is ignored.
|
|
95
106
|
function submitSweepProof(
|
|
96
107
|
BridgeState.Storage storage self,
|
|
97
|
-
Wallets.Data storage wallets,
|
|
98
108
|
BitcoinTx.Info calldata sweepTx,
|
|
99
109
|
BitcoinTx.Proof calldata sweepProof,
|
|
100
110
|
BitcoinTx.UTXO calldata mainUtxo
|
|
101
111
|
) external {
|
|
102
|
-
// TODO: Fail early if the function call gets frontrunned. See discussion:
|
|
103
|
-
// https://github.com/keep-network/tbtc-v2/pull/106#discussion_r801745204
|
|
104
|
-
|
|
105
112
|
// The actual transaction proof is performed here. After that point, we
|
|
106
113
|
// can assume the transaction happened on Bitcoin chain and has
|
|
107
114
|
// a sufficient number of confirmations as determined by
|
|
108
115
|
// `txProofDifficultyFactor` constant.
|
|
109
|
-
bytes32 sweepTxHash =
|
|
110
|
-
sweepTx,
|
|
111
|
-
sweepProof,
|
|
112
|
-
self.proofDifficultyContext()
|
|
113
|
-
);
|
|
116
|
+
bytes32 sweepTxHash = self.validateProof(sweepTx, sweepProof);
|
|
114
117
|
|
|
115
118
|
// Process sweep transaction output and extract its target wallet
|
|
116
119
|
// public key hash and value.
|
|
@@ -122,7 +125,7 @@ library Sweep {
|
|
|
122
125
|
(
|
|
123
126
|
Wallets.Wallet storage wallet,
|
|
124
127
|
BitcoinTx.UTXO memory resolvedMainUtxo
|
|
125
|
-
) = resolveSweepingWallet(
|
|
128
|
+
) = resolveSweepingWallet(self, walletPubKeyHash, mainUtxo);
|
|
126
129
|
|
|
127
130
|
// Process sweep transaction inputs and extract all information needed
|
|
128
131
|
// to perform deposit bookkeeping.
|
|
@@ -208,17 +211,18 @@ library Sweep {
|
|
|
208
211
|
/// - If the main UTXO of the sweeping wallet exists in the storage,
|
|
209
212
|
/// the passed `mainUTXO` parameter must be equal to the stored one.
|
|
210
213
|
function resolveSweepingWallet(
|
|
211
|
-
|
|
214
|
+
BridgeState.Storage storage self,
|
|
212
215
|
bytes20 walletPubKeyHash,
|
|
213
216
|
BitcoinTx.UTXO calldata mainUtxo
|
|
214
217
|
)
|
|
215
218
|
internal
|
|
219
|
+
view
|
|
216
220
|
returns (
|
|
217
221
|
Wallets.Wallet storage wallet,
|
|
218
222
|
BitcoinTx.UTXO memory resolvedMainUtxo
|
|
219
223
|
)
|
|
220
224
|
{
|
|
221
|
-
wallet =
|
|
225
|
+
wallet = self.registeredWallets[walletPubKeyHash];
|
|
222
226
|
|
|
223
227
|
Wallets.WalletState walletState = wallet.state;
|
|
224
228
|
require(
|