generated from axone-protocol/template-oss
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(tx): add tx client to send transaction
- Loading branch information
Showing
3 changed files
with
205 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |