-
Notifications
You must be signed in to change notification settings - Fork 76
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
CLI command to submit a deposit sweep proposal (#3549)
We added a CLI command to submit a deposit sweep proposal. The command verifies the proposal with the same rules as nodes will do and submits the proposal to the chain. To submit a deposit sweep proposal run: ``` keep-client coordinator propose-deposits-sweep --wallet <wallet_address> --fee <fee> <deposit_1> <deposit_2> ... ``` Following flags can be used with the command: - `--wallet <address>` - wallet to sweep - `--fee` - fee to use for the sweep transaction The command requires `ethereum` and `bitcoin.electrum` node details to be provided in the config. ### Deposits The command requires the deposits details to be provided as variadic arguments in a specific format: `<unprefixed bitcoin transaction hash>:<bitcoin transaction output index>:<ethereum reveal block number>` e.g. `bd99d1d0a61fd104925d9b7ac997958aa8af570418b3fde091f7bfc561608865:1:8392394` ## Sample command ``` keep-client --config ./configs/forked/config.toml \ --goerli \ coordinator \ propose-deposits-sweep \ --wallet 0x03b74d6893ad46dfdd01b9e0e3b3385f4fce2d1e \ --fee 12 \ da3ec4f5620f686d5013c37d49a411fa49daac5077c98809402572f481c6ea0:0:8502238 \ 214a85db0871b537d4cd649a8d74aecdbee112919983ad22fb85cfa2704a3593:0:8502224 \ 3704d01b48212ddacc77e613be0491978a8c19ad11af6b8536eacf9e9953eb13:0:8502070 ``` ## Testing ~To test this feature `WalletCoordinator` contract is required to be deployed. It is not yet available on Goerli or Mainnet. To have the contract available you can run a hardhat node as Goerli fork (https://github.com/nkuba/hardhat-forked-node) and deploy the `WalletCoordinator` contract there.~ Depends on: #3545
- Loading branch information
Showing
8 changed files
with
281 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
package coordinator | ||
|
||
import ( | ||
"fmt" | ||
"math/big" | ||
"regexp" | ||
"strconv" | ||
|
||
"github.com/keep-network/keep-core/pkg/bitcoin" | ||
"github.com/keep-network/keep-core/pkg/tbtc" | ||
) | ||
|
||
type btcTransaction = struct { | ||
FundingTxHash bitcoin.Hash | ||
FundingOutputIndex uint32 | ||
} | ||
|
||
const requiredFundingTxConfirmations = uint(6) | ||
|
||
var ( | ||
DepositsFormatDescription = `Deposits details should be provided as strings containing: | ||
- bitcoin transaction hash (unprefixed bitcoin transaction hash in reverse (RPC) order), | ||
- bitcoin transaction output index, | ||
- ethereum block number when the deposit was revealed to the chain. | ||
The properties should be separated by semicolons, in the following format: | ||
` + depositsFormatPattern + ` | ||
e.g. bd99d1d0a61fd104925d9b7ac997958aa8af570418b3fde091f7bfc561608865:1:8392394 | ||
` | ||
depositsFormatPattern = "<unprefixed bitcoin transaction hash>:<bitcoin transaction output index>:<ethereum reveal block number>" | ||
depositsFormatRegexp = regexp.MustCompile(`^([[:xdigit:]]+):(\d+):(\d+)$`) | ||
) | ||
|
||
// ProposeDepositsSweep handles deposit sweep proposal request submission. | ||
func ProposeDepositsSweep( | ||
tbtcChain tbtc.Chain, | ||
btcChain bitcoin.Chain, | ||
walletStr string, | ||
fee int64, | ||
depositsString []string, | ||
dryRun bool, | ||
) error { | ||
walletPublicKeyHash, err := hexToWalletPublicKeyHash(walletStr) | ||
if err != nil { | ||
return fmt.Errorf("failed extract wallet public key hash: %v", err) | ||
} | ||
|
||
btcTransactions, depositsRevealBlocks, err := parseDeposits(depositsString) | ||
if err != nil { | ||
return fmt.Errorf("failed to parse arguments: %w", err) | ||
} | ||
|
||
proposal := &tbtc.DepositSweepProposal{ | ||
WalletPublicKeyHash: walletPublicKeyHash, | ||
DepositsKeys: btcTransactions, | ||
SweepTxFee: big.NewInt(fee), | ||
DepositsRevealBlocks: depositsRevealBlocks, | ||
} | ||
|
||
logger.Infof("validating the proposal...") | ||
if _, err := tbtc.ValidateDepositSweepProposal( | ||
logger, | ||
proposal, | ||
requiredFundingTxConfirmations, | ||
tbtcChain, | ||
btcChain, | ||
); err != nil { | ||
return fmt.Errorf("failed to verify deposit sweep proposal: %v", err) | ||
} | ||
|
||
if !dryRun { | ||
logger.Infof("submitting the proposal...") | ||
if err := tbtcChain.SubmitDepositSweepProposal(proposal); err != nil { | ||
return fmt.Errorf("failed to submit deposit sweep proposal: %v", err) | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func parseDeposits(depositsStrings []string) ([]btcTransaction, []*big.Int, error) { | ||
depositsKeys := make([]btcTransaction, len(depositsStrings)) | ||
depositsRevealBlocks := make([]*big.Int, len(depositsStrings)) | ||
|
||
for i, depositString := range depositsStrings { | ||
matched := depositsFormatRegexp.FindStringSubmatch(depositString) | ||
// Check if number of resolved entries match expected number of groups | ||
// for the given regexp. | ||
if len(matched) != 4 { | ||
return nil, nil, fmt.Errorf("failed to parse deposit: [%s]", depositString) | ||
} | ||
|
||
txHash, err := bitcoin.NewHashFromString(matched[1], bitcoin.ReversedByteOrder) | ||
if err != nil { | ||
return nil, nil, fmt.Errorf("invalid bitcoin transaction hash [%s]: %v", matched[1], err) | ||
|
||
} | ||
|
||
outputIndex, err := strconv.ParseInt(matched[2], 10, 32) | ||
if err != nil { | ||
return nil, nil, fmt.Errorf("invalid bitcoin transaction output index [%s]: %v", matched[2], err) | ||
} | ||
|
||
revealBlock, err := strconv.ParseInt(matched[3], 10, 32) | ||
if err != nil { | ||
return nil, nil, fmt.Errorf("invalid reveal block number [%s]: %v", matched[3], err) | ||
} | ||
|
||
depositsKeys[i] = btcTransaction{ | ||
FundingTxHash: txHash, | ||
FundingOutputIndex: uint32(outputIndex), | ||
} | ||
|
||
depositsRevealBlocks[i] = big.NewInt(revealBlock) | ||
} | ||
|
||
return depositsKeys, depositsRevealBlocks, nil | ||
} | ||
|
||
// ValidateDepositString validates format of the string containing deposit details. | ||
func ValidateDepositString(depositString string) error { | ||
if !depositsFormatRegexp.MatchString(depositString) { | ||
return fmt.Errorf( | ||
"[%s] doesn't match pattern: %s", | ||
depositString, | ||
depositsFormatPattern, | ||
) | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.