github.com/ava-labs/avalanchego@v1.11.11/vms/avm/static_service.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package avm
     5  
     6  import (
     7  	"encoding/json"
     8  	"errors"
     9  	"fmt"
    10  	"net/http"
    11  
    12  	"github.com/ava-labs/avalanchego/ids"
    13  	"github.com/ava-labs/avalanchego/utils"
    14  	"github.com/ava-labs/avalanchego/utils/formatting"
    15  	"github.com/ava-labs/avalanchego/utils/formatting/address"
    16  	"github.com/ava-labs/avalanchego/vms/avm/fxs"
    17  	"github.com/ava-labs/avalanchego/vms/avm/txs"
    18  	"github.com/ava-labs/avalanchego/vms/components/avax"
    19  	"github.com/ava-labs/avalanchego/vms/components/verify"
    20  	"github.com/ava-labs/avalanchego/vms/nftfx"
    21  	"github.com/ava-labs/avalanchego/vms/propertyfx"
    22  	"github.com/ava-labs/avalanchego/vms/secp256k1fx"
    23  
    24  	avajson "github.com/ava-labs/avalanchego/utils/json"
    25  )
    26  
    27  var (
    28  	errUnknownAssetType = errors.New("unknown asset type")
    29  
    30  	_ avax.TransferableIn  = (*secp256k1fx.TransferInput)(nil)
    31  	_ verify.State         = (*secp256k1fx.MintOutput)(nil)
    32  	_ avax.TransferableOut = (*secp256k1fx.TransferOutput)(nil)
    33  	_ fxs.FxOperation      = (*secp256k1fx.MintOperation)(nil)
    34  	_ verify.Verifiable    = (*secp256k1fx.Credential)(nil)
    35  
    36  	_ verify.State      = (*nftfx.MintOutput)(nil)
    37  	_ verify.State      = (*nftfx.TransferOutput)(nil)
    38  	_ fxs.FxOperation   = (*nftfx.MintOperation)(nil)
    39  	_ fxs.FxOperation   = (*nftfx.TransferOperation)(nil)
    40  	_ verify.Verifiable = (*nftfx.Credential)(nil)
    41  
    42  	_ verify.State      = (*propertyfx.MintOutput)(nil)
    43  	_ verify.State      = (*propertyfx.OwnedOutput)(nil)
    44  	_ fxs.FxOperation   = (*propertyfx.MintOperation)(nil)
    45  	_ fxs.FxOperation   = (*propertyfx.BurnOperation)(nil)
    46  	_ verify.Verifiable = (*propertyfx.Credential)(nil)
    47  )
    48  
    49  // StaticService defines the base service for the asset vm
    50  type StaticService struct{}
    51  
    52  func CreateStaticService() *StaticService {
    53  	return &StaticService{}
    54  }
    55  
    56  // BuildGenesisArgs are arguments for BuildGenesis
    57  type BuildGenesisArgs struct {
    58  	NetworkID   avajson.Uint32             `json:"networkID"`
    59  	GenesisData map[string]AssetDefinition `json:"genesisData"`
    60  	Encoding    formatting.Encoding        `json:"encoding"`
    61  }
    62  
    63  type AssetDefinition struct {
    64  	Name         string                   `json:"name"`
    65  	Symbol       string                   `json:"symbol"`
    66  	Denomination avajson.Uint8            `json:"denomination"`
    67  	InitialState map[string][]interface{} `json:"initialState"`
    68  	Memo         string                   `json:"memo"`
    69  }
    70  
    71  // BuildGenesisReply is the reply from BuildGenesis
    72  type BuildGenesisReply struct {
    73  	Bytes    string              `json:"bytes"`
    74  	Encoding formatting.Encoding `json:"encoding"`
    75  }
    76  
    77  // BuildGenesis returns the UTXOs such that at least one address in [args.Addresses] is
    78  // referenced in the UTXO.
    79  func (*StaticService) BuildGenesis(_ *http.Request, args *BuildGenesisArgs, reply *BuildGenesisReply) error {
    80  	parser, err := txs.NewParser(
    81  		[]fxs.Fx{
    82  			&secp256k1fx.Fx{},
    83  			&nftfx.Fx{},
    84  			&propertyfx.Fx{},
    85  		},
    86  	)
    87  	if err != nil {
    88  		return err
    89  	}
    90  
    91  	g := Genesis{}
    92  	genesisCodec := parser.GenesisCodec()
    93  	for assetAlias, assetDefinition := range args.GenesisData {
    94  		assetMemo, err := formatting.Decode(args.Encoding, assetDefinition.Memo)
    95  		if err != nil {
    96  			return fmt.Errorf("problem formatting asset definition memo due to: %w", err)
    97  		}
    98  		asset := GenesisAsset{
    99  			Alias: assetAlias,
   100  			CreateAssetTx: txs.CreateAssetTx{
   101  				BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{
   102  					NetworkID:    uint32(args.NetworkID),
   103  					BlockchainID: ids.Empty,
   104  					Memo:         assetMemo,
   105  				}},
   106  				Name:         assetDefinition.Name,
   107  				Symbol:       assetDefinition.Symbol,
   108  				Denomination: byte(assetDefinition.Denomination),
   109  			},
   110  		}
   111  		if len(assetDefinition.InitialState) > 0 {
   112  			initialState := &txs.InitialState{
   113  				FxIndex: 0, // TODO: Should lookup secp256k1fx FxID
   114  			}
   115  			for assetType, initialStates := range assetDefinition.InitialState {
   116  				switch assetType {
   117  				case "fixedCap":
   118  					for _, state := range initialStates {
   119  						b, err := json.Marshal(state)
   120  						if err != nil {
   121  							return fmt.Errorf("problem marshaling state: %w", err)
   122  						}
   123  						holder := Holder{}
   124  						if err := json.Unmarshal(b, &holder); err != nil {
   125  							return fmt.Errorf("problem unmarshaling holder: %w", err)
   126  						}
   127  						_, addrbuff, err := address.ParseBech32(holder.Address)
   128  						if err != nil {
   129  							return fmt.Errorf("problem parsing holder address: %w", err)
   130  						}
   131  						addr, err := ids.ToShortID(addrbuff)
   132  						if err != nil {
   133  							return fmt.Errorf("problem parsing holder address: %w", err)
   134  						}
   135  						initialState.Outs = append(initialState.Outs, &secp256k1fx.TransferOutput{
   136  							Amt: uint64(holder.Amount),
   137  							OutputOwners: secp256k1fx.OutputOwners{
   138  								Threshold: 1,
   139  								Addrs:     []ids.ShortID{addr},
   140  							},
   141  						})
   142  					}
   143  				case "variableCap":
   144  					for _, state := range initialStates {
   145  						b, err := json.Marshal(state)
   146  						if err != nil {
   147  							return fmt.Errorf("problem marshaling state: %w", err)
   148  						}
   149  						owners := Owners{}
   150  						if err := json.Unmarshal(b, &owners); err != nil {
   151  							return fmt.Errorf("problem unmarshaling Owners: %w", err)
   152  						}
   153  
   154  						out := &secp256k1fx.MintOutput{
   155  							OutputOwners: secp256k1fx.OutputOwners{
   156  								Threshold: 1,
   157  							},
   158  						}
   159  						for _, addrStr := range owners.Minters {
   160  							_, addrBytes, err := address.ParseBech32(addrStr)
   161  							if err != nil {
   162  								return fmt.Errorf("problem parsing minters address: %w", err)
   163  							}
   164  							addr, err := ids.ToShortID(addrBytes)
   165  							if err != nil {
   166  								return fmt.Errorf("problem parsing minters address: %w", err)
   167  							}
   168  							out.Addrs = append(out.Addrs, addr)
   169  						}
   170  						out.Sort()
   171  
   172  						initialState.Outs = append(initialState.Outs, out)
   173  					}
   174  				default:
   175  					return errUnknownAssetType
   176  				}
   177  			}
   178  			initialState.Sort(genesisCodec)
   179  			asset.States = append(asset.States, initialState)
   180  		}
   181  		utils.Sort(asset.States)
   182  		g.Txs = append(g.Txs, &asset)
   183  	}
   184  	utils.Sort(g.Txs)
   185  
   186  	b, err := genesisCodec.Marshal(txs.CodecVersion, &g)
   187  	if err != nil {
   188  		return fmt.Errorf("problem marshaling genesis: %w", err)
   189  	}
   190  
   191  	reply.Bytes, err = formatting.Encode(args.Encoding, b)
   192  	if err != nil {
   193  		return fmt.Errorf("couldn't encode genesis as string: %w", err)
   194  	}
   195  	reply.Encoding = args.Encoding
   196  	return nil
   197  }