Skip to content

Commit

Permalink
Merge pull request #17 from ava-labs/apply-multisig
Browse files Browse the repository at this point in the history
use multisig as create tx output, and wrap wallet for multisig options
  • Loading branch information
felipemadero authored May 28, 2024
2 parents 1afa484 + 0b09c3a commit dfc3414
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 60 deletions.
56 changes: 29 additions & 27 deletions multisig/multisig.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,80 +3,82 @@
package multisig

import (
"github.com/ava-labs/avalanche-tooling-sdk-go/network"
"avalanche-tooling-sdk-go/avalanche"

"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/vms/platformvm/txs"
"github.com/ava-labs/avalanchego/wallet/subnet/primary"
)

type PChainTxKind int

const (
Invalid = iota
CreateBlockchain
TransferSubnetOwnership
)
type TxKind struct {
_ string // vm
_ string // tx
}

type PChainMultisig struct {
_ *txs.Tx
type Multisig struct {
_ *txs.Tx // pChainTx
}

func New(_ *txs.Tx) *PChainMultisig {
func New(_ *txs.Tx) *Multisig {
return nil
}

func (*PChainMultisig) ToBytes() ([]byte, error) {
func (*Multisig) ToBytes() ([]byte, error) {
return nil, nil
}

func (*PChainMultisig) FromBytes(_ []byte) error {
func (*Multisig) FromBytes(_ []byte) error {
return nil
}

func (*PChainMultisig) ToFile(_ string) error {
func (*Multisig) ToFile(_ string) error {
return nil
}

func (*PChainMultisig) FromFile(_ string) error {
func (*Multisig) FromFile(_ string) error {
return nil
}

func (*PChainMultisig) Sign(_ *primary.Wallet) error {
func (*Multisig) Sign(_ *primary.Wallet) error {
return nil
}

func (*PChainMultisig) Commit() error {
func (*Multisig) Commit() error {
return nil
}

func (*PChainMultisig) IsReadyToCommit() error {
func (*Multisig) IsReadyToCommit() error {
return nil
}

func (*PChainMultisig) GetRemainingSigners() ([]ids.ID, error) {
func (*Multisig) GetRemainingSigners() ([]ids.ID, error) {
return nil, nil
}

func (*PChainMultisig) GetAuthSigners() ([]ids.ID, error) {
func (*Multisig) GetAuthSigners() ([]ids.ID, error) {
return nil, nil
}

func (*PChainMultisig) GetFeeSigners() ([]ids.ID, error) {
func (*Multisig) GetFeeSigners() ([]ids.ID, error) {
return nil, nil
}

func (*PChainMultisig) GetKind() PChainTxKind {
return Invalid
func (*Multisig) GetTxKind() TxKind {
return TxKind{}
}

func (*PChainMultisig) GetNetwork() (network.Network, error) {
return nil, nil
func (*Multisig) GetNetwork() (avalanche.Network, error) {
return avalanche.Network{}, nil
}

func (*Multisig) GetBlockchainID() (ids.ID, error) {
return ids.Empty, nil
}

func (*PChainMultisig) GetSubnetID() (ids.ID, error) {
func (*Multisig) GetSubnetID() (ids.ID, error) {
return ids.Empty, nil
}

func (*PChainMultisig) GetSubnetOwners() ([]ids.ID, int, error) {
func (*Multisig) GetSubnetOwners() ([]ids.ID, int, error) {
return nil, 0, nil
}
38 changes: 7 additions & 31 deletions subnet/deploy_subnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,16 @@ import (
"context"
"fmt"

Check failure on line 9 in subnet/deploy_subnet.go

View workflow job for this annotation

GitHub Actions / Lint

File is not `gofumpt`-ed (gofumpt)
"avalanche-tooling-sdk-go/avalanche"
"avalanche-tooling-sdk-go/multisig"

"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/utils/crypto/keychain"
"github.com/ava-labs/avalanchego/utils/formatting/address"
"github.com/ava-labs/avalanchego/utils/set"
"github.com/ava-labs/avalanchego/vms/platformvm/txs"
"github.com/ava-labs/avalanchego/vms/secp256k1fx"
"github.com/ava-labs/avalanchego/wallet/subnet/primary"
"github.com/ava-labs/avalanchego/wallet/subnet/primary/common"
)

// CreateSubnetTx creates uncommitted createSubnet transaction
func (c *Subnet) CreateSubnetTx(wallet primary.Wallet) (*txs.Tx, error) {
func (c *Subnet) CreateSubnetTx(wallet Wallet) (*multisig.Multisig, error) {
addrs, err := address.ParseToIDs(c.ControlKeys)
if err != nil {
return nil, fmt.Errorf("failure parsing control keys: %w", err)
Expand All @@ -40,47 +36,27 @@ func (c *Subnet) CreateSubnetTx(wallet primary.Wallet) (*txs.Tx, error) {
if err := wallet.P().Signer().Sign(context.Background(), &tx); err != nil {
return nil, fmt.Errorf("error signing tx: %w", err)
}
return &tx, nil
return multisig.New(&tx), nil
}

// CreateBlockchainTx creates uncommitted createBlockchain transaction
func (c *Subnet) CreateBlockchainTx(wallet primary.Wallet, keyChain avalanche.Keychain) (*txs.Tx, error) {
fxIDs := make([]ids.ID, 0)
options := getMultisigTxOptions(keyChain.Keychain, c.SubnetAuthKeys)
func (c *Subnet) CreateBlockchainTx(wallet Wallet) (*multisig.Multisig, error) {
wallet.SetSubnetAuthMultisig(c.SubnetAuthKeys)
// create tx
fxIDs := make([]ids.ID, 0)
unsignedTx, err := wallet.P().Builder().NewCreateChainTx(
c.SubnetID,
c.Genesis,
c.VMID,
fxIDs,
c.Name,
options...,
)
if err != nil {
return nil, fmt.Errorf("error building tx: %w", err)
}
tx := txs.Tx{Unsigned: unsignedTx}
// sign with current wallet
if err := wallet.P().Signer().Sign(context.Background(), &tx); err != nil {
return nil, fmt.Errorf("error signing tx: %w", err)
}
return &tx, nil
}

func getMultisigTxOptions(keychain keychain.Keychain, subnetAuthKeys []ids.ShortID) []common.Option {
options := []common.Option{}
walletAddrs := keychain.Addresses().List()
changeAddr := walletAddrs[0]
// addrs to use for signing
customAddrsSet := set.Set[ids.ShortID]{}
customAddrsSet.Add(walletAddrs...)
customAddrsSet.Add(subnetAuthKeys...)
options = append(options, common.WithCustomAddresses(customAddrsSet))
// set change to go to wallet addr (instead of any other subnet auth key)
changeOwner := &secp256k1fx.OutputOwners{
Threshold: 1,
Addrs: []ids.ShortID{changeAddr},
}
options = append(options, common.WithChangeOwner(changeOwner))
return options
return multisig.New(&tx), nil
}
5 changes: 3 additions & 2 deletions subnet/subnet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ import (
"avalanche-tooling-sdk-go/avalanche"
"context"
"fmt"
"testing"

"github.com/ava-labs/avalanchego/vms/secp256k1fx"
"github.com/ava-labs/avalanchego/wallet/subnet/primary"
"testing"
)

func TestSubnetDeploy(t *testing.T) {

Check warning on line 16 in subnet/subnet_test.go

View workflow job for this annotation

GitHub Actions / Lint

unused-parameter: parameter 't' seems to be unused, consider removing or renaming it as _ (revive)
Expand All @@ -27,7 +28,7 @@ func TestSubnetDeploy(t *testing.T) {
}
newSubnet := New(baseApp, &subnetParams)
ctx := context.Background()
wallet, _ := primary.MakeWallet(
wallet, _ := NewWallet(
ctx,
&primary.WalletConfig{
URI: "",
Expand Down
63 changes: 63 additions & 0 deletions subnet/wallet.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright (C) 2024, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package subnet

import (
"context"

"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/utils/crypto/keychain"
"github.com/ava-labs/avalanchego/utils/set"
"github.com/ava-labs/avalanchego/vms/secp256k1fx"
"github.com/ava-labs/avalanchego/wallet/subnet/primary"
"github.com/ava-labs/avalanchego/wallet/subnet/primary/common"
)

type Wallet struct {
primary.Wallet
keychain keychain.Keychain
options []common.Option
}

func NewWallet(ctx context.Context, config *primary.WalletConfig) (Wallet, error) {
wallet, err := primary.MakeWallet(
ctx,
config,
)
return Wallet{
Wallet: wallet,
keychain: config.AVAXKeychain,
}, err
}

// secure that a fee paying address (wallet's keychain) will receive the change,
// and not a randomly selected auth key that may not be paying fees
func (w *Wallet) SecureWalletIsChangeOwner() {
addrs := w.keychain.Addresses().List()
changeAddr := addrs[0]
// set change to go to wallet addr (instead of any other subnet auth key)
changeOwner := &secp256k1fx.OutputOwners{
Threshold: 1,
Addrs: []ids.ShortID{changeAddr},
}
// TODO: avoid continuosly adding the options in succesive calls

Check failure on line 44 in subnet/wallet.go

View workflow job for this annotation

GitHub Actions / Lint

`continuosly` is a misspelling of `continuously` (misspell)
w.options = append(w.options, common.WithChangeOwner(changeOwner))
w.Wallet = primary.NewWalletWithOptions(w.Wallet, w.options...)
}

// set auth keys that will also used when signing txs, besides the wallet's keychain fee paying ones
func (w *Wallet) SetAuthKeys(authKeys []ids.ShortID) {
addrs := w.keychain.Addresses().List()
addrsSet := set.Set[ids.ShortID]{}
addrsSet.Add(addrs...)
addrsSet.Add(authKeys...)
// TODO: avoid continuosly adding the options in succesive calls

Check failure on line 55 in subnet/wallet.go

View workflow job for this annotation

GitHub Actions / Lint

`continuosly` is a misspelling of `continuously` (misspell)
w.options = append(w.options, common.WithCustomAddresses(addrsSet))
w.Wallet = primary.NewWalletWithOptions(w.Wallet, w.options...)
}

func (w *Wallet) SetSubnetAuthMultisig(authKeys []ids.ShortID) {
w.SecureWalletIsChangeOwner()
w.SetAuthKeys(authKeys)
}

0 comments on commit dfc3414

Please sign in to comment.