mirror of
https://github.com/luxfi/cli.git
synced 2026-10-30 17:01:20 +00:00
311 lines
8.6 KiB
Go
311 lines
8.6 KiB
Go
// Copyright (C) 2022-2025, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package contract
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"math/big"
|
|
|
|
"github.com/luxfi/cli/pkg/application"
|
|
"github.com/luxfi/cli/pkg/key"
|
|
"github.com/luxfi/cli/pkg/utils"
|
|
"github.com/luxfi/crypto"
|
|
"github.com/luxfi/evm/precompile/contracts/nativeminter"
|
|
"github.com/luxfi/genesis/pkg/genesis"
|
|
"github.com/luxfi/sdk/models"
|
|
)
|
|
|
|
// returns information for the blockchain default allocation key
|
|
// if found, returns
|
|
// key name, address, private key
|
|
func GetDefaultBlockchainAirdropKeyInfo(
|
|
app *application.Lux,
|
|
blockchainName string,
|
|
) (string, string, string, error) {
|
|
keyName := genesis.GetDefaultBlockchainAirdropKeyName(blockchainName)
|
|
keyPath := app.GetKeyPath(keyName)
|
|
if utils.FileExists(keyPath) {
|
|
k, err := key.LoadSoft(models.NewLocalNetwork().ID(), keyPath)
|
|
if err != nil {
|
|
return "", "", "", err
|
|
}
|
|
return keyName, k.C(), k.PrivKeyHex(), nil
|
|
}
|
|
return "", "", "", nil
|
|
}
|
|
|
|
// from a given genesis, look for known private keys inside it, giving
|
|
// preference to the ones expected to be default
|
|
// it searches for:
|
|
// 1) default CLI allocation key for blockchains
|
|
// 2) all other stored keys managed by CLI
|
|
// returns address + private key when found
|
|
func GetBlockchainAirdropKeyInfo(
|
|
app *application.Lux,
|
|
network models.Network,
|
|
blockchainName string,
|
|
genesisData []byte,
|
|
) (string, string, string, error) {
|
|
genesis, err := utils.ByteSliceToEVMGenesis(genesisData)
|
|
if err != nil {
|
|
return "", "", "", err
|
|
}
|
|
if blockchainName != "" {
|
|
airdropKeyName, airdropAddress, airdropPrivKey, err := GetDefaultBlockchainAirdropKeyInfo(app, blockchainName)
|
|
if err != nil {
|
|
return "", "", "", err
|
|
}
|
|
for address := range genesis.Alloc {
|
|
if address.Hex() == airdropAddress {
|
|
return airdropKeyName, airdropAddress, airdropPrivKey, nil
|
|
}
|
|
}
|
|
}
|
|
maxBalance := big.NewInt(0)
|
|
maxBalanceKeyName := ""
|
|
maxBalanceAddr := ""
|
|
maxBalancePrivKey := ""
|
|
for address, alloc := range genesis.Alloc {
|
|
if alloc.Balance == nil {
|
|
continue
|
|
}
|
|
// Convert geth common.Address to crypto.Address
|
|
cryptoAddr := crypto.Address(address.Bytes())
|
|
found, keyName, addressStr, privKey, err := SearchForManagedKey(app, network, cryptoAddr)
|
|
if err != nil {
|
|
return "", "", "", err
|
|
}
|
|
if found && alloc.Balance.Cmp(maxBalance) > 0 {
|
|
maxBalance = alloc.Balance
|
|
maxBalanceKeyName = keyName
|
|
maxBalanceAddr = addressStr
|
|
maxBalancePrivKey = privKey
|
|
}
|
|
}
|
|
return maxBalanceKeyName, maxBalanceAddr, maxBalancePrivKey, nil
|
|
}
|
|
|
|
func SearchForManagedKey(
|
|
app *application.Lux,
|
|
network models.Network,
|
|
address crypto.Address,
|
|
) (bool, string, string, string, error) {
|
|
keyNames, err := utils.GetKeyNames(app.GetKeyDir())
|
|
if err != nil {
|
|
return false, "", "", "", err
|
|
}
|
|
for _, keyName := range keyNames {
|
|
keyPath := app.GetKeyPath(keyName)
|
|
if k, err := key.LoadSoft(network.ID(), keyPath); err != nil {
|
|
return false, "", "", "", err
|
|
} else if address.Hex() == k.C() {
|
|
return true, keyName, k.C(), k.PrivKeyHex(), nil
|
|
}
|
|
}
|
|
return false, "", "", "", nil
|
|
}
|
|
|
|
// get the deployed blockchain genesis, and then look for known
|
|
// private keys inside it
|
|
// returns address + private key when found
|
|
func GetEVMChainPrefundedKey(
|
|
app *application.Lux,
|
|
network models.Network,
|
|
chainSpec ChainSpec,
|
|
) (string, string, error) {
|
|
genesisData, err := GetBlockchainGenesis(
|
|
app,
|
|
network,
|
|
chainSpec,
|
|
)
|
|
if err != nil {
|
|
return "", "", err
|
|
}
|
|
if !utils.ByteSliceIsEVMGenesis(genesisData) {
|
|
return "", "", fmt.Errorf("search for prefunded key is only supported on EVM based vms")
|
|
}
|
|
_, genesisAddress, genesisPrivateKey, err := GetBlockchainAirdropKeyInfo(
|
|
app,
|
|
network,
|
|
chainSpec.BlockchainName,
|
|
genesisData,
|
|
)
|
|
if err != nil {
|
|
return "", "", err
|
|
}
|
|
return genesisAddress, genesisPrivateKey, nil
|
|
}
|
|
|
|
// get the deployed blockchain genesis
|
|
func GetBlockchainGenesis(
|
|
app *application.Lux,
|
|
network models.Network,
|
|
chainSpec ChainSpec,
|
|
) ([]byte, error) {
|
|
blockchainID, err := GetBlockchainID(app, network, chainSpec)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
createChainTx, err := utils.GetBlockchainTx(network.Endpoint(), blockchainID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return createChainTx.GenesisData, err
|
|
}
|
|
|
|
func sumGenesisSupply(
|
|
genesisData []byte,
|
|
) (*big.Int, error) {
|
|
sum := new(big.Int)
|
|
genesis, err := utils.ByteSliceToEVMGenesis(genesisData)
|
|
if err != nil {
|
|
return sum, err
|
|
}
|
|
for _, allocation := range genesis.Alloc {
|
|
sum.Add(sum, allocation.Balance)
|
|
}
|
|
return sum, nil
|
|
}
|
|
|
|
func GetEVMChainGenesisSupply(
|
|
app *application.Lux,
|
|
network models.Network,
|
|
chainSpec ChainSpec,
|
|
) (*big.Int, error) {
|
|
genesisData, err := GetBlockchainGenesis(
|
|
app,
|
|
network,
|
|
chainSpec,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !utils.ByteSliceIsEVMGenesis(genesisData) {
|
|
return nil, fmt.Errorf("genesis supply calculation is only supported on EVM based vms")
|
|
}
|
|
return sumGenesisSupply(genesisData)
|
|
}
|
|
|
|
func getGenesisNativeMinterAdmin(
|
|
app *application.Lux,
|
|
network models.Network,
|
|
genesisData []byte,
|
|
) (bool, bool, string, string, string, error) {
|
|
_, err := utils.ByteSliceToEVMGenesis(genesisData)
|
|
if err != nil {
|
|
return false, false, "", "", "", err
|
|
}
|
|
// Access GenesisPrecompiles through genesis extras if available
|
|
// For now, return no admin found since params.ChainConfig doesn't have GenesisPrecompiles
|
|
if false { // Will be enabled when extras.ChainConfig is available
|
|
var allowListCfg *nativeminter.Config
|
|
_ = allowListCfg
|
|
if len(allowListCfg.AdminAddresses) == 0 {
|
|
return false, false, "", "", "", nil
|
|
}
|
|
for _, admin := range allowListCfg.AdminAddresses {
|
|
// Convert geth address to crypto.Address
|
|
cryptoAddr := crypto.Address(admin.Bytes())
|
|
found, keyName, addressStr, privKey, err := SearchForManagedKey(app, network, cryptoAddr)
|
|
if err != nil {
|
|
return false, false, "", "", "", err
|
|
}
|
|
if found {
|
|
return true, true, keyName, addressStr, privKey, nil
|
|
}
|
|
}
|
|
return true, false, "", allowListCfg.AdminAddresses[0].Hex(), "", nil
|
|
}
|
|
return false, false, "", "", "", nil
|
|
}
|
|
|
|
func getGenesisNativeMinterManager(
|
|
app *application.Lux,
|
|
network models.Network,
|
|
genesisData []byte,
|
|
) (bool, bool, string, string, string, error) {
|
|
_, err := utils.ByteSliceToEVMGenesis(genesisData)
|
|
if err != nil {
|
|
return false, false, "", "", "", err
|
|
}
|
|
// Access GenesisPrecompiles through genesis extras if available
|
|
// For now, return no admin found since params.ChainConfig doesn't have GenesisPrecompiles
|
|
if false { // Will be enabled when extras.ChainConfig is available
|
|
var allowListCfg *nativeminter.Config
|
|
_ = allowListCfg
|
|
if len(allowListCfg.ManagerAddresses) == 0 {
|
|
return false, false, "", "", "", nil
|
|
}
|
|
for _, admin := range allowListCfg.ManagerAddresses {
|
|
// Convert geth address to crypto.Address
|
|
cryptoAddr := crypto.Address(admin.Bytes())
|
|
found, keyName, addressStr, privKey, err := SearchForManagedKey(app, network, cryptoAddr)
|
|
if err != nil {
|
|
return false, false, "", "", "", err
|
|
}
|
|
if found {
|
|
return true, true, keyName, addressStr, privKey, nil
|
|
}
|
|
}
|
|
return true, false, "", allowListCfg.ManagerAddresses[0].Hex(), "", nil
|
|
}
|
|
return false, false, "", "", "", nil
|
|
}
|
|
|
|
func GetEVMChainGenesisNativeMinterAdmin(
|
|
app *application.Lux,
|
|
network models.Network,
|
|
chainSpec ChainSpec,
|
|
) (bool, bool, string, string, string, error) {
|
|
genesisData, err := GetBlockchainGenesis(
|
|
app,
|
|
network,
|
|
chainSpec,
|
|
)
|
|
if err != nil {
|
|
return false, false, "", "", "", err
|
|
}
|
|
if !utils.ByteSliceIsEVMGenesis(genesisData) {
|
|
return false, false, "", "", "", fmt.Errorf("genesis native minter admin query is only supported on EVM based vms")
|
|
}
|
|
return getGenesisNativeMinterAdmin(app, network, genesisData)
|
|
}
|
|
|
|
func GetEVMChainGenesisNativeMinterManager(
|
|
app *application.Lux,
|
|
network models.Network,
|
|
chainSpec ChainSpec,
|
|
) (bool, bool, string, string, string, error) {
|
|
genesisData, err := GetBlockchainGenesis(
|
|
app,
|
|
network,
|
|
chainSpec,
|
|
)
|
|
if err != nil {
|
|
return false, false, "", "", "", err
|
|
}
|
|
if !utils.ByteSliceIsEVMGenesis(genesisData) {
|
|
return false, false, "", "", "", fmt.Errorf("genesis native minter manager query is only supported on EVM based vms")
|
|
}
|
|
return getGenesisNativeMinterManager(app, network, genesisData)
|
|
}
|
|
|
|
func ContractAddressIsInGenesisData(
|
|
genesisData []byte,
|
|
contractAddress crypto.Address,
|
|
) (bool, error) {
|
|
genesis, err := utils.ByteSliceToEVMGenesis(genesisData)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
for address, allocation := range genesis.Alloc {
|
|
// Compare by converting to the same type
|
|
if bytes.Equal(address.Bytes(), contractAddress.Bytes()) {
|
|
return len(allocation.Code) > 0, nil
|
|
}
|
|
}
|
|
return false, nil
|
|
}
|