mirror of
https://github.com/luxfi/cli.git
synced 2026-10-30 17:01:20 +00:00
Adds .hanzo/workflows/cicd.yml calling the canonical pipeline and drops the GitHub-hosted workflows it replaces. Lands here because this is where the repo is written — git.hanzo.ai is upstream and github.com is its push mirror, so the same change made on github.com never reaches the runner fleet.
170 lines
4.7 KiB
Go
170 lines
4.7 KiB
Go
// Copyright (C) 2022-2025, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package txutils
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/luxfi/address"
|
|
"github.com/luxfi/cli/pkg/key"
|
|
"github.com/luxfi/constants"
|
|
"github.com/luxfi/ids"
|
|
"github.com/luxfi/proto/p/txs"
|
|
"github.com/luxfi/sdk/models"
|
|
"github.com/luxfi/sdk/platformvm"
|
|
"github.com/luxfi/utxo/secp256k1fx"
|
|
)
|
|
|
|
// GetNetwork returns the network model associated with a tx.
|
|
// Handles the chain-owner-authorized forms (CreateChainTx,
|
|
// ConvertNetworkToL1Tx) and the legacy AddChainValidatorTx /
|
|
// RemoveChainValidatorTx — kept here for one release cycle while the
|
|
// sovereign-L1 model phases in.
|
|
func GetNetwork(tx *txs.Tx) (models.Network, error) {
|
|
unsignedTx := tx.Unsigned
|
|
var networkID uint32
|
|
switch unsignedTx := unsignedTx.(type) {
|
|
case *txs.RemoveChainValidatorTx:
|
|
networkID = unsignedTx.BaseTx.NetworkID
|
|
case *txs.AddChainValidatorTx:
|
|
// Deprecated path — AddValidatorTx (primary network) is preferred.
|
|
networkID = unsignedTx.BaseTx.NetworkID
|
|
case *txs.CreateChainTx:
|
|
networkID = unsignedTx.BaseTx.NetworkID
|
|
case *txs.ConvertNetworkToL1Tx:
|
|
networkID = unsignedTx.BaseTx.NetworkID
|
|
default:
|
|
return models.Undefined, fmt.Errorf("unexpected unsigned tx type %T", unsignedTx)
|
|
}
|
|
network := models.NetworkFromNetworkID(networkID)
|
|
if network == models.Undefined {
|
|
return models.Undefined, fmt.Errorf("undefined network model for tx")
|
|
}
|
|
return network, nil
|
|
}
|
|
|
|
// GetLedgerDisplayName returns the display name for a tx on the ledger.
|
|
func GetLedgerDisplayName(tx *txs.Tx) string {
|
|
unsignedTx := tx.Unsigned
|
|
switch unsignedTx.(type) {
|
|
case *txs.AddChainValidatorTx:
|
|
// Deprecated tx type — kept for one release cycle.
|
|
return "AddChainValidator"
|
|
case *txs.CreateChainTx:
|
|
return "CreateChain"
|
|
default:
|
|
return ""
|
|
}
|
|
}
|
|
|
|
// IsCreateChainTx returns true if the tx is a CreateChainTx.
|
|
func IsCreateChainTx(tx *txs.Tx) bool {
|
|
_, ok := tx.Unsigned.(*txs.CreateChainTx)
|
|
return ok
|
|
}
|
|
|
|
// ChainOwners contains the ownership information for a chain
|
|
type ChainOwners struct {
|
|
IsPermissioned bool
|
|
ControlKeys []string
|
|
Threshold uint32
|
|
}
|
|
|
|
// GetChainOwners retrieves ownership information for a chain
|
|
func GetChainOwners(network models.Network, chainID ids.ID) (*ChainOwners, error) {
|
|
pClient, err := getPlatformClient(network)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
tx, err := getChainTx(pClient, chainID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
createChainTx, ok := tx.Unsigned.(*txs.CreateNetworkTx)
|
|
if !ok {
|
|
return nil, fmt.Errorf("got unexpected type %T for chain tx %s", tx.Unsigned, chainID)
|
|
}
|
|
|
|
owner, ok := createChainTx.Owner.(*secp256k1fx.OutputOwners)
|
|
if !ok {
|
|
// If not a standard OutputOwners, it might be a different owner type
|
|
// For now, treat as non-permissioned
|
|
return &ChainOwners{IsPermissioned: false}, nil
|
|
}
|
|
|
|
// Format control keys as strings
|
|
controlKeysStrs, err := formatControlKeys(network, owner.Addrs)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &ChainOwners{
|
|
IsPermissioned: true,
|
|
ControlKeys: controlKeysStrs,
|
|
Threshold: owner.Threshold,
|
|
}, nil
|
|
}
|
|
|
|
// GetOwners returns ownership information in the legacy format (for backward compatibility)
|
|
func GetOwners(network models.Network, chainID ids.ID) (bool, []string, uint32, error) {
|
|
owners, err := GetChainOwners(network, chainID)
|
|
if err != nil {
|
|
return false, nil, 0, err
|
|
}
|
|
return owners.IsPermissioned, owners.ControlKeys, owners.Threshold, nil
|
|
}
|
|
|
|
// Helper functions for better composability
|
|
|
|
func getPlatformClient(network models.Network) (*platformvm.Client, error) {
|
|
var api string
|
|
switch network {
|
|
case models.Testnet:
|
|
api = constants.TestnetAPIEndpoint
|
|
case models.Mainnet:
|
|
api = constants.MainnetAPIEndpoint
|
|
case models.Local:
|
|
api = constants.LocalAPIEndpoint
|
|
default:
|
|
return nil, fmt.Errorf("network not supported: %v", network)
|
|
}
|
|
return platformvm.NewClient(api), nil
|
|
}
|
|
|
|
func getChainTx(pClient *platformvm.Client, chainID ids.ID) (*txs.Tx, error) {
|
|
ctx := context.Background()
|
|
txBytes, err := pClient.GetTx(ctx, chainID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("chain tx %s query error: %w", chainID, err)
|
|
}
|
|
|
|
tx, err := txs.Parse(txBytes)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("couldn't parse tx %s: %w", chainID, err)
|
|
}
|
|
return tx, nil
|
|
}
|
|
|
|
func formatControlKeys(network models.Network, addrs []ids.ShortID) ([]string, error) {
|
|
networkID, err := network.NetworkID()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
hrp := key.GetHRP(networkID)
|
|
controlKeysStrs := make([]string, 0, len(addrs))
|
|
|
|
for _, addr := range addrs {
|
|
addrStr, err := address.Format("P", hrp, addr[:])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
controlKeysStrs = append(controlKeysStrs, addrStr)
|
|
}
|
|
return controlKeysStrs, nil
|
|
}
|