github.com/stafiprotocol/go-substrate-rpc-client@v1.4.7/client/tx.go (about) 1 package client 2 3 import ( 4 "errors" 5 "fmt" 6 7 "github.com/stafiprotocol/go-substrate-rpc-client/config" 8 "github.com/stafiprotocol/go-substrate-rpc-client/rpc/author" 9 "github.com/stafiprotocol/go-substrate-rpc-client/types" 10 ) 11 12 func (sc *GsrpcClient) NewUnsignedExtrinsic(callMethod string, args ...interface{}) (interface{}, error) { 13 sc.log.Debug("Submitting substrate call...", "callMethod", callMethod, "addressType", sc.addressType, "sender", sc.key.Address) 14 15 ci, err := sc.FindCallIndex(callMethod) 16 if err != nil { 17 return nil, err 18 } 19 call, err := types.NewCallWithCallIndex(ci, callMethod, args...) 20 if err != nil { 21 return nil, err 22 } 23 24 if sc.addressType == AddressTypeAccountId { 25 unsignedExt := types.NewExtrinsic(call) 26 return &unsignedExt, nil 27 } else if sc.addressType == AddressTypeMultiAddress { 28 unsignedExt := types.NewExtrinsicMulti(call) 29 return &unsignedExt, nil 30 } else { 31 return nil, errors.New("addressType not supported") 32 } 33 } 34 35 func (sc *GsrpcClient) SignAndSubmitTx(ext interface{}) error { 36 err := sc.signExtrinsic(ext) 37 if err != nil { 38 return err 39 } 40 sc.log.Trace("signExtrinsic ok") 41 42 api, err := sc.FlashApi() 43 if err != nil { 44 return err 45 } 46 sc.log.Trace("flashApi ok") 47 // Do the transfer and track the actual status 48 sub, err := api.Author.SubmitAndWatch(ext) 49 if err != nil { 50 return err 51 } 52 sc.log.Trace("Extrinsic submission succeeded") 53 defer sub.Unsubscribe() 54 55 return sc.watchSubmission(sub) 56 } 57 58 func (sc *GsrpcClient) watchSubmission(sub *author.ExtrinsicStatusSubscription) error { 59 for { 60 select { 61 case status := <-sub.Chan(): 62 switch { 63 case status.IsInBlock: 64 sc.log.Info("Extrinsic included in block", "block", status.AsInBlock.Hex()) 65 return nil 66 case status.IsRetracted: 67 return fmt.Errorf("extrinsic retracted: %s", status.AsRetracted.Hex()) 68 case status.IsDropped: 69 return fmt.Errorf("extrinsic dropped from network") 70 case status.IsInvalid: 71 return fmt.Errorf("extrinsic invalid") 72 } 73 case err := <-sub.Err(): 74 sc.log.Trace("Extrinsic subscription error", "err", err) 75 return err 76 } 77 } 78 } 79 80 func (sc *GsrpcClient) signExtrinsic(xt interface{}) error { 81 rv, err := sc.GetLatestRuntimeVersion() 82 if err != nil { 83 return err 84 } 85 86 nonce, err := sc.GetLatestNonce() 87 if err != nil { 88 return err 89 } 90 91 o := types.SignatureOptions{ 92 BlockHash: sc.genesisHash, 93 Era: types.ExtrinsicEra{IsMortalEra: false}, 94 GenesisHash: sc.genesisHash, 95 Nonce: types.NewUCompactFromUInt(uint64(nonce)), 96 SpecVersion: rv.SpecVersion, 97 Tip: types.NewUCompactFromUInt(0), 98 TransactionVersion: rv.TransactionVersion, 99 } 100 101 if ext, ok := xt.(*types.Extrinsic); ok { 102 sc.log.Debug("signExtrinsic", "addressType", sc.addressType) 103 err = ext.Sign(*sc.key, o) 104 if err != nil { 105 return err 106 } 107 } else if ext, ok := xt.(*types.ExtrinsicMulti); ok { 108 sc.log.Debug("signExtrinsic", "addressType", sc.addressType) 109 err = ext.Sign(*sc.key, o) 110 if err != nil { 111 return fmt.Errorf("sign err: %s", err) 112 } 113 } else { 114 return errors.New("extrinsic cast error") 115 } 116 117 return nil 118 } 119 120 func (sc *GsrpcClient) SingleTransferTo(accountId []byte, value types.UCompact) error { 121 var addr interface{} 122 switch sc.addressType { 123 case AddressTypeAccountId: 124 addr = types.NewAddressFromAccountID(accountId) 125 case AddressTypeMultiAddress: 126 addr = types.NewMultiAddressFromAccountID(accountId) 127 default: 128 return fmt.Errorf("unsupported address type: %s", sc.addressType) 129 } 130 ext, err := sc.NewUnsignedExtrinsic(config.MethodTransferKeepAlive, addr, value) 131 if err != nil { 132 return err 133 } 134 return sc.SignAndSubmitTx(ext) 135 }