Skip to content

Commit dbc4da4

Browse files
Merge pull request #97 from Peersyst/xrpl/feat/gateway-balances-request
[TA-3977]: gateway_balances request
2 parents 07353d6 + 45c0c5d commit dbc4da4

File tree

7 files changed

+454
-0
lines changed

7 files changed

+454
-0
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [v0.1.4]
99

10+
### Added
11+
12+
#### xrpl
13+
14+
- Added `GatewayBalances` query.
15+
1016
### Fixed
1117

1218
#### xrpl
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package account
2+
3+
import (
4+
"github.com/Peersyst/xrpl-go/xrpl/queries/common"
5+
"github.com/Peersyst/xrpl-go/xrpl/queries/version"
6+
"github.com/Peersyst/xrpl-go/xrpl/transaction/types"
7+
)
8+
9+
// ############################################################################
10+
// Request
11+
// ############################################################################
12+
13+
// The gateway_balances command calculates the total balances issued by a given
14+
// account, optionally excluding amounts held by operational addresses. Expects
15+
// a response in the form of a GatewayBalancesResponse.
16+
type GatewayBalancesRequest struct {
17+
common.BaseRequest
18+
19+
// The Address to check. This should be the issuing address.
20+
Account types.Address `json:"account"`
21+
// If true, only accept an address or public key for the account parameter.
22+
// Defaults to false.
23+
Strict bool `json:"strict,omitempty"`
24+
// An operational address to exclude from the balances issued, or an array of
25+
// Such addresses.
26+
HotWallet interface{} `json:"hotwallet,omitempty"`
27+
}
28+
29+
func (r *GatewayBalancesRequest) Method() string {
30+
return "gateway_balances"
31+
}
32+
33+
func (r *GatewayBalancesRequest) APIVersion() int {
34+
return version.RippledAPIV2
35+
}
36+
37+
func (r *GatewayBalancesRequest) Validate() error {
38+
return nil
39+
}
40+
41+
// ############################################################################
42+
// Response
43+
// ############################################################################
44+
45+
type GatewayBalance struct {
46+
Currency string `json:"currency"`
47+
Value string `json:"value"`
48+
}
49+
50+
// The expected response from the gateway_balances method.
51+
type GatewayBalancesResponse struct {
52+
// The address of the account that issued the balances.
53+
Account types.Address `json:"account"`
54+
55+
// Total amounts issued to addresses not excluded, as a map of currencies
56+
// to the total value issued.
57+
Obligations map[string]string `json:"obligations,omitempty"`
58+
59+
// Amounts issued to the hotwallet addresses from the request. The keys are
60+
// addresses and the values are arrays of currency amounts they hold.
61+
Balances map[string][]GatewayBalance `json:"balances,omitempty"`
62+
63+
// Total amounts held that are issued by others. In the recommended
64+
// configuration, the issuing address should have none.
65+
Assets map[string][]GatewayBalance `json:"assets,omitempty"`
66+
67+
// The identifying hash of the ledger version that was used to generate
68+
// this response.
69+
LedgerHash common.LedgerHash `json:"ledger_hash,omitempty"`
70+
71+
// The ledger index of the ledger version that was used to generate this
72+
// response.
73+
LedgerCurrentIndex common.LedgerIndex `json:"ledger_current_index,omitempty"`
74+
75+
// The ledger index of the current in-progress ledger version, which was
76+
// used to retrieve this information.
77+
LedgerIndex common.LedgerIndex `json:"ledger_index,omitempty"`
78+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package account
2+
3+
import (
4+
"testing"
5+
6+
"github.com/Peersyst/xrpl-go/xrpl/testutil"
7+
)
8+
9+
func TestGatewayBalancesRequest(t *testing.T) {
10+
s := GatewayBalancesRequest{
11+
Account: "rLHmBn4fT92w4F6ViyYbjoizLTo83tHTHu",
12+
Strict: true,
13+
HotWallet: []string{"rLHmBn4fT92w4F6ViyYbjoizLTo83tHTHu"},
14+
}
15+
16+
j := `{
17+
"account": "rLHmBn4fT92w4F6ViyYbjoizLTo83tHTHu",
18+
"strict": true,
19+
"hotwallet": [
20+
"rLHmBn4fT92w4F6ViyYbjoizLTo83tHTHu"
21+
]
22+
}`
23+
if err := testutil.Serialize(t, s, j); err != nil {
24+
t.Error(err)
25+
}
26+
}
27+
28+
func TestGatewayBalancesResponse(t *testing.T) {
29+
s := GatewayBalancesResponse{
30+
Account: "rLHmBn4fT92w4F6ViyYbjoizLTo83tHTHu",
31+
Obligations: map[string]string{
32+
"USD": "100",
33+
"EUR": "200",
34+
},
35+
Balances: map[string][]GatewayBalance{
36+
"rLHmBn4fT92w4F6ViyYbjoizLTo83tHTHu": {
37+
{
38+
Currency: "USD",
39+
Value: "50",
40+
},
41+
{
42+
Currency: "EUR",
43+
Value: "100",
44+
},
45+
},
46+
},
47+
Assets: map[string][]GatewayBalance{
48+
"rLHmBn4fT92w4F6ViyYbjoizLTo83tHTHu": {
49+
{
50+
Currency: "USD",
51+
Value: "25",
52+
},
53+
},
54+
},
55+
LedgerHash: "ABC123",
56+
LedgerCurrentIndex: 54321,
57+
LedgerIndex: 12345,
58+
}
59+
60+
j := `{
61+
"account": "rLHmBn4fT92w4F6ViyYbjoizLTo83tHTHu",
62+
"obligations": {
63+
"EUR": "200",
64+
"USD": "100"
65+
},
66+
"balances": {
67+
"rLHmBn4fT92w4F6ViyYbjoizLTo83tHTHu": [
68+
{
69+
"currency": "USD",
70+
"value": "50"
71+
},
72+
{
73+
"currency": "EUR",
74+
"value": "100"
75+
}
76+
]
77+
},
78+
"assets": {
79+
"rLHmBn4fT92w4F6ViyYbjoizLTo83tHTHu": [
80+
{
81+
"currency": "USD",
82+
"value": "25"
83+
}
84+
]
85+
},
86+
"ledger_hash": "ABC123",
87+
"ledger_current_index": 54321,
88+
"ledger_index": 12345
89+
}`
90+
if err := testutil.Serialize(t, s, j); err != nil {
91+
t.Error(err)
92+
}
93+
}

xrpl/rpc/queries.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,22 @@ func (c *Client) GetAccountTransactions(req *account.TransactionsRequest) (*acco
158158
return &acr, nil
159159
}
160160

161+
// GetGatewayBalances retrieves the gateway balances for an account.
162+
// It takes a GatewayBalancesRequest as input and returns a GatewayBalancesResponse,
163+
// along with any error encountered.
164+
func (c *Client) GetGatewayBalances(req *account.GatewayBalancesRequest) (*account.GatewayBalancesResponse, error) {
165+
res, err := c.Request(req)
166+
if err != nil {
167+
return nil, err
168+
}
169+
var acr account.GatewayBalancesResponse
170+
err = res.GetResult(&acr)
171+
if err != nil {
172+
return nil, err
173+
}
174+
return &acr, nil
175+
}
176+
161177
// Channel queries
162178

163179
// GetChannelVerify verifies the signature of a payment channel claim.

xrpl/rpc/queries_test.go

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -866,6 +866,132 @@ func TestClient_GetAccountTransactions(t *testing.T) {
866866
}
867867
}
868868

869+
func TestClient_GetGatewayBalances(t *testing.T) {
870+
tests := []struct {
871+
name string
872+
mockResponse string
873+
mockStatus int
874+
request *account.GatewayBalancesRequest
875+
expected account.GatewayBalancesResponse
876+
expectedError string
877+
}{
878+
{
879+
name: "successful response",
880+
mockResponse: `{
881+
"result": {
882+
"account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
883+
"assets": {
884+
"r9F6wk8HkXrgYWoJ7fsv4VrUBVoqDVtzkH": [
885+
{
886+
"currency": "BTC",
887+
"value": "5444166510000000e-26"
888+
}
889+
]
890+
},
891+
"balances": {
892+
"rKm4uWpg9tfwbVSeATv4KxDe6mpE9yPkgJ": [
893+
{
894+
"currency": "EUR",
895+
"value": "29826.1965999999"
896+
}
897+
],
898+
"ra7JkEzrgeKHdzKgo4EUUVBnxggY4z37kt": [
899+
{
900+
"currency": "USD",
901+
"value": "13857.70416"
902+
}
903+
]
904+
},
905+
"ledger_hash": "61DDBF304AF6E8101576BF161D447CA8E4F0170DDFBEAFFD993DC9383D443388",
906+
"ledger_index": 14483212,
907+
"obligations": {
908+
"EUR": "5599.716599999999",
909+
"USD": "12345.9"
910+
},
911+
"status": "success"
912+
}
913+
}`,
914+
mockStatus: 200,
915+
request: &account.GatewayBalancesRequest{
916+
Account: "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
917+
},
918+
expected: account.GatewayBalancesResponse{
919+
Account: "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
920+
Assets: map[string][]account.GatewayBalance{
921+
"r9F6wk8HkXrgYWoJ7fsv4VrUBVoqDVtzkH": {
922+
{
923+
Currency: "BTC",
924+
Value: "5444166510000000e-26",
925+
},
926+
},
927+
},
928+
Balances: map[string][]account.GatewayBalance{
929+
"rKm4uWpg9tfwbVSeATv4KxDe6mpE9yPkgJ": {
930+
{
931+
Currency: "EUR",
932+
Value: "29826.1965999999",
933+
},
934+
},
935+
"ra7JkEzrgeKHdzKgo4EUUVBnxggY4z37kt": {
936+
{
937+
Currency: "USD",
938+
Value: "13857.70416",
939+
},
940+
},
941+
},
942+
LedgerHash: "61DDBF304AF6E8101576BF161D447CA8E4F0170DDFBEAFFD993DC9383D443388",
943+
LedgerIndex: 14483212,
944+
Obligations: map[string]string{
945+
"EUR": "5599.716599999999",
946+
"USD": "12345.9",
947+
},
948+
},
949+
},
950+
{
951+
name: "error response",
952+
mockResponse: `{
953+
"result": {
954+
"error": "actNotFound",
955+
"status": "error"
956+
}
957+
}`,
958+
mockStatus: 200,
959+
request: &account.GatewayBalancesRequest{
960+
Account: "rInvalidAccount",
961+
},
962+
expectedError: "actNotFound",
963+
},
964+
}
965+
966+
for _, tt := range tests {
967+
t.Run(tt.name, func(t *testing.T) {
968+
mc := testutil.JSONRPCMockClient{}
969+
mc.DoFunc = testutil.MockResponse(tt.mockResponse, tt.mockStatus, &mc)
970+
971+
cfg, err := NewClientConfig("http://testnode/", WithHTTPClient(&mc))
972+
require.NoError(t, err)
973+
974+
client := NewClient(cfg)
975+
976+
resp, err := client.Request(tt.request)
977+
978+
if tt.expectedError != "" {
979+
require.Error(t, err)
980+
require.Contains(t, err.Error(), tt.expectedError)
981+
return
982+
}
983+
984+
require.NoError(t, err)
985+
986+
var gatewayBalancesResp account.GatewayBalancesResponse
987+
err = resp.GetResult(&gatewayBalancesResp)
988+
require.NoError(t, err)
989+
990+
require.Equal(t, tt.expected, gatewayBalancesResp)
991+
})
992+
}
993+
}
994+
869995
func TestClient_GetChannelVerify(t *testing.T) {
870996
tests := []struct {
871997
name string

xrpl/websocket/queries.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,22 @@ func (c *Client) GetAccountTransactions(req *account.TransactionsRequest) (*acco
162162
return &acr, nil
163163
}
164164

165+
// GetGatewayBalances retrieves the gateway balances for an account.
166+
// It takes a GatewayBalancesRequest as input and returns a GatewayBalancesResponse,
167+
// along with any error encountered.
168+
func (c *Client) GetGatewayBalances(req *account.GatewayBalancesRequest) (*account.GatewayBalancesResponse, error) {
169+
res, err := c.Request(req)
170+
if err != nil {
171+
return nil, err
172+
}
173+
var acr account.GatewayBalancesResponse
174+
err = res.GetResult(&acr)
175+
if err != nil {
176+
return nil, err
177+
}
178+
return &acr, nil
179+
}
180+
165181
// Channel queries
166182

167183
// GetChannelVerify verifies the signature of a payment channel claim.

0 commit comments

Comments
 (0)