github.com/mavryk-network/mvgo@v1.19.9/examples/fa12/main.go (about) 1 // Copyright (c) 2020-2021 Blockwatch Data Inc. 2 // Author: alex@blockwatch.cc 3 4 // RPC examples 5 package main 6 7 import ( 8 "context" 9 "encoding/json" 10 "flag" 11 "fmt" 12 "os" 13 "strconv" 14 15 "github.com/mavryk-network/mvgo/mavryk" 16 "github.com/mavryk-network/mvgo/micheline" 17 "github.com/mavryk-network/mvgo/rpc" 18 19 "github.com/echa/log" 20 ) 21 22 var ( 23 flags = flag.NewFlagSet("fa12", flag.ContinueOnError) 24 verbose bool 25 node string 26 ) 27 28 func init() { 29 flags.Usage = func() {} 30 flags.BoolVar(&verbose, "v", false, "be verbose") 31 flags.StringVar(&node, "node", "https://rpc.tzpro.io", "Tezos node URL") 32 } 33 34 func main() { 35 if err := flags.Parse(os.Args[1:]); err != nil { 36 if err == flag.ErrHelp { 37 fmt.Println("Usage: fa12 [args] <block> <pos>") 38 fmt.Println("\n Decodes FA1.2 transfer info from transaction.") 39 fmt.Println("\nArguments") 40 flags.PrintDefaults() 41 os.Exit(0) 42 } 43 log.Fatal("Error:", err) 44 } 45 46 if err := run(); err != nil { 47 log.Fatal("Error:", err) 48 } 49 } 50 51 func run() error { 52 if flags.NArg() < 2 { 53 return fmt.Errorf("Argument required") 54 } 55 56 switch { 57 case verbose: 58 log.SetLevel(log.LevelInfo) 59 default: 60 log.SetLevel(log.LevelWarn) 61 } 62 rpc.UseLogger(log.Log) 63 64 hash, err := mavryk.ParseBlockHash(flags.Arg(0)) 65 if err != nil { 66 return err 67 } 68 op_n, err := strconv.ParseInt(flags.Arg(1), 10, 64) 69 if err != nil { 70 return err 71 } 72 73 ctx, cancel := context.WithCancel(context.Background()) 74 defer cancel() 75 76 c, err := rpc.NewClient(node, nil) 77 if err != nil { 78 return err 79 } 80 81 b, err := c.GetBlock(ctx, hash) 82 if err != nil { 83 return err 84 } 85 86 tx := b.Operations[3][op_n].Contents[0].(*rpc.Transaction) 87 88 // you need the contract's script for type info 89 script, err := c.GetContractScript(ctx, tx.Destination) 90 if err != nil { 91 return err 92 } 93 94 // unwind params for nested entrypoints 95 ep, prim, err := tx.Parameters.MapEntrypoint(script.ParamType()) 96 if err != nil { 97 return err 98 } 99 100 // convert Micheline params into human-readable form 101 val := micheline.NewValue(ep.Type(), prim) 102 103 // use Value interface to access data, you have multiple options 104 // 1/ get a decoded `map[string]interface{}` 105 m, err := val.Map() 106 if err != nil { 107 return err 108 } 109 110 buf, err := json.MarshalIndent(m, "", " ") 111 if err != nil { 112 return err 113 } 114 fmt.Println("Map=", string(buf)) 115 fmt.Printf("Value=%s %[1]T\n", m.(map[string]interface{})["transfer"].(map[string]interface{})["value"]) 116 117 // 2/ access individual fields (ok is true when the field exists and 118 // has the correct type) 119 from, ok := val.GetAddress("transfer.from") 120 if !ok { 121 return fmt.Errorf("No from param") 122 } 123 fmt.Println("Sent from", from) 124 125 // 3/ unmarshal the decoded Micheline parameters into a Go struct 126 type FA12Transfer struct { 127 From mavryk.Address `json:"from"` 128 To mavryk.Address `json:"to"` 129 Value mavryk.Z `json:"value"` 130 } 131 type FA12TransferWrapper struct { 132 Transfer FA12Transfer `json:"transfer"` 133 } 134 135 var transfer FA12TransferWrapper 136 err = val.Unmarshal(&transfer) 137 if err != nil { 138 return err 139 } 140 buf, _ = json.MarshalIndent(transfer, "", " ") 141 fmt.Printf("FA transfer %s\n", string(buf)) 142 143 return nil 144 }