Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Konradstaniec/delete endpoint and docs #115

Merged
merged 5 commits into from
Jan 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)

- [#111](https://github.com/babylonlabs-io/btc-staker/pull/111) Add CLI command
to create phase-1/phase-2 PoP payload
- [#115](https://github.com/babylonlabs-io/btc-staker/pull/115) Add CLI command
to create payload for phase-1/phase-2 PoP deletion

## v0.14.0

Expand Down
131 changes: 126 additions & 5 deletions cmd/stakercli/pop/pop.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package pop

import (
"encoding/base64"
"fmt"
"strconv"

"github.com/babylonlabs-io/btc-staker/babylonclient/keyringcontroller"
"github.com/babylonlabs-io/btc-staker/cmd/stakercli/helpers"
Expand Down Expand Up @@ -35,15 +37,16 @@ var PopCommands = []cli.Command{
Usage: "Commands realted to generation and verification of the Proof of Possession",
Category: "PoP commands",
Subcommands: []cli.Command{
generatePopCmd,
generateCreatePopCmd,
generateDeletePopCmd,
},
},
}

var generatePopCmd = cli.Command{
Name: "generate-pop",
ShortName: "gp",
Usage: "stakercli pop generate-pop",
var generateCreatePopCmd = cli.Command{
Name: "generate-create-pop",
ShortName: "gcp",
Usage: "stakercli pop generate-create-pop",
Flags: []cli.Flag{
cli.StringFlag{
Name: btcAddressFlag,
Expand Down Expand Up @@ -163,3 +166,121 @@ func generatePop(c *cli.Context) error {

return nil
}

var generateDeletePopCmd = cli.Command{
Name: "generate-delete-pop",
ShortName: "gdp",
Usage: "stakercli pop generate-delete-pop",
Flags: []cli.Flag{
cli.StringFlag{
Name: btcAddressFlag,
Usage: "Bitcoin address to delete proof of possession for",
Required: true,
},
cli.StringFlag{
Name: babyAddressFlag,
Usage: "Baby address to delete proof of possession for",
Required: true,
},
cli.StringFlag{
Name: msgFlag,
Usage: "message to sign",
Required: true,
},
cli.StringFlag{
Name: babyAddressPrefixFlag,
Usage: "Baby address prefix",
Value: "bbn",
},
cli.StringFlag{
Name: btcNetworkFlag,
Usage: "Bitcoin network on which staking should take place (testnet3, mainnet, regtest, simnet, signet)",
Value: "testnet3",
},
cli.StringFlag{
Name: keyringDirFlag,
Usage: "Keyring directory",
Value: "",
},
cli.StringFlag{
Name: keyringBackendFlag,
Usage: "Keyring backend",
Value: "test",
},
},
Action: generateDeletePop,
}

type DeletePopPayload struct {
BabyAddress string `json:"babyAddress"`
BabySignature string `json:"babySignature"`
BabyPublicKey string `json:"babyPublicKey"`
BtcAddress string `json:"btcAddress"`
}

func generateDeletePop(c *cli.Context) error {
network := c.String(btcNetworkFlag)

networkParams, err := ut.GetBtcNetworkParams(network)
if err != nil {
return err
}

btcAddress, err := btcutil.DecodeAddress(c.String(btcAddressFlag), networkParams)
if err != nil {
return fmt.Errorf("failed to decode bitcoin address: %w", err)
}

babylonAddress := c.String(babyAddressFlag)
babyAddressPrefix := c.String(babyAddressPrefixFlag)

sdkAddressBytes, err := sdk.GetFromBech32(babylonAddress, babyAddressPrefix)
if err != nil {
return fmt.Errorf("failed to decode baby address: %w", err)
}

sdkAddress := sdk.AccAddress(sdkAddressBytes)

keyringDir := c.String(keyringDirFlag)
keyringBackend := c.String(keyringBackendFlag)

keyring, err := keyringcontroller.CreateKeyring(keyringDir, "babylon", keyringBackend, nil)
if err != nil {
return err
}

record, babyPubKey, err := staker.GetBabyPubKey(keyring, sdkAddress)
if err != nil {
return err
}

msg := c.String(msgFlag)

// We are assuming we are receiving string literal with escape characters
interpretedMsg, err := strconv.Unquote(`"` + msg + `"`)
if err != nil {
return err
}

signature, err := staker.SignCosmosAdr36(
keyring,
record.Name,
sdkAddress.String(),
[]byte(interpretedMsg),
)

if err != nil {
return err
}

payload := DeletePopPayload{
BabyAddress: sdkAddress.String(),
BabySignature: base64.StdEncoding.EncodeToString(signature),
BabyPublicKey: base64.StdEncoding.EncodeToString(babyPubKey.Bytes()),
BtcAddress: btcAddress.String(),
}

helpers.PrintRespJSON(payload)

return nil
}
112 changes: 57 additions & 55 deletions staker/pop_creator.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,59 +42,6 @@ func NewPopCreator(bitcoinWalletController *walletcontroller.RPCWalletController
}
}

func (pc *PopCreator) getBabyPubKey(babylonAddress sdk.AccAddress) (*keyring.Record, *secp256k1.PubKey, error) {
record, err := pc.KeyRing.KeyByAddress(babylonAddress)

if err != nil {
return nil, nil, err
}

pubKey, err := record.GetPubKey()

if err != nil {
return nil, nil, err
}

switch v := pubKey.(type) {
case *secp256k1.PubKey:
return record, v, nil
default:
return nil, nil, fmt.Errorf("unsupported key type in keyring")
}
}

func (pc *PopCreator) signCosmosAdr36(
keyName string,
cosmosBech32Address string,
bytesToSign []byte,
) ([]byte, error) {
base64Bytes := base64.StdEncoding.EncodeToString(bytesToSign)

signDoc := NewCosmosSignDoc(
cosmosBech32Address,
base64Bytes,
)

marshaled, err := json.Marshal(signDoc)
if err != nil {
return nil, fmt.Errorf("failed to marshal sign doc: %w", err)
}

bz := sdk.MustSortJSON(marshaled)

babySignBTCAddress, _, err := pc.KeyRing.Sign(
keyName,
bz,
signing.SignMode_SIGN_MODE_DIRECT,
)

if err != nil {
return nil, fmt.Errorf("failed to sign btc address bytes: %w", err)
}

return babySignBTCAddress, nil
}

func (pc *PopCreator) CreatePop(
btcAddress btcutil.Address,
babyAddressPrefix string,
Expand Down Expand Up @@ -124,12 +71,13 @@ func (pc *PopCreator) CreatePop(
return nil, err
}

record, babyPubKey, err := pc.getBabyPubKey(babyAddress)
record, babyPubKey, err := GetBabyPubKey(pc.KeyRing, babyAddress)
if err != nil {
return nil, err
}

babySignBTCAddress, err := pc.signCosmosAdr36(
babySignBTCAddress, err := SignCosmosAdr36(
pc.KeyRing,
record.Name,
bech32cosmosAddressString,
[]byte(btcAddress.String()),
Expand Down Expand Up @@ -197,3 +145,57 @@ func NewCosmosSignDoc(
Memo: "",
}
}

func GetBabyPubKey(kr keyring.Keyring, babylonAddress sdk.AccAddress) (*keyring.Record, *secp256k1.PubKey, error) {
record, err := kr.KeyByAddress(babylonAddress)

if err != nil {
return nil, nil, err
}

pubKey, err := record.GetPubKey()

if err != nil {
return nil, nil, err
}

switch v := pubKey.(type) {
case *secp256k1.PubKey:
return record, v, nil
default:
return nil, nil, fmt.Errorf("unsupported key type in keyring")
}
}

func SignCosmosAdr36(
kr keyring.Keyring,
keyName string,
cosmosBech32Address string,
bytesToSign []byte,
) ([]byte, error) {
base64Bytes := base64.StdEncoding.EncodeToString(bytesToSign)

signDoc := NewCosmosSignDoc(
cosmosBech32Address,
base64Bytes,
)

marshaled, err := json.Marshal(signDoc)
if err != nil {
return nil, fmt.Errorf("failed to marshal sign doc: %w", err)
}

bz := sdk.MustSortJSON(marshaled)

babySignBTCAddress, _, err := kr.Sign(
keyName,
bz,
signing.SignMode_SIGN_MODE_DIRECT,
)

if err != nil {
return nil, fmt.Errorf("failed to sign btc address bytes: %w", err)
}

return babySignBTCAddress, nil
}
Loading