> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbitflare.com/llms.txt
> Use this file to discover all available pages before exploring further.

# RPC 客户端

> 带重试、故障转移，以及针对常见 Solana 方法的类型化辅助方法的 JSON-RPC 客户端。

## 安装

```bash theme={null}
go get github.com/orbitflare/orbitflare-sdk-go
```

```go theme={null}
import "github.com/orbitflare/orbitflare-sdk-go/rpc"
```

## 构建客户端

下面是设置了所有选项的客户端：

```go theme={null}
import (
    "time"

    "github.com/orbitflare/orbitflare-sdk-go/orbitflare"
    "github.com/orbitflare/orbitflare-sdk-go/rpc"
)

client, err := rpc.NewBuilder().
    URL("http://ny.rpc.orbitflare.com").
    FallbackURL("http://fra.rpc.orbitflare.com").
    FallbackURL("http://ams.rpc.orbitflare.com").
    APIKey("ORBIT-XXXXXX-NNNNNN-NNNNNN").
    Commitment("confirmed").
    Retry(orbitflare.RetryPolicy{
        InitialDelay: 100 * time.Millisecond,
        MaxDelay:     30 * time.Second,
        Multiplier:   2.0,
        MaxAttempts:  5,
    }).
    Timeout(30 * time.Second).
    Build()
```

大多数选项都有合理的默认值。最小化设置：

```go theme={null}
client, err := rpc.NewBuilder().
    URL("http://ny.rpc.orbitflare.com").
    Build()
```

每个方法都接收一个 `context.Context`，因此可传入带截止时间的 context 来限定单次调用：

```go theme={null}
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
```

### 构建器方法

**`.URL(url)`** - 发送请求的主端点。若未设置，SDK 会读取 `ORBITFLARE_RPC_URL` 环境变量。

```go theme={null}
.URL("http://ny.rpc.orbitflare.com")
```

**`.URLs(urls...)`** - 一次性设置主端点及全部回退端点。第一个为主端点，其余为回退端点。

```go theme={null}
.URLs("http://ny.rpc.orbitflare.com", "http://fra.rpc.orbitflare.com", "http://ams.rpc.orbitflare.com")
```

**`.FallbackURL(url)`** - 添加单个回退端点。可多次调用以添加多个。当主端点失败时，SDK 会按顺序尝试回退端点。

```go theme={null}
.FallbackURL("http://fra.rpc.orbitflare.com").
FallbackURL("http://ams.rpc.orbitflare.com")
```

**`.FallbackURLs(urls...)`** - 与 `FallbackURL` 相同，但可一次传入多个。

```go theme={null}
.FallbackURLs("http://fra.rpc.orbitflare.com", "http://ams.rpc.orbitflare.com")
```

**`.APIKey(key)`** - 你的 OrbitFlare 许可证密钥。若未设置，SDK 会读取环境变量 `ORBITFLARE_LICENSE_KEY`。密钥在请求时注入 URL，绝不存储于端点，也绝不出现在日志或错误信息中。

```go theme={null}
.APIKey("ORBIT-XXXXXX-NNNNNN-NNNNNN")
```

**`.Commitment(level)`** - 所有类型化辅助方法使用的默认承诺级别。可选：`"processed"`、`"confirmed"`、`"finalized"`。默认 `"confirmed"`。

```go theme={null}
.Commitment("finalized")
```

**`.Retry(policy)`** - 控制 SDK 如何重试失败的请求。`InitialDelay` 是首次重试前的等待时间。`Multiplier` 在每次尝试时缩放延迟。`MaxDelay` 为退避上限。`MaxAttempts` 限制总重试次数（0 表示无限）。默认：100ms 初始、30s 上限、2 倍系数、无限次。

```go theme={null}
.Retry(orbitflare.RetryPolicy{
    InitialDelay: 200 * time.Millisecond,
    MaxDelay:     15 * time.Second,
    Multiplier:   2.0,
    MaxAttempts:  5,
})
```

**`.Timeout(duration)`** - 每次请求的 HTTP 超时。默认 30 秒。

```go theme={null}
.Timeout(10 * time.Second)
```

**`.Logger(logger)`** - 用于请求重试与故障转移的 `*slog.Logger`。未设置时，日志由 `ORBITFLARE_LOG` 环境变量控制（`trace|debug|info|warn|error|silent`，默认 `silent`）。

```go theme={null}
.Logger(slog.New(slog.NewTextHandler(os.Stderr, nil)))
```

## 可用 RPC 方法

类型化辅助方法返回 Go 值；其余方法返回可自行反序列化为你自己类型的 `json.RawMessage`。

### `GetSlot(ctx)`

返回当前槽位号。

```go theme={null}
slot, err := client.GetSlot(ctx) // uint64
```

### `GetBalance(ctx, address)`

返回账户余额（以 lamports 计）。

```go theme={null}
lamports, err := client.GetBalance(ctx, "So11111111111111111111111111111111111111112") // uint64
sol := float64(lamports) / 1_000_000_000
```

### `GetAccountInfo(ctx, address)`

返回完整账户数据（`json.RawMessage`），账户不存在时为 nil。数据为 base64 编码。

```go theme={null}
raw, err := client.GetAccountInfo(ctx, "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v")
if raw != nil {
    var info struct {
        Owner    string `json:"owner"`
        Lamports uint64 `json:"lamports"`
    }
    json.Unmarshal(raw, &info)
}
```

### `GetMultipleAccounts(ctx, addresses)`

一次调用获取多个账户。自动按每批 100 个分块（Solana 的单请求上限），因此可传入任意数量的地址。

```go theme={null}
accounts, err := client.GetMultipleAccounts(ctx, []string{"addr1", "addr2", "addr3"}) // []json.RawMessage
```

### `GetLatestBlockhash(ctx)`

返回最新的 blockhash 及其有效的最后区块高度。

```go theme={null}
blockhash, lastValid, err := client.GetLatestBlockhash(ctx) // (string, uint64)
```

### `GetTransaction(ctx, signature)`

按签名获取已确认交易。返回带元数据的完整交易（`json.RawMessage`）。

```go theme={null}
raw, err := client.GetTransaction(ctx, "5K8F2j...")
```

### `GetSignaturesForAddress(ctx, address, limit)`

返回某地址最近的交易签名，最新的在前。

```go theme={null}
sigs, err := client.GetSignaturesForAddress(ctx, "So111...", 10) // []json.RawMessage
```

### `GetProgramAccounts(ctx, programID)`

返回某程序拥有的全部账户。数据量可能很大。

```go theme={null}
accounts, err := client.GetProgramAccounts(ctx, "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")
```

### `GetRecentPrioritizationFees(ctx, addresses)`

返回一组账户的近期优先费。可用于估算计算单元定价。

```go theme={null}
fees, err := client.GetRecentPrioritizationFees(ctx, []string{"6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"})
```

### `SendTransaction(ctx, txBase64)`

向网络发送已签名交易。接收 base64 编码的序列化交易。返回交易签名。

```go theme={null}
signature, err := client.SendTransaction(ctx, txBase64) // string
```

### `SimulateTransaction(ctx, txBase64)`

在不提交的情况下模拟交易。返回日志、消耗的计算单元以及任何错误（`json.RawMessage`）。

```go theme={null}
raw, err := client.SimulateTransaction(ctx, txBase64)
```

### `GetTokenAccountsByOwner(ctx, owner, mint, programID)`

返回钱包的代币账户。传入特定 mint 或代币程序 ID。若两者均为空字符串，则默认使用 SPL Token 程序。

```go theme={null}
tokens, err := client.GetTokenAccountsByOwner(ctx, "wallet_address", "", "")
```

### `GetTransactionsForAddress(ctx, address, options)`

OrbitFlare 专属方法，将 `getSignaturesForAddress` 与 `getTransaction` 合并为一次调用。返回带 `Data` 切片及可选 `PaginationToken`（用于翻页）的 `GetTransactionsResult`。

支持四种详情级别（`signatures`、`none`、`accounts`、`full`）、双向排序、时间/槽位过滤、状态过滤以及代币账户包含。`options` 可为 nil 以使用默认值。

```go theme={null}
details, order, status := "full", "asc", "succeeded"
var limit uint32 = 100
gte, lte := int64(1704067200), int64(1706745600)

result, err := client.GetTransactionsForAddress(ctx, "address", &rpc.GetTransactionsOptions{
    TransactionDetails: &details,
    Limit:              &limit,
    SortOrder:          &order,
    Filters: &rpc.GetTransactionsFilters{
        Status:    &status,
        BlockTime: &rpc.RangeFilter[int64]{Gte: &gte, Lte: &lte},
    },
})

for _, tx := range result.Data {
    _ = tx // json.RawMessage
}
if result.PaginationToken != nil {
    // 在下次调用时设置 PaginationToken 以获取下一页
}
```

### `Request(ctx, method, params)`

按名称调用任意 RPC 方法。SDK 构建 JSON-RPC 信封、处理重试与故障转移，并返回 `result` 字段（`json.RawMessage`）。

```go theme={null}
epoch, err := client.Request(ctx, "getEpochInfo", []any{})
inflation, err := client.Request(ctx, "getInflationRate", []any{})
```

### `RequestRaw(ctx, body)`

发送原始 JSON-RPC 主体字符串。与其他方法一样具备重试与故障转移。

```go theme={null}
result, err := client.RequestRaw(ctx, `{"jsonrpc":"2.0","id":1,"method":"getHealth","params":[]}`)
```

## 完整示例

一个检查网络状态、获取钱包 SOL 余额并查询近期交易的程序。

```go theme={null}
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"
    "time"

    "github.com/orbitflare/orbitflare-sdk-go/rpc"
)

func main() {
    client, err := rpc.NewBuilder().
        URL("http://ny.rpc.orbitflare.com").
        FallbackURL("http://fra.rpc.orbitflare.com").
        Commitment("confirmed").
        Build()
    if err != nil {
        log.Fatal(err)
    }

    ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
    defer cancel()

    wallet := "CKs1E69a2e9TmH4mKKLrXFF8kD3ZnwKjoEuXa6sz9WqX"

    slot, _ := client.GetSlot(ctx)
    blockhash, _, _ := client.GetLatestBlockhash(ctx)
    fmt.Printf("network slot: %d\nblockhash: %s\n", slot, blockhash)

    balance, _ := client.GetBalance(ctx, wallet)
    fmt.Printf("\n%s\n  SOL: %.4f\n", wallet, float64(balance)/1_000_000_000)

    sigs, _ := client.GetSignaturesForAddress(ctx, wallet, 5)
    fmt.Println("\nrecent transactions:")
    for _, raw := range sigs {
        var sig struct {
            Signature string `json:"signature"`
            Slot      uint64 `json:"slot"`
            Err       any    `json:"err"`
        }
        json.Unmarshal(raw, &sig)
        status := "ok"
        if sig.Err != nil {
            status = "failed"
        }
        fmt.Printf("  %d %s %s\n", sig.Slot, status, sig.Signature[:20])
    }
}
```
