@keep-network/tbtc-v2 0.1.1-dev.96 → 0.1.1-dev.99
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/Bank.json +8 -8
- package/artifacts/Bridge.json +67 -67
- package/artifacts/Deposit.json +9 -9
- package/artifacts/DepositSweep.json +9 -9
- package/artifacts/EcdsaDkgValidator.json +1 -1
- package/artifacts/EcdsaInactivity.json +1 -1
- package/artifacts/EcdsaSortitionPool.json +2 -2
- package/artifacts/Fraud.json +9 -9
- package/artifacts/KeepRegistry.json +1 -1
- package/artifacts/KeepStake.json +2 -2
- package/artifacts/KeepToken.json +2 -2
- package/artifacts/KeepTokenStaking.json +1 -1
- package/artifacts/MovingFunds.json +9 -9
- package/artifacts/NuCypherStakingEscrow.json +1 -1
- package/artifacts/NuCypherToken.json +2 -2
- package/artifacts/RandomBeaconStub.json +1 -1
- package/artifacts/Redemption.json +10 -10
- package/artifacts/ReimbursementPool.json +2 -2
- package/artifacts/Relay.json +9 -9
- package/artifacts/T.json +2 -2
- package/artifacts/TBTC.json +10 -10
- package/artifacts/TBTCToken.json +10 -10
- package/artifacts/TBTCVault.json +15 -15
- package/artifacts/TokenStaking.json +1 -1
- package/artifacts/TokenholderGovernor.json +9 -9
- package/artifacts/TokenholderTimelock.json +8 -8
- package/artifacts/VendingMachine.json +11 -11
- package/artifacts/VendingMachineKeep.json +1 -1
- package/artifacts/VendingMachineNuCypher.json +1 -1
- package/artifacts/WalletRegistry.json +5 -5
- package/artifacts/WalletRegistryGovernance.json +2 -2
- package/artifacts/Wallets.json +11 -11
- package/artifacts/solcInputs/{3cf46a7694ce157f71d9dbf4db692b09.json → 5334fac3c976c2a5cd9bc3d6190e35c4.json} +9 -9
- package/build/contracts/GovernanceUtils.sol/GovernanceUtils.dbg.json +1 -1
- package/build/contracts/bank/Bank.sol/Bank.dbg.json +1 -1
- package/build/contracts/bank/IReceiveBalanceApproval.sol/IReceiveBalanceApproval.dbg.json +1 -1
- package/build/contracts/bridge/BitcoinTx.sol/BitcoinTx.dbg.json +1 -1
- package/build/contracts/bridge/BitcoinTx.sol/BitcoinTx.json +2 -2
- package/build/contracts/bridge/Bridge.sol/Bridge.dbg.json +1 -1
- package/build/contracts/bridge/Bridge.sol/Bridge.json +123 -123
- package/build/contracts/bridge/BridgeState.sol/BridgeState.dbg.json +1 -1
- package/build/contracts/bridge/BridgeState.sol/BridgeState.json +16 -16
- package/build/contracts/bridge/Deposit.sol/Deposit.dbg.json +1 -1
- package/build/contracts/bridge/Deposit.sol/Deposit.json +2 -2
- package/build/contracts/bridge/DepositSweep.sol/DepositSweep.dbg.json +1 -1
- package/build/contracts/bridge/DepositSweep.sol/DepositSweep.json +2 -2
- package/build/contracts/bridge/EcdsaLib.sol/EcdsaLib.dbg.json +1 -1
- package/build/contracts/bridge/Fraud.sol/Fraud.dbg.json +1 -1
- package/build/contracts/bridge/Fraud.sol/Fraud.json +2 -2
- package/build/contracts/bridge/Heartbeat.sol/Heartbeat.dbg.json +1 -1
- package/build/contracts/bridge/IRelay.sol/IRelay.dbg.json +1 -1
- package/build/contracts/bridge/MovingFunds.sol/MovingFunds.dbg.json +1 -1
- package/build/contracts/bridge/MovingFunds.sol/MovingFunds.json +2 -2
- package/build/contracts/bridge/Redemption.sol/OutboundTx.dbg.json +1 -1
- package/build/contracts/bridge/Redemption.sol/OutboundTx.json +2 -2
- package/build/contracts/bridge/Redemption.sol/Redemption.dbg.json +1 -1
- package/build/contracts/bridge/Redemption.sol/Redemption.json +2 -2
- package/build/contracts/bridge/VendingMachine.sol/VendingMachine.dbg.json +1 -1
- package/build/contracts/bridge/Wallets.sol/Wallets.dbg.json +1 -1
- package/build/contracts/bridge/Wallets.sol/Wallets.json +2 -2
- package/build/contracts/token/TBTC.sol/TBTC.dbg.json +1 -1
- package/build/contracts/vault/DonationVault.sol/DonationVault.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/BitcoinTx.sol +74 -39
- package/contracts/bridge/Bridge.sol +31 -31
- package/contracts/bridge/BridgeState.sol +100 -84
- package/contracts/bridge/Fraud.sol +7 -32
- package/contracts/bridge/MovingFunds.sol +18 -51
- package/contracts/bridge/Redemption.sol +95 -76
- package/contracts/bridge/Wallets.sol +309 -143
- package/export.json +54 -54
- package/package.json +2 -2
|
@@ -424,16 +424,14 @@ library Redemption {
|
|
|
424
424
|
);
|
|
425
425
|
|
|
426
426
|
// Validate if redeemer output script is a correct standard type
|
|
427
|
-
// (P2PKH, P2WPKH, P2SH or P2WSH). This is done by
|
|
428
|
-
//
|
|
429
|
-
//
|
|
430
|
-
//
|
|
431
|
-
//
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
.encodePacked(bytes8(0), redeemerOutputScript)
|
|
436
|
-
.extractHash();
|
|
427
|
+
// (P2PKH, P2WPKH, P2SH or P2WSH). This is done by using
|
|
428
|
+
// `BTCUtils.extractHashAt` on it. Such a function extracts the payload
|
|
429
|
+
// properly only from standard outputs so if it succeeds, we have a
|
|
430
|
+
// guarantee the redeemer output script is proper. The underlying way
|
|
431
|
+
// of validation is the same as in tBTC v1.
|
|
432
|
+
bytes memory redeemerOutputScriptPayload = redeemerOutputScript
|
|
433
|
+
.extractHashAt(0, redeemerOutputScript.length);
|
|
434
|
+
|
|
437
435
|
require(
|
|
438
436
|
redeemerOutputScriptPayload.length > 0,
|
|
439
437
|
"Redeemer output script must be a standard type"
|
|
@@ -441,8 +439,8 @@ library Redemption {
|
|
|
441
439
|
// Check if the redeemer output script payload does not point to the
|
|
442
440
|
// wallet public key hash.
|
|
443
441
|
require(
|
|
444
|
-
|
|
445
|
-
|
|
442
|
+
redeemerOutputScriptPayload.length != 20 ||
|
|
443
|
+
walletPubKeyHash != redeemerOutputScriptPayload.slice20(0),
|
|
446
444
|
"Redeemer output script must not point to the wallet PKH"
|
|
447
445
|
);
|
|
448
446
|
|
|
@@ -455,8 +453,9 @@ library Redemption {
|
|
|
455
453
|
// and redeemer output script pair. That means there can be only one
|
|
456
454
|
// request asking for redemption from the given wallet to the given
|
|
457
455
|
// BTC script at the same time.
|
|
458
|
-
uint256 redemptionKey =
|
|
459
|
-
|
|
456
|
+
uint256 redemptionKey = getRedemptionKey(
|
|
457
|
+
walletPubKeyHash,
|
|
458
|
+
redeemerOutputScript
|
|
460
459
|
);
|
|
461
460
|
|
|
462
461
|
// Check if given redemption key is not used by a pending redemption.
|
|
@@ -497,6 +496,7 @@ library Redemption {
|
|
|
497
496
|
uint32(block.timestamp)
|
|
498
497
|
);
|
|
499
498
|
|
|
499
|
+
// slither-disable-next-line reentrancy-events
|
|
500
500
|
emit RedemptionRequested(
|
|
501
501
|
walletPubKeyHash,
|
|
502
502
|
redeemerOutputScript,
|
|
@@ -674,7 +674,7 @@ library Redemption {
|
|
|
674
674
|
/// must be validated using e.g. `BTCUtils.validateVout` function
|
|
675
675
|
/// before it is passed here.
|
|
676
676
|
/// @param walletPubKeyHash 20-byte public key hash (computed using Bitcoin
|
|
677
|
-
|
|
677
|
+
/// HASH160 over the compressed ECDSA public key) of the wallet which
|
|
678
678
|
/// performed the redemption transaction.
|
|
679
679
|
/// @return info Outcomes of the processing.
|
|
680
680
|
function processRedemptionTxOutputs(
|
|
@@ -722,7 +722,7 @@ library Redemption {
|
|
|
722
722
|
// which matches the P2PKH structure as per:
|
|
723
723
|
// https://en.bitcoin.it/wiki/Transaction#Pay-to-PubkeyHash
|
|
724
724
|
bytes32 walletP2PKHScriptKeccak = keccak256(
|
|
725
|
-
abi.encodePacked(
|
|
725
|
+
abi.encodePacked(BitcoinTx.makeP2PKHScript(walletPubKeyHash))
|
|
726
726
|
);
|
|
727
727
|
// The P2WPKH script has the byte format: <0x160014> <20-byte PKH>.
|
|
728
728
|
// According to https://en.bitcoin.it/wiki/Script#Opcodes this translates to:
|
|
@@ -732,7 +732,7 @@ library Redemption {
|
|
|
732
732
|
// which matches the P2WPKH structure as per:
|
|
733
733
|
// https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#P2WPKH
|
|
734
734
|
bytes32 walletP2WPKHScriptKeccak = keccak256(
|
|
735
|
-
abi.encodePacked(
|
|
735
|
+
abi.encodePacked(BitcoinTx.makeP2WPKHScript(walletPubKeyHash))
|
|
736
736
|
);
|
|
737
737
|
|
|
738
738
|
return
|
|
@@ -751,7 +751,7 @@ library Redemption {
|
|
|
751
751
|
|
|
752
752
|
/// @notice Processes all outputs from the redemption transaction. Tries to
|
|
753
753
|
/// identify output as a change output, pending redemption request
|
|
754
|
-
|
|
754
|
+
/// or reported redemption. Reverts if one of the outputs cannot be
|
|
755
755
|
/// recognized properly. Marks each request as processed by removing
|
|
756
756
|
/// them from `pendingRedemptions` mapping.
|
|
757
757
|
/// @param redemptionTxOutputVector Bitcoin redemption transaction output
|
|
@@ -759,7 +759,7 @@ library Redemption {
|
|
|
759
759
|
/// must be validated using e.g. `BTCUtils.validateVout` function
|
|
760
760
|
/// before it is passed here.
|
|
761
761
|
/// @param walletPubKeyHash 20-byte public key hash (computed using Bitcoin
|
|
762
|
-
|
|
762
|
+
/// HASH160 over the compressed ECDSA public key) of the wallet which
|
|
763
763
|
/// performed the redemption transaction.
|
|
764
764
|
/// @param processInfo RedemptionTxOutputsProcessingInfo identifying output
|
|
765
765
|
/// starting index, the number of outputs and possible wallet change
|
|
@@ -777,30 +777,38 @@ library Redemption {
|
|
|
777
777
|
|
|
778
778
|
// Outputs processing loop.
|
|
779
779
|
for (uint256 i = 0; i < processInfo.outputsCount; i++) {
|
|
780
|
-
// TODO: Check if we can optimize gas costs by adding
|
|
781
|
-
// `extractValueAt` and `extractHashAt` in `bitcoin-spv-sol`
|
|
782
|
-
// in order to avoid allocating bytes in memory.
|
|
783
|
-
// https://github.com/keep-network/tbtc-v2/issues/257
|
|
784
780
|
uint256 outputLength = redemptionTxOutputVector
|
|
785
781
|
.determineOutputLengthAt(processInfo.outputStartingIndex);
|
|
786
|
-
bytes memory output = redemptionTxOutputVector.slice(
|
|
787
|
-
processInfo.outputStartingIndex,
|
|
788
|
-
outputLength
|
|
789
|
-
);
|
|
790
782
|
|
|
791
783
|
// Extract the value from given output.
|
|
792
|
-
uint64 outputValue =
|
|
784
|
+
uint64 outputValue = redemptionTxOutputVector.extractValueAt(
|
|
785
|
+
processInfo.outputStartingIndex
|
|
786
|
+
);
|
|
787
|
+
|
|
793
788
|
// The output consists of an 8-byte value and a variable length
|
|
794
|
-
// script. To
|
|
789
|
+
// script. To hash that script we slice the output starting from
|
|
795
790
|
// 9th byte until the end.
|
|
796
|
-
|
|
791
|
+
uint256 scriptLength = outputLength - 8;
|
|
792
|
+
uint256 outputScriptStart = processInfo.outputStartingIndex + 8;
|
|
793
|
+
|
|
794
|
+
bytes32 outputScriptHash;
|
|
795
|
+
/* solhint-disable-next-line no-inline-assembly */
|
|
796
|
+
assembly {
|
|
797
|
+
// The first argument to assembly keccak256 is the pointer.
|
|
798
|
+
// We point to `redemptionTxOutputVector` but at the position
|
|
799
|
+
// indicated by `outputScriptStart`. To load that position, we
|
|
800
|
+
// need to call `add(outputScriptStart, 32)` because
|
|
801
|
+
// `outputScriptStart` has 32 bytes.
|
|
802
|
+
outputScriptHash := keccak256(
|
|
803
|
+
add(redemptionTxOutputVector, add(outputScriptStart, 32)),
|
|
804
|
+
scriptLength
|
|
805
|
+
)
|
|
806
|
+
}
|
|
797
807
|
|
|
798
808
|
if (
|
|
799
809
|
resultInfo.changeValue == 0 &&
|
|
800
|
-
(
|
|
801
|
-
processInfo.
|
|
802
|
-
keccak256(outputScript) ==
|
|
803
|
-
processInfo.walletP2WPKHScriptKeccak) &&
|
|
810
|
+
(outputScriptHash == processInfo.walletP2PKHScriptKeccak ||
|
|
811
|
+
outputScriptHash == processInfo.walletP2WPKHScriptKeccak) &&
|
|
804
812
|
outputValue > 0
|
|
805
813
|
) {
|
|
806
814
|
// If we entered here, that means the change output with a
|
|
@@ -815,8 +823,7 @@ library Redemption {
|
|
|
815
823
|
uint64 treasuryFee
|
|
816
824
|
) = processNonChangeRedemptionTxOutput(
|
|
817
825
|
self,
|
|
818
|
-
walletPubKeyHash,
|
|
819
|
-
outputScript,
|
|
826
|
+
_getRedemptionKey(walletPubKeyHash, outputScriptHash),
|
|
820
827
|
outputValue
|
|
821
828
|
);
|
|
822
829
|
resultInfo.totalBurnableValue += burnableValue;
|
|
@@ -847,10 +854,7 @@ library Redemption {
|
|
|
847
854
|
/// requested and reported timed-out redemption.
|
|
848
855
|
/// This function also marks each pending request as processed by
|
|
849
856
|
/// removing them from `pendingRedemptions` mapping.
|
|
850
|
-
/// @param
|
|
851
|
-
// HASH160 over the compressed ECDSA public key) of the wallet which
|
|
852
|
-
/// performed the redemption transaction.
|
|
853
|
-
/// @param outputScript Non-change output script to be processed.
|
|
857
|
+
/// @param redemptionKey Redemption key of the output being processed.
|
|
854
858
|
/// @param outputValue Value of the output being processed.
|
|
855
859
|
/// @return burnableValue The value burnable as a result of processing this
|
|
856
860
|
/// single redemption output. This value needs to be summed up with
|
|
@@ -862,19 +866,14 @@ library Redemption {
|
|
|
862
866
|
/// outputs to evaluate the total treasury fee for the entire
|
|
863
867
|
/// redemption transaction. This value is 0 for a timed-out
|
|
864
868
|
/// redemption request.
|
|
869
|
+
/// @dev Requirements:
|
|
870
|
+
/// - This function should be called only if the given output
|
|
871
|
+
/// represents redemption. It must not be the change output.
|
|
865
872
|
function processNonChangeRedemptionTxOutput(
|
|
866
873
|
BridgeState.Storage storage self,
|
|
867
|
-
|
|
868
|
-
bytes memory outputScript,
|
|
874
|
+
uint256 redemptionKey,
|
|
869
875
|
uint64 outputValue
|
|
870
876
|
) internal returns (uint64 burnableValue, uint64 treasuryFee) {
|
|
871
|
-
// This function should be called only if the given output is
|
|
872
|
-
// supposed to represent a redemption. Build the redemption key
|
|
873
|
-
// to perform that check.
|
|
874
|
-
uint256 redemptionKey = uint256(
|
|
875
|
-
keccak256(abi.encodePacked(walletPubKeyHash, outputScript))
|
|
876
|
-
);
|
|
877
|
-
|
|
878
877
|
if (self.pendingRedemptions[redemptionKey].requestedAt != 0) {
|
|
879
878
|
// If we entered here, that means the output was identified
|
|
880
879
|
// as a pending redemption request.
|
|
@@ -936,7 +935,7 @@ library Redemption {
|
|
|
936
935
|
/// @notice Notifies that there is a pending redemption request associated
|
|
937
936
|
/// with the given wallet, that has timed out. The redemption
|
|
938
937
|
/// request is identified by the key built as
|
|
939
|
-
/// `keccak256(
|
|
938
|
+
/// `keccak256(keccak256(redeemerOutputScript) | walletPubKeyHash)`.
|
|
940
939
|
/// The results of calling this function:
|
|
941
940
|
/// - the pending redemptions value for the wallet will be decreased
|
|
942
941
|
/// by the requested amount (minus treasury fee),
|
|
@@ -974,8 +973,10 @@ library Redemption {
|
|
|
974
973
|
uint32[] calldata walletMembersIDs,
|
|
975
974
|
bytes calldata redeemerOutputScript
|
|
976
975
|
) external {
|
|
977
|
-
|
|
978
|
-
|
|
976
|
+
// Wallet state is validated in `notifyWalletRedemptionTimeout`.
|
|
977
|
+
uint256 redemptionKey = getRedemptionKey(
|
|
978
|
+
walletPubKeyHash,
|
|
979
|
+
redeemerOutputScript
|
|
979
980
|
);
|
|
980
981
|
Redemption.RedemptionRequest memory request = self.pendingRedemptions[
|
|
981
982
|
redemptionKey
|
|
@@ -996,44 +997,62 @@ library Redemption {
|
|
|
996
997
|
request.requestedAmount -
|
|
997
998
|
request.treasuryFee;
|
|
998
999
|
|
|
999
|
-
require(
|
|
1000
|
-
wallet.state == Wallets.WalletState.Live ||
|
|
1001
|
-
wallet.state == Wallets.WalletState.MovingFunds ||
|
|
1002
|
-
wallet.state == Wallets.WalletState.Terminated,
|
|
1003
|
-
"Wallet must be in Live, MovingFunds or Terminated state"
|
|
1004
|
-
);
|
|
1005
|
-
|
|
1006
1000
|
// It is worth noting that there is no need to check if
|
|
1007
1001
|
// `timedOutRedemption` mapping already contains the given redemption
|
|
1008
1002
|
// key. There is no possibility to re-use a key of a reported timed-out
|
|
1009
1003
|
// redemption because the wallet responsible for causing the timeout is
|
|
1010
1004
|
// moved to a state that prevents it to receive new redemption requests.
|
|
1011
1005
|
|
|
1006
|
+
// Propagate timeout consequences to the wallet
|
|
1007
|
+
self.notifyWalletRedemptionTimeout(walletPubKeyHash, walletMembersIDs);
|
|
1008
|
+
|
|
1012
1009
|
// Move the redemption from pending redemptions to timed-out redemptions
|
|
1013
1010
|
self.timedOutRedemptions[redemptionKey] = request;
|
|
1014
1011
|
delete self.pendingRedemptions[redemptionKey];
|
|
1015
1012
|
|
|
1016
|
-
if (
|
|
1017
|
-
wallet.state == Wallets.WalletState.Live ||
|
|
1018
|
-
wallet.state == Wallets.WalletState.MovingFunds
|
|
1019
|
-
) {
|
|
1020
|
-
// Slash the wallet operators and reward the notifier
|
|
1021
|
-
self.ecdsaWalletRegistry.seize(
|
|
1022
|
-
self.redemptionTimeoutSlashingAmount,
|
|
1023
|
-
self.redemptionTimeoutNotifierRewardMultiplier,
|
|
1024
|
-
msg.sender,
|
|
1025
|
-
wallet.ecdsaWalletID,
|
|
1026
|
-
walletMembersIDs
|
|
1027
|
-
);
|
|
1028
|
-
|
|
1029
|
-
// Propagate timeout consequences to the wallet
|
|
1030
|
-
self.notifyWalletTimedOutRedemption(walletPubKeyHash);
|
|
1031
|
-
}
|
|
1032
|
-
|
|
1033
1013
|
// slither-disable-next-line reentrancy-events
|
|
1034
1014
|
emit RedemptionTimedOut(walletPubKeyHash, redeemerOutputScript);
|
|
1035
1015
|
|
|
1036
1016
|
// Return the requested amount of tokens to the redeemer
|
|
1037
1017
|
self.bank.transferBalance(request.redeemer, request.requestedAmount);
|
|
1038
1018
|
}
|
|
1019
|
+
|
|
1020
|
+
/// @notice Calculate redemption key without allocations.
|
|
1021
|
+
/// @param walletPubKeyHash the pubkey hash of the wallet.
|
|
1022
|
+
/// @param script the output script of the redemption.
|
|
1023
|
+
/// @return The key = keccak256(keccak256(script) | walletPubKeyHash).
|
|
1024
|
+
function getRedemptionKey(bytes20 walletPubKeyHash, bytes memory script)
|
|
1025
|
+
internal
|
|
1026
|
+
pure
|
|
1027
|
+
returns (uint256)
|
|
1028
|
+
{
|
|
1029
|
+
bytes32 scriptHash = keccak256(script);
|
|
1030
|
+
uint256 key;
|
|
1031
|
+
/* solhint-disable-next-line no-inline-assembly */
|
|
1032
|
+
assembly {
|
|
1033
|
+
mstore(0, scriptHash)
|
|
1034
|
+
mstore(32, walletPubKeyHash)
|
|
1035
|
+
key := keccak256(0, 52)
|
|
1036
|
+
}
|
|
1037
|
+
return key;
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
/// @notice Finish calculating redemption key without allocations.
|
|
1041
|
+
/// @param walletPubKeyHash the pubkey hash of the wallet.
|
|
1042
|
+
/// @param scriptHash the output script hash of the redemption.
|
|
1043
|
+
/// @return The key = keccak256(scriptHash | walletPubKeyHash).
|
|
1044
|
+
function _getRedemptionKey(bytes20 walletPubKeyHash, bytes32 scriptHash)
|
|
1045
|
+
internal
|
|
1046
|
+
pure
|
|
1047
|
+
returns (uint256)
|
|
1048
|
+
{
|
|
1049
|
+
uint256 key;
|
|
1050
|
+
/* solhint-disable-next-line no-inline-assembly */
|
|
1051
|
+
assembly {
|
|
1052
|
+
mstore(0, scriptHash)
|
|
1053
|
+
mstore(32, walletPubKeyHash)
|
|
1054
|
+
key := keccak256(0, 52)
|
|
1055
|
+
}
|
|
1056
|
+
return key;
|
|
1057
|
+
}
|
|
1039
1058
|
}
|