Skip to content

Commit

Permalink
feat(tx): add tx client to send transaction
Browse files Browse the repository at this point in the history
  • Loading branch information
bdeneux committed Sep 11, 2024
1 parent e4d308d commit 59becfb
Show file tree
Hide file tree
Showing 3 changed files with 205 additions and 0 deletions.
138 changes: 138 additions & 0 deletions tx/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package tx

import (
"cosmossdk.io/x/tx/signing"
"github.com/axone-protocol/axone-sdk/types"
sdkclient "github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/address"
codectype "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/tx"
signingtypes "github.com/cosmos/cosmos-sdk/types/tx/signing"
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/gogoproto/proto"
)

type Client interface {
SendTx(ctx types.Context, msgs []sdk.Msg, opts ...Option) (*sdk.TxResponse, error)
}

type client struct {
authClient authtypes.QueryClient
txConfig sdkclient.TxConfig
txClient tx.ServiceClient
}

func NewClient(authClient authtypes.QueryClient, txClient tx.ServiceClient) (Client, error) {
config, err := makeTxConfig()
if err != nil {
return nil, err
}

return &client{
authClient,
config,
txClient,
}, nil
}

func (c *client) SendTx(ctx types.Context, msgs []sdk.Msg, opts ...Option) (*sdk.TxResponse, error) {
txBuilder := c.txConfig.NewTxBuilder()
transaction := New(txBuilder, msgs, opts...)

accNum, accSeq, err := c.getAccountNumberSequence(ctx, transaction.signer.PubKey().Address().String())

signerData := authsigning.SignerData{
Address: transaction.signer.PubKey().Address().String(),
ChainID: ctx.ChainID(),
AccountNumber: accNum,
Sequence: accSeq,
PubKey: transaction.signer.PubKey(),
}

sig := signingtypes.SignatureV2{
PubKey: transaction.signer.PubKey(),
Data: &signingtypes.SingleSignatureData{
SignMode: signingtypes.SignMode_SIGN_MODE_DIRECT,
Signature: nil,
},
Sequence: signerData.Sequence,
}

if err := txBuilder.SetSignatures(sig); err != nil {
return nil, err
}

bytesToSign, err := authsigning.GetSignBytesAdapter(ctx,
c.txConfig.SignModeHandler(),
signingtypes.SignMode_SIGN_MODE_DIRECT,
signerData,
txBuilder.GetTx())
if err != nil {
return nil, err
}

sigBytes, err := transaction.signer.Sign(bytesToSign)
if err != nil {
return nil, err
}

sig.Data = &signingtypes.SingleSignatureData{
SignMode: signingtypes.SignMode_SIGN_MODE_DIRECT,
Signature: sigBytes,
}

if err := txBuilder.SetSignatures(sig); err != nil {
return nil, err
}

encodeTx, err := c.txConfig.TxEncoder()(txBuilder.GetTx())
if err != nil {
return nil, err
}

resp, err := c.txClient.BroadcastTx(ctx, &tx.BroadcastTxRequest{TxBytes: encodeTx})
if err != nil {
return nil, err
}
return resp.TxResponse, nil
}

func (c *client) getAccountNumberSequence(ctx types.Context, addr string) (uint64, uint64, error) {
resp, err := c.authClient.Account(ctx, &authtypes.QueryAccountRequest{Address: addr})
if err != nil {
return 0, 0, err
}

var account authtypes.BaseAccount
if err := account.Unmarshal(resp.GetAccount().Value); err != nil {
return 0, 0, err
}

return account.AccountNumber, account.Sequence, nil
}

func makeTxConfig() (sdkclient.TxConfig, error) {
interfaceRegistry, err := codectype.NewInterfaceRegistryWithOptions(codectype.InterfaceRegistryOptions{
ProtoFiles: proto.HybridResolver,
SigningOptions: signing.Options{
AddressCodec: address.Bech32Codec{
Bech32Prefix: sdk.GetConfig().GetBech32AccountAddrPrefix(),
},
ValidatorAddressCodec: address.Bech32Codec{
Bech32Prefix: sdk.GetConfig().GetBech32ValidatorAddrPrefix(),
},
},
})
if err != nil {
return nil, err
}

return authtx.NewTxConfig(
codec.NewProtoCodec(interfaceRegistry),
authtx.DefaultSignModes,
), nil
}
48 changes: 48 additions & 0 deletions tx/transaction.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package tx

import (
"github.com/axone-protocol/axone-sdk/keys"
sdkclient "github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/types"
)

type Transaction struct {
builder sdkclient.TxBuilder
signer keys.Keyring
}

type Option func(*Transaction)

func New(builder sdkclient.TxBuilder, msgs []types.Msg, opts ...Option) *Transaction {
tx := &Transaction{
builder: builder,
}
for _, opt := range opts {
opt(tx)
}
return tx
}

func WithMemo(memo string) Option {
return func(tx *Transaction) {
tx.builder.SetMemo(memo)
}
}

func WithGasLimit(limit uint64) Option {
return func(tx *Transaction) {
tx.builder.SetGasLimit(limit)
}
}

func WithFeeAmount(amount types.Coins) Option {
return func(tx *Transaction) {
tx.builder.SetFeeAmount(amount)
}
}

func WithSigner(signer keys.Keyring) Option {
return func(tx *Transaction) {
tx.signer = signer
}
}
19 changes: 19 additions & 0 deletions types/context.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package types

import "context"

type Context struct {
context.Context

chainID string
}

func (c Context) ChainID() string {
return c.chainID
}

// WithChainID returns a new context with the given chain ID.
func (c Context) WithChainID(chainID string) Context {
c.chainID = chainID
return c
}

0 comments on commit 59becfb

Please sign in to comment.