mirror of
https://github.com/sonr-io/sonr.git
synced 2026-08-04 10:21:40 +00:00
@@ -0,0 +1,181 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/tx"
|
||||
)
|
||||
|
||||
// TxResponse represents transaction broadcast response
|
||||
type TxResponse struct {
|
||||
TxHash string `json:"txhash"`
|
||||
Code uint32 `json:"code"`
|
||||
RawLog string `json:"raw_log"`
|
||||
GasUsed string `json:"gas_used"`
|
||||
GasWanted string `json:"gas_wanted"`
|
||||
Height string `json:"height"`
|
||||
Events []struct {
|
||||
Type string `json:"type"`
|
||||
Attributes []struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
} `json:"attributes"`
|
||||
} `json:"events"`
|
||||
}
|
||||
|
||||
// BroadcastTxRequest represents transaction broadcast request
|
||||
type BroadcastTxRequest struct {
|
||||
TxBytes []byte `json:"tx_bytes"`
|
||||
Mode BroadcastMode `json:"mode"`
|
||||
}
|
||||
|
||||
// BroadcastMode represents different broadcast modes
|
||||
type BroadcastMode string
|
||||
|
||||
const (
|
||||
BroadcastModeSync BroadcastMode = "BROADCAST_MODE_SYNC"
|
||||
BroadcastModeAsync BroadcastMode = "BROADCAST_MODE_ASYNC"
|
||||
BroadcastModeBlock BroadcastMode = "BROADCAST_MODE_BLOCK"
|
||||
)
|
||||
|
||||
// BroadcastTx broadcasts a transaction to the network
|
||||
func (c *StarshipClient) BroadcastTx(ctx context.Context, txBytes []byte, mode BroadcastMode) (*TxResponse, error) {
|
||||
url := fmt.Sprintf("%s/cosmos/tx/v1beta1/txs", c.baseURL)
|
||||
|
||||
reqBody := BroadcastTxRequest{
|
||||
TxBytes: txBytes,
|
||||
Mode: mode,
|
||||
}
|
||||
|
||||
jsonBody, err := json.Marshal(reqBody)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal request: %w", err)
|
||||
}
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewBuffer(jsonBody))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create request: %w", err)
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
resp, err := c.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to broadcast transaction: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("broadcast failed with status %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
var broadcastResp struct {
|
||||
TxResponse TxResponse `json:"tx_response"`
|
||||
}
|
||||
|
||||
if err := json.NewDecoder(resp.Body).Decode(&broadcastResp); err != nil {
|
||||
return nil, fmt.Errorf("failed to decode broadcast response: %w", err)
|
||||
}
|
||||
|
||||
return &broadcastResp.TxResponse, nil
|
||||
}
|
||||
|
||||
// GetTxResponse represents get transaction response
|
||||
type GetTxResponse struct {
|
||||
Tx tx.Tx `json:"tx"`
|
||||
TxResponse TxResponse `json:"tx_response"`
|
||||
}
|
||||
|
||||
// GetTx queries a transaction by hash
|
||||
func (c *StarshipClient) GetTx(ctx context.Context, txHash string) (*GetTxResponse, error) {
|
||||
url := fmt.Sprintf("%s/cosmos/tx/v1beta1/txs/%s", c.baseURL, txHash)
|
||||
|
||||
var txResp GetTxResponse
|
||||
if err := c.doRequest(ctx, url, &txResp); err != nil {
|
||||
return nil, fmt.Errorf("failed to query transaction: %w", err)
|
||||
}
|
||||
|
||||
return &txResp, nil
|
||||
}
|
||||
|
||||
// SimulateRequest represents transaction simulation request
|
||||
type SimulateRequest struct {
|
||||
TxBytes []byte `json:"tx_bytes"`
|
||||
}
|
||||
|
||||
// SimulateResponse represents transaction simulation response
|
||||
type SimulateResponse struct {
|
||||
GasInfo struct {
|
||||
GasWanted string `json:"gas_wanted"`
|
||||
GasUsed string `json:"gas_used"`
|
||||
} `json:"gas_info"`
|
||||
Result struct {
|
||||
Data string `json:"data"`
|
||||
Log string `json:"log"`
|
||||
Events []sdk.StringEvent `json:"events"`
|
||||
} `json:"result"`
|
||||
}
|
||||
|
||||
// SimulateTx simulates a transaction to estimate gas
|
||||
func (c *StarshipClient) SimulateTx(ctx context.Context, txBytes []byte) (*SimulateResponse, error) {
|
||||
url := fmt.Sprintf("%s/cosmos/tx/v1beta1/simulate", c.baseURL)
|
||||
|
||||
reqBody := SimulateRequest{
|
||||
TxBytes: txBytes,
|
||||
}
|
||||
|
||||
jsonBody, err := json.Marshal(reqBody)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal simulate request: %w", err)
|
||||
}
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewBuffer(jsonBody))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create simulate request: %w", err)
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
resp, err := c.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to simulate transaction: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("simulation failed with status %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
var simResp SimulateResponse
|
||||
if err := json.NewDecoder(resp.Body).Decode(&simResp); err != nil {
|
||||
return nil, fmt.Errorf("failed to decode simulation response: %w", err)
|
||||
}
|
||||
|
||||
return &simResp, nil
|
||||
}
|
||||
|
||||
// WaitForTx waits for a transaction to be included in a block
|
||||
func (c *StarshipClient) WaitForTx(ctx context.Context, txHash string, timeout time.Duration) (*GetTxResponse, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, timeout)
|
||||
defer cancel()
|
||||
|
||||
ticker := time.NewTicker(2 * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, fmt.Errorf("timeout waiting for transaction %s", txHash)
|
||||
case <-ticker.C:
|
||||
tx, err := c.GetTx(ctx, txHash)
|
||||
if err == nil && tx.TxResponse.Code == 0 {
|
||||
return tx, nil
|
||||
}
|
||||
// Continue waiting if transaction not found or failed
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user