Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 138 additions & 0 deletions rpc/getMinContextSlot_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package rpc

import (
"context"
"testing"

"github.com/gagliardetto/solana-go"
stdjson "github.com/goccy/go-json"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

// TestClient_GetProgramAccountsWithOpts_MinContextSlot pins that the
// minContextSlot opt is forwarded into the params object.
func TestClient_GetProgramAccountsWithOpts_MinContextSlot(t *testing.T) {
responseBody := `[{"account":{"data":["dGVzdA==","base64"],"executable":true,"lamports":2039280,"owner":"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA","rentEpoch":206},"pubkey":"7xLk17EQQ5KLDLDe44wCmupJKJjTGd8hs3eSVVhCx932"}]`
server, closer := mockJSONRPC(t, stdjson.RawMessage(wrapIntoRPC(responseBody)))
defer closer()
client := New(server.URL)

pubkeyString := "7xLk17EQQ5KLDLDe44wCmupJKJjTGd8hs3eSVVhCx932"
pubKey := solana.MustPublicKeyFromBase58(pubkeyString)

minSlot := uint64(123456789)
_, err := client.GetProgramAccountsWithOpts(
context.Background(),
pubKey,
&GetProgramAccountsOpts{
MinContextSlot: &minSlot,
},
)
require.NoError(t, err)

reqBody := server.RequestBody(t)
reqBody["id"] = any(nil)

assert.Equal(t,
map[string]any{
"id": any(nil),
"jsonrpc": "2.0",
"method": "getProgramAccounts",
"params": []any{
pubkeyString,
map[string]any{
"encoding": "base64",
"minContextSlot": float64(minSlot),
},
},
},
reqBody,
)
}

// TestClient_GetTokenAccountsByOwner_MinContextSlot pins that the
// minContextSlot opt is forwarded into the params object for the owner variant.
func TestClient_GetTokenAccountsByOwner_MinContextSlot(t *testing.T) {
responseBody := `{"context":{"slot":1},"value":[]}`
server, closer := mockJSONRPC(t, stdjson.RawMessage(wrapIntoRPC(responseBody)))
defer closer()
client := New(server.URL)

ownerString := "7xLk17EQQ5KLDLDe44wCmupJKJjTGd8hs3eSVVhCx932"
owner := solana.MustPublicKeyFromBase58(ownerString)
programIDString := "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
programID := solana.MustPublicKeyFromBase58(programIDString)

minSlot := uint64(987654321)
_, err := client.GetTokenAccountsByOwner(
context.Background(),
owner,
&GetTokenAccountsConfig{ProgramId: &programID},
&GetTokenAccountsOpts{MinContextSlot: &minSlot},
)
require.NoError(t, err)

reqBody := server.RequestBody(t)
reqBody["id"] = any(nil)

assert.Equal(t,
map[string]any{
"id": any(nil),
"jsonrpc": "2.0",
"method": "getTokenAccountsByOwner",
"params": []any{
ownerString,
map[string]any{"programId": programIDString},
map[string]any{
"encoding": "base64",
"minContextSlot": float64(minSlot),
},
},
},
reqBody,
)
}

// TestClient_GetTokenAccountsByDelegate_MinContextSlot pins the same for the
// delegate variant.
func TestClient_GetTokenAccountsByDelegate_MinContextSlot(t *testing.T) {
responseBody := `{"context":{"slot":1},"value":[]}`
server, closer := mockJSONRPC(t, stdjson.RawMessage(wrapIntoRPC(responseBody)))
defer closer()
client := New(server.URL)

delegateString := "7xLk17EQQ5KLDLDe44wCmupJKJjTGd8hs3eSVVhCx932"
delegate := solana.MustPublicKeyFromBase58(delegateString)
programIDString := "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
programID := solana.MustPublicKeyFromBase58(programIDString)

minSlot := uint64(42)
_, err := client.GetTokenAccountsByDelegate(
context.Background(),
delegate,
&GetTokenAccountsConfig{ProgramId: &programID},
&GetTokenAccountsOpts{MinContextSlot: &minSlot},
)
require.NoError(t, err)

reqBody := server.RequestBody(t)
reqBody["id"] = any(nil)

assert.Equal(t,
map[string]any{
"id": any(nil),
"jsonrpc": "2.0",
"method": "getTokenAccountsByDelegate",
"params": []any{
delegateString,
map[string]any{"programId": programIDString},
map[string]any{
"encoding": "base64",
"minContextSlot": float64(minSlot),
},
},
},
reqBody,
)
}
3 changes: 3 additions & 0 deletions rpc/getProgramAccounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ func buildGetProgramAccountsParams(publicKey solana.PublicKey, opts *GetProgramA
if opts.SortResults != nil {
obj["sortResults"] = *opts.SortResults
}
if opts.MinContextSlot != nil {
obj["minContextSlot"] = *opts.MinContextSlot
}
}
return []any{publicKey, obj}
}
6 changes: 6 additions & 0 deletions rpc/getTokenAccountsByDelegate.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ type GetTokenAccountsOpts struct {
Encoding solana.EncodingType `json:"encoding,omitempty"`

DataSlice *DataSlice `json:"dataSlice,omitempty"`

// The minimum slot that the request can be evaluated at.
MinContextSlot *uint64 `json:"minContextSlot,omitempty"`
}

// GetTokenAccountsByDelegate returns all SPL Token accounts by approved Delegate.
Expand Down Expand Up @@ -87,6 +90,9 @@ func (cl *Client) GetTokenAccountsByDelegate(
return nil, errors.New("cannot use dataSlice with EncodingJSONParsed")
}
}
if opts.MinContextSlot != nil {
optsObj["minContextSlot"] = *opts.MinContextSlot
}
if len(optsObj) > 0 {
params = append(params, optsObj)
}
Expand Down
3 changes: 3 additions & 0 deletions rpc/getTokenAccountsByOwner.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ func (cl *Client) GetTokenAccountsByOwner(
return nil, errors.New("cannot use dataSlice with EncodingJSONParsed")
}
}
if opts.MinContextSlot != nil {
optsObj["minContextSlot"] = *opts.MinContextSlot
}
if len(optsObj) > 0 {
params = append(params, optsObj)
}
Expand Down
3 changes: 3 additions & 0 deletions rpc/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,9 @@ type GetProgramAccountsOpts struct {

// Sort the results (useful for deterministic pagination).
SortResults *bool `json:"sortResults,omitempty"`

// The minimum slot that the request can be evaluated at.
MinContextSlot *uint64 `json:"minContextSlot,omitempty"`
}

type GetProgramAccountsResult []*KeyedAccount
Expand Down