Skip to content

Commit 886c1dd

Browse files
Merge pull request #98 from Peersyst/xrpl/feat/get-aggregated-price-request
[TA-3978]: get_aggregate_price request
2 parents dbc4da4 + 4c053e1 commit 886c1dd

File tree

11 files changed

+362
-5
lines changed

11 files changed

+362
-5
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
#### xrpl
1313

14-
- Added `GatewayBalances` query.
14+
- Added `GatewayBalances` and `GetAggregatePrice` queries.
1515

1616
### Fixed
1717

xrpl/queries/account/gateway_balances.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ type GatewayBalancesRequest struct {
2424
// An operational address to exclude from the balances issued, or an array of
2525
// Such addresses.
2626
HotWallet interface{} `json:"hotwallet,omitempty"`
27+
// A 20-byte hex string for the ledger version to use.
28+
LedgerHash common.LedgerHash `json:"ledger_hash,omitempty"`
29+
// The ledger index of the ledger to use, or a shortcut string.
30+
LedgerIndex common.LedgerSpecifier `json:"ledger_index,omitempty"`
2731
}
2832

2933
func (r *GatewayBalancesRequest) Method() string {

xrpl/queries/account/gateway_balances_test.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,28 @@ package account
33
import (
44
"testing"
55

6+
7+
"github.com/Peersyst/xrpl-go/xrpl/queries/common"
68
"github.com/Peersyst/xrpl-go/xrpl/testutil"
79
)
810

911
func TestGatewayBalancesRequest(t *testing.T) {
1012
s := GatewayBalancesRequest{
11-
Account: "rLHmBn4fT92w4F6ViyYbjoizLTo83tHTHu",
12-
Strict: true,
13-
HotWallet: []string{"rLHmBn4fT92w4F6ViyYbjoizLTo83tHTHu"},
13+
Account: "rLHmBn4fT92w4F6ViyYbjoizLTo83tHTHu",
14+
Strict: true,
15+
HotWallet: []string{"rLHmBn4fT92w4F6ViyYbjoizLTo83tHTHu"},
16+
LedgerHash: "ABC123",
17+
LedgerIndex: common.LedgerTitle("validated"),
1418
}
1519

1620
j := `{
1721
"account": "rLHmBn4fT92w4F6ViyYbjoizLTo83tHTHu",
1822
"strict": true,
1923
"hotwallet": [
2024
"rLHmBn4fT92w4F6ViyYbjoizLTo83tHTHu"
21-
]
25+
],
26+
"ledger_hash": "ABC123",
27+
"ledger_index": "validated"
2228
}`
2329
if err := testutil.Serialize(t, s, j); err != nil {
2430
t.Error(err)
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package oracle
2+
3+
import (
4+
"github.com/Peersyst/xrpl-go/xrpl/queries/common"
5+
"github.com/Peersyst/xrpl-go/xrpl/queries/oracle/types"
6+
"github.com/Peersyst/xrpl-go/xrpl/queries/version"
7+
)
8+
9+
// ############################################################################
10+
// Request
11+
// ############################################################################
12+
13+
// The `get_aggregate_price` method retrieves the aggregate price of specified Oracle objects,
14+
// returning three price statistics: mean, median, and trimmed mean.
15+
// Returns an GetAggregatePriceResponse.
16+
type GetAggregatePriceRequest struct {
17+
common.BaseRequest
18+
// The currency code of the asset to be priced.
19+
BaseAsset string `json:"base_asset"`
20+
// The currency code of the asset to quote the price of the base asset.
21+
QuoteAsset string `json:"quote_asset"`
22+
// The oracles identifiers
23+
Oracles []types.Oracle `json:"oracles"`
24+
// The percentage of outliers to trim. Valid trim range is 1-25. If included, the API
25+
// returns statistics for the trimmed mean.
26+
Trim uint32 `json:"trim,omitempty"`
27+
// Defines a time range in seconds for filtering out older price data. Default value is 0,
28+
// which doesn't filter any data.
29+
TrimThreshold uint32 `json:"trim_threshold,omitempty"`
30+
}
31+
32+
func (r *GetAggregatePriceRequest) Method() string {
33+
return "get_aggregate_price"
34+
}
35+
36+
func (r *GetAggregatePriceRequest) APIVersion() int {
37+
return version.RippledAPIV2
38+
}
39+
40+
func (r *GetAggregatePriceRequest) Validate() error {
41+
return nil
42+
}
43+
44+
// ############################################################################
45+
// Response
46+
// ############################################################################
47+
48+
// The expected response from the get_aggregate_price method.
49+
type GetAggregatePriceResponse struct {
50+
// The statistics from the collected oracle prices.
51+
EntireSet types.Set `json:"entire_set"`
52+
// The trimmed statistics from the collected oracle prices. Only appears if the trim field was specified in the request.
53+
TrimmedSet types.Set `json:"trimmed_set,omitempty"`
54+
// The median of the collected oracle prices.
55+
Median string `json:"median"`
56+
// The most recent timestamp out of all LastUpdateTime values.
57+
Time uint `json:"time"`
58+
// The ledger index of the ledger version that was used to generate this
59+
// response.
60+
LedgerCurrentIndex common.LedgerIndex `json:"ledger_current_index"`
61+
// If included and set to true, the information in this response comes from
62+
// a validated ledger version. Otherwise, the information is subject to
63+
// change.
64+
Validated bool `json:"validated"`
65+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package oracle
2+
3+
import (
4+
"testing"
5+
6+
"github.com/Peersyst/xrpl-go/xrpl/queries/oracle/types"
7+
"github.com/Peersyst/xrpl-go/xrpl/testutil"
8+
)
9+
10+
func TestGetAggregatePriceRequest(t *testing.T) {
11+
s := GetAggregatePriceRequest{
12+
BaseAsset: "XRP",
13+
QuoteAsset: "USD",
14+
Oracles: []types.Oracle{
15+
{
16+
Account: "rLHmBn4fT92w4F6ViyYbjoizLTo83tHTHu",
17+
OracleDocumentID: "123",
18+
},
19+
},
20+
Trim: 10,
21+
TrimThreshold: 3600,
22+
}
23+
24+
j := `{
25+
"base_asset": "XRP",
26+
"quote_asset": "USD",
27+
"oracles": [
28+
{
29+
"account": "rLHmBn4fT92w4F6ViyYbjoizLTo83tHTHu",
30+
"oracle_document_id": "123"
31+
}
32+
],
33+
"trim": 10,
34+
"trim_threshold": 3600
35+
}`
36+
if err := testutil.Serialize(t, s, j); err != nil {
37+
t.Error(err)
38+
}
39+
}
40+
41+
func TestGetAggregatePriceResponse(t *testing.T) {
42+
s := GetAggregatePriceResponse{
43+
EntireSet: types.Set{
44+
Mean: "0.5123",
45+
Size: 10,
46+
StandardDeviation: "0.0123",
47+
},
48+
TrimmedSet: types.Set{
49+
Mean: "0.5100",
50+
Size: 8,
51+
StandardDeviation: "0.0100",
52+
},
53+
Median: "0.5110",
54+
Time: 1609459200,
55+
LedgerCurrentIndex: 54321,
56+
Validated: true,
57+
}
58+
59+
j := `{
60+
"entire_set": {
61+
"mean": "0.5123",
62+
"size": 10,
63+
"standard_deviation": "0.0123"
64+
},
65+
"trimmed_set": {
66+
"mean": "0.5100",
67+
"size": 8,
68+
"standard_deviation": "0.0100"
69+
},
70+
"median": "0.5110",
71+
"time": 1609459200,
72+
"ledger_current_index": 54321,
73+
"validated": true
74+
}`
75+
if err := testutil.Serialize(t, s, j); err != nil {
76+
t.Error(err)
77+
}
78+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package types
2+
3+
type Oracle struct {
4+
Account string `json:"account"`
5+
OracleDocumentID interface{} `json:"oracle_document_id"`
6+
}

xrpl/queries/oracle/types/set.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package types
2+
3+
type Set struct {
4+
Mean string `json:"mean"`
5+
Size uint32 `json:"size"`
6+
StandardDeviation string `json:"standard_deviation"`
7+
}

xrpl/rpc/queries.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"github.com/Peersyst/xrpl-go/xrpl/queries/common"
88
ledger "github.com/Peersyst/xrpl-go/xrpl/queries/ledger"
99
nft "github.com/Peersyst/xrpl-go/xrpl/queries/nft"
10+
"github.com/Peersyst/xrpl-go/xrpl/queries/oracle"
1011
path "github.com/Peersyst/xrpl-go/xrpl/queries/path"
1112
server "github.com/Peersyst/xrpl-go/xrpl/queries/server"
1213
utility "github.com/Peersyst/xrpl-go/xrpl/queries/utility"
@@ -504,6 +505,24 @@ func (c *Client) GetServerState(req *server.StateRequest) (*server.StateResponse
504505
return &lr, nil
505506
}
506507

508+
// Oracle queries
509+
510+
// GetAggregatePrice retrieves the aggregate price of an asset.
511+
// It takes a GetAggregatePriceRequest as input and returns a GetAggregatePriceResponse,
512+
// along with any error encountered.
513+
func (c *Client) GetAggregatePrice(req *oracle.GetAggregatePriceRequest) (*oracle.GetAggregatePriceResponse, error) {
514+
res, err := c.Request(req)
515+
if err != nil {
516+
return nil, err
517+
}
518+
var lr oracle.GetAggregatePriceResponse
519+
err = res.GetResult(&lr)
520+
if err != nil {
521+
return nil, err
522+
}
523+
return &lr, nil
524+
}
525+
507526
// Utility queries
508527

509528
// Ping tests the connection to the server.

xrpl/rpc/queries_test.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
ledgertypes "github.com/Peersyst/xrpl-go/xrpl/queries/ledger/types"
1414
nft "github.com/Peersyst/xrpl-go/xrpl/queries/nft"
1515
nfttypes "github.com/Peersyst/xrpl-go/xrpl/queries/nft/types"
16+
"github.com/Peersyst/xrpl-go/xrpl/queries/oracle"
1617
path "github.com/Peersyst/xrpl-go/xrpl/queries/path"
1718
pathtypes "github.com/Peersyst/xrpl-go/xrpl/queries/path/types"
1819
server "github.com/Peersyst/xrpl-go/xrpl/queries/server"
@@ -2767,6 +2768,73 @@ func TestClient_GetServerState(t *testing.T) {
27672768
}
27682769
}
27692770

2771+
func TestClient_GetAggregatePrice(t *testing.T) {
2772+
tests := []struct {
2773+
name string
2774+
mockResponse string
2775+
mockStatus int
2776+
request *oracle.GetAggregatePriceRequest
2777+
expected oracle.GetAggregatePriceResponse
2778+
expectedError string
2779+
}{
2780+
{
2781+
name: "successful response",
2782+
mockResponse: `{
2783+
"result": {
2784+
"median": "123.45",
2785+
"time": 1234567890
2786+
}
2787+
}`,
2788+
mockStatus: 200,
2789+
request: &oracle.GetAggregatePriceRequest{},
2790+
expected: oracle.GetAggregatePriceResponse{
2791+
Median: "123.45",
2792+
Time: 1234567890,
2793+
},
2794+
},
2795+
{
2796+
name: "error response",
2797+
mockResponse: `{
2798+
"result": {
2799+
"error": "invalidParams",
2800+
"status": "error"
2801+
}
2802+
}`,
2803+
mockStatus: 200,
2804+
request: &oracle.GetAggregatePriceRequest{},
2805+
expectedError: "invalidParams",
2806+
},
2807+
}
2808+
2809+
for _, tt := range tests {
2810+
t.Run(tt.name, func(t *testing.T) {
2811+
mc := testutil.JSONRPCMockClient{}
2812+
mc.DoFunc = testutil.MockResponse(tt.mockResponse, tt.mockStatus, &mc)
2813+
2814+
cfg, err := NewClientConfig("http://testnode/", WithHTTPClient(&mc))
2815+
require.NoError(t, err)
2816+
2817+
client := NewClient(cfg)
2818+
2819+
resp, err := client.Request(tt.request)
2820+
2821+
if tt.expectedError != "" {
2822+
require.Error(t, err)
2823+
require.Contains(t, err.Error(), tt.expectedError)
2824+
return
2825+
}
2826+
2827+
require.NoError(t, err)
2828+
2829+
var priceResp oracle.GetAggregatePriceResponse
2830+
err = resp.GetResult(&priceResp)
2831+
require.NoError(t, err)
2832+
2833+
require.Equal(t, tt.expected, priceResp)
2834+
})
2835+
}
2836+
}
2837+
27702838
func TestClient_Ping(t *testing.T) {
27712839
tests := []struct {
27722840
name string

xrpl/websocket/queries.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"github.com/Peersyst/xrpl-go/xrpl/queries/common"
88
"github.com/Peersyst/xrpl-go/xrpl/queries/ledger"
99
"github.com/Peersyst/xrpl-go/xrpl/queries/nft"
10+
"github.com/Peersyst/xrpl-go/xrpl/queries/oracle"
1011
"github.com/Peersyst/xrpl-go/xrpl/queries/path"
1112
"github.com/Peersyst/xrpl-go/xrpl/queries/server"
1213
"github.com/Peersyst/xrpl-go/xrpl/queries/utility"
@@ -508,6 +509,24 @@ func (c *Client) GetServerState(req *server.StateRequest) (*server.StateResponse
508509
return &lr, nil
509510
}
510511

512+
// Oracle queries
513+
514+
// GetAggregatePrice retrieves the aggregate price of an asset.
515+
// It takes a GetAggregatePriceRequest as input and returns a GetAggregatePriceResponse,
516+
// along with any error encountered.
517+
func (c *Client) GetAggregatePrice(req *oracle.GetAggregatePriceRequest) (*oracle.GetAggregatePriceResponse, error) {
518+
res, err := c.Request(req)
519+
if err != nil {
520+
return nil, err
521+
}
522+
var lr oracle.GetAggregatePriceResponse
523+
err = res.GetResult(&lr)
524+
if err != nil {
525+
return nil, err
526+
}
527+
return &lr, nil
528+
}
529+
511530
// Utility queries
512531

513532
// Ping tests the connection to the server.

0 commit comments

Comments
 (0)