Files
node/vms/platformvm/txs/executor/create_asset_tx.go
T
Hanzo DevandGitHub be744a9dbf refactor: XAssetID → UTXOAssetID (#119)
The field is the primary network's UTXO fee asset (P+X), not
X-chain-specific. P-chain CreateChainTx / AddChainValidatorTx and
X-chain transfers all burn it for fees. Same number on P and X by
construction; the name should reflect the function, not the chain.

Renames applied across:
- wallet/chain/{p,x}/builder.Context.UTXOAssetID
- wallet/chain/x/builder.Backend.UTXOAssetID() trait method
- node/config: resolveUTXOAssetID + nodeConfig.UTXOAssetID
- vms/platformvm + vms/xvm + chains/manager consumers
- examples (deploy-chains, get-p-chain-balance, ...)

Includes local replaces for luxfi/{runtime,consensus} pending their
release tags landing. Drop after upstream tags ship.

Companion PRs: luxfi/runtime#2, luxfi/consensus#11. Downstream
consumers (sdk, cli, genesis, liquidity) follow.
2026-05-30 14:28:08 -07:00

89 lines
2.9 KiB
Go

// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package executor
import (
"github.com/luxfi/ids"
lux "github.com/luxfi/utxo"
"github.com/luxfi/node/vms/platformvm/status"
"github.com/luxfi/node/vms/platformvm/txs"
)
// CreateAssetTx mints a new UTXO asset on the P-Chain.
//
// The asset ID is, by convention with the X-Chain wire format, the tx ID.
// The fee charged is computed by the fee calculator (static config →
// `CreateAssetTxFee`; dynamic fee → gas complexity); the minted asset is
// produced as UTXOs owned by [tx.States[*].Outs] keyed by the new asset ID.
func (e *standardTxExecutor) CreateAssetTx(tx *txs.CreateAssetTx) error {
// Verify the tx is well-formed first.
if err := e.tx.SyntacticVerify(e.backend.Runtime); err != nil {
return err
}
// Fee flow check.
fee, err := e.feeCalculator.CalculateFee(tx)
if err != nil {
return err
}
if err := e.backend.FlowChecker.VerifySpend(
tx,
e.state,
tx.Ins,
tx.Outs,
e.tx.Creds,
map[ids.ID]uint64{
e.backend.Runtime.UTXOAssetID: fee,
},
); err != nil {
return err
}
txID := e.tx.ID()
// Consume the fee inputs, produce the fee change outputs (BaseTx outs).
lux.Consume(e.state, tx.Ins)
lux.Produce(e.state, txID, tx.Outs)
// Produce the freshly minted asset UTXOs. The asset ID is the tx ID.
//
// Output indices come from the InitialState slot position, NOT from the
// count of UTXOs we actually wrote. Mirrors XVM semantics: a mint output
// at States[0].Outs[0] gets `OutputIndex = len(tx.Outs)` even though the
// executor doesn't write the mint UTXO here (mint authority is held in
// the asset registry, materialised on first OperationTx mint). A holder
// transfer output at States[0].Outs[1] gets `OutputIndex = len(tx.Outs)+1`.
// Compacting indices would break OperationTx references back to mint
// outputs (RED V4 outputIndex-phantom-UTXO vector).
outputIndex := uint32(len(tx.Outs))
for _, state := range tx.States {
for _, out := range state.Outs {
if transferOut, ok := out.(lux.TransferableOut); ok {
utxo := &lux.UTXO{
UTXOID: lux.UTXOID{
TxID: txID,
OutputIndex: outputIndex,
},
Asset: lux.Asset{ID: txID},
Out: transferOut,
}
e.state.AddUTXO(utxo)
}
// Non-TransferableOut (e.g. MintOutput) — index slot reserved
// for OperationTx references; UTXO materialised on first mint.
outputIndex++
}
}
// Persist the create-asset tx itself so future ops, SemanticVerifier-style
// lookups (`State.GetTx(assetID)`) and indexer projections
// (`chain.PrimaryAlias(assetID)`) resolve to the original tx with all
// metadata. The asset ID is the tx ID by construction (line 43 above);
// `state.AddTx` is the canonical PlatformVM persistence API used by
// CreateChainTx / CreateNetworkTx / committed-block paths.
e.state.AddTx(e.tx, status.Committed)
return nil
}