Some checks are pending
Docs Deploy / build_and_deploy (push) Waiting to run
Generate Docs / cli (push) Waiting to run
Generate Config Doc / cli (push) Waiting to run
Go formatting / go-formatting (push) Waiting to run
Check links / markdown-link-check (push) Waiting to run
Integration / pre-test (push) Waiting to run
Integration / test on (push) Blocked by required conditions
Integration / status (push) Blocked by required conditions
Lint / Lint Go code (push) Waiting to run
Test / test (ubuntu-latest) (push) Waiting to run
142 lines
4.2 KiB
Go
142 lines
4.2 KiB
Go
package cosmosclient
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/cosmos/cosmos-sdk/client"
|
|
"github.com/cosmos/cosmos-sdk/client/tx"
|
|
sdktypes "github.com/cosmos/cosmos-sdk/types"
|
|
|
|
"github.com/ignite/cli/v29/ignite/pkg/errors"
|
|
)
|
|
|
|
// BroadcastOption configures broadcast behavior.
|
|
type BroadcastOption func(*broadcastConfig)
|
|
|
|
// broadcastConfig holds configuration for broadcast operations.
|
|
type broadcastConfig struct {
|
|
sequence uint64
|
|
unordered bool
|
|
}
|
|
|
|
// WithSequence overrides the account sequence for the transaction.
|
|
func WithSequence(sequence uint64) BroadcastOption {
|
|
return func(cfg *broadcastConfig) {
|
|
cfg.sequence = sequence
|
|
}
|
|
}
|
|
|
|
// WithUnordered sets the unordered flag for the transaction.
|
|
// NOTE: This is only supported for Cosmos SDK versions >= v0.53.
|
|
func WithUnordered(unordered bool) BroadcastOption {
|
|
return func(cfg *broadcastConfig) {
|
|
cfg.unordered = unordered
|
|
}
|
|
}
|
|
|
|
type TxService struct {
|
|
client Client
|
|
clientContext client.Context
|
|
txBuilder client.TxBuilder
|
|
txFactory tx.Factory
|
|
}
|
|
|
|
// Gas is gas decided to use for this tx.
|
|
// either calculated or configured by the caller.
|
|
func (s TxService) Gas() uint64 {
|
|
return s.txBuilder.GetTx().GetGas()
|
|
}
|
|
|
|
// broadcast signs and broadcasts the transaction returning the initial broadcast response.
|
|
func (s TxService) broadcast(ctx context.Context, opts ...BroadcastOption) (*sdktypes.TxResponse, error) {
|
|
defer s.client.lockBech32Prefix()()
|
|
|
|
// validate msgs.
|
|
for _, msg := range s.txBuilder.GetTx().GetMsgs() {
|
|
msg, ok := msg.(sdktypes.HasValidateBasic)
|
|
if !ok {
|
|
continue
|
|
}
|
|
if err := msg.ValidateBasic(); err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
}
|
|
|
|
// Apply broadcast options
|
|
cfg := &broadcastConfig{}
|
|
for _, opt := range opts {
|
|
opt(cfg)
|
|
}
|
|
|
|
// Override sequence if specified
|
|
if cfg.sequence != 0 {
|
|
s.txFactory = s.txFactory.WithSequence(cfg.sequence)
|
|
}
|
|
s.txFactory = s.txFactory.WithUnordered(cfg.unordered)
|
|
|
|
accountName := s.clientContext.FromName
|
|
if err := s.client.signer.Sign(ctx, s.txFactory, accountName, s.txBuilder, true); err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
txBytes, err := s.clientContext.TxConfig.TxEncoder()(s.txBuilder.GetTx())
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
resp, err := s.clientContext.BroadcastTx(txBytes)
|
|
if err := handleBroadcastResult(resp, err); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return resp, nil
|
|
}
|
|
|
|
// Broadcast signs and broadcasts this tx.
|
|
// If faucet is enabled and if the "from" account doesn't have enough funds, is
|
|
// it automatically filled with the default amount, and the tx is broadcasted
|
|
// again. Note that this may still end with the same error if the amount is
|
|
// greater than the amount dumped by the faucet.
|
|
func (s TxService) Broadcast(ctx context.Context, opts ...BroadcastOption) (Response, error) {
|
|
resp, err := s.broadcast(ctx, opts...)
|
|
if err != nil {
|
|
return Response{}, err
|
|
}
|
|
|
|
res, err := s.client.WaitForTx(ctx, resp.TxHash)
|
|
if err != nil {
|
|
return Response{}, err
|
|
}
|
|
// NOTE(tb) second and third parameters are omitted:
|
|
// - second parameter represents the tx and should be of type sdktypes.Any,
|
|
// but it is very ugly to decode, not sure if it's worth it (see sdk code
|
|
// x/auth/query.go method makeTxResult)
|
|
// - third parameter represents the timestamp of the tx, which must be
|
|
// fetched from the block itself. So it requires another API call to
|
|
// fetch the block from res.Height, not sure if it's worth it too.
|
|
resp = sdktypes.NewResponseResultTx(res, nil, "")
|
|
|
|
return Response{
|
|
Codec: s.clientContext.Codec,
|
|
TxResponse: resp,
|
|
}, handleBroadcastResult(resp, err)
|
|
}
|
|
|
|
// BroadcastAsync signs and broadcasts this tx.
|
|
// It is similar to Broadcast but it does not wait for the transaction to be included in a block.
|
|
func (s TxService) BroadcastAsync(ctx context.Context, opts ...BroadcastOption) (Response, error) {
|
|
resp, err := s.broadcast(ctx, opts...)
|
|
if err != nil {
|
|
return Response{}, err
|
|
}
|
|
|
|
return Response{
|
|
Codec: s.clientContext.Codec,
|
|
TxResponse: resp,
|
|
}, handleBroadcastResult(resp, err)
|
|
}
|
|
|
|
// EncodeJSON encodes the transaction as a json string.
|
|
func (s TxService) EncodeJSON() ([]byte, error) {
|
|
return s.client.context.TxConfig.TxJSONEncoder()(s.txBuilder.GetTx())
|
|
}
|