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

cli: Add support for address book #1087

Merged
merged 2 commits into from
Sep 16, 2022
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
16 changes: 3 additions & 13 deletions cli/cmd/accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import (
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/helpers"
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/modules/accounts"
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/modules/consensusaccounts"
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/testing"
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/types"
)

Expand Down Expand Up @@ -400,18 +399,7 @@ var (
addrToCheck = addr.String()
}

// Safety check for withdrawals to known accounts that are not supported on the consensus layer.
for name, acc := range cliConfig.Global().Wallet.All {
if acc.Address == addrToCheck && !acc.HasConsensusSigner() {
cobra.CheckErr(fmt.Errorf("account '%s' (%s) will not be able to sign transactions on consensus layer", name, acc.Address))
}
}
for name := range testing.TestAccounts {
testAcc, _ := common.LoadTestAccount(name)
if testAcc.Address().String() == addrToCheck && testAcc.ConsensusSigner() == nil {
cobra.CheckErr(fmt.Errorf("test account '%s' (%s) will not be able to sign transactions on consensus layer", name, testAcc.Address().String()))
}
}
cobra.CheckErr(common.CheckLocalAccountIsConsensusCapable(cfg, addrToCheck))

// Parse amount.
// TODO: This should actually query the ParaTime (or config) to check what the consensus
Expand Down Expand Up @@ -501,6 +489,8 @@ var (
var sigTx, meta interface{}
switch npa.ParaTime {
case nil:
cobra.CheckErr(common.CheckLocalAccountIsConsensusCapable(cfg, toAddr.String()))

// Consensus layer transfer.
amount, err := helpers.ParseConsensusDenomination(npa.Network, amount)
cobra.CheckErr(err)
Expand Down
127 changes: 127 additions & 0 deletions cli/cmd/addressbook.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package cmd

import (
"fmt"
"sort"

"github.com/spf13/cobra"

"github.com/oasisprotocol/oasis-sdk/cli/config"
"github.com/oasisprotocol/oasis-sdk/cli/table"
)

var (
addressBookCmd = &cobra.Command{
Use: "addressbook",
Short: "Manage addresses in the local address book",
}

abListCmd = &cobra.Command{
Use: "list",
Aliases: []string{"ls"},
Short: "List addresses stored in address book",
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
cfg := config.Global()
table := table.New()
table.SetHeader([]string{"Name", "Address"})

var output [][]string
for name, acc := range cfg.AddressBook.All {
addrStr := acc.Address
if ethAddr := acc.GetEthAddress(); ethAddr != nil {
addrStr = ethAddr.Hex()
}
output = append(output, []string{
name,
addrStr,
})
}

// Sort output by name.
sort.Slice(output, func(i, j int) bool {
return output[i][0] < output[j][0]
})

table.AppendBulk(output)
table.Render()
},
}

abAddCmd = &cobra.Command{
Use: "add <name> <address>",
Short: "Add an address to address book",
Args: cobra.ExactArgs(2),
Run: func(cmd *cobra.Command, args []string) {
cfg := config.Global()
name := args[0]
address := args[1]

err := cfg.AddressBook.Add(name, address)
cobra.CheckErr(err)

err = cfg.Save()
cobra.CheckErr(err)
},
}

abShowCmd = &cobra.Command{
Use: "show <name>",
Short: "Show address information",
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
name := args[0]
abEntry, ok := config.Global().AddressBook.All[name]
if !ok {
cobra.CheckErr(fmt.Errorf("address named '%s' does not exist in the address book", name))
}

fmt.Printf("Name: %s\n", name)
if abEntry.GetEthAddress() != nil {
fmt.Printf("Ethereum address: %s\n", abEntry.GetEthAddress().Hex())
}
fmt.Printf("Native address: %s\n", abEntry.GetAddress())
},
}

abRmCmd = &cobra.Command{
Use: "rm <name>",
Aliases: []string{"remove"},
Short: "Remove an address from address book",
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
cfg := config.Global()
name := args[0]

err := cfg.AddressBook.Remove(name)
cobra.CheckErr(err)

err = cfg.Save()
cobra.CheckErr(err)
},
}

abRenameCmd = &cobra.Command{
Use: "rename <old> <new>",
Short: "Rename address",
Args: cobra.ExactArgs(2),
Run: func(cmd *cobra.Command, args []string) {
cfg := config.Global()
oldName, newName := args[0], args[1]

err := cfg.AddressBook.Rename(oldName, newName)
cobra.CheckErr(err)

err = cfg.Save()
cobra.CheckErr(err)
},
}
)

func init() {
addressBookCmd.AddCommand(abAddCmd)
addressBookCmd.AddCommand(abListCmd)
addressBookCmd.AddCommand(abRenameCmd)
addressBookCmd.AddCommand(abRmCmd)
addressBookCmd.AddCommand(abShowCmd)
}
34 changes: 33 additions & 1 deletion cli/cmd/common/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,43 @@ func LoadTestAccountConfig(name string) (*config.Account, error) {

// ResolveLocalAccountOrAddress resolves a string address into the corresponding account address.
func ResolveLocalAccountOrAddress(net *configSdk.Network, address string) (*types.Address, error) {
// Check, if address is the account name in the wallet.
// Check if address is the account name in the wallet.
if acc, ok := config.Global().Wallet.All[address]; ok {
addr := acc.GetAddress()
return &addr, nil
}

// Check if address is the name of an address book entry.
if entry, ok := config.Global().AddressBook.All[address]; ok {
addr := entry.GetAddress()
return &addr, nil
}

return helpers.ResolveAddress(net, address)
}

// CheckLocalAccountIsConsensusCapable is a safety check for withdrawals or consensus layer
// transfers to potentially known native addresses which key pairs are not compatible with
// consensus or the address is a derivation of a known Ethereum address.
func CheckLocalAccountIsConsensusCapable(cfg *config.Config, address string) error {
for name, acc := range cfg.Wallet.All {
if acc.Address == address && !acc.HasConsensusSigner() {
return fmt.Errorf("destination account '%s' (%s) will not be able to sign transactions on consensus layer", name, acc.Address)
}
}

for name := range testing.TestAccounts {
testAcc, _ := LoadTestAccount(name)
if testAcc.Address().String() == address && testAcc.ConsensusSigner() == nil {
return fmt.Errorf("test account '%s' (%s) will not be able to sign transactions on consensus layer", name, testAcc.Address().String())
}
}

for name, acc := range cfg.AddressBook.All {
if acc.Address == address && acc.GetEthAddress() != nil {
return fmt.Errorf("destination address named '%s' (%s) will not be able to sign transactions on consensus layer", name, acc.GetEthAddress().Hex())
}
}

return nil
}
1 change: 1 addition & 0 deletions cli/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ func init() {
rootCmd.AddCommand(paratimeCmd)
rootCmd.AddCommand(walletCmd)
rootCmd.AddCommand(accountsCmd)
rootCmd.AddCommand(addressBookCmd)
rootCmd.AddCommand(contractsCmd)
rootCmd.AddCommand(inspect.Cmd)
}
28 changes: 18 additions & 10 deletions cli/cmd/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import (
"github.com/oasisprotocol/oasis-sdk/cli/table"
"github.com/oasisprotocol/oasis-sdk/cli/wallet"
walletFile "github.com/oasisprotocol/oasis-sdk/cli/wallet/file"
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/helpers"
)

var (
Expand Down Expand Up @@ -88,6 +87,9 @@ var (
err = accCfg.SetConfigFromFlags()
cobra.CheckErr(err)

if _, exists := cfg.AddressBook.All[name]; exists {
cobra.CheckErr(fmt.Errorf("address named '%s' already exists in address book", name))
}
err = cfg.Wallet.Create(name, passphrase, accCfg)
cobra.CheckErr(err)

Expand All @@ -104,7 +106,7 @@ var (
name := args[0]

acc := common.LoadAccount(config.Global(), name)
showPublicWalletInfo(acc)
showPublicWalletInfo(name, acc)
},
}

Expand Down Expand Up @@ -186,7 +188,10 @@ var (
name := args[0]

if _, exists := cfg.Wallet.All[name]; exists {
cobra.CheckErr(fmt.Errorf("account '%s' already exists", name))
cobra.CheckErr(fmt.Errorf("account '%s' already exists in the wallet", name))
}
if _, exists := cfg.AddressBook.All[name]; exists {
cobra.CheckErr(fmt.Errorf("address named '%s' already exists in the address book", name))
}

// NOTE: We only support importing into the file-based wallet for now.
Expand All @@ -201,7 +206,7 @@ var (

var kindRaw string
err = survey.AskOne(&survey.Select{
Message: "Import kind:",
Message: "Kind:",
Options: supportedKinds,
}, &kindRaw)
cobra.CheckErr(err)
Expand Down Expand Up @@ -258,7 +263,7 @@ var (
fmt.Printf("WARNING: Exporting the account will expose secret key material!\n")
acc := common.LoadAccount(config.Global(), name)

showPublicWalletInfo(acc)
showPublicWalletInfo(name, acc)

fmt.Printf("Export:\n")
fmt.Println(acc.UnsafeExport())
Expand Down Expand Up @@ -349,12 +354,15 @@ func (sf *accountEntitySignerFactory) Load(
return sf.signer, nil
}

func showPublicWalletInfo(wallet wallet.Account) {
fmt.Printf("Public Key: %s\n", wallet.Signer().Public())
fmt.Printf("Address: %s\n", wallet.Address())
if wallet.SignatureAddressSpec().Secp256k1Eth != nil {
fmt.Printf("Ethereum address: %s\n", helpers.EthAddressFromPubKey(*wallet.SignatureAddressSpec().Secp256k1Eth))
func showPublicWalletInfo(name string, wallet wallet.Account) {
fmt.Printf("Name: %s\n", name)
if signer := wallet.Signer(); signer != nil {
fmt.Printf("Public Key: %s\n", signer.Public())
}
if ethAddr := wallet.EthAddress(); ethAddr != nil {
fmt.Printf("Ethereum address: %s\n", ethAddr.Hex())
}
fmt.Printf("Native address: %s\n", wallet.Address())
}

func init() {
Expand Down
Loading