@keep-network/tbtc-v2 0.1.1-dev.18 → 0.1.1-dev.19

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.
@@ -101,12 +101,40 @@ contract Bridge is Ownable {
101
101
  // Address of the Bank vault the deposit is routed to.
102
102
  // Optional, can be 0x0.
103
103
  address vault;
104
+ // Treasury TBTC fee in satoshi at the moment of deposit reveal.
105
+ uint64 treasuryFee;
104
106
  // UNIX timestamp the deposit was swept at. Note this is not the
105
107
  // time when the deposit was swept on the Bitcoin chain but actually
106
108
  // the time when the sweep proof was delivered to the Ethereum chain.
107
109
  uint32 sweptAt;
108
110
  }
109
111
 
112
+ /// @notice Represents an outcome of the sweep Bitcoin transaction
113
+ /// inputs processing.
114
+ struct SweepTxInputsInfo {
115
+ // Sum of all inputs values i.e. all deposits and main UTXO value,
116
+ // if present.
117
+ uint256 inputsTotalValue;
118
+ // Addresses of depositors who performed processed deposits. Ordered in
119
+ // the same order as deposits inputs in the input vector. Size of this
120
+ // array is either equal to the number of inputs (main UTXO doesn't
121
+ // exist) or less by one (main UTXO exists and is pointed by one of
122
+ // the inputs).
123
+ address[] depositors;
124
+ // Amounts of deposits corresponding to processed deposits. Ordered in
125
+ // the same order as deposits inputs in the input vector. Size of this
126
+ // array is either equal to the number of inputs (main UTXO doesn't
127
+ // exist) or less by one (main UTXO exists and is pointed by one of
128
+ // the inputs).
129
+ uint256[] depositedAmounts;
130
+ // Values of the treasury fee corresponding to processed deposits.
131
+ // Ordered in the same order as deposits inputs in the input vector.
132
+ // Size of this array is either equal to the number of inputs (main
133
+ // UTXO doesn't exist) or less by one (main UTXO exists and is pointed
134
+ // by one of the inputs).
135
+ uint256[] treasuryFees;
136
+ }
137
+
110
138
  /// @notice Represents a redemption request.
111
139
  struct RedemptionRequest {
112
140
  // ETH address of the redeemer who created the request.
@@ -187,6 +215,16 @@ contract Bridge is Ownable {
187
215
  /// Treasury takes part in the operators rewarding process.
188
216
  address public immutable treasury;
189
217
 
218
+ /// TODO: Make it governable.
219
+ /// @notice Divisor used to compute the treasury fee taken from each
220
+ /// deposit and transferred to the treasury upon sweep proof
221
+ /// submission. That fee is computed as follows:
222
+ /// `treasuryFee = depositedAmount / depositTreasuryFeeDivisor`
223
+ /// For example, if the treasury fee needs to be 2% of each deposit,
224
+ /// the `redemptionTreasuryFeeDivisor` should be set to `50`
225
+ /// because `1/50 = 0.02 = 2%`.
226
+ uint64 public depositTreasuryFeeDivisor;
227
+
190
228
  /// TODO: Make it governable.
191
229
  /// @notice The minimal amount that can be requested for redemption.
192
230
  /// Value of this parameter must take into account the value of
@@ -339,6 +377,7 @@ contract Bridge is Ownable {
339
377
  txProofDifficultyFactor = _txProofDifficultyFactor;
340
378
 
341
379
  // TODO: Revisit initial values.
380
+ depositTreasuryFeeDivisor = 2000; // 1/2000 == 5bps == 0.05% == 0.0005
342
381
  redemptionDustThreshold = 1000000; // 1000000 satoshi = 0.01 BTC
343
382
  redemptionTreasuryFeeDivisor = 2000; // 1/2000 == 5bps == 0.05% == 0.0005
344
383
  redemptionTxMaxFee = 1000; // 1000 satoshi
@@ -496,6 +535,9 @@ contract Bridge is Ownable {
496
535
  /* solhint-disable-next-line not-rely-on-time */
497
536
  deposit.revealedAt = uint32(block.timestamp);
498
537
  deposit.vault = reveal.vault;
538
+ deposit.treasuryFee = depositTreasuryFeeDivisor > 0
539
+ ? fundingOutputAmount / depositTreasuryFeeDivisor
540
+ : 0;
499
541
 
500
542
  emit DepositRevealed(
501
543
  fundingTxHash,
@@ -592,30 +634,39 @@ contract Bridge is Ownable {
592
634
  resolvedMainUtxo = mainUtxo;
593
635
  }
594
636
 
595
- // Process sweep transaction inputs and extract their value sum and
596
- // all information needed to perform deposit bookkeeping.
597
- (
598
- uint256 sweepTxInputsValue,
599
- address[] memory depositors,
600
- uint256[] memory depositedAmounts
601
- ) = processSweepTxInputs(sweepTx.inputVector, resolvedMainUtxo);
602
-
603
- // Compute the sweep transaction fee which is a difference between
604
- // inputs amounts sum and the output amount.
605
- // TODO: Check fee against max fee.
606
- uint256 fee = sweepTxInputsValue - sweepTxOutputValue;
607
- // Calculate fee share by dividing the total fee by deposits count.
637
+ // Process sweep transaction inputs and extract all information needed
638
+ // to perform deposit bookkeeping.
639
+ SweepTxInputsInfo memory inputsInfo = processSweepTxInputs(
640
+ sweepTx.inputVector,
641
+ resolvedMainUtxo
642
+ );
643
+
644
+ // Helper variable that will hold the sum of treasury fees paid by
645
+ // all deposits.
646
+ uint256 totalTreasuryFee = 0;
647
+
648
+ // Calculate the transaction fee per deposit by dividing the total
649
+ // transaction fee by deposits count. The total fee is just the
650
+ // difference between inputs amounts sum and the output amount.
608
651
  // TODO: Deal with precision loss by having the last depositor pay
609
- // the higher fee than others if there is a change, just like it has
610
- // been proposed for the redemption flow. See:
652
+ // the higher transaction fee than others if there is a change,
653
+ // just like it has been proposed in discussion:
611
654
  // https://github.com/keep-network/tbtc-v2/pull/128#discussion_r800555359.
612
- uint256 feeShare = fee / depositedAmounts.length;
613
- // Reduce each deposit amount by fee share value.
614
- for (uint256 i = 0; i < depositedAmounts.length; i++) {
615
- // We don't have to check if `feeShare` is bigger than the amount
616
- // since we have the dust threshold preventing against too small
617
- // deposits amounts.
618
- depositedAmounts[i] -= feeShare;
655
+ // TODO: Check txFee against max fee.
656
+ uint256 txFee = (inputsInfo.inputsTotalValue - sweepTxOutputValue) /
657
+ inputsInfo.depositedAmounts.length;
658
+
659
+ // Reduce each deposit amount by treasury fee and transaction fee.
660
+ for (uint256 i = 0; i < inputsInfo.depositedAmounts.length; i++) {
661
+ // There is no need to check whether
662
+ // `inputsInfo.depositedAmounts[i] - inputsInfo.treasuryFees[i] - txFee > 0`
663
+ // since the `depositDustThreshold` should force that condition
664
+ // to be always true.
665
+ inputsInfo.depositedAmounts[i] =
666
+ inputsInfo.depositedAmounts[i] -
667
+ inputsInfo.treasuryFees[i] -
668
+ txFee;
669
+ totalTreasuryFee += inputsInfo.treasuryFees[i];
619
670
  }
620
671
 
621
672
  // Record this sweep data and assign them to the wallet public key hash
@@ -628,7 +679,12 @@ contract Bridge is Ownable {
628
679
  emit DepositsSwept(walletPubKeyHash, sweepTxHash);
629
680
 
630
681
  // Update depositors balances in the Bank.
631
- bank.increaseBalances(depositors, depositedAmounts);
682
+ bank.increaseBalances(
683
+ inputsInfo.depositors,
684
+ inputsInfo.depositedAmounts
685
+ );
686
+ // Pass the treasury fee to the treasury address.
687
+ bank.increaseBalance(treasury, totalTreasuryFee);
632
688
 
633
689
  // TODO: Handle deposits having `vault` set.
634
690
  }
@@ -789,29 +845,11 @@ contract Bridge is Ownable {
789
845
  /// @param mainUtxo Data of the wallet's main UTXO. If no main UTXO
790
846
  /// exists for the given the wallet, this parameter's fields should
791
847
  /// be zeroed to bypass the main UTXO validation
792
- /// @return inputsTotalValue Sum of all inputs values i.e. all deposits and
793
- /// main UTXO value, if present.
794
- /// @return depositors Addresses of depositors who performed processed
795
- /// deposits. Ordered in the same order as deposits inputs in the
796
- /// input vector. Size of this array is either equal to the
797
- /// number of inputs (main UTXO doesn't exist) or less by one
798
- /// (main UTXO exists and is pointed by one of the inputs).
799
- /// @return depositedAmounts Amounts of deposits corresponding to processed
800
- /// deposits. Ordered in the same order as deposits inputs in the
801
- /// input vector. Size of this array is either equal to the
802
- /// number of inputs (main UTXO doesn't exist) or less by one
803
- /// (main UTXO exists and is pointed by one of the inputs).
848
+ /// @return info Outcomes of the processing.
804
849
  function processSweepTxInputs(
805
850
  bytes memory sweepTxInputVector,
806
851
  BitcoinTx.UTXO memory mainUtxo
807
- )
808
- internal
809
- returns (
810
- uint256 inputsTotalValue,
811
- address[] memory depositors,
812
- uint256[] memory depositedAmounts
813
- )
814
- {
852
+ ) internal returns (SweepTxInputsInfo memory info) {
815
853
  // If the passed `mainUtxo` parameter's values are zeroed, the main UTXO
816
854
  // for the given wallet doesn't exist and it is not expected to be
817
855
  // included in the sweep transaction input vector.
@@ -846,10 +884,11 @@ contract Bridge is Ownable {
846
884
  // Determine the swept deposits count. If main UTXO is NOT expected,
847
885
  // all inputs should be deposits. If main UTXO is expected, one input
848
886
  // should point to that main UTXO.
849
- depositors = new address[](
887
+ info.depositors = new address[](
850
888
  !mainUtxoExpected ? inputsCount : inputsCount - 1
851
889
  );
852
- depositedAmounts = new uint256[](depositors.length);
890
+ info.depositedAmounts = new uint256[](info.depositors.length);
891
+ info.treasuryFees = new uint256[](info.depositors.length);
853
892
 
854
893
  // Initialize helper variables.
855
894
  uint256 processedDepositsCount = 0;
@@ -873,7 +912,7 @@ contract Bridge is Ownable {
873
912
  // a revealed deposit.
874
913
  require(deposit.sweptAt == 0, "Deposit already swept");
875
914
 
876
- if (processedDepositsCount == depositors.length) {
915
+ if (processedDepositsCount == info.depositors.length) {
877
916
  // If this condition is true, that means a deposit input
878
917
  // took place of an expected main UTXO input.
879
918
  // In other words, there is no expected main UTXO
@@ -886,9 +925,12 @@ contract Bridge is Ownable {
886
925
  /* solhint-disable-next-line not-rely-on-time */
887
926
  deposit.sweptAt = uint32(block.timestamp);
888
927
 
889
- depositors[processedDepositsCount] = deposit.depositor;
890
- depositedAmounts[processedDepositsCount] = deposit.amount;
891
- inputsTotalValue += depositedAmounts[processedDepositsCount];
928
+ info.depositors[processedDepositsCount] = deposit.depositor;
929
+ info.depositedAmounts[processedDepositsCount] = deposit.amount;
930
+ info.inputsTotalValue += info.depositedAmounts[
931
+ processedDepositsCount
932
+ ];
933
+ info.treasuryFees[processedDepositsCount] = deposit.treasuryFee;
892
934
 
893
935
  processedDepositsCount++;
894
936
  } else if (
@@ -897,7 +939,7 @@ contract Bridge is Ownable {
897
939
  ) {
898
940
  // If we entered here, that means the input was identified as
899
941
  // the expected main UTXO.
900
- inputsTotalValue += mainUtxo.txOutputValue;
942
+ info.inputsTotalValue += mainUtxo.txOutputValue;
901
943
  mainUtxoFound = true;
902
944
  } else {
903
945
  revert("Unknown input type");
@@ -909,7 +951,7 @@ contract Bridge is Ownable {
909
951
  }
910
952
 
911
953
  // Construction of the input processing loop guarantees that:
912
- // `processedDepositsCount == depositors.length == depositedAmounts.length`
954
+ // `processedDepositsCount == info.depositors.length == info.depositedAmounts.length`
913
955
  // is always true at this point. We just use the first variable
914
956
  // to assert the total count of swept deposit is bigger than zero.
915
957
  require(
@@ -924,7 +966,7 @@ contract Bridge is Ownable {
924
966
  "Expected main UTXO not present in sweep transaction inputs"
925
967
  );
926
968
 
927
- return (inputsTotalValue, depositors, depositedAmounts);
969
+ return info;
928
970
  }
929
971
 
930
972
  /// @notice Parses a Bitcoin transaction input starting at the given index.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@keep-network/tbtc-v2",
3
- "version": "0.1.1-dev.18+main.c18c4c2c114e2a54c770d7224299cfdf50e62ca1",
3
+ "version": "0.1.1-dev.19+main.6afd5b941bb544214e7e77a28f5688e0df8b05ad",
4
4
  "license": "MIT",
5
5
  "files": [
6
6
  "artifacts/",