go-substrate-rpc-client icon indicating copy to clipboard operation
go-substrate-rpc-client copied to clipboard

MakeASimpleTransfer Error

Open ygcool opened this issue 3 years ago • 9 comments

package main

import (
	"fmt"
	"math/big"

	gsrpc "github.com/centrifuge/go-substrate-rpc-client/v4"
	"github.com/centrifuge/go-substrate-rpc-client/v4/signature"
	"github.com/centrifuge/go-substrate-rpc-client/v4/types"
)

func main() {
	// This sample shows how to create a transaction to make a transfer from one an account to another.

	// Instantiate the API
	api, err := gsrpc.NewSubstrateAPI("wss://mainnet-node.dock.io")
	if err != nil {
		panic(err)
	}

	meta, err := api.RPC.State.GetMetadataLatest()
	if err != nil {
		panic(err)
	}

	// Create a call, transferring 12345 units to Bob
	// address : 3EbS8cbBoUmd23TrxRavif4S922xxq2AtfjXHqeoFRR7RghX
	// publicKey : 0x649d0efed4358bb99e3de015487accb56765b68322e18225bf9fef0a8766ef03
	bob, err := types.NewMultiAddressFromHexAccountID("0x649d0efed4358bb99e3de015487accb56765b68322e18225bf9fef0a8766ef03")
	if err != nil {
		panic(err)
	}

	// 1 unit of transfer
	bal, ok := new(big.Int).SetString("100000000000000", 10)
	if !ok {
		panic(fmt.Errorf("failed to convert balance"))
	}

	c, err := types.NewCall(meta, "Balances.transfer", bob, types.NewUCompact(bal))
	if err != nil {
		panic(err)
	}

	// Create the extrinsic
	ext := types.NewExtrinsic(c)

	genesisHash, err := api.RPC.Chain.GetBlockHash(0)
	if err != nil {
		panic(err)
	}

	rv, err := api.RPC.State.GetRuntimeVersionLatest()
	if err != nil {
		panic(err)
	}

	fromKey, err := signature.KeyringPairFromSecret("0xxxxxxx", 22)
	if err != nil {
		panic(err)
	}
	key, err := types.CreateStorageKey(meta, "System", "Account", fromKey.PublicKey)
	if err != nil {
		panic(err)
	}

	var accountInfo types.AccountInfo
	ok, err = api.RPC.State.GetStorageLatest(key, &accountInfo)
	if err != nil || !ok {
		panic(err)
	}

	nonce := uint32(accountInfo.Nonce)
	o := types.SignatureOptions{
		BlockHash:          genesisHash,
		Era:                types.ExtrinsicEra{IsMortalEra: false},
		GenesisHash:        genesisHash,
		Nonce:              types.NewUCompactFromUInt(uint64(nonce)),
		SpecVersion:        rv.SpecVersion,
		Tip:                types.NewUCompactFromUInt(100),
		TransactionVersion: rv.TransactionVersion,
	}

	// Sign the transaction using Alice's default account
	err = ext.Sign(fromKey, o)
	if err != nil {
		panic(err)
	}

	// Send the extrinsic
	_, err = api.RPC.Author.SubmitExtrinsic(ext)
	if err != nil {
		panic(err)
	}

	fmt.Printf("Balance transferred from Alice to Bob: %v\n", bal.String())
}

My Address : 3FShsMXRytNXrVFAXzD5L5vCMapbRMhwzpdBK3urgBLVcQJT

Error:

type *types.AccountInfo does not support Decodeable interface and could not be decoded field by field, error: type *struct { Free types.U128; Reserved types.U128; MiscFrozen types.U128; FreeFrozen types.U128 } does not support Decodeable interface and could not be decoded field by field, error: Cannot read the required number of bytes 16, only 4 available

image

How can I resolve this error?

Thanks

ygcool avatar Aug 08 '22 06:08 ygcool

Hi @ygcool,

Please try creating a different entity for AccountInfo, that is using U64 instead of U128, as seen below:

// AccountInfo contains information of an account
type AccountInfo struct {
	Nonce    U32
	Refcount U8
	Data     struct {
		Free       U64
		Reserved   U64
		MiscFrozen U64
		FreeFrozen U64
	}
}

Reason for this being the fact that the parachain implementation that you are connecting to, is using U64 for Balance instead of U128, based on the following:

https://github.com/docknetwork/dock-substrate/blob/4a2c69b26ab0446cac7ee6196db70461a36dc175/runtime/src/lib.rs#L416

https://github.com/docknetwork/dock-substrate/blob/4a2c69b26ab0446cac7ee6196db70461a36dc175/runtime/src/lib.rs#L134

Please let me know if this works for you.

cdamian avatar Aug 08 '22 08:08 cdamian

Can be solved. thank you!

When I send a transaction,New error: Example unable to decode field 4 event #1 with EventID [2 2], field Balances_Transfer: expected more bytes, but could not decode any more

ygcool avatar Aug 08 '22 08:08 ygcool

@ygcool same reason as before, the current Value field that we have for that event is U128 when the parachain sends it as U64.

Making the following adjustment will fix that issue:

// EventBalancesTransfer is emitted when a transfer succeeded (from, to, value)
type EventBalancesTransfer struct {
	Phase  Phase
	From   AccountID
	To     AccountID
	Value  U64
	Topics []Hash
}

The same applies to any event, call or storage entries that use the Balance defined in that parachain.

cdamian avatar Aug 08 '22 10:08 cdamian

@ygcool same reason as before, the current Value field that we have for that event is U128 when the parachain sends it as U64.

Making the following adjustment will fix that issue:

// EventBalancesTransfer is emitted when a transfer succeeded (from, to, value)
type EventBalancesTransfer struct {
	Phase  Phase
	From   AccountID
	To     AccountID
	Value  U64
	Topics []Hash
}

The same applies to any event, call or storage entries that use the Balance defined in that parachain.

thank you.
and, how to convert accountID to address string?

ygcool avatar Aug 09 '22 03:08 ygcool

  1. If I use this example listen transactions, I passed balances_ Transfer can get from/to/value, How to get transaction hash and block number? Or how to make sure the deal is successful
  2. and, In other codes, how can I get details through transaction hash?
  3. How to get address balance?

ygcool avatar Aug 09 '22 06:08 ygcool

you can find basically all your answers in the types repo or RPC repo

sheenhx avatar Aug 09 '22 13:08 sheenhx

type AccountInfo struct {
	Nonce    types.U32
	Refcount types.U8
	Data     struct {
		Free       types.U64
		Reserved   types.U64
		MiscFrozen types.U64
		FreeFrozen types.U64
	}
}

var accountInfo AccountInfo
ok, err = api.RPC.State.GetStorageLatest(key, &accountInfo)
if err != nil || !ok {
	panic(err)
}

However, the free I obtained is different from the actual balance.

Like this: https://dock.subscan.io/account/3FShsMXRytNXrVFAXzD5L5vCMapbRMhwzpdBK3urgBLVcQJT balance is: 3.269 But the value obtained is always 16777216

ygcool avatar Aug 10 '22 06:08 ygcool

type AccountInfo struct {
	Nonce    types.U32
	Refcount types.U8
	Data     struct {
		Free       types.U64
		Reserved   types.U64
		MiscFrozen types.U64
		FreeFrozen types.U64
	}
}

var accountInfo AccountInfo
ok, err = api.RPC.State.GetStorageLatest(key, &accountInfo)
if err != nil || !ok {
	panic(err)
}

However, the free I obtained is different from the actual balance.

Like this: https://dock.subscan.io/account/3FShsMXRytNXrVFAXzD5L5vCMapbRMhwzpdBK3urgBLVcQJT balance is: 3.269 But the value obtained is always 16777216

Solved this problem, AccountInfo :

type AccountInfo struct {
	Nonce    types.U64
	Refcount types.U64
	Data struct {
		Free       types.U64
		Reserved   types.U64
		MiscFrozen types.U64
		FreeFrozen types.U64
	}
}

No solution has been found to these two problems:

  1. If I use this example listen transactions, I passed balances_ Transfer can get from/to/value, How to get transaction hash and block number? Or how to make sure the deal is successful
  2. and, In other codes, how can I get details through transaction hash?

ygcool avatar Aug 10 '22 07:08 ygcool

@ygcool I'm not sure I understand you last questions. Do you still need help executing a transfer here or is there something else that's not working for you?

cdamian avatar Dec 05 '23 12:12 cdamian