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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/README.adoc +12 -0
  2. package/artifacts/TBTC.json +19 -18
  3. package/artifacts/TBTCToken.json +19 -18
  4. package/artifacts/VendingMachine.json +20 -19
  5. package/artifacts/solcInputs/f1a50b67569d88ee54efa3e22c6b484e.json +215 -0
  6. package/build/contracts/GovernanceUtils.sol/GovernanceUtils.dbg.json +1 -1
  7. package/build/contracts/GovernanceUtils.sol/GovernanceUtils.json +2 -2
  8. package/build/contracts/bank/Bank.sol/Bank.dbg.json +1 -1
  9. package/build/contracts/bank/Bank.sol/Bank.json +20 -2
  10. package/build/contracts/bridge/BitcoinTx.sol/BitcoinTx.dbg.json +4 -0
  11. package/build/contracts/bridge/BitcoinTx.sol/BitcoinTx.json +10 -0
  12. package/build/contracts/bridge/Bridge.sol/Bridge.dbg.json +1 -1
  13. package/build/contracts/bridge/Bridge.sol/Bridge.json +1743 -64
  14. package/build/contracts/bridge/BridgeState.sol/BridgeState.dbg.json +4 -0
  15. package/build/contracts/bridge/BridgeState.sol/BridgeState.json +10 -0
  16. package/build/contracts/bridge/Deposit.sol/Deposit.dbg.json +4 -0
  17. package/build/contracts/bridge/Deposit.sol/Deposit.json +72 -0
  18. package/build/contracts/bridge/EcdsaLib.sol/EcdsaLib.dbg.json +4 -0
  19. package/build/contracts/bridge/EcdsaLib.sol/EcdsaLib.json +10 -0
  20. package/build/contracts/bridge/Frauds.sol/Frauds.dbg.json +4 -0
  21. package/build/contracts/bridge/Frauds.sol/Frauds.json +138 -0
  22. package/build/contracts/bridge/IRelay.sol/IRelay.dbg.json +4 -0
  23. package/build/contracts/bridge/IRelay.sol/IRelay.json +37 -0
  24. package/build/contracts/bridge/MovingFunds.sol/MovingFunds.dbg.json +4 -0
  25. package/build/contracts/bridge/MovingFunds.sol/MovingFunds.json +48 -0
  26. package/build/contracts/bridge/Redeem.sol/OutboundTx.dbg.json +4 -0
  27. package/build/contracts/bridge/Redeem.sol/OutboundTx.json +10 -0
  28. package/build/contracts/bridge/Redeem.sol/Redeem.dbg.json +4 -0
  29. package/build/contracts/bridge/Redeem.sol/Redeem.json +110 -0
  30. package/build/contracts/bridge/Sweep.sol/Sweep.dbg.json +4 -0
  31. package/build/contracts/bridge/Sweep.sol/Sweep.json +30 -0
  32. package/build/contracts/bridge/VendingMachine.sol/VendingMachine.dbg.json +1 -1
  33. package/build/contracts/bridge/VendingMachine.sol/VendingMachine.json +2 -2
  34. package/build/contracts/bridge/Wallets.sol/Wallets.dbg.json +4 -0
  35. package/build/contracts/bridge/Wallets.sol/Wallets.json +138 -0
  36. package/build/contracts/token/TBTC.sol/TBTC.dbg.json +1 -1
  37. package/build/contracts/token/TBTC.sol/TBTC.json +2 -2
  38. package/build/contracts/vault/IVault.sol/IVault.dbg.json +1 -1
  39. package/build/contracts/vault/IVault.sol/IVault.json +19 -1
  40. package/build/contracts/vault/TBTCVault.sol/TBTCVault.dbg.json +1 -1
  41. package/build/contracts/vault/TBTCVault.sol/TBTCVault.json +36 -18
  42. package/contracts/GovernanceUtils.sol +1 -1
  43. package/contracts/bank/Bank.sol +34 -18
  44. package/contracts/bridge/BitcoinTx.sol +241 -0
  45. package/contracts/bridge/Bridge.sol +980 -123
  46. package/contracts/bridge/BridgeState.sol +172 -0
  47. package/contracts/bridge/Deposit.sol +247 -0
  48. package/contracts/bridge/EcdsaLib.sol +30 -0
  49. package/contracts/bridge/Frauds.sol +529 -0
  50. package/contracts/bridge/IRelay.sol +28 -0
  51. package/contracts/bridge/MovingFunds.sol +280 -0
  52. package/contracts/bridge/Redeem.sol +849 -0
  53. package/contracts/bridge/Sweep.sol +510 -0
  54. package/contracts/bridge/VendingMachine.sol +1 -1
  55. package/contracts/bridge/Wallets.sol +591 -0
  56. package/contracts/token/TBTC.sol +1 -1
  57. package/contracts/vault/IVault.sol +32 -10
  58. package/contracts/vault/TBTCVault.sol +20 -2
  59. package/package.json +28 -24
  60. package/artifacts/solcInputs/d71966212a658480bad5748ad85b1396.json +0 -116
@@ -0,0 +1,172 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ // ██████████████ ▐████▌ ██████████████
4
+ // ██████████████ ▐████▌ ██████████████
5
+ // ▐████▌ ▐████▌
6
+ // ▐████▌ ▐████▌
7
+ // ██████████████ ▐████▌ ██████████████
8
+ // ██████████████ ▐████▌ ██████████████
9
+ // ▐████▌ ▐████▌
10
+ // ▐████▌ ▐████▌
11
+ // ▐████▌ ▐████▌
12
+ // ▐████▌ ▐████▌
13
+ // ▐████▌ ▐████▌
14
+ // ▐████▌ ▐████▌
15
+
16
+ pragma solidity ^0.8.9;
17
+
18
+ import "./IRelay.sol";
19
+ import "./Deposit.sol";
20
+ import "./Redeem.sol";
21
+
22
+ import "../bank/Bank.sol";
23
+
24
+ library BridgeState {
25
+ struct Storage {
26
+ /// @notice The number of confirmations on the Bitcoin chain required to
27
+ /// successfully evaluate an SPV proof.
28
+ uint256 txProofDifficultyFactor;
29
+ /// TODO: Revisit whether it should be governable or not.
30
+ /// @notice Address of the Bank this Bridge belongs to.
31
+ Bank bank;
32
+ /// TODO: Make it governable.
33
+ /// @notice Bitcoin relay providing the current Bitcoin network
34
+ /// difficulty.
35
+ IRelay relay;
36
+ /// TODO: Revisit whether it should be governable or not.
37
+ /// @notice Address where the deposit and redemption treasury fees will
38
+ /// be sent to. Treasury takes part in the operators rewarding
39
+ /// process.
40
+ address treasury;
41
+ /// TODO: Make it governable.
42
+ /// @notice The minimal amount that can be requested to deposit.
43
+ /// Value of this parameter must take into account the value of
44
+ /// `depositTreasuryFeeDivisor` and `depositTxMaxFee`
45
+ /// parameters in order to make requests that can incur the
46
+ /// treasury and transaction fee and still satisfy the depositor.
47
+ uint64 depositDustThreshold;
48
+ /// TODO: Make it governable.
49
+ /// @notice Divisor used to compute the treasury fee taken from each
50
+ /// deposit and transferred to the treasury upon sweep proof
51
+ /// submission. That fee is computed as follows:
52
+ /// `treasuryFee = depositedAmount / depositTreasuryFeeDivisor`
53
+ /// For example, if the treasury fee needs to be 2% of each deposit,
54
+ /// the `depositTreasuryFeeDivisor` should be set to `50`
55
+ /// because `1/50 = 0.02 = 2%`.
56
+ uint64 depositTreasuryFeeDivisor;
57
+ /// TODO: Make it governable.
58
+ /// @notice Maximum amount of BTC transaction fee that can be incurred by
59
+ /// each swept deposit being part of the given sweep
60
+ /// transaction. If the maximum BTC transaction fee is exceeded,
61
+ /// such transaction is considered a fraud.
62
+ /// @dev This is a per-deposit input max fee for the sweep transaction.
63
+ uint64 depositTxMaxFee;
64
+ /// @notice 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
69
+ /// validating them before attempting to execute a sweep.
70
+ mapping(uint256 => Deposit.DepositRequest) deposits;
71
+ /// @notice Indicates if the vault with the given address is trusted or not.
72
+ /// Depositors can route their revealed deposits only to trusted
73
+ /// vaults and have trusted vaults notified about new deposits as
74
+ /// soon as these deposits get swept. Vaults not trusted by the
75
+ /// Bridge can still be used by Bank balance owners on their own
76
+ /// responsibility - anyone can approve their Bank balance to any
77
+ /// address.
78
+ mapping(address => bool) isVaultTrusted;
79
+ /// TODO: Make it governable.
80
+ /// @notice Maximum amount of the total BTC transaction fee that is
81
+ /// acceptable in a single moving funds transaction.
82
+ /// @dev This is a TOTAL max fee for the moving funds transaction. Note
83
+ /// that `depositTxMaxFee` is per single deposit and `redemptionTxMaxFee`
84
+ /// if per single redemption. `movingFundsTxMaxTotalFee` is a total
85
+ /// fee for the entire transaction.
86
+ uint64 movingFundsTxMaxTotalFee;
87
+ /// TODO: Make it governable.
88
+ /// @notice The minimal amount that can be requested for redemption.
89
+ /// Value of this parameter must take into account the value of
90
+ /// `redemptionTreasuryFeeDivisor` and `redemptionTxMaxFee`
91
+ /// parameters in order to make requests that can incur the
92
+ /// treasury and transaction fee and still satisfy the redeemer.
93
+ uint64 redemptionDustThreshold;
94
+ /// TODO: Make it governable.
95
+ /// @notice Divisor used to compute the treasury fee taken from each
96
+ /// redemption request and transferred to the treasury upon
97
+ /// successful request finalization. That fee is computed as follows:
98
+ /// `treasuryFee = requestedAmount / redemptionTreasuryFeeDivisor`
99
+ /// For example, if the treasury fee needs to be 2% of each
100
+ /// redemption request, the `redemptionTreasuryFeeDivisor` should
101
+ /// be set to `50` because `1/50 = 0.02 = 2%`.
102
+ uint64 redemptionTreasuryFeeDivisor;
103
+ /// TODO: Make it governable.
104
+ /// @notice Maximum amount of BTC transaction fee that can be incurred by
105
+ /// each redemption request being part of the given redemption
106
+ /// transaction. If the maximum BTC transaction fee is exceeded, such
107
+ /// transaction is considered a fraud.
108
+ /// @dev This is a per-redemption output max fee for the redemption transaction.
109
+ uint64 redemptionTxMaxFee;
110
+ /// TODO: Make it governable.
111
+ /// @notice Time after which the redemption request can be reported as
112
+ /// timed out. It is counted from the moment when the redemption
113
+ /// request was created via `requestRedemption` call. Reported
114
+ /// timed out requests are cancelled and locked TBTC is returned
115
+ /// to the redeemer in full amount.
116
+ uint256 redemptionTimeout;
117
+ /// @notice Collection of all pending redemption requests indexed by
118
+ /// redemption key built as
119
+ /// keccak256(walletPubKeyHash | redeemerOutputScript). The
120
+ /// walletPubKeyHash is the 20-byte wallet's public key hash
121
+ /// (computed using Bitcoin HASH160 over the compressed ECDSA
122
+ /// public key) and redeemerOutputScript is a Bitcoin script
123
+ /// (P2PKH, P2WPKH, P2SH or P2WSH) that will be used to lock
124
+ /// redeemed BTC as requested by the redeemer. Requests are added
125
+ /// to this mapping by the `requestRedemption` method (duplicates
126
+ /// not allowed) and are removed by one of the following methods:
127
+ /// - `submitRedemptionProof` in case the request was handled
128
+ /// successfully
129
+ /// - `notifyRedemptionTimeout` in case the request was reported
130
+ /// to be timed out
131
+ mapping(uint256 => Redeem.RedemptionRequest) pendingRedemptions;
132
+ /// @notice Collection of all timed out redemptions requests indexed by
133
+ /// redemption key built as
134
+ /// keccak256(walletPubKeyHash | redeemerOutputScript). The
135
+ /// walletPubKeyHash is the 20-byte wallet's public key hash
136
+ /// (computed using Bitcoin HASH160 over the compressed ECDSA
137
+ /// public key) and redeemerOutputScript is the Bitcoin script
138
+ /// (P2PKH, P2WPKH, P2SH or P2WSH) that is involved in the timed
139
+ /// out request. Timed out requests are stored in this mapping to
140
+ /// avoid slashing the wallets multiple times for the same timeout.
141
+ /// Only one method can add to this mapping:
142
+ /// - `notifyRedemptionTimeout` which puts the redemption key
143
+ /// to this mapping basing on a timed out request stored
144
+ /// previously in `pendingRedemptions` mapping.
145
+ mapping(uint256 => Redeem.RedemptionRequest) timedOutRedemptions;
146
+ /// @notice Collection of main UTXOs that are honestly spent indexed by
147
+ /// keccak256(fundingTxHash | fundingOutputIndex). The fundingTxHash
148
+ /// is bytes32 (ordered as in Bitcoin internally) and
149
+ /// fundingOutputIndex an uint32. A main UTXO is considered honestly
150
+ /// spent if it was used as an input of a transaction that have been
151
+ /// proven in the Bridge.
152
+ mapping(uint256 => bool) spentMainUTXOs;
153
+ }
154
+
155
+ // TODO: Is it the right place for this function? Should we move it to Bridge?
156
+ /// @notice Determines the current Bitcoin SPV proof difficulty context.
157
+ /// @return proofDifficulty Bitcoin proof difficulty context.
158
+ function proofDifficultyContext(Storage storage self)
159
+ internal
160
+ view
161
+ returns (BitcoinTx.ProofDifficulty memory proofDifficulty)
162
+ {
163
+ IRelay relay = self.relay;
164
+ proofDifficulty.currentEpochDifficulty = relay
165
+ .getCurrentEpochDifficulty();
166
+ proofDifficulty.previousEpochDifficulty = relay
167
+ .getPrevEpochDifficulty();
168
+ proofDifficulty.difficultyFactor = self.txProofDifficultyFactor;
169
+
170
+ return proofDifficulty;
171
+ }
172
+ }
@@ -0,0 +1,247 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ // ██████████████ ▐████▌ ██████████████
4
+ // ██████████████ ▐████▌ ██████████████
5
+ // ▐████▌ ▐████▌
6
+ // ▐████▌ ▐████▌
7
+ // ██████████████ ▐████▌ ██████████████
8
+ // ██████████████ ▐████▌ ██████████████
9
+ // ▐████▌ ▐████▌
10
+ // ▐████▌ ▐████▌
11
+ // ▐████▌ ▐████▌
12
+ // ▐████▌ ▐████▌
13
+ // ▐████▌ ▐████▌
14
+ // ▐████▌ ▐████▌
15
+
16
+ pragma solidity ^0.8.9;
17
+
18
+ import {BTCUtils} from "@keep-network/bitcoin-spv-sol/contracts/BTCUtils.sol";
19
+ import {BytesLib} from "@keep-network/bitcoin-spv-sol/contracts/BytesLib.sol";
20
+
21
+ import "./BitcoinTx.sol";
22
+ import "./BridgeState.sol";
23
+ import "./Wallets.sol";
24
+
25
+ library Deposit {
26
+ using Wallets for Wallets.Data;
27
+
28
+ using BTCUtils for bytes;
29
+ using BytesLib for bytes;
30
+
31
+ /// @notice Represents data which must be revealed by the depositor during
32
+ /// deposit reveal.
33
+ struct DepositRevealInfo {
34
+ // Index of the funding output belonging to the funding transaction.
35
+ uint32 fundingOutputIndex;
36
+ // Ethereum depositor address.
37
+ address depositor;
38
+ // The blinding factor as 8 bytes. Byte endianness doesn't matter
39
+ // as this factor is not interpreted as uint.
40
+ bytes8 blindingFactor;
41
+ // The compressed Bitcoin public key (33 bytes and 02 or 03 prefix)
42
+ // of the deposit's wallet hashed in the HASH160 Bitcoin opcode style.
43
+ bytes20 walletPubKeyHash;
44
+ // The compressed Bitcoin public key (33 bytes and 02 or 03 prefix)
45
+ // that can be used to make the deposit refund after the refund
46
+ // locktime passes. Hashed in the HASH160 Bitcoin opcode style.
47
+ bytes20 refundPubKeyHash;
48
+ // The refund locktime (4-byte LE). Interpreted according to locktime
49
+ // parsing rules described in:
50
+ // https://developer.bitcoin.org/devguide/transactions.html#locktime-and-sequence-number
51
+ // and used with OP_CHECKLOCKTIMEVERIFY opcode as described in:
52
+ // https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki
53
+ bytes4 refundLocktime;
54
+ // Address of the Bank vault to which the deposit is routed to.
55
+ // Optional, can be 0x0. The vault must be trusted by the Bridge.
56
+ address vault;
57
+ }
58
+
59
+ /// @notice Represents tBTC deposit request data.
60
+ struct DepositRequest {
61
+ // Ethereum depositor address.
62
+ address depositor;
63
+ // Deposit amount in satoshi.
64
+ uint64 amount;
65
+ // UNIX timestamp the deposit was revealed at.
66
+ uint32 revealedAt;
67
+ // Address of the Bank vault the deposit is routed to.
68
+ // Optional, can be 0x0.
69
+ address vault;
70
+ // Treasury TBTC fee in satoshi at the moment of deposit reveal.
71
+ uint64 treasuryFee;
72
+ // UNIX timestamp the deposit was swept at. Note this is not the
73
+ // time when the deposit was swept on the Bitcoin chain but actually
74
+ // the time when the sweep proof was delivered to the Ethereum chain.
75
+ uint32 sweptAt;
76
+ }
77
+
78
+ event DepositRevealed(
79
+ bytes32 fundingTxHash,
80
+ uint32 fundingOutputIndex,
81
+ address depositor,
82
+ uint64 amount,
83
+ bytes8 blindingFactor,
84
+ bytes20 walletPubKeyHash,
85
+ bytes20 refundPubKeyHash,
86
+ bytes4 refundLocktime,
87
+ address vault
88
+ );
89
+
90
+ /// @notice Used by the depositor to reveal information about their P2(W)SH
91
+ /// Bitcoin deposit to the Bridge on Ethereum chain. The off-chain
92
+ /// wallet listens for revealed deposit events and may decide to
93
+ /// include the revealed deposit in the next executed sweep.
94
+ /// Information about the Bitcoin deposit can be revealed before or
95
+ /// after the Bitcoin transaction with P2(W)SH deposit is mined on
96
+ /// the Bitcoin chain. Worth noting, the gas cost of this function
97
+ /// scales with the number of P2(W)SH transaction inputs and
98
+ /// outputs. The deposit may be routed to one of the trusted vaults.
99
+ /// When a deposit is routed to a vault, vault gets notified when
100
+ /// the deposit gets swept and it may execute the appropriate action.
101
+ /// @param fundingTx Bitcoin funding transaction data, see `BitcoinTx.Info`
102
+ /// @param reveal Deposit reveal data, see `RevealInfo struct
103
+ /// @dev Requirements:
104
+ /// - `reveal.walletPubKeyHash` must identify a `Live` wallet
105
+ /// - `reveal.vault` must be 0x0 or point to a trusted vault
106
+ /// - `reveal.fundingOutputIndex` must point to the actual P2(W)SH
107
+ /// output of the BTC deposit transaction
108
+ /// - `reveal.depositor` must be the Ethereum address used in the
109
+ /// P2(W)SH BTC deposit transaction,
110
+ /// - `reveal.blindingFactor` must be the blinding factor used in the
111
+ /// P2(W)SH BTC deposit transaction,
112
+ /// - `reveal.walletPubKeyHash` must be the wallet pub key hash used in
113
+ /// the P2(W)SH BTC deposit transaction,
114
+ /// - `reveal.refundPubKeyHash` must be the refund pub key hash used in
115
+ /// the P2(W)SH BTC deposit transaction,
116
+ /// - `reveal.refundLocktime` must be the refund locktime used in the
117
+ /// P2(W)SH BTC deposit transaction,
118
+ /// - BTC deposit for the given `fundingTxHash`, `fundingOutputIndex`
119
+ /// can be revealed only one time.
120
+ ///
121
+ /// If any of these requirements is not met, the wallet _must_ refuse
122
+ /// to sweep the deposit and the depositor has to wait until the
123
+ /// deposit script unlocks to receive their BTC back.
124
+ function revealDeposit(
125
+ BridgeState.Storage storage self,
126
+ Wallets.Data storage wallets,
127
+ BitcoinTx.Info calldata fundingTx,
128
+ DepositRevealInfo calldata reveal
129
+ ) external {
130
+ require(
131
+ wallets.registeredWallets[reveal.walletPubKeyHash].state ==
132
+ Wallets.WalletState.Live,
133
+ "Wallet is not in Live state"
134
+ );
135
+
136
+ require(
137
+ reveal.vault == address(0) || self.isVaultTrusted[reveal.vault],
138
+ "Vault is not trusted"
139
+ );
140
+
141
+ // TODO: Should we enforce a specific locktime at contract level?
142
+
143
+ bytes memory expectedScript = abi.encodePacked(
144
+ hex"14", // Byte length of depositor Ethereum address.
145
+ reveal.depositor,
146
+ hex"75", // OP_DROP
147
+ hex"08", // Byte length of blinding factor value.
148
+ reveal.blindingFactor,
149
+ hex"75", // OP_DROP
150
+ hex"76", // OP_DUP
151
+ hex"a9", // OP_HASH160
152
+ hex"14", // Byte length of a compressed Bitcoin public key hash.
153
+ reveal.walletPubKeyHash,
154
+ hex"87", // OP_EQUAL
155
+ hex"63", // OP_IF
156
+ hex"ac", // OP_CHECKSIG
157
+ hex"67", // OP_ELSE
158
+ hex"76", // OP_DUP
159
+ hex"a9", // OP_HASH160
160
+ hex"14", // Byte length of a compressed Bitcoin public key hash.
161
+ reveal.refundPubKeyHash,
162
+ hex"88", // OP_EQUALVERIFY
163
+ hex"04", // Byte length of refund locktime value.
164
+ reveal.refundLocktime,
165
+ hex"b1", // OP_CHECKLOCKTIMEVERIFY
166
+ hex"75", // OP_DROP
167
+ hex"ac", // OP_CHECKSIG
168
+ hex"68" // OP_ENDIF
169
+ );
170
+
171
+ bytes memory fundingOutput = fundingTx
172
+ .outputVector
173
+ .extractOutputAtIndex(reveal.fundingOutputIndex);
174
+ bytes memory fundingOutputHash = fundingOutput.extractHash();
175
+
176
+ if (fundingOutputHash.length == 20) {
177
+ // A 20-byte output hash is used by P2SH. That hash is constructed
178
+ // by applying OP_HASH160 on the locking script. A 20-byte output
179
+ // hash is used as well by P2PKH and P2WPKH (OP_HASH160 on the
180
+ // public key). However, since we compare the actual output hash
181
+ // with an expected locking script hash, this check will succeed only
182
+ // for P2SH transaction type with expected script hash value. For
183
+ // P2PKH and P2WPKH, it will fail on the output hash comparison with
184
+ // the expected locking script hash.
185
+ require(
186
+ fundingOutputHash.slice20(0) == expectedScript.hash160View(),
187
+ "Wrong 20-byte script hash"
188
+ );
189
+ } else if (fundingOutputHash.length == 32) {
190
+ // A 32-byte output hash is used by P2WSH. That hash is constructed
191
+ // by applying OP_SHA256 on the locking script.
192
+ require(
193
+ fundingOutputHash.toBytes32() == sha256(expectedScript),
194
+ "Wrong 32-byte script hash"
195
+ );
196
+ } else {
197
+ revert("Wrong script hash length");
198
+ }
199
+
200
+ // Resulting TX hash is in native Bitcoin little-endian format.
201
+ bytes32 fundingTxHash = abi
202
+ .encodePacked(
203
+ fundingTx.version,
204
+ fundingTx.inputVector,
205
+ fundingTx.outputVector,
206
+ fundingTx.locktime
207
+ )
208
+ .hash256View();
209
+
210
+ DepositRequest storage deposit = self.deposits[
211
+ uint256(
212
+ keccak256(
213
+ abi.encodePacked(fundingTxHash, reveal.fundingOutputIndex)
214
+ )
215
+ )
216
+ ];
217
+ require(deposit.revealedAt == 0, "Deposit already revealed");
218
+
219
+ uint64 fundingOutputAmount = fundingOutput.extractValue();
220
+
221
+ require(
222
+ fundingOutputAmount >= self.depositDustThreshold,
223
+ "Deposit amount too small"
224
+ );
225
+
226
+ deposit.amount = fundingOutputAmount;
227
+ deposit.depositor = reveal.depositor;
228
+ /* solhint-disable-next-line not-rely-on-time */
229
+ deposit.revealedAt = uint32(block.timestamp);
230
+ deposit.vault = reveal.vault;
231
+ deposit.treasuryFee = self.depositTreasuryFeeDivisor > 0
232
+ ? fundingOutputAmount / self.depositTreasuryFeeDivisor
233
+ : 0;
234
+
235
+ emit DepositRevealed(
236
+ fundingTxHash,
237
+ reveal.fundingOutputIndex,
238
+ reveal.depositor,
239
+ fundingOutputAmount,
240
+ reveal.blindingFactor,
241
+ reveal.walletPubKeyHash,
242
+ reveal.refundPubKeyHash,
243
+ reveal.refundLocktime,
244
+ reveal.vault
245
+ );
246
+ }
247
+ }
@@ -0,0 +1,30 @@
1
+ pragma solidity ^0.8.9;
2
+
3
+ import "@keep-network/bitcoin-spv-sol/contracts/BytesLib.sol";
4
+
5
+ library EcdsaLib {
6
+ using BytesLib for bytes;
7
+
8
+ /// @notice Converts public key X and Y coordinates (32-byte each) to a
9
+ /// compressed public key (33-byte). Compressed public key is X
10
+ /// coordinate prefixed with `02` or `03` based on the Y coordinate parity.
11
+ /// It is expected that the uncompressed public key is stripped
12
+ /// (i.e. it is not prefixed with `04`).
13
+ /// @param x Wallet's public key's X coordinate.
14
+ /// @param y Wallet's public key's Y coordinate.
15
+ /// @return Compressed public key (33-byte), prefixed with `02` or `03`.
16
+ function compressPublicKey(bytes32 x, bytes32 y)
17
+ internal
18
+ pure
19
+ returns (bytes memory)
20
+ {
21
+ bytes1 prefix;
22
+ if (uint256(y) % 2 == 0) {
23
+ prefix = hex"02";
24
+ } else {
25
+ prefix = hex"03";
26
+ }
27
+
28
+ return bytes.concat(prefix, x);
29
+ }
30
+ }