Files
zeekay 2faf6ed0df The wire is ZAP: no codec, no marshal, no parallel wallet
github.com/luxfi/codec is gone from this module — no import, no call, no
require. Nothing here marshals or unmarshals a transaction any more.

WHY IT BROKE. codec deleted its jsonrpc subpackage (1b67d6a, "delete dead
subpackages") while nine files imported it. It looked dead because the
PUBLISHED [email protected] still ships it, so only a workspace build — which
resolves codec from the local checkout — ever saw the break.

THE WIRE. A tx already carries its own ZAP encoding, so the codec was
re-deriving what the tx could hand over:
  txs.Codec.Marshal(txs.CodecVersion, &tx.Unsigned)  ->  tx.Unsigned.Bytes()
                                                          txs.UnsignedBytes(tx.Unsigned)
  txs.Codec.Marshal(txs.CodecVersion, tx)            ->  tx.Initialize()
  txs.Codec.Unmarshal(txBytes, &tx)                  ->  txs.Parse(txBytes)
  codec.Unmarshal(utxoBytes, &utxo)                  ->  utxo.ParseUTXO(...)
These are the same calls the node makes in txs.Tx.Sign. AddAllUTXOs no longer
takes a codec.Manager, and SortTransferableOutputs / state.Sort /
SortOperations no longer get one — upstream dropped the parameter.

PARALLEL IMPLEMENTATIONS, DELETED. wallet/chain/{p,x} carried a second copy of
the builder and signer beside the subpackages that already held them —
p/signer_visitor.go and p/signer/visitor.go were both 399 lines of the same
thing, and each defect had to be fixed twice. The flat files are gone; the
package keeps the facade it already had in wallet_exports.go, which re-exports
the subpackage. -4787 lines.

wallet/chain/c is deleted. Its whole reason to exist was a codec.Manager
scaffold for C-chain atomic-tx wire that nothing runs: NewWallet was passed
nil for it, and the builder was commented out. The two symbols anything used
move to where they are read — Account, a balance and a nonce off an EVM
client, and EVMKeychain, the geth-address half of a keychain. Wallet no longer
advertises a C() that only ever returned nil.

ALIGNED. XAssetID -> UTXOAssetID, matching runtime.Runtime and netrunner, which
already expected it. Keychain GetEth -> GetByEVM, EthAddrs -> EVMAddrs. warp
UnsignedMessage and Message collapsed into one flat Message, so a signature is
an Envelope rather than a second message type. netrunner's HealthResponse is
read as a field: the getter form is protobuf, behind //go:build grpc, and the
default build is ZAP-native.

VERIFIED on a machine with the native libraries: go build ./... exits 0 with no
codec require in go.mod, and go test ./... is 23 ok. Three packages still fail
to build their tests — profiles, wallet/keychain, wallet/primary — and all
three fail identically on the tree before this change: Consensus,
VerifyHybridSecp256k1MLDSA and isXChainNotEnabled are referenced by tests and
defined nowhere. evm failed there too and now passes.
2026-08-28 22:25:12 -07:00

190 lines
5.8 KiB
Go

// Copyright (C) 2019-2025, Lux Industries Inc All rights reserved.
// See the file LICENSE for licensing terms.
package primary
import (
"context"
gethcommon "github.com/luxfi/geth/common"
"github.com/luxfi/constants"
"github.com/luxfi/ids"
"github.com/luxfi/keychain"
"github.com/luxfi/math/set"
"github.com/luxfi/proto/p/txs"
"github.com/luxfi/sdk/wallet/chain/p"
"github.com/luxfi/sdk/wallet/chain/x"
"github.com/luxfi/sdk/wallet/primary/common"
"github.com/luxfi/utxo/secp256k1fx"
pbuilder "github.com/luxfi/sdk/wallet/chain/p/builder"
psigner "github.com/luxfi/sdk/wallet/chain/p/signer"
xbuilder "github.com/luxfi/sdk/wallet/chain/x/builder"
xsigner "github.com/luxfi/sdk/wallet/chain/x/signer"
)
var _ Wallet = (*wallet)(nil)
// EVMKeychain is the geth-address half of a keychain: the addresses an EVM
// chain uses and the signers behind them. It was declared in the C-chain
// wallet package, which held nothing else that ran.
type EVMKeychain interface {
GetEth(addr gethcommon.Address) (keychain.Signer, bool)
EthAddresses() set.Set[gethcommon.Address]
}
// KeychainAdapter adapts secp256k1fx.Keychain to wallet/keychain.Keychain and
// EVMKeychain.
// This allows secp256k1fx.Keychain to be used with MakeWallet.
type KeychainAdapter struct {
*secp256k1fx.Keychain
}
// Addresses implements wallet/keychain.Keychain
func (kc *KeychainAdapter) Addresses() set.Set[ids.ShortID] {
return kc.Keychain.Addrs
}
// Get implements wallet/keychain.Keychain (returns wallet/keychain.Signer, not utils/crypto/keychain.Signer)
func (kc *KeychainAdapter) Get(addr ids.ShortID) (keychain.Signer, bool) {
return kc.Keychain.Get(addr)
}
// GetEth implements EVMKeychain
func (kc *KeychainAdapter) GetEth(addr gethcommon.Address) (keychain.Signer, bool) {
return kc.Keychain.GetByEVM(addr)
}
// EthAddresses implements EVMKeychain
func (kc *KeychainAdapter) EthAddresses() set.Set[gethcommon.Address] {
return kc.Keychain.EVMAddrs
}
// NewKeychainAdapter creates a KeychainAdapter from a secp256k1fx.Keychain
func NewKeychainAdapter(kc *secp256k1fx.Keychain) *KeychainAdapter {
return &KeychainAdapter{Keychain: kc}
}
// Wallet provides chain wallets for the primary network.
type Wallet interface {
P() p.Wallet
X() x.Wallet
}
type wallet struct {
p p.Wallet
x x.Wallet
}
func (w *wallet) P() p.Wallet {
return w.p
}
func (w *wallet) X() x.Wallet {
return w.x
}
// Creates a new default wallet
func NewWallet(p p.Wallet, x x.Wallet) Wallet {
return &wallet{
p: p,
x: x,
}
}
// Creates a Wallet with the given set of options
func NewWalletWithOptions(w Wallet, options ...common.Option) Wallet {
return NewWallet(
p.NewWalletWithOptions(w.P(), options...),
x.NewWalletWithOptions(w.X(), options...),
)
}
type WalletConfig struct {
// Base URI to use for all node requests.
URI string // required
// Keys to use for signing all transactions.
LUXKeychain keychain.Keychain // required
EthKeychain EVMKeychain // required
// Set of P-chain transactions that the wallet should know about to be able
// to generate transactions.
PChainTxs map[ids.ID]*txs.Tx // optional
// Set of P-chain transactions that the wallet should fetch to be able to
// generate transactions.
PChainTxsToFetch set.Set[ids.ID] // optional
}
// MakeWallet returns a wallet that supports issuing transactions to the chains
// living in the primary network.
//
// On creation, the wallet attaches to the provided uri and fetches all UTXOs
// that reference any of the provided keys. If the UTXOs are modified through an
// external issuance process, such as another instance of the wallet, the UTXOs
// may become out of sync. The wallet will also fetch all requested P-chain
// transactions.
//
// The wallet manages all state locally, and performs all tx signing locally.
func MakeWallet(ctx context.Context, config *WalletConfig) (Wallet, error) {
luxAddrs := config.LUXKeychain.Addresses()
luxState, err := FetchState(ctx, config.URI, luxAddrs)
if err != nil {
return nil, err
}
// Eth state fetching disabled for now
// ethAddrs := config.EthKeychain.EthAddresses()
// ethState, err := FetchEthState(ctx, config.URI, ethAddrs)
// if err != nil {
// return nil, err
// }
pChainTxs := config.PChainTxs
if pChainTxs == nil {
pChainTxs = make(map[ids.ID]*txs.Tx)
}
for txID := range config.PChainTxsToFetch {
txBytes, err := luxState.PClient.GetTx(ctx, txID)
if err != nil {
return nil, err
}
tx, err := txs.Parse(txBytes)
if err != nil {
return nil, err
}
pChainTxs[txID] = tx
}
pUTXOs := common.NewChainUTXOs(constants.PlatformChainID, luxState.UTXOs)
pBackend := p.NewBackend(luxState.PCTX, pUTXOs, pChainTxs)
pBuilder := pbuilder.New(luxAddrs, luxState.PCTX, pBackend)
pSigner := psigner.New(config.LUXKeychain, pBackend)
xChainID := luxState.XCTX.BlockchainID
xUTXOs := common.NewChainUTXOs(xChainID, luxState.UTXOs)
xBackend := x.NewBackend(luxState.XCTX, xUTXOs)
xBuilder := xbuilder.New(luxAddrs, luxState.XCTX, xBackend)
xSigner := xsigner.New(config.LUXKeychain, xBackend)
// C-chain wallet disabled - requires full EVM client implementation
// cChainID := luxState.CCTX.BlockchainID
// cUTXOs := common.NewChainUTXOs(cChainID, luxState.UTXOs)
// cBackend := c.NewBackend(cUTXOs, nil)
// cBuilder := c.NewBuilder(luxAddrs, config.EthKeychain.EthAddresses(), luxState.CCTX, cBackend)
// cSigner := c.NewSigner(config.LUXKeychain, config.EthKeychain, cBackend)
pClient := p.NewClient(luxState.PClient, pBackend)
return NewWallet(
p.NewWallet(pClient, pBuilder, pSigner),
x.NewWallet(xBuilder, xSigner, xBackend),
), nil
}
// MakePChainWallet returns a wallet that only supports issuing P-chain transactions.
// This is an alias for MakeWallet for backward compatibility.
func MakePChainWallet(ctx context.Context, config *WalletConfig) (Wallet, error) {
return MakeWallet(ctx, config)
}