@keep-network/tbtc-v2 0.1.1-dev.18 → 0.1.1-dev.20
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/{9a2493c7e2ff82685283d04dc6bcdde1.json → 5c08a447a71edda5755711e12ca577ad.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 +33 -2
- 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 +103 -52
- 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,6 +215,23 @@ 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
|
+
|
|
228
|
+
/// TODO: Make it governable.
|
|
229
|
+
/// @notice Maximum amount of BTC transaction fee that can be incurred by
|
|
230
|
+
/// each swept deposit being part of the given sweep
|
|
231
|
+
/// transaction. If the maximum BTC transaction fee is exceeded,
|
|
232
|
+
/// such transaction is considered a fraud.
|
|
233
|
+
uint64 public depositTxMaxFee;
|
|
234
|
+
|
|
190
235
|
/// TODO: Make it governable.
|
|
191
236
|
/// @notice The minimal amount that can be requested for redemption.
|
|
192
237
|
/// Value of this parameter must take into account the value of
|
|
@@ -339,6 +384,8 @@ contract Bridge is Ownable {
|
|
|
339
384
|
txProofDifficultyFactor = _txProofDifficultyFactor;
|
|
340
385
|
|
|
341
386
|
// TODO: Revisit initial values.
|
|
387
|
+
depositTxMaxFee = 1000; // 1000 satoshi
|
|
388
|
+
depositTreasuryFeeDivisor = 2000; // 1/2000 == 5bps == 0.05% == 0.0005
|
|
342
389
|
redemptionDustThreshold = 1000000; // 1000000 satoshi = 0.01 BTC
|
|
343
390
|
redemptionTreasuryFeeDivisor = 2000; // 1/2000 == 5bps == 0.05% == 0.0005
|
|
344
391
|
redemptionTxMaxFee = 1000; // 1000 satoshi
|
|
@@ -496,6 +543,9 @@ contract Bridge is Ownable {
|
|
|
496
543
|
/* solhint-disable-next-line not-rely-on-time */
|
|
497
544
|
deposit.revealedAt = uint32(block.timestamp);
|
|
498
545
|
deposit.vault = reveal.vault;
|
|
546
|
+
deposit.treasuryFee = depositTreasuryFeeDivisor > 0
|
|
547
|
+
? fundingOutputAmount / depositTreasuryFeeDivisor
|
|
548
|
+
: 0;
|
|
499
549
|
|
|
500
550
|
emit DepositRevealed(
|
|
501
551
|
fundingTxHash,
|
|
@@ -592,30 +642,40 @@ contract Bridge is Ownable {
|
|
|
592
642
|
resolvedMainUtxo = mainUtxo;
|
|
593
643
|
}
|
|
594
644
|
|
|
595
|
-
// Process sweep transaction inputs and extract
|
|
596
|
-
//
|
|
597
|
-
(
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
//
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
//
|
|
645
|
+
// Process sweep transaction inputs and extract all information needed
|
|
646
|
+
// to perform deposit bookkeeping.
|
|
647
|
+
SweepTxInputsInfo memory inputsInfo = processSweepTxInputs(
|
|
648
|
+
sweepTx.inputVector,
|
|
649
|
+
resolvedMainUtxo
|
|
650
|
+
);
|
|
651
|
+
|
|
652
|
+
// Helper variable that will hold the sum of treasury fees paid by
|
|
653
|
+
// all deposits.
|
|
654
|
+
uint256 totalTreasuryFee = 0;
|
|
655
|
+
|
|
656
|
+
// Calculate the transaction fee per deposit by dividing the total
|
|
657
|
+
// transaction fee by deposits count. The total fee is just the
|
|
658
|
+
// difference between inputs amounts sum and the output amount.
|
|
608
659
|
// TODO: Deal with precision loss by having the last depositor pay
|
|
609
|
-
// the higher fee than others if there is a change,
|
|
610
|
-
//
|
|
660
|
+
// the higher transaction fee than others if there is a change,
|
|
661
|
+
// just like it has been proposed in discussion:
|
|
611
662
|
// https://github.com/keep-network/tbtc-v2/pull/128#discussion_r800555359.
|
|
612
|
-
uint256
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
663
|
+
uint256 txFee = (inputsInfo.inputsTotalValue - sweepTxOutputValue) /
|
|
664
|
+
inputsInfo.depositedAmounts.length;
|
|
665
|
+
|
|
666
|
+
require(txFee <= depositTxMaxFee, "Transaction fee is too high");
|
|
667
|
+
|
|
668
|
+
// Reduce each deposit amount by treasury fee and transaction fee.
|
|
669
|
+
for (uint256 i = 0; i < inputsInfo.depositedAmounts.length; i++) {
|
|
670
|
+
// There is no need to check whether
|
|
671
|
+
// `inputsInfo.depositedAmounts[i] - inputsInfo.treasuryFees[i] - txFee > 0`
|
|
672
|
+
// since the `depositDustThreshold` should force that condition
|
|
673
|
+
// to be always true.
|
|
674
|
+
inputsInfo.depositedAmounts[i] =
|
|
675
|
+
inputsInfo.depositedAmounts[i] -
|
|
676
|
+
inputsInfo.treasuryFees[i] -
|
|
677
|
+
txFee;
|
|
678
|
+
totalTreasuryFee += inputsInfo.treasuryFees[i];
|
|
619
679
|
}
|
|
620
680
|
|
|
621
681
|
// Record this sweep data and assign them to the wallet public key hash
|
|
@@ -628,7 +688,12 @@ contract Bridge is Ownable {
|
|
|
628
688
|
emit DepositsSwept(walletPubKeyHash, sweepTxHash);
|
|
629
689
|
|
|
630
690
|
// Update depositors balances in the Bank.
|
|
631
|
-
bank.increaseBalances(
|
|
691
|
+
bank.increaseBalances(
|
|
692
|
+
inputsInfo.depositors,
|
|
693
|
+
inputsInfo.depositedAmounts
|
|
694
|
+
);
|
|
695
|
+
// Pass the treasury fee to the treasury address.
|
|
696
|
+
bank.increaseBalance(treasury, totalTreasuryFee);
|
|
632
697
|
|
|
633
698
|
// TODO: Handle deposits having `vault` set.
|
|
634
699
|
}
|
|
@@ -789,29 +854,11 @@ contract Bridge is Ownable {
|
|
|
789
854
|
/// @param mainUtxo Data of the wallet's main UTXO. If no main UTXO
|
|
790
855
|
/// exists for the given the wallet, this parameter's fields should
|
|
791
856
|
/// be zeroed to bypass the main UTXO validation
|
|
792
|
-
/// @return
|
|
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).
|
|
857
|
+
/// @return info Outcomes of the processing.
|
|
804
858
|
function processSweepTxInputs(
|
|
805
859
|
bytes memory sweepTxInputVector,
|
|
806
860
|
BitcoinTx.UTXO memory mainUtxo
|
|
807
|
-
)
|
|
808
|
-
internal
|
|
809
|
-
returns (
|
|
810
|
-
uint256 inputsTotalValue,
|
|
811
|
-
address[] memory depositors,
|
|
812
|
-
uint256[] memory depositedAmounts
|
|
813
|
-
)
|
|
814
|
-
{
|
|
861
|
+
) internal returns (SweepTxInputsInfo memory info) {
|
|
815
862
|
// If the passed `mainUtxo` parameter's values are zeroed, the main UTXO
|
|
816
863
|
// for the given wallet doesn't exist and it is not expected to be
|
|
817
864
|
// included in the sweep transaction input vector.
|
|
@@ -846,10 +893,11 @@ contract Bridge is Ownable {
|
|
|
846
893
|
// Determine the swept deposits count. If main UTXO is NOT expected,
|
|
847
894
|
// all inputs should be deposits. If main UTXO is expected, one input
|
|
848
895
|
// should point to that main UTXO.
|
|
849
|
-
depositors = new address[](
|
|
896
|
+
info.depositors = new address[](
|
|
850
897
|
!mainUtxoExpected ? inputsCount : inputsCount - 1
|
|
851
898
|
);
|
|
852
|
-
depositedAmounts = new uint256[](depositors.length);
|
|
899
|
+
info.depositedAmounts = new uint256[](info.depositors.length);
|
|
900
|
+
info.treasuryFees = new uint256[](info.depositors.length);
|
|
853
901
|
|
|
854
902
|
// Initialize helper variables.
|
|
855
903
|
uint256 processedDepositsCount = 0;
|
|
@@ -873,7 +921,7 @@ contract Bridge is Ownable {
|
|
|
873
921
|
// a revealed deposit.
|
|
874
922
|
require(deposit.sweptAt == 0, "Deposit already swept");
|
|
875
923
|
|
|
876
|
-
if (processedDepositsCount == depositors.length) {
|
|
924
|
+
if (processedDepositsCount == info.depositors.length) {
|
|
877
925
|
// If this condition is true, that means a deposit input
|
|
878
926
|
// took place of an expected main UTXO input.
|
|
879
927
|
// In other words, there is no expected main UTXO
|
|
@@ -886,9 +934,12 @@ contract Bridge is Ownable {
|
|
|
886
934
|
/* solhint-disable-next-line not-rely-on-time */
|
|
887
935
|
deposit.sweptAt = uint32(block.timestamp);
|
|
888
936
|
|
|
889
|
-
depositors[processedDepositsCount] = deposit.depositor;
|
|
890
|
-
depositedAmounts[processedDepositsCount] = deposit.amount;
|
|
891
|
-
inputsTotalValue += depositedAmounts[
|
|
937
|
+
info.depositors[processedDepositsCount] = deposit.depositor;
|
|
938
|
+
info.depositedAmounts[processedDepositsCount] = deposit.amount;
|
|
939
|
+
info.inputsTotalValue += info.depositedAmounts[
|
|
940
|
+
processedDepositsCount
|
|
941
|
+
];
|
|
942
|
+
info.treasuryFees[processedDepositsCount] = deposit.treasuryFee;
|
|
892
943
|
|
|
893
944
|
processedDepositsCount++;
|
|
894
945
|
} else if (
|
|
@@ -897,7 +948,7 @@ contract Bridge is Ownable {
|
|
|
897
948
|
) {
|
|
898
949
|
// If we entered here, that means the input was identified as
|
|
899
950
|
// the expected main UTXO.
|
|
900
|
-
inputsTotalValue += mainUtxo.txOutputValue;
|
|
951
|
+
info.inputsTotalValue += mainUtxo.txOutputValue;
|
|
901
952
|
mainUtxoFound = true;
|
|
902
953
|
} else {
|
|
903
954
|
revert("Unknown input type");
|
|
@@ -909,7 +960,7 @@ contract Bridge is Ownable {
|
|
|
909
960
|
}
|
|
910
961
|
|
|
911
962
|
// Construction of the input processing loop guarantees that:
|
|
912
|
-
// `processedDepositsCount == depositors.length == depositedAmounts.length`
|
|
963
|
+
// `processedDepositsCount == info.depositors.length == info.depositedAmounts.length`
|
|
913
964
|
// is always true at this point. We just use the first variable
|
|
914
965
|
// to assert the total count of swept deposit is bigger than zero.
|
|
915
966
|
require(
|
|
@@ -924,7 +975,7 @@ contract Bridge is Ownable {
|
|
|
924
975
|
"Expected main UTXO not present in sweep transaction inputs"
|
|
925
976
|
);
|
|
926
977
|
|
|
927
|
-
return
|
|
978
|
+
return info;
|
|
928
979
|
}
|
|
929
980
|
|
|
930
981
|
/// @notice Parses a Bitcoin transaction input starting at the given index.
|