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#include <xrpld/rpc/detail/RPCHelpers.h>
21#include <xrpl/beast/unit_test.h>
22#include <xrpl/protocol/Feature.h>
23#include <xrpl/protocol/jss.h>
24
25namespace ripple {
26namespace test {
27
29{
30public:
31 void
33 {
34 using namespace std::chrono_literals;
35 using namespace jtx;
36 Env env(*this, features);
37
38 {
39 // Gateway account and assets
40 Account const alice{"alice"};
41 env.fund(XRP(10000), "alice");
42 auto USD = alice["USD"];
43 auto CNY = alice["CNY"];
44 auto JPY = alice["JPY"];
45
46 // Create a hotwallet
47 Account const hw{"hw"};
48 env.fund(XRP(10000), "hw");
49 env(trust(hw, USD(10000)));
50 env(trust(hw, JPY(10000)));
51 env(pay(alice, hw, USD(5000)));
52 env(pay(alice, hw, JPY(5000)));
53
54 // Create some clients
55 Account const bob{"bob"};
56 env.fund(XRP(10000), "bob");
57 env(trust(bob, USD(100)));
58 env(trust(bob, CNY(100)));
59 env(pay(alice, bob, USD(50)));
60
61 Account const charley{"charley"};
62 env.fund(XRP(10000), "charley");
63 env(trust(charley, CNY(500)));
64 env(trust(charley, JPY(500)));
65 env(pay(alice, charley, CNY(250)));
66 env(pay(alice, charley, JPY(250)));
67
68 Account const dave{"dave"};
69 env.fund(XRP(10000), "dave");
70 env(trust(dave, CNY(100)));
71 env(pay(alice, dave, CNY(30)));
72
73 // give the gateway an asset
74 env(trust(alice, charley["USD"](50)));
75 env(pay(charley, alice, USD(10)));
76
77 // freeze dave
78 env(trust(alice, dave["CNY"](0), dave, tfSetFreeze));
79
80 env.close();
81
82 auto wsc = makeWSClient(env.app().config());
83
84 Json::Value qry;
85 qry[jss::account] = alice.human();
86 qry[jss::hotwallet] = hw.human();
87
88 auto jv = wsc->invoke("gateway_balances", qry);
89 expect(jv[jss::status] == "success");
90 if (wsc->version() == 2)
91 {
92 expect(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
93 expect(
94 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
95 expect(jv.isMember(jss::id) && jv[jss::id] == 5);
96 }
97
98 auto const& result = jv[jss::result];
99 expect(result[jss::account] == alice.human());
100 expect(result[jss::status] == "success");
101
102 {
103 auto const& balances = result[jss::balances];
104 expect(balances.isObject(), "balances is not an object");
105 expect(balances.size() == 1, "balances size is not 1");
106
107 auto const& hwBalance = balances[hw.human()];
108 expect(hwBalance.isArray(), "hwBalance is not an array");
109 expect(hwBalance.size() == 2);
110 auto c1 = hwBalance[0u][jss::currency];
111 auto c2 = hwBalance[1u][jss::currency];
112 expect(c1 == "USD" || c2 == "USD");
113 expect(c1 == "JPY" || c2 == "JPY");
114 expect(
115 hwBalance[0u][jss::value] == "5000" &&
116 hwBalance[1u][jss::value] == "5000");
117 }
118
119 {
120 auto const& fBalances = result[jss::frozen_balances];
121 expect(fBalances.isObject());
122 expect(fBalances.size() == 1);
123
124 auto const& fBal = fBalances[dave.human()];
125 expect(fBal.isArray());
126 expect(fBal.size() == 1);
127 expect(fBal[0u].isObject());
128 expect(fBal[0u][jss::currency] == "CNY");
129 expect(fBal[0u][jss::value] == "30");
130 }
131
132 {
133 auto const& assets = result[jss::assets];
134 expect(assets.isObject(), "assets it not an object");
135 expect(assets.size() == 1, "assets size is not 1");
136
137 auto const& cAssets = assets[charley.human()];
138 expect(cAssets.isArray());
139 expect(cAssets.size() == 1);
140 expect(cAssets[0u][jss::currency] == "USD");
141 expect(cAssets[0u][jss::value] == "10");
142 }
143
144 {
145 auto const& obligations = result[jss::obligations];
146 expect(obligations.isObject(), "obligations is not an object");
147 expect(obligations.size() == 3);
148 expect(obligations["CNY"] == "250");
149 expect(obligations["JPY"] == "250");
150 expect(obligations["USD"] == "50");
151 }
152 }
153 }
154
155 void
157 {
158 using namespace std::chrono_literals;
159 using namespace jtx;
160 Env env(*this, features);
161
162 // Gateway account and assets
163 Account const alice{"alice"};
164 env.fund(XRP(10000), alice);
165 Account const hw{"hw"};
166 env.fund(XRP(10000), hw);
167 env.close();
168
169 auto wsc = makeWSClient(env.app().config());
170
171 Json::Value qry2;
172 qry2[jss::account] = alice.human();
173 qry2[jss::hotwallet] = "asdf";
174
175 forAllApiVersions([&, this](unsigned apiVersion) {
176 qry2[jss::api_version] = apiVersion;
177 auto jv = wsc->invoke("gateway_balances", qry2);
178 expect(jv[jss::status] == "error");
179
180 auto response = jv[jss::result];
181 auto const error =
182 apiVersion < 2u ? "invalidHotWallet" : "invalidParams";
183 BEAST_EXPECT(response[jss::error] == error);
184 });
185 }
186
187 void
189 {
190 using namespace std::chrono_literals;
191 using namespace jtx;
192 Env env(*this);
193
194 // Gateway account and assets
195 Account const alice{"alice"};
196 env.fund(XRP(10000), alice);
197 env.close();
198 auto USD = alice["USD"];
199
200 // The largest valid STAmount of USD:
201 STAmount const maxUSD(
203
204 // Create a hotwallet
205 Account const hw{"hw"};
206 env.fund(XRP(10000), hw);
207 env(trust(hw, maxUSD));
208 env.close();
209 env(pay(alice, hw, maxUSD));
210
211 // Create some clients
212 Account const bob{"bob"};
213 env.fund(XRP(10000), bob);
214 env(trust(bob, maxUSD));
215 env.close();
216 env(pay(alice, bob, maxUSD));
217
218 Account const charley{"charley"};
219 env.fund(XRP(10000), charley);
220 env(trust(charley, maxUSD));
221 env.close();
222 env(pay(alice, charley, maxUSD));
223
224 env.close();
225
226 auto wsc = makeWSClient(env.app().config());
227
228 Json::Value query;
229 query[jss::account] = alice.human();
230 query[jss::hotwallet] = hw.human();
231
232 // Note that the sum of bob's and charley's USD balances exceeds
233 // the amount that can be represented in an STAmount. Nevertheless
234 // we get a valid "obligations" that shows the maximum valid
235 // STAmount.
236 auto jv = wsc->invoke("gateway_balances", query);
237 expect(jv[jss::status] == "success");
238 expect(jv[jss::result][jss::obligations]["USD"] == maxUSD.getText());
239 }
240
241 void
242 run() override
243 {
244 using namespace jtx;
245 auto const sa = supported_amendments();
246 for (auto feature : {sa - featureFlowCross, sa})
247 {
248 testGWB(feature);
249 testGWBApiVersions(feature);
250 }
251
253 }
254};
255
256BEAST_DEFINE_TESTSUITE(GatewayBalances, app, ripple);
257
258} // namespace test
259} // namespace ripple
Represents a JSON value.
Definition: json_value.h:148
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 const int cMaxOffset
Definition: STAmount.h:66
std::string getText() const override
Definition: STAmount.cpp:547
static const std::uint64_t cMaxValue
Definition: STAmount.h:70
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:118
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition: Env.cpp:115
Application & app()
Definition: Env.h:256
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition: Env.cpp:231
Json::Value trust(Account const &account, STAmount const &amount, std::uint32_t flags)
Modify a trust line.
Definition: trust.cpp:31
Json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
Definition: pay.cpp:29
XRP_t const XRP
Converts to XRP Issue or STAmount.
Definition: amount.cpp:104
FeatureBitset supported_amendments()
Definition: Env.h:71
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:301
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:115