| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- //go:build ignore
- // ChainID Auto-Generation Tool
- //
- // This file generates the ChainID methods for the VAA struct in the SDK.
- // It automatically creates String(), ChainIDFromString(), and GetAllNetworkIDs()
- // methods by parsing ChainID constants from vaa/structs.go.
- //
- // ADDING A NEW CHAINID:
- // 1. Add the new ChainID constant to vaa/structs.go following the pattern:
- // // ChainIDNewChain is the ChainID of NewChain
- // ChainIDNewChain ChainID = 99
- //
- // 2. Run `make go-generate` to regenerate the methods in vaa/chainid_generated.go
- //
- // 3. The generator will automatically:
- // - Extract the chain name from the constant (removes "ChainID" prefix)
- // - Convert to lowercase for string representation
- // - Handle special cases like testnet names (e.g., "PolygonSepolia" -> "polygon_sepolia")
- // - Add the new chain to all generated methods
- //
- // The generated file should never be edited manually - always regenerate it.
- package main
- import (
- "fmt"
- "go/ast"
- "go/parser"
- "go/token"
- "log"
- "os"
- "sort"
- "strconv"
- "strings"
- "text/template"
- )
- type ChainInfo struct {
- Name string
- Value int
- GoName string
- }
- func main() {
- // Parse the source file to extract ChainID constants from vaa/structs.go
- // This reads the Go source code and builds an Abstract Syntax Tree (AST)
- // to programmatically find all ChainID constant declarations
- fset := token.NewFileSet()
- node, err := parser.ParseFile(fset, "vaa/structs.go", nil, parser.ParseComments)
- if err != nil {
- log.Fatal(err)
- }
- // Stores each ChainID declared as a constant in vaa/structs.go
- // Each ChainInfo contains the chain name, numeric value, and Go constant name
- var chains []ChainInfo
- // Walk the AST to find ChainID constants
- // This traverses the parsed Go code looking for constant declarations
- // that have the type "ChainID"
- ast.Inspect(node, func(n ast.Node) bool {
- switch x := n.(type) {
- case *ast.GenDecl:
- if x.Tok == token.CONST {
- for _, spec := range x.Specs {
- if vspec, ok := spec.(*ast.ValueSpec); ok {
- // Check if this is a ChainID constant by examining the type
- if vspec.Type != nil {
- if ident, ok := vspec.Type.(*ast.Ident); ok && ident.Name == "ChainID" {
- for i, name := range vspec.Names {
- if name.Name == "ChainIDUnset" {
- // Skip the unset value (ChainIDUnset = 0)
- // This is a special case that shouldn't be included in generated methods
- continue
- }
- // Extract the numeric value from the constant declaration
- var value int
- if len(vspec.Values) > i {
- if basic, ok := vspec.Values[i].(*ast.BasicLit); ok {
- if v, err := strconv.Atoi(basic.Value); err == nil {
- value = v
- }
- }
- }
- // Extract the chain name from the constant name
- // e.g., "ChainIDEthereum" -> "Ethereum"
- chainName := strings.TrimPrefix(name.Name, "ChainID")
- // Convert to lowercase for string representation
- // e.g., "Ethereum" -> "ethereum"
- chainNameLower := strings.ToLower(chainName)
- // Handle special naming for testnet chains
- // Separate alt-EVM testnet names with underscores.
- // e.g. `PolygonSepolia` --> `polygon_sepolia`.
- // (Don't match on "sepolia" itself though.)
- if strings.HasSuffix(chainNameLower, "sepolia") && len(chainNameLower) > len("sepolia") {
- chainNameLower = fmt.Sprintf("%s_sepolia", strings.TrimSuffix(chainNameLower, "sepolia"))
- }
- // Store the chain information for code generation
- chains = append(chains, ChainInfo{
- Name: chainNameLower, // String representation (e.g., "ethereum")
- Value: value, // Numeric ID (e.g., 2)
- GoName: name.Name, // Go constant name (e.g., "ChainIDEthereum")
- })
- }
- }
- }
- }
- }
- }
- }
- return true
- })
- // Sort by numeric value for consistent output
- // This ensures the generated code has chains in the same order as the constants
- sort.Slice(chains, func(i, j int) bool {
- return chains[i].Value < chains[j].Value
- })
- // Generate the code template for the output file
- // This template creates three methods:
- // 1. String() - converts ChainID to string representation
- // 2. ChainIDFromString() - converts string to ChainID
- // 3. GetAllNetworkIDs() - returns slice of all known ChainIDs
- // NOTE: This should follow gofumpt formatting in order to pass CI checks.
- tmpl := `// Code generated by go generate; DO NOT EDIT.
- package vaa
- import (
- "fmt"
- "strings"
- )
- // String returns the string representation of the ChainID
- func (c ChainID) String() string {
- switch c {
- case ChainIDUnset:
- return "unset"
- {{- range .Chains }}
- case {{ .GoName }}:
- return "{{ .Name }}"
- {{- end }}
- default:
- return fmt.Sprintf("unknown chain ID: %d", c)
- }
- }
- // ChainIDFromString converts from a chain's full name to its corresponding ChainID.
- func ChainIDFromString(s string) (ChainID, error) {
- s = strings.ToLower(s)
- switch s {
- {{- range .Chains }}
- case "{{ .Name }}":
- return {{ .GoName }}, nil
- {{- end }}
- default:
- return ChainIDUnset, fmt.Errorf("unknown chain ID: %s", s)
- }
- }
- // GetAllNetworkIDs returns all known ChainIDs
- func GetAllNetworkIDs() []ChainID {
- return []ChainID{
- {{- range .Chains }}
- {{ .GoName }},
- {{- end }}
- }
- }
- `
- // Write the generated code to the output file
- outfile := "vaa/chainid_generated.go"
- t, err := template.New("chainid").Parse(tmpl)
- if err != nil {
- log.Fatal(err)
- }
- output, err := os.Create(outfile)
- if err != nil {
- log.Fatal(err)
- }
- defer output.Close()
- // Execute the template with the extracted chain information
- err = t.Execute(output, struct {
- Chains []ChainInfo
- }{
- Chains: chains,
- })
- if err != nil {
- log.Fatal(err)
- }
- fmt.Printf("Generated %s with %d chains\n", outfile, len(chains))
- }
|