xrpld
Loading...
Searching...
No Matches
GatewayBalances_test.cpp
1#include <test/jtx/Account.h>
2#include <test/jtx/Env.h>
3#include <test/jtx/WSClient.h>
4#include <test/jtx/amount.h>
5#include <test/jtx/escrow.h>
6#include <test/jtx/mpt.h>
7#include <test/jtx/pay.h>
8#include <test/jtx/trust.h>
9
10#include <xrpl/beast/unit_test/suite.h>
11#include <xrpl/json/json_value.h>
12#include <xrpl/protocol/ApiVersion.h>
13#include <xrpl/protocol/Feature.h>
14#include <xrpl/protocol/STAmount.h>
15#include <xrpl/protocol/TxFlags.h>
16#include <xrpl/protocol/jss.h>
17
18namespace xrpl::test {
19
21{
22public:
23 void
25 {
26 using namespace std::chrono_literals;
27 using namespace jtx;
28 Env env(*this, features);
29
30 {
31 // Gateway account and assets
32 Account const alice{"alice"};
33 env.fund(XRP(10000), "alice");
34 auto usd = alice["USD"];
35 auto cny = alice["CNY"];
36 auto jpy = alice["JPY"];
37
38 // Create a hotwallet
39 Account const hw{"hw"};
40 env.fund(XRP(10000), "hw");
41 env.close();
42 env(trust(hw, usd(10000)));
43 env(trust(hw, jpy(10000)));
44 env(pay(alice, hw, usd(5000)));
45 env(pay(alice, hw, jpy(5000)));
46
47 // Create some clients
48 Account const bob{"bob"};
49 env.fund(XRP(10000), "bob");
50 env.close();
51 env(trust(bob, usd(100)));
52 env(trust(bob, cny(100)));
53 env(pay(alice, bob, usd(50)));
54
55 Account const charley{"charley"};
56 env.fund(XRP(10000), "charley");
57 env.close();
58 env(trust(charley, cny(500)));
59 env(trust(charley, jpy(500)));
60 env(pay(alice, charley, cny(250)));
61 env(pay(alice, charley, jpy(250)));
62
63 Account const dave{"dave"};
64 env.fund(XRP(10000), "dave");
65 env.close();
66 env(trust(dave, cny(100)));
67 env(pay(alice, dave, cny(30)));
68
69 // give the gateway an asset
70 env(trust(alice, charley["USD"](50)));
71 env(pay(charley, alice, usd(10)));
72
73 // freeze dave
74 env(trust(alice, dave["CNY"](0), dave, tfSetFreeze));
75
76 env.close();
77
78 auto wsc = makeWSClient(env.app().config());
79
80 json::Value qry;
81 qry[jss::account] = alice.human();
82 qry[jss::hotwallet] = hw.human();
83
84 auto jv = wsc->invoke("gateway_balances", qry);
85 expect(jv[jss::status] == "success");
86 if (wsc->version() == 2)
87 {
88 expect(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
89 expect(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
90 expect(jv.isMember(jss::id) && jv[jss::id] == 5);
91 }
92
93 auto const& result = jv[jss::result];
94 expect(result[jss::account] == alice.human());
95 expect(result[jss::status] == "success");
96
97 {
98 auto const& balances = result[jss::balances];
99 expect(balances.isObject(), "balances is not an object");
100 expect(balances.size() == 1, "balances size is not 1");
101
102 auto const& hwBalance = balances[hw.human()];
103 expect(hwBalance.isArray(), "hwBalance is not an array");
104 expect(hwBalance.size() == 2);
105 auto c1 = hwBalance[0u][jss::currency];
106 auto c2 = hwBalance[1u][jss::currency];
107 expect(c1 == "USD" || c2 == "USD");
108 expect(c1 == "JPY" || c2 == "JPY");
109 expect(hwBalance[0u][jss::value] == "5000" && hwBalance[1u][jss::value] == "5000");
110 }
111
112 {
113 auto const& fBalances = result[jss::frozen_balances];
114 expect(fBalances.isObject());
115 expect(fBalances.size() == 1);
116
117 auto const& fBal = fBalances[dave.human()];
118 expect(fBal.isArray());
119 expect(fBal.size() == 1);
120 expect(fBal[0u].isObject());
121 expect(fBal[0u][jss::currency] == "CNY");
122 expect(fBal[0u][jss::value] == "30");
123 }
124
125 {
126 auto const& assets = result[jss::assets];
127 expect(assets.isObject(), "assets it not an object");
128 expect(assets.size() == 1, "assets size is not 1");
129
130 auto const& cAssets = assets[charley.human()];
131 expect(cAssets.isArray());
132 expect(cAssets.size() == 1);
133 expect(cAssets[0u][jss::currency] == "USD");
134 expect(cAssets[0u][jss::value] == "10");
135 }
136
137 {
138 auto const& obligations = result[jss::obligations];
139 expect(obligations.isObject(), "obligations is not an object");
140 expect(obligations.size() == 3);
141 expect(obligations["CNY"] == "250");
142 expect(obligations["JPY"] == "250");
143 expect(obligations["USD"] == "50");
144 }
145 }
146 }
147
148 void
150 {
151 using namespace std::chrono_literals;
152 using namespace jtx;
153 Env env(*this, features);
154
155 // Gateway account and assets
156 Account const alice{"alice"};
157 env.fund(XRP(10000), alice);
158 Account const hw{"hw"};
159 env.fund(XRP(10000), hw);
160 env.close();
161
162 auto wsc = makeWSClient(env.app().config());
163
164 json::Value qry2;
165 qry2[jss::account] = alice.human();
166 qry2[jss::hotwallet] = "asdf";
167
168 forAllApiVersions([&, this](unsigned apiVersion) {
169 qry2[jss::api_version] = apiVersion;
170 auto jv = wsc->invoke("gateway_balances", qry2);
171 expect(jv[jss::status] == "error");
172
173 auto response = jv[jss::result];
174 auto const error = apiVersion < 2u ? "invalidHotWallet" : "invalidParams";
175 BEAST_EXPECT(response[jss::error] == error);
176 });
177 }
178
179 void
181 {
182 using namespace std::chrono_literals;
183 using namespace jtx;
184 Env env(*this);
185
186 // Gateway account and assets
187 Account const alice{"alice"};
188 env.fund(XRP(10000), alice);
189 env.close();
190 auto usd = alice["USD"];
191
192 // The largest valid STAmount of USD:
194
195 // Create a hotwallet
196 Account const hw{"hw"};
197 env.fund(XRP(10000), hw);
198 env.close();
199 env(trust(hw, maxUSD));
200 env.close();
201 env(pay(alice, hw, maxUSD));
202
203 // Create some clients
204 Account const bob{"bob"};
205 env.fund(XRP(10000), bob);
206 env.close();
207 env(trust(bob, maxUSD));
208 env.close();
209 env(pay(alice, bob, maxUSD));
210
211 Account const charley{"charley"};
212 env.fund(XRP(10000), charley);
213 env.close();
214 env(trust(charley, maxUSD));
215 env.close();
216 env(pay(alice, charley, maxUSD));
217
218 env.close();
219
220 auto wsc = makeWSClient(env.app().config());
221
222 json::Value query;
223 query[jss::account] = alice.human();
224 query[jss::hotwallet] = hw.human();
225
226 // Note that the sum of bob's and charley's USD balances exceeds
227 // the amount that can be represented in an STAmount. Nevertheless
228 // we get a valid "obligations" that shows the maximum valid
229 // STAmount.
230 auto jv = wsc->invoke("gateway_balances", query);
231 expect(jv[jss::status] == "success");
232 expect(jv[jss::result][jss::obligations]["USD"] == maxUSD.getText());
233 }
234
235 void
237 {
238 testcase("Gateway Balances with MPT Escrow");
239 using namespace std::chrono_literals;
240 using namespace jtx;
241
242 // testableAmendments() includes MPT
243 FeatureBitset const features = testableAmendments();
244 Env env(*this, features);
245
246 Account const alice{"alice"};
247 Account const bob{"bob"};
248
249 env.fund(XRP(10000), alice, bob);
250 env.close();
251
252 // Create MPT issuance (Alice) with Escrow capability
253 MPTTester mpt(env, alice, {.holders = {bob}, .fund = false});
254 mpt.create({.flags = tfMPTCanEscrow});
255
256 // Authorize Bob and fund him
257 mpt.authorize({.account = bob, .holderCount = 1});
258 mpt.pay(alice, bob, 1000);
259
260 // Bob creates an escrow of MPT to Alice.
261 auto const MPT = mpt["MPT"]; // NOLINT(readability-identifier-naming)
262 env(escrow::create(bob, alice, MPT(100)), escrow::kFinishTime(env.now() + 10s));
263 env.close();
264
265 // Query gateway_balances for Bob.
266 auto wsc = makeWSClient(env.app().config());
267 json::Value qry;
268 qry[jss::account] = bob.human();
269
270 auto jv = wsc->invoke("gateway_balances", qry);
271 expect(jv[jss::status] == "success");
272 }
273
274 void
275 run() override
276 {
277 using namespace jtx;
278 auto const sa = testableAmendments();
279 for (auto feature : {sa - featurePermissionedDEX, sa})
280 {
281 testGWB(feature);
282 testGWBApiVersions(feature);
283 }
286 }
287};
288
289BEAST_DEFINE_TESTSUITE(GatewayBalances, rpc, xrpl);
290
291} // namespace xrpl::test
A testsuite class.
Definition suite.h:50
bool expect(Condition const &shouldBeTrue)
Evaluate a test condition.
Definition suite.h:223
TestcaseT testcase
Memberspace for declaring test cases.
Definition suite.h:149
Represents a JSON value.
Definition json_value.h:130
virtual Config & config()=0
std::string getText() const override
Definition STAmount.cpp:646
static constexpr std::uint64_t kMaxValue
Definition STAmount.h:53
static constexpr int kMaxOffset
Definition STAmount.h:48
void testGWB(FeatureBitset features)
void run() override
Runs the suite.
void testGWBApiVersions(FeatureBitset features)
Immutable cryptographic account descriptor.
Definition jtx/Account.h:17
std::string const & human() const
Returns the human readable public key.
Definition jtx/Account.h:92
A transaction testing environment.
Definition Env.h:143
Application & app()
Definition Env.h:280
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition Env.cpp:133
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition Env.cpp:296
NetClock::time_point now()
Returns the current network time.
Definition Env.h:305
Test helper for creating, mutating, and asserting MPT and confidential MPT ledger state.
Definition mpt.h:385
void create(MPTCreate const &arg=MPTCreate{})
Definition mpt.cpp:256
Converts to MPT Issue or STAmount.
json::Value create(AccountID const &account, AccountID const &to, STAmount const &amount)
Definition escrow.cpp:21
auto const kFinishTime
Set the "FinishAfter" time tag on a JTx.
Definition escrow.h:69
json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
Definition pay.cpp:14
XrpT const XRP
Converts to XRP Issue or STAmount.
Definition amount.cpp:92
FeatureBitset testableAmendments()
Definition Env.h:76
json::Value trust(Account const &account, STAmount const &amount, std::uint32_t flags)
Modify a trust line.
Definition trust.cpp:18
BEAST_DEFINE_TESTSUITE(AMMClawback, app, xrpl)
std::unique_ptr< WSClient > makeWSClient(Config const &cfg, bool v2, unsigned rpcVersion, std::unordered_map< std::string, std::string > const &headers)
Returns a client operating through WebSockets/S.
Definition WSClient.cpp:329
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
void forAllApiVersions(Fn const &fn, Args &&... args)
Definition ApiVersion.h:158