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..76f09df --- /dev/null +++ b/avalanche/network.go @@ -0,0 +1,14 @@ +// Copyright (C) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package avalanche + +type NetworkKind int64 + +type Network struct { + Kind NetworkKind + + ID uint32 + + Endpoint 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/multisig/multisig.go b/multisig/multisig.go new file mode 100644 index 0000000..a7316b5 --- /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/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 + +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(_ *primary.Wallet) 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 +} diff --git a/subnet/deploy_subnet.go b/subnet/deploy_subnet.go new file mode 100644 index 0000000..81aae0c --- /dev/null +++ b/subnet/deploy_subnet.go @@ -0,0 +1,86 @@ +// Copyright (C) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package subnet + +import ( + "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" + "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, keyChain avalanche.Keychain) (*txs.Tx, error) { + 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 +} 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 +}