@keep-network/tbtc-v2 0.1.1-dev.16 → 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.
- package/artifacts/TBTC.json +3 -3
- package/artifacts/TBTCToken.json +3 -3
- package/artifacts/VendingMachine.json +10 -10
- package/artifacts/solcInputs/{3d68045732e072924745a5b701f4ad2a.json → ae21171227bd4056829d16d192693b7d.json} +2 -2
- 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/Bridge.sol/Bridge.dbg.json +1 -1
- package/build/contracts/bridge/Bridge.sol/Bridge.json +21 -3
- 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/Bridge.sol +114 -61
- package/package.json +1 -1
|
@@ -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,17 +215,33 @@ 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
|
-
/// Value of this parameter
|
|
193
|
-
///
|
|
194
|
-
///
|
|
230
|
+
/// Value of this parameter must take into account the value of
|
|
231
|
+
/// `redemptionTreasuryFeeDivisor` and `redemptionTxMaxFee`
|
|
232
|
+
/// parameters in order to make requests that can incur the
|
|
233
|
+
/// treasury and transaction fee and still satisfy the redeemer.
|
|
195
234
|
uint64 public redemptionDustThreshold;
|
|
196
235
|
|
|
197
236
|
/// TODO: Make it governable.
|
|
198
|
-
/// @notice
|
|
199
|
-
/// transferred to the treasury upon
|
|
200
|
-
|
|
237
|
+
/// @notice Divisor used to compute the treasury fee taken from each
|
|
238
|
+
/// redemption request and transferred to the treasury upon
|
|
239
|
+
/// successful request finalization. That fee is computed as follows:
|
|
240
|
+
/// `treasuryFee = requestedAmount / redemptionTreasuryFeeDivisor`
|
|
241
|
+
/// For example, if the treasury fee needs to be 2% of each
|
|
242
|
+
/// redemption request, the `redemptionTreasuryFeeDivisor` should
|
|
243
|
+
/// be set to `50` because `1/50 = 0.02 = 2%`.
|
|
244
|
+
uint64 public redemptionTreasuryFeeDivisor;
|
|
201
245
|
|
|
202
246
|
/// TODO: Make it governable.
|
|
203
247
|
/// @notice Maximum amount of BTC transaction fee that can be incurred by
|
|
@@ -333,8 +377,9 @@ contract Bridge is Ownable {
|
|
|
333
377
|
txProofDifficultyFactor = _txProofDifficultyFactor;
|
|
334
378
|
|
|
335
379
|
// TODO: Revisit initial values.
|
|
380
|
+
depositTreasuryFeeDivisor = 2000; // 1/2000 == 5bps == 0.05% == 0.0005
|
|
336
381
|
redemptionDustThreshold = 1000000; // 1000000 satoshi = 0.01 BTC
|
|
337
|
-
|
|
382
|
+
redemptionTreasuryFeeDivisor = 2000; // 1/2000 == 5bps == 0.05% == 0.0005
|
|
338
383
|
redemptionTxMaxFee = 1000; // 1000 satoshi
|
|
339
384
|
redemptionTimeout = 172800; // 48 hours
|
|
340
385
|
}
|
|
@@ -490,6 +535,9 @@ contract Bridge is Ownable {
|
|
|
490
535
|
/* solhint-disable-next-line not-rely-on-time */
|
|
491
536
|
deposit.revealedAt = uint32(block.timestamp);
|
|
492
537
|
deposit.vault = reveal.vault;
|
|
538
|
+
deposit.treasuryFee = depositTreasuryFeeDivisor > 0
|
|
539
|
+
? fundingOutputAmount / depositTreasuryFeeDivisor
|
|
540
|
+
: 0;
|
|
493
541
|
|
|
494
542
|
emit DepositRevealed(
|
|
495
543
|
fundingTxHash,
|
|
@@ -586,30 +634,39 @@ contract Bridge is Ownable {
|
|
|
586
634
|
resolvedMainUtxo = mainUtxo;
|
|
587
635
|
}
|
|
588
636
|
|
|
589
|
-
// Process sweep transaction inputs and extract
|
|
590
|
-
//
|
|
591
|
-
(
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
//
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
//
|
|
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.
|
|
602
651
|
// TODO: Deal with precision loss by having the last depositor pay
|
|
603
|
-
// the higher fee than others if there is a change,
|
|
604
|
-
//
|
|
652
|
+
// the higher transaction fee than others if there is a change,
|
|
653
|
+
// just like it has been proposed in discussion:
|
|
605
654
|
// https://github.com/keep-network/tbtc-v2/pull/128#discussion_r800555359.
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
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];
|
|
613
670
|
}
|
|
614
671
|
|
|
615
672
|
// Record this sweep data and assign them to the wallet public key hash
|
|
@@ -622,7 +679,12 @@ contract Bridge is Ownable {
|
|
|
622
679
|
emit DepositsSwept(walletPubKeyHash, sweepTxHash);
|
|
623
680
|
|
|
624
681
|
// Update depositors balances in the Bank.
|
|
625
|
-
bank.increaseBalances(
|
|
682
|
+
bank.increaseBalances(
|
|
683
|
+
inputsInfo.depositors,
|
|
684
|
+
inputsInfo.depositedAmounts
|
|
685
|
+
);
|
|
686
|
+
// Pass the treasury fee to the treasury address.
|
|
687
|
+
bank.increaseBalance(treasury, totalTreasuryFee);
|
|
626
688
|
|
|
627
689
|
// TODO: Handle deposits having `vault` set.
|
|
628
690
|
}
|
|
@@ -783,29 +845,11 @@ contract Bridge is Ownable {
|
|
|
783
845
|
/// @param mainUtxo Data of the wallet's main UTXO. If no main UTXO
|
|
784
846
|
/// exists for the given the wallet, this parameter's fields should
|
|
785
847
|
/// be zeroed to bypass the main UTXO validation
|
|
786
|
-
/// @return
|
|
787
|
-
/// main UTXO value, if present.
|
|
788
|
-
/// @return depositors Addresses of depositors who performed processed
|
|
789
|
-
/// deposits. Ordered in the same order as deposits inputs in the
|
|
790
|
-
/// input vector. Size of this array is either equal to the
|
|
791
|
-
/// number of inputs (main UTXO doesn't exist) or less by one
|
|
792
|
-
/// (main UTXO exists and is pointed by one of the inputs).
|
|
793
|
-
/// @return depositedAmounts Amounts of deposits corresponding to processed
|
|
794
|
-
/// deposits. Ordered in the same order as deposits inputs in the
|
|
795
|
-
/// input vector. Size of this array is either equal to the
|
|
796
|
-
/// number of inputs (main UTXO doesn't exist) or less by one
|
|
797
|
-
/// (main UTXO exists and is pointed by one of the inputs).
|
|
848
|
+
/// @return info Outcomes of the processing.
|
|
798
849
|
function processSweepTxInputs(
|
|
799
850
|
bytes memory sweepTxInputVector,
|
|
800
851
|
BitcoinTx.UTXO memory mainUtxo
|
|
801
|
-
)
|
|
802
|
-
internal
|
|
803
|
-
returns (
|
|
804
|
-
uint256 inputsTotalValue,
|
|
805
|
-
address[] memory depositors,
|
|
806
|
-
uint256[] memory depositedAmounts
|
|
807
|
-
)
|
|
808
|
-
{
|
|
852
|
+
) internal returns (SweepTxInputsInfo memory info) {
|
|
809
853
|
// If the passed `mainUtxo` parameter's values are zeroed, the main UTXO
|
|
810
854
|
// for the given wallet doesn't exist and it is not expected to be
|
|
811
855
|
// included in the sweep transaction input vector.
|
|
@@ -840,10 +884,11 @@ contract Bridge is Ownable {
|
|
|
840
884
|
// Determine the swept deposits count. If main UTXO is NOT expected,
|
|
841
885
|
// all inputs should be deposits. If main UTXO is expected, one input
|
|
842
886
|
// should point to that main UTXO.
|
|
843
|
-
depositors = new address[](
|
|
887
|
+
info.depositors = new address[](
|
|
844
888
|
!mainUtxoExpected ? inputsCount : inputsCount - 1
|
|
845
889
|
);
|
|
846
|
-
depositedAmounts = new uint256[](depositors.length);
|
|
890
|
+
info.depositedAmounts = new uint256[](info.depositors.length);
|
|
891
|
+
info.treasuryFees = new uint256[](info.depositors.length);
|
|
847
892
|
|
|
848
893
|
// Initialize helper variables.
|
|
849
894
|
uint256 processedDepositsCount = 0;
|
|
@@ -867,7 +912,7 @@ contract Bridge is Ownable {
|
|
|
867
912
|
// a revealed deposit.
|
|
868
913
|
require(deposit.sweptAt == 0, "Deposit already swept");
|
|
869
914
|
|
|
870
|
-
if (processedDepositsCount == depositors.length) {
|
|
915
|
+
if (processedDepositsCount == info.depositors.length) {
|
|
871
916
|
// If this condition is true, that means a deposit input
|
|
872
917
|
// took place of an expected main UTXO input.
|
|
873
918
|
// In other words, there is no expected main UTXO
|
|
@@ -880,9 +925,12 @@ contract Bridge is Ownable {
|
|
|
880
925
|
/* solhint-disable-next-line not-rely-on-time */
|
|
881
926
|
deposit.sweptAt = uint32(block.timestamp);
|
|
882
927
|
|
|
883
|
-
depositors[processedDepositsCount] = deposit.depositor;
|
|
884
|
-
depositedAmounts[processedDepositsCount] = deposit.amount;
|
|
885
|
-
inputsTotalValue += depositedAmounts[
|
|
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;
|
|
886
934
|
|
|
887
935
|
processedDepositsCount++;
|
|
888
936
|
} else if (
|
|
@@ -891,7 +939,7 @@ contract Bridge is Ownable {
|
|
|
891
939
|
) {
|
|
892
940
|
// If we entered here, that means the input was identified as
|
|
893
941
|
// the expected main UTXO.
|
|
894
|
-
inputsTotalValue += mainUtxo.txOutputValue;
|
|
942
|
+
info.inputsTotalValue += mainUtxo.txOutputValue;
|
|
895
943
|
mainUtxoFound = true;
|
|
896
944
|
} else {
|
|
897
945
|
revert("Unknown input type");
|
|
@@ -903,7 +951,7 @@ contract Bridge is Ownable {
|
|
|
903
951
|
}
|
|
904
952
|
|
|
905
953
|
// Construction of the input processing loop guarantees that:
|
|
906
|
-
// `processedDepositsCount == depositors.length == depositedAmounts.length`
|
|
954
|
+
// `processedDepositsCount == info.depositors.length == info.depositedAmounts.length`
|
|
907
955
|
// is always true at this point. We just use the first variable
|
|
908
956
|
// to assert the total count of swept deposit is bigger than zero.
|
|
909
957
|
require(
|
|
@@ -918,7 +966,7 @@ contract Bridge is Ownable {
|
|
|
918
966
|
"Expected main UTXO not present in sweep transaction inputs"
|
|
919
967
|
);
|
|
920
968
|
|
|
921
|
-
return
|
|
969
|
+
return info;
|
|
922
970
|
}
|
|
923
971
|
|
|
924
972
|
/// @notice Parses a Bitcoin transaction input starting at the given index.
|
|
@@ -970,7 +1018,7 @@ contract Bridge is Ownable {
|
|
|
970
1018
|
/// on the redeemer output script will be always lower than this value
|
|
971
1019
|
/// since the treasury and Bitcoin transaction fees must be incurred.
|
|
972
1020
|
/// The minimal amount satisfying the request can be computed as:
|
|
973
|
-
/// `amount -
|
|
1021
|
+
/// `amount - (amount / redemptionTreasuryFeeDivisor) - redemptionTxMaxFee`.
|
|
974
1022
|
/// Fees values are taken at the moment of request creation.
|
|
975
1023
|
/// @dev Requirements:
|
|
976
1024
|
/// - Wallet behind `walletPubKeyHash` must be active
|
|
@@ -1065,7 +1113,12 @@ contract Bridge is Ownable {
|
|
|
1065
1113
|
"There is a pending redemption request from this wallet to the same address"
|
|
1066
1114
|
);
|
|
1067
1115
|
|
|
1068
|
-
|
|
1116
|
+
// No need to check whether `amount - treasuryFee - txMaxFee > 0`
|
|
1117
|
+
// since the `redemptionDustThreshold` should force that condition
|
|
1118
|
+
// to be always true.
|
|
1119
|
+
uint64 treasuryFee = redemptionTreasuryFeeDivisor > 0
|
|
1120
|
+
? amount / redemptionTreasuryFeeDivisor
|
|
1121
|
+
: 0;
|
|
1069
1122
|
uint64 txMaxFee = redemptionTxMaxFee;
|
|
1070
1123
|
|
|
1071
1124
|
// The main wallet UTXO's value doesn't include all pending redemptions.
|