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 <test/jtx.h>
22 #include <test/jtx/WSClient.h>
23 
24 namespace ripple {
25 namespace test {
26 
27 class GatewayBalances_test : public beast::unit_test::suite
28 {
29 public:
30  void
32  {
33  using namespace std::chrono_literals;
34  using namespace jtx;
35  Env env(*this, features);
36 
37  // Gateway account and assets
38  Account const alice{"alice"};
39  env.fund(XRP(10000), "alice");
40  auto USD = alice["USD"];
41  auto CNY = alice["CNY"];
42  auto JPY = alice["JPY"];
43 
44  // Create a hotwallet
45  Account const hw{"hw"};
46  env.fund(XRP(10000), "hw");
47  env(trust(hw, USD(10000)));
48  env(trust(hw, JPY(10000)));
49  env(pay(alice, hw, USD(5000)));
50  env(pay(alice, hw, JPY(5000)));
51 
52  // Create some clients
53  Account const bob{"bob"};
54  env.fund(XRP(10000), "bob");
55  env(trust(bob, USD(100)));
56  env(trust(bob, CNY(100)));
57  env(pay(alice, bob, USD(50)));
58 
59  Account const charley{"charley"};
60  env.fund(XRP(10000), "charley");
61  env(trust(charley, CNY(500)));
62  env(trust(charley, JPY(500)));
63  env(pay(alice, charley, CNY(250)));
64  env(pay(alice, charley, JPY(250)));
65 
66  Account const dave{"dave"};
67  env.fund(XRP(10000), "dave");
68  env(trust(dave, CNY(100)));
69  env(pay(alice, dave, CNY(30)));
70 
71  // give the gateway an asset
72  env(trust(alice, charley["USD"](50)));
73  env(pay(charley, alice, USD(10)));
74 
75  // freeze dave
76  env(trust(alice, dave["CNY"](0), dave, tfSetFreeze));
77 
78  env.close();
79 
80  auto wsc = makeWSClient(env.app().config());
81 
82  Json::Value qry;
83  qry[jss::account] = alice.human();
84  qry[jss::hotwallet] = hw.human();
85 
86  auto jv = wsc->invoke("gateway_balances", qry);
87  expect(jv[jss::status] == "success");
88  if (wsc->version() == 2)
89  {
90  expect(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
91  expect(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
92  expect(jv.isMember(jss::id) && jv[jss::id] == 5);
93  }
94 
95  auto const& result = jv[jss::result];
96  expect(result[jss::account] == alice.human());
97  expect(result[jss::status] == "success");
98 
99  {
100  auto const& balances = result[jss::balances];
101  expect(balances.isObject(), "balances is not an object");
102  expect(balances.size() == 1, "balances size is not 1");
103 
104  auto const& hwBalance = balances[hw.human()];
105  expect(hwBalance.isArray(), "hwBalance is not an array");
106  expect(hwBalance.size() == 2);
107  auto c1 = hwBalance[0u][jss::currency];
108  auto c2 = hwBalance[1u][jss::currency];
109  expect(c1 == "USD" || c2 == "USD");
110  expect(c1 == "JPY" || c2 == "JPY");
111  expect(
112  hwBalance[0u][jss::value] == "5000" &&
113  hwBalance[1u][jss::value] == "5000");
114  }
115 
116  {
117  auto const& fBalances = result[jss::frozen_balances];
118  expect(fBalances.isObject());
119  expect(fBalances.size() == 1);
120 
121  auto const& fBal = fBalances[dave.human()];
122  expect(fBal.isArray());
123  expect(fBal.size() == 1);
124  expect(fBal[0u].isObject());
125  expect(fBal[0u][jss::currency] == "CNY");
126  expect(fBal[0u][jss::value] == "30");
127  }
128 
129  {
130  auto const& assets = result[jss::assets];
131  expect(assets.isObject(), "assets it not an object");
132  expect(assets.size() == 1, "assets size is not 1");
133 
134  auto const& cAssets = assets[charley.human()];
135  expect(cAssets.isArray());
136  expect(cAssets.size() == 1);
137  expect(cAssets[0u][jss::currency] == "USD");
138  expect(cAssets[0u][jss::value] == "10");
139  }
140 
141  {
142  auto const& obligations = result[jss::obligations];
143  expect(obligations.isObject(), "obligations is not an object");
144  expect(obligations.size() == 3);
145  expect(obligations["CNY"] == "250");
146  expect(obligations["JPY"] == "250");
147  expect(obligations["USD"] == "50");
148  }
149  }
150 
151  void
153  {
154  using namespace std::chrono_literals;
155  using namespace jtx;
156  Env env(*this);
157 
158  // Gateway account and assets
159  Account const alice{"alice"};
160  env.fund(XRP(10000), alice);
161  env.close();
162  auto USD = alice["USD"];
163 
164  // The largest valid STAmount of USD:
165  STAmount const maxUSD(
167 
168  // Create a hotwallet
169  Account const hw{"hw"};
170  env.fund(XRP(10000), hw);
171  env(trust(hw, maxUSD));
172  env.close();
173  env(pay(alice, hw, maxUSD));
174 
175  // Create some clients
176  Account const bob{"bob"};
177  env.fund(XRP(10000), bob);
178  env(trust(bob, maxUSD));
179  env.close();
180  env(pay(alice, bob, maxUSD));
181 
182  Account const charley{"charley"};
183  env.fund(XRP(10000), charley);
184  env(trust(charley, maxUSD));
185  env.close();
186  env(pay(alice, charley, maxUSD));
187 
188  env.close();
189 
190  auto wsc = makeWSClient(env.app().config());
191 
192  Json::Value query;
193  query[jss::account] = alice.human();
194  query[jss::hotwallet] = hw.human();
195 
196  // Note that the sum of bob's and charley's USD balances exceeds
197  // the amount that can be represented in an STAmount. Nevertheless
198  // we get a valid "obligations" that shows the maximum valid
199  // STAmount.
200  auto jv = wsc->invoke("gateway_balances", query);
201  expect(jv[jss::status] == "success");
202  expect(jv[jss::result][jss::obligations]["USD"] == maxUSD.getText());
203  }
204 
205  void
206  run() override
207  {
208  using namespace jtx;
209  auto const sa = supported_amendments();
211  testGWB(sa);
212 
213  testGWBOverflow();
214  }
215 };
216 
217 BEAST_DEFINE_TESTSUITE(GatewayBalances, app, ripple);
218 
219 } // namespace test
220 } // 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:206
ripple::test::jtx::trust
Json::Value trust(Account const &account, STAmount const &amount, std::uint32_t flags)
Modify a trust line.
Definition: trust.cpp:30
ripple::STAmount::getText
std::string getText() const override
Definition: STAmount.cpp:571
ripple::test::jtx::Env::app
Application & app()
Definition: Env.h:241
ripple::test::GatewayBalances_test::testGWB
void testGWB(FeatureBitset features)
Definition: GatewayBalances_test.cpp:31
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:45
ripple::test::jtx::supported_amendments
FeatureBitset supported_amendments()
Definition: Env.h:70
ripple::test::GatewayBalances_test::testGWBOverflow
void testGWBOverflow()
Definition: GatewayBalances_test.cpp:152
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:111
ripple::test::jtx::pay
Json::Value pay(Account const &account, Account const &to, AnyAmount amount)
Create a payment.
Definition: pay.cpp:29
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::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:27
ripple::STAmount::cMaxOffset
static const int cMaxOffset
Definition: STAmount.h:63
ripple::featureFlowCross
const uint256 featureFlowCross
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:116
ripple::STAmount::cMaxValue
static const std::uint64_t cMaxValue
Definition: STAmount.h:67
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::test::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(DeliverMin, app, ripple)