rippled
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 <ripple/beast/unit_test.h>
19 #include <ripple/protocol/Feature.h>
20 #include <ripple/protocol/jss.h>
21 #include <ripple/rpc/impl/RPCHelpers.h>
22 #include <test/jtx.h>
23 #include <test/jtx/WSClient.h>
24 
25 namespace ripple {
26 namespace test {
27 
28 class GatewayBalances_test : public beast::unit_test::suite
29 {
30 public:
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  for (auto apiVersion = RPC::apiMinimumSupportedVersion;
176  apiVersion <= RPC::apiBetaVersion;
177  ++apiVersion)
178  {
179  qry2[jss::api_version] = apiVersion;
180  auto jv = wsc->invoke("gateway_balances", qry2);
181  expect(jv[jss::status] == "error");
182 
183  auto response = jv[jss::result];
184  auto const error =
185  apiVersion < 2u ? "invalidHotWallet" : "invalidParams";
186  BEAST_EXPECT(response[jss::error] == error);
187  }
188  }
189 
190  void
192  {
193  using namespace std::chrono_literals;
194  using namespace jtx;
195  Env env(*this);
196 
197  // Gateway account and assets
198  Account const alice{"alice"};
199  env.fund(XRP(10000), alice);
200  env.close();
201  auto USD = alice["USD"];
202 
203  // The largest valid STAmount of USD:
204  STAmount const maxUSD(
206 
207  // Create a hotwallet
208  Account const hw{"hw"};
209  env.fund(XRP(10000), hw);
210  env(trust(hw, maxUSD));
211  env.close();
212  env(pay(alice, hw, maxUSD));
213 
214  // Create some clients
215  Account const bob{"bob"};
216  env.fund(XRP(10000), bob);
217  env(trust(bob, maxUSD));
218  env.close();
219  env(pay(alice, bob, maxUSD));
220 
221  Account const charley{"charley"};
222  env.fund(XRP(10000), charley);
223  env(trust(charley, maxUSD));
224  env.close();
225  env(pay(alice, charley, maxUSD));
226 
227  env.close();
228 
229  auto wsc = makeWSClient(env.app().config());
230 
231  Json::Value query;
232  query[jss::account] = alice.human();
233  query[jss::hotwallet] = hw.human();
234 
235  // Note that the sum of bob's and charley's USD balances exceeds
236  // the amount that can be represented in an STAmount. Nevertheless
237  // we get a valid "obligations" that shows the maximum valid
238  // STAmount.
239  auto jv = wsc->invoke("gateway_balances", query);
240  expect(jv[jss::status] == "success");
241  expect(jv[jss::result][jss::obligations]["USD"] == maxUSD.getText());
242  }
243 
244  void
245  run() override
246  {
247  using namespace jtx;
248  auto const sa = supported_amendments();
249  for (auto feature : {sa - featureFlowCross, sa})
250  {
251  testGWB(feature);
252  testGWBApiVersions(feature);
253  }
254 
255  testGWBOverflow();
256  }
257 };
258 
259 BEAST_DEFINE_TESTSUITE(GatewayBalances, app, ripple);
260 
261 } // namespace test
262 } // namespace ripple
ripple::test::jtx::XRP
const XRP_t XRP
Converts to XRP Issue or STAmount.
Definition: amount.cpp:105
ripple::test::GatewayBalances_test::run
void run() override
Definition: GatewayBalances_test.cpp:245
ripple::STAmount::getText
std::string getText() const override
Definition: STAmount.cpp:569
ripple::test::jtx::Env::app
Application & app()
Definition: Env.h:242
ripple::test::GatewayBalances_test::testGWB
void testGWB(FeatureBitset features)
Definition: GatewayBalances_test.cpp:32
ripple::RPC::apiBetaVersion
constexpr unsigned int apiBetaVersion
Definition: RPCHelpers.h:244
ripple::Application::config
virtual Config & config()=0
ripple::test::jtx::Env::close
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition: Env.cpp:121
ripple::STAmount
Definition: STAmount.h:46
ripple::test::jtx::supported_amendments
FeatureBitset supported_amendments()
Definition: Env.h:71
ripple::test::GatewayBalances_test::testGWBOverflow
void testGWBOverflow()
Definition: GatewayBalances_test.cpp:191
ripple::RPC::apiMinimumSupportedVersion
constexpr unsigned int apiMinimumSupportedVersion
Definition: RPCHelpers.h:242
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::tfSetFreeze
constexpr std::uint32_t tfSetFreeze
Definition: TxFlags.h:112
ripple::test::jtx::Env::fund
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition: Env.cpp:228
ripple::FeatureBitset
Definition: Feature.h:113
ripple::test::GatewayBalances_test::testGWBApiVersions
void testGWBApiVersions(FeatureBitset features)
Definition: GatewayBalances_test.cpp:156
ripple::test::makeWSClient
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:300
ripple::test::jtx::Account
Immutable cryptographic account descriptor.
Definition: Account.h:37
ripple::test::GatewayBalances_test
Definition: GatewayBalances_test.cpp:28
ripple::STAmount::cMaxOffset
static const int cMaxOffset
Definition: STAmount.h:64
ripple::featureFlowCross
const uint256 featureFlowCross
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:117
ripple::STAmount::cMaxValue
static const std::uint64_t cMaxValue
Definition: STAmount.h:68
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::test::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(DeliverMin, app, ripple)