From edeb436f20b7204023080e0d9428009b1fda9f15 Mon Sep 17 00:00:00 2001 From: Felipe Madero Date: Wed, 22 May 2024 16:20:46 -0400 Subject: [PATCH 1/8] add multisig type --- multisig/multisig.go | 82 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 multisig/multisig.go diff --git a/multisig/multisig.go b/multisig/multisig.go new file mode 100644 index 0000000..e21e8ab --- /dev/null +++ b/multisig/multisig.go @@ -0,0 +1,82 @@ +// Copyright (C) 2022, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. +package multisig + +import ( + "github.com/ava-labs/avalanche-tooling-sdk-go/keychain" + "github.com/ava-labs/avalanche-tooling-sdk-go/network" + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/vms/platformvm/txs" +) + +type PChainTxKind int + +const ( + Invalid = iota + CreateBlockchain + TransferSubnetOwnership +) + +type PChainMultisig struct { + _ *txs.Tx +} + +func New(_ *txs.Tx) *PChainMultisig { + return nil +} + +func (*PChainMultisig) ToBytes() ([]byte, error) { + return nil, nil +} + +func (*PChainMultisig) FromBytes(_ []byte) error { + return nil +} + +func (*PChainMultisig) ToFile(_ string) error { + return nil +} + +func (*PChainMultisig) FromFile(_ string) error { + return nil +} + +func (*PChainMultisig) Sign(_ keychain.Keychain) error { + return nil +} + +func (*PChainMultisig) Commit() error { + return nil +} + +func (*PChainMultisig) IsReadyToCommit() error { + return nil +} + +func (*PChainMultisig) GetRemainingSigners() ([]ids.ID, error) { + return nil, nil +} + +func (*PChainMultisig) GetAuthSigners() ([]ids.ID, error) { + return nil, nil +} + +func (*PChainMultisig) GetFeeSigners() ([]ids.ID, error) { + return nil, nil +} + +func (*PChainMultisig) GetKind() PChainTxKind { + return Invalid +} + +func (*PChainMultisig) GetNetwork() (network.Network, error) { + return nil, nil +} + +func (*PChainMultisig) GetSubnetID() (ids.ID, error) { + return ids.Empty, nil +} + +func (*PChainMultisig) GetSubnetOwners() ([]ids.ID, int, error) { + return nil, 0, nil +} From 8fd699ca41d570599d8031aea55739f207ee1006 Mon Sep 17 00:00:00 2001 From: Raymond Sukanto Date: Tue, 21 May 2024 17:48:19 -0400 Subject: [PATCH 2/8] deploy subnet --- avalanche/app.go | 28 ++++++++++ avalanche/avalanche.go | 8 +++ avalanche/keychain.go | 18 +++++++ avalanche/network.go | 24 +++++++++ avalanche/vm.go | 29 ++++++++++ subnet/deploy_subnet.go | 116 ++++++++++++++++++++++++++++++++++++++++ subnet/subnet.go | 12 ++++- utils/common.go | 13 +++++ 8 files changed, 247 insertions(+), 1 deletion(-) create mode 100644 avalanche/app.go create mode 100644 avalanche/avalanche.go create mode 100644 avalanche/keychain.go create mode 100644 avalanche/network.go create mode 100644 avalanche/vm.go create mode 100644 subnet/deploy_subnet.go create mode 100644 utils/common.go diff --git a/avalanche/app.go b/avalanche/app.go new file mode 100644 index 0000000..60fbb01 --- /dev/null +++ b/avalanche/app.go @@ -0,0 +1,28 @@ +// Copyright (C) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package avalanche + +import "github.com/ava-labs/avalanchego/utils/logging" + +type Avalanche struct { + Log logging.Logger + //baseDir string + //Conf *config.Config + //Prompt prompts.Prompter + //Apm *apm.APM + //ApmDir string + //Downloader Downloader +} + +func New() *Avalanche { + return &Avalanche{} +} + +func (app *Avalanche) Setup(log logging.Logger) { + //app.baseDir = baseDir + app.Log = log + //app.Conf = conf + //app.Prompt = prompt + //app.Downloader = downloader +} diff --git a/avalanche/avalanche.go b/avalanche/avalanche.go new file mode 100644 index 0000000..47770f3 --- /dev/null +++ b/avalanche/avalanche.go @@ -0,0 +1,8 @@ +// Copyright (C) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package avalanche + +const ( + SubnetEVMRepoName = "subnet-evm" +) diff --git a/avalanche/keychain.go b/avalanche/keychain.go new file mode 100644 index 0000000..fd1741c --- /dev/null +++ b/avalanche/keychain.go @@ -0,0 +1,18 @@ +// Copyright (C) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package avalanche + +import "github.com/ava-labs/avalanchego/utils/crypto/keychain" + +type Keychain struct { + Network Network + + Keychain keychain.Keychain + + Ledger keychain.Ledger + + UsesLedger bool + + LedgerIndices []uint32 +} diff --git a/avalanche/network.go b/avalanche/network.go new file mode 100644 index 0000000..fc18bea --- /dev/null +++ b/avalanche/network.go @@ -0,0 +1,24 @@ +// Copyright (C) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package avalanche + +type NetworkKind int64 + +const ( + Undefined NetworkKind = iota + Mainnet + Fuji + LocalNetwork + Devnet +) + +type Network struct { + Kind NetworkKind + + ID uint32 + + Endpoint string + + ClusterName string +} diff --git a/avalanche/vm.go b/avalanche/vm.go new file mode 100644 index 0000000..9d433b2 --- /dev/null +++ b/avalanche/vm.go @@ -0,0 +1,29 @@ +// Copyright (C) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package avalanche + +type VMType string + +const ( + SubnetEvm = "Subnet-EVM" + CustomVM = "Custom" +) + +func VMTypeFromString(s string) VMType { + switch s { + case SubnetEvm: + return SubnetEvm + default: + return CustomVM + } +} + +func (v VMType) RepoName() string { + switch v { + case SubnetEvm: + return SubnetEVMRepoName + default: + return "unknown" + } +} diff --git a/subnet/deploy_subnet.go b/subnet/deploy_subnet.go new file mode 100644 index 0000000..7bef7ef --- /dev/null +++ b/subnet/deploy_subnet.go @@ -0,0 +1,116 @@ +// Copyright (C) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package subnet + +import ( + "avalanche-tooling-sdk-go/avalanche" + "avalanche-tooling-sdk-go/utils" + "context" + "fmt" + "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 createSubnetTx(subnet Subnet, wallet primary.Wallet) (*txs.Tx, error) { + addrs, err := address.ParseToIDs(subnet.ControlKeys) + if err != nil { + return nil, fmt.Errorf("failure parsing control keys: %w", err) + } + owners := &secp256k1fx.OutputOwners{ + Addrs: addrs, + Threshold: subnet.Threshold, + Locktime: 0, + } + unsignedTx, err := wallet.P().Builder().NewCreateSubnetTx( + owners, + ) + if err != nil { + return nil, fmt.Errorf("error building tx: %w", err) + } + tx := txs.Tx{Unsigned: unsignedTx} + if err := wallet.P().Signer().Sign(context.Background(), &tx); err != nil { + return nil, fmt.Errorf("error signing tx: %w", err) + } + return &tx, nil +} + +// createBlockchainTx creates uncommitted createBlockchain transaction +func createBlockchainTx(subnet Subnet, wallet primary.Wallet, network avalanche.Network, keyChain avalanche.Keychain) (*txs.Tx, error) { + wallet, err := loadCacheWallet(network, keyChain, wallet, subnet.SubnetID, subnet.TransferSubnetOwnershipTxID) + if err != nil { + return nil, err + } + fxIDs := make([]ids.ID, 0) + options := getMultisigTxOptions(keyChain.Keychain, subnet.SubnetAuthKeys) + // create tx + unsignedTx, err := wallet.P().Builder().NewCreateChainTx( + subnet.SubnetID, + subnet.Genesis, + subnet.VMID, + fxIDs, + subnet.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 +} + +func loadCacheWallet(network avalanche.Network, keyChain avalanche.Keychain, wallet primary.Wallet, preloadTxs ...ids.ID) (primary.Wallet, error) { + var err error + if wallet == nil { + wallet, err = loadWallet(network, keyChain, preloadTxs...) + } + return wallet, err +} + +func loadWallet(network avalanche.Network, keyChain avalanche.Keychain, preloadTxs ...ids.ID) (primary.Wallet, error) { + ctx := context.Background() + // filter out ids.Empty txs + filteredTxs := utils.Filter(preloadTxs, func(e ids.ID) bool { return e != ids.Empty }) + wallet, err := primary.MakeWallet( + ctx, + &primary.WalletConfig{ + URI: network.Endpoint, + AVAXKeychain: keyChain.Keychain, + EthKeychain: secp256k1fx.NewKeychain(), + PChainTxsToFetch: set.Of(filteredTxs...), + }, + ) + if err != nil { + return nil, err + } + return wallet, nil +} diff --git a/subnet/subnet.go b/subnet/subnet.go index bbdba05..271687d 100644 --- a/subnet/subnet.go +++ b/subnet/subnet.go @@ -21,6 +21,8 @@ type SubnetParams struct { // Custom VM parameters to use // Do not set CustomVM value if you are using Subnet-EVM CustomVM CustomVMParams + + Name string } type SubnetEVMParams struct { @@ -86,11 +88,13 @@ type CustomVMParams struct { } type Subnet struct { + Name string + Genesis []byte ControlKeys []string - SubnetAuthKeys []string + SubnetAuthKeys []ids.ShortID SubnetID ids.ID @@ -101,4 +105,10 @@ type Subnet struct { Threshold uint32 VMID ids.ID + + RPCVersion int + + TokenName string + + TokenSymbol string } diff --git a/utils/common.go b/utils/common.go new file mode 100644 index 0000000..fbe5340 --- /dev/null +++ b/utils/common.go @@ -0,0 +1,13 @@ +// Copyright (C) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. +package utils + +func Filter[T any](input []T, f func(T) bool) []T { + output := make([]T, 0, len(input)) + for _, e := range input { + if f(e) { + output = append(output, e) + } + } + return output +} From 4897d88f6828d7429555d25f3c0e4bfdb499829e Mon Sep 17 00:00:00 2001 From: Raymond Sukanto Date: Tue, 21 May 2024 17:48:40 -0400 Subject: [PATCH 3/8] deploy subnet --- avalanche/network.go | 8 -------- 1 file changed, 8 deletions(-) diff --git a/avalanche/network.go b/avalanche/network.go index fc18bea..3c7a775 100644 --- a/avalanche/network.go +++ b/avalanche/network.go @@ -5,14 +5,6 @@ package avalanche type NetworkKind int64 -const ( - Undefined NetworkKind = iota - Mainnet - Fuji - LocalNetwork - Devnet -) - type Network struct { Kind NetworkKind From 8ccf5bfac28d0260304154faab78e8ac83c6eaf4 Mon Sep 17 00:00:00 2001 From: Raymond Sukanto Date: Wed, 22 May 2024 11:57:10 -0400 Subject: [PATCH 4/8] remove app go --- avalanche/app.go | 28 ---------------------------- 1 file changed, 28 deletions(-) delete mode 100644 avalanche/app.go diff --git a/avalanche/app.go b/avalanche/app.go deleted file mode 100644 index 60fbb01..0000000 --- a/avalanche/app.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (C) 2024, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package avalanche - -import "github.com/ava-labs/avalanchego/utils/logging" - -type Avalanche struct { - Log logging.Logger - //baseDir string - //Conf *config.Config - //Prompt prompts.Prompter - //Apm *apm.APM - //ApmDir string - //Downloader Downloader -} - -func New() *Avalanche { - return &Avalanche{} -} - -func (app *Avalanche) Setup(log logging.Logger) { - //app.baseDir = baseDir - app.Log = log - //app.Conf = conf - //app.Prompt = prompt - //app.Downloader = downloader -} From a6bbab4d8d4be75b72e162935fbbac5348ec316b Mon Sep 17 00:00:00 2001 From: Raymond Sukanto Date: Wed, 22 May 2024 16:30:54 -0400 Subject: [PATCH 5/8] update load wallet --- subnet/deploy_subnet.go | 34 +--------------------------------- 1 file changed, 1 insertion(+), 33 deletions(-) diff --git a/subnet/deploy_subnet.go b/subnet/deploy_subnet.go index 7bef7ef..54a225f 100644 --- a/subnet/deploy_subnet.go +++ b/subnet/deploy_subnet.go @@ -5,7 +5,6 @@ package subnet import ( "avalanche-tooling-sdk-go/avalanche" - "avalanche-tooling-sdk-go/utils" "context" "fmt" "github.com/ava-labs/avalanchego/ids" @@ -43,11 +42,7 @@ func createSubnetTx(subnet Subnet, wallet primary.Wallet) (*txs.Tx, error) { } // createBlockchainTx creates uncommitted createBlockchain transaction -func createBlockchainTx(subnet Subnet, wallet primary.Wallet, network avalanche.Network, keyChain avalanche.Keychain) (*txs.Tx, error) { - wallet, err := loadCacheWallet(network, keyChain, wallet, subnet.SubnetID, subnet.TransferSubnetOwnershipTxID) - if err != nil { - return nil, err - } +func createBlockchainTx(subnet Subnet, wallet primary.Wallet, keyChain avalanche.Keychain) (*txs.Tx, error) { fxIDs := make([]ids.ID, 0) options := getMultisigTxOptions(keyChain.Keychain, subnet.SubnetAuthKeys) // create tx @@ -87,30 +82,3 @@ func getMultisigTxOptions(keychain keychain.Keychain, subnetAuthKeys []ids.Short options = append(options, common.WithChangeOwner(changeOwner)) return options } - -func loadCacheWallet(network avalanche.Network, keyChain avalanche.Keychain, wallet primary.Wallet, preloadTxs ...ids.ID) (primary.Wallet, error) { - var err error - if wallet == nil { - wallet, err = loadWallet(network, keyChain, preloadTxs...) - } - return wallet, err -} - -func loadWallet(network avalanche.Network, keyChain avalanche.Keychain, preloadTxs ...ids.ID) (primary.Wallet, error) { - ctx := context.Background() - // filter out ids.Empty txs - filteredTxs := utils.Filter(preloadTxs, func(e ids.ID) bool { return e != ids.Empty }) - wallet, err := primary.MakeWallet( - ctx, - &primary.WalletConfig{ - URI: network.Endpoint, - AVAXKeychain: keyChain.Keychain, - EthKeychain: secp256k1fx.NewKeychain(), - PChainTxsToFetch: set.Of(filteredTxs...), - }, - ) - if err != nil { - return nil, err - } - return wallet, nil -} From 7e427428710bd754fc34c3bcf105211da2657e63 Mon Sep 17 00:00:00 2001 From: Raymond Sukanto Date: Wed, 22 May 2024 16:33:12 -0400 Subject: [PATCH 6/8] address comments --- avalanche/network.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/avalanche/network.go b/avalanche/network.go index 3c7a775..76f09df 100644 --- a/avalanche/network.go +++ b/avalanche/network.go @@ -11,6 +11,4 @@ type Network struct { ID uint32 Endpoint string - - ClusterName string } From c5b14afef2c8b1bfdfd1df9317dc66e9a1310d6b Mon Sep 17 00:00:00 2001 From: Raymond Sukanto Date: Wed, 22 May 2024 16:37:10 -0400 Subject: [PATCH 7/8] fix lint --- subnet/deploy_subnet.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/subnet/deploy_subnet.go b/subnet/deploy_subnet.go index 54a225f..81aae0c 100644 --- a/subnet/deploy_subnet.go +++ b/subnet/deploy_subnet.go @@ -4,9 +4,11 @@ package subnet import ( - "avalanche-tooling-sdk-go/avalanche" "context" "fmt" + + "avalanche-tooling-sdk-go/avalanche" + "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/crypto/keychain" "github.com/ava-labs/avalanchego/utils/formatting/address" From 8474677a473163e30c0c7a923e5d0a8378026ad8 Mon Sep 17 00:00:00 2001 From: Felipe Madero Date: Wed, 22 May 2024 16:43:28 -0400 Subject: [PATCH 8/8] fix wallet instead of keychain --- multisig/multisig.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/multisig/multisig.go b/multisig/multisig.go index e21e8ab..a7316b5 100644 --- a/multisig/multisig.go +++ b/multisig/multisig.go @@ -3,10 +3,10 @@ package multisig import ( - "github.com/ava-labs/avalanche-tooling-sdk-go/keychain" "github.com/ava-labs/avalanche-tooling-sdk-go/network" "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 @@ -41,7 +41,7 @@ func (*PChainMultisig) FromFile(_ string) error { return nil } -func (*PChainMultisig) Sign(_ keychain.Keychain) error { +func (*PChainMultisig) Sign(_ *primary.Wallet) error { return nil }