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 }