@keep-network/tbtc-v2 0.1.1-dev.34 → 0.1.1-dev.35

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 (31) hide show
  1. package/artifacts/TBTC.json +3 -3
  2. package/artifacts/TBTCToken.json +3 -3
  3. package/artifacts/VendingMachine.json +10 -10
  4. package/artifacts/solcInputs/{a67a2c11233ce411fb55a9f369ced323.json → 922339b8aca537314dc3d35162317588.json} +12 -6
  5. package/build/contracts/GovernanceUtils.sol/GovernanceUtils.dbg.json +1 -1
  6. package/build/contracts/bank/Bank.sol/Bank.dbg.json +1 -1
  7. package/build/contracts/bridge/BitcoinTx.sol/BitcoinTx.dbg.json +1 -1
  8. package/build/contracts/bridge/Bridge.sol/Bridge.dbg.json +1 -1
  9. package/build/contracts/bridge/Bridge.sol/Bridge.json +89 -113
  10. package/build/contracts/bridge/BridgeState.sol/BridgeState.dbg.json +1 -1
  11. package/build/contracts/bridge/BridgeState.sol/BridgeState.json +2 -2
  12. package/build/contracts/bridge/Deposit.sol/Deposit.dbg.json +1 -1
  13. package/build/contracts/bridge/Deposit.sol/Deposit.json +2 -2
  14. package/build/contracts/bridge/EcdsaLib.sol/EcdsaLib.dbg.json +1 -1
  15. package/build/contracts/bridge/Frauds.sol/Frauds.dbg.json +1 -1
  16. package/build/contracts/bridge/Frauds.sol/Frauds.json +2 -2
  17. package/build/contracts/bridge/IRelay.sol/IRelay.dbg.json +4 -0
  18. package/build/contracts/bridge/{Bridge.sol → IRelay.sol}/IRelay.json +1 -1
  19. package/build/contracts/bridge/Sweep.sol/Sweep.dbg.json +4 -0
  20. package/build/contracts/bridge/Sweep.sol/Sweep.json +48 -0
  21. package/build/contracts/bridge/VendingMachine.sol/VendingMachine.dbg.json +1 -1
  22. package/build/contracts/bridge/Wallets.sol/Wallets.dbg.json +1 -1
  23. package/build/contracts/token/TBTC.sol/TBTC.dbg.json +1 -1
  24. package/build/contracts/vault/IVault.sol/IVault.dbg.json +1 -1
  25. package/build/contracts/vault/TBTCVault.sol/TBTCVault.dbg.json +1 -1
  26. package/contracts/bridge/Bridge.sol +57 -506
  27. package/contracts/bridge/BridgeState.sol +50 -0
  28. package/contracts/bridge/IRelay.sol +28 -0
  29. package/contracts/bridge/Sweep.sol +510 -0
  30. package/package.json +1 -1
  31. package/build/contracts/bridge/Bridge.sol/IRelay.dbg.json +0 -4
@@ -19,26 +19,19 @@ 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
+
22
23
  import {IWalletOwner as EcdsaWalletOwner} from "@keep-network/ecdsa/contracts/api/IWalletOwner.sol";
23
24
 
24
- import "../bank/Bank.sol";
25
+ import "./IRelay.sol";
25
26
  import "./BridgeState.sol";
27
+ import "./Deposit.sol";
28
+ import "./Sweep.sol";
26
29
  import "./BitcoinTx.sol";
27
30
  import "./EcdsaLib.sol";
28
31
  import "./Wallets.sol";
29
32
  import "./Frauds.sol";
30
33
 
31
- /// @title Interface for the Bitcoin relay
32
- /// @notice Contains only the methods needed by tBTC v2. The Bitcoin relay
33
- /// provides the difficulty of the previous and current epoch. One
34
- /// difficulty epoch spans 2016 blocks.
35
- interface IRelay {
36
- /// @notice Returns the difficulty of the current epoch.
37
- function getCurrentEpochDifficulty() external view returns (uint256);
38
-
39
- /// @notice Returns the difficulty of the previous epoch.
40
- function getPrevEpochDifficulty() external view returns (uint256);
41
- }
34
+ import "../bank/Bank.sol";
42
35
 
43
36
  /// @title Bitcoin Bridge
44
37
  /// @notice Bridge manages BTC deposit and redemption flow and is increasing and
@@ -67,6 +60,7 @@ interface IRelay {
67
60
  contract Bridge is Ownable, EcdsaWalletOwner {
68
61
  using BridgeState for BridgeState.Storage;
69
62
  using Deposit for BridgeState.Storage;
63
+ using Sweep for BridgeState.Storage;
70
64
  using Frauds for Frauds.Data;
71
65
  using Wallets for Wallets.Data;
72
66
 
@@ -74,32 +68,6 @@ contract Bridge is Ownable, EcdsaWalletOwner {
74
68
  using BTCUtils for uint256;
75
69
  using BytesLib for bytes;
76
70
 
77
- /// @notice Represents an outcome of the sweep Bitcoin transaction
78
- /// inputs processing.
79
- struct SweepTxInputsInfo {
80
- // Sum of all inputs values i.e. all deposits and main UTXO value,
81
- // if present.
82
- uint256 inputsTotalValue;
83
- // Addresses of depositors who performed processed deposits. Ordered in
84
- // the same order as deposits inputs in the input vector. Size of this
85
- // array is either equal to the number of inputs (main UTXO doesn't
86
- // exist) or less by one (main UTXO exists and is pointed by one of
87
- // the inputs).
88
- address[] depositors;
89
- // Amounts of deposits corresponding to processed deposits. Ordered in
90
- // the same order as deposits inputs in the input vector. Size of this
91
- // array is either equal to the number of inputs (main UTXO doesn't
92
- // exist) or less by one (main UTXO exists and is pointed by one of
93
- // the inputs).
94
- uint256[] depositedAmounts;
95
- // Values of the treasury fee corresponding to processed deposits.
96
- // Ordered in the same order as deposits inputs in the input vector.
97
- // Size of this array is either equal to the number of inputs (main
98
- // UTXO doesn't exist) or less by one (main UTXO exists and is pointed
99
- // by one of the inputs).
100
- uint256[] treasuryFees;
101
- }
102
-
103
71
  /// @notice Represents a redemption request.
104
72
  struct RedemptionRequest {
105
73
  // ETH address of the redeemer who created the request.
@@ -133,33 +101,8 @@ contract Bridge is Ownable, EcdsaWalletOwner {
133
101
  uint64 changeValue;
134
102
  }
135
103
 
136
- /// @notice The number of confirmations on the Bitcoin chain required to
137
- /// successfully evaluate an SPV proof.
138
- uint256 public txProofDifficultyFactor;
139
-
140
- /// TODO: Revisit whether it should be governable or not.
141
- /// @notice Address of the Bank this Bridge belongs to.
142
- Bank public bank;
143
-
144
- /// TODO: Make it governable.
145
- /// @notice Handle to the Bitcoin relay.
146
- IRelay public relay;
147
-
148
- /// TODO: Revisit whether it should be governable or not.
149
- /// @notice Address where the redemptions treasury fees will be sent to.
150
- /// Treasury takes part in the operators rewarding process.
151
- address public treasury;
152
-
153
104
  BridgeState.Storage internal self;
154
105
 
155
- /// TODO: Make it governable.
156
- /// @notice Maximum amount of BTC transaction fee that can be incurred by
157
- /// each swept deposit being part of the given sweep
158
- /// transaction. If the maximum BTC transaction fee is exceeded,
159
- /// such transaction is considered a fraud.
160
- /// @dev This is a per-deposit input max fee for the sweep transaction.
161
- uint64 public depositTxMaxFee;
162
-
163
106
  /// TODO: Make it governable.
164
107
  /// @notice The minimal amount that can be requested for redemption.
165
108
  /// Value of this parameter must take into account the value of
@@ -203,14 +146,6 @@ contract Bridge is Ownable, EcdsaWalletOwner {
203
146
  /// for the entire transaction.
204
147
  uint64 public movingFundsTxMaxTotalFee;
205
148
 
206
- /// @notice Collection of main UTXOs that are honestly spent indexed by
207
- /// keccak256(fundingTxHash | fundingOutputIndex). The fundingTxHash
208
- /// is bytes32 (ordered as in Bitcoin internally) and
209
- /// fundingOutputIndex an uint32. A main UTXO is considered honestly
210
- /// spent if it was used as an input of a transaction that have been
211
- /// proven in the Bridge.
212
- mapping(uint256 => bool) public spentMainUTXOs;
213
-
214
149
  /// @notice Collection of all pending redemption requests indexed by
215
150
  /// redemption key built as
216
151
  /// keccak256(walletPubKeyHash | redeemerOutputScript). The
@@ -357,19 +292,19 @@ contract Bridge is Ownable, EcdsaWalletOwner {
357
292
  uint256 _txProofDifficultyFactor
358
293
  ) {
359
294
  require(_bank != address(0), "Bank address cannot be zero");
360
- bank = Bank(_bank);
295
+ self.bank = Bank(_bank);
361
296
 
362
297
  require(_relay != address(0), "Relay address cannot be zero");
363
- relay = IRelay(_relay);
298
+ self.relay = IRelay(_relay);
364
299
 
365
300
  require(_treasury != address(0), "Treasury address cannot be zero");
366
- treasury = _treasury;
301
+ self.treasury = _treasury;
367
302
 
368
- txProofDifficultyFactor = _txProofDifficultyFactor;
303
+ self.txProofDifficultyFactor = _txProofDifficultyFactor;
369
304
 
370
305
  // TODO: Revisit initial values.
371
306
  self.depositDustThreshold = 1000000; // 1000000 satoshi = 0.01 BTC
372
- depositTxMaxFee = 10000; // 10000 satoshi
307
+ self.depositTxMaxFee = 10000; // 10000 satoshi
373
308
  self.depositTreasuryFeeDivisor = 2000; // 1/2000 == 5bps == 0.05% == 0.0005
374
309
  redemptionDustThreshold = 1000000; // 1000000 satoshi = 0.01 BTC
375
310
  redemptionTreasuryFeeDivisor = 2000; // 1/2000 == 5bps == 0.05% == 0.0005
@@ -549,22 +484,6 @@ contract Bridge is Ownable, EcdsaWalletOwner {
549
484
  return wallets.activeWalletPubKeyHash;
550
485
  }
551
486
 
552
- /// @notice Determines the current Bitcoin SPV proof difficulty context.
553
- /// @return proofDifficulty Bitcoin proof difficulty context.
554
- function proofDifficultyContext()
555
- internal
556
- view
557
- returns (BitcoinTx.ProofDifficulty memory proofDifficulty)
558
- {
559
- proofDifficulty.currentEpochDifficulty = relay
560
- .getCurrentEpochDifficulty();
561
- proofDifficulty.previousEpochDifficulty = relay
562
- .getPrevEpochDifficulty();
563
- proofDifficulty.difficultyFactor = txProofDifficultyFactor;
564
-
565
- return proofDifficulty;
566
- }
567
-
568
487
  /// @notice Used by the depositor to reveal information about their P2(W)SH
569
488
  /// Bitcoin deposit to the Bridge on Ethereum chain. The off-chain
570
489
  /// wallet listens for revealed deposit events and may decide to
@@ -647,410 +566,7 @@ contract Bridge is Ownable, EcdsaWalletOwner {
647
566
  BitcoinTx.Proof calldata sweepProof,
648
567
  BitcoinTx.UTXO calldata mainUtxo
649
568
  ) external {
650
- // TODO: Fail early if the function call gets frontrunned. See discussion:
651
- // https://github.com/keep-network/tbtc-v2/pull/106#discussion_r801745204
652
-
653
- // The actual transaction proof is performed here. After that point, we
654
- // can assume the transaction happened on Bitcoin chain and has
655
- // a sufficient number of confirmations as determined by
656
- // `txProofDifficultyFactor` constant.
657
- bytes32 sweepTxHash = BitcoinTx.validateProof(
658
- sweepTx,
659
- sweepProof,
660
- proofDifficultyContext()
661
- );
662
-
663
- // Process sweep transaction output and extract its target wallet
664
- // public key hash and value.
665
- (
666
- bytes20 walletPubKeyHash,
667
- uint64 sweepTxOutputValue
668
- ) = processSweepTxOutput(sweepTx.outputVector);
669
-
670
- (
671
- Wallets.Wallet storage wallet,
672
- BitcoinTx.UTXO memory resolvedMainUtxo
673
- ) = resolveSweepingWallet(walletPubKeyHash, mainUtxo);
674
-
675
- // Process sweep transaction inputs and extract all information needed
676
- // to perform deposit bookkeeping.
677
- SweepTxInputsInfo memory inputsInfo = processSweepTxInputs(
678
- sweepTx.inputVector,
679
- resolvedMainUtxo
680
- );
681
-
682
- // Helper variable that will hold the sum of treasury fees paid by
683
- // all deposits.
684
- uint256 totalTreasuryFee = 0;
685
-
686
- // Determine the transaction fee that should be incurred by each deposit
687
- // and the indivisible remainder that should be additionally incurred
688
- // by the last deposit.
689
- (
690
- uint256 depositTxFee,
691
- uint256 depositTxFeeRemainder
692
- ) = sweepTxFeeDistribution(
693
- inputsInfo.inputsTotalValue,
694
- sweepTxOutputValue,
695
- inputsInfo.depositedAmounts.length
696
- );
697
-
698
- // Make sure the highest value of the deposit transaction fee does not
699
- // exceed the maximum value limited by the governable parameter.
700
- require(
701
- depositTxFee + depositTxFeeRemainder <= depositTxMaxFee,
702
- "Transaction fee is too high"
703
- );
704
-
705
- // Reduce each deposit amount by treasury fee and transaction fee.
706
- for (uint256 i = 0; i < inputsInfo.depositedAmounts.length; i++) {
707
- // The last deposit should incur the deposit transaction fee
708
- // remainder.
709
- uint256 depositTxFeeIncurred = i ==
710
- inputsInfo.depositedAmounts.length - 1
711
- ? depositTxFee + depositTxFeeRemainder
712
- : depositTxFee;
713
-
714
- // There is no need to check whether
715
- // `inputsInfo.depositedAmounts[i] - inputsInfo.treasuryFees[i] - txFee > 0`
716
- // since the `depositDustThreshold` should force that condition
717
- // to be always true.
718
- inputsInfo.depositedAmounts[i] =
719
- inputsInfo.depositedAmounts[i] -
720
- inputsInfo.treasuryFees[i] -
721
- depositTxFeeIncurred;
722
- totalTreasuryFee += inputsInfo.treasuryFees[i];
723
- }
724
-
725
- // Record this sweep data and assign them to the wallet public key hash
726
- // as new main UTXO. Transaction output index is always 0 as sweep
727
- // transaction always contains only one output.
728
- wallet.mainUtxoHash = keccak256(
729
- abi.encodePacked(sweepTxHash, uint32(0), sweepTxOutputValue)
730
- );
731
-
732
- emit DepositsSwept(walletPubKeyHash, sweepTxHash);
733
-
734
- // Update depositors balances in the Bank.
735
- bank.increaseBalances(
736
- inputsInfo.depositors,
737
- inputsInfo.depositedAmounts
738
- );
739
- // Pass the treasury fee to the treasury address.
740
- bank.increaseBalance(treasury, totalTreasuryFee);
741
-
742
- // TODO: Handle deposits having `vault` set.
743
- }
744
-
745
- /// @notice Resolves sweeping wallet based on the provided wallet public key
746
- /// hash. Validates the wallet state and current main UTXO, as
747
- /// currently known on the Ethereum chain.
748
- /// @param walletPubKeyHash public key hash of the wallet proving the sweep
749
- /// Bitcoin transaction.
750
- /// @param mainUtxo Data of the wallet's main UTXO, as currently known on
751
- /// the Ethereum chain. If no main UTXO exists for the given wallet,
752
- /// this parameter is ignored
753
- /// @dev Requirements:
754
- /// - Sweeping wallet must be either in Live or MovingFunds state.
755
- /// - If the main UTXO of the sweeping wallet exists in the storage,
756
- /// the passed `mainUTXO` parameter must be equal to the stored one.
757
- function resolveSweepingWallet(
758
- bytes20 walletPubKeyHash,
759
- BitcoinTx.UTXO calldata mainUtxo
760
- )
761
- internal
762
- returns (
763
- Wallets.Wallet storage wallet,
764
- BitcoinTx.UTXO memory resolvedMainUtxo
765
- )
766
- {
767
- wallet = wallets.registeredWallets[walletPubKeyHash];
768
-
769
- Wallets.WalletState walletState = wallet.state;
770
- require(
771
- walletState == Wallets.WalletState.Live ||
772
- walletState == Wallets.WalletState.MovingFunds,
773
- "Wallet must be in Live or MovingFunds state"
774
- );
775
-
776
- // Check if the main UTXO for given wallet exists. If so, validate
777
- // passed main UTXO data against the stored hash and use them for
778
- // further processing. If no main UTXO exists, use empty data.
779
- resolvedMainUtxo = BitcoinTx.UTXO(bytes32(0), 0, 0);
780
- bytes32 mainUtxoHash = wallet.mainUtxoHash;
781
- if (mainUtxoHash != bytes32(0)) {
782
- require(
783
- keccak256(
784
- abi.encodePacked(
785
- mainUtxo.txHash,
786
- mainUtxo.txOutputIndex,
787
- mainUtxo.txOutputValue
788
- )
789
- ) == mainUtxoHash,
790
- "Invalid main UTXO data"
791
- );
792
- resolvedMainUtxo = mainUtxo;
793
- }
794
- }
795
-
796
- /// @notice Processes the Bitcoin sweep transaction output vector by
797
- /// extracting the single output and using it to gain additional
798
- /// information required for further processing (e.g. value and
799
- /// wallet public key hash).
800
- /// @param sweepTxOutputVector Bitcoin sweep transaction output vector.
801
- /// This function assumes vector's structure is valid so it must be
802
- /// validated using e.g. `BTCUtils.validateVout` function before
803
- /// it is passed here
804
- /// @return walletPubKeyHash 20-byte wallet public key hash.
805
- /// @return value 8-byte sweep transaction output value.
806
- function processSweepTxOutput(bytes memory sweepTxOutputVector)
807
- internal
808
- pure
809
- returns (bytes20 walletPubKeyHash, uint64 value)
810
- {
811
- // To determine the total number of sweep transaction outputs, we need to
812
- // parse the compactSize uint (VarInt) the output vector is prepended by.
813
- // That compactSize uint encodes the number of vector elements using the
814
- // format presented in:
815
- // https://developer.bitcoin.org/reference/transactions.html#compactsize-unsigned-integers
816
- // We don't need asserting the compactSize uint is parseable since it
817
- // was already checked during `validateVout` validation.
818
- // See `BitcoinTx.outputVector` docs for more details.
819
- (, uint256 outputsCount) = sweepTxOutputVector.parseVarInt();
820
- require(
821
- outputsCount == 1,
822
- "Sweep transaction must have a single output"
823
- );
824
-
825
- bytes memory output = sweepTxOutputVector.extractOutputAtIndex(0);
826
- value = output.extractValue();
827
- bytes memory walletPubKeyHashBytes = output.extractHash();
828
- // The sweep transaction output should always be P2PKH or P2WPKH.
829
- // In both cases, the wallet public key hash should be 20 bytes length.
830
- require(
831
- walletPubKeyHashBytes.length == 20,
832
- "Wallet public key hash should have 20 bytes"
833
- );
834
- /* solhint-disable-next-line no-inline-assembly */
835
- assembly {
836
- walletPubKeyHash := mload(add(walletPubKeyHashBytes, 32))
837
- }
838
-
839
- return (walletPubKeyHash, value);
840
- }
841
-
842
- /// @notice Processes the Bitcoin sweep transaction input vector. It
843
- /// extracts each input and tries to obtain associated deposit or
844
- /// main UTXO data, depending on the input type. Reverts
845
- /// if one of the inputs cannot be recognized as a pointer to a
846
- /// revealed deposit or expected main UTXO.
847
- /// This function also marks each processed deposit as swept.
848
- /// @param sweepTxInputVector Bitcoin sweep transaction input vector.
849
- /// This function assumes vector's structure is valid so it must be
850
- /// validated using e.g. `BTCUtils.validateVin` function before
851
- /// it is passed here
852
- /// @param mainUtxo Data of the wallet's main UTXO. If no main UTXO
853
- /// exists for the given the wallet, this parameter's fields should
854
- /// be zeroed to bypass the main UTXO validation
855
- /// @return info Outcomes of the processing.
856
- function processSweepTxInputs(
857
- bytes memory sweepTxInputVector,
858
- BitcoinTx.UTXO memory mainUtxo
859
- ) internal returns (SweepTxInputsInfo memory info) {
860
- // If the passed `mainUtxo` parameter's values are zeroed, the main UTXO
861
- // for the given wallet doesn't exist and it is not expected to be
862
- // included in the sweep transaction input vector.
863
- bool mainUtxoExpected = mainUtxo.txHash != bytes32(0);
864
- bool mainUtxoFound = false;
865
-
866
- // Determining the total number of sweep transaction inputs in the same
867
- // way as for number of outputs. See `BitcoinTx.inputVector` docs for
868
- // more details.
869
- (
870
- uint256 inputsCompactSizeUintLength,
871
- uint256 inputsCount
872
- ) = sweepTxInputVector.parseVarInt();
873
-
874
- // To determine the first input starting index, we must jump over
875
- // the compactSize uint which prepends the input vector. One byte
876
- // must be added because `BtcUtils.parseVarInt` does not include
877
- // compactSize uint tag in the returned length.
878
- //
879
- // For >= 0 && <= 252, `BTCUtils.determineVarIntDataLengthAt`
880
- // returns `0`, so we jump over one byte of compactSize uint.
881
- //
882
- // For >= 253 && <= 0xffff there is `0xfd` tag,
883
- // `BTCUtils.determineVarIntDataLengthAt` returns `2` (no
884
- // tag byte included) so we need to jump over 1+2 bytes of
885
- // compactSize uint.
886
- //
887
- // Please refer `BTCUtils` library and compactSize uint
888
- // docs in `BitcoinTx` library for more details.
889
- uint256 inputStartingIndex = 1 + inputsCompactSizeUintLength;
890
-
891
- // Determine the swept deposits count. If main UTXO is NOT expected,
892
- // all inputs should be deposits. If main UTXO is expected, one input
893
- // should point to that main UTXO.
894
- info.depositors = new address[](
895
- !mainUtxoExpected ? inputsCount : inputsCount - 1
896
- );
897
- info.depositedAmounts = new uint256[](info.depositors.length);
898
- info.treasuryFees = new uint256[](info.depositors.length);
899
-
900
- // Initialize helper variables.
901
- uint256 processedDepositsCount = 0;
902
-
903
- // Inputs processing loop.
904
- for (uint256 i = 0; i < inputsCount; i++) {
905
- (
906
- bytes32 outpointTxHash,
907
- uint32 outpointIndex,
908
- uint256 inputLength
909
- ) = parseTxInputAt(sweepTxInputVector, inputStartingIndex);
910
-
911
- Deposit.Request storage deposit = self.deposits[
912
- uint256(
913
- keccak256(abi.encodePacked(outpointTxHash, outpointIndex))
914
- )
915
- ];
916
-
917
- if (deposit.revealedAt != 0) {
918
- // If we entered here, that means the input was identified as
919
- // a revealed deposit.
920
- require(deposit.sweptAt == 0, "Deposit already swept");
921
-
922
- if (processedDepositsCount == info.depositors.length) {
923
- // If this condition is true, that means a deposit input
924
- // took place of an expected main UTXO input.
925
- // In other words, there is no expected main UTXO
926
- // input and all inputs come from valid, revealed deposits.
927
- revert(
928
- "Expected main UTXO not present in sweep transaction inputs"
929
- );
930
- }
931
-
932
- /* solhint-disable-next-line not-rely-on-time */
933
- deposit.sweptAt = uint32(block.timestamp);
934
-
935
- info.depositors[processedDepositsCount] = deposit.depositor;
936
- info.depositedAmounts[processedDepositsCount] = deposit.amount;
937
- info.inputsTotalValue += info.depositedAmounts[
938
- processedDepositsCount
939
- ];
940
- info.treasuryFees[processedDepositsCount] = deposit.treasuryFee;
941
-
942
- processedDepositsCount++;
943
- } else if (
944
- mainUtxoExpected != mainUtxoFound &&
945
- mainUtxo.txHash == outpointTxHash
946
- ) {
947
- // If we entered here, that means the input was identified as
948
- // the expected main UTXO.
949
- info.inputsTotalValue += mainUtxo.txOutputValue;
950
- mainUtxoFound = true;
951
-
952
- // Main UTXO used as an input, mark it as spent.
953
- spentMainUTXOs[
954
- uint256(
955
- keccak256(
956
- abi.encodePacked(outpointTxHash, outpointIndex)
957
- )
958
- )
959
- ] = true;
960
- } else {
961
- revert("Unknown input type");
962
- }
963
-
964
- // Make the `inputStartingIndex` pointing to the next input by
965
- // increasing it by current input's length.
966
- inputStartingIndex += inputLength;
967
- }
968
-
969
- // Construction of the input processing loop guarantees that:
970
- // `processedDepositsCount == info.depositors.length == info.depositedAmounts.length`
971
- // is always true at this point. We just use the first variable
972
- // to assert the total count of swept deposit is bigger than zero.
973
- require(
974
- processedDepositsCount > 0,
975
- "Sweep transaction must process at least one deposit"
976
- );
977
-
978
- // Assert the main UTXO was used as one of current sweep's inputs if
979
- // it was actually expected.
980
- require(
981
- mainUtxoExpected == mainUtxoFound,
982
- "Expected main UTXO not present in sweep transaction inputs"
983
- );
984
-
985
- return info;
986
- }
987
-
988
- /// @notice Parses a Bitcoin transaction input starting at the given index.
989
- /// @param inputVector Bitcoin transaction input vector
990
- /// @param inputStartingIndex Index the given input starts at
991
- /// @return outpointTxHash 32-byte hash of the Bitcoin transaction which is
992
- /// pointed in the given input's outpoint.
993
- /// @return outpointIndex 4-byte index of the Bitcoin transaction output
994
- /// which is pointed in the given input's outpoint.
995
- /// @return inputLength Byte length of the given input.
996
- /// @dev This function assumes vector's structure is valid so it must be
997
- /// validated using e.g. `BTCUtils.validateVin` function before it
998
- /// is passed here.
999
- function parseTxInputAt(
1000
- bytes memory inputVector,
1001
- uint256 inputStartingIndex
1002
- )
1003
- internal
1004
- pure
1005
- returns (
1006
- bytes32 outpointTxHash,
1007
- uint32 outpointIndex,
1008
- uint256 inputLength
1009
- )
1010
- {
1011
- outpointTxHash = inputVector.extractInputTxIdLeAt(inputStartingIndex);
1012
-
1013
- outpointIndex = BTCUtils.reverseUint32(
1014
- uint32(inputVector.extractTxIndexLeAt(inputStartingIndex))
1015
- );
1016
-
1017
- inputLength = inputVector.determineInputLengthAt(inputStartingIndex);
1018
-
1019
- return (outpointTxHash, outpointIndex, inputLength);
1020
- }
1021
-
1022
- /// @notice Determines the distribution of the sweep transaction fee
1023
- /// over swept deposits.
1024
- /// @param sweepTxInputsTotalValue Total value of all sweep transaction inputs.
1025
- /// @param sweepTxOutputValue Value of the sweep transaction output.
1026
- /// @param depositsCount Count of the deposits swept by the sweep transaction.
1027
- /// @return depositTxFee Transaction fee per deposit determined by evenly
1028
- /// spreading the divisible part of the sweep transaction fee
1029
- /// over all deposits.
1030
- /// @return depositTxFeeRemainder The indivisible part of the sweep
1031
- /// transaction fee than cannot be distributed over all deposits.
1032
- /// @dev It is up to the caller to decide how the remainder should be
1033
- /// counted in. This function only computes its value.
1034
- function sweepTxFeeDistribution(
1035
- uint256 sweepTxInputsTotalValue,
1036
- uint256 sweepTxOutputValue,
1037
- uint256 depositsCount
1038
- )
1039
- internal
1040
- pure
1041
- returns (uint256 depositTxFee, uint256 depositTxFeeRemainder)
1042
- {
1043
- // The sweep transaction fee is just the difference between inputs
1044
- // amounts sum and the output amount.
1045
- uint256 sweepTxFee = sweepTxInputsTotalValue - sweepTxOutputValue;
1046
- // Compute the indivisible remainder that remains after dividing the
1047
- // sweep transaction fee over all deposits evenly.
1048
- depositTxFeeRemainder = sweepTxFee % depositsCount;
1049
- // Compute the transaction fee per deposit by dividing the sweep
1050
- // transaction fee (reduced by the remainder) by the number of deposits.
1051
- depositTxFee = (sweepTxFee - depositTxFeeRemainder) / depositsCount;
1052
-
1053
- return (depositTxFee, depositTxFeeRemainder);
569
+ self.submitSweepProof(wallets, sweepTx, sweepProof, mainUtxo);
1054
570
  }
1055
571
 
1056
572
  /// @notice Submits a fraud challenge indicating that a UTXO being under
@@ -1155,11 +671,11 @@ contract Bridge is Ownable, EcdsaWalletOwner {
1155
671
 
1156
672
  // Check that the UTXO key identifies a correctly spent UTXO.
1157
673
  require(
1158
- self.deposits[utxoKey].sweptAt > 0 || spentMainUTXOs[utxoKey],
674
+ self.deposits[utxoKey].sweptAt > 0 || self.spentMainUTXOs[utxoKey],
1159
675
  "Spent UTXO not found among correctly spent UTXOs"
1160
676
  );
1161
677
 
1162
- frauds.defeatChallenge(walletPublicKey, preimage, treasury);
678
+ frauds.defeatChallenge(walletPublicKey, preimage, self.treasury);
1163
679
  }
1164
680
 
1165
681
  /// @notice Notifies about defeat timeout for the given fraud challenge.
@@ -1381,7 +897,7 @@ contract Bridge is Ownable, EcdsaWalletOwner {
1381
897
  txMaxFee
1382
898
  );
1383
899
 
1384
- bank.transferBalanceFrom(msg.sender, address(this), amount);
900
+ self.bank.transferBalanceFrom(msg.sender, address(this), amount);
1385
901
  }
1386
902
 
1387
903
  /// @notice Used by the wallet to prove the BTC redemption transaction
@@ -1445,7 +961,7 @@ contract Bridge is Ownable, EcdsaWalletOwner {
1445
961
  bytes32 redemptionTxHash = BitcoinTx.validateProof(
1446
962
  redemptionTx,
1447
963
  redemptionProof,
1448
- proofDifficultyContext()
964
+ self.proofDifficultyContext()
1449
965
  );
1450
966
 
1451
967
  // Process the redemption transaction input. Specifically, check if it
@@ -1495,8 +1011,8 @@ contract Bridge is Ownable, EcdsaWalletOwner {
1495
1011
 
1496
1012
  emit RedemptionsCompleted(walletPubKeyHash, redemptionTxHash);
1497
1013
 
1498
- bank.decreaseBalance(outputsInfo.totalBurnableValue);
1499
- bank.transferBalance(treasury, outputsInfo.totalTreasuryFee);
1014
+ self.bank.decreaseBalance(outputsInfo.totalBurnableValue);
1015
+ self.bank.transferBalance(self.treasury, outputsInfo.totalTreasuryFee);
1500
1016
  }
1501
1017
 
1502
1018
  /// @notice Checks whether an outbound Bitcoin transaction performed from
@@ -1552,7 +1068,7 @@ contract Bridge is Ownable, EcdsaWalletOwner {
1552
1068
  );
1553
1069
 
1554
1070
  // Main UTXO used as an input, mark it as spent.
1555
- spentMainUTXOs[
1071
+ self.spentMainUTXOs[
1556
1072
  uint256(
1557
1073
  keccak256(
1558
1074
  abi.encodePacked(mainUtxo.txHash, mainUtxo.txOutputIndex)
@@ -1877,7 +1393,7 @@ contract Bridge is Ownable, EcdsaWalletOwner {
1877
1393
  emit RedemptionTimedOut(walletPubKeyHash, redeemerOutputScript);
1878
1394
 
1879
1395
  // Return the requested amount of tokens to the redeemer
1880
- bank.transferBalance(request.redeemer, request.requestedAmount);
1396
+ self.bank.transferBalance(request.redeemer, request.requestedAmount);
1881
1397
  }
1882
1398
 
1883
1399
  /// @notice Used by the wallet to prove the BTC moving funds transaction
@@ -1938,7 +1454,7 @@ contract Bridge is Ownable, EcdsaWalletOwner {
1938
1454
  bytes32 movingFundsTxHash = BitcoinTx.validateProof(
1939
1455
  movingFundsTx,
1940
1456
  movingFundsProof,
1941
- proofDifficultyContext()
1457
+ self.proofDifficultyContext()
1942
1458
  );
1943
1459
 
1944
1460
  // Process the moving funds transaction input. Specifically, check if
@@ -2120,6 +1636,14 @@ contract Bridge is Ownable, EcdsaWalletOwner {
2120
1636
  return (targetWalletsHash, outputsTotalValue);
2121
1637
  }
2122
1638
 
1639
+ /// @return bank Address of the Bank the Bridge belongs to.
1640
+ /// @return relay Address of the Bitcoin relay providing the current Bitcoin
1641
+ /// network difficulty.
1642
+ function getContracts() external view returns (Bank bank, IRelay relay) {
1643
+ bank = self.bank;
1644
+ relay = self.relay;
1645
+ }
1646
+
2123
1647
  /// @notice Returns the current values of Bridge deposit parameters.
2124
1648
  /// @return depositDustThreshold The minimal amount that can be requested
2125
1649
  /// to deposit. Value of this parameter must take into account the
@@ -2133,13 +1657,30 @@ contract Bridge is Ownable, EcdsaWalletOwner {
2133
1657
  /// For example, if the treasury fee needs to be 2% of each deposit,
2134
1658
  /// the `depositTreasuryFeeDivisor` should be set to `50`
2135
1659
  /// because `1/50 = 0.02 = 2%`.
1660
+ /// @return depositTxMaxFee Maximum amount of BTC transaction fee that can
1661
+ /// be incurred by each swept deposit being part of the given sweep
1662
+ /// transaction. If the maximum BTC transaction fee is exceeded,
1663
+ /// such transaction is considered a fraud.
1664
+ /// @return treasury Address where the deposit treasury fees will be
1665
+ /// sent to. Treasury takes part in the operators rewarding process.
1666
+ /// @return txProofDifficultyFactor The number of confirmations on the
1667
+ /// Bitcoin chain required to successfully evaluate an SPV proof.
2136
1668
  function depositParameters()
2137
1669
  external
2138
1670
  view
2139
- returns (uint64 depositDustThreshold, uint64 depositTreasuryFeeDivisor)
1671
+ returns (
1672
+ uint64 depositDustThreshold,
1673
+ uint64 depositTreasuryFeeDivisor,
1674
+ uint64 depositTxMaxFee,
1675
+ address treasury,
1676
+ uint256 txProofDifficultyFactor
1677
+ )
2140
1678
  {
2141
1679
  depositDustThreshold = self.depositDustThreshold;
2142
1680
  depositTreasuryFeeDivisor = self.depositTreasuryFeeDivisor;
1681
+ depositTxMaxFee = self.depositTxMaxFee;
1682
+ treasury = self.treasury;
1683
+ txProofDifficultyFactor = self.txProofDifficultyFactor;
2143
1684
  }
2144
1685
 
2145
1686
  /// @notice Indicates if the vault with the given address is trusted or not.
@@ -2167,4 +1708,14 @@ contract Bridge is Ownable, EcdsaWalletOwner {
2167
1708
  // TODO: rename to getDeposit?
2168
1709
  return self.deposits[depositKey];
2169
1710
  }
1711
+
1712
+ /// @notice Collection of main UTXOs that are honestly spent indexed by
1713
+ /// keccak256(fundingTxHash | fundingOutputIndex). The fundingTxHash
1714
+ /// is bytes32 (ordered as in Bitcoin internally) and
1715
+ /// fundingOutputIndex an uint32. A main UTXO is considered honestly
1716
+ /// spent if it was used as an input of a transaction that have been
1717
+ /// proven in the Bridge.
1718
+ function spentMainUTXOs(uint256 utxoKey) external view returns (bool) {
1719
+ return self.spentMainUTXOs[utxoKey];
1720
+ }
2170
1721
  }