@keep-network/tbtc-v2 0.1.1-dev.21 → 0.1.1-dev.22
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/TBTC.json +3 -3
- package/artifacts/TBTCToken.json +3 -3
- package/artifacts/VendingMachine.json +10 -10
- package/artifacts/solcInputs/{af7a1ba64c125a6b01a6d1518b2bcc34.json → e2b5f983e9c69369a4f41eb2f0688e3c.json} +5 -5
- 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 +89 -3
- package/build/contracts/bridge/Bridge.sol/Bridge.dbg.json +1 -1
- package/build/contracts/bridge/Bridge.sol/Bridge.json +30 -4
- package/build/contracts/bridge/Bridge.sol/IRelay.dbg.json +1 -1
- package/build/contracts/bridge/VendingMachine.sol/VendingMachine.dbg.json +1 -1
- 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 +107 -2
- package/contracts/bridge/Bridge.sol +24 -103
- package/package.json +2 -1
|
@@ -15,6 +15,9 @@
|
|
|
15
15
|
|
|
16
16
|
pragma solidity ^0.8.9;
|
|
17
17
|
|
|
18
|
+
import {BTCUtils} from "@keep-network/bitcoin-spv-sol/contracts/BTCUtils.sol";
|
|
19
|
+
import {ValidateSPV} from "@keep-network/bitcoin-spv-sol/contracts/ValidateSPV.sol";
|
|
20
|
+
|
|
18
21
|
/// @title Bitcoin transaction
|
|
19
22
|
/// @notice Allows to reference Bitcoin raw transaction in Solidity.
|
|
20
23
|
/// @dev See https://developer.bitcoin.org/reference/transactions.html#raw-transaction-format
|
|
@@ -69,8 +72,12 @@ pragma solidity ^0.8.9;
|
|
|
69
72
|
/// (*) compactSize uint is often references as VarInt)
|
|
70
73
|
///
|
|
71
74
|
library BitcoinTx {
|
|
72
|
-
|
|
73
|
-
|
|
75
|
+
using BTCUtils for bytes;
|
|
76
|
+
using BTCUtils for uint256;
|
|
77
|
+
using ValidateSPV for bytes;
|
|
78
|
+
using ValidateSPV for bytes32;
|
|
79
|
+
|
|
80
|
+
/// @notice Represents Bitcoin transaction data.
|
|
74
81
|
struct Info {
|
|
75
82
|
/// @notice Bitcoin transaction version
|
|
76
83
|
/// @dev `version` from raw Bitcon transaction data.
|
|
@@ -113,6 +120,17 @@ library BitcoinTx {
|
|
|
113
120
|
bytes bitcoinHeaders;
|
|
114
121
|
}
|
|
115
122
|
|
|
123
|
+
/// @notice Determines the difficulty context for a Bitcoin SPV proof.
|
|
124
|
+
struct ProofDifficulty {
|
|
125
|
+
/// @notice Difficulty of the current epoch.
|
|
126
|
+
uint256 currentEpochDifficulty;
|
|
127
|
+
/// @notice Difficulty of the previous epoch.
|
|
128
|
+
uint256 previousEpochDifficulty;
|
|
129
|
+
/// @notice The number of confirmations on the Bitcoin chain required
|
|
130
|
+
/// to successfully evaluate an SPV proof.
|
|
131
|
+
uint256 difficultyFactor;
|
|
132
|
+
}
|
|
133
|
+
|
|
116
134
|
/// @notice Represents info about an unspent transaction output.
|
|
117
135
|
struct UTXO {
|
|
118
136
|
/// @notice Hash of the transaction the output belongs to.
|
|
@@ -123,4 +141,91 @@ library BitcoinTx {
|
|
|
123
141
|
/// @notice Value of the transaction output.
|
|
124
142
|
uint64 txOutputValue;
|
|
125
143
|
}
|
|
144
|
+
|
|
145
|
+
/// @notice Validates the SPV proof of the Bitcoin transaction.
|
|
146
|
+
/// Reverts in case the validation or proof verification fail.
|
|
147
|
+
/// @param txInfo Bitcoin transaction data
|
|
148
|
+
/// @param proof Bitcoin proof data
|
|
149
|
+
/// @param proofDifficulty Bitcoin proof difficulty context.
|
|
150
|
+
/// @return txHash Proven 32-byte transaction hash.
|
|
151
|
+
function validateProof(
|
|
152
|
+
Info calldata txInfo,
|
|
153
|
+
Proof calldata proof,
|
|
154
|
+
ProofDifficulty calldata proofDifficulty
|
|
155
|
+
) external view returns (bytes32 txHash) {
|
|
156
|
+
require(
|
|
157
|
+
txInfo.inputVector.validateVin(),
|
|
158
|
+
"Invalid input vector provided"
|
|
159
|
+
);
|
|
160
|
+
require(
|
|
161
|
+
txInfo.outputVector.validateVout(),
|
|
162
|
+
"Invalid output vector provided"
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
txHash = abi
|
|
166
|
+
.encodePacked(
|
|
167
|
+
txInfo.version,
|
|
168
|
+
txInfo.inputVector,
|
|
169
|
+
txInfo.outputVector,
|
|
170
|
+
txInfo.locktime
|
|
171
|
+
)
|
|
172
|
+
.hash256View();
|
|
173
|
+
|
|
174
|
+
require(
|
|
175
|
+
txHash.prove(
|
|
176
|
+
proof.bitcoinHeaders.extractMerkleRootLE(),
|
|
177
|
+
proof.merkleProof,
|
|
178
|
+
proof.txIndexInBlock
|
|
179
|
+
),
|
|
180
|
+
"Tx merkle proof is not valid for provided header and tx hash"
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
evaluateProofDifficulty(proof.bitcoinHeaders, proofDifficulty);
|
|
184
|
+
|
|
185
|
+
return txHash;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/// @notice Evaluates the given Bitcoin proof difficulty against the actual
|
|
189
|
+
/// Bitcoin chain difficulty provided by the relay oracle.
|
|
190
|
+
/// Reverts in case the evaluation fails.
|
|
191
|
+
/// @param bitcoinHeaders Bitcoin headers chain being part of the SPV
|
|
192
|
+
/// proof. Used to extract the observed proof difficulty
|
|
193
|
+
/// @param proofDifficulty Bitcoin proof difficulty context.
|
|
194
|
+
function evaluateProofDifficulty(
|
|
195
|
+
bytes memory bitcoinHeaders,
|
|
196
|
+
ProofDifficulty calldata proofDifficulty
|
|
197
|
+
) internal view {
|
|
198
|
+
uint256 requestedDiff = 0;
|
|
199
|
+
uint256 firstHeaderDiff = bitcoinHeaders
|
|
200
|
+
.extractTarget()
|
|
201
|
+
.calculateDifficulty();
|
|
202
|
+
|
|
203
|
+
if (firstHeaderDiff == proofDifficulty.currentEpochDifficulty) {
|
|
204
|
+
requestedDiff = proofDifficulty.currentEpochDifficulty;
|
|
205
|
+
} else if (firstHeaderDiff == proofDifficulty.previousEpochDifficulty) {
|
|
206
|
+
requestedDiff = proofDifficulty.previousEpochDifficulty;
|
|
207
|
+
} else {
|
|
208
|
+
revert("Not at current or previous difficulty");
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
uint256 observedDiff = bitcoinHeaders.validateHeaderChain();
|
|
212
|
+
|
|
213
|
+
require(
|
|
214
|
+
observedDiff != ValidateSPV.getErrBadLength(),
|
|
215
|
+
"Invalid length of the headers chain"
|
|
216
|
+
);
|
|
217
|
+
require(
|
|
218
|
+
observedDiff != ValidateSPV.getErrInvalidChain(),
|
|
219
|
+
"Invalid headers chain"
|
|
220
|
+
);
|
|
221
|
+
require(
|
|
222
|
+
observedDiff != ValidateSPV.getErrLowWork(),
|
|
223
|
+
"Insufficient work in a header"
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
require(
|
|
227
|
+
observedDiff >= requestedDiff * proofDifficulty.difficultyFactor,
|
|
228
|
+
"Insufficient accumulated difficulty in header chain"
|
|
229
|
+
);
|
|
230
|
+
}
|
|
126
231
|
}
|
|
@@ -19,7 +19,6 @@ import "@openzeppelin/contracts/access/Ownable.sol";
|
|
|
19
19
|
|
|
20
20
|
import {BTCUtils} from "@keep-network/bitcoin-spv-sol/contracts/BTCUtils.sol";
|
|
21
21
|
import {BytesLib} from "@keep-network/bitcoin-spv-sol/contracts/BytesLib.sol";
|
|
22
|
-
import {ValidateSPV} from "@keep-network/bitcoin-spv-sol/contracts/ValidateSPV.sol";
|
|
23
22
|
|
|
24
23
|
import "../bank/Bank.sol";
|
|
25
24
|
import "./BitcoinTx.sol";
|
|
@@ -59,8 +58,6 @@ contract Bridge is Ownable {
|
|
|
59
58
|
using BTCUtils for bytes;
|
|
60
59
|
using BTCUtils for uint256;
|
|
61
60
|
using BytesLib for bytes;
|
|
62
|
-
using ValidateSPV for bytes;
|
|
63
|
-
using ValidateSPV for bytes32;
|
|
64
61
|
|
|
65
62
|
/// @notice Represents data which must be revealed by the depositor during
|
|
66
63
|
/// deposit reveal.
|
|
@@ -413,6 +410,22 @@ contract Bridge is Ownable {
|
|
|
413
410
|
emit VaultStatusUpdated(vault, isTrusted);
|
|
414
411
|
}
|
|
415
412
|
|
|
413
|
+
/// @notice Determines the current Bitcoin SPV proof difficulty context.
|
|
414
|
+
/// @return proofDifficulty Bitcoin proof difficulty context.
|
|
415
|
+
function proofDifficultyContext()
|
|
416
|
+
internal
|
|
417
|
+
view
|
|
418
|
+
returns (BitcoinTx.ProofDifficulty memory proofDifficulty)
|
|
419
|
+
{
|
|
420
|
+
proofDifficulty.currentEpochDifficulty = relay
|
|
421
|
+
.getCurrentEpochDifficulty();
|
|
422
|
+
proofDifficulty.previousEpochDifficulty = relay
|
|
423
|
+
.getPrevEpochDifficulty();
|
|
424
|
+
proofDifficulty.difficultyFactor = txProofDifficultyFactor;
|
|
425
|
+
|
|
426
|
+
return proofDifficulty;
|
|
427
|
+
}
|
|
428
|
+
|
|
416
429
|
/// @notice Used by the depositor to reveal information about their P2(W)SH
|
|
417
430
|
/// Bitcoin deposit to the Bridge on Ethereum chain. The off-chain
|
|
418
431
|
/// wallet listens for revealed deposit events and may decide to
|
|
@@ -608,7 +621,11 @@ contract Bridge is Ownable {
|
|
|
608
621
|
// can assume the transaction happened on Bitcoin chain and has
|
|
609
622
|
// a sufficient number of confirmations as determined by
|
|
610
623
|
// `txProofDifficultyFactor` constant.
|
|
611
|
-
bytes32 sweepTxHash =
|
|
624
|
+
bytes32 sweepTxHash = BitcoinTx.validateProof(
|
|
625
|
+
sweepTx,
|
|
626
|
+
sweepProof,
|
|
627
|
+
proofDifficultyContext()
|
|
628
|
+
);
|
|
612
629
|
|
|
613
630
|
// Process sweep transaction output and extract its target wallet
|
|
614
631
|
// public key hash and value.
|
|
@@ -712,103 +729,6 @@ contract Bridge is Ownable {
|
|
|
712
729
|
// TODO: Handle deposits having `vault` set.
|
|
713
730
|
}
|
|
714
731
|
|
|
715
|
-
/// @notice Validates the SPV proof of the Bitcoin transaction.
|
|
716
|
-
/// Reverts in case the validation or proof verification fail.
|
|
717
|
-
/// @param txInfo Bitcoin transaction data
|
|
718
|
-
/// @param proof Bitcoin proof data
|
|
719
|
-
/// @return txHash Proven 32-byte transaction hash.
|
|
720
|
-
function validateBitcoinTxProof(
|
|
721
|
-
BitcoinTx.Info calldata txInfo,
|
|
722
|
-
BitcoinTx.Proof calldata proof
|
|
723
|
-
) internal view returns (bytes32 txHash) {
|
|
724
|
-
require(
|
|
725
|
-
txInfo.inputVector.validateVin(),
|
|
726
|
-
"Invalid input vector provided"
|
|
727
|
-
);
|
|
728
|
-
require(
|
|
729
|
-
txInfo.outputVector.validateVout(),
|
|
730
|
-
"Invalid output vector provided"
|
|
731
|
-
);
|
|
732
|
-
|
|
733
|
-
txHash = abi
|
|
734
|
-
.encodePacked(
|
|
735
|
-
txInfo.version,
|
|
736
|
-
txInfo.inputVector,
|
|
737
|
-
txInfo.outputVector,
|
|
738
|
-
txInfo.locktime
|
|
739
|
-
)
|
|
740
|
-
.hash256View();
|
|
741
|
-
|
|
742
|
-
checkProofFromTxHash(txHash, proof);
|
|
743
|
-
|
|
744
|
-
return txHash;
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
/// @notice Checks the given Bitcoin transaction hash against the SPV proof.
|
|
748
|
-
/// Reverts in case the check fails.
|
|
749
|
-
/// @param txHash 32-byte hash of the checked Bitcoin transaction
|
|
750
|
-
/// @param proof Bitcoin proof data
|
|
751
|
-
function checkProofFromTxHash(
|
|
752
|
-
bytes32 txHash,
|
|
753
|
-
BitcoinTx.Proof calldata proof
|
|
754
|
-
) internal view {
|
|
755
|
-
require(
|
|
756
|
-
txHash.prove(
|
|
757
|
-
proof.bitcoinHeaders.extractMerkleRootLE(),
|
|
758
|
-
proof.merkleProof,
|
|
759
|
-
proof.txIndexInBlock
|
|
760
|
-
),
|
|
761
|
-
"Tx merkle proof is not valid for provided header and tx hash"
|
|
762
|
-
);
|
|
763
|
-
|
|
764
|
-
evaluateProofDifficulty(proof.bitcoinHeaders);
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
/// @notice Evaluates the given Bitcoin proof difficulty against the actual
|
|
768
|
-
/// Bitcoin chain difficulty provided by the relay oracle.
|
|
769
|
-
/// Reverts in case the evaluation fails.
|
|
770
|
-
/// @param bitcoinHeaders Bitcoin headers chain being part of the SPV
|
|
771
|
-
/// proof. Used to extract the observed proof difficulty
|
|
772
|
-
function evaluateProofDifficulty(bytes memory bitcoinHeaders)
|
|
773
|
-
internal
|
|
774
|
-
view
|
|
775
|
-
{
|
|
776
|
-
uint256 requestedDiff = 0;
|
|
777
|
-
uint256 currentDiff = relay.getCurrentEpochDifficulty();
|
|
778
|
-
uint256 previousDiff = relay.getPrevEpochDifficulty();
|
|
779
|
-
uint256 firstHeaderDiff = bitcoinHeaders
|
|
780
|
-
.extractTarget()
|
|
781
|
-
.calculateDifficulty();
|
|
782
|
-
|
|
783
|
-
if (firstHeaderDiff == currentDiff) {
|
|
784
|
-
requestedDiff = currentDiff;
|
|
785
|
-
} else if (firstHeaderDiff == previousDiff) {
|
|
786
|
-
requestedDiff = previousDiff;
|
|
787
|
-
} else {
|
|
788
|
-
revert("Not at current or previous difficulty");
|
|
789
|
-
}
|
|
790
|
-
|
|
791
|
-
uint256 observedDiff = bitcoinHeaders.validateHeaderChain();
|
|
792
|
-
|
|
793
|
-
require(
|
|
794
|
-
observedDiff != ValidateSPV.getErrBadLength(),
|
|
795
|
-
"Invalid length of the headers chain"
|
|
796
|
-
);
|
|
797
|
-
require(
|
|
798
|
-
observedDiff != ValidateSPV.getErrInvalidChain(),
|
|
799
|
-
"Invalid headers chain"
|
|
800
|
-
);
|
|
801
|
-
require(
|
|
802
|
-
observedDiff != ValidateSPV.getErrLowWork(),
|
|
803
|
-
"Insufficient work in a header"
|
|
804
|
-
);
|
|
805
|
-
|
|
806
|
-
require(
|
|
807
|
-
observedDiff >= requestedDiff * txProofDifficultyFactor,
|
|
808
|
-
"Insufficient accumulated difficulty in header chain"
|
|
809
|
-
);
|
|
810
|
-
}
|
|
811
|
-
|
|
812
732
|
/// @notice Processes the Bitcoin sweep transaction output vector by
|
|
813
733
|
/// extracting the single output and using it to gain additional
|
|
814
734
|
/// information required for further processing (e.g. value and
|
|
@@ -1271,9 +1191,10 @@ contract Bridge is Ownable {
|
|
|
1271
1191
|
// can assume the transaction happened on Bitcoin chain and has
|
|
1272
1192
|
// a sufficient number of confirmations as determined by
|
|
1273
1193
|
// `txProofDifficultyFactor` constant.
|
|
1274
|
-
bytes32 redemptionTxHash =
|
|
1194
|
+
bytes32 redemptionTxHash = BitcoinTx.validateProof(
|
|
1275
1195
|
redemptionTx,
|
|
1276
|
-
redemptionProof
|
|
1196
|
+
redemptionProof,
|
|
1197
|
+
proofDifficultyContext()
|
|
1277
1198
|
);
|
|
1278
1199
|
|
|
1279
1200
|
// Perform validation of the redemption transaction input. Specifically,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@keep-network/tbtc-v2",
|
|
3
|
-
"version": "0.1.1-dev.
|
|
3
|
+
"version": "0.1.1-dev.22+main.c25835616ce50ecd68c4421262fb4462cb716d0e",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"files": [
|
|
6
6
|
"artifacts/",
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
"ethereum-waffle": "^3.4.0",
|
|
50
50
|
"ethers": "^5.4.7",
|
|
51
51
|
"hardhat": "^2.6.4",
|
|
52
|
+
"hardhat-contract-sizer": "^2.5.0",
|
|
52
53
|
"hardhat-deploy": "^0.8.11",
|
|
53
54
|
"hardhat-gas-reporter": "^1.0.4",
|
|
54
55
|
"prettier": "^2.5.1",
|