Skip to content

Commit

Permalink
Konradstaniec/delete endpoint and docs (#115)
Browse files Browse the repository at this point in the history
* refactor sign adr36 to separate function

* add command to delete pop payload
  • Loading branch information
KonradStaniec authored Jan 13, 2025
1 parent 0a59e30 commit d2be612
Show file tree
Hide file tree
Showing 3 changed files with 185 additions and 60 deletions.
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
}

0 comments on commit d2be612

Please sign in to comment.