rippled
Loading...
Searching...
No Matches
GatewayBalances_test.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012, 2013 Ripple Labs Inc.
5 Permission to use, copy, modify, and/or distribute this software for any
6 purpose with or without fee is hereby granted, provided that the above
7 copyright notice and this permission notice appear in all copies.
8 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15*/
16//==============================================================================
17
18#include <test/jtx.h>
19#include <test/jtx/WSClient.h>
20
21#include <xrpld/rpc/detail/RPCHelpers.h>
22
23#include <xrpl/beast/unit_test.h>
24#include <xrpl/protocol/Feature.h>
25#include <xrpl/protocol/jss.h>
26
27namespace ripple {
28namespace test {
29
31{
32public:
33 void
35 {
36 using namespace std::chrono_literals;
37 using namespace jtx;
38 Env env(*this, features);
39
40 {
41 // Gateway account and assets
42 Account const alice{"alice"};
43 env.fund(XRP(10000), "alice");
44 auto USD = alice["USD"];
45 auto CNY = alice["CNY"];
46 auto JPY = alice["JPY"];
47
48 // Create a hotwallet
49 Account const hw{"hw"};
50 env.fund(XRP(10000), "hw");
51 env.close();
52 env(trust(hw, USD(10000)));
53 env(trust(hw, JPY(10000)));
54 env(pay(alice, hw, USD(5000)));
55 env(pay(alice, hw, JPY(5000)));
56
57 // Create some clients
58 Account const bob{"bob"};
59 env.fund(XRP(10000), "bob");
60 env.close();
61 env(trust(bob, USD(100)));
62 env(trust(bob, CNY(100)));
63 env(pay(alice, bob, USD(50)));
64
65 Account const charley{"charley"};
66 env.fund(XRP(10000), "charley");
67 env.close();
68 env(trust(charley, CNY(500)));
69 env(trust(charley, JPY(500)));
70 env(pay(alice, charley, CNY(250)));
71 env(pay(alice, charley, JPY(250)));
72
73 Account const dave{"dave"};
74 env.fund(XRP(10000), "dave");
75 env.close();
76 env(trust(dave, CNY(100)));
77 env(pay(alice, dave, CNY(30)));
78
79 // give the gateway an asset
80 env(trust(alice, charley["USD"](50)));
81 env(pay(charley, alice, USD(10)));
82
83 // freeze dave
84 env(trust(alice, dave["CNY"](0), dave, tfSetFreeze));
85
86 env.close();
87
88 auto wsc = makeWSClient(env.app().config());
89
90 Json::Value qry;
91 qry[jss::account] = alice.human();
92 qry[jss::hotwallet] = hw.human();
93
94 auto jv = wsc->invoke("gateway_balances", qry);
95 expect(jv[jss::status] == "success");
96 if (wsc->version() == 2)
97 {
98 expect(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
99 expect(
100 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
101 expect(jv.isMember(jss::id) && jv[jss::id] == 5);
102 }
103
104 auto const& result = jv[jss::result];
105 expect(result[jss::account] == alice.human());
106 expect(result[jss::status] == "success");
107
108 {
109 auto const& balances = result[jss::balances];
110 expect(balances.isObject(), "balances is not an object");
111 expect(balances.size() == 1, "balances size is not 1");
112
113 auto const& hwBalance = balances[hw.human()];
114 expect(hwBalance.isArray(), "hwBalance is not an array");
115 expect(hwBalance.size() == 2);
116 auto c1 = hwBalance[0u][jss::currency];
117 auto c2 = hwBalance[1u][jss::currency];
118 expect(c1 == "USD" || c2 == "USD");
119 expect(c1 == "JPY" || c2 == "JPY");
120 expect(
121 hwBalance[0u][jss::value] == "5000" &&
122 hwBalance[1u][jss::value] == "5000");
123 }
124
125 {
126 auto const& fBalances = result[jss::frozen_balances];
127 expect(fBalances.isObject());
128 expect(fBalances.size() == 1);
129
130 auto const& fBal = fBalances[dave.human()];
131 expect(fBal.isArray());
132 expect(fBal.size() == 1);
133 expect(fBal[0u].isObject());
134 expect(fBal[0u][jss::currency] == "CNY");
135 expect(fBal[0u][jss::value] == "30");
136 }
137
138 {
139 auto const& assets = result[jss::assets];
140 expect(assets.isObject(), "assets it not an object");
141 expect(assets.size() == 1, "assets size is not 1");
142
143 auto const& cAssets = assets[charley.human()];
144 expect(cAssets.isArray());
145 expect(cAssets.size() == 1);
146 expect(cAssets[0u][jss::currency] == "USD");
147 expect(cAssets[0u][jss::value] == "10");
148 }
149
150 {
151 auto const& obligations = result[jss::obligations];
152 expect(obligations.isObject(), "obligations is not an object");
153 expect(obligations.size() == 3);
154 expect(obligations["CNY"] == "250");
155 expect(obligations["JPY"] == "250");
156 expect(obligations["USD"] == "50");
157 }
158 }
159 }
160
161 void
163 {
164 using namespace std::chrono_literals;
165 using namespace jtx;
166 Env env(*this, features);
167
168 // Gateway account and assets
169 Account const alice{"alice"};
170 env.fund(XRP(10000), alice);
171 Account const hw{"hw"};
172 env.fund(XRP(10000), hw);
173 env.close();
174
175 auto wsc = makeWSClient(env.app().config());
176
177 Json::Value qry2;
178 qry2[jss::account] = alice.human();
179 qry2[jss::hotwallet] = "asdf";
180
181 forAllApiVersions([&, this](unsigned apiVersion) {
182 qry2[jss::api_version] = apiVersion;
183 auto jv = wsc->invoke("gateway_balances", qry2);
184 expect(jv[jss::status] == "error");
185
186 auto response = jv[jss::result];
187 auto const error =
188 apiVersion < 2u ? "invalidHotWallet" : "invalidParams";
189 BEAST_EXPECT(response[jss::error] == error);
190 });
191 }
192
193 void
195 {
196 using namespace std::chrono_literals;
197 using namespace jtx;
198 Env env(*this);
199
200 // Gateway account and assets
201 Account const alice{"alice"};
202 env.fund(XRP(10000), alice);
203 env.close();
204 auto USD = alice["USD"];
205
206 // The largest valid STAmount of USD:
207 STAmount const maxUSD(
209
210 // Create a hotwallet
211 Account const hw{"hw"};
212 env.fund(XRP(10000), hw);
213 env.close();
214 env(trust(hw, maxUSD));
215 env.close();
216 env(pay(alice, hw, maxUSD));
217
218 // Create some clients
219 Account const bob{"bob"};
220 env.fund(XRP(10000), bob);
221 env.close();
222 env(trust(bob, maxUSD));
223 env.close();
224 env(pay(alice, bob, maxUSD));
225
226 Account const charley{"charley"};
227 env.fund(XRP(10000), charley);
228 env.close();
229 env(trust(charley, maxUSD));
230 env.close();
231 env(pay(alice, charley, maxUSD));
232
233 env.close();
234
235 auto wsc = makeWSClient(env.app().config());
236
237 Json::Value query;
238 query[jss::account] = alice.human();
239 query[jss::hotwallet] = hw.human();
240
241 // Note that the sum of bob's and charley's USD balances exceeds
242 // the amount that can be represented in an STAmount. Nevertheless
243 // we get a valid "obligations" that shows the maximum valid
244 // STAmount.
245 auto jv = wsc->invoke("gateway_balances", query);
246 expect(jv[jss::status] == "success");
247 expect(jv[jss::result][jss::obligations]["USD"] == maxUSD.getText());
248 }
249
250 void
251 run() override
252 {
253 using namespace jtx;
254 auto const sa = supported_amendments();
255 for (auto feature :
256 {sa - featureFlowCross - featurePermissionedDEX,
257 sa - featurePermissionedDEX,
258 sa})
259 {
260 testGWB(feature);
261 testGWBApiVersions(feature);
262 }
263
265 }
266};
267
268BEAST_DEFINE_TESTSUITE(GatewayBalances, app, ripple);
269
270} // namespace test
271} // namespace ripple
Represents a JSON value.
Definition: json_value.h:150
A testsuite class.
Definition: suite.h:55
bool expect(Condition const &shouldBeTrue)
Evaluate a test condition.
Definition: suite.h:229
virtual Config & config()=0
static int const cMaxOffset
Definition: STAmount.h:66
static std::uint64_t const cMaxValue
Definition: STAmount.h:70
std::string getText() const override
Definition: STAmount.cpp:706
void testGWBApiVersions(FeatureBitset features)
void run() override
Runs the suite.
void testGWB(FeatureBitset features)
Immutable cryptographic account descriptor.
Definition: Account.h:39
A transaction testing environment.
Definition: Env.h:121
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition: Env.cpp:117
Application & app()
Definition: Env.h:261
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition: Env.cpp:275
Json::Value trust(Account const &account, STAmount const &amount, std::uint32_t flags)
Modify a trust line.
Definition: trust.cpp:32
Json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
Definition: pay.cpp:30
XRP_t const XRP
Converts to XRP Issue or STAmount.
Definition: amount.cpp:105
FeatureBitset supported_amendments()
Definition: Env.h:74
std::unique_ptr< WSClient > makeWSClient(Config const &cfg, bool v2, unsigned rpc_version, std::unordered_map< std::string, std::string > const &headers)
Returns a client operating through WebSockets/S.
Definition: WSClient.cpp:302
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
void forAllApiVersions(Fn const &fn, Args &&... args)
Definition: ApiVersion.h:102
constexpr std::uint32_t tfSetFreeze
Definition: TxFlags.h:118