From 8bf338c8b5c8293069fb5a9fac1a097694af625b Mon Sep 17 00:00:00 2001 From: bthomee Date: Wed, 29 Oct 2025 09:11:24 -0700 Subject: [PATCH] deploy: efa917d9f32958ab9ebb2f0c284657a96901e922 --- AMMExtended__test_8cpp_source.html | 7318 +++++++------ CreateOffer_8cpp_source.html | 322 +- CreateOffer_8h_source.html | 2 +- Feature__test_8cpp_source.html | 1013 +- NoRipple__test_8cpp_source.html | 426 +- Offer__test_8cpp_source.html | 9118 ++++++++--------- SetTrust_8cpp_source.html | 2 +- classripple_1_1CreateOffer.html | 2 +- classripple_1_1Feature__test.html | 18 +- classripple_1_1test_1_1NoRipple__test.html | 6 +- ...ple_1_1test_1_1OfferAllFeatures__test.html | 114 +- ...ripple_1_1test_1_1OfferBaseUtil__test.html | 112 +- ...le_1_1test_1_1OfferWOFillOrKill__test.html | 114 +- ...ipple_1_1test_1_1OfferWOPermDEX__test.html | 114 +- ..._1_1test_1_1OfferWOSmallQOffers__test.html | 114 +- ..._1_1test_1_1OfferWTakerDryOffer__test.html | 114 +- ...ripple_1_1test_1_1Offer__manual__test.html | 114 +- ...ctripple_1_1test_1_1AMMExtended__test.html | 106 +- 18 files changed, 9549 insertions(+), 9580 deletions(-) diff --git a/AMMExtended__test_8cpp_source.html b/AMMExtended__test_8cpp_source.html index 4b73b2bfef..934530f29f 100644 --- a/AMMExtended__test_8cpp_source.html +++ b/AMMExtended__test_8cpp_source.html @@ -284,3783 +284,3773 @@ $(document).ready(function() { init_codefold(0); });
198 // Fill or Kill - unless we fully cross, just charge a fee and don't
199 // place the offer on the books. But also clean up expired offers
200 // that are discovered along the way.
-
201 //
-
202 // fix1578 changes the return code. Verify expected behavior
-
203 // without and with fix1578.
-
204 for (auto const& tweakedFeatures :
-
205 {features - fix1578, features | fix1578})
-
206 {
-
207 testAMM(
-
208 [&](AMM& ammAlice, Env& env) {
-
209 // Order that can't be filled
-
210 TER const killedCode{
-
211 tweakedFeatures[fix1578] ? TER{tecKILLED}
-
212 : TER{tesSUCCESS}};
-
213 env(offer(carol, USD(100), XRP(100)),
-
214 txflags(tfFillOrKill),
-
215 ter(killedCode));
-
216 env.close();
-
217 BEAST_EXPECT(ammAlice.expectBalances(
-
218 XRP(10'100), USD(10'000), ammAlice.tokens()));
-
219 // fee = AMM
-
220 BEAST_EXPECT(expectLedgerEntryRoot(
-
221 env, carol, XRP(30'000) - (txfee(env, 1))));
-
222 BEAST_EXPECT(expectOffers(env, carol, 0));
-
223 BEAST_EXPECT(expectHolding(env, carol, USD(30'000)));
-
224
-
225 // Order that can be filled
-
226 env(offer(carol, XRP(100), USD(100)),
-
227 txflags(tfFillOrKill),
-
228 ter(tesSUCCESS));
-
229 BEAST_EXPECT(ammAlice.expectBalances(
-
230 XRP(10'000), USD(10'100), ammAlice.tokens()));
-
231 BEAST_EXPECT(expectLedgerEntryRoot(
-
232 env, carol, XRP(30'000) + XRP(100) - txfee(env, 2)));
-
233 BEAST_EXPECT(expectHolding(env, carol, USD(29'900)));
-
234 BEAST_EXPECT(expectOffers(env, carol, 0));
-
235 },
-
236 {{XRP(10'100), USD(10'000)}},
-
237 0,
-
238 std::nullopt,
-
239 {tweakedFeatures});
+
201 testAMM(
+
202 [&](AMM& ammAlice, Env& env) {
+
203 // Order that can't be filled
+
204 TER const killedCode{TER{tecKILLED}};
+
205 env(offer(carol, USD(100), XRP(100)),
+
206 txflags(tfFillOrKill),
+
207 ter(killedCode));
+
208 env.close();
+
209 BEAST_EXPECT(ammAlice.expectBalances(
+
210 XRP(10'100), USD(10'000), ammAlice.tokens()));
+
211 // fee = AMM
+
212 BEAST_EXPECT(expectLedgerEntryRoot(
+
213 env, carol, XRP(30'000) - (txfee(env, 1))));
+
214 BEAST_EXPECT(expectOffers(env, carol, 0));
+
215 BEAST_EXPECT(expectHolding(env, carol, USD(30'000)));
+
216
+
217 // Order that can be filled
+
218 env(offer(carol, XRP(100), USD(100)),
+
219 txflags(tfFillOrKill),
+
220 ter(tesSUCCESS));
+
221 BEAST_EXPECT(ammAlice.expectBalances(
+
222 XRP(10'000), USD(10'100), ammAlice.tokens()));
+
223 BEAST_EXPECT(expectLedgerEntryRoot(
+
224 env, carol, XRP(30'000) + XRP(100) - txfee(env, 2)));
+
225 BEAST_EXPECT(expectHolding(env, carol, USD(29'900)));
+
226 BEAST_EXPECT(expectOffers(env, carol, 0));
+
227 },
+
228 {{XRP(10'100), USD(10'000)}},
+
229 0,
+
230 std::nullopt,
+
231 {features});
+
232
+
233 // Immediate or Cancel - cross as much as possible
+
234 // and add nothing on the books.
+
235 testAMM(
+
236 [&](AMM& ammAlice, Env& env) {
+
237 env(offer(carol, XRP(200), USD(200)),
+
238 txflags(tfImmediateOrCancel),
+
239 ter(tesSUCCESS));
240
-
241 // Immediate or Cancel - cross as much as possible
-
242 // and add nothing on the books.
-
243 testAMM(
-
244 [&](AMM& ammAlice, Env& env) {
-
245 env(offer(carol, XRP(200), USD(200)),
-
246 txflags(tfImmediateOrCancel),
-
247 ter(tesSUCCESS));
-
248
-
249 // AMM generates a synthetic offer of 100USD/100XRP
-
250 // to match the CLOB offer quality.
-
251 BEAST_EXPECT(ammAlice.expectBalances(
-
252 XRP(10'000), USD(10'100), ammAlice.tokens()));
-
253 // +AMM - offer * fee
-
254 BEAST_EXPECT(expectLedgerEntryRoot(
-
255 env, carol, XRP(30'000) + XRP(100) - txfee(env, 1)));
-
256 // AMM
-
257 BEAST_EXPECT(expectHolding(env, carol, USD(29'900)));
-
258 BEAST_EXPECT(expectOffers(env, carol, 0));
-
259 },
-
260 {{XRP(10'100), USD(10'000)}},
-
261 0,
-
262 std::nullopt,
-
263 {tweakedFeatures});
-
264
-
265 // tfPassive -- place the offer without crossing it.
-
266 testAMM(
-
267 [&](AMM& ammAlice, Env& env) {
-
268 // Carol creates a passive offer that could cross AMM.
-
269 // Carol's offer should stay in the ledger.
-
270 env(offer(carol, XRP(100), USD(100), tfPassive));
-
271 env.close();
-
272 BEAST_EXPECT(ammAlice.expectBalances(
-
273 XRP(10'100), STAmount{USD, 10'000}, ammAlice.tokens()));
-
274 BEAST_EXPECT(expectOffers(
-
275 env, carol, 1, {{{XRP(100), STAmount{USD, 100}}}}));
-
276 },
-
277 {{XRP(10'100), USD(10'000)}},
-
278 0,
-
279 std::nullopt,
-
280 {tweakedFeatures});
-
281
-
282 // tfPassive -- cross only offers of better quality.
-
283 testAMM(
-
284 [&](AMM& ammAlice, Env& env) {
-
285 env(offer(alice, USD(110), XRP(100)));
-
286 env.close();
-
287
-
288 // Carol creates a passive offer. That offer should cross
-
289 // AMM and leave Alice's offer untouched.
-
290 env(offer(carol, XRP(100), USD(100), tfPassive));
-
291 env.close();
-
292 BEAST_EXPECT(ammAlice.expectBalances(
-
293 XRP(10'900),
-
294 STAmount{USD, UINT64_C(9'082'56880733945), -11},
-
295 ammAlice.tokens()));
-
296 BEAST_EXPECT(expectOffers(env, carol, 0));
-
297 BEAST_EXPECT(expectOffers(env, alice, 1));
-
298 },
-
299 {{XRP(11'000), USD(9'000)}},
-
300 0,
-
301 std::nullopt,
-
302 {tweakedFeatures});
-
303 }
-
304 }
+
241 // AMM generates a synthetic offer of 100USD/100XRP
+
242 // to match the CLOB offer quality.
+
243 BEAST_EXPECT(ammAlice.expectBalances(
+
244 XRP(10'000), USD(10'100), ammAlice.tokens()));
+
245 // +AMM - offer * fee
+
246 BEAST_EXPECT(expectLedgerEntryRoot(
+
247 env, carol, XRP(30'000) + XRP(100) - txfee(env, 1)));
+
248 // AMM
+
249 BEAST_EXPECT(expectHolding(env, carol, USD(29'900)));
+
250 BEAST_EXPECT(expectOffers(env, carol, 0));
+
251 },
+
252 {{XRP(10'100), USD(10'000)}},
+
253 0,
+
254 std::nullopt,
+
255 {features});
+
256
+
257 // tfPassive -- place the offer without crossing it.
+
258 testAMM(
+
259 [&](AMM& ammAlice, Env& env) {
+
260 // Carol creates a passive offer that could cross AMM.
+
261 // Carol's offer should stay in the ledger.
+
262 env(offer(carol, XRP(100), USD(100), tfPassive));
+
263 env.close();
+
264 BEAST_EXPECT(ammAlice.expectBalances(
+
265 XRP(10'100), STAmount{USD, 10'000}, ammAlice.tokens()));
+
266 BEAST_EXPECT(expectOffers(
+
267 env, carol, 1, {{{XRP(100), STAmount{USD, 100}}}}));
+
268 },
+
269 {{XRP(10'100), USD(10'000)}},
+
270 0,
+
271 std::nullopt,
+
272 {features});
+
273
+
274 // tfPassive -- cross only offers of better quality.
+
275 testAMM(
+
276 [&](AMM& ammAlice, Env& env) {
+
277 env(offer(alice, USD(110), XRP(100)));
+
278 env.close();
+
279
+
280 // Carol creates a passive offer. That offer should cross
+
281 // AMM and leave Alice's offer untouched.
+
282 env(offer(carol, XRP(100), USD(100), tfPassive));
+
283 env.close();
+
284 BEAST_EXPECT(ammAlice.expectBalances(
+
285 XRP(10'900),
+
286 STAmount{USD, UINT64_C(9'082'56880733945), -11},
+
287 ammAlice.tokens()));
+
288 BEAST_EXPECT(expectOffers(env, carol, 0));
+
289 BEAST_EXPECT(expectOffers(env, alice, 1));
+
290 },
+
291 {{XRP(11'000), USD(9'000)}},
+
292 0,
+
293 std::nullopt,
+
294 {features});
+
295 }
+
296
+
297 void
+
+ +
299 {
+
300 testcase("Offer Crossing with XRP, Normal order");
+
301
+
302 using namespace jtx;
+
303
+
304 Env env{*this, features};
305
-
306 void
-
- -
308 {
-
309 testcase("Offer Crossing with XRP, Normal order");
-
310
-
311 using namespace jtx;
-
312
-
313 Env env{*this, features};
-
314
-
315 fund(env, gw, {bob, alice}, XRP(300'000), {USD(100)}, Fund::All);
-
316
-
317 AMM ammAlice(env, alice, XRP(150'000), USD(50));
-
318
-
319 // Existing offer pays better than this wants.
-
320 // Partially consume existing offer.
-
321 // Pay 1 USD, get 3061224490 Drops.
-
322 auto const xrpTransferred = XRPAmount{3'061'224'490};
-
323 env(offer(bob, USD(1), XRP(4'000)));
-
324
-
325 BEAST_EXPECT(ammAlice.expectBalances(
-
326 XRP(150'000) + xrpTransferred,
-
327 USD(49),
-
328 IOUAmount{273'861'278752583, -8}));
-
329
-
330 BEAST_EXPECT(expectHolding(env, bob, STAmount{USD, 101}));
-
331 BEAST_EXPECT(expectLedgerEntryRoot(
-
332 env, bob, XRP(300'000) - xrpTransferred - txfee(env, 1)));
-
333 BEAST_EXPECT(expectOffers(env, bob, 0));
-
334 }
+
306 fund(env, gw, {bob, alice}, XRP(300'000), {USD(100)}, Fund::All);
+
307
+
308 AMM ammAlice(env, alice, XRP(150'000), USD(50));
+
309
+
310 // Existing offer pays better than this wants.
+
311 // Partially consume existing offer.
+
312 // Pay 1 USD, get 3061224490 Drops.
+
313 auto const xrpTransferred = XRPAmount{3'061'224'490};
+
314 env(offer(bob, USD(1), XRP(4'000)));
+
315
+
316 BEAST_EXPECT(ammAlice.expectBalances(
+
317 XRP(150'000) + xrpTransferred,
+
318 USD(49),
+
319 IOUAmount{273'861'278752583, -8}));
+
320
+
321 BEAST_EXPECT(expectHolding(env, bob, STAmount{USD, 101}));
+
322 BEAST_EXPECT(expectLedgerEntryRoot(
+
323 env, bob, XRP(300'000) - xrpTransferred - txfee(env, 1)));
+
324 BEAST_EXPECT(expectOffers(env, bob, 0));
+
325 }
+
326
+
327 void
+
+ +
329 {
+
330 testcase("Offer Crossing with Limit Override");
+
331
+
332 using namespace jtx;
+
333
+
334 Env env{*this, features};
335
-
336 void
-
- -
338 {
-
339 testcase("Offer Crossing with Limit Override");
+
336 env.fund(XRP(200'000), gw, alice, bob);
+
337 env.close();
+
338
+
339 env(trust(alice, USD(1'000)));
340
-
341 using namespace jtx;
+
341 env(pay(gw, alice, alice["USD"](500)));
342
-
343 Env env{*this, features};
-
344
-
345 env.fund(XRP(200'000), gw, alice, bob);
-
346 env.close();
-
347
-
348 env(trust(alice, USD(1'000)));
-
349
-
350 env(pay(gw, alice, alice["USD"](500)));
-
351
-
352 AMM ammAlice(env, alice, XRP(150'000), USD(51));
-
353 env(offer(bob, USD(1), XRP(3'000)));
-
354
-
355 BEAST_EXPECT(
-
356 ammAlice.expectBalances(XRP(153'000), USD(50), ammAlice.tokens()));
-
357
-
358 auto jrr = ledgerEntryState(env, bob, gw, "USD");
-
359 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-1");
-
360 jrr = ledgerEntryRoot(env, bob);
-
361 BEAST_EXPECT(
-
362 jrr[jss::node][sfBalance.fieldName] ==
-
363 to_string(
-
364 (XRP(200'000) - XRP(3'000) - env.current()->fees().base * 1)
-
365 .xrp()));
-
366 }
+
343 AMM ammAlice(env, alice, XRP(150'000), USD(51));
+
344 env(offer(bob, USD(1), XRP(3'000)));
+
345
+
346 BEAST_EXPECT(
+
347 ammAlice.expectBalances(XRP(153'000), USD(50), ammAlice.tokens()));
+
348
+
349 auto jrr = ledgerEntryState(env, bob, gw, "USD");
+
350 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-1");
+
351 jrr = ledgerEntryRoot(env, bob);
+
352 BEAST_EXPECT(
+
353 jrr[jss::node][sfBalance.fieldName] ==
+
354 to_string(
+
355 (XRP(200'000) - XRP(3'000) - env.current()->fees().base * 1)
+
356 .xrp()));
+
357 }
+
358
+
359 void
+
+ +
361 {
+
362 testcase("Currency Conversion: Entire Offer");
+
363
+
364 using namespace jtx;
+
365
+
366 Env env{*this, features};
367
-
368 void
-
- -
370 {
-
371 testcase("Currency Conversion: Entire Offer");
-
372
-
373 using namespace jtx;
+
368 fund(env, gw, {alice, bob}, XRP(10'000));
+
369 env.require(owners(bob, 0));
+
370
+
371 env(trust(alice, USD(100)));
+
372 env(trust(bob, USD(1'000)));
+
373 env(pay(gw, bob, USD(1'000)));
374
-
375 Env env{*this, features};
+
375 env.require(owners(alice, 1), owners(bob, 1));
376
-
377 fund(env, gw, {alice, bob}, XRP(10'000));
-
378 env.require(owners(bob, 0));
+
377 env(pay(gw, alice, alice["USD"](100)));
+
378 AMM ammBob(env, bob, USD(200), XRP(1'500));
379
-
380 env(trust(alice, USD(100)));
-
381 env(trust(bob, USD(1'000)));
-
382 env(pay(gw, bob, USD(1'000)));
-
383
-
384 env.require(owners(alice, 1), owners(bob, 1));
+
380 env(pay(alice, alice, XRP(500)), sendmax(USD(100)));
+
381
+
382 BEAST_EXPECT(
+
383 ammBob.expectBalances(USD(300), XRP(1'000), ammBob.tokens()));
+
384 BEAST_EXPECT(expectHolding(env, alice, USD(0)));
385
-
386 env(pay(gw, alice, alice["USD"](100)));
-
387 AMM ammBob(env, bob, USD(200), XRP(1'500));
-
388
-
389 env(pay(alice, alice, XRP(500)), sendmax(USD(100)));
-
390
-
391 BEAST_EXPECT(
-
392 ammBob.expectBalances(USD(300), XRP(1'000), ammBob.tokens()));
-
393 BEAST_EXPECT(expectHolding(env, alice, USD(0)));
-
394
-
395 auto jrr = ledgerEntryRoot(env, alice);
-
396 BEAST_EXPECT(
-
397 jrr[jss::node][sfBalance.fieldName] ==
-
398 to_string((XRP(10'000) + XRP(500) - env.current()->fees().base * 2)
-
399 .xrp()));
-
400 }
+
386 auto jrr = ledgerEntryRoot(env, alice);
+
387 BEAST_EXPECT(
+
388 jrr[jss::node][sfBalance.fieldName] ==
+
389 to_string((XRP(10'000) + XRP(500) - env.current()->fees().base * 2)
+
390 .xrp()));
+
391 }
-
401
-
402 void
-
- -
404 {
-
405 testcase("Currency Conversion: In Parts");
-
406
-
407 using namespace jtx;
-
408
-
409 testAMM(
-
410 [&](AMM& ammAlice, Env& env) {
-
411 // Alice converts USD to XRP which should fail
-
412 // due to PartialPayment.
-
413 env(pay(alice, alice, XRP(100)),
-
414 sendmax(USD(100)),
- -
416
-
417 // Alice converts USD to XRP, should succeed because
-
418 // we permit partial payment
-
419 env(pay(alice, alice, XRP(100)),
-
420 sendmax(USD(100)),
- -
422 env.close();
-
423 BEAST_EXPECT(ammAlice.expectBalances(
-
424 XRPAmount{9'900'990'100}, USD(10'100), ammAlice.tokens()));
-
425 // initial 30,000 - 10,000AMM - 100pay
-
426 BEAST_EXPECT(expectHolding(env, alice, USD(19'900)));
-
427 // initial 30,000 - 10,0000AMM + 99.009900pay - fee*3
-
428 BEAST_EXPECT(expectLedgerEntryRoot(
-
429 env,
-
430 alice,
-
431 XRP(30'000) - XRP(10'000) + XRPAmount{99'009'900} -
-
432 ammCrtFee(env) - txfee(env, 2)));
-
433 },
-
434 {{XRP(10'000), USD(10'000)}},
-
435 0,
- -
437 {features});
-
438 }
+
392
+
393 void
+
+ +
395 {
+
396 testcase("Currency Conversion: In Parts");
+
397
+
398 using namespace jtx;
+
399
+
400 testAMM(
+
401 [&](AMM& ammAlice, Env& env) {
+
402 // Alice converts USD to XRP which should fail
+
403 // due to PartialPayment.
+
404 env(pay(alice, alice, XRP(100)),
+
405 sendmax(USD(100)),
+ +
407
+
408 // Alice converts USD to XRP, should succeed because
+
409 // we permit partial payment
+
410 env(pay(alice, alice, XRP(100)),
+
411 sendmax(USD(100)),
+ +
413 env.close();
+
414 BEAST_EXPECT(ammAlice.expectBalances(
+
415 XRPAmount{9'900'990'100}, USD(10'100), ammAlice.tokens()));
+
416 // initial 30,000 - 10,000AMM - 100pay
+
417 BEAST_EXPECT(expectHolding(env, alice, USD(19'900)));
+
418 // initial 30,000 - 10,0000AMM + 99.009900pay - fee*3
+
419 BEAST_EXPECT(expectLedgerEntryRoot(
+
420 env,
+
421 alice,
+
422 XRP(30'000) - XRP(10'000) + XRPAmount{99'009'900} -
+
423 ammCrtFee(env) - txfee(env, 2)));
+
424 },
+
425 {{XRP(10'000), USD(10'000)}},
+
426 0,
+ +
428 {features});
+
429 }
-
439
-
440 void
-
- -
442 {
-
443 testcase("Cross Currency Payment: Start with XRP");
-
444
-
445 using namespace jtx;
-
446
-
447 testAMM(
-
448 [&](AMM& ammAlice, Env& env) {
-
449 env.fund(XRP(1'000), bob);
-
450 env.close();
-
451 env(trust(bob, USD(100)));
-
452 env.close();
-
453 env(pay(alice, bob, USD(100)), sendmax(XRP(100)));
-
454 BEAST_EXPECT(ammAlice.expectBalances(
-
455 XRP(10'100), USD(10'000), ammAlice.tokens()));
-
456 BEAST_EXPECT(expectHolding(env, bob, USD(100)));
-
457 },
-
458 {{XRP(10'000), USD(10'100)}},
-
459 0,
- -
461 {features});
-
462 }
+
430
+
431 void
+
+ +
433 {
+
434 testcase("Cross Currency Payment: Start with XRP");
+
435
+
436 using namespace jtx;
+
437
+
438 testAMM(
+
439 [&](AMM& ammAlice, Env& env) {
+
440 env.fund(XRP(1'000), bob);
+
441 env.close();
+
442 env(trust(bob, USD(100)));
+
443 env.close();
+
444 env(pay(alice, bob, USD(100)), sendmax(XRP(100)));
+
445 BEAST_EXPECT(ammAlice.expectBalances(
+
446 XRP(10'100), USD(10'000), ammAlice.tokens()));
+
447 BEAST_EXPECT(expectHolding(env, bob, USD(100)));
+
448 },
+
449 {{XRP(10'000), USD(10'100)}},
+
450 0,
+ +
452 {features});
+
453 }
-
463
-
464 void
-
- -
466 {
-
467 testcase("Cross Currency Payment: End with XRP");
-
468
-
469 using namespace jtx;
-
470
-
471 testAMM(
-
472 [&](AMM& ammAlice, Env& env) {
-
473 env.fund(XRP(1'000), bob);
-
474 env.close();
-
475 env(trust(bob, USD(100)));
-
476 env.close();
-
477 env(pay(alice, bob, XRP(100)), sendmax(USD(100)));
-
478 BEAST_EXPECT(ammAlice.expectBalances(
-
479 XRP(10'000), USD(10'100), ammAlice.tokens()));
-
480 BEAST_EXPECT(expectLedgerEntryRoot(
-
481 env, bob, XRP(1'000) + XRP(100) - txfee(env, 1)));
-
482 },
-
483 {{XRP(10'100), USD(10'000)}},
-
484 0,
- -
486 {features});
-
487 }
+
454
+
455 void
+
+ +
457 {
+
458 testcase("Cross Currency Payment: End with XRP");
+
459
+
460 using namespace jtx;
+
461
+
462 testAMM(
+
463 [&](AMM& ammAlice, Env& env) {
+
464 env.fund(XRP(1'000), bob);
+
465 env.close();
+
466 env(trust(bob, USD(100)));
+
467 env.close();
+
468 env(pay(alice, bob, XRP(100)), sendmax(USD(100)));
+
469 BEAST_EXPECT(ammAlice.expectBalances(
+
470 XRP(10'000), USD(10'100), ammAlice.tokens()));
+
471 BEAST_EXPECT(expectLedgerEntryRoot(
+
472 env, bob, XRP(1'000) + XRP(100) - txfee(env, 1)));
+
473 },
+
474 {{XRP(10'100), USD(10'000)}},
+
475 0,
+ +
477 {features});
+
478 }
+
479
+
480 void
+
+ +
482 {
+
483 testcase("Cross Currency Payment: Bridged");
+
484
+
485 using namespace jtx;
+
486
+
487 Env env{*this, features};
488
-
489 void
-
- -
491 {
-
492 testcase("Cross Currency Payment: Bridged");
-
493
-
494 using namespace jtx;
-
495
-
496 Env env{*this, features};
-
497
-
498 auto const gw1 = Account{"gateway_1"};
-
499 auto const gw2 = Account{"gateway_2"};
-
500 auto const dan = Account{"dan"};
-
501 auto const USD1 = gw1["USD"];
-
502 auto const EUR1 = gw2["EUR"];
-
503
-
504 fund(env, gw1, {gw2, alice, bob, carol, dan}, XRP(60'000));
-
505 env(trust(alice, USD1(1'000)));
+
489 auto const gw1 = Account{"gateway_1"};
+
490 auto const gw2 = Account{"gateway_2"};
+
491 auto const dan = Account{"dan"};
+
492 auto const USD1 = gw1["USD"];
+
493 auto const EUR1 = gw2["EUR"];
+
494
+
495 fund(env, gw1, {gw2, alice, bob, carol, dan}, XRP(60'000));
+
496 env(trust(alice, USD1(1'000)));
+
497 env.close();
+
498 env(trust(bob, EUR1(1'000)));
+
499 env.close();
+
500 env(trust(carol, USD1(10'000)));
+
501 env.close();
+
502 env(trust(dan, EUR1(1'000)));
+
503 env.close();
+
504
+
505 env(pay(gw1, alice, alice["USD"](500)));
506 env.close();
-
507 env(trust(bob, EUR1(1'000)));
-
508 env.close();
-
509 env(trust(carol, USD1(10'000)));
-
510 env.close();
-
511 env(trust(dan, EUR1(1'000)));
-
512 env.close();
-
513
-
514 env(pay(gw1, alice, alice["USD"](500)));
-
515 env.close();
-
516 env(pay(gw1, carol, carol["USD"](6'000)));
-
517 env(pay(gw2, dan, dan["EUR"](400)));
-
518 env.close();
-
519
-
520 AMM ammCarol(env, carol, USD1(5'000), XRP(50'000));
-
521
-
522 env(offer(dan, XRP(500), EUR1(50)));
-
523 env.close();
-
524
- -
526 jtp[0u][0u][jss::currency] = "XRP";
-
527 env(pay(alice, bob, EUR1(30)),
-
528 json(jss::Paths, jtp),
-
529 sendmax(USD1(333)));
-
530 env.close();
-
531 BEAST_EXPECT(ammCarol.expectBalances(
-
532 XRP(49'700),
-
533 STAmount{USD1, UINT64_C(5'030'181086519115), -12},
-
534 ammCarol.tokens()));
-
535 BEAST_EXPECT(expectOffers(env, dan, 1, {{Amounts{XRP(200), EUR(20)}}}));
-
536 BEAST_EXPECT(expectHolding(env, bob, STAmount{EUR1, 30}));
-
537 }
+
507 env(pay(gw1, carol, carol["USD"](6'000)));
+
508 env(pay(gw2, dan, dan["EUR"](400)));
+
509 env.close();
+
510
+
511 AMM ammCarol(env, carol, USD1(5'000), XRP(50'000));
+
512
+
513 env(offer(dan, XRP(500), EUR1(50)));
+
514 env.close();
+
515
+ +
517 jtp[0u][0u][jss::currency] = "XRP";
+
518 env(pay(alice, bob, EUR1(30)),
+
519 json(jss::Paths, jtp),
+
520 sendmax(USD1(333)));
+
521 env.close();
+
522 BEAST_EXPECT(ammCarol.expectBalances(
+
523 XRP(49'700),
+
524 STAmount{USD1, UINT64_C(5'030'181086519115), -12},
+
525 ammCarol.tokens()));
+
526 BEAST_EXPECT(expectOffers(env, dan, 1, {{Amounts{XRP(200), EUR(20)}}}));
+
527 BEAST_EXPECT(expectHolding(env, bob, STAmount{EUR1, 30}));
+
528 }
+
529
+
530 void
+
+ +
532 {
+
533 testcase("Offer Fees Consume Funds");
+
534
+
535 using namespace jtx;
+
536
+
537 Env env{*this, features};
538
-
539 void
-
- -
541 {
-
542 testcase("Offer Fees Consume Funds");
-
543
-
544 using namespace jtx;
-
545
-
546 Env env{*this, features};
+
539 auto const gw1 = Account{"gateway_1"};
+
540 auto const gw2 = Account{"gateway_2"};
+
541 auto const gw3 = Account{"gateway_3"};
+
542 auto const alice = Account{"alice"};
+
543 auto const bob = Account{"bob"};
+
544 auto const USD1 = gw1["USD"];
+
545 auto const USD2 = gw2["USD"];
+
546 auto const USD3 = gw3["USD"];
547
-
548 auto const gw1 = Account{"gateway_1"};
-
549 auto const gw2 = Account{"gateway_2"};
-
550 auto const gw3 = Account{"gateway_3"};
-
551 auto const alice = Account{"alice"};
-
552 auto const bob = Account{"bob"};
-
553 auto const USD1 = gw1["USD"];
-
554 auto const USD2 = gw2["USD"];
-
555 auto const USD3 = gw3["USD"];
-
556
-
557 // Provide micro amounts to compensate for fees to make results round
-
558 // nice.
-
559 // reserve: Alice has 3 entries in the ledger, via trust lines
-
560 // fees:
-
561 // 1 for each trust limit == 3 (alice < mtgox/amazon/bitstamp) +
-
562 // 1 for payment == 4
-
563 auto const starting_xrp = XRP(100) +
-
564 env.current()->fees().accountReserve(3) +
-
565 env.current()->fees().base * 4;
-
566
-
567 env.fund(starting_xrp, gw1, gw2, gw3, alice);
-
568 env.fund(XRP(2'000), bob);
-
569 env.close();
-
570
-
571 env(trust(alice, USD1(1'000)));
-
572 env(trust(alice, USD2(1'000)));
-
573 env(trust(alice, USD3(1'000)));
-
574 env(trust(bob, USD1(1'200)));
-
575 env(trust(bob, USD2(1'100)));
-
576
-
577 env(pay(gw1, bob, bob["USD"](1'200)));
-
578
-
579 AMM ammBob(env, bob, XRP(1'000), USD1(1'200));
-
580 // Alice has 350 fees - a reserve of 50 = 250 reserve = 100 available.
-
581 // Ask for more than available to prove reserve works.
-
582 env(offer(alice, USD1(200), XRP(200)));
-
583
-
584 // The pool gets only 100XRP for ~109.09USD, even though
-
585 // it can exchange more.
-
586 BEAST_EXPECT(ammBob.expectBalances(
-
587 XRP(1'100),
-
588 STAmount{USD1, UINT64_C(1'090'909090909091), -12},
-
589 ammBob.tokens()));
+
548 // Provide micro amounts to compensate for fees to make results round
+
549 // nice.
+
550 // reserve: Alice has 3 entries in the ledger, via trust lines
+
551 // fees:
+
552 // 1 for each trust limit == 3 (alice < mtgox/amazon/bitstamp) +
+
553 // 1 for payment == 4
+
554 auto const starting_xrp = XRP(100) +
+
555 env.current()->fees().accountReserve(3) +
+
556 env.current()->fees().base * 4;
+
557
+
558 env.fund(starting_xrp, gw1, gw2, gw3, alice);
+
559 env.fund(XRP(2'000), bob);
+
560 env.close();
+
561
+
562 env(trust(alice, USD1(1'000)));
+
563 env(trust(alice, USD2(1'000)));
+
564 env(trust(alice, USD3(1'000)));
+
565 env(trust(bob, USD1(1'200)));
+
566 env(trust(bob, USD2(1'100)));
+
567
+
568 env(pay(gw1, bob, bob["USD"](1'200)));
+
569
+
570 AMM ammBob(env, bob, XRP(1'000), USD1(1'200));
+
571 // Alice has 350 fees - a reserve of 50 = 250 reserve = 100 available.
+
572 // Ask for more than available to prove reserve works.
+
573 env(offer(alice, USD1(200), XRP(200)));
+
574
+
575 // The pool gets only 100XRP for ~109.09USD, even though
+
576 // it can exchange more.
+
577 BEAST_EXPECT(ammBob.expectBalances(
+
578 XRP(1'100),
+
579 STAmount{USD1, UINT64_C(1'090'909090909091), -12},
+
580 ammBob.tokens()));
+
581
+
582 auto jrr = ledgerEntryState(env, alice, gw1, "USD");
+
583 BEAST_EXPECT(
+
584 jrr[jss::node][sfBalance.fieldName][jss::value] ==
+
585 "109.090909090909");
+
586 jrr = ledgerEntryRoot(env, alice);
+
587 BEAST_EXPECT(
+
588 jrr[jss::node][sfBalance.fieldName] == XRP(350).value().getText());
+
589 }
+
590
-
591 auto jrr = ledgerEntryState(env, alice, gw1, "USD");
-
592 BEAST_EXPECT(
-
593 jrr[jss::node][sfBalance.fieldName][jss::value] ==
-
594 "109.090909090909");
-
595 jrr = ledgerEntryRoot(env, alice);
-
596 BEAST_EXPECT(
-
597 jrr[jss::node][sfBalance.fieldName] == XRP(350).value().getText());
-
598 }
-
+
591 void
+
+ +
593 {
+
594 testcase("Offer Create, then Cross");
+
595
+
596 using namespace jtx;
+
597
+
598 Env env{*this, features};
599
-
600 void
-
- -
602 {
-
603 testcase("Offer Create, then Cross");
-
604
-
605 using namespace jtx;
+
600 fund(env, gw, {alice, bob}, XRP(200'000));
+
601
+
602 env(rate(gw, 1.005));
+
603
+
604 env(trust(alice, USD(1'000)));
+
605 env(trust(bob, USD(1'000)));
606
-
607 Env env{*this, features};
-
608
-
609 fund(env, gw, {alice, bob}, XRP(200'000));
-
610
-
611 env(rate(gw, 1.005));
+
607 env(pay(gw, bob, USD(1)));
+
608 env(pay(gw, alice, USD(200)));
+
609
+
610 AMM ammAlice(env, alice, USD(150), XRP(150'100));
+
611 env(offer(bob, XRP(100), USD(0.1)));
612
-
613 env(trust(alice, USD(1'000)));
-
614 env(trust(bob, USD(1'000)));
+
613 BEAST_EXPECT(ammAlice.expectBalances(
+
614 USD(150.1), XRP(150'000), ammAlice.tokens()));
615
-
616 env(pay(gw, bob, USD(1)));
-
617 env(pay(gw, alice, USD(200)));
-
618
-
619 AMM ammAlice(env, alice, USD(150), XRP(150'100));
-
620 env(offer(bob, XRP(100), USD(0.1)));
+
616 auto const jrr = ledgerEntryState(env, bob, gw, "USD");
+
617 // Bob pays 0.005 transfer fee. Note 10**-10 round-off.
+
618 BEAST_EXPECT(
+
619 jrr[jss::node][sfBalance.fieldName][jss::value] == "-0.8995000001");
+
620 }
+
621
-
622 BEAST_EXPECT(ammAlice.expectBalances(
-
623 USD(150.1), XRP(150'000), ammAlice.tokens()));
-
624
-
625 auto const jrr = ledgerEntryState(env, bob, gw, "USD");
-
626 // Bob pays 0.005 transfer fee. Note 10**-10 round-off.
-
627 BEAST_EXPECT(
-
628 jrr[jss::node][sfBalance.fieldName][jss::value] == "-0.8995000001");
-
629 }
-
-
630
-
631 void
-
- -
633 {
-
634 testcase("Offer tfSell: Basic Sell");
-
635
-
636 using namespace jtx;
-
637
-
638 testAMM(
-
639 [&](AMM& ammAlice, Env& env) {
-
640 env(offer(carol, USD(100), XRP(100)), json(jss::Flags, tfSell));
-
641 env.close();
-
642 BEAST_EXPECT(ammAlice.expectBalances(
-
643 XRP(10'000), USD(9'999), ammAlice.tokens()));
-
644 BEAST_EXPECT(expectOffers(env, carol, 0));
-
645 BEAST_EXPECT(expectHolding(env, carol, USD(30'101)));
-
646 BEAST_EXPECT(expectLedgerEntryRoot(
-
647 env, carol, XRP(30'000) - XRP(100) - txfee(env, 1)));
-
648 },
-
649 {{XRP(9'900), USD(10'100)}},
-
650 0,
- -
652 {features});
-
653 }
+
622 void
+
+ +
624 {
+
625 testcase("Offer tfSell: Basic Sell");
+
626
+
627 using namespace jtx;
+
628
+
629 testAMM(
+
630 [&](AMM& ammAlice, Env& env) {
+
631 env(offer(carol, USD(100), XRP(100)), json(jss::Flags, tfSell));
+
632 env.close();
+
633 BEAST_EXPECT(ammAlice.expectBalances(
+
634 XRP(10'000), USD(9'999), ammAlice.tokens()));
+
635 BEAST_EXPECT(expectOffers(env, carol, 0));
+
636 BEAST_EXPECT(expectHolding(env, carol, USD(30'101)));
+
637 BEAST_EXPECT(expectLedgerEntryRoot(
+
638 env, carol, XRP(30'000) - XRP(100) - txfee(env, 1)));
+
639 },
+
640 {{XRP(9'900), USD(10'100)}},
+
641 0,
+ +
643 {features});
+
644 }
+
645
+
646 void
+
+ +
648 {
+
649 testcase("Offer tfSell: 2x Sell Exceed Limit");
+
650
+
651 using namespace jtx;
+
652
+
653 Env env{*this, features};
654
-
655 void
-
- -
657 {
-
658 testcase("Offer tfSell: 2x Sell Exceed Limit");
-
659
-
660 using namespace jtx;
+
655 auto const starting_xrp =
+
656 XRP(100) + reserve(env, 1) + env.current()->fees().base * 2;
+
657
+
658 env.fund(starting_xrp, gw, alice);
+
659 env.fund(XRP(2'000), bob);
+
660 env.close();
661
-
662 Env env{*this, features};
-
663
-
664 auto const starting_xrp =
-
665 XRP(100) + reserve(env, 1) + env.current()->fees().base * 2;
+
662 env(trust(alice, USD(150)));
+
663 env(trust(bob, USD(4'000)));
+
664
+
665 env(pay(gw, bob, bob["USD"](2'200)));
666
-
667 env.fund(starting_xrp, gw, alice);
-
668 env.fund(XRP(2'000), bob);
-
669 env.close();
-
670
-
671 env(trust(alice, USD(150)));
-
672 env(trust(bob, USD(4'000)));
-
673
-
674 env(pay(gw, bob, bob["USD"](2'200)));
-
675
-
676 AMM ammBob(env, bob, XRP(1'000), USD(2'200));
-
677 // Alice has 350 fees - a reserve of 50 = 250 reserve = 100 available.
-
678 // Ask for more than available to prove reserve works.
-
679 // Taker pays 100 USD for 100 XRP.
-
680 // Selling XRP.
-
681 // Will sell all 100 XRP and get more USD than asked for.
-
682 env(offer(alice, USD(100), XRP(200)), json(jss::Flags, tfSell));
-
683 BEAST_EXPECT(
-
684 ammBob.expectBalances(XRP(1'100), USD(2'000), ammBob.tokens()));
-
685 BEAST_EXPECT(expectHolding(env, alice, USD(200)));
-
686 BEAST_EXPECT(expectLedgerEntryRoot(env, alice, XRP(250)));
-
687 BEAST_EXPECT(expectOffers(env, alice, 0));
-
688 }
+
667 AMM ammBob(env, bob, XRP(1'000), USD(2'200));
+
668 // Alice has 350 fees - a reserve of 50 = 250 reserve = 100 available.
+
669 // Ask for more than available to prove reserve works.
+
670 // Taker pays 100 USD for 100 XRP.
+
671 // Selling XRP.
+
672 // Will sell all 100 XRP and get more USD than asked for.
+
673 env(offer(alice, USD(100), XRP(200)), json(jss::Flags, tfSell));
+
674 BEAST_EXPECT(
+
675 ammBob.expectBalances(XRP(1'100), USD(2'000), ammBob.tokens()));
+
676 BEAST_EXPECT(expectHolding(env, alice, USD(200)));
+
677 BEAST_EXPECT(expectLedgerEntryRoot(env, alice, XRP(250)));
+
678 BEAST_EXPECT(expectOffers(env, alice, 0));
+
679 }
+
680
+
681 void
+
+ +
683 {
+
684 testcase("Client Issue: Gateway Cross Currency");
+
685
+
686 using namespace jtx;
+
687
+
688 Env env{*this, features};
689
-
690 void
-
- -
692 {
-
693 testcase("Client Issue: Gateway Cross Currency");
-
694
-
695 using namespace jtx;
-
696
-
697 Env env{*this, features};
-
698
-
699 auto const XTS = gw["XTS"];
-
700 auto const XXX = gw["XXX"];
-
701
-
702 auto const starting_xrp =
-
703 XRP(100.1) + reserve(env, 1) + env.current()->fees().base * 2;
-
704 fund(
-
705 env,
-
706 gw,
-
707 {alice, bob},
-
708 starting_xrp,
-
709 {XTS(100), XXX(100)},
-
710 Fund::All);
-
711
-
712 AMM ammAlice(env, alice, XTS(100), XXX(100));
-
713
-
714 Json::Value payment;
-
715 payment[jss::secret] = toBase58(generateSeed("bob"));
-
716 payment[jss::id] = env.seq(bob);
-
717 payment[jss::build_path] = true;
-
718 payment[jss::tx_json] = pay(bob, bob, bob["XXX"](1));
-
719 payment[jss::tx_json][jss::Sequence] =
-
720 env.current()
-
721 ->read(keylet::account(bob.id()))
-
722 ->getFieldU32(sfSequence);
-
723 payment[jss::tx_json][jss::Fee] = to_string(env.current()->fees().base);
-
724 payment[jss::tx_json][jss::SendMax] =
-
725 bob["XTS"](1.5).value().getJson(JsonOptions::none);
-
726 payment[jss::tx_json][jss::Flags] = tfPartialPayment;
-
727 auto const jrr = env.rpc("json", "submit", to_string(payment));
-
728 BEAST_EXPECT(jrr[jss::result][jss::status] == "success");
-
729 BEAST_EXPECT(jrr[jss::result][jss::engine_result] == "tesSUCCESS");
-
730 if (!features[fixAMMv1_1])
+
690 auto const XTS = gw["XTS"];
+
691 auto const XXX = gw["XXX"];
+
692
+
693 auto const starting_xrp =
+
694 XRP(100.1) + reserve(env, 1) + env.current()->fees().base * 2;
+
695 fund(
+
696 env,
+
697 gw,
+
698 {alice, bob},
+
699 starting_xrp,
+
700 {XTS(100), XXX(100)},
+
701 Fund::All);
+
702
+
703 AMM ammAlice(env, alice, XTS(100), XXX(100));
+
704
+
705 Json::Value payment;
+
706 payment[jss::secret] = toBase58(generateSeed("bob"));
+
707 payment[jss::id] = env.seq(bob);
+
708 payment[jss::build_path] = true;
+
709 payment[jss::tx_json] = pay(bob, bob, bob["XXX"](1));
+
710 payment[jss::tx_json][jss::Sequence] =
+
711 env.current()
+
712 ->read(keylet::account(bob.id()))
+
713 ->getFieldU32(sfSequence);
+
714 payment[jss::tx_json][jss::Fee] = to_string(env.current()->fees().base);
+
715 payment[jss::tx_json][jss::SendMax] =
+
716 bob["XTS"](1.5).value().getJson(JsonOptions::none);
+
717 payment[jss::tx_json][jss::Flags] = tfPartialPayment;
+
718 auto const jrr = env.rpc("json", "submit", to_string(payment));
+
719 BEAST_EXPECT(jrr[jss::result][jss::status] == "success");
+
720 BEAST_EXPECT(jrr[jss::result][jss::engine_result] == "tesSUCCESS");
+
721 if (!features[fixAMMv1_1])
+
722 {
+
723 BEAST_EXPECT(ammAlice.expectBalances(
+
724 STAmount(XTS, UINT64_C(101'010101010101), -12),
+
725 XXX(99),
+
726 ammAlice.tokens()));
+
727 BEAST_EXPECT(expectHolding(
+
728 env, bob, STAmount{XTS, UINT64_C(98'989898989899), -12}));
+
729 }
+
730 else
731 {
732 BEAST_EXPECT(ammAlice.expectBalances(
-
733 STAmount(XTS, UINT64_C(101'010101010101), -12),
+
733 STAmount(XTS, UINT64_C(101'0101010101011), -13),
734 XXX(99),
735 ammAlice.tokens()));
736 BEAST_EXPECT(expectHolding(
-
737 env, bob, STAmount{XTS, UINT64_C(98'989898989899), -12}));
+
737 env, bob, STAmount{XTS, UINT64_C(98'9898989898989), -13}));
738 }
-
739 else
-
740 {
-
741 BEAST_EXPECT(ammAlice.expectBalances(
-
742 STAmount(XTS, UINT64_C(101'0101010101011), -13),
-
743 XXX(99),
-
744 ammAlice.tokens()));
-
745 BEAST_EXPECT(expectHolding(
-
746 env, bob, STAmount{XTS, UINT64_C(98'9898989898989), -13}));
-
747 }
-
748 BEAST_EXPECT(expectHolding(env, bob, XXX(101)));
-
749 }
+
739 BEAST_EXPECT(expectHolding(env, bob, XXX(101)));
+
740 }
-
750
-
751 void
-
- -
753 {
-
754 testcase("Bridged Crossing");
-
755
-
756 using namespace jtx;
-
757
-
758 {
-
759 Env env{*this, features};
-
760
-
761 fund(
-
762 env,
-
763 gw,
-
764 {alice, bob, carol},
-
765 {USD(15'000), EUR(15'000)},
-
766 Fund::All);
+
741
+
742 void
+
+ +
744 {
+
745 testcase("Bridged Crossing");
+
746
+
747 using namespace jtx;
+
748
+
749 {
+
750 Env env{*this, features};
+
751
+
752 fund(
+
753 env,
+
754 gw,
+
755 {alice, bob, carol},
+
756 {USD(15'000), EUR(15'000)},
+
757 Fund::All);
+
758
+
759 // The scenario:
+
760 // o USD/XRP AMM is created.
+
761 // o EUR/XRP AMM is created.
+
762 // o carol has EUR but wants USD.
+
763 // Note that carol's offer must come last. If carol's offer is
+
764 // placed before AMM is created, then autobridging will not occur.
+
765 AMM ammAlice(env, alice, XRP(10'000), USD(10'100));
+
766 AMM ammBob(env, bob, EUR(10'000), XRP(10'100));
767
-
768 // The scenario:
-
769 // o USD/XRP AMM is created.
-
770 // o EUR/XRP AMM is created.
-
771 // o carol has EUR but wants USD.
-
772 // Note that carol's offer must come last. If carol's offer is
-
773 // placed before AMM is created, then autobridging will not occur.
-
774 AMM ammAlice(env, alice, XRP(10'000), USD(10'100));
-
775 AMM ammBob(env, bob, EUR(10'000), XRP(10'100));
-
776
-
777 // Carol makes an offer that consumes AMM liquidity and
-
778 // fully consumes Carol's offer.
-
779 env(offer(carol, USD(100), EUR(100)));
-
780 env.close();
+
768 // Carol makes an offer that consumes AMM liquidity and
+
769 // fully consumes Carol's offer.
+
770 env(offer(carol, USD(100), EUR(100)));
+
771 env.close();
+
772
+
773 BEAST_EXPECT(ammAlice.expectBalances(
+
774 XRP(10'100), USD(10'000), ammAlice.tokens()));
+
775 BEAST_EXPECT(ammBob.expectBalances(
+
776 XRP(10'000), EUR(10'100), ammBob.tokens()));
+
777 BEAST_EXPECT(expectHolding(env, carol, USD(15'100)));
+
778 BEAST_EXPECT(expectHolding(env, carol, EUR(14'900)));
+
779 BEAST_EXPECT(expectOffers(env, carol, 0));
+
780 }
781
-
782 BEAST_EXPECT(ammAlice.expectBalances(
-
783 XRP(10'100), USD(10'000), ammAlice.tokens()));
-
784 BEAST_EXPECT(ammBob.expectBalances(
-
785 XRP(10'000), EUR(10'100), ammBob.tokens()));
-
786 BEAST_EXPECT(expectHolding(env, carol, USD(15'100)));
-
787 BEAST_EXPECT(expectHolding(env, carol, EUR(14'900)));
-
788 BEAST_EXPECT(expectOffers(env, carol, 0));
-
789 }
-
790
-
791 {
-
792 Env env{*this, features};
-
793
-
794 fund(
-
795 env,
-
796 gw,
-
797 {alice, bob, carol},
-
798 {USD(15'000), EUR(15'000)},
-
799 Fund::All);
-
800
-
801 // The scenario:
-
802 // o USD/XRP AMM is created.
-
803 // o EUR/XRP offer is created.
-
804 // o carol has EUR but wants USD.
-
805 // Note that carol's offer must come last. If carol's offer is
-
806 // placed before AMM and bob's offer are created, then autobridging
-
807 // will not occur.
-
808 AMM ammAlice(env, alice, XRP(10'000), USD(10'100));
-
809 env(offer(bob, EUR(100), XRP(100)));
-
810 env.close();
-
811
-
812 // Carol makes an offer that consumes AMM liquidity and
-
813 // fully consumes Carol's offer.
-
814 env(offer(carol, USD(100), EUR(100)));
-
815 env.close();
-
816
-
817 BEAST_EXPECT(ammAlice.expectBalances(
-
818 XRP(10'100), USD(10'000), ammAlice.tokens()));
-
819 BEAST_EXPECT(expectHolding(env, carol, USD(15'100)));
-
820 BEAST_EXPECT(expectHolding(env, carol, EUR(14'900)));
-
821 BEAST_EXPECT(expectOffers(env, carol, 0));
-
822 BEAST_EXPECT(expectOffers(env, bob, 0));
-
823 }
-
824
-
825 {
-
826 Env env{*this, features};
-
827
-
828 fund(
-
829 env,
-
830 gw,
-
831 {alice, bob, carol},
-
832 {USD(15'000), EUR(15'000)},
-
833 Fund::All);
-
834
-
835 // The scenario:
-
836 // o USD/XRP offer is created.
-
837 // o EUR/XRP AMM is created.
-
838 // o carol has EUR but wants USD.
-
839 // Note that carol's offer must come last. If carol's offer is
-
840 // placed before AMM and alice's offer are created, then
-
841 // autobridging will not occur.
-
842 env(offer(alice, XRP(100), USD(100)));
-
843 env.close();
-
844 AMM ammBob(env, bob, EUR(10'000), XRP(10'100));
-
845
-
846 // Carol makes an offer that consumes AMM liquidity and
-
847 // fully consumes Carol's offer.
-
848 env(offer(carol, USD(100), EUR(100)));
-
849 env.close();
+
782 {
+
783 Env env{*this, features};
+
784
+
785 fund(
+
786 env,
+
787 gw,
+
788 {alice, bob, carol},
+
789 {USD(15'000), EUR(15'000)},
+
790 Fund::All);
+
791
+
792 // The scenario:
+
793 // o USD/XRP AMM is created.
+
794 // o EUR/XRP offer is created.
+
795 // o carol has EUR but wants USD.
+
796 // Note that carol's offer must come last. If carol's offer is
+
797 // placed before AMM and bob's offer are created, then autobridging
+
798 // will not occur.
+
799 AMM ammAlice(env, alice, XRP(10'000), USD(10'100));
+
800 env(offer(bob, EUR(100), XRP(100)));
+
801 env.close();
+
802
+
803 // Carol makes an offer that consumes AMM liquidity and
+
804 // fully consumes Carol's offer.
+
805 env(offer(carol, USD(100), EUR(100)));
+
806 env.close();
+
807
+
808 BEAST_EXPECT(ammAlice.expectBalances(
+
809 XRP(10'100), USD(10'000), ammAlice.tokens()));
+
810 BEAST_EXPECT(expectHolding(env, carol, USD(15'100)));
+
811 BEAST_EXPECT(expectHolding(env, carol, EUR(14'900)));
+
812 BEAST_EXPECT(expectOffers(env, carol, 0));
+
813 BEAST_EXPECT(expectOffers(env, bob, 0));
+
814 }
+
815
+
816 {
+
817 Env env{*this, features};
+
818
+
819 fund(
+
820 env,
+
821 gw,
+
822 {alice, bob, carol},
+
823 {USD(15'000), EUR(15'000)},
+
824 Fund::All);
+
825
+
826 // The scenario:
+
827 // o USD/XRP offer is created.
+
828 // o EUR/XRP AMM is created.
+
829 // o carol has EUR but wants USD.
+
830 // Note that carol's offer must come last. If carol's offer is
+
831 // placed before AMM and alice's offer are created, then
+
832 // autobridging will not occur.
+
833 env(offer(alice, XRP(100), USD(100)));
+
834 env.close();
+
835 AMM ammBob(env, bob, EUR(10'000), XRP(10'100));
+
836
+
837 // Carol makes an offer that consumes AMM liquidity and
+
838 // fully consumes Carol's offer.
+
839 env(offer(carol, USD(100), EUR(100)));
+
840 env.close();
+
841
+
842 BEAST_EXPECT(ammBob.expectBalances(
+
843 XRP(10'000), EUR(10'100), ammBob.tokens()));
+
844 BEAST_EXPECT(expectHolding(env, carol, USD(15'100)));
+
845 BEAST_EXPECT(expectHolding(env, carol, EUR(14'900)));
+
846 BEAST_EXPECT(expectOffers(env, carol, 0));
+
847 BEAST_EXPECT(expectOffers(env, alice, 0));
+
848 }
+
849 }
+
850
-
851 BEAST_EXPECT(ammBob.expectBalances(
-
852 XRP(10'000), EUR(10'100), ammBob.tokens()));
-
853 BEAST_EXPECT(expectHolding(env, carol, USD(15'100)));
-
854 BEAST_EXPECT(expectHolding(env, carol, EUR(14'900)));
-
855 BEAST_EXPECT(expectOffers(env, carol, 0));
-
856 BEAST_EXPECT(expectOffers(env, alice, 0));
-
857 }
-
858 }
-
+
851 void
+
+ +
853 {
+
854 // Test a number of different corner cases regarding offer crossing
+
855 // when both the tfSell flag and tfFillOrKill flags are set.
+
856 testcase("Combine tfSell with tfFillOrKill");
+
857
+
858 using namespace jtx;
859
-
860 void
-
- -
862 {
-
863 // Test a number of different corner cases regarding offer crossing
-
864 // when both the tfSell flag and tfFillOrKill flags are set.
-
865 testcase("Combine tfSell with tfFillOrKill");
-
866
-
867 using namespace jtx;
-
868
-
869 // Code returned if an offer is killed.
-
870 TER const killedCode{
-
871 features[fix1578] ? TER{tecKILLED} : TER{tesSUCCESS}};
-
872
-
873 {
-
874 Env env{*this, features};
-
875 fund(env, gw, {alice, bob}, {USD(20'000)}, Fund::All);
-
876 AMM ammBob(env, bob, XRP(20'000), USD(200));
-
877 // alice submits a tfSell | tfFillOrKill offer that does not cross.
-
878 env(offer(alice, USD(2.1), XRP(210), tfSell | tfFillOrKill),
-
879 ter(killedCode));
-
880
-
881 BEAST_EXPECT(
-
882 ammBob.expectBalances(XRP(20'000), USD(200), ammBob.tokens()));
-
883 BEAST_EXPECT(expectOffers(env, bob, 0));
-
884 }
-
885 {
-
886 Env env{*this, features};
-
887 fund(env, gw, {alice, bob}, {USD(1'000)}, Fund::All);
-
888 AMM ammBob(env, bob, XRP(20'000), USD(200));
-
889 // alice submits a tfSell | tfFillOrKill offer that crosses.
-
890 // Even though tfSell is present it doesn't matter this time.
-
891 env(offer(alice, USD(2), XRP(220), tfSell | tfFillOrKill));
-
892 env.close();
-
893 BEAST_EXPECT(ammBob.expectBalances(
-
894 XRP(20'220),
-
895 STAmount{USD, UINT64_C(197'8239366963403), -13},
-
896 ammBob.tokens()));
-
897 BEAST_EXPECT(expectHolding(
-
898 env, alice, STAmount{USD, UINT64_C(1'002'17606330366), -11}));
-
899 BEAST_EXPECT(expectOffers(env, alice, 0));
-
900 }
-
901 {
-
902 // alice submits a tfSell | tfFillOrKill offer that crosses and
-
903 // returns more than was asked for (because of the tfSell flag).
-
904 Env env{*this, features};
-
905 fund(env, gw, {alice, bob}, {USD(1'000)}, Fund::All);
-
906 AMM ammBob(env, bob, XRP(20'000), USD(200));
-
907
-
908 env(offer(alice, USD(10), XRP(1'500), tfSell | tfFillOrKill));
-
909 env.close();
-
910
-
911 BEAST_EXPECT(ammBob.expectBalances(
-
912 XRP(21'500),
-
913 STAmount{USD, UINT64_C(186'046511627907), -12},
-
914 ammBob.tokens()));
-
915 BEAST_EXPECT(expectHolding(
-
916 env, alice, STAmount{USD, UINT64_C(1'013'953488372093), -12}));
-
917 BEAST_EXPECT(expectOffers(env, alice, 0));
-
918 }
-
919 {
-
920 // alice submits a tfSell | tfFillOrKill offer that doesn't cross.
-
921 // This would have succeeded with a regular tfSell, but the
-
922 // fillOrKill prevents the transaction from crossing since not
-
923 // all of the offer is consumed because AMM generated offer,
-
924 // which matches alice's offer quality is ~ 10XRP/0.01996USD.
-
925 Env env{*this, features};
-
926 fund(env, gw, {alice, bob}, {USD(10'000)}, Fund::All);
-
927 AMM ammBob(env, bob, XRP(5000), USD(10));
-
928
-
929 env(offer(alice, USD(1), XRP(501), tfSell | tfFillOrKill),
-
930 ter(tecKILLED));
-
931 env.close();
-
932 BEAST_EXPECT(expectOffers(env, alice, 0));
-
933 BEAST_EXPECT(expectOffers(env, bob, 0));
-
934 }
-
935 }
+
860 // Code returned if an offer is killed.
+
861 TER const killedCode{TER{tecKILLED}};
+
862
+
863 {
+
864 Env env{*this, features};
+
865 fund(env, gw, {alice, bob}, {USD(20'000)}, Fund::All);
+
866 AMM ammBob(env, bob, XRP(20'000), USD(200));
+
867 // alice submits a tfSell | tfFillOrKill offer that does not cross.
+
868 env(offer(alice, USD(2.1), XRP(210), tfSell | tfFillOrKill),
+
869 ter(killedCode));
+
870
+
871 BEAST_EXPECT(
+
872 ammBob.expectBalances(XRP(20'000), USD(200), ammBob.tokens()));
+
873 BEAST_EXPECT(expectOffers(env, bob, 0));
+
874 }
+
875 {
+
876 Env env{*this, features};
+
877 fund(env, gw, {alice, bob}, {USD(1'000)}, Fund::All);
+
878 AMM ammBob(env, bob, XRP(20'000), USD(200));
+
879 // alice submits a tfSell | tfFillOrKill offer that crosses.
+
880 // Even though tfSell is present it doesn't matter this time.
+
881 env(offer(alice, USD(2), XRP(220), tfSell | tfFillOrKill));
+
882 env.close();
+
883 BEAST_EXPECT(ammBob.expectBalances(
+
884 XRP(20'220),
+
885 STAmount{USD, UINT64_C(197'8239366963403), -13},
+
886 ammBob.tokens()));
+
887 BEAST_EXPECT(expectHolding(
+
888 env, alice, STAmount{USD, UINT64_C(1'002'17606330366), -11}));
+
889 BEAST_EXPECT(expectOffers(env, alice, 0));
+
890 }
+
891 {
+
892 // alice submits a tfSell | tfFillOrKill offer that crosses and
+
893 // returns more than was asked for (because of the tfSell flag).
+
894 Env env{*this, features};
+
895 fund(env, gw, {alice, bob}, {USD(1'000)}, Fund::All);
+
896 AMM ammBob(env, bob, XRP(20'000), USD(200));
+
897
+
898 env(offer(alice, USD(10), XRP(1'500), tfSell | tfFillOrKill));
+
899 env.close();
+
900
+
901 BEAST_EXPECT(ammBob.expectBalances(
+
902 XRP(21'500),
+
903 STAmount{USD, UINT64_C(186'046511627907), -12},
+
904 ammBob.tokens()));
+
905 BEAST_EXPECT(expectHolding(
+
906 env, alice, STAmount{USD, UINT64_C(1'013'953488372093), -12}));
+
907 BEAST_EXPECT(expectOffers(env, alice, 0));
+
908 }
+
909 {
+
910 // alice submits a tfSell | tfFillOrKill offer that doesn't cross.
+
911 // This would have succeeded with a regular tfSell, but the
+
912 // fillOrKill prevents the transaction from crossing since not
+
913 // all of the offer is consumed because AMM generated offer,
+
914 // which matches alice's offer quality is ~ 10XRP/0.01996USD.
+
915 Env env{*this, features};
+
916 fund(env, gw, {alice, bob}, {USD(10'000)}, Fund::All);
+
917 AMM ammBob(env, bob, XRP(5000), USD(10));
+
918
+
919 env(offer(alice, USD(1), XRP(501), tfSell | tfFillOrKill),
+
920 ter(tecKILLED));
+
921 env.close();
+
922 BEAST_EXPECT(expectOffers(env, alice, 0));
+
923 BEAST_EXPECT(expectOffers(env, bob, 0));
+
924 }
+
925 }
-
936
-
937 void
-
- -
939 {
-
940 testcase("Transfer Rate Offer");
-
941
-
942 using namespace jtx;
-
943
-
944 // AMM XRP/USD. Alice places USD/XRP offer.
-
945 testAMM(
-
946 [&](AMM& ammAlice, Env& env) {
-
947 env(rate(gw, 1.25));
-
948 env.close();
-
949
-
950 env(offer(carol, USD(100), XRP(100)));
-
951 env.close();
-
952
-
953 // AMM doesn't pay the transfer fee
-
954 BEAST_EXPECT(ammAlice.expectBalances(
-
955 XRP(10'100), USD(10'000), ammAlice.tokens()));
-
956 BEAST_EXPECT(expectHolding(env, carol, USD(30'100)));
-
957 BEAST_EXPECT(expectOffers(env, carol, 0));
-
958 },
-
959 {{XRP(10'000), USD(10'100)}},
-
960 0,
- -
962 {features});
+
926
+
927 void
+
+ +
929 {
+
930 testcase("Transfer Rate Offer");
+
931
+
932 using namespace jtx;
+
933
+
934 // AMM XRP/USD. Alice places USD/XRP offer.
+
935 testAMM(
+
936 [&](AMM& ammAlice, Env& env) {
+
937 env(rate(gw, 1.25));
+
938 env.close();
+
939
+
940 env(offer(carol, USD(100), XRP(100)));
+
941 env.close();
+
942
+
943 // AMM doesn't pay the transfer fee
+
944 BEAST_EXPECT(ammAlice.expectBalances(
+
945 XRP(10'100), USD(10'000), ammAlice.tokens()));
+
946 BEAST_EXPECT(expectHolding(env, carol, USD(30'100)));
+
947 BEAST_EXPECT(expectOffers(env, carol, 0));
+
948 },
+
949 {{XRP(10'000), USD(10'100)}},
+
950 0,
+ +
952 {features});
+
953
+
954 // Reverse the order, so the offer in the books is to sell XRP
+
955 // in return for USD.
+
956 testAMM(
+
957 [&](AMM& ammAlice, Env& env) {
+
958 env(rate(gw, 1.25));
+
959 env.close();
+
960
+
961 env(offer(carol, XRP(100), USD(100)));
+
962 env.close();
963
-
964 // Reverse the order, so the offer in the books is to sell XRP
-
965 // in return for USD.
-
966 testAMM(
-
967 [&](AMM& ammAlice, Env& env) {
-
968 env(rate(gw, 1.25));
-
969 env.close();
-
970
-
971 env(offer(carol, XRP(100), USD(100)));
-
972 env.close();
-
973
-
974 BEAST_EXPECT(ammAlice.expectBalances(
-
975 XRP(10'000), USD(10'100), ammAlice.tokens()));
-
976 // Carol pays 25% transfer fee
-
977 BEAST_EXPECT(expectHolding(env, carol, USD(29'875)));
-
978 BEAST_EXPECT(expectOffers(env, carol, 0));
-
979 },
-
980 {{XRP(10'100), USD(10'000)}},
-
981 0,
- -
983 {features});
-
984
-
985 {
-
986 // Bridged crossing.
-
987 Env env{*this, features};
-
988 fund(
-
989 env,
-
990 gw,
-
991 {alice, bob, carol},
-
992 {USD(15'000), EUR(15'000)},
-
993 Fund::All);
-
994 env(rate(gw, 1.25));
+
964 BEAST_EXPECT(ammAlice.expectBalances(
+
965 XRP(10'000), USD(10'100), ammAlice.tokens()));
+
966 // Carol pays 25% transfer fee
+
967 BEAST_EXPECT(expectHolding(env, carol, USD(29'875)));
+
968 BEAST_EXPECT(expectOffers(env, carol, 0));
+
969 },
+
970 {{XRP(10'100), USD(10'000)}},
+
971 0,
+ +
973 {features});
+
974
+
975 {
+
976 // Bridged crossing.
+
977 Env env{*this, features};
+
978 fund(
+
979 env,
+
980 gw,
+
981 {alice, bob, carol},
+
982 {USD(15'000), EUR(15'000)},
+
983 Fund::All);
+
984 env(rate(gw, 1.25));
+
985
+
986 // The scenario:
+
987 // o USD/XRP AMM is created.
+
988 // o EUR/XRP Offer is created.
+
989 // o carol has EUR but wants USD.
+
990 // Note that Carol's offer must come last. If Carol's offer is
+
991 // placed before AMM is created, then autobridging will not occur.
+
992 AMM ammAlice(env, alice, XRP(10'000), USD(10'100));
+
993 env(offer(bob, EUR(100), XRP(100)));
+
994 env.close();
995
-
996 // The scenario:
-
997 // o USD/XRP AMM is created.
-
998 // o EUR/XRP Offer is created.
-
999 // o carol has EUR but wants USD.
-
1000 // Note that Carol's offer must come last. If Carol's offer is
-
1001 // placed before AMM is created, then autobridging will not occur.
-
1002 AMM ammAlice(env, alice, XRP(10'000), USD(10'100));
-
1003 env(offer(bob, EUR(100), XRP(100)));
-
1004 env.close();
-
1005
-
1006 // Carol makes an offer that consumes AMM liquidity and
-
1007 // fully consumes Bob's offer.
-
1008 env(offer(carol, USD(100), EUR(100)));
-
1009 env.close();
+
996 // Carol makes an offer that consumes AMM liquidity and
+
997 // fully consumes Bob's offer.
+
998 env(offer(carol, USD(100), EUR(100)));
+
999 env.close();
+
1000
+
1001 // AMM doesn't pay the transfer fee
+
1002 BEAST_EXPECT(ammAlice.expectBalances(
+
1003 XRP(10'100), USD(10'000), ammAlice.tokens()));
+
1004 BEAST_EXPECT(expectHolding(env, carol, USD(15'100)));
+
1005 // Carol pays 25% transfer fee.
+
1006 BEAST_EXPECT(expectHolding(env, carol, EUR(14'875)));
+
1007 BEAST_EXPECT(expectOffers(env, carol, 0));
+
1008 BEAST_EXPECT(expectOffers(env, bob, 0));
+
1009 }
1010
-
1011 // AMM doesn't pay the transfer fee
-
1012 BEAST_EXPECT(ammAlice.expectBalances(
-
1013 XRP(10'100), USD(10'000), ammAlice.tokens()));
-
1014 BEAST_EXPECT(expectHolding(env, carol, USD(15'100)));
-
1015 // Carol pays 25% transfer fee.
-
1016 BEAST_EXPECT(expectHolding(env, carol, EUR(14'875)));
-
1017 BEAST_EXPECT(expectOffers(env, carol, 0));
-
1018 BEAST_EXPECT(expectOffers(env, bob, 0));
-
1019 }
-
1020
-
1021 {
-
1022 // Bridged crossing. The transfer fee is paid on the step not
-
1023 // involving AMM as src/dst.
-
1024 Env env{*this, features};
-
1025 fund(
-
1026 env,
-
1027 gw,
-
1028 {alice, bob, carol},
-
1029 {USD(15'000), EUR(15'000)},
-
1030 Fund::All);
-
1031 env(rate(gw, 1.25));
+
1011 {
+
1012 // Bridged crossing. The transfer fee is paid on the step not
+
1013 // involving AMM as src/dst.
+
1014 Env env{*this, features};
+
1015 fund(
+
1016 env,
+
1017 gw,
+
1018 {alice, bob, carol},
+
1019 {USD(15'000), EUR(15'000)},
+
1020 Fund::All);
+
1021 env(rate(gw, 1.25));
+
1022
+
1023 // The scenario:
+
1024 // o USD/XRP AMM is created.
+
1025 // o EUR/XRP Offer is created.
+
1026 // o carol has EUR but wants USD.
+
1027 // Note that Carol's offer must come last. If Carol's offer is
+
1028 // placed before AMM is created, then autobridging will not occur.
+
1029 AMM ammAlice(env, alice, XRP(10'000), USD(10'050));
+
1030 env(offer(bob, EUR(100), XRP(100)));
+
1031 env.close();
1032
-
1033 // The scenario:
-
1034 // o USD/XRP AMM is created.
-
1035 // o EUR/XRP Offer is created.
-
1036 // o carol has EUR but wants USD.
-
1037 // Note that Carol's offer must come last. If Carol's offer is
-
1038 // placed before AMM is created, then autobridging will not occur.
-
1039 AMM ammAlice(env, alice, XRP(10'000), USD(10'050));
-
1040 env(offer(bob, EUR(100), XRP(100)));
-
1041 env.close();
-
1042
-
1043 // Carol makes an offer that consumes AMM liquidity and
-
1044 // partially consumes Bob's offer.
-
1045 env(offer(carol, USD(50), EUR(50)));
-
1046 env.close();
-
1047 // This test verifies that the amount removed from an offer
-
1048 // accounts for the transfer fee that is removed from the
-
1049 // account but not from the remaining offer.
-
1050
-
1051 // AMM doesn't pay the transfer fee
-
1052 BEAST_EXPECT(ammAlice.expectBalances(
-
1053 XRP(10'050), USD(10'000), ammAlice.tokens()));
-
1054 BEAST_EXPECT(expectHolding(env, carol, USD(15'050)));
-
1055 // Carol pays 25% transfer fee.
-
1056 BEAST_EXPECT(expectHolding(env, carol, EUR(14'937.5)));
-
1057 BEAST_EXPECT(expectOffers(env, carol, 0));
-
1058 BEAST_EXPECT(
-
1059 expectOffers(env, bob, 1, {{Amounts{EUR(50), XRP(50)}}}));
-
1060 }
-
1061
-
1062 {
-
1063 // A trust line's QualityIn should not affect offer crossing.
-
1064 // Bridged crossing. The transfer fee is paid on the step not
-
1065 // involving AMM as src/dst.
-
1066 Env env{*this, features};
-
1067 fund(env, gw, {alice, carol, bob}, XRP(30'000));
-
1068 env(rate(gw, 1.25));
-
1069 env(trust(alice, USD(15'000)));
-
1070 env(trust(bob, EUR(15'000)));
-
1071 env(trust(carol, EUR(15'000)), qualityInPercent(80));
-
1072 env(trust(bob, USD(15'000)));
-
1073 env(trust(carol, USD(15'000)));
-
1074 env.close();
-
1075
-
1076 env(pay(gw, alice, USD(11'000)));
-
1077 env(pay(gw, carol, EUR(1'000)), sendmax(EUR(10'000)));
-
1078 env.close();
-
1079 // 1000 / 0.8
-
1080 BEAST_EXPECT(expectHolding(env, carol, EUR(1'250)));
-
1081 // The scenario:
-
1082 // o USD/XRP AMM is created.
-
1083 // o EUR/XRP Offer is created.
-
1084 // o carol has EUR but wants USD.
-
1085 // Note that Carol's offer must come last. If Carol's offer is
-
1086 // placed before AMM is created, then autobridging will not occur.
-
1087 AMM ammAlice(env, alice, XRP(10'000), USD(10'100));
-
1088 env(offer(bob, EUR(100), XRP(100)));
-
1089 env.close();
-
1090
-
1091 // Carol makes an offer that consumes AMM liquidity and
-
1092 // fully consumes Bob's offer.
-
1093 env(offer(carol, USD(100), EUR(100)));
-
1094 env.close();
+
1033 // Carol makes an offer that consumes AMM liquidity and
+
1034 // partially consumes Bob's offer.
+
1035 env(offer(carol, USD(50), EUR(50)));
+
1036 env.close();
+
1037 // This test verifies that the amount removed from an offer
+
1038 // accounts for the transfer fee that is removed from the
+
1039 // account but not from the remaining offer.
+
1040
+
1041 // AMM doesn't pay the transfer fee
+
1042 BEAST_EXPECT(ammAlice.expectBalances(
+
1043 XRP(10'050), USD(10'000), ammAlice.tokens()));
+
1044 BEAST_EXPECT(expectHolding(env, carol, USD(15'050)));
+
1045 // Carol pays 25% transfer fee.
+
1046 BEAST_EXPECT(expectHolding(env, carol, EUR(14'937.5)));
+
1047 BEAST_EXPECT(expectOffers(env, carol, 0));
+
1048 BEAST_EXPECT(
+
1049 expectOffers(env, bob, 1, {{Amounts{EUR(50), XRP(50)}}}));
+
1050 }
+
1051
+
1052 {
+
1053 // A trust line's QualityIn should not affect offer crossing.
+
1054 // Bridged crossing. The transfer fee is paid on the step not
+
1055 // involving AMM as src/dst.
+
1056 Env env{*this, features};
+
1057 fund(env, gw, {alice, carol, bob}, XRP(30'000));
+
1058 env(rate(gw, 1.25));
+
1059 env(trust(alice, USD(15'000)));
+
1060 env(trust(bob, EUR(15'000)));
+
1061 env(trust(carol, EUR(15'000)), qualityInPercent(80));
+
1062 env(trust(bob, USD(15'000)));
+
1063 env(trust(carol, USD(15'000)));
+
1064 env.close();
+
1065
+
1066 env(pay(gw, alice, USD(11'000)));
+
1067 env(pay(gw, carol, EUR(1'000)), sendmax(EUR(10'000)));
+
1068 env.close();
+
1069 // 1000 / 0.8
+
1070 BEAST_EXPECT(expectHolding(env, carol, EUR(1'250)));
+
1071 // The scenario:
+
1072 // o USD/XRP AMM is created.
+
1073 // o EUR/XRP Offer is created.
+
1074 // o carol has EUR but wants USD.
+
1075 // Note that Carol's offer must come last. If Carol's offer is
+
1076 // placed before AMM is created, then autobridging will not occur.
+
1077 AMM ammAlice(env, alice, XRP(10'000), USD(10'100));
+
1078 env(offer(bob, EUR(100), XRP(100)));
+
1079 env.close();
+
1080
+
1081 // Carol makes an offer that consumes AMM liquidity and
+
1082 // fully consumes Bob's offer.
+
1083 env(offer(carol, USD(100), EUR(100)));
+
1084 env.close();
+
1085
+
1086 // AMM doesn't pay the transfer fee
+
1087 BEAST_EXPECT(ammAlice.expectBalances(
+
1088 XRP(10'100), USD(10'000), ammAlice.tokens()));
+
1089 BEAST_EXPECT(expectHolding(env, carol, USD(100)));
+
1090 // Carol pays 25% transfer fee: 1250 - 100(offer) - 25(transfer fee)
+
1091 BEAST_EXPECT(expectHolding(env, carol, EUR(1'125)));
+
1092 BEAST_EXPECT(expectOffers(env, carol, 0));
+
1093 BEAST_EXPECT(expectOffers(env, bob, 0));
+
1094 }
1095
-
1096 // AMM doesn't pay the transfer fee
-
1097 BEAST_EXPECT(ammAlice.expectBalances(
-
1098 XRP(10'100), USD(10'000), ammAlice.tokens()));
-
1099 BEAST_EXPECT(expectHolding(env, carol, USD(100)));
-
1100 // Carol pays 25% transfer fee: 1250 - 100(offer) - 25(transfer fee)
-
1101 BEAST_EXPECT(expectHolding(env, carol, EUR(1'125)));
-
1102 BEAST_EXPECT(expectOffers(env, carol, 0));
-
1103 BEAST_EXPECT(expectOffers(env, bob, 0));
-
1104 }
-
1105
-
1106 {
-
1107 // A trust line's QualityOut should not affect offer crossing.
-
1108 // Bridged crossing. The transfer fee is paid on the step not
-
1109 // involving AMM as src/dst.
-
1110 Env env{*this, features};
-
1111 fund(env, gw, {alice, carol, bob}, XRP(30'000));
-
1112 env(rate(gw, 1.25));
-
1113 env(trust(alice, USD(15'000)));
-
1114 env(trust(bob, EUR(15'000)));
-
1115 env(trust(carol, EUR(15'000)), qualityOutPercent(120));
-
1116 env(trust(bob, USD(15'000)));
-
1117 env(trust(carol, USD(15'000)));
-
1118 env.close();
-
1119
-
1120 env(pay(gw, alice, USD(11'000)));
-
1121 env(pay(gw, carol, EUR(1'000)), sendmax(EUR(10'000)));
+
1096 {
+
1097 // A trust line's QualityOut should not affect offer crossing.
+
1098 // Bridged crossing. The transfer fee is paid on the step not
+
1099 // involving AMM as src/dst.
+
1100 Env env{*this, features};
+
1101 fund(env, gw, {alice, carol, bob}, XRP(30'000));
+
1102 env(rate(gw, 1.25));
+
1103 env(trust(alice, USD(15'000)));
+
1104 env(trust(bob, EUR(15'000)));
+
1105 env(trust(carol, EUR(15'000)), qualityOutPercent(120));
+
1106 env(trust(bob, USD(15'000)));
+
1107 env(trust(carol, USD(15'000)));
+
1108 env.close();
+
1109
+
1110 env(pay(gw, alice, USD(11'000)));
+
1111 env(pay(gw, carol, EUR(1'000)), sendmax(EUR(10'000)));
+
1112 env.close();
+
1113 BEAST_EXPECT(expectHolding(env, carol, EUR(1'000)));
+
1114 // The scenario:
+
1115 // o USD/XRP AMM is created.
+
1116 // o EUR/XRP Offer is created.
+
1117 // o carol has EUR but wants USD.
+
1118 // Note that Carol's offer must come last. If Carol's offer is
+
1119 // placed before AMM is created, then autobridging will not occur.
+
1120 AMM ammAlice(env, alice, XRP(10'000), USD(10'100));
+
1121 env(offer(bob, EUR(100), XRP(100)));
1122 env.close();
-
1123 BEAST_EXPECT(expectHolding(env, carol, EUR(1'000)));
-
1124 // The scenario:
-
1125 // o USD/XRP AMM is created.
-
1126 // o EUR/XRP Offer is created.
-
1127 // o carol has EUR but wants USD.
-
1128 // Note that Carol's offer must come last. If Carol's offer is
-
1129 // placed before AMM is created, then autobridging will not occur.
-
1130 AMM ammAlice(env, alice, XRP(10'000), USD(10'100));
-
1131 env(offer(bob, EUR(100), XRP(100)));
-
1132 env.close();
-
1133
-
1134 // Carol makes an offer that consumes AMM liquidity and
-
1135 // fully consumes Bob's offer.
-
1136 env(offer(carol, USD(100), EUR(100)));
-
1137 env.close();
-
1138
-
1139 // AMM pay doesn't transfer fee
-
1140 BEAST_EXPECT(ammAlice.expectBalances(
-
1141 XRP(10'100), USD(10'000), ammAlice.tokens()));
-
1142 BEAST_EXPECT(expectHolding(env, carol, USD(100)));
-
1143 // Carol pays 25% transfer fee: 1000 - 100(offer) - 25(transfer fee)
-
1144 BEAST_EXPECT(expectHolding(env, carol, EUR(875)));
-
1145 BEAST_EXPECT(expectOffers(env, carol, 0));
-
1146 BEAST_EXPECT(expectOffers(env, bob, 0));
-
1147 }
-
1148 }
+
1123
+
1124 // Carol makes an offer that consumes AMM liquidity and
+
1125 // fully consumes Bob's offer.
+
1126 env(offer(carol, USD(100), EUR(100)));
+
1127 env.close();
+
1128
+
1129 // AMM pay doesn't transfer fee
+
1130 BEAST_EXPECT(ammAlice.expectBalances(
+
1131 XRP(10'100), USD(10'000), ammAlice.tokens()));
+
1132 BEAST_EXPECT(expectHolding(env, carol, USD(100)));
+
1133 // Carol pays 25% transfer fee: 1000 - 100(offer) - 25(transfer fee)
+
1134 BEAST_EXPECT(expectHolding(env, carol, EUR(875)));
+
1135 BEAST_EXPECT(expectOffers(env, carol, 0));
+
1136 BEAST_EXPECT(expectOffers(env, bob, 0));
+
1137 }
+
1138 }
+
1139
+
1140 void
+
+ +
1142 {
+
1143 // This test is not the same as corresponding testSelfIssueOffer()
+
1144 // in the Offer_test. It simply tests AMM with self issue and
+
1145 // offer crossing.
+
1146 using namespace jtx;
+
1147
+
1148 Env env{*this, features};
1149
-
1150 void
-
- -
1152 {
-
1153 // This test is not the same as corresponding testSelfIssueOffer()
-
1154 // in the Offer_test. It simply tests AMM with self issue and
-
1155 // offer crossing.
-
1156 using namespace jtx;
-
1157
-
1158 Env env{*this, features};
+
1150 auto const USD_bob = bob["USD"];
+
1151 auto const f = env.current()->fees().base;
+
1152
+
1153 env.fund(XRP(30'000) + f, alice, bob);
+
1154 env.close();
+
1155 AMM ammBob(env, bob, XRP(10'000), USD_bob(10'100));
+
1156
+
1157 env(offer(alice, USD_bob(100), XRP(100)));
+
1158 env.close();
1159
-
1160 auto const USD_bob = bob["USD"];
-
1161 auto const f = env.current()->fees().base;
-
1162
-
1163 env.fund(XRP(30'000) + f, alice, bob);
-
1164 env.close();
-
1165 AMM ammBob(env, bob, XRP(10'000), USD_bob(10'100));
-
1166
-
1167 env(offer(alice, USD_bob(100), XRP(100)));
-
1168 env.close();
-
1169
-
1170 BEAST_EXPECT(ammBob.expectBalances(
-
1171 XRP(10'100), USD_bob(10'000), ammBob.tokens()));
-
1172 BEAST_EXPECT(expectOffers(env, alice, 0));
-
1173 BEAST_EXPECT(expectHolding(env, alice, USD_bob(100)));
-
1174 }
+
1160 BEAST_EXPECT(ammBob.expectBalances(
+
1161 XRP(10'100), USD_bob(10'000), ammBob.tokens()));
+
1162 BEAST_EXPECT(expectOffers(env, alice, 0));
+
1163 BEAST_EXPECT(expectHolding(env, alice, USD_bob(100)));
+
1164 }
+
1165
+
1166 void
+
+ +
1168 {
+
1169 // At one point in the past this invalid path caused assert. It
+
1170 // should not be possible for user-supplied data to cause assert.
+
1171 // Make sure assert is gone.
+
1172 testcase("Bad path assert");
+
1173
+
1174 using namespace jtx;
1175
-
1176 void
-
- -
1178 {
-
1179 // At one point in the past this invalid path caused assert. It
-
1180 // should not be possible for user-supplied data to cause assert.
-
1181 // Make sure assert is gone.
-
1182 testcase("Bad path assert");
-
1183
-
1184 using namespace jtx;
-
1185
-
1186 Env env{*this, features};
-
1187
-
1188 // The fee that's charged for transactions.
-
1189 auto const fee = env.current()->fees().base;
-
1190 {
-
1191 // A trust line's QualityOut should not affect offer crossing.
-
1192 auto const ann = Account("ann");
-
1193 auto const A_BUX = ann["BUX"];
-
1194 auto const bob = Account("bob");
-
1195 auto const cam = Account("cam");
-
1196 auto const dan = Account("dan");
-
1197 auto const D_BUX = dan["BUX"];
-
1198
-
1199 // Verify trust line QualityOut affects payments.
-
1200 env.fund(reserve(env, 4) + (fee * 4), ann, bob, cam, dan);
-
1201 env.close();
-
1202
-
1203 env(trust(bob, A_BUX(400)));
-
1204 env(trust(bob, D_BUX(200)), qualityOutPercent(120));
-
1205 env(trust(cam, D_BUX(100)));
-
1206 env.close();
-
1207 env(pay(dan, bob, D_BUX(100)));
-
1208 env.close();
-
1209 BEAST_EXPECT(expectHolding(env, bob, D_BUX(100)));
-
1210
-
1211 env(pay(ann, cam, D_BUX(60)), path(bob, dan), sendmax(A_BUX(200)));
-
1212 env.close();
-
1213
-
1214 BEAST_EXPECT(expectHolding(env, ann, A_BUX(none)));
-
1215 BEAST_EXPECT(expectHolding(env, ann, D_BUX(none)));
-
1216 BEAST_EXPECT(expectHolding(env, bob, A_BUX(72)));
-
1217 BEAST_EXPECT(expectHolding(env, bob, D_BUX(40)));
-
1218 BEAST_EXPECT(expectHolding(env, cam, A_BUX(none)));
-
1219 BEAST_EXPECT(expectHolding(env, cam, D_BUX(60)));
-
1220 BEAST_EXPECT(expectHolding(env, dan, A_BUX(none)));
-
1221 BEAST_EXPECT(expectHolding(env, dan, D_BUX(none)));
-
1222
-
1223 AMM ammBob(env, bob, A_BUX(30), D_BUX(30));
+
1176 Env env{*this, features};
+
1177
+
1178 // The fee that's charged for transactions.
+
1179 auto const fee = env.current()->fees().base;
+
1180 {
+
1181 // A trust line's QualityOut should not affect offer crossing.
+
1182 auto const ann = Account("ann");
+
1183 auto const A_BUX = ann["BUX"];
+
1184 auto const bob = Account("bob");
+
1185 auto const cam = Account("cam");
+
1186 auto const dan = Account("dan");
+
1187 auto const D_BUX = dan["BUX"];
+
1188
+
1189 // Verify trust line QualityOut affects payments.
+
1190 env.fund(reserve(env, 4) + (fee * 4), ann, bob, cam, dan);
+
1191 env.close();
+
1192
+
1193 env(trust(bob, A_BUX(400)));
+
1194 env(trust(bob, D_BUX(200)), qualityOutPercent(120));
+
1195 env(trust(cam, D_BUX(100)));
+
1196 env.close();
+
1197 env(pay(dan, bob, D_BUX(100)));
+
1198 env.close();
+
1199 BEAST_EXPECT(expectHolding(env, bob, D_BUX(100)));
+
1200
+
1201 env(pay(ann, cam, D_BUX(60)), path(bob, dan), sendmax(A_BUX(200)));
+
1202 env.close();
+
1203
+
1204 BEAST_EXPECT(expectHolding(env, ann, A_BUX(none)));
+
1205 BEAST_EXPECT(expectHolding(env, ann, D_BUX(none)));
+
1206 BEAST_EXPECT(expectHolding(env, bob, A_BUX(72)));
+
1207 BEAST_EXPECT(expectHolding(env, bob, D_BUX(40)));
+
1208 BEAST_EXPECT(expectHolding(env, cam, A_BUX(none)));
+
1209 BEAST_EXPECT(expectHolding(env, cam, D_BUX(60)));
+
1210 BEAST_EXPECT(expectHolding(env, dan, A_BUX(none)));
+
1211 BEAST_EXPECT(expectHolding(env, dan, D_BUX(none)));
+
1212
+
1213 AMM ammBob(env, bob, A_BUX(30), D_BUX(30));
+
1214
+
1215 env(trust(ann, D_BUX(100)));
+
1216 env.close();
+
1217
+
1218 // This payment caused the assert.
+
1219 env(pay(ann, ann, D_BUX(30)),
+
1220 path(A_BUX, D_BUX),
+
1221 sendmax(A_BUX(30)),
+
1222 ter(temBAD_PATH));
+
1223 env.close();
1224
-
1225 env(trust(ann, D_BUX(100)));
-
1226 env.close();
-
1227
-
1228 // This payment caused the assert.
-
1229 env(pay(ann, ann, D_BUX(30)),
-
1230 path(A_BUX, D_BUX),
-
1231 sendmax(A_BUX(30)),
-
1232 ter(temBAD_PATH));
-
1233 env.close();
-
1234
-
1235 BEAST_EXPECT(
-
1236 ammBob.expectBalances(A_BUX(30), D_BUX(30), ammBob.tokens()));
-
1237 BEAST_EXPECT(expectHolding(env, ann, A_BUX(none)));
-
1238 BEAST_EXPECT(expectHolding(env, ann, D_BUX(0)));
-
1239 BEAST_EXPECT(expectHolding(env, cam, A_BUX(none)));
-
1240 BEAST_EXPECT(expectHolding(env, cam, D_BUX(60)));
-
1241 BEAST_EXPECT(expectHolding(env, dan, A_BUX(0)));
-
1242 BEAST_EXPECT(expectHolding(env, dan, D_BUX(none)));
-
1243 }
-
1244 }
+
1225 BEAST_EXPECT(
+
1226 ammBob.expectBalances(A_BUX(30), D_BUX(30), ammBob.tokens()));
+
1227 BEAST_EXPECT(expectHolding(env, ann, A_BUX(none)));
+
1228 BEAST_EXPECT(expectHolding(env, ann, D_BUX(0)));
+
1229 BEAST_EXPECT(expectHolding(env, cam, A_BUX(none)));
+
1230 BEAST_EXPECT(expectHolding(env, cam, D_BUX(60)));
+
1231 BEAST_EXPECT(expectHolding(env, dan, A_BUX(0)));
+
1232 BEAST_EXPECT(expectHolding(env, dan, D_BUX(none)));
+
1233 }
+
1234 }
-
1245
-
1246 void
-
- -
1248 {
-
1249 // The offer crossing code expects that a DirectStep is always
-
1250 // preceded by a BookStep. In one instance the default path
-
1251 // was not matching that assumption. Here we recreate that case
-
1252 // so we can prove the bug stays fixed.
-
1253 testcase("Direct to Direct path");
-
1254
-
1255 using namespace jtx;
-
1256
-
1257 Env env{*this, features};
-
1258
-
1259 auto const ann = Account("ann");
-
1260 auto const bob = Account("bob");
-
1261 auto const cam = Account("cam");
-
1262 auto const carol = Account("carol");
-
1263 auto const A_BUX = ann["BUX"];
-
1264 auto const B_BUX = bob["BUX"];
-
1265
-
1266 auto const fee = env.current()->fees().base;
-
1267 env.fund(XRP(1'000), carol);
-
1268 env.fund(reserve(env, 4) + (fee * 5), ann, bob, cam);
-
1269 env.close();
-
1270
-
1271 env(trust(ann, B_BUX(40)));
-
1272 env(trust(cam, A_BUX(40)));
-
1273 env(trust(bob, A_BUX(30)));
-
1274 env(trust(cam, B_BUX(40)));
-
1275 env(trust(carol, B_BUX(400)));
-
1276 env(trust(carol, A_BUX(400)));
-
1277 env.close();
-
1278
-
1279 env(pay(ann, cam, A_BUX(35)));
-
1280 env(pay(bob, cam, B_BUX(35)));
-
1281 env(pay(bob, carol, B_BUX(400)));
-
1282 env(pay(ann, carol, A_BUX(400)));
-
1283
-
1284 AMM ammCarol(env, carol, A_BUX(300), B_BUX(330));
-
1285
-
1286 // cam puts an offer on the books that her upcoming offer could cross.
-
1287 // But this offer should be deleted, not crossed, by her upcoming
-
1288 // offer.
-
1289 env(offer(cam, A_BUX(29), B_BUX(30), tfPassive));
-
1290 env.close();
-
1291 env.require(balance(cam, A_BUX(35)));
-
1292 env.require(balance(cam, B_BUX(35)));
-
1293 env.require(offers(cam, 1));
-
1294
-
1295 // This offer caused the assert.
-
1296 env(offer(cam, B_BUX(30), A_BUX(30)));
-
1297
-
1298 // AMM is consumed up to the first cam Offer quality
-
1299 if (!features[fixAMMv1_1])
-
1300 {
-
1301 BEAST_EXPECT(ammCarol.expectBalances(
-
1302 STAmount{A_BUX, UINT64_C(309'3541659651605), -13},
-
1303 STAmount{B_BUX, UINT64_C(320'0215509984417), -13},
-
1304 ammCarol.tokens()));
-
1305 BEAST_EXPECT(expectOffers(
-
1306 env,
-
1307 cam,
-
1308 1,
-
1309 {{Amounts{
-
1310 STAmount{B_BUX, UINT64_C(20'0215509984417), -13},
-
1311 STAmount{A_BUX, UINT64_C(20'0215509984417), -13}}}}));
-
1312 }
-
1313 else
-
1314 {
-
1315 BEAST_EXPECT(ammCarol.expectBalances(
-
1316 STAmount{A_BUX, UINT64_C(309'3541659651604), -13},
-
1317 STAmount{B_BUX, UINT64_C(320'0215509984419), -13},
-
1318 ammCarol.tokens()));
-
1319 BEAST_EXPECT(expectOffers(
-
1320 env,
-
1321 cam,
-
1322 1,
-
1323 {{Amounts{
-
1324 STAmount{B_BUX, UINT64_C(20'0215509984419), -13},
-
1325 STAmount{A_BUX, UINT64_C(20'0215509984419), -13}}}}));
-
1326 }
-
1327 }
+
1235
+
1236 void
+
+ +
1238 {
+
1239 // The offer crossing code expects that a DirectStep is always
+
1240 // preceded by a BookStep. In one instance the default path
+
1241 // was not matching that assumption. Here we recreate that case
+
1242 // so we can prove the bug stays fixed.
+
1243 testcase("Direct to Direct path");
+
1244
+
1245 using namespace jtx;
+
1246
+
1247 Env env{*this, features};
+
1248
+
1249 auto const ann = Account("ann");
+
1250 auto const bob = Account("bob");
+
1251 auto const cam = Account("cam");
+
1252 auto const carol = Account("carol");
+
1253 auto const A_BUX = ann["BUX"];
+
1254 auto const B_BUX = bob["BUX"];
+
1255
+
1256 auto const fee = env.current()->fees().base;
+
1257 env.fund(XRP(1'000), carol);
+
1258 env.fund(reserve(env, 4) + (fee * 5), ann, bob, cam);
+
1259 env.close();
+
1260
+
1261 env(trust(ann, B_BUX(40)));
+
1262 env(trust(cam, A_BUX(40)));
+
1263 env(trust(bob, A_BUX(30)));
+
1264 env(trust(cam, B_BUX(40)));
+
1265 env(trust(carol, B_BUX(400)));
+
1266 env(trust(carol, A_BUX(400)));
+
1267 env.close();
+
1268
+
1269 env(pay(ann, cam, A_BUX(35)));
+
1270 env(pay(bob, cam, B_BUX(35)));
+
1271 env(pay(bob, carol, B_BUX(400)));
+
1272 env(pay(ann, carol, A_BUX(400)));
+
1273
+
1274 AMM ammCarol(env, carol, A_BUX(300), B_BUX(330));
+
1275
+
1276 // cam puts an offer on the books that her upcoming offer could cross.
+
1277 // But this offer should be deleted, not crossed, by her upcoming
+
1278 // offer.
+
1279 env(offer(cam, A_BUX(29), B_BUX(30), tfPassive));
+
1280 env.close();
+
1281 env.require(balance(cam, A_BUX(35)));
+
1282 env.require(balance(cam, B_BUX(35)));
+
1283 env.require(offers(cam, 1));
+
1284
+
1285 // This offer caused the assert.
+
1286 env(offer(cam, B_BUX(30), A_BUX(30)));
+
1287
+
1288 // AMM is consumed up to the first cam Offer quality
+
1289 if (!features[fixAMMv1_1])
+
1290 {
+
1291 BEAST_EXPECT(ammCarol.expectBalances(
+
1292 STAmount{A_BUX, UINT64_C(309'3541659651605), -13},
+
1293 STAmount{B_BUX, UINT64_C(320'0215509984417), -13},
+
1294 ammCarol.tokens()));
+
1295 BEAST_EXPECT(expectOffers(
+
1296 env,
+
1297 cam,
+
1298 1,
+
1299 {{Amounts{
+
1300 STAmount{B_BUX, UINT64_C(20'0215509984417), -13},
+
1301 STAmount{A_BUX, UINT64_C(20'0215509984417), -13}}}}));
+
1302 }
+
1303 else
+
1304 {
+
1305 BEAST_EXPECT(ammCarol.expectBalances(
+
1306 STAmount{A_BUX, UINT64_C(309'3541659651604), -13},
+
1307 STAmount{B_BUX, UINT64_C(320'0215509984419), -13},
+
1308 ammCarol.tokens()));
+
1309 BEAST_EXPECT(expectOffers(
+
1310 env,
+
1311 cam,
+
1312 1,
+
1313 {{Amounts{
+
1314 STAmount{B_BUX, UINT64_C(20'0215509984419), -13},
+
1315 STAmount{A_BUX, UINT64_C(20'0215509984419), -13}}}}));
+
1316 }
+
1317 }
-
1328
-
1329 void
-
- -
1331 {
-
1332 testcase("lsfRequireAuth");
+
1318
+
1319 void
+
+ +
1321 {
+
1322 testcase("lsfRequireAuth");
+
1323
+
1324 using namespace jtx;
+
1325
+
1326 Env env{*this, features};
+
1327
+
1328 auto const aliceUSD = alice["USD"];
+
1329 auto const bobUSD = bob["USD"];
+
1330
+
1331 env.fund(XRP(400'000), gw, alice, bob);
+
1332 env.close();
1333
-
1334 using namespace jtx;
-
1335
-
1336 Env env{*this, features};
+
1334 // GW requires authorization for holders of its IOUs
+
1335 env(fset(gw, asfRequireAuth));
+
1336 env.close();
1337
-
1338 auto const aliceUSD = alice["USD"];
-
1339 auto const bobUSD = bob["USD"];
-
1340
-
1341 env.fund(XRP(400'000), gw, alice, bob);
-
1342 env.close();
-
1343
-
1344 // GW requires authorization for holders of its IOUs
-
1345 env(fset(gw, asfRequireAuth));
-
1346 env.close();
+
1338 // Properly set trust and have gw authorize bob and alice
+
1339 env(trust(gw, bobUSD(100)), txflags(tfSetfAuth));
+
1340 env(trust(bob, USD(100)));
+
1341 env(trust(gw, aliceUSD(100)), txflags(tfSetfAuth));
+
1342 env(trust(alice, USD(2'000)));
+
1343 env(pay(gw, alice, USD(1'000)));
+
1344 env.close();
+
1345 // Alice is able to create AMM since the GW has authorized her
+
1346 AMM ammAlice(env, alice, USD(1'000), XRP(1'050));
1347
-
1348 // Properly set trust and have gw authorize bob and alice
-
1349 env(trust(gw, bobUSD(100)), txflags(tfSetfAuth));
-
1350 env(trust(bob, USD(100)));
-
1351 env(trust(gw, aliceUSD(100)), txflags(tfSetfAuth));
-
1352 env(trust(alice, USD(2'000)));
-
1353 env(pay(gw, alice, USD(1'000)));
+
1348 // Set up authorized trust line for AMM.
+
1349 env(trust(gw, STAmount{Issue{USD.currency, ammAlice.ammAccount()}, 10}),
+ +
1351 env.close();
+
1352
+
1353 env(pay(gw, bob, USD(50)));
1354 env.close();
-
1355 // Alice is able to create AMM since the GW has authorized her
-
1356 AMM ammAlice(env, alice, USD(1'000), XRP(1'050));
+
1355
+
1356 BEAST_EXPECT(expectHolding(env, bob, USD(50)));
1357
-
1358 // Set up authorized trust line for AMM.
-
1359 env(trust(gw, STAmount{Issue{USD.currency, ammAlice.ammAccount()}, 10}),
- -
1361 env.close();
-
1362
-
1363 env(pay(gw, bob, USD(50)));
-
1364 env.close();
-
1365
-
1366 BEAST_EXPECT(expectHolding(env, bob, USD(50)));
+
1358 // Bob's offer should cross Alice's AMM
+
1359 env(offer(bob, XRP(50), USD(50)));
+
1360 env.close();
+
1361
+
1362 BEAST_EXPECT(
+
1363 ammAlice.expectBalances(USD(1'050), XRP(1'000), ammAlice.tokens()));
+
1364 BEAST_EXPECT(expectOffers(env, bob, 0));
+
1365 BEAST_EXPECT(expectHolding(env, bob, USD(0)));
+
1366 }
+
1367
-
1368 // Bob's offer should cross Alice's AMM
-
1369 env(offer(bob, XRP(50), USD(50)));
-
1370 env.close();
-
1371
-
1372 BEAST_EXPECT(
-
1373 ammAlice.expectBalances(USD(1'050), XRP(1'000), ammAlice.tokens()));
-
1374 BEAST_EXPECT(expectOffers(env, bob, 0));
-
1375 BEAST_EXPECT(expectHolding(env, bob, USD(0)));
-
1376 }
-
-
1377
-
1378 void
-
- -
1380 {
-
1381 testcase("Missing Auth");
-
1382
-
1383 using namespace jtx;
-
1384
-
1385 Env env{*this, features};
-
1386
-
1387 env.fund(XRP(400'000), gw, alice, bob);
-
1388 env.close();
-
1389
-
1390 // Alice doesn't have the funds
-
1391 {
-
1392 AMM ammAlice(
-
1393 env, alice, USD(1'000), XRP(1'000), ter(tecUNFUNDED_AMM));
-
1394 }
-
1395
-
1396 env(fset(gw, asfRequireAuth));
-
1397 env.close();
-
1398
-
1399 env(trust(gw, bob["USD"](50)), txflags(tfSetfAuth));
-
1400 env.close();
-
1401 env(trust(bob, USD(50)));
-
1402 env.close();
-
1403
-
1404 env(pay(gw, bob, USD(50)));
-
1405 env.close();
-
1406 BEAST_EXPECT(expectHolding(env, bob, USD(50)));
+
1368 void
+
+ +
1370 {
+
1371 testcase("Missing Auth");
+
1372
+
1373 using namespace jtx;
+
1374
+
1375 Env env{*this, features};
+
1376
+
1377 env.fund(XRP(400'000), gw, alice, bob);
+
1378 env.close();
+
1379
+
1380 // Alice doesn't have the funds
+
1381 {
+
1382 AMM ammAlice(
+
1383 env, alice, USD(1'000), XRP(1'000), ter(tecUNFUNDED_AMM));
+
1384 }
+
1385
+
1386 env(fset(gw, asfRequireAuth));
+
1387 env.close();
+
1388
+
1389 env(trust(gw, bob["USD"](50)), txflags(tfSetfAuth));
+
1390 env.close();
+
1391 env(trust(bob, USD(50)));
+
1392 env.close();
+
1393
+
1394 env(pay(gw, bob, USD(50)));
+
1395 env.close();
+
1396 BEAST_EXPECT(expectHolding(env, bob, USD(50)));
+
1397
+
1398 // Alice should not be able to create AMM without authorization.
+
1399 {
+
1400 AMM ammAlice(env, alice, USD(1'000), XRP(1'000), ter(tecNO_LINE));
+
1401 }
+
1402
+
1403 // Set up a trust line for Alice, but don't authorize it. Alice
+
1404 // should still not be able to create AMM for USD/gw.
+
1405 env(trust(gw, alice["USD"](2'000)));
+
1406 env.close();
1407
-
1408 // Alice should not be able to create AMM without authorization.
-
1409 {
-
1410 AMM ammAlice(env, alice, USD(1'000), XRP(1'000), ter(tecNO_LINE));
-
1411 }
-
1412
-
1413 // Set up a trust line for Alice, but don't authorize it. Alice
-
1414 // should still not be able to create AMM for USD/gw.
-
1415 env(trust(gw, alice["USD"](2'000)));
-
1416 env.close();
-
1417
-
1418 {
-
1419 AMM ammAlice(env, alice, USD(1'000), XRP(1'000), ter(tecNO_AUTH));
-
1420 }
-
1421
-
1422 // Finally, set up an authorized trust line for Alice. Now Alice's
-
1423 // AMM create should succeed.
-
1424 env(trust(gw, alice["USD"](100)), txflags(tfSetfAuth));
-
1425 env(trust(alice, USD(2'000)));
-
1426 env(pay(gw, alice, USD(1'000)));
-
1427 env.close();
-
1428
-
1429 AMM ammAlice(env, alice, USD(1'000), XRP(1'050));
-
1430
-
1431 // Set up authorized trust line for AMM.
-
1432 env(trust(gw, STAmount{Issue{USD.currency, ammAlice.ammAccount()}, 10}),
- -
1434 env.close();
+
1408 {
+
1409 AMM ammAlice(env, alice, USD(1'000), XRP(1'000), ter(tecNO_AUTH));
+
1410 }
+
1411
+
1412 // Finally, set up an authorized trust line for Alice. Now Alice's
+
1413 // AMM create should succeed.
+
1414 env(trust(gw, alice["USD"](100)), txflags(tfSetfAuth));
+
1415 env(trust(alice, USD(2'000)));
+
1416 env(pay(gw, alice, USD(1'000)));
+
1417 env.close();
+
1418
+
1419 AMM ammAlice(env, alice, USD(1'000), XRP(1'050));
+
1420
+
1421 // Set up authorized trust line for AMM.
+
1422 env(trust(gw, STAmount{Issue{USD.currency, ammAlice.ammAccount()}, 10}),
+ +
1424 env.close();
+
1425
+
1426 // Now bob creates his offer again, which crosses with alice's AMM.
+
1427 env(offer(bob, XRP(50), USD(50)));
+
1428 env.close();
+
1429
+
1430 BEAST_EXPECT(
+
1431 ammAlice.expectBalances(USD(1'050), XRP(1'000), ammAlice.tokens()));
+
1432 BEAST_EXPECT(expectOffers(env, bob, 0));
+
1433 BEAST_EXPECT(expectHolding(env, bob, USD(0)));
+
1434 }
+
1435
-
1436 // Now bob creates his offer again, which crosses with alice's AMM.
-
1437 env(offer(bob, XRP(50), USD(50)));
-
1438 env.close();
-
1439
-
1440 BEAST_EXPECT(
-
1441 ammAlice.expectBalances(USD(1'050), XRP(1'000), ammAlice.tokens()));
-
1442 BEAST_EXPECT(expectOffers(env, bob, 0));
-
1443 BEAST_EXPECT(expectHolding(env, bob, USD(0)));
-
1444 }
+
1436 void
+ -
1445
-
1446 void
-
- -
1448 {
-
1449 using namespace jtx;
- - -
1452 testRmFundedOffer(all - fixAMMv1_1 - fixAMMv1_3);
- - - - - - - - - - - - - -
1466 testGatewayCrossCurrency(all - fixAMMv1_1 - fixAMMv1_3);
- - - - - - - -
1474 testDirectToDirectPath(all - fixAMMv1_1 - fixAMMv1_3);
- - -
1477 }
+
1468
+
1469 void
+
+ +
1471 {
+
1472 testcase("path find consume all");
+
1473 using namespace jtx;
+
1474
+
1475 Env env = pathTestEnv();
+
1476 env.fund(XRP(100'000'250), alice);
+
1477 fund(env, gw, {carol, bob}, {USD(100)}, Fund::All);
+
1478 fund(env, gw, {alice}, {USD(100)}, Fund::IOUOnly);
+
1479 AMM ammCarol(env, carol, XRP(100), USD(100));
+
1480
+
1481 STPathSet st;
+
1482 STAmount sa;
+
1483 STAmount da;
+
1484 std::tie(st, sa, da) = find_paths(
+
1485 env,
+
1486 alice,
+
1487 bob,
+
1488 bob["AUD"](-1),
+
1489 std::optional<STAmount>(XRP(100'000'000)));
+
1490 BEAST_EXPECT(st.empty());
+
1491 std::tie(st, sa, da) = find_paths(
+
1492 env,
+
1493 alice,
+
1494 bob,
+
1495 bob["USD"](-1),
+
1496 std::optional<STAmount>(XRP(100'000'000)));
+
1497 // Alice sends all requested 100,000,000XRP
+
1498 BEAST_EXPECT(sa == XRP(100'000'000));
+
1499 // Bob gets ~99.99USD. This is the amount Bob
+
1500 // can get out of AMM for 100,000,000XRP.
+
1501 BEAST_EXPECT(equal(
+
1502 da, STAmount{bob["USD"].issue(), UINT64_C(99'9999000001), -10}));
+
1503 }
-
1478
-
1479 void
-
- -
1481 {
-
1482 testcase("path find consume all");
-
1483 using namespace jtx;
-
1484
-
1485 Env env = pathTestEnv();
-
1486 env.fund(XRP(100'000'250), alice);
-
1487 fund(env, gw, {carol, bob}, {USD(100)}, Fund::All);
-
1488 fund(env, gw, {alice}, {USD(100)}, Fund::IOUOnly);
-
1489 AMM ammCarol(env, carol, XRP(100), USD(100));
-
1490
-
1491 STPathSet st;
-
1492 STAmount sa;
-
1493 STAmount da;
-
1494 std::tie(st, sa, da) = find_paths(
-
1495 env,
-
1496 alice,
-
1497 bob,
-
1498 bob["AUD"](-1),
-
1499 std::optional<STAmount>(XRP(100'000'000)));
-
1500 BEAST_EXPECT(st.empty());
-
1501 std::tie(st, sa, da) = find_paths(
-
1502 env,
-
1503 alice,
-
1504 bob,
-
1505 bob["USD"](-1),
-
1506 std::optional<STAmount>(XRP(100'000'000)));
-
1507 // Alice sends all requested 100,000,000XRP
-
1508 BEAST_EXPECT(sa == XRP(100'000'000));
-
1509 // Bob gets ~99.99USD. This is the amount Bob
-
1510 // can get out of AMM for 100,000,000XRP.
-
1511 BEAST_EXPECT(equal(
-
1512 da, STAmount{bob["USD"].issue(), UINT64_C(99'9999000001), -10}));
-
1513 }
+
1504
+
1505 // carol holds gateway AUD, sells gateway AUD for XRP
+
1506 // bob will hold gateway AUD
+
1507 // alice pays bob gateway AUD using XRP
+
1508 void
+
+ +
1510 {
+
1511 testcase("via gateway");
+
1512 using namespace jtx;
+
1513
+
1514 Env env = pathTestEnv();
+
1515 auto const AUD = gw["AUD"];
+
1516 env.fund(XRP(10'000), alice, bob, carol, gw);
+
1517 env.close();
+
1518 env(rate(gw, 1.1));
+
1519 env.trust(AUD(2'000), bob, carol);
+
1520 env(pay(gw, carol, AUD(51)));
+
1521 env.close();
+
1522 AMM ammCarol(env, carol, XRP(40), AUD(51));
+
1523 env(pay(alice, bob, AUD(10)), sendmax(XRP(100)), paths(XRP));
+
1524 env.close();
+
1525 // AMM offer is 51.282052XRP/11AUD, 11AUD/1.1 = 10AUD to bob
+
1526 BEAST_EXPECT(
+
1527 ammCarol.expectBalances(XRP(51), AUD(40), ammCarol.tokens()));
+
1528 BEAST_EXPECT(expectHolding(env, bob, AUD(10)));
+
1529
+
1530 auto const result =
+
1531 find_paths(env, alice, bob, Account(bob)["USD"](25));
+
1532 BEAST_EXPECT(std::get<0>(result).empty());
+
1533 }
-
1514
-
1515 // carol holds gateway AUD, sells gateway AUD for XRP
-
1516 // bob will hold gateway AUD
-
1517 // alice pays bob gateway AUD using XRP
-
1518 void
-
- -
1520 {
-
1521 testcase("via gateway");
-
1522 using namespace jtx;
-
1523
-
1524 Env env = pathTestEnv();
-
1525 auto const AUD = gw["AUD"];
-
1526 env.fund(XRP(10'000), alice, bob, carol, gw);
-
1527 env.close();
-
1528 env(rate(gw, 1.1));
-
1529 env.trust(AUD(2'000), bob, carol);
-
1530 env(pay(gw, carol, AUD(51)));
-
1531 env.close();
-
1532 AMM ammCarol(env, carol, XRP(40), AUD(51));
-
1533 env(pay(alice, bob, AUD(10)), sendmax(XRP(100)), paths(XRP));
-
1534 env.close();
-
1535 // AMM offer is 51.282052XRP/11AUD, 11AUD/1.1 = 10AUD to bob
-
1536 BEAST_EXPECT(
-
1537 ammCarol.expectBalances(XRP(51), AUD(40), ammCarol.tokens()));
-
1538 BEAST_EXPECT(expectHolding(env, bob, AUD(10)));
-
1539
-
1540 auto const result =
-
1541 find_paths(env, alice, bob, Account(bob)["USD"](25));
-
1542 BEAST_EXPECT(std::get<0>(result).empty());
-
1543 }
+
1534
+
1535 void
+
+ +
1537 {
+
1538 testcase("Receive max");
+
1539 using namespace jtx;
+
1540 auto const charlie = Account("charlie");
+
1541 {
+
1542 // XRP -> IOU receive max
+
1543 Env env = pathTestEnv();
+
1544 fund(env, gw, {alice, bob, charlie}, {USD(11)}, Fund::All);
+
1545 AMM ammCharlie(env, charlie, XRP(10), USD(11));
+
1546 auto [st, sa, da] =
+
1547 find_paths(env, alice, bob, USD(-1), XRP(1).value());
+
1548 BEAST_EXPECT(sa == XRP(1));
+
1549 BEAST_EXPECT(equal(da, USD(1)));
+
1550 if (BEAST_EXPECT(st.size() == 1 && st[0].size() == 1))
+
1551 {
+
1552 auto const& pathElem = st[0][0];
+
1553 BEAST_EXPECT(
+
1554 pathElem.isOffer() && pathElem.getIssuerID() == gw.id() &&
+
1555 pathElem.getCurrency() == USD.currency);
+
1556 }
+
1557 }
+
1558 {
+
1559 // IOU -> XRP receive max
+
1560 Env env = pathTestEnv();
+
1561 fund(env, gw, {alice, bob, charlie}, {USD(11)}, Fund::All);
+
1562 AMM ammCharlie(env, charlie, XRP(11), USD(10));
+
1563 env.close();
+
1564 auto [st, sa, da] =
+
1565 find_paths(env, alice, bob, drops(-1), USD(1).value());
+
1566 BEAST_EXPECT(sa == USD(1));
+
1567 BEAST_EXPECT(equal(da, XRP(1)));
+
1568 if (BEAST_EXPECT(st.size() == 1 && st[0].size() == 1))
+
1569 {
+
1570 auto const& pathElem = st[0][0];
+
1571 BEAST_EXPECT(
+
1572 pathElem.isOffer() &&
+
1573 pathElem.getIssuerID() == xrpAccount() &&
+
1574 pathElem.getCurrency() == xrpCurrency());
+
1575 }
+
1576 }
+
1577 }
-
1544
-
1545 void
-
- -
1547 {
-
1548 testcase("Receive max");
-
1549 using namespace jtx;
-
1550 auto const charlie = Account("charlie");
-
1551 {
-
1552 // XRP -> IOU receive max
-
1553 Env env = pathTestEnv();
-
1554 fund(env, gw, {alice, bob, charlie}, {USD(11)}, Fund::All);
-
1555 AMM ammCharlie(env, charlie, XRP(10), USD(11));
-
1556 auto [st, sa, da] =
-
1557 find_paths(env, alice, bob, USD(-1), XRP(1).value());
-
1558 BEAST_EXPECT(sa == XRP(1));
-
1559 BEAST_EXPECT(equal(da, USD(1)));
-
1560 if (BEAST_EXPECT(st.size() == 1 && st[0].size() == 1))
-
1561 {
-
1562 auto const& pathElem = st[0][0];
-
1563 BEAST_EXPECT(
-
1564 pathElem.isOffer() && pathElem.getIssuerID() == gw.id() &&
-
1565 pathElem.getCurrency() == USD.currency);
-
1566 }
-
1567 }
-
1568 {
-
1569 // IOU -> XRP receive max
-
1570 Env env = pathTestEnv();
-
1571 fund(env, gw, {alice, bob, charlie}, {USD(11)}, Fund::All);
-
1572 AMM ammCharlie(env, charlie, XRP(11), USD(10));
-
1573 env.close();
-
1574 auto [st, sa, da] =
-
1575 find_paths(env, alice, bob, drops(-1), USD(1).value());
-
1576 BEAST_EXPECT(sa == USD(1));
-
1577 BEAST_EXPECT(equal(da, XRP(1)));
-
1578 if (BEAST_EXPECT(st.size() == 1 && st[0].size() == 1))
-
1579 {
-
1580 auto const& pathElem = st[0][0];
-
1581 BEAST_EXPECT(
-
1582 pathElem.isOffer() &&
-
1583 pathElem.getIssuerID() == xrpAccount() &&
-
1584 pathElem.getCurrency() == xrpCurrency());
-
1585 }
-
1586 }
-
1587 }
-
-
1588
-
1589 void
-
- -
1591 {
-
1592 testcase("Path Find: XRP -> XRP and XRP -> IOU");
-
1593 using namespace jtx;
-
1594 Env env = pathTestEnv();
-
1595 Account A1{"A1"};
-
1596 Account A2{"A2"};
-
1597 Account A3{"A3"};
-
1598 Account G1{"G1"};
-
1599 Account G2{"G2"};
-
1600 Account G3{"G3"};
-
1601 Account M1{"M1"};
-
1602
-
1603 env.fund(XRP(100'000), A1);
-
1604 env.fund(XRP(10'000), A2);
-
1605 env.fund(XRP(1'000), A3, G1, G2, G3);
-
1606 env.fund(XRP(20'000), M1);
+
1578
+
1579 void
+
+ +
1581 {
+
1582 testcase("Path Find: XRP -> XRP and XRP -> IOU");
+
1583 using namespace jtx;
+
1584 Env env = pathTestEnv();
+
1585 Account A1{"A1"};
+
1586 Account A2{"A2"};
+
1587 Account A3{"A3"};
+
1588 Account G1{"G1"};
+
1589 Account G2{"G2"};
+
1590 Account G3{"G3"};
+
1591 Account M1{"M1"};
+
1592
+
1593 env.fund(XRP(100'000), A1);
+
1594 env.fund(XRP(10'000), A2);
+
1595 env.fund(XRP(1'000), A3, G1, G2, G3);
+
1596 env.fund(XRP(20'000), M1);
+
1597 env.close();
+
1598
+
1599 env.trust(G1["XYZ"](5'000), A1);
+
1600 env.trust(G3["ABC"](5'000), A1);
+
1601 env.trust(G2["XYZ"](5'000), A2);
+
1602 env.trust(G3["ABC"](5'000), A2);
+
1603 env.trust(A2["ABC"](1'000), A3);
+
1604 env.trust(G1["XYZ"](100'000), M1);
+
1605 env.trust(G2["XYZ"](100'000), M1);
+
1606 env.trust(G3["ABC"](100'000), M1);
1607 env.close();
1608
-
1609 env.trust(G1["XYZ"](5'000), A1);
-
1610 env.trust(G3["ABC"](5'000), A1);
-
1611 env.trust(G2["XYZ"](5'000), A2);
-
1612 env.trust(G3["ABC"](5'000), A2);
-
1613 env.trust(A2["ABC"](1'000), A3);
-
1614 env.trust(G1["XYZ"](100'000), M1);
-
1615 env.trust(G2["XYZ"](100'000), M1);
-
1616 env.trust(G3["ABC"](100'000), M1);
-
1617 env.close();
+
1609 env(pay(G1, A1, G1["XYZ"](3'500)));
+
1610 env(pay(G3, A1, G3["ABC"](1'200)));
+
1611 env(pay(G1, M1, G1["XYZ"](25'000)));
+
1612 env(pay(G2, M1, G2["XYZ"](25'000)));
+
1613 env(pay(G3, M1, G3["ABC"](25'000)));
+
1614 env.close();
+
1615
+
1616 AMM ammM1_G1_G2(env, M1, G1["XYZ"](1'000), G2["XYZ"](1'000));
+
1617 AMM ammM1_XRP_G3(env, M1, XRP(10'000), G3["ABC"](1'000));
1618
-
1619 env(pay(G1, A1, G1["XYZ"](3'500)));
-
1620 env(pay(G3, A1, G3["ABC"](1'200)));
-
1621 env(pay(G1, M1, G1["XYZ"](25'000)));
-
1622 env(pay(G2, M1, G2["XYZ"](25'000)));
-
1623 env(pay(G3, M1, G3["ABC"](25'000)));
-
1624 env.close();
-
1625
-
1626 AMM ammM1_G1_G2(env, M1, G1["XYZ"](1'000), G2["XYZ"](1'000));
-
1627 AMM ammM1_XRP_G3(env, M1, XRP(10'000), G3["ABC"](1'000));
-
1628
-
1629 STPathSet st;
-
1630 STAmount sa, da;
-
1631
-
1632 {
-
1633 auto const& send_amt = XRP(10);
-
1634 std::tie(st, sa, da) =
-
1635 find_paths(env, A1, A2, send_amt, std::nullopt, xrpCurrency());
+
1619 STPathSet st;
+
1620 STAmount sa, da;
+
1621
+
1622 {
+
1623 auto const& send_amt = XRP(10);
+
1624 std::tie(st, sa, da) =
+
1625 find_paths(env, A1, A2, send_amt, std::nullopt, xrpCurrency());
+
1626 BEAST_EXPECT(equal(da, send_amt));
+
1627 BEAST_EXPECT(st.empty());
+
1628 }
+
1629
+
1630 {
+
1631 // no path should exist for this since dest account
+
1632 // does not exist.
+
1633 auto const& send_amt = XRP(200);
+
1634 std::tie(st, sa, da) = find_paths(
+
1635 env, A1, Account{"A0"}, send_amt, std::nullopt, xrpCurrency());
1636 BEAST_EXPECT(equal(da, send_amt));
1637 BEAST_EXPECT(st.empty());
1638 }
1639
1640 {
-
1641 // no path should exist for this since dest account
-
1642 // does not exist.
-
1643 auto const& send_amt = XRP(200);
-
1644 std::tie(st, sa, da) = find_paths(
-
1645 env, A1, Account{"A0"}, send_amt, std::nullopt, xrpCurrency());
-
1646 BEAST_EXPECT(equal(da, send_amt));
-
1647 BEAST_EXPECT(st.empty());
-
1648 }
-
1649
-
1650 {
-
1651 auto const& send_amt = G3["ABC"](10);
-
1652 std::tie(st, sa, da) =
-
1653 find_paths(env, A2, G3, send_amt, std::nullopt, xrpCurrency());
-
1654 BEAST_EXPECT(equal(da, send_amt));
-
1655 BEAST_EXPECT(equal(sa, XRPAmount{101'010'102}));
-
1656 BEAST_EXPECT(same(st, stpath(IPE(G3["ABC"]))));
-
1657 }
-
1658
-
1659 {
-
1660 auto const& send_amt = A2["ABC"](1);
-
1661 std::tie(st, sa, da) =
-
1662 find_paths(env, A1, A2, send_amt, std::nullopt, xrpCurrency());
-
1663 BEAST_EXPECT(equal(da, send_amt));
-
1664 BEAST_EXPECT(equal(sa, XRPAmount{10'010'011}));
-
1665 BEAST_EXPECT(same(st, stpath(IPE(G3["ABC"]), G3)));
-
1666 }
+
1641 auto const& send_amt = G3["ABC"](10);
+
1642 std::tie(st, sa, da) =
+
1643 find_paths(env, A2, G3, send_amt, std::nullopt, xrpCurrency());
+
1644 BEAST_EXPECT(equal(da, send_amt));
+
1645 BEAST_EXPECT(equal(sa, XRPAmount{101'010'102}));
+
1646 BEAST_EXPECT(same(st, stpath(IPE(G3["ABC"]))));
+
1647 }
+
1648
+
1649 {
+
1650 auto const& send_amt = A2["ABC"](1);
+
1651 std::tie(st, sa, da) =
+
1652 find_paths(env, A1, A2, send_amt, std::nullopt, xrpCurrency());
+
1653 BEAST_EXPECT(equal(da, send_amt));
+
1654 BEAST_EXPECT(equal(sa, XRPAmount{10'010'011}));
+
1655 BEAST_EXPECT(same(st, stpath(IPE(G3["ABC"]), G3)));
+
1656 }
+
1657
+
1658 {
+
1659 auto const& send_amt = A3["ABC"](1);
+
1660 std::tie(st, sa, da) =
+
1661 find_paths(env, A1, A3, send_amt, std::nullopt, xrpCurrency());
+
1662 BEAST_EXPECT(equal(da, send_amt));
+
1663 BEAST_EXPECT(equal(sa, XRPAmount{10'010'011}));
+
1664 BEAST_EXPECT(same(st, stpath(IPE(G3["ABC"]), G3, A2)));
+
1665 }
+
1666 }
+
1667
-
1668 {
-
1669 auto const& send_amt = A3["ABC"](1);
-
1670 std::tie(st, sa, da) =
-
1671 find_paths(env, A1, A3, send_amt, std::nullopt, xrpCurrency());
-
1672 BEAST_EXPECT(equal(da, send_amt));
-
1673 BEAST_EXPECT(equal(sa, XRPAmount{10'010'011}));
-
1674 BEAST_EXPECT(same(st, stpath(IPE(G3["ABC"]), G3, A2)));
-
1675 }
-
1676 }
-
-
1677
-
1678 void
-
- -
1680 {
-
1681 testcase("Path Find: non-XRP -> XRP");
-
1682 using namespace jtx;
-
1683 Env env = pathTestEnv();
-
1684 Account A1{"A1"};
-
1685 Account A2{"A2"};
-
1686 Account G3{"G3"};
-
1687 Account M1{"M1"};
-
1688
-
1689 env.fund(XRP(1'000), A1, A2, G3);
-
1690 env.fund(XRP(11'000), M1);
-
1691 env.close();
-
1692
-
1693 env.trust(G3["ABC"](1'000), A1, A2);
-
1694 env.trust(G3["ABC"](100'000), M1);
-
1695 env.close();
+
1668 void
+
+ +
1670 {
+
1671 testcase("Path Find: non-XRP -> XRP");
+
1672 using namespace jtx;
+
1673 Env env = pathTestEnv();
+
1674 Account A1{"A1"};
+
1675 Account A2{"A2"};
+
1676 Account G3{"G3"};
+
1677 Account M1{"M1"};
+
1678
+
1679 env.fund(XRP(1'000), A1, A2, G3);
+
1680 env.fund(XRP(11'000), M1);
+
1681 env.close();
+
1682
+
1683 env.trust(G3["ABC"](1'000), A1, A2);
+
1684 env.trust(G3["ABC"](100'000), M1);
+
1685 env.close();
+
1686
+
1687 env(pay(G3, A1, G3["ABC"](1'000)));
+
1688 env(pay(G3, A2, G3["ABC"](1'000)));
+
1689 env(pay(G3, M1, G3["ABC"](1'200)));
+
1690 env.close();
+
1691
+
1692 AMM ammM1(env, M1, G3["ABC"](1'000), XRP(10'010));
+
1693
+
1694 STPathSet st;
+
1695 STAmount sa, da;
1696
-
1697 env(pay(G3, A1, G3["ABC"](1'000)));
-
1698 env(pay(G3, A2, G3["ABC"](1'000)));
-
1699 env(pay(G3, M1, G3["ABC"](1'200)));
-
1700 env.close();
-
1701
-
1702 AMM ammM1(env, M1, G3["ABC"](1'000), XRP(10'010));
-
1703
-
1704 STPathSet st;
-
1705 STAmount sa, da;
-
1706
-
1707 auto const& send_amt = XRP(10);
-
1708 std::tie(st, sa, da) =
-
1709 find_paths(env, A1, A2, send_amt, std::nullopt, A2["ABC"].currency);
-
1710 BEAST_EXPECT(equal(da, send_amt));
-
1711 BEAST_EXPECT(equal(sa, A1["ABC"](1)));
-
1712 BEAST_EXPECT(same(st, stpath(G3, IPE(xrpIssue()))));
-
1713 }
+
1697 auto const& send_amt = XRP(10);
+
1698 std::tie(st, sa, da) =
+
1699 find_paths(env, A1, A2, send_amt, std::nullopt, A2["ABC"].currency);
+
1700 BEAST_EXPECT(equal(da, send_amt));
+
1701 BEAST_EXPECT(equal(sa, A1["ABC"](1)));
+
1702 BEAST_EXPECT(same(st, stpath(G3, IPE(xrpIssue()))));
+
1703 }
-
1714
-
1715 void
-
- -
1717 {
-
1718 testcase("Path Find: non-XRP -> non-XRP, same currency");
-
1719 using namespace jtx;
-
1720 Env env = pathTestEnv();
-
1721 Account A1{"A1"};
-
1722 Account A2{"A2"};
-
1723 Account A3{"A3"};
-
1724 Account A4{"A4"};
-
1725 Account G1{"G1"};
-
1726 Account G2{"G2"};
-
1727 Account G3{"G3"};
-
1728 Account G4{"G4"};
-
1729 Account M1{"M1"};
-
1730 Account M2{"M2"};
-
1731
-
1732 env.fund(XRP(1'000), A1, A2, A3, G1, G2, G3, G4);
-
1733 env.fund(XRP(10'000), A4);
-
1734 env.fund(XRP(21'000), M1, M2);
-
1735 env.close();
-
1736
-
1737 env.trust(G1["HKD"](2'000), A1);
-
1738 env.trust(G2["HKD"](2'000), A2);
-
1739 env.trust(G1["HKD"](2'000), A3);
-
1740 env.trust(G1["HKD"](100'000), M1);
-
1741 env.trust(G2["HKD"](100'000), M1);
-
1742 env.trust(G1["HKD"](100'000), M2);
-
1743 env.trust(G2["HKD"](100'000), M2);
-
1744 env.close();
-
1745
-
1746 env(pay(G1, A1, G1["HKD"](1'000)));
-
1747 env(pay(G2, A2, G2["HKD"](1'000)));
-
1748 env(pay(G1, A3, G1["HKD"](1'000)));
-
1749 env(pay(G1, M1, G1["HKD"](1'200)));
-
1750 env(pay(G2, M1, G2["HKD"](5'000)));
-
1751 env(pay(G1, M2, G1["HKD"](1'200)));
-
1752 env(pay(G2, M2, G2["HKD"](5'000)));
-
1753 env.close();
-
1754
-
1755 AMM ammM1(env, M1, G1["HKD"](1'010), G2["HKD"](1'000));
-
1756 AMM ammM2XRP_G2(env, M2, XRP(10'000), G2["HKD"](1'010));
-
1757 AMM ammM2G1_XRP(env, M2, G1["HKD"](1'010), XRP(10'000));
-
1758
-
1759 STPathSet st;
-
1760 STAmount sa, da;
-
1761
-
1762 {
-
1763 // A) Borrow or repay --
-
1764 // Source -> Destination (repay source issuer)
-
1765 auto const& send_amt = G1["HKD"](10);
-
1766 std::tie(st, sa, da) = find_paths(
-
1767 env, A1, G1, send_amt, std::nullopt, G1["HKD"].currency);
-
1768 BEAST_EXPECT(st.empty());
-
1769 BEAST_EXPECT(equal(da, send_amt));
-
1770 BEAST_EXPECT(equal(sa, A1["HKD"](10)));
-
1771 }
-
1772
-
1773 {
-
1774 // A2) Borrow or repay --
-
1775 // Source -> Destination (repay destination issuer)
-
1776 auto const& send_amt = A1["HKD"](10);
-
1777 std::tie(st, sa, da) = find_paths(
-
1778 env, A1, G1, send_amt, std::nullopt, G1["HKD"].currency);
-
1779 BEAST_EXPECT(st.empty());
+
1704
+
1705 void
+
+ +
1707 {
+
1708 testcase("Path Find: non-XRP -> non-XRP, same currency");
+
1709 using namespace jtx;
+
1710 Env env = pathTestEnv();
+
1711 Account A1{"A1"};
+
1712 Account A2{"A2"};
+
1713 Account A3{"A3"};
+
1714 Account A4{"A4"};
+
1715 Account G1{"G1"};
+
1716 Account G2{"G2"};
+
1717 Account G3{"G3"};
+
1718 Account G4{"G4"};
+
1719 Account M1{"M1"};
+
1720 Account M2{"M2"};
+
1721
+
1722 env.fund(XRP(1'000), A1, A2, A3, G1, G2, G3, G4);
+
1723 env.fund(XRP(10'000), A4);
+
1724 env.fund(XRP(21'000), M1, M2);
+
1725 env.close();
+
1726
+
1727 env.trust(G1["HKD"](2'000), A1);
+
1728 env.trust(G2["HKD"](2'000), A2);
+
1729 env.trust(G1["HKD"](2'000), A3);
+
1730 env.trust(G1["HKD"](100'000), M1);
+
1731 env.trust(G2["HKD"](100'000), M1);
+
1732 env.trust(G1["HKD"](100'000), M2);
+
1733 env.trust(G2["HKD"](100'000), M2);
+
1734 env.close();
+
1735
+
1736 env(pay(G1, A1, G1["HKD"](1'000)));
+
1737 env(pay(G2, A2, G2["HKD"](1'000)));
+
1738 env(pay(G1, A3, G1["HKD"](1'000)));
+
1739 env(pay(G1, M1, G1["HKD"](1'200)));
+
1740 env(pay(G2, M1, G2["HKD"](5'000)));
+
1741 env(pay(G1, M2, G1["HKD"](1'200)));
+
1742 env(pay(G2, M2, G2["HKD"](5'000)));
+
1743 env.close();
+
1744
+
1745 AMM ammM1(env, M1, G1["HKD"](1'010), G2["HKD"](1'000));
+
1746 AMM ammM2XRP_G2(env, M2, XRP(10'000), G2["HKD"](1'010));
+
1747 AMM ammM2G1_XRP(env, M2, G1["HKD"](1'010), XRP(10'000));
+
1748
+
1749 STPathSet st;
+
1750 STAmount sa, da;
+
1751
+
1752 {
+
1753 // A) Borrow or repay --
+
1754 // Source -> Destination (repay source issuer)
+
1755 auto const& send_amt = G1["HKD"](10);
+
1756 std::tie(st, sa, da) = find_paths(
+
1757 env, A1, G1, send_amt, std::nullopt, G1["HKD"].currency);
+
1758 BEAST_EXPECT(st.empty());
+
1759 BEAST_EXPECT(equal(da, send_amt));
+
1760 BEAST_EXPECT(equal(sa, A1["HKD"](10)));
+
1761 }
+
1762
+
1763 {
+
1764 // A2) Borrow or repay --
+
1765 // Source -> Destination (repay destination issuer)
+
1766 auto const& send_amt = A1["HKD"](10);
+
1767 std::tie(st, sa, da) = find_paths(
+
1768 env, A1, G1, send_amt, std::nullopt, G1["HKD"].currency);
+
1769 BEAST_EXPECT(st.empty());
+
1770 BEAST_EXPECT(equal(da, send_amt));
+
1771 BEAST_EXPECT(equal(sa, A1["HKD"](10)));
+
1772 }
+
1773
+
1774 {
+
1775 // B) Common gateway --
+
1776 // Source -> AC -> Destination
+
1777 auto const& send_amt = A3["HKD"](10);
+
1778 std::tie(st, sa, da) = find_paths(
+
1779 env, A1, A3, send_amt, std::nullopt, G1["HKD"].currency);
1780 BEAST_EXPECT(equal(da, send_amt));
1781 BEAST_EXPECT(equal(sa, A1["HKD"](10)));
-
1782 }
-
1783
-
1784 {
-
1785 // B) Common gateway --
-
1786 // Source -> AC -> Destination
-
1787 auto const& send_amt = A3["HKD"](10);
-
1788 std::tie(st, sa, da) = find_paths(
-
1789 env, A1, A3, send_amt, std::nullopt, G1["HKD"].currency);
-
1790 BEAST_EXPECT(equal(da, send_amt));
-
1791 BEAST_EXPECT(equal(sa, A1["HKD"](10)));
-
1792 BEAST_EXPECT(same(st, stpath(G1)));
-
1793 }
-
1794
-
1795 {
-
1796 // C) Gateway to gateway --
-
1797 // Source -> OB -> Destination
-
1798 auto const& send_amt = G2["HKD"](10);
-
1799 std::tie(st, sa, da) = find_paths(
-
1800 env, G1, G2, send_amt, std::nullopt, G1["HKD"].currency);
-
1801 BEAST_EXPECT(equal(da, send_amt));
-
1802 BEAST_EXPECT(equal(sa, G1["HKD"](10)));
-
1803 BEAST_EXPECT(same(
-
1804 st,
-
1805 stpath(IPE(G2["HKD"])),
-
1806 stpath(M1),
-
1807 stpath(M2),
-
1808 stpath(IPE(xrpIssue()), IPE(G2["HKD"]))));
-
1809 }
-
1810
-
1811 {
-
1812 // D) User to unlinked gateway via order book --
-
1813 // Source -> AC -> OB -> Destination
-
1814 auto const& send_amt = G2["HKD"](10);
-
1815 std::tie(st, sa, da) = find_paths(
-
1816 env, A1, G2, send_amt, std::nullopt, G1["HKD"].currency);
-
1817 BEAST_EXPECT(equal(da, send_amt));
-
1818 BEAST_EXPECT(equal(sa, A1["HKD"](10)));
-
1819 BEAST_EXPECT(same(
-
1820 st,
-
1821 stpath(G1, M1),
-
1822 stpath(G1, M2),
-
1823 stpath(G1, IPE(G2["HKD"])),
-
1824 stpath(G1, IPE(xrpIssue()), IPE(G2["HKD"]))));
-
1825 }
-
1826
-
1827 {
-
1828 // I4) XRP bridge" --
-
1829 // Source -> AC -> OB to XRP -> OB from XRP -> AC ->
-
1830 // Destination
-
1831 auto const& send_amt = A2["HKD"](10);
-
1832 std::tie(st, sa, da) = find_paths(
-
1833 env, A1, A2, send_amt, std::nullopt, G1["HKD"].currency);
-
1834 BEAST_EXPECT(equal(da, send_amt));
-
1835 BEAST_EXPECT(equal(sa, A1["HKD"](10)));
-
1836 BEAST_EXPECT(same(
-
1837 st,
-
1838 stpath(G1, M1, G2),
-
1839 stpath(G1, M2, G2),
-
1840 stpath(G1, IPE(G2["HKD"]), G2),
-
1841 stpath(G1, IPE(xrpIssue()), IPE(G2["HKD"]), G2)));
-
1842 }
-
1843 }
+
1782 BEAST_EXPECT(same(st, stpath(G1)));
+
1783 }
+
1784
+
1785 {
+
1786 // C) Gateway to gateway --
+
1787 // Source -> OB -> Destination
+
1788 auto const& send_amt = G2["HKD"](10);
+
1789 std::tie(st, sa, da) = find_paths(
+
1790 env, G1, G2, send_amt, std::nullopt, G1["HKD"].currency);
+
1791 BEAST_EXPECT(equal(da, send_amt));
+
1792 BEAST_EXPECT(equal(sa, G1["HKD"](10)));
+
1793 BEAST_EXPECT(same(
+
1794 st,
+
1795 stpath(IPE(G2["HKD"])),
+
1796 stpath(M1),
+
1797 stpath(M2),
+
1798 stpath(IPE(xrpIssue()), IPE(G2["HKD"]))));
+
1799 }
+
1800
+
1801 {
+
1802 // D) User to unlinked gateway via order book --
+
1803 // Source -> AC -> OB -> Destination
+
1804 auto const& send_amt = G2["HKD"](10);
+
1805 std::tie(st, sa, da) = find_paths(
+
1806 env, A1, G2, send_amt, std::nullopt, G1["HKD"].currency);
+
1807 BEAST_EXPECT(equal(da, send_amt));
+
1808 BEAST_EXPECT(equal(sa, A1["HKD"](10)));
+
1809 BEAST_EXPECT(same(
+
1810 st,
+
1811 stpath(G1, M1),
+
1812 stpath(G1, M2),
+
1813 stpath(G1, IPE(G2["HKD"])),
+
1814 stpath(G1, IPE(xrpIssue()), IPE(G2["HKD"]))));
+
1815 }
+
1816
+
1817 {
+
1818 // I4) XRP bridge" --
+
1819 // Source -> AC -> OB to XRP -> OB from XRP -> AC ->
+
1820 // Destination
+
1821 auto const& send_amt = A2["HKD"](10);
+
1822 std::tie(st, sa, da) = find_paths(
+
1823 env, A1, A2, send_amt, std::nullopt, G1["HKD"].currency);
+
1824 BEAST_EXPECT(equal(da, send_amt));
+
1825 BEAST_EXPECT(equal(sa, A1["HKD"](10)));
+
1826 BEAST_EXPECT(same(
+
1827 st,
+
1828 stpath(G1, M1, G2),
+
1829 stpath(G1, M2, G2),
+
1830 stpath(G1, IPE(G2["HKD"]), G2),
+
1831 stpath(G1, IPE(xrpIssue()), IPE(G2["HKD"]), G2)));
+
1832 }
+
1833 }
-
1844
-
1845 void
-
- -
1847 {
-
1848 testcase("Path Find: non-XRP -> non-XRP, same currency");
-
1849 using namespace jtx;
-
1850 Env env = pathTestEnv();
-
1851 Account A1{"A1"};
-
1852 Account A2{"A2"};
-
1853 Account A3{"A3"};
-
1854 Account G1{"G1"};
-
1855 Account G2{"G2"};
-
1856 Account M1{"M1"};
-
1857
-
1858 env.fund(XRP(11'000), M1);
-
1859 env.fund(XRP(1'000), A1, A2, A3, G1, G2);
-
1860 env.close();
-
1861
-
1862 env.trust(G1["HKD"](2'000), A1);
-
1863 env.trust(G2["HKD"](2'000), A2);
-
1864 env.trust(A2["HKD"](2'000), A3);
-
1865 env.trust(G1["HKD"](100'000), M1);
-
1866 env.trust(G2["HKD"](100'000), M1);
-
1867 env.close();
-
1868
-
1869 env(pay(G1, A1, G1["HKD"](1'000)));
-
1870 env(pay(G2, A2, G2["HKD"](1'000)));
-
1871 env(pay(G1, M1, G1["HKD"](5'000)));
-
1872 env(pay(G2, M1, G2["HKD"](5'000)));
-
1873 env.close();
-
1874
-
1875 AMM ammM1(env, M1, G1["HKD"](1'010), G2["HKD"](1'000));
-
1876
-
1877 // E) Gateway to user
-
1878 // Source -> OB -> AC -> Destination
-
1879 auto const& send_amt = A2["HKD"](10);
-
1880 STPathSet st;
-
1881 STAmount sa, da;
-
1882 std::tie(st, sa, da) =
-
1883 find_paths(env, G1, A2, send_amt, std::nullopt, G1["HKD"].currency);
-
1884 BEAST_EXPECT(equal(da, send_amt));
-
1885 BEAST_EXPECT(equal(sa, G1["HKD"](10)));
-
1886 BEAST_EXPECT(same(st, stpath(M1, G2), stpath(IPE(G2["HKD"]), G2)));
-
1887 }
+
1834
+
1835 void
+
+ +
1837 {
+
1838 testcase("Path Find: non-XRP -> non-XRP, same currency");
+
1839 using namespace jtx;
+
1840 Env env = pathTestEnv();
+
1841 Account A1{"A1"};
+
1842 Account A2{"A2"};
+
1843 Account A3{"A3"};
+
1844 Account G1{"G1"};
+
1845 Account G2{"G2"};
+
1846 Account M1{"M1"};
+
1847
+
1848 env.fund(XRP(11'000), M1);
+
1849 env.fund(XRP(1'000), A1, A2, A3, G1, G2);
+
1850 env.close();
+
1851
+
1852 env.trust(G1["HKD"](2'000), A1);
+
1853 env.trust(G2["HKD"](2'000), A2);
+
1854 env.trust(A2["HKD"](2'000), A3);
+
1855 env.trust(G1["HKD"](100'000), M1);
+
1856 env.trust(G2["HKD"](100'000), M1);
+
1857 env.close();
+
1858
+
1859 env(pay(G1, A1, G1["HKD"](1'000)));
+
1860 env(pay(G2, A2, G2["HKD"](1'000)));
+
1861 env(pay(G1, M1, G1["HKD"](5'000)));
+
1862 env(pay(G2, M1, G2["HKD"](5'000)));
+
1863 env.close();
+
1864
+
1865 AMM ammM1(env, M1, G1["HKD"](1'010), G2["HKD"](1'000));
+
1866
+
1867 // E) Gateway to user
+
1868 // Source -> OB -> AC -> Destination
+
1869 auto const& send_amt = A2["HKD"](10);
+
1870 STPathSet st;
+
1871 STAmount sa, da;
+
1872 std::tie(st, sa, da) =
+
1873 find_paths(env, G1, A2, send_amt, std::nullopt, G1["HKD"].currency);
+
1874 BEAST_EXPECT(equal(da, send_amt));
+
1875 BEAST_EXPECT(equal(sa, G1["HKD"](10)));
+
1876 BEAST_EXPECT(same(st, stpath(M1, G2), stpath(IPE(G2["HKD"]), G2)));
+
1877 }
-
1888
-
1889 void
-
- -
1891 {
-
1892 testcase("falseDryChanges");
-
1893
-
1894 using namespace jtx;
-
1895
-
1896 Env env(*this, features);
+
1878
+
1879 void
+
+ +
1881 {
+
1882 testcase("falseDryChanges");
+
1883
+
1884 using namespace jtx;
+
1885
+
1886 Env env(*this, features);
+
1887
+
1888 env.fund(XRP(10'000), alice, gw);
+
1889 // This removes no ripple for carol,
+
1890 // different from the original test
+
1891 fund(env, gw, {carol}, XRP(10'000), {}, Fund::Acct);
+
1892 auto const AMMXRPPool = env.current()->fees().increment * 2;
+
1893 env.fund(reserve(env, 5) + ammCrtFee(env) + AMMXRPPool, bob);
+
1894 env.close();
+
1895 env.trust(USD(1'000), alice, bob, carol);
+
1896 env.trust(EUR(1'000), alice, bob, carol);
1897
-
1898 env.fund(XRP(10'000), alice, gw);
-
1899 // This removes no ripple for carol,
-
1900 // different from the original test
-
1901 fund(env, gw, {carol}, XRP(10'000), {}, Fund::Acct);
-
1902 auto const AMMXRPPool = env.current()->fees().increment * 2;
-
1903 env.fund(reserve(env, 5) + ammCrtFee(env) + AMMXRPPool, bob);
-
1904 env.close();
-
1905 env.trust(USD(1'000), alice, bob, carol);
-
1906 env.trust(EUR(1'000), alice, bob, carol);
-
1907
-
1908 env(pay(gw, alice, EUR(50)));
-
1909 env(pay(gw, bob, USD(150)));
+
1898 env(pay(gw, alice, EUR(50)));
+
1899 env(pay(gw, bob, USD(150)));
+
1900
+
1901 // Bob has _just_ slightly less than 50 xrp available
+
1902 // If his owner count changes, he will have more liquidity.
+
1903 // This is one error case to test (when Flow is used).
+
1904 // Computing the incoming xrp to the XRP/USD offer will require two
+
1905 // recursive calls to the EUR/XRP offer. The second call will return
+
1906 // tecPATH_DRY, but the entire path should not be marked as dry.
+
1907 // This is the second error case to test (when flowV1 is used).
+
1908 env(offer(bob, EUR(50), XRP(50)));
+
1909 AMM ammBob(env, bob, AMMXRPPool, USD(150));
1910
-
1911 // Bob has _just_ slightly less than 50 xrp available
-
1912 // If his owner count changes, he will have more liquidity.
-
1913 // This is one error case to test (when Flow is used).
-
1914 // Computing the incoming xrp to the XRP/USD offer will require two
-
1915 // recursive calls to the EUR/XRP offer. The second call will return
-
1916 // tecPATH_DRY, but the entire path should not be marked as dry.
-
1917 // This is the second error case to test (when flowV1 is used).
-
1918 env(offer(bob, EUR(50), XRP(50)));
-
1919 AMM ammBob(env, bob, AMMXRPPool, USD(150));
-
1920
-
1921 env(pay(alice, carol, USD(1'000'000)),
-
1922 path(~XRP, ~USD),
-
1923 sendmax(EUR(500)),
- -
1925
-
1926 auto const carolUSD = env.balance(carol, USD).value();
-
1927 BEAST_EXPECT(carolUSD > USD(0) && carolUSD < USD(50));
-
1928 }
+
1911 env(pay(alice, carol, USD(1'000'000)),
+
1912 path(~XRP, ~USD),
+
1913 sendmax(EUR(500)),
+ +
1915
+
1916 auto const carolUSD = env.balance(carol, USD).value();
+
1917 BEAST_EXPECT(carolUSD > USD(0) && carolUSD < USD(50));
+
1918 }
-
1929
-
1930 void
-
- -
1932 {
-
1933 testcase("Book Step");
-
1934
-
1935 using namespace jtx;
-
1936
-
1937 {
-
1938 // simple IOU/IOU offer
-
1939 Env env(*this, features);
+
1919
+
1920 void
+
+ +
1922 {
+
1923 testcase("Book Step");
+
1924
+
1925 using namespace jtx;
+
1926
+
1927 {
+
1928 // simple IOU/IOU offer
+
1929 Env env(*this, features);
+
1930
+
1931 fund(
+
1932 env,
+
1933 gw,
+
1934 {alice, bob, carol},
+
1935 XRP(10'000),
+
1936 {BTC(100), USD(150)},
+
1937 Fund::All);
+
1938
+
1939 AMM ammBob(env, bob, BTC(100), USD(150));
1940
-
1941 fund(
-
1942 env,
-
1943 gw,
-
1944 {alice, bob, carol},
-
1945 XRP(10'000),
-
1946 {BTC(100), USD(150)},
-
1947 Fund::All);
-
1948
-
1949 AMM ammBob(env, bob, BTC(100), USD(150));
-
1950
-
1951 env(pay(alice, carol, USD(50)), path(~USD), sendmax(BTC(50)));
-
1952
-
1953 BEAST_EXPECT(expectHolding(env, alice, BTC(50)));
-
1954 BEAST_EXPECT(expectHolding(env, bob, BTC(0)));
-
1955 BEAST_EXPECT(expectHolding(env, bob, USD(0)));
-
1956 BEAST_EXPECT(expectHolding(env, carol, USD(200)));
-
1957 BEAST_EXPECT(
-
1958 ammBob.expectBalances(BTC(150), USD(100), ammBob.tokens()));
-
1959 }
-
1960 {
-
1961 // simple IOU/XRP XRP/IOU offer
-
1962 Env env(*this, features);
-
1963
-
1964 fund(
-
1965 env,
-
1966 gw,
-
1967 {alice, carol, bob},
-
1968 XRP(10'000),
-
1969 {BTC(100), USD(150)},
-
1970 Fund::All);
-
1971
-
1972 AMM ammBobBTC_XRP(env, bob, BTC(100), XRP(150));
-
1973 AMM ammBobXRP_USD(env, bob, XRP(100), USD(150));
-
1974
-
1975 env(pay(alice, carol, USD(50)), path(~XRP, ~USD), sendmax(BTC(50)));
-
1976
-
1977 BEAST_EXPECT(expectHolding(env, alice, BTC(50)));
-
1978 BEAST_EXPECT(expectHolding(env, bob, BTC(0)));
-
1979 BEAST_EXPECT(expectHolding(env, bob, USD(0)));
-
1980 BEAST_EXPECT(expectHolding(env, carol, USD(200)));
-
1981 BEAST_EXPECT(ammBobBTC_XRP.expectBalances(
-
1982 BTC(150), XRP(100), ammBobBTC_XRP.tokens()));
-
1983 BEAST_EXPECT(ammBobXRP_USD.expectBalances(
-
1984 XRP(150), USD(100), ammBobXRP_USD.tokens()));
-
1985 }
-
1986 {
-
1987 // simple XRP -> USD through offer and sendmax
-
1988 Env env(*this, features);
+
1941 env(pay(alice, carol, USD(50)), path(~USD), sendmax(BTC(50)));
+
1942
+
1943 BEAST_EXPECT(expectHolding(env, alice, BTC(50)));
+
1944 BEAST_EXPECT(expectHolding(env, bob, BTC(0)));
+
1945 BEAST_EXPECT(expectHolding(env, bob, USD(0)));
+
1946 BEAST_EXPECT(expectHolding(env, carol, USD(200)));
+
1947 BEAST_EXPECT(
+
1948 ammBob.expectBalances(BTC(150), USD(100), ammBob.tokens()));
+
1949 }
+
1950 {
+
1951 // simple IOU/XRP XRP/IOU offer
+
1952 Env env(*this, features);
+
1953
+
1954 fund(
+
1955 env,
+
1956 gw,
+
1957 {alice, carol, bob},
+
1958 XRP(10'000),
+
1959 {BTC(100), USD(150)},
+
1960 Fund::All);
+
1961
+
1962 AMM ammBobBTC_XRP(env, bob, BTC(100), XRP(150));
+
1963 AMM ammBobXRP_USD(env, bob, XRP(100), USD(150));
+
1964
+
1965 env(pay(alice, carol, USD(50)), path(~XRP, ~USD), sendmax(BTC(50)));
+
1966
+
1967 BEAST_EXPECT(expectHolding(env, alice, BTC(50)));
+
1968 BEAST_EXPECT(expectHolding(env, bob, BTC(0)));
+
1969 BEAST_EXPECT(expectHolding(env, bob, USD(0)));
+
1970 BEAST_EXPECT(expectHolding(env, carol, USD(200)));
+
1971 BEAST_EXPECT(ammBobBTC_XRP.expectBalances(
+
1972 BTC(150), XRP(100), ammBobBTC_XRP.tokens()));
+
1973 BEAST_EXPECT(ammBobXRP_USD.expectBalances(
+
1974 XRP(150), USD(100), ammBobXRP_USD.tokens()));
+
1975 }
+
1976 {
+
1977 // simple XRP -> USD through offer and sendmax
+
1978 Env env(*this, features);
+
1979
+
1980 fund(
+
1981 env,
+
1982 gw,
+
1983 {alice, carol, bob},
+
1984 XRP(10'000),
+
1985 {USD(150)},
+
1986 Fund::All);
+
1987
+
1988 AMM ammBob(env, bob, XRP(100), USD(150));
1989
-
1990 fund(
-
1991 env,
-
1992 gw,
-
1993 {alice, carol, bob},
-
1994 XRP(10'000),
-
1995 {USD(150)},
-
1996 Fund::All);
-
1997
-
1998 AMM ammBob(env, bob, XRP(100), USD(150));
-
1999
-
2000 env(pay(alice, carol, USD(50)), path(~USD), sendmax(XRP(50)));
-
2001
-
2002 BEAST_EXPECT(expectLedgerEntryRoot(
-
2003 env, alice, xrpMinusFee(env, 10'000 - 50)));
-
2004 BEAST_EXPECT(expectLedgerEntryRoot(
-
2005 env, bob, XRP(10'000) - XRP(100) - ammCrtFee(env)));
-
2006 BEAST_EXPECT(expectHolding(env, bob, USD(0)));
-
2007 BEAST_EXPECT(expectHolding(env, carol, USD(200)));
-
2008 BEAST_EXPECT(
-
2009 ammBob.expectBalances(XRP(150), USD(100), ammBob.tokens()));
-
2010 }
-
2011 {
-
2012 // simple USD -> XRP through offer and sendmax
-
2013 Env env(*this, features);
+
1990 env(pay(alice, carol, USD(50)), path(~USD), sendmax(XRP(50)));
+
1991
+
1992 BEAST_EXPECT(expectLedgerEntryRoot(
+
1993 env, alice, xrpMinusFee(env, 10'000 - 50)));
+
1994 BEAST_EXPECT(expectLedgerEntryRoot(
+
1995 env, bob, XRP(10'000) - XRP(100) - ammCrtFee(env)));
+
1996 BEAST_EXPECT(expectHolding(env, bob, USD(0)));
+
1997 BEAST_EXPECT(expectHolding(env, carol, USD(200)));
+
1998 BEAST_EXPECT(
+
1999 ammBob.expectBalances(XRP(150), USD(100), ammBob.tokens()));
+
2000 }
+
2001 {
+
2002 // simple USD -> XRP through offer and sendmax
+
2003 Env env(*this, features);
+
2004
+
2005 fund(
+
2006 env,
+
2007 gw,
+
2008 {alice, carol, bob},
+
2009 XRP(10'000),
+
2010 {USD(100)},
+
2011 Fund::All);
+
2012
+
2013 AMM ammBob(env, bob, USD(100), XRP(150));
2014
-
2015 fund(
-
2016 env,
-
2017 gw,
-
2018 {alice, carol, bob},
-
2019 XRP(10'000),
-
2020 {USD(100)},
-
2021 Fund::All);
-
2022
-
2023 AMM ammBob(env, bob, USD(100), XRP(150));
-
2024
-
2025 env(pay(alice, carol, XRP(50)), path(~XRP), sendmax(USD(50)));
-
2026
-
2027 BEAST_EXPECT(expectHolding(env, alice, USD(50)));
-
2028 BEAST_EXPECT(expectLedgerEntryRoot(
-
2029 env, bob, XRP(10'000) - XRP(150) - ammCrtFee(env)));
-
2030 BEAST_EXPECT(expectHolding(env, bob, USD(0)));
-
2031 BEAST_EXPECT(expectLedgerEntryRoot(env, carol, XRP(10'000 + 50)));
-
2032 BEAST_EXPECT(
-
2033 ammBob.expectBalances(USD(150), XRP(100), ammBob.tokens()));
-
2034 }
-
2035 {
-
2036 // test unfunded offers are removed when payment succeeds
-
2037 Env env(*this, features);
-
2038
-
2039 env.fund(XRP(10'000), alice, carol, gw);
-
2040 env.fund(XRP(10'000), bob);
-
2041 env.close();
-
2042 env.trust(USD(1'000), alice, bob, carol);
-
2043 env.trust(BTC(1'000), alice, bob, carol);
-
2044 env.trust(EUR(1'000), alice, bob, carol);
-
2045 env.close();
+
2015 env(pay(alice, carol, XRP(50)), path(~XRP), sendmax(USD(50)));
+
2016
+
2017 BEAST_EXPECT(expectHolding(env, alice, USD(50)));
+
2018 BEAST_EXPECT(expectLedgerEntryRoot(
+
2019 env, bob, XRP(10'000) - XRP(150) - ammCrtFee(env)));
+
2020 BEAST_EXPECT(expectHolding(env, bob, USD(0)));
+
2021 BEAST_EXPECT(expectLedgerEntryRoot(env, carol, XRP(10'000 + 50)));
+
2022 BEAST_EXPECT(
+
2023 ammBob.expectBalances(USD(150), XRP(100), ammBob.tokens()));
+
2024 }
+
2025 {
+
2026 // test unfunded offers are removed when payment succeeds
+
2027 Env env(*this, features);
+
2028
+
2029 env.fund(XRP(10'000), alice, carol, gw);
+
2030 env.fund(XRP(10'000), bob);
+
2031 env.close();
+
2032 env.trust(USD(1'000), alice, bob, carol);
+
2033 env.trust(BTC(1'000), alice, bob, carol);
+
2034 env.trust(EUR(1'000), alice, bob, carol);
+
2035 env.close();
+
2036
+
2037 env(pay(gw, alice, BTC(60)));
+
2038 env(pay(gw, bob, USD(200)));
+
2039 env(pay(gw, bob, EUR(150)));
+
2040 env.close();
+
2041
+
2042 env(offer(bob, BTC(50), USD(50)));
+
2043 env(offer(bob, BTC(40), EUR(50)));
+
2044 env.close();
+
2045 AMM ammBob(env, bob, EUR(100), USD(150));
2046
-
2047 env(pay(gw, alice, BTC(60)));
-
2048 env(pay(gw, bob, USD(200)));
-
2049 env(pay(gw, bob, EUR(150)));
-
2050 env.close();
+
2047 // unfund offer
+
2048 env(pay(bob, gw, EUR(50)));
+
2049 BEAST_EXPECT(isOffer(env, bob, BTC(50), USD(50)));
+
2050 BEAST_EXPECT(isOffer(env, bob, BTC(40), EUR(50)));
2051
-
2052 env(offer(bob, BTC(50), USD(50)));
-
2053 env(offer(bob, BTC(40), EUR(50)));
-
2054 env.close();
-
2055 AMM ammBob(env, bob, EUR(100), USD(150));
+
2052 env(pay(alice, carol, USD(50)),
+
2053 path(~USD),
+
2054 path(~EUR, ~USD),
+
2055 sendmax(BTC(60)));
2056
-
2057 // unfund offer
-
2058 env(pay(bob, gw, EUR(50)));
-
2059 BEAST_EXPECT(isOffer(env, bob, BTC(50), USD(50)));
-
2060 BEAST_EXPECT(isOffer(env, bob, BTC(40), EUR(50)));
-
2061
-
2062 env(pay(alice, carol, USD(50)),
-
2063 path(~USD),
-
2064 path(~EUR, ~USD),
-
2065 sendmax(BTC(60)));
-
2066
-
2067 env.require(balance(alice, BTC(10)));
-
2068 env.require(balance(bob, BTC(50)));
-
2069 env.require(balance(bob, USD(0)));
-
2070 env.require(balance(bob, EUR(0)));
-
2071 env.require(balance(carol, USD(50)));
-
2072 // used in the payment
-
2073 BEAST_EXPECT(!isOffer(env, bob, BTC(50), USD(50)));
-
2074 // found unfunded
-
2075 BEAST_EXPECT(!isOffer(env, bob, BTC(40), EUR(50)));
-
2076 // unchanged
-
2077 BEAST_EXPECT(
-
2078 ammBob.expectBalances(EUR(100), USD(150), ammBob.tokens()));
-
2079 }
-
2080 {
-
2081 // test unfunded offers are removed when the payment fails.
-
2082 // bob makes two offers: a funded 50 USD for 50 BTC and an
-
2083 // unfunded 50 EUR for 60 BTC. alice pays carol 61 USD with 61
-
2084 // BTC. alice only has 60 BTC, so the payment will fail. The
-
2085 // payment uses two paths: one through bob's funded offer and
-
2086 // one through his unfunded offer. When the payment fails `flow`
-
2087 // should return the unfunded offer. This test is intentionally
-
2088 // similar to the one that removes unfunded offers when the
-
2089 // payment succeeds.
-
2090 Env env(*this, features);
+
2057 env.require(balance(alice, BTC(10)));
+
2058 env.require(balance(bob, BTC(50)));
+
2059 env.require(balance(bob, USD(0)));
+
2060 env.require(balance(bob, EUR(0)));
+
2061 env.require(balance(carol, USD(50)));
+
2062 // used in the payment
+
2063 BEAST_EXPECT(!isOffer(env, bob, BTC(50), USD(50)));
+
2064 // found unfunded
+
2065 BEAST_EXPECT(!isOffer(env, bob, BTC(40), EUR(50)));
+
2066 // unchanged
+
2067 BEAST_EXPECT(
+
2068 ammBob.expectBalances(EUR(100), USD(150), ammBob.tokens()));
+
2069 }
+
2070 {
+
2071 // test unfunded offers are removed when the payment fails.
+
2072 // bob makes two offers: a funded 50 USD for 50 BTC and an
+
2073 // unfunded 50 EUR for 60 BTC. alice pays carol 61 USD with 61
+
2074 // BTC. alice only has 60 BTC, so the payment will fail. The
+
2075 // payment uses two paths: one through bob's funded offer and
+
2076 // one through his unfunded offer. When the payment fails `flow`
+
2077 // should return the unfunded offer. This test is intentionally
+
2078 // similar to the one that removes unfunded offers when the
+
2079 // payment succeeds.
+
2080 Env env(*this, features);
+
2081
+
2082 env.fund(XRP(10'000), bob, carol, gw);
+
2083 env.close();
+
2084 // Sets rippling on, this is different from
+
2085 // the original test
+
2086 fund(env, gw, {alice}, XRP(10'000), {}, Fund::Acct);
+
2087 env.trust(USD(1'000), alice, bob, carol);
+
2088 env.trust(BTC(1'000), alice, bob, carol);
+
2089 env.trust(EUR(1'000), alice, bob, carol);
+
2090 env.close();
2091
-
2092 env.fund(XRP(10'000), bob, carol, gw);
-
2093 env.close();
-
2094 // Sets rippling on, this is different from
-
2095 // the original test
-
2096 fund(env, gw, {alice}, XRP(10'000), {}, Fund::Acct);
-
2097 env.trust(USD(1'000), alice, bob, carol);
-
2098 env.trust(BTC(1'000), alice, bob, carol);
-
2099 env.trust(EUR(1'000), alice, bob, carol);
-
2100 env.close();
-
2101
-
2102 env(pay(gw, alice, BTC(60)));
-
2103 env(pay(gw, bob, BTC(100)));
-
2104 env(pay(gw, bob, USD(100)));
-
2105 env(pay(gw, bob, EUR(50)));
-
2106 env(pay(gw, carol, EUR(1)));
-
2107 env.close();
-
2108
-
2109 // This is multiplath, which generates limited # of offers
-
2110 AMM ammBobBTC_USD(env, bob, BTC(50), USD(50));
-
2111 env(offer(bob, BTC(60), EUR(50)));
-
2112 env(offer(carol, BTC(1'000), EUR(1)));
-
2113 env(offer(bob, EUR(50), USD(50)));
-
2114
-
2115 // unfund offer
-
2116 env(pay(bob, gw, EUR(50)));
-
2117 BEAST_EXPECT(ammBobBTC_USD.expectBalances(
-
2118 BTC(50), USD(50), ammBobBTC_USD.tokens()));
-
2119 BEAST_EXPECT(isOffer(env, bob, BTC(60), EUR(50)));
-
2120 BEAST_EXPECT(isOffer(env, carol, BTC(1'000), EUR(1)));
-
2121 BEAST_EXPECT(isOffer(env, bob, EUR(50), USD(50)));
-
2122
-
2123 auto flowJournal = env.app().logs().journal("Flow");
-
2124 auto const flowResult = [&] {
-
2125 STAmount deliver(USD(51));
-
2126 STAmount smax(BTC(61));
-
2127 PaymentSandbox sb(env.current().get(), tapNONE);
- -
2129 auto IPE = [](Issue const& iss) {
-
2130 return STPathElement(
- -
2132 xrpAccount(),
-
2133 iss.currency,
-
2134 iss.account);
-
2135 };
-
2136 {
-
2137 // BTC -> USD
-
2138 STPath p1({IPE(USD.issue())});
-
2139 paths.push_back(p1);
-
2140 // BTC -> EUR -> USD
-
2141 STPath p2({IPE(EUR.issue()), IPE(USD.issue())});
-
2142 paths.push_back(p2);
-
2143 }
-
2144
-
2145 return flow(
-
2146 sb,
-
2147 deliver,
-
2148 alice,
-
2149 carol,
-
2150 paths,
-
2151 false,
-
2152 false,
-
2153 true,
- - -
2156 smax,
- -
2158 flowJournal);
-
2159 }();
-
2160
-
2161 BEAST_EXPECT(flowResult.removableOffers.size() == 1);
-
2162 env.app().openLedger().modify(
-
2163 [&](OpenView& view, beast::Journal j) {
-
2164 if (flowResult.removableOffers.empty())
-
2165 return false;
-
2166 Sandbox sb(&view, tapNONE);
-
2167 for (auto const& o : flowResult.removableOffers)
-
2168 if (auto ok = sb.peek(keylet::offer(o)))
-
2169 offerDelete(sb, ok, flowJournal);
-
2170 sb.apply(view);
-
2171 return true;
-
2172 });
-
2173
-
2174 // used in payment, but since payment failed should be untouched
-
2175 BEAST_EXPECT(ammBobBTC_USD.expectBalances(
-
2176 BTC(50), USD(50), ammBobBTC_USD.tokens()));
-
2177 BEAST_EXPECT(isOffer(env, carol, BTC(1'000), EUR(1)));
-
2178 // found unfunded
-
2179 BEAST_EXPECT(!isOffer(env, bob, BTC(60), EUR(50)));
-
2180 }
-
2181 {
-
2182 // Do not produce more in the forward pass than the reverse pass
-
2183 // This test uses a path that whose reverse pass will compute a
-
2184 // 0.5 USD input required for a 1 EUR output. It sets a sendmax
-
2185 // of 0.4 USD, so the payment engine will need to do a forward
-
2186 // pass. Without limits, the 0.4 USD would produce 1000 EUR in
-
2187 // the forward pass. This test checks that the payment produces
-
2188 // 1 EUR, as expected.
-
2189
-
2190 Env env(*this, features);
-
2191 env.fund(XRP(10'000), bob, carol, gw);
-
2192 env.close();
-
2193 fund(env, gw, {alice}, XRP(10'000), {}, Fund::Acct);
-
2194 env.trust(USD(1'000), alice, bob, carol);
-
2195 env.trust(EUR(1'000), alice, bob, carol);
-
2196 env.close();
-
2197
-
2198 env(pay(gw, alice, USD(1'000)));
-
2199 env(pay(gw, bob, EUR(1'000)));
-
2200 env(pay(gw, bob, USD(1'000)));
-
2201 env.close();
-
2202
-
2203 // env(offer(bob, USD(1), drops(2)), txflags(tfPassive));
-
2204 AMM ammBob(env, bob, USD(8), XRPAmount{21});
-
2205 env(offer(bob, drops(1), EUR(1'000)), txflags(tfPassive));
-
2206
-
2207 env(pay(alice, carol, EUR(1)),
-
2208 path(~XRP, ~EUR),
-
2209 sendmax(USD(0.4)),
- -
2211
-
2212 BEAST_EXPECT(expectHolding(env, carol, EUR(1)));
-
2213 BEAST_EXPECT(ammBob.expectBalances(
-
2214 USD(8.4), XRPAmount{20}, ammBob.tokens()));
-
2215 }
-
2216 }
+
2092 env(pay(gw, alice, BTC(60)));
+
2093 env(pay(gw, bob, BTC(100)));
+
2094 env(pay(gw, bob, USD(100)));
+
2095 env(pay(gw, bob, EUR(50)));
+
2096 env(pay(gw, carol, EUR(1)));
+
2097 env.close();
+
2098
+
2099 // This is multiplath, which generates limited # of offers
+
2100 AMM ammBobBTC_USD(env, bob, BTC(50), USD(50));
+
2101 env(offer(bob, BTC(60), EUR(50)));
+
2102 env(offer(carol, BTC(1'000), EUR(1)));
+
2103 env(offer(bob, EUR(50), USD(50)));
+
2104
+
2105 // unfund offer
+
2106 env(pay(bob, gw, EUR(50)));
+
2107 BEAST_EXPECT(ammBobBTC_USD.expectBalances(
+
2108 BTC(50), USD(50), ammBobBTC_USD.tokens()));
+
2109 BEAST_EXPECT(isOffer(env, bob, BTC(60), EUR(50)));
+
2110 BEAST_EXPECT(isOffer(env, carol, BTC(1'000), EUR(1)));
+
2111 BEAST_EXPECT(isOffer(env, bob, EUR(50), USD(50)));
+
2112
+
2113 auto flowJournal = env.app().logs().journal("Flow");
+
2114 auto const flowResult = [&] {
+
2115 STAmount deliver(USD(51));
+
2116 STAmount smax(BTC(61));
+
2117 PaymentSandbox sb(env.current().get(), tapNONE);
+ +
2119 auto IPE = [](Issue const& iss) {
+
2120 return STPathElement(
+ +
2122 xrpAccount(),
+
2123 iss.currency,
+
2124 iss.account);
+
2125 };
+
2126 {
+
2127 // BTC -> USD
+
2128 STPath p1({IPE(USD.issue())});
+
2129 paths.push_back(p1);
+
2130 // BTC -> EUR -> USD
+
2131 STPath p2({IPE(EUR.issue()), IPE(USD.issue())});
+
2132 paths.push_back(p2);
+
2133 }
+
2134
+
2135 return flow(
+
2136 sb,
+
2137 deliver,
+
2138 alice,
+
2139 carol,
+
2140 paths,
+
2141 false,
+
2142 false,
+
2143 true,
+ + +
2146 smax,
+ +
2148 flowJournal);
+
2149 }();
+
2150
+
2151 BEAST_EXPECT(flowResult.removableOffers.size() == 1);
+
2152 env.app().openLedger().modify(
+
2153 [&](OpenView& view, beast::Journal j) {
+
2154 if (flowResult.removableOffers.empty())
+
2155 return false;
+
2156 Sandbox sb(&view, tapNONE);
+
2157 for (auto const& o : flowResult.removableOffers)
+
2158 if (auto ok = sb.peek(keylet::offer(o)))
+
2159 offerDelete(sb, ok, flowJournal);
+
2160 sb.apply(view);
+
2161 return true;
+
2162 });
+
2163
+
2164 // used in payment, but since payment failed should be untouched
+
2165 BEAST_EXPECT(ammBobBTC_USD.expectBalances(
+
2166 BTC(50), USD(50), ammBobBTC_USD.tokens()));
+
2167 BEAST_EXPECT(isOffer(env, carol, BTC(1'000), EUR(1)));
+
2168 // found unfunded
+
2169 BEAST_EXPECT(!isOffer(env, bob, BTC(60), EUR(50)));
+
2170 }
+
2171 {
+
2172 // Do not produce more in the forward pass than the reverse pass
+
2173 // This test uses a path that whose reverse pass will compute a
+
2174 // 0.5 USD input required for a 1 EUR output. It sets a sendmax
+
2175 // of 0.4 USD, so the payment engine will need to do a forward
+
2176 // pass. Without limits, the 0.4 USD would produce 1000 EUR in
+
2177 // the forward pass. This test checks that the payment produces
+
2178 // 1 EUR, as expected.
+
2179
+
2180 Env env(*this, features);
+
2181 env.fund(XRP(10'000), bob, carol, gw);
+
2182 env.close();
+
2183 fund(env, gw, {alice}, XRP(10'000), {}, Fund::Acct);
+
2184 env.trust(USD(1'000), alice, bob, carol);
+
2185 env.trust(EUR(1'000), alice, bob, carol);
+
2186 env.close();
+
2187
+
2188 env(pay(gw, alice, USD(1'000)));
+
2189 env(pay(gw, bob, EUR(1'000)));
+
2190 env(pay(gw, bob, USD(1'000)));
+
2191 env.close();
+
2192
+
2193 // env(offer(bob, USD(1), drops(2)), txflags(tfPassive));
+
2194 AMM ammBob(env, bob, USD(8), XRPAmount{21});
+
2195 env(offer(bob, drops(1), EUR(1'000)), txflags(tfPassive));
+
2196
+
2197 env(pay(alice, carol, EUR(1)),
+
2198 path(~XRP, ~EUR),
+
2199 sendmax(USD(0.4)),
+ +
2201
+
2202 BEAST_EXPECT(expectHolding(env, carol, EUR(1)));
+
2203 BEAST_EXPECT(ammBob.expectBalances(
+
2204 USD(8.4), XRPAmount{20}, ammBob.tokens()));
+
2205 }
+
2206 }
+
2207
+
2208 void
+
+ +
2210 {
+
2211 testcase("No Owner Fee");
+
2212 using namespace jtx;
+
2213
+
2214 {
+
2215 // payment via AMM
+
2216 Env env(*this, features);
2217
-
2218 void
-
- -
2220 {
-
2221 testcase("No Owner Fee");
-
2222 using namespace jtx;
-
2223
-
2224 {
-
2225 // payment via AMM
-
2226 Env env(*this, features);
-
2227
-
2228 fund(
-
2229 env,
-
2230 gw,
-
2231 {alice, bob, carol},
-
2232 XRP(1'000),
-
2233 {USD(1'000), GBP(1'000)});
-
2234 env(rate(gw, 1.25));
-
2235 env.close();
-
2236
-
2237 AMM amm(env, bob, GBP(1'000), USD(1'000));
-
2238
-
2239 env(pay(alice, carol, USD(100)),
-
2240 path(~USD),
-
2241 sendmax(GBP(150)),
- -
2243 env.close();
-
2244
-
2245 // alice buys 107.1428USD with 120GBP and pays 25% tr fee on 120GBP
-
2246 // 1,000 - 120*1.25 = 850GBP
-
2247 BEAST_EXPECT(expectHolding(env, alice, GBP(850)));
-
2248 if (!features[fixAMMv1_1])
-
2249 {
-
2250 // 120GBP is swapped in for 107.1428USD
-
2251 BEAST_EXPECT(amm.expectBalances(
-
2252 GBP(1'120),
-
2253 STAmount{USD, UINT64_C(892'8571428571428), -13},
-
2254 amm.tokens()));
-
2255 }
-
2256 else
-
2257 {
-
2258 BEAST_EXPECT(amm.expectBalances(
-
2259 GBP(1'120),
-
2260 STAmount{USD, UINT64_C(892'8571428571429), -13},
-
2261 amm.tokens()));
-
2262 }
-
2263 // 25% of 85.7142USD is paid in tr fee
-
2264 // 85.7142*1.25 = 107.1428USD
-
2265 BEAST_EXPECT(expectHolding(
-
2266 env, carol, STAmount(USD, UINT64_C(1'085'714285714286), -12)));
-
2267 }
-
2268
-
2269 {
-
2270 // Payment via offer and AMM
-
2271 Env env(*this, features);
-
2272 Account const ed("ed");
-
2273
-
2274 fund(
-
2275 env,
-
2276 gw,
-
2277 {alice, bob, carol, ed},
-
2278 XRP(1'000),
-
2279 {USD(1'000), EUR(1'000), GBP(1'000)});
-
2280 env(rate(gw, 1.25));
-
2281 env.close();
-
2282
-
2283 env(offer(ed, GBP(1'000), EUR(1'000)), txflags(tfPassive));
-
2284 env.close();
-
2285
-
2286 AMM amm(env, bob, EUR(1'000), USD(1'000));
-
2287
-
2288 env(pay(alice, carol, USD(100)),
-
2289 path(~EUR, ~USD),
-
2290 sendmax(GBP(150)),
- -
2292 env.close();
-
2293
-
2294 // alice buys 120EUR with 120GBP via the offer
-
2295 // and pays 25% tr fee on 120GBP
-
2296 // 1,000 - 120*1.25 = 850GBP
-
2297 BEAST_EXPECT(expectHolding(env, alice, GBP(850)));
-
2298 // consumed offer is 120GBP/120EUR
-
2299 // ed doesn't pay tr fee
-
2300 BEAST_EXPECT(expectHolding(env, ed, EUR(880), GBP(1'120)));
-
2301 BEAST_EXPECT(
-
2302 expectOffers(env, ed, 1, {Amounts{GBP(880), EUR(880)}}));
-
2303 // 25% on 96EUR is paid in tr fee 96*1.25 = 120EUR
-
2304 // 96EUR is swapped in for 87.5912USD
-
2305 BEAST_EXPECT(amm.expectBalances(
-
2306 EUR(1'096),
-
2307 STAmount{USD, UINT64_C(912'4087591240876), -13},
-
2308 amm.tokens()));
-
2309 // 25% on 70.0729USD is paid in tr fee 70.0729*1.25 = 87.5912USD
-
2310 BEAST_EXPECT(expectHolding(
-
2311 env, carol, STAmount(USD, UINT64_C(1'070'07299270073), -11)));
-
2312 }
-
2313 {
-
2314 // Payment via AMM, AMM
-
2315 Env env(*this, features);
-
2316 Account const ed("ed");
-
2317
-
2318 fund(
-
2319 env,
-
2320 gw,
-
2321 {alice, bob, carol, ed},
-
2322 XRP(1'000),
-
2323 {USD(1'000), EUR(1'000), GBP(1'000)});
-
2324 env(rate(gw, 1.25));
-
2325 env.close();
-
2326
-
2327 AMM amm1(env, bob, GBP(1'000), EUR(1'000));
-
2328 AMM amm2(env, ed, EUR(1'000), USD(1'000));
-
2329
-
2330 env(pay(alice, carol, USD(100)),
-
2331 path(~EUR, ~USD),
-
2332 sendmax(GBP(150)),
- -
2334 env.close();
-
2335
-
2336 BEAST_EXPECT(expectHolding(env, alice, GBP(850)));
-
2337 if (!features[fixAMMv1_1])
-
2338 {
-
2339 // alice buys 107.1428EUR with 120GBP and pays 25% tr fee on
-
2340 // 120GBP 1,000 - 120*1.25 = 850GBP 120GBP is swapped in for
-
2341 // 107.1428EUR
-
2342 BEAST_EXPECT(amm1.expectBalances(
-
2343 GBP(1'120),
-
2344 STAmount{EUR, UINT64_C(892'8571428571428), -13},
-
2345 amm1.tokens()));
-
2346 // 25% on 85.7142EUR is paid in tr fee 85.7142*1.25 =
-
2347 // 107.1428EUR 85.7142EUR is swapped in for 78.9473USD
-
2348 BEAST_EXPECT(amm2.expectBalances(
-
2349 STAmount(EUR, UINT64_C(1'085'714285714286), -12),
-
2350 STAmount{USD, UINT64_C(921'0526315789471), -13},
-
2351 amm2.tokens()));
-
2352 }
-
2353 else
-
2354 {
-
2355 // alice buys 107.1428EUR with 120GBP and pays 25% tr fee on
-
2356 // 120GBP 1,000 - 120*1.25 = 850GBP 120GBP is swapped in for
-
2357 // 107.1428EUR
-
2358 BEAST_EXPECT(amm1.expectBalances(
-
2359 GBP(1'120),
-
2360 STAmount{EUR, UINT64_C(892'8571428571429), -13},
-
2361 amm1.tokens()));
-
2362 // 25% on 85.7142EUR is paid in tr fee 85.7142*1.25 =
-
2363 // 107.1428EUR 85.7142EUR is swapped in for 78.9473USD
-
2364 BEAST_EXPECT(amm2.expectBalances(
-
2365 STAmount(EUR, UINT64_C(1'085'714285714286), -12),
-
2366 STAmount{USD, UINT64_C(921'052631578948), -12},
-
2367 amm2.tokens()));
-
2368 }
-
2369 // 25% on 63.1578USD is paid in tr fee 63.1578*1.25 = 78.9473USD
-
2370 BEAST_EXPECT(expectHolding(
-
2371 env, carol, STAmount(USD, UINT64_C(1'063'157894736842), -12)));
-
2372 }
-
2373 {
-
2374 // AMM offer crossing
-
2375 Env env(*this, features);
-
2376
-
2377 fund(env, gw, {alice, bob}, XRP(1'000), {USD(1'100), EUR(1'100)});
-
2378 env(rate(gw, 1.25));
-
2379 env.close();
-
2380
-
2381 AMM amm(env, bob, USD(1'000), EUR(1'100));
-
2382 env(offer(alice, EUR(100), USD(100)));
-
2383 env.close();
-
2384
-
2385 // 100USD is swapped in for 100EUR
-
2386 BEAST_EXPECT(
-
2387 amm.expectBalances(USD(1'100), EUR(1'000), amm.tokens()));
-
2388 // alice pays 25% tr fee on 100USD 1100-100*1.25 = 975USD
-
2389 BEAST_EXPECT(expectHolding(env, alice, USD(975), EUR(1'200)));
-
2390 BEAST_EXPECT(expectOffers(env, alice, 0));
-
2391 }
-
2392
-
2393 {
-
2394 // Payment via AMM with limit quality
-
2395 Env env(*this, features);
-
2396
-
2397 fund(
-
2398 env,
-
2399 gw,
-
2400 {alice, bob, carol},
-
2401 XRP(1'000),
-
2402 {USD(1'000), GBP(1'000)});
-
2403 env(rate(gw, 1.25));
+
2218 fund(
+
2219 env,
+
2220 gw,
+
2221 {alice, bob, carol},
+
2222 XRP(1'000),
+
2223 {USD(1'000), GBP(1'000)});
+
2224 env(rate(gw, 1.25));
+
2225 env.close();
+
2226
+
2227 AMM amm(env, bob, GBP(1'000), USD(1'000));
+
2228
+
2229 env(pay(alice, carol, USD(100)),
+
2230 path(~USD),
+
2231 sendmax(GBP(150)),
+ +
2233 env.close();
+
2234
+
2235 // alice buys 107.1428USD with 120GBP and pays 25% tr fee on 120GBP
+
2236 // 1,000 - 120*1.25 = 850GBP
+
2237 BEAST_EXPECT(expectHolding(env, alice, GBP(850)));
+
2238 if (!features[fixAMMv1_1])
+
2239 {
+
2240 // 120GBP is swapped in for 107.1428USD
+
2241 BEAST_EXPECT(amm.expectBalances(
+
2242 GBP(1'120),
+
2243 STAmount{USD, UINT64_C(892'8571428571428), -13},
+
2244 amm.tokens()));
+
2245 }
+
2246 else
+
2247 {
+
2248 BEAST_EXPECT(amm.expectBalances(
+
2249 GBP(1'120),
+
2250 STAmount{USD, UINT64_C(892'8571428571429), -13},
+
2251 amm.tokens()));
+
2252 }
+
2253 // 25% of 85.7142USD is paid in tr fee
+
2254 // 85.7142*1.25 = 107.1428USD
+
2255 BEAST_EXPECT(expectHolding(
+
2256 env, carol, STAmount(USD, UINT64_C(1'085'714285714286), -12)));
+
2257 }
+
2258
+
2259 {
+
2260 // Payment via offer and AMM
+
2261 Env env(*this, features);
+
2262 Account const ed("ed");
+
2263
+
2264 fund(
+
2265 env,
+
2266 gw,
+
2267 {alice, bob, carol, ed},
+
2268 XRP(1'000),
+
2269 {USD(1'000), EUR(1'000), GBP(1'000)});
+
2270 env(rate(gw, 1.25));
+
2271 env.close();
+
2272
+
2273 env(offer(ed, GBP(1'000), EUR(1'000)), txflags(tfPassive));
+
2274 env.close();
+
2275
+
2276 AMM amm(env, bob, EUR(1'000), USD(1'000));
+
2277
+
2278 env(pay(alice, carol, USD(100)),
+
2279 path(~EUR, ~USD),
+
2280 sendmax(GBP(150)),
+ +
2282 env.close();
+
2283
+
2284 // alice buys 120EUR with 120GBP via the offer
+
2285 // and pays 25% tr fee on 120GBP
+
2286 // 1,000 - 120*1.25 = 850GBP
+
2287 BEAST_EXPECT(expectHolding(env, alice, GBP(850)));
+
2288 // consumed offer is 120GBP/120EUR
+
2289 // ed doesn't pay tr fee
+
2290 BEAST_EXPECT(expectHolding(env, ed, EUR(880), GBP(1'120)));
+
2291 BEAST_EXPECT(
+
2292 expectOffers(env, ed, 1, {Amounts{GBP(880), EUR(880)}}));
+
2293 // 25% on 96EUR is paid in tr fee 96*1.25 = 120EUR
+
2294 // 96EUR is swapped in for 87.5912USD
+
2295 BEAST_EXPECT(amm.expectBalances(
+
2296 EUR(1'096),
+
2297 STAmount{USD, UINT64_C(912'4087591240876), -13},
+
2298 amm.tokens()));
+
2299 // 25% on 70.0729USD is paid in tr fee 70.0729*1.25 = 87.5912USD
+
2300 BEAST_EXPECT(expectHolding(
+
2301 env, carol, STAmount(USD, UINT64_C(1'070'07299270073), -11)));
+
2302 }
+
2303 {
+
2304 // Payment via AMM, AMM
+
2305 Env env(*this, features);
+
2306 Account const ed("ed");
+
2307
+
2308 fund(
+
2309 env,
+
2310 gw,
+
2311 {alice, bob, carol, ed},
+
2312 XRP(1'000),
+
2313 {USD(1'000), EUR(1'000), GBP(1'000)});
+
2314 env(rate(gw, 1.25));
+
2315 env.close();
+
2316
+
2317 AMM amm1(env, bob, GBP(1'000), EUR(1'000));
+
2318 AMM amm2(env, ed, EUR(1'000), USD(1'000));
+
2319
+
2320 env(pay(alice, carol, USD(100)),
+
2321 path(~EUR, ~USD),
+
2322 sendmax(GBP(150)),
+ +
2324 env.close();
+
2325
+
2326 BEAST_EXPECT(expectHolding(env, alice, GBP(850)));
+
2327 if (!features[fixAMMv1_1])
+
2328 {
+
2329 // alice buys 107.1428EUR with 120GBP and pays 25% tr fee on
+
2330 // 120GBP 1,000 - 120*1.25 = 850GBP 120GBP is swapped in for
+
2331 // 107.1428EUR
+
2332 BEAST_EXPECT(amm1.expectBalances(
+
2333 GBP(1'120),
+
2334 STAmount{EUR, UINT64_C(892'8571428571428), -13},
+
2335 amm1.tokens()));
+
2336 // 25% on 85.7142EUR is paid in tr fee 85.7142*1.25 =
+
2337 // 107.1428EUR 85.7142EUR is swapped in for 78.9473USD
+
2338 BEAST_EXPECT(amm2.expectBalances(
+
2339 STAmount(EUR, UINT64_C(1'085'714285714286), -12),
+
2340 STAmount{USD, UINT64_C(921'0526315789471), -13},
+
2341 amm2.tokens()));
+
2342 }
+
2343 else
+
2344 {
+
2345 // alice buys 107.1428EUR with 120GBP and pays 25% tr fee on
+
2346 // 120GBP 1,000 - 120*1.25 = 850GBP 120GBP is swapped in for
+
2347 // 107.1428EUR
+
2348 BEAST_EXPECT(amm1.expectBalances(
+
2349 GBP(1'120),
+
2350 STAmount{EUR, UINT64_C(892'8571428571429), -13},
+
2351 amm1.tokens()));
+
2352 // 25% on 85.7142EUR is paid in tr fee 85.7142*1.25 =
+
2353 // 107.1428EUR 85.7142EUR is swapped in for 78.9473USD
+
2354 BEAST_EXPECT(amm2.expectBalances(
+
2355 STAmount(EUR, UINT64_C(1'085'714285714286), -12),
+
2356 STAmount{USD, UINT64_C(921'052631578948), -12},
+
2357 amm2.tokens()));
+
2358 }
+
2359 // 25% on 63.1578USD is paid in tr fee 63.1578*1.25 = 78.9473USD
+
2360 BEAST_EXPECT(expectHolding(
+
2361 env, carol, STAmount(USD, UINT64_C(1'063'157894736842), -12)));
+
2362 }
+
2363 {
+
2364 // AMM offer crossing
+
2365 Env env(*this, features);
+
2366
+
2367 fund(env, gw, {alice, bob}, XRP(1'000), {USD(1'100), EUR(1'100)});
+
2368 env(rate(gw, 1.25));
+
2369 env.close();
+
2370
+
2371 AMM amm(env, bob, USD(1'000), EUR(1'100));
+
2372 env(offer(alice, EUR(100), USD(100)));
+
2373 env.close();
+
2374
+
2375 // 100USD is swapped in for 100EUR
+
2376 BEAST_EXPECT(
+
2377 amm.expectBalances(USD(1'100), EUR(1'000), amm.tokens()));
+
2378 // alice pays 25% tr fee on 100USD 1100-100*1.25 = 975USD
+
2379 BEAST_EXPECT(expectHolding(env, alice, USD(975), EUR(1'200)));
+
2380 BEAST_EXPECT(expectOffers(env, alice, 0));
+
2381 }
+
2382
+
2383 {
+
2384 // Payment via AMM with limit quality
+
2385 Env env(*this, features);
+
2386
+
2387 fund(
+
2388 env,
+
2389 gw,
+
2390 {alice, bob, carol},
+
2391 XRP(1'000),
+
2392 {USD(1'000), GBP(1'000)});
+
2393 env(rate(gw, 1.25));
+
2394 env.close();
+
2395
+
2396 AMM amm(env, bob, GBP(1'000), USD(1'000));
+
2397
+
2398 // requested quality limit is 100USD/178.58GBP = 0.55997
+
2399 // trade quality is 100USD/178.5714 = 0.55999
+
2400 env(pay(alice, carol, USD(100)),
+
2401 path(~USD),
+
2402 sendmax(GBP(178.58)),
+
2404 env.close();
2405
-
2406 AMM amm(env, bob, GBP(1'000), USD(1'000));
-
2407
-
2408 // requested quality limit is 100USD/178.58GBP = 0.55997
-
2409 // trade quality is 100USD/178.5714 = 0.55999
-
2410 env(pay(alice, carol, USD(100)),
-
2411 path(~USD),
-
2412 sendmax(GBP(178.58)),
- -
2414 env.close();
-
2415
-
2416 // alice buys 125USD with 142.8571GBP and pays 25% tr fee
-
2417 // on 142.8571GBP
-
2418 // 1,000 - 142.8571*1.25 = 821.4285GBP
-
2419 BEAST_EXPECT(expectHolding(
-
2420 env, alice, STAmount(GBP, UINT64_C(821'4285714285712), -13)));
-
2421 // 142.8571GBP is swapped in for 125USD
-
2422 BEAST_EXPECT(amm.expectBalances(
-
2423 STAmount{GBP, UINT64_C(1'142'857142857143), -12},
-
2424 USD(875),
-
2425 amm.tokens()));
-
2426 // 25% on 100USD is paid in tr fee
-
2427 // 100*1.25 = 125USD
-
2428 BEAST_EXPECT(expectHolding(env, carol, USD(1'100)));
-
2429 }
-
2430 {
-
2431 // Payment via AMM with limit quality, deliver less
-
2432 // than requested
-
2433 Env env(*this, features);
-
2434
-
2435 fund(
-
2436 env,
-
2437 gw,
-
2438 {alice, bob, carol},
-
2439 XRP(1'000),
-
2440 {USD(1'200), GBP(1'200)});
-
2441 env(rate(gw, 1.25));
+
2406 // alice buys 125USD with 142.8571GBP and pays 25% tr fee
+
2407 // on 142.8571GBP
+
2408 // 1,000 - 142.8571*1.25 = 821.4285GBP
+
2409 BEAST_EXPECT(expectHolding(
+
2410 env, alice, STAmount(GBP, UINT64_C(821'4285714285712), -13)));
+
2411 // 142.8571GBP is swapped in for 125USD
+
2412 BEAST_EXPECT(amm.expectBalances(
+
2413 STAmount{GBP, UINT64_C(1'142'857142857143), -12},
+
2414 USD(875),
+
2415 amm.tokens()));
+
2416 // 25% on 100USD is paid in tr fee
+
2417 // 100*1.25 = 125USD
+
2418 BEAST_EXPECT(expectHolding(env, carol, USD(1'100)));
+
2419 }
+
2420 {
+
2421 // Payment via AMM with limit quality, deliver less
+
2422 // than requested
+
2423 Env env(*this, features);
+
2424
+
2425 fund(
+
2426 env,
+
2427 gw,
+
2428 {alice, bob, carol},
+
2429 XRP(1'000),
+
2430 {USD(1'200), GBP(1'200)});
+
2431 env(rate(gw, 1.25));
+
2432 env.close();
+
2433
+
2434 AMM amm(env, bob, GBP(1'000), USD(1'200));
+
2435
+
2436 // requested quality limit is 90USD/120GBP = 0.75
+
2437 // trade quality is 22.5USD/30GBP = 0.75
+
2438 env(pay(alice, carol, USD(90)),
+
2439 path(~USD),
+
2440 sendmax(GBP(120)),
+
2442 env.close();
2443
-
2444 AMM amm(env, bob, GBP(1'000), USD(1'200));
-
2445
-
2446 // requested quality limit is 90USD/120GBP = 0.75
-
2447 // trade quality is 22.5USD/30GBP = 0.75
-
2448 env(pay(alice, carol, USD(90)),
-
2449 path(~USD),
-
2450 sendmax(GBP(120)),
- -
2452 env.close();
-
2453
-
2454 if (!features[fixAMMv1_1])
+
2444 if (!features[fixAMMv1_1])
+
2445 {
+
2446 // alice buys 28.125USD with 24GBP and pays 25% tr fee
+
2447 // on 24GBP
+
2448 // 1,200 - 24*1.25 = 1,170GBP
+
2449 BEAST_EXPECT(expectHolding(env, alice, GBP(1'170)));
+
2450 // 24GBP is swapped in for 28.125USD
+
2451 BEAST_EXPECT(amm.expectBalances(
+
2452 GBP(1'024), USD(1'171.875), amm.tokens()));
+
2453 }
+
2454 else
2455 {
2456 // alice buys 28.125USD with 24GBP and pays 25% tr fee
2457 // on 24GBP
-
2458 // 1,200 - 24*1.25 = 1,170GBP
-
2459 BEAST_EXPECT(expectHolding(env, alice, GBP(1'170)));
-
2460 // 24GBP is swapped in for 28.125USD
-
2461 BEAST_EXPECT(amm.expectBalances(
-
2462 GBP(1'024), USD(1'171.875), amm.tokens()));
-
2463 }
-
2464 else
-
2465 {
-
2466 // alice buys 28.125USD with 24GBP and pays 25% tr fee
-
2467 // on 24GBP
-
2468 // 1,200 - 24*1.25 =~ 1,170GBP
-
2469 BEAST_EXPECT(expectHolding(
-
2470 env,
-
2471 alice,
-
2472 STAmount{GBP, UINT64_C(1'169'999999999999), -12}));
-
2473 // 24GBP is swapped in for 28.125USD
-
2474 BEAST_EXPECT(amm.expectBalances(
-
2475 STAmount{GBP, UINT64_C(1'024'000000000001), -12},
-
2476 USD(1'171.875),
-
2477 amm.tokens()));
-
2478 }
-
2479 // 25% on 22.5USD is paid in tr fee
-
2480 // 22.5*1.25 = 28.125USD
-
2481 BEAST_EXPECT(expectHolding(env, carol, USD(1'222.5)));
-
2482 }
-
2483 {
-
2484 // Payment via offer and AMM with limit quality, deliver less
-
2485 // than requested
-
2486 Env env(*this, features);
-
2487 Account const ed("ed");
-
2488
-
2489 fund(
-
2490 env,
-
2491 gw,
-
2492 {alice, bob, carol, ed},
-
2493 XRP(1'000),
-
2494 {USD(1'400), EUR(1'400), GBP(1'400)});
-
2495 env(rate(gw, 1.25));
-
2496 env.close();
-
2497
-
2498 env(offer(ed, GBP(1'000), EUR(1'000)), txflags(tfPassive));
+
2458 // 1,200 - 24*1.25 =~ 1,170GBP
+
2459 BEAST_EXPECT(expectHolding(
+
2460 env,
+
2461 alice,
+
2462 STAmount{GBP, UINT64_C(1'169'999999999999), -12}));
+
2463 // 24GBP is swapped in for 28.125USD
+
2464 BEAST_EXPECT(amm.expectBalances(
+
2465 STAmount{GBP, UINT64_C(1'024'000000000001), -12},
+
2466 USD(1'171.875),
+
2467 amm.tokens()));
+
2468 }
+
2469 // 25% on 22.5USD is paid in tr fee
+
2470 // 22.5*1.25 = 28.125USD
+
2471 BEAST_EXPECT(expectHolding(env, carol, USD(1'222.5)));
+
2472 }
+
2473 {
+
2474 // Payment via offer and AMM with limit quality, deliver less
+
2475 // than requested
+
2476 Env env(*this, features);
+
2477 Account const ed("ed");
+
2478
+
2479 fund(
+
2480 env,
+
2481 gw,
+
2482 {alice, bob, carol, ed},
+
2483 XRP(1'000),
+
2484 {USD(1'400), EUR(1'400), GBP(1'400)});
+
2485 env(rate(gw, 1.25));
+
2486 env.close();
+
2487
+
2488 env(offer(ed, GBP(1'000), EUR(1'000)), txflags(tfPassive));
+
2489 env.close();
+
2490
+
2491 AMM amm(env, bob, EUR(1'000), USD(1'400));
+
2492
+
2493 // requested quality limit is 95USD/140GBP = 0.6785
+
2494 // trade quality is 59.7321USD/88.0262GBP = 0.6785
+
2495 env(pay(alice, carol, USD(95)),
+
2496 path(~EUR, ~USD),
+
2497 sendmax(GBP(140)),
+
2499 env.close();
2500
-
2501 AMM amm(env, bob, EUR(1'000), USD(1'400));
-
2502
-
2503 // requested quality limit is 95USD/140GBP = 0.6785
-
2504 // trade quality is 59.7321USD/88.0262GBP = 0.6785
-
2505 env(pay(alice, carol, USD(95)),
-
2506 path(~EUR, ~USD),
-
2507 sendmax(GBP(140)),
- -
2509 env.close();
-
2510
-
2511 if (!features[fixAMMv1_1])
-
2512 {
-
2513 // alice buys 70.4210EUR with 70.4210GBP via the offer
-
2514 // and pays 25% tr fee on 70.4210GBP
-
2515 // 1,400 - 70.4210*1.25 = 1400 - 88.0262 = 1311.9736GBP
-
2516 BEAST_EXPECT(expectHolding(
-
2517 env,
-
2518 alice,
-
2519 STAmount{GBP, UINT64_C(1'311'973684210527), -12}));
-
2520 // ed doesn't pay tr fee, the balances reflect consumed offer
-
2521 // 70.4210GBP/70.4210EUR
-
2522 BEAST_EXPECT(expectHolding(
-
2523 env,
-
2524 ed,
-
2525 STAmount{EUR, UINT64_C(1'329'578947368421), -12},
-
2526 STAmount{GBP, UINT64_C(1'470'421052631579), -12}));
-
2527 BEAST_EXPECT(expectOffers(
-
2528 env,
-
2529 ed,
-
2530 1,
-
2531 {Amounts{
-
2532 STAmount{GBP, UINT64_C(929'5789473684212), -13},
-
2533 STAmount{EUR, UINT64_C(929'5789473684212), -13}}}));
-
2534 // 25% on 56.3368EUR is paid in tr fee 56.3368*1.25 = 70.4210EUR
-
2535 // 56.3368EUR is swapped in for 74.6651USD
-
2536 BEAST_EXPECT(amm.expectBalances(
-
2537 STAmount{EUR, UINT64_C(1'056'336842105263), -12},
-
2538 STAmount{USD, UINT64_C(1'325'334821428571), -12},
-
2539 amm.tokens()));
-
2540 }
-
2541 else
-
2542 {
-
2543 // alice buys 70.4210EUR with 70.4210GBP via the offer
-
2544 // and pays 25% tr fee on 70.4210GBP
-
2545 // 1,400 - 70.4210*1.25 = 1400 - 88.0262 = 1311.9736GBP
-
2546 BEAST_EXPECT(expectHolding(
-
2547 env,
-
2548 alice,
-
2549 STAmount{GBP, UINT64_C(1'311'973684210525), -12}));
-
2550 // ed doesn't pay tr fee, the balances reflect consumed offer
-
2551 // 70.4210GBP/70.4210EUR
-
2552 BEAST_EXPECT(expectHolding(
-
2553 env,
-
2554 ed,
-
2555 STAmount{EUR, UINT64_C(1'329'57894736842), -11},
-
2556 STAmount{GBP, UINT64_C(1'470'42105263158), -11}));
-
2557 BEAST_EXPECT(expectOffers(
-
2558 env,
-
2559 ed,
-
2560 1,
-
2561 {Amounts{
-
2562 STAmount{GBP, UINT64_C(929'57894736842), -11},
-
2563 STAmount{EUR, UINT64_C(929'57894736842), -11}}}));
-
2564 // 25% on 56.3368EUR is paid in tr fee 56.3368*1.25 = 70.4210EUR
-
2565 // 56.3368EUR is swapped in for 74.6651USD
-
2566 BEAST_EXPECT(amm.expectBalances(
-
2567 STAmount{EUR, UINT64_C(1'056'336842105264), -12},
-
2568 STAmount{USD, UINT64_C(1'325'334821428571), -12},
-
2569 amm.tokens()));
-
2570 }
-
2571 // 25% on 59.7321USD is paid in tr fee 59.7321*1.25 = 74.6651USD
-
2572 BEAST_EXPECT(expectHolding(
-
2573 env, carol, STAmount(USD, UINT64_C(1'459'732142857143), -12)));
-
2574 }
-
2575 {
-
2576 // Payment via AMM and offer with limit quality, deliver less
-
2577 // than requested
-
2578 Env env(*this, features);
-
2579 Account const ed("ed");
-
2580
-
2581 fund(
-
2582 env,
-
2583 gw,
-
2584 {alice, bob, carol, ed},
-
2585 XRP(1'000),
-
2586 {USD(1'400), EUR(1'400), GBP(1'400)});
-
2587 env(rate(gw, 1.25));
-
2588 env.close();
-
2589
-
2590 AMM amm(env, bob, GBP(1'000), EUR(1'000));
-
2591
-
2592 env(offer(ed, EUR(1'000), USD(1'400)), txflags(tfPassive));
-
2593 env.close();
-
2594
-
2595 // requested quality limit is 95USD/140GBP = 0.6785
-
2596 // trade quality is 47.7857USD/70.4210GBP = 0.6785
-
2597 env(pay(alice, carol, USD(95)),
-
2598 path(~EUR, ~USD),
-
2599 sendmax(GBP(140)),
- -
2601 env.close();
-
2602
-
2603 if (!features[fixAMMv1_1])
-
2604 {
-
2605 // alice buys 53.3322EUR with 56.3368GBP via the amm
-
2606 // and pays 25% tr fee on 56.3368GBP
-
2607 // 1,400 - 56.3368*1.25 = 1400 - 70.4210 = 1329.5789GBP
-
2608 BEAST_EXPECT(expectHolding(
-
2609 env,
-
2610 alice,
-
2611 STAmount{GBP, UINT64_C(1'329'578947368421), -12}));
-
2614 // 56.3368GBP is swapped in for 53.3322EUR
-
2615 BEAST_EXPECT(amm.expectBalances(
-
2616 STAmount{GBP, UINT64_C(1'056'336842105263), -12},
-
2617 STAmount{EUR, UINT64_C(946'6677295918366), -13},
-
2618 amm.tokens()));
-
2619 }
-
2620 else
-
2621 {
-
2622 // alice buys 53.3322EUR with 56.3368GBP via the amm
-
2623 // and pays 25% tr fee on 56.3368GBP
-
2624 // 1,400 - 56.3368*1.25 = 1400 - 70.4210 = 1329.5789GBP
-
2625 BEAST_EXPECT(expectHolding(
-
2626 env,
-
2627 alice,
-
2628 STAmount{GBP, UINT64_C(1'329'57894736842), -11}));
-
2631 // 56.3368GBP is swapped in for 53.3322EUR
-
2632 BEAST_EXPECT(amm.expectBalances(
-
2633 STAmount{GBP, UINT64_C(1'056'336842105264), -12},
-
2634 STAmount{EUR, UINT64_C(946'6677295918366), -13},
-
2635 amm.tokens()));
-
2636 }
-
2637 // 25% on 42.6658EUR is paid in tr fee 42.6658*1.25 = 53.3322EUR
-
2638 // 42.6658EUR/59.7321USD
-
2639 BEAST_EXPECT(expectHolding(
-
2640 env,
-
2641 ed,
-
2642 STAmount{USD, UINT64_C(1'340'267857142857), -12},
-
2643 STAmount{EUR, UINT64_C(1'442'665816326531), -12}));
-
2644 BEAST_EXPECT(expectOffers(
-
2645 env,
-
2646 ed,
-
2647 1,
-
2648 {Amounts{
-
2649 STAmount{EUR, UINT64_C(957'3341836734693), -13},
-
2650 STAmount{USD, UINT64_C(1'340'267857142857), -12}}}));
-
2651 // 25% on 47.7857USD is paid in tr fee 47.7857*1.25 = 59.7321USD
-
2652 BEAST_EXPECT(expectHolding(
-
2653 env, carol, STAmount(USD, UINT64_C(1'447'785714285714), -12)));
-
2654 }
-
2655 {
-
2656 // Payment via AMM, AMM with limit quality, deliver less
-
2657 // than requested
-
2658 Env env(*this, features);
-
2659 Account const ed("ed");
-
2660
-
2661 fund(
-
2662 env,
-
2663 gw,
-
2664 {alice, bob, carol, ed},
-
2665 XRP(1'000),
-
2666 {USD(1'400), EUR(1'400), GBP(1'400)});
-
2667 env(rate(gw, 1.25));
-
2668 env.close();
-
2669
-
2670 AMM amm1(env, bob, GBP(1'000), EUR(1'000));
-
2671 AMM amm2(env, ed, EUR(1'000), USD(1'400));
-
2672
-
2673 // requested quality limit is 90USD/145GBP = 0.6206
-
2674 // trade quality is 66.7432USD/107.5308GBP = 0.6206
-
2675 env(pay(alice, carol, USD(90)),
-
2676 path(~EUR, ~USD),
-
2677 sendmax(GBP(145)),
- -
2679 env.close();
-
2680
-
2681 if (!features[fixAMMv1_1])
-
2682 {
-
2683 // alice buys 53.3322EUR with 107.5308GBP
-
2684 // 25% on 86.0246GBP is paid in tr fee
-
2685 // 1,400 - 86.0246*1.25 = 1400 - 107.5308 = 1229.4691GBP
-
2686 BEAST_EXPECT(expectHolding(
-
2687 env,
-
2688 alice,
-
2689 STAmount{GBP, UINT64_C(1'292'469135802469), -12}));
-
2690 // 86.0246GBP is swapped in for 79.2106EUR
-
2691 BEAST_EXPECT(amm1.expectBalances(
-
2692 STAmount{GBP, UINT64_C(1'086'024691358025), -12},
-
2693 STAmount{EUR, UINT64_C(920'78937795562), -11},
-
2694 amm1.tokens()));
-
2695 // 25% on 63.3684EUR is paid in tr fee 63.3684*1.25 = 79.2106EUR
-
2696 // 63.3684EUR is swapped in for 83.4291USD
-
2697 BEAST_EXPECT(amm2.expectBalances(
-
2698 STAmount{EUR, UINT64_C(1'063'368497635504), -12},
-
2699 STAmount{USD, UINT64_C(1'316'570881226053), -12},
-
2700 amm2.tokens()));
-
2701 }
-
2702 else
-
2703 {
-
2704 // alice buys 53.3322EUR with 107.5308GBP
-
2705 // 25% on 86.0246GBP is paid in tr fee
-
2706 // 1,400 - 86.0246*1.25 = 1400 - 107.5308 = 1229.4691GBP
-
2707 BEAST_EXPECT(expectHolding(
-
2708 env,
-
2709 alice,
-
2710 STAmount{GBP, UINT64_C(1'292'469135802466), -12}));
-
2711 // 86.0246GBP is swapped in for 79.2106EUR
-
2712 BEAST_EXPECT(amm1.expectBalances(
-
2713 STAmount{GBP, UINT64_C(1'086'024691358027), -12},
-
2714 STAmount{EUR, UINT64_C(920'7893779556188), -13},
-
2715 amm1.tokens()));
-
2716 // 25% on 63.3684EUR is paid in tr fee 63.3684*1.25 = 79.2106EUR
-
2717 // 63.3684EUR is swapped in for 83.4291USD
-
2718 BEAST_EXPECT(amm2.expectBalances(
-
2719 STAmount{EUR, UINT64_C(1'063'368497635505), -12},
-
2720 STAmount{USD, UINT64_C(1'316'570881226053), -12},
-
2721 amm2.tokens()));
-
2722 }
-
2723 // 25% on 66.7432USD is paid in tr fee 66.7432*1.25 = 83.4291USD
-
2724 BEAST_EXPECT(expectHolding(
-
2725 env, carol, STAmount(USD, UINT64_C(1'466'743295019157), -12)));
-
2726 }
-
2727 {
-
2728 // Payment by the issuer via AMM, AMM with limit quality,
-
2729 // deliver less than requested
-
2730 Env env(*this, features);
-
2731
-
2732 fund(
-
2733 env,
-
2734 gw,
-
2735 {alice, bob, carol},
-
2736 XRP(1'000),
-
2737 {USD(1'400), EUR(1'400), GBP(1'400)});
-
2738 env(rate(gw, 1.25));
-
2739 env.close();
-
2740
-
2741 AMM amm1(env, alice, GBP(1'000), EUR(1'000));
-
2742 AMM amm2(env, bob, EUR(1'000), USD(1'400));
-
2743
-
2744 // requested quality limit is 90USD/120GBP = 0.75
-
2745 // trade quality is 81.1111USD/108.1481GBP = 0.75
-
2746 env(pay(gw, carol, USD(90)),
-
2747 path(~EUR, ~USD),
-
2748 sendmax(GBP(120)),
- -
2750 env.close();
-
2751
-
2752 if (!features[fixAMMv1_1])
-
2753 {
-
2754 // 108.1481GBP is swapped in for 97.5935EUR
-
2755 BEAST_EXPECT(amm1.expectBalances(
-
2756 STAmount{GBP, UINT64_C(1'108'148148148149), -12},
-
2757 STAmount{EUR, UINT64_C(902'4064171122988), -13},
-
2758 amm1.tokens()));
-
2759 // 25% on 78.0748EUR is paid in tr fee 78.0748*1.25 = 97.5935EUR
-
2760 // 78.0748EUR is swapped in for 101.3888USD
-
2761 BEAST_EXPECT(amm2.expectBalances(
-
2762 STAmount{EUR, UINT64_C(1'078'074866310161), -12},
-
2763 STAmount{USD, UINT64_C(1'298'611111111111), -12},
-
2764 amm2.tokens()));
-
2765 }
-
2766 else
-
2767 {
-
2768 // 108.1481GBP is swapped in for 97.5935EUR
-
2769 BEAST_EXPECT(amm1.expectBalances(
-
2770 STAmount{GBP, UINT64_C(1'108'148148148151), -12},
-
2771 STAmount{EUR, UINT64_C(902'4064171122975), -13},
-
2772 amm1.tokens()));
-
2773 // 25% on 78.0748EUR is paid in tr fee 78.0748*1.25 = 97.5935EUR
-
2774 // 78.0748EUR is swapped in for 101.3888USD
-
2775 BEAST_EXPECT(amm2.expectBalances(
-
2776 STAmount{EUR, UINT64_C(1'078'074866310162), -12},
-
2777 STAmount{USD, UINT64_C(1'298'611111111111), -12},
-
2778 amm2.tokens()));
-
2779 }
-
2780 // 25% on 81.1111USD is paid in tr fee 81.1111*1.25 = 101.3888USD
-
2781 BEAST_EXPECT(expectHolding(
-
2782 env, carol, STAmount{USD, UINT64_C(1'481'111111111111), -12}));
-
2783 }
-
2784 }
+
2501 if (!features[fixAMMv1_1])
+
2502 {
+
2503 // alice buys 70.4210EUR with 70.4210GBP via the offer
+
2504 // and pays 25% tr fee on 70.4210GBP
+
2505 // 1,400 - 70.4210*1.25 = 1400 - 88.0262 = 1311.9736GBP
+
2506 BEAST_EXPECT(expectHolding(
+
2507 env,
+
2508 alice,
+
2509 STAmount{GBP, UINT64_C(1'311'973684210527), -12}));
+
2510 // ed doesn't pay tr fee, the balances reflect consumed offer
+
2511 // 70.4210GBP/70.4210EUR
+
2512 BEAST_EXPECT(expectHolding(
+
2513 env,
+
2514 ed,
+
2515 STAmount{EUR, UINT64_C(1'329'578947368421), -12},
+
2516 STAmount{GBP, UINT64_C(1'470'421052631579), -12}));
+
2517 BEAST_EXPECT(expectOffers(
+
2518 env,
+
2519 ed,
+
2520 1,
+
2521 {Amounts{
+
2522 STAmount{GBP, UINT64_C(929'5789473684212), -13},
+
2523 STAmount{EUR, UINT64_C(929'5789473684212), -13}}}));
+
2524 // 25% on 56.3368EUR is paid in tr fee 56.3368*1.25 = 70.4210EUR
+
2525 // 56.3368EUR is swapped in for 74.6651USD
+
2526 BEAST_EXPECT(amm.expectBalances(
+
2527 STAmount{EUR, UINT64_C(1'056'336842105263), -12},
+
2528 STAmount{USD, UINT64_C(1'325'334821428571), -12},
+
2529 amm.tokens()));
+
2530 }
+
2531 else
+
2532 {
+
2533 // alice buys 70.4210EUR with 70.4210GBP via the offer
+
2534 // and pays 25% tr fee on 70.4210GBP
+
2535 // 1,400 - 70.4210*1.25 = 1400 - 88.0262 = 1311.9736GBP
+
2536 BEAST_EXPECT(expectHolding(
+
2537 env,
+
2538 alice,
+
2539 STAmount{GBP, UINT64_C(1'311'973684210525), -12}));
+
2540 // ed doesn't pay tr fee, the balances reflect consumed offer
+
2541 // 70.4210GBP/70.4210EUR
+
2542 BEAST_EXPECT(expectHolding(
+
2543 env,
+
2544 ed,
+
2545 STAmount{EUR, UINT64_C(1'329'57894736842), -11},
+
2546 STAmount{GBP, UINT64_C(1'470'42105263158), -11}));
+
2547 BEAST_EXPECT(expectOffers(
+
2548 env,
+
2549 ed,
+
2550 1,
+
2551 {Amounts{
+
2552 STAmount{GBP, UINT64_C(929'57894736842), -11},
+
2553 STAmount{EUR, UINT64_C(929'57894736842), -11}}}));
+
2554 // 25% on 56.3368EUR is paid in tr fee 56.3368*1.25 = 70.4210EUR
+
2555 // 56.3368EUR is swapped in for 74.6651USD
+
2556 BEAST_EXPECT(amm.expectBalances(
+
2557 STAmount{EUR, UINT64_C(1'056'336842105264), -12},
+
2558 STAmount{USD, UINT64_C(1'325'334821428571), -12},
+
2559 amm.tokens()));
+
2560 }
+
2561 // 25% on 59.7321USD is paid in tr fee 59.7321*1.25 = 74.6651USD
+
2562 BEAST_EXPECT(expectHolding(
+
2563 env, carol, STAmount(USD, UINT64_C(1'459'732142857143), -12)));
+
2564 }
+
2565 {
+
2566 // Payment via AMM and offer with limit quality, deliver less
+
2567 // than requested
+
2568 Env env(*this, features);
+
2569 Account const ed("ed");
+
2570
+
2571 fund(
+
2572 env,
+
2573 gw,
+
2574 {alice, bob, carol, ed},
+
2575 XRP(1'000),
+
2576 {USD(1'400), EUR(1'400), GBP(1'400)});
+
2577 env(rate(gw, 1.25));
+
2578 env.close();
+
2579
+
2580 AMM amm(env, bob, GBP(1'000), EUR(1'000));
+
2581
+
2582 env(offer(ed, EUR(1'000), USD(1'400)), txflags(tfPassive));
+
2583 env.close();
+
2584
+
2585 // requested quality limit is 95USD/140GBP = 0.6785
+
2586 // trade quality is 47.7857USD/70.4210GBP = 0.6785
+
2587 env(pay(alice, carol, USD(95)),
+
2588 path(~EUR, ~USD),
+
2589 sendmax(GBP(140)),
+ +
2591 env.close();
+
2592
+
2593 if (!features[fixAMMv1_1])
+
2594 {
+
2595 // alice buys 53.3322EUR with 56.3368GBP via the amm
+
2596 // and pays 25% tr fee on 56.3368GBP
+
2597 // 1,400 - 56.3368*1.25 = 1400 - 70.4210 = 1329.5789GBP
+
2598 BEAST_EXPECT(expectHolding(
+
2599 env,
+
2600 alice,
+
2601 STAmount{GBP, UINT64_C(1'329'578947368421), -12}));
+
2604 // 56.3368GBP is swapped in for 53.3322EUR
+
2605 BEAST_EXPECT(amm.expectBalances(
+
2606 STAmount{GBP, UINT64_C(1'056'336842105263), -12},
+
2607 STAmount{EUR, UINT64_C(946'6677295918366), -13},
+
2608 amm.tokens()));
+
2609 }
+
2610 else
+
2611 {
+
2612 // alice buys 53.3322EUR with 56.3368GBP via the amm
+
2613 // and pays 25% tr fee on 56.3368GBP
+
2614 // 1,400 - 56.3368*1.25 = 1400 - 70.4210 = 1329.5789GBP
+
2615 BEAST_EXPECT(expectHolding(
+
2616 env,
+
2617 alice,
+
2618 STAmount{GBP, UINT64_C(1'329'57894736842), -11}));
+
2621 // 56.3368GBP is swapped in for 53.3322EUR
+
2622 BEAST_EXPECT(amm.expectBalances(
+
2623 STAmount{GBP, UINT64_C(1'056'336842105264), -12},
+
2624 STAmount{EUR, UINT64_C(946'6677295918366), -13},
+
2625 amm.tokens()));
+
2626 }
+
2627 // 25% on 42.6658EUR is paid in tr fee 42.6658*1.25 = 53.3322EUR
+
2628 // 42.6658EUR/59.7321USD
+
2629 BEAST_EXPECT(expectHolding(
+
2630 env,
+
2631 ed,
+
2632 STAmount{USD, UINT64_C(1'340'267857142857), -12},
+
2633 STAmount{EUR, UINT64_C(1'442'665816326531), -12}));
+
2634 BEAST_EXPECT(expectOffers(
+
2635 env,
+
2636 ed,
+
2637 1,
+
2638 {Amounts{
+
2639 STAmount{EUR, UINT64_C(957'3341836734693), -13},
+
2640 STAmount{USD, UINT64_C(1'340'267857142857), -12}}}));
+
2641 // 25% on 47.7857USD is paid in tr fee 47.7857*1.25 = 59.7321USD
+
2642 BEAST_EXPECT(expectHolding(
+
2643 env, carol, STAmount(USD, UINT64_C(1'447'785714285714), -12)));
+
2644 }
+
2645 {
+
2646 // Payment via AMM, AMM with limit quality, deliver less
+
2647 // than requested
+
2648 Env env(*this, features);
+
2649 Account const ed("ed");
+
2650
+
2651 fund(
+
2652 env,
+
2653 gw,
+
2654 {alice, bob, carol, ed},
+
2655 XRP(1'000),
+
2656 {USD(1'400), EUR(1'400), GBP(1'400)});
+
2657 env(rate(gw, 1.25));
+
2658 env.close();
+
2659
+
2660 AMM amm1(env, bob, GBP(1'000), EUR(1'000));
+
2661 AMM amm2(env, ed, EUR(1'000), USD(1'400));
+
2662
+
2663 // requested quality limit is 90USD/145GBP = 0.6206
+
2664 // trade quality is 66.7432USD/107.5308GBP = 0.6206
+
2665 env(pay(alice, carol, USD(90)),
+
2666 path(~EUR, ~USD),
+
2667 sendmax(GBP(145)),
+ +
2669 env.close();
+
2670
+
2671 if (!features[fixAMMv1_1])
+
2672 {
+
2673 // alice buys 53.3322EUR with 107.5308GBP
+
2674 // 25% on 86.0246GBP is paid in tr fee
+
2675 // 1,400 - 86.0246*1.25 = 1400 - 107.5308 = 1229.4691GBP
+
2676 BEAST_EXPECT(expectHolding(
+
2677 env,
+
2678 alice,
+
2679 STAmount{GBP, UINT64_C(1'292'469135802469), -12}));
+
2680 // 86.0246GBP is swapped in for 79.2106EUR
+
2681 BEAST_EXPECT(amm1.expectBalances(
+
2682 STAmount{GBP, UINT64_C(1'086'024691358025), -12},
+
2683 STAmount{EUR, UINT64_C(920'78937795562), -11},
+
2684 amm1.tokens()));
+
2685 // 25% on 63.3684EUR is paid in tr fee 63.3684*1.25 = 79.2106EUR
+
2686 // 63.3684EUR is swapped in for 83.4291USD
+
2687 BEAST_EXPECT(amm2.expectBalances(
+
2688 STAmount{EUR, UINT64_C(1'063'368497635504), -12},
+
2689 STAmount{USD, UINT64_C(1'316'570881226053), -12},
+
2690 amm2.tokens()));
+
2691 }
+
2692 else
+
2693 {
+
2694 // alice buys 53.3322EUR with 107.5308GBP
+
2695 // 25% on 86.0246GBP is paid in tr fee
+
2696 // 1,400 - 86.0246*1.25 = 1400 - 107.5308 = 1229.4691GBP
+
2697 BEAST_EXPECT(expectHolding(
+
2698 env,
+
2699 alice,
+
2700 STAmount{GBP, UINT64_C(1'292'469135802466), -12}));
+
2701 // 86.0246GBP is swapped in for 79.2106EUR
+
2702 BEAST_EXPECT(amm1.expectBalances(
+
2703 STAmount{GBP, UINT64_C(1'086'024691358027), -12},
+
2704 STAmount{EUR, UINT64_C(920'7893779556188), -13},
+
2705 amm1.tokens()));
+
2706 // 25% on 63.3684EUR is paid in tr fee 63.3684*1.25 = 79.2106EUR
+
2707 // 63.3684EUR is swapped in for 83.4291USD
+
2708 BEAST_EXPECT(amm2.expectBalances(
+
2709 STAmount{EUR, UINT64_C(1'063'368497635505), -12},
+
2710 STAmount{USD, UINT64_C(1'316'570881226053), -12},
+
2711 amm2.tokens()));
+
2712 }
+
2713 // 25% on 66.7432USD is paid in tr fee 66.7432*1.25 = 83.4291USD
+
2714 BEAST_EXPECT(expectHolding(
+
2715 env, carol, STAmount(USD, UINT64_C(1'466'743295019157), -12)));
+
2716 }
+
2717 {
+
2718 // Payment by the issuer via AMM, AMM with limit quality,
+
2719 // deliver less than requested
+
2720 Env env(*this, features);
+
2721
+
2722 fund(
+
2723 env,
+
2724 gw,
+
2725 {alice, bob, carol},
+
2726 XRP(1'000),
+
2727 {USD(1'400), EUR(1'400), GBP(1'400)});
+
2728 env(rate(gw, 1.25));
+
2729 env.close();
+
2730
+
2731 AMM amm1(env, alice, GBP(1'000), EUR(1'000));
+
2732 AMM amm2(env, bob, EUR(1'000), USD(1'400));
+
2733
+
2734 // requested quality limit is 90USD/120GBP = 0.75
+
2735 // trade quality is 81.1111USD/108.1481GBP = 0.75
+
2736 env(pay(gw, carol, USD(90)),
+
2737 path(~EUR, ~USD),
+
2738 sendmax(GBP(120)),
+ +
2740 env.close();
+
2741
+
2742 if (!features[fixAMMv1_1])
+
2743 {
+
2744 // 108.1481GBP is swapped in for 97.5935EUR
+
2745 BEAST_EXPECT(amm1.expectBalances(
+
2746 STAmount{GBP, UINT64_C(1'108'148148148149), -12},
+
2747 STAmount{EUR, UINT64_C(902'4064171122988), -13},
+
2748 amm1.tokens()));
+
2749 // 25% on 78.0748EUR is paid in tr fee 78.0748*1.25 = 97.5935EUR
+
2750 // 78.0748EUR is swapped in for 101.3888USD
+
2751 BEAST_EXPECT(amm2.expectBalances(
+
2752 STAmount{EUR, UINT64_C(1'078'074866310161), -12},
+
2753 STAmount{USD, UINT64_C(1'298'611111111111), -12},
+
2754 amm2.tokens()));
+
2755 }
+
2756 else
+
2757 {
+
2758 // 108.1481GBP is swapped in for 97.5935EUR
+
2759 BEAST_EXPECT(amm1.expectBalances(
+
2760 STAmount{GBP, UINT64_C(1'108'148148148151), -12},
+
2761 STAmount{EUR, UINT64_C(902'4064171122975), -13},
+
2762 amm1.tokens()));
+
2763 // 25% on 78.0748EUR is paid in tr fee 78.0748*1.25 = 97.5935EUR
+
2764 // 78.0748EUR is swapped in for 101.3888USD
+
2765 BEAST_EXPECT(amm2.expectBalances(
+
2766 STAmount{EUR, UINT64_C(1'078'074866310162), -12},
+
2767 STAmount{USD, UINT64_C(1'298'611111111111), -12},
+
2768 amm2.tokens()));
+
2769 }
+
2770 // 25% on 81.1111USD is paid in tr fee 81.1111*1.25 = 101.3888USD
+
2771 BEAST_EXPECT(expectHolding(
+
2772 env, carol, STAmount{USD, UINT64_C(1'481'111111111111), -12}));
+
2773 }
+
2774 }
+
2775
+
2776 void
+
+ +
2778 {
+
2779 // Single path with amm, offer, and limit quality. The quality limit
+
2780 // is such that the first offer should be taken but the second
+
2781 // should not. The total amount delivered should be the sum of the
+
2782 // two offers and sendMax should be more than the first offer.
+
2783 testcase("limitQuality");
+
2784 using namespace jtx;
2785
-
2786 void
-
- -
2788 {
-
2789 // Single path with amm, offer, and limit quality. The quality limit
-
2790 // is such that the first offer should be taken but the second
-
2791 // should not. The total amount delivered should be the sum of the
-
2792 // two offers and sendMax should be more than the first offer.
-
2793 testcase("limitQuality");
-
2794 using namespace jtx;
-
2795
-
2796 {
-
2797 Env env(*this);
+
2786 {
+
2787 Env env(*this);
+
2788
+
2789 fund(env, gw, {alice, bob, carol}, XRP(10'000), {USD(2'000)});
+
2790
+
2791 AMM ammBob(env, bob, XRP(1'000), USD(1'050));
+
2792 env(offer(bob, XRP(100), USD(50)));
+
2793
+
2794 env(pay(alice, carol, USD(100)),
+
2795 path(~USD),
+
2796 sendmax(XRP(100)),
+
2798
-
2799 fund(env, gw, {alice, bob, carol}, XRP(10'000), {USD(2'000)});
-
2800
-
2801 AMM ammBob(env, bob, XRP(1'000), USD(1'050));
-
2802 env(offer(bob, XRP(100), USD(50)));
-
2803
-
2804 env(pay(alice, carol, USD(100)),
-
2805 path(~USD),
-
2806 sendmax(XRP(100)),
- -
2808
-
2809 BEAST_EXPECT(
-
2810 ammBob.expectBalances(XRP(1'050), USD(1'000), ammBob.tokens()));
-
2811 BEAST_EXPECT(expectHolding(env, carol, USD(2'050)));
-
2812 BEAST_EXPECT(expectOffers(env, bob, 1, {{{XRP(100), USD(50)}}}));
-
2813 }
-
2814 }
+
2799 BEAST_EXPECT(
+
2800 ammBob.expectBalances(XRP(1'050), USD(1'000), ammBob.tokens()));
+
2801 BEAST_EXPECT(expectHolding(env, carol, USD(2'050)));
+
2802 BEAST_EXPECT(expectOffers(env, bob, 1, {{{XRP(100), USD(50)}}}));
+
2803 }
+
2804 }
-
2815
-
2816 void
-
- -
2818 {
-
2819 testcase("Circular XRP");
-
2820
-
2821 using namespace jtx;
-
2822 {
-
2823 // Payment path starting with XRP
-
2824 Env env(*this, testable_amendments());
-
2825 // Note, if alice doesn't have default ripple, then pay
-
2826 // fails with tecPATH_DRY.
-
2827 fund(
-
2828 env,
-
2829 gw,
-
2830 {alice, bob},
-
2831 XRP(10'000),
-
2832 {USD(200), EUR(200)},
-
2833 Fund::All);
-
2834
-
2835 AMM ammAliceXRP_USD(env, alice, XRP(100), USD(101));
-
2836 AMM ammAliceXRP_EUR(env, alice, XRP(100), EUR(101));
-
2837 env.close();
-
2838
-
2839 TER const expectedTer = TER{temBAD_PATH_LOOP};
-
2840 env(pay(alice, bob, EUR(1)),
-
2841 path(~USD, ~XRP, ~EUR),
-
2842 sendmax(XRP(1)),
- -
2844 ter(expectedTer));
-
2845 }
-
2846 {
-
2847 // Payment path ending with XRP
-
2848 Env env(*this);
-
2849 // Note, if alice doesn't have default ripple, then pay fails
-
2850 // with tecPATH_DRY.
-
2851 fund(
-
2852 env,
-
2853 gw,
-
2854 {alice, bob},
-
2855 XRP(10'000),
-
2856 {USD(200), EUR(200)},
-
2857 Fund::All);
-
2858
-
2859 AMM ammAliceXRP_USD(env, alice, XRP(100), USD(100));
-
2860 AMM ammAliceXRP_EUR(env, alice, XRP(100), EUR(100));
-
2861 // EUR -> //XRP -> //USD ->XRP
-
2862 env(pay(alice, bob, XRP(1)),
-
2863 path(~XRP, ~USD, ~XRP),
-
2864 sendmax(EUR(1)),
- - -
2867 }
-
2868 {
-
2869 // Payment where loop is formed in the middle of the path, not
-
2870 // on an endpoint
-
2871 auto const JPY = gw["JPY"];
-
2872 Env env(*this);
-
2873 // Note, if alice doesn't have default ripple, then pay fails
-
2874 // with tecPATH_DRY.
-
2875 fund(
-
2876 env,
-
2877 gw,
-
2878 {alice, bob},
-
2879 XRP(10'000),
-
2880 {USD(200), EUR(200), JPY(200)},
-
2881 Fund::All);
-
2882
-
2883 AMM ammAliceXRP_USD(env, alice, XRP(100), USD(100));
-
2884 AMM ammAliceXRP_EUR(env, alice, XRP(100), EUR(100));
-
2885 AMM ammAliceXRP_JPY(env, alice, XRP(100), JPY(100));
-
2886
-
2887 env(pay(alice, bob, JPY(1)),
-
2888 path(~XRP, ~EUR, ~XRP, ~JPY),
-
2889 sendmax(USD(1)),
- - -
2892 }
-
2893 }
+
2805
+
2806 void
+
+ +
2808 {
+
2809 testcase("Circular XRP");
+
2810
+
2811 using namespace jtx;
+
2812 {
+
2813 // Payment path starting with XRP
+
2814 Env env(*this, testable_amendments());
+
2815 // Note, if alice doesn't have default ripple, then pay
+
2816 // fails with tecPATH_DRY.
+
2817 fund(
+
2818 env,
+
2819 gw,
+
2820 {alice, bob},
+
2821 XRP(10'000),
+
2822 {USD(200), EUR(200)},
+
2823 Fund::All);
+
2824
+
2825 AMM ammAliceXRP_USD(env, alice, XRP(100), USD(101));
+
2826 AMM ammAliceXRP_EUR(env, alice, XRP(100), EUR(101));
+
2827 env.close();
+
2828
+
2829 TER const expectedTer = TER{temBAD_PATH_LOOP};
+
2830 env(pay(alice, bob, EUR(1)),
+
2831 path(~USD, ~XRP, ~EUR),
+
2832 sendmax(XRP(1)),
+ +
2834 ter(expectedTer));
+
2835 }
+
2836 {
+
2837 // Payment path ending with XRP
+
2838 Env env(*this);
+
2839 // Note, if alice doesn't have default ripple, then pay fails
+
2840 // with tecPATH_DRY.
+
2841 fund(
+
2842 env,
+
2843 gw,
+
2844 {alice, bob},
+
2845 XRP(10'000),
+
2846 {USD(200), EUR(200)},
+
2847 Fund::All);
+
2848
+
2849 AMM ammAliceXRP_USD(env, alice, XRP(100), USD(100));
+
2850 AMM ammAliceXRP_EUR(env, alice, XRP(100), EUR(100));
+
2851 // EUR -> //XRP -> //USD ->XRP
+
2852 env(pay(alice, bob, XRP(1)),
+
2853 path(~XRP, ~USD, ~XRP),
+
2854 sendmax(EUR(1)),
+ + +
2857 }
+
2858 {
+
2859 // Payment where loop is formed in the middle of the path, not
+
2860 // on an endpoint
+
2861 auto const JPY = gw["JPY"];
+
2862 Env env(*this);
+
2863 // Note, if alice doesn't have default ripple, then pay fails
+
2864 // with tecPATH_DRY.
+
2865 fund(
+
2866 env,
+
2867 gw,
+
2868 {alice, bob},
+
2869 XRP(10'000),
+
2870 {USD(200), EUR(200), JPY(200)},
+
2871 Fund::All);
+
2872
+
2873 AMM ammAliceXRP_USD(env, alice, XRP(100), USD(100));
+
2874 AMM ammAliceXRP_EUR(env, alice, XRP(100), EUR(100));
+
2875 AMM ammAliceXRP_JPY(env, alice, XRP(100), JPY(100));
+
2876
+
2877 env(pay(alice, bob, JPY(1)),
+
2878 path(~XRP, ~EUR, ~XRP, ~JPY),
+
2879 sendmax(USD(1)),
+ + +
2882 }
+
2883 }
+
2884
+
2885 void
+
+ +
2887 {
+
2888 testcase("Step Limit");
+
2889
+
2890 using namespace jtx;
+
2891 Env env(*this, features);
+
2892 auto const dan = Account("dan");
+
2893 auto const ed = Account("ed");
2894
-
2895 void
-
- -
2897 {
-
2898 testcase("Step Limit");
-
2899
-
2900 using namespace jtx;
-
2901 Env env(*this, features);
-
2902 auto const dan = Account("dan");
-
2903 auto const ed = Account("ed");
-
2904
-
2905 fund(env, gw, {ed}, XRP(100'000'000), {USD(11)});
-
2906 env.fund(XRP(100'000'000), alice, bob, carol, dan);
-
2907 env.close();
-
2908 env.trust(USD(1), bob);
-
2909 env(pay(gw, bob, USD(1)));
-
2910 env.trust(USD(1), dan);
-
2911 env(pay(gw, dan, USD(1)));
-
2912 n_offers(env, 2'000, bob, XRP(1), USD(1));
-
2913 n_offers(env, 1, dan, XRP(1), USD(1));
-
2914 AMM ammEd(env, ed, XRP(9), USD(11));
-
2915
-
2916 // Alice offers to buy 1000 XRP for 1000 USD. She takes Bob's first
-
2917 // offer, removes 999 more as unfunded, then hits the step limit.
-
2918 env(offer(alice, USD(1'000), XRP(1'000)));
-
2919 if (!features[fixAMMv1_1])
-
2920 env.require(balance(
-
2921 alice, STAmount{USD, UINT64_C(2'050126257867561), -15}));
-
2922 else
-
2923 env.require(balance(
-
2924 alice, STAmount{USD, UINT64_C(2'050125257867587), -15}));
-
2925 env.require(owners(alice, 2));
+
2895 fund(env, gw, {ed}, XRP(100'000'000), {USD(11)});
+
2896 env.fund(XRP(100'000'000), alice, bob, carol, dan);
+
2897 env.close();
+
2898 env.trust(USD(1), bob);
+
2899 env(pay(gw, bob, USD(1)));
+
2900 env.trust(USD(1), dan);
+
2901 env(pay(gw, dan, USD(1)));
+
2902 n_offers(env, 2'000, bob, XRP(1), USD(1));
+
2903 n_offers(env, 1, dan, XRP(1), USD(1));
+
2904 AMM ammEd(env, ed, XRP(9), USD(11));
+
2905
+
2906 // Alice offers to buy 1000 XRP for 1000 USD. She takes Bob's first
+
2907 // offer, removes 999 more as unfunded, then hits the step limit.
+
2908 env(offer(alice, USD(1'000), XRP(1'000)));
+
2909 if (!features[fixAMMv1_1])
+
2910 env.require(balance(
+
2911 alice, STAmount{USD, UINT64_C(2'050126257867561), -15}));
+
2912 else
+
2913 env.require(balance(
+
2914 alice, STAmount{USD, UINT64_C(2'050125257867587), -15}));
+
2915 env.require(owners(alice, 2));
+
2916 env.require(balance(bob, USD(0)));
+
2917 env.require(owners(bob, 1'001));
+
2918 env.require(balance(dan, USD(1)));
+
2919 env.require(owners(dan, 2));
+
2920
+
2921 // Carol offers to buy 1000 XRP for 1000 USD. She removes Bob's next
+
2922 // 1000 offers as unfunded and hits the step limit.
+
2923 env(offer(carol, USD(1'000), XRP(1'000)));
+
2924 env.require(balance(carol, USD(none)));
+
2925 env.require(owners(carol, 1));
2926 env.require(balance(bob, USD(0)));
-
2927 env.require(owners(bob, 1'001));
+
2927 env.require(owners(bob, 1));
2928 env.require(balance(dan, USD(1)));
2929 env.require(owners(dan, 2));
-
2930
-
2931 // Carol offers to buy 1000 XRP for 1000 USD. She removes Bob's next
-
2932 // 1000 offers as unfunded and hits the step limit.
-
2933 env(offer(carol, USD(1'000), XRP(1'000)));
-
2934 env.require(balance(carol, USD(none)));
-
2935 env.require(owners(carol, 1));
-
2936 env.require(balance(bob, USD(0)));
-
2937 env.require(owners(bob, 1));
-
2938 env.require(balance(dan, USD(1)));
-
2939 env.require(owners(dan, 2));
-
2940 }
+
2930 }
-
2941
-
2942 void
-
- -
2944 {
-
2945 testcase("Convert all of an asset using DeliverMin");
-
2946
-
2947 using namespace jtx;
-
2948
-
2949 {
-
2950 Env env(*this, features);
-
2951 fund(env, gw, {alice, bob, carol}, XRP(10'000));
-
2952 env.trust(USD(100), alice, bob, carol);
-
2953 env(pay(alice, bob, USD(10)),
-
2954 delivermin(USD(10)),
- -
2956 env(pay(alice, bob, USD(10)),
-
2957 delivermin(USD(-5)),
- - -
2960 env(pay(alice, bob, USD(10)),
-
2961 delivermin(XRP(5)),
- - +
2931
+
2932 void
+
+ +
2934 {
+
2935 testcase("Convert all of an asset using DeliverMin");
+
2936
+
2937 using namespace jtx;
+
2938
+
2939 {
+
2940 Env env(*this, features);
+
2941 fund(env, gw, {alice, bob, carol}, XRP(10'000));
+
2942 env.trust(USD(100), alice, bob, carol);
+
2943 env(pay(alice, bob, USD(10)),
+
2944 delivermin(USD(10)),
+ +
2946 env(pay(alice, bob, USD(10)),
+
2947 delivermin(USD(-5)),
+ + +
2950 env(pay(alice, bob, USD(10)),
+
2951 delivermin(XRP(5)),
+ + +
2954 env(pay(alice, bob, USD(10)),
+
2955 delivermin(Account(carol)["USD"](5)),
+ + +
2958 env(pay(alice, bob, USD(10)),
+
2959 delivermin(USD(15)),
+ + +
2962 env(pay(gw, carol, USD(50)));
+
2963 AMM ammCarol(env, carol, XRP(10), USD(15));
2964 env(pay(alice, bob, USD(10)),
-
2965 delivermin(Account(carol)["USD"](5)),
- - -
2968 env(pay(alice, bob, USD(10)),
-
2969 delivermin(USD(15)),
- - -
2972 env(pay(gw, carol, USD(50)));
-
2973 AMM ammCarol(env, carol, XRP(10), USD(15));
-
2974 env(pay(alice, bob, USD(10)),
-
2975 paths(XRP),
-
2976 delivermin(USD(7)),
- -
2978 sendmax(XRP(5)),
- -
2980 env.require(balance(
-
2981 alice,
-
2982 drops(10'000'000'000 - env.current()->fees().base.drops())));
-
2983 env.require(balance(bob, XRP(10'000)));
-
2984 }
-
2985
-
2986 {
-
2987 Env env(*this, features);
-
2988 fund(env, gw, {alice, bob}, XRP(10'000));
-
2989 env.trust(USD(1'100), alice, bob);
-
2990 env(pay(gw, bob, USD(1'100)));
-
2991 AMM ammBob(env, bob, XRP(1'000), USD(1'100));
-
2992 env(pay(alice, alice, USD(10'000)),
-
2993 paths(XRP),
-
2994 delivermin(USD(100)),
- -
2996 sendmax(XRP(100)));
-
2997 env.require(balance(alice, USD(100)));
-
2998 }
-
2999
-
3000 {
-
3001 Env env(*this, features);
-
3002 fund(env, gw, {alice, bob, carol}, XRP(10'000));
-
3003 env.trust(USD(1'200), bob, carol);
-
3004 env(pay(gw, bob, USD(1'200)));
-
3005 AMM ammBob(env, bob, XRP(5'500), USD(1'200));
-
3006 env(pay(alice, carol, USD(10'000)),
-
3007 paths(XRP),
-
3008 delivermin(USD(200)),
- -
3010 sendmax(XRP(1'000)),
- -
3012 env(pay(alice, carol, USD(10'000)),
-
3013 paths(XRP),
-
3014 delivermin(USD(200)),
- -
3016 sendmax(XRP(1'100)));
-
3017 BEAST_EXPECT(
-
3018 ammBob.expectBalances(XRP(6'600), USD(1'000), ammBob.tokens()));
-
3019 env.require(balance(carol, USD(200)));
-
3020 }
-
3021
-
3022 {
-
3023 auto const dan = Account("dan");
-
3024 Env env(*this, features);
-
3025 fund(env, gw, {alice, bob, carol, dan}, XRP(10'000));
-
3026 env.close();
-
3027 env.trust(USD(1'100), bob, carol, dan);
-
3028 env(pay(gw, bob, USD(100)));
-
3029 env(pay(gw, dan, USD(1'100)));
-
3030 env(offer(bob, XRP(100), USD(100)));
-
3031 env(offer(bob, XRP(1'000), USD(100)));
-
3032 AMM ammDan(env, dan, XRP(1'000), USD(1'100));
-
3033 if (!features[fixAMMv1_1])
-
3034 {
-
3035 env(pay(alice, carol, USD(10'000)),
-
3036 paths(XRP),
-
3037 delivermin(USD(200)),
- -
3039 sendmax(XRP(200)));
-
3040 env.require(balance(bob, USD(0)));
-
3041 env.require(balance(carol, USD(200)));
-
3042 BEAST_EXPECT(ammDan.expectBalances(
-
3043 XRP(1'100), USD(1'000), ammDan.tokens()));
-
3044 }
-
3045 else
-
3046 {
-
3047 env(pay(alice, carol, USD(10'000)),
-
3048 paths(XRP),
-
3049 delivermin(USD(200)),
- -
3051 sendmax(XRPAmount(200'000'001)));
-
3052 env.require(balance(bob, USD(0)));
-
3053 env.require(balance(
-
3054 carol, STAmount{USD, UINT64_C(200'00000090909), -11}));
-
3055 BEAST_EXPECT(ammDan.expectBalances(
-
3056 XRPAmount{1'100'000'001},
-
3057 STAmount{USD, UINT64_C(999'99999909091), -11},
-
3058 ammDan.tokens()));
-
3059 }
-
3060 }
-
3061 }
+
2965 paths(XRP),
+
2966 delivermin(USD(7)),
+ +
2968 sendmax(XRP(5)),
+ +
2970 env.require(balance(
+
2971 alice,
+
2972 drops(10'000'000'000 - env.current()->fees().base.drops())));
+
2973 env.require(balance(bob, XRP(10'000)));
+
2974 }
+
2975
+
2976 {
+
2977 Env env(*this, features);
+
2978 fund(env, gw, {alice, bob}, XRP(10'000));
+
2979 env.trust(USD(1'100), alice, bob);
+
2980 env(pay(gw, bob, USD(1'100)));
+
2981 AMM ammBob(env, bob, XRP(1'000), USD(1'100));
+
2982 env(pay(alice, alice, USD(10'000)),
+
2983 paths(XRP),
+
2984 delivermin(USD(100)),
+ +
2986 sendmax(XRP(100)));
+
2987 env.require(balance(alice, USD(100)));
+
2988 }
+
2989
+
2990 {
+
2991 Env env(*this, features);
+
2992 fund(env, gw, {alice, bob, carol}, XRP(10'000));
+
2993 env.trust(USD(1'200), bob, carol);
+
2994 env(pay(gw, bob, USD(1'200)));
+
2995 AMM ammBob(env, bob, XRP(5'500), USD(1'200));
+
2996 env(pay(alice, carol, USD(10'000)),
+
2997 paths(XRP),
+
2998 delivermin(USD(200)),
+ +
3000 sendmax(XRP(1'000)),
+ +
3002 env(pay(alice, carol, USD(10'000)),
+
3003 paths(XRP),
+
3004 delivermin(USD(200)),
+ +
3006 sendmax(XRP(1'100)));
+
3007 BEAST_EXPECT(
+
3008 ammBob.expectBalances(XRP(6'600), USD(1'000), ammBob.tokens()));
+
3009 env.require(balance(carol, USD(200)));
+
3010 }
+
3011
+
3012 {
+
3013 auto const dan = Account("dan");
+
3014 Env env(*this, features);
+
3015 fund(env, gw, {alice, bob, carol, dan}, XRP(10'000));
+
3016 env.close();
+
3017 env.trust(USD(1'100), bob, carol, dan);
+
3018 env(pay(gw, bob, USD(100)));
+
3019 env(pay(gw, dan, USD(1'100)));
+
3020 env(offer(bob, XRP(100), USD(100)));
+
3021 env(offer(bob, XRP(1'000), USD(100)));
+
3022 AMM ammDan(env, dan, XRP(1'000), USD(1'100));
+
3023 if (!features[fixAMMv1_1])
+
3024 {
+
3025 env(pay(alice, carol, USD(10'000)),
+
3026 paths(XRP),
+
3027 delivermin(USD(200)),
+ +
3029 sendmax(XRP(200)));
+
3030 env.require(balance(bob, USD(0)));
+
3031 env.require(balance(carol, USD(200)));
+
3032 BEAST_EXPECT(ammDan.expectBalances(
+
3033 XRP(1'100), USD(1'000), ammDan.tokens()));
+
3034 }
+
3035 else
+
3036 {
+
3037 env(pay(alice, carol, USD(10'000)),
+
3038 paths(XRP),
+
3039 delivermin(USD(200)),
+ +
3041 sendmax(XRPAmount(200'000'001)));
+
3042 env.require(balance(bob, USD(0)));
+
3043 env.require(balance(
+
3044 carol, STAmount{USD, UINT64_C(200'00000090909), -11}));
+
3045 BEAST_EXPECT(ammDan.expectBalances(
+
3046 XRPAmount{1'100'000'001},
+
3047 STAmount{USD, UINT64_C(999'99999909091), -11},
+
3048 ammDan.tokens()));
+
3049 }
+
3050 }
+
3051 }
+
3052
+
3053 void
+
+ +
3055 {
+
3056 testcase("Payment");
+
3057
+
3058 using namespace jtx;
+
3059 Account const becky{"becky"};
+
3060
+
3061 bool const supportsPreauth = {features[featureDepositPreauth]};
3062
-
3063 void
-
- -
3065 {
-
3066 testcase("Payment");
-
3067
-
3068 using namespace jtx;
-
3069 Account const becky{"becky"};
-
3070
-
3071 bool const supportsPreauth = {features[featureDepositPreauth]};
-
3072
-
3073 // The initial implementation of DepositAuth had a bug where an
-
3074 // account with the DepositAuth flag set could not make a payment
-
3075 // to itself. That bug was fixed in the DepositPreauth amendment.
-
3076 Env env(*this, features);
-
3077 fund(env, gw, {alice, becky}, XRP(5'000));
-
3078 env.close();
-
3079
-
3080 env.trust(USD(1'000), alice);
-
3081 env.trust(USD(1'000), becky);
+
3063 // The initial implementation of DepositAuth had a bug where an
+
3064 // account with the DepositAuth flag set could not make a payment
+
3065 // to itself. That bug was fixed in the DepositPreauth amendment.
+
3066 Env env(*this, features);
+
3067 fund(env, gw, {alice, becky}, XRP(5'000));
+
3068 env.close();
+
3069
+
3070 env.trust(USD(1'000), alice);
+
3071 env.trust(USD(1'000), becky);
+
3072 env.close();
+
3073
+
3074 env(pay(gw, alice, USD(500)));
+
3075 env.close();
+
3076
+
3077 AMM ammAlice(env, alice, XRP(100), USD(140));
+
3078
+
3079 // becky pays herself USD (10) by consuming part of alice's offer.
+
3080 // Make sure the payment works if PaymentAuth is not involved.
+
3081 env(pay(becky, becky, USD(10)), path(~USD), sendmax(XRP(10)));
3082 env.close();
-
3083
-
3084 env(pay(gw, alice, USD(500)));
-
3085 env.close();
-
3086
-
3087 AMM ammAlice(env, alice, XRP(100), USD(140));
-
3088
-
3089 // becky pays herself USD (10) by consuming part of alice's offer.
-
3090 // Make sure the payment works if PaymentAuth is not involved.
-
3091 env(pay(becky, becky, USD(10)), path(~USD), sendmax(XRP(10)));
-
3092 env.close();
-
3093 BEAST_EXPECT(ammAlice.expectBalances(
-
3094 XRPAmount(107'692'308), USD(130), ammAlice.tokens()));
-
3095
-
3096 // becky decides to require authorization for deposits.
-
3097 env(fset(becky, asfDepositAuth));
-
3098 env.close();
+
3083 BEAST_EXPECT(ammAlice.expectBalances(
+
3084 XRPAmount(107'692'308), USD(130), ammAlice.tokens()));
+
3085
+
3086 // becky decides to require authorization for deposits.
+
3087 env(fset(becky, asfDepositAuth));
+
3088 env.close();
+
3089
+
3090 // becky pays herself again. Whether it succeeds depends on
+
3091 // whether featureDepositPreauth is enabled.
+
3092 TER const expect{
+
3093 supportsPreauth ? TER{tesSUCCESS} : TER{tecNO_PERMISSION}};
+
3094
+
3095 env(pay(becky, becky, USD(10)),
+
3096 path(~USD),
+
3097 sendmax(XRP(10)),
+
3098 ter(expect));
3099
-
3100 // becky pays herself again. Whether it succeeds depends on
-
3101 // whether featureDepositPreauth is enabled.
-
3102 TER const expect{
-
3103 supportsPreauth ? TER{tesSUCCESS} : TER{tecNO_PERMISSION}};
-
3104
-
3105 env(pay(becky, becky, USD(10)),
-
3106 path(~USD),
-
3107 sendmax(XRP(10)),
-
3108 ter(expect));
-
3109
-
3110 env.close();
-
3111 }
+
3100 env.close();
+
3101 }
-
3112
-
3113 void
-
- -
3115 {
-
3116 // Exercise IOU payments and non-direct XRP payments to an account
-
3117 // that has the lsfDepositAuth flag set.
-
3118 testcase("Pay IOU");
-
3119
-
3120 using namespace jtx;
+
3102
+
3103 void
+
+ +
3105 {
+
3106 // Exercise IOU payments and non-direct XRP payments to an account
+
3107 // that has the lsfDepositAuth flag set.
+
3108 testcase("Pay IOU");
+
3109
+
3110 using namespace jtx;
+
3111
+
3112 Env env(*this);
+
3113
+
3114 fund(env, gw, {alice, bob, carol}, XRP(10'000));
+
3115 env.trust(USD(1'000), alice, bob, carol);
+
3116 env.close();
+
3117
+
3118 env(pay(gw, alice, USD(150)));
+
3119 env(pay(gw, carol, USD(150)));
+
3120 AMM ammCarol(env, carol, USD(100), XRPAmount(101));
3121
-
3122 Env env(*this);
-
3123
-
3124 fund(env, gw, {alice, bob, carol}, XRP(10'000));
-
3125 env.trust(USD(1'000), alice, bob, carol);
-
3126 env.close();
-
3127
-
3128 env(pay(gw, alice, USD(150)));
-
3129 env(pay(gw, carol, USD(150)));
-
3130 AMM ammCarol(env, carol, USD(100), XRPAmount(101));
-
3131
-
3132 // Make sure bob's trust line is all set up so he can receive USD.
-
3133 env(pay(alice, bob, USD(50)));
-
3134 env.close();
-
3135
-
3136 // bob sets the lsfDepositAuth flag.
- -
3138 env.close();
-
3139
-
3140 // None of the following payments should succeed.
-
3141 auto failedIouPayments = [this, &env]() {
- -
3143
-
3144 // Capture bob's balances before hand to confirm they don't
-
3145 // change.
-
3146 PrettyAmount const bobXrpBalance{env.balance(bob, XRP)};
-
3147 PrettyAmount const bobUsdBalance{env.balance(bob, USD)};
-
3148
-
3149 env(pay(alice, bob, USD(50)), ter(tecNO_PERMISSION));
-
3150 env.close();
-
3151
-
3152 // Note that even though alice is paying bob in XRP, the payment
-
3153 // is still not allowed since the payment passes through an
-
3154 // offer.
-
3155 env(pay(alice, bob, drops(1)),
-
3156 sendmax(USD(1)),
- -
3158 env.close();
-
3159
-
3160 BEAST_EXPECT(bobXrpBalance == env.balance(bob, XRP));
-
3161 BEAST_EXPECT(bobUsdBalance == env.balance(bob, USD));
-
3162 };
-
3163
-
3164 // Test when bob has an XRP balance > base reserve.
-
3165 failedIouPayments();
-
3166
-
3167 // Set bob's XRP balance == base reserve. Also demonstrate that
-
3168 // bob can make payments while his lsfDepositAuth flag is set.
-
3169 env(pay(bob, alice, USD(25)));
-
3170 env.close();
-
3171
-
3172 {
-
3173 STAmount const bobPaysXRP{env.balance(bob, XRP) - reserve(env, 1)};
-
3174 XRPAmount const bobPaysFee{reserve(env, 1) - reserve(env, 0)};
-
3175 env(pay(bob, alice, bobPaysXRP), fee(bobPaysFee));
-
3176 env.close();
-
3177 }
-
3178
-
3179 // Test when bob's XRP balance == base reserve.
-
3180 BEAST_EXPECT(env.balance(bob, XRP) == reserve(env, 0));
-
3181 BEAST_EXPECT(env.balance(bob, USD) == USD(25));
-
3182 failedIouPayments();
+
3122 // Make sure bob's trust line is all set up so he can receive USD.
+
3123 env(pay(alice, bob, USD(50)));
+
3124 env.close();
+
3125
+
3126 // bob sets the lsfDepositAuth flag.
+ +
3128 env.close();
+
3129
+
3130 // None of the following payments should succeed.
+
3131 auto failedIouPayments = [this, &env]() {
+ +
3133
+
3134 // Capture bob's balances before hand to confirm they don't
+
3135 // change.
+
3136 PrettyAmount const bobXrpBalance{env.balance(bob, XRP)};
+
3137 PrettyAmount const bobUsdBalance{env.balance(bob, USD)};
+
3138
+
3139 env(pay(alice, bob, USD(50)), ter(tecNO_PERMISSION));
+
3140 env.close();
+
3141
+
3142 // Note that even though alice is paying bob in XRP, the payment
+
3143 // is still not allowed since the payment passes through an
+
3144 // offer.
+
3145 env(pay(alice, bob, drops(1)),
+
3146 sendmax(USD(1)),
+ +
3148 env.close();
+
3149
+
3150 BEAST_EXPECT(bobXrpBalance == env.balance(bob, XRP));
+
3151 BEAST_EXPECT(bobUsdBalance == env.balance(bob, USD));
+
3152 };
+
3153
+
3154 // Test when bob has an XRP balance > base reserve.
+
3155 failedIouPayments();
+
3156
+
3157 // Set bob's XRP balance == base reserve. Also demonstrate that
+
3158 // bob can make payments while his lsfDepositAuth flag is set.
+
3159 env(pay(bob, alice, USD(25)));
+
3160 env.close();
+
3161
+
3162 {
+
3163 STAmount const bobPaysXRP{env.balance(bob, XRP) - reserve(env, 1)};
+
3164 XRPAmount const bobPaysFee{reserve(env, 1) - reserve(env, 0)};
+
3165 env(pay(bob, alice, bobPaysXRP), fee(bobPaysFee));
+
3166 env.close();
+
3167 }
+
3168
+
3169 // Test when bob's XRP balance == base reserve.
+
3170 BEAST_EXPECT(env.balance(bob, XRP) == reserve(env, 0));
+
3171 BEAST_EXPECT(env.balance(bob, USD) == USD(25));
+
3172 failedIouPayments();
+
3173
+
3174 // Test when bob has an XRP balance == 0.
+
3175 env(noop(bob), fee(reserve(env, 0)));
+
3176 env.close();
+
3177
+
3178 BEAST_EXPECT(env.balance(bob, XRP) == XRP(0));
+
3179 failedIouPayments();
+
3180
+
3181 // Give bob enough XRP for the fee to clear the lsfDepositAuth flag.
+
3182 env(pay(alice, bob, drops(env.current()->fees().base)));
3183
-
3184 // Test when bob has an XRP balance == 0.
-
3185 env(noop(bob), fee(reserve(env, 0)));
+
3184 // bob clears the lsfDepositAuth and the next payment succeeds.
+
3185 env(fclear(bob, asfDepositAuth));
3186 env.close();
3187
-
3188 BEAST_EXPECT(env.balance(bob, XRP) == XRP(0));
-
3189 failedIouPayments();
+
3188 env(pay(alice, bob, USD(50)));
+
3189 env.close();
3190
-
3191 // Give bob enough XRP for the fee to clear the lsfDepositAuth flag.
-
3192 env(pay(alice, bob, drops(env.current()->fees().base)));
-
3193
-
3194 // bob clears the lsfDepositAuth and the next payment succeeds.
-
3195 env(fclear(bob, asfDepositAuth));
-
3196 env.close();
-
3197
-
3198 env(pay(alice, bob, USD(50)));
-
3199 env.close();
-
3200
-
3201 env(pay(alice, bob, drops(1)), sendmax(USD(1)));
-
3202 env.close();
-
3203 BEAST_EXPECT(ammCarol.expectBalances(
-
3204 USD(101), XRPAmount(100), ammCarol.tokens()));
-
3205 }
+
3191 env(pay(alice, bob, drops(1)), sendmax(USD(1)));
+
3192 env.close();
+
3193 BEAST_EXPECT(ammCarol.expectBalances(
+
3194 USD(101), XRPAmount(100), ammCarol.tokens()));
+
3195 }
-
3206
-
3207 void
-
- -
3209 {
-
3210 testcase("RippleState Freeze");
+
3196
+
3197 void
+
+ +
3199 {
+
3200 testcase("RippleState Freeze");
+
3201
+
3202 using namespace test::jtx;
+
3203 Env env(*this, features);
+
3204
+
3205 Account const G1{"G1"};
+
3206 Account const alice{"alice"};
+
3207 Account const bob{"bob"};
+
3208
+
3209 env.fund(XRP(1'000), G1, alice, bob);
+
3210 env.close();
3211
-
3212 using namespace test::jtx;
-
3213 Env env(*this, features);
-
3214
-
3215 Account const G1{"G1"};
-
3216 Account const alice{"alice"};
-
3217 Account const bob{"bob"};
-
3218
-
3219 env.fund(XRP(1'000), G1, alice, bob);
-
3220 env.close();
+
3212 env.trust(G1["USD"](100), bob);
+
3213 env.trust(G1["USD"](205), alice);
+
3214 env.close();
+
3215
+
3216 env(pay(G1, bob, G1["USD"](10)));
+
3217 env(pay(G1, alice, G1["USD"](205)));
+
3218 env.close();
+
3219
+
3220 AMM ammAlice(env, alice, XRP(500), G1["USD"](105));
3221
-
3222 env.trust(G1["USD"](100), bob);
-
3223 env.trust(G1["USD"](205), alice);
-
3224 env.close();
-
3225
-
3226 env(pay(G1, bob, G1["USD"](10)));
-
3227 env(pay(G1, alice, G1["USD"](205)));
-
3228 env.close();
-
3229
-
3230 AMM ammAlice(env, alice, XRP(500), G1["USD"](105));
-
3231
-
3232 {
-
3233 auto lines = getAccountLines(env, bob);
-
3234 if (!BEAST_EXPECT(checkArraySize(lines[jss::lines], 1u)))
-
3235 return;
-
3236 BEAST_EXPECT(lines[jss::lines][0u][jss::account] == G1.human());
-
3237 BEAST_EXPECT(lines[jss::lines][0u][jss::limit] == "100");
-
3238 BEAST_EXPECT(lines[jss::lines][0u][jss::balance] == "10");
+
3222 {
+
3223 auto lines = getAccountLines(env, bob);
+
3224 if (!BEAST_EXPECT(checkArraySize(lines[jss::lines], 1u)))
+
3225 return;
+
3226 BEAST_EXPECT(lines[jss::lines][0u][jss::account] == G1.human());
+
3227 BEAST_EXPECT(lines[jss::lines][0u][jss::limit] == "100");
+
3228 BEAST_EXPECT(lines[jss::lines][0u][jss::balance] == "10");
+
3229 }
+
3230
+
3231 {
+
3232 auto lines = getAccountLines(env, alice, G1["USD"]);
+
3233 if (!BEAST_EXPECT(checkArraySize(lines[jss::lines], 1u)))
+
3234 return;
+
3235 BEAST_EXPECT(lines[jss::lines][0u][jss::account] == G1.human());
+
3236 BEAST_EXPECT(lines[jss::lines][0u][jss::limit] == "205");
+
3237 // 105 transferred to AMM
+
3238 BEAST_EXPECT(lines[jss::lines][0u][jss::balance] == "100");
3239 }
3240
-
3241 {
-
3242 auto lines = getAccountLines(env, alice, G1["USD"]);
-
3243 if (!BEAST_EXPECT(checkArraySize(lines[jss::lines], 1u)))
-
3244 return;
-
3245 BEAST_EXPECT(lines[jss::lines][0u][jss::account] == G1.human());
-
3246 BEAST_EXPECT(lines[jss::lines][0u][jss::limit] == "205");
-
3247 // 105 transferred to AMM
-
3248 BEAST_EXPECT(lines[jss::lines][0u][jss::balance] == "100");
-
3249 }
-
3250
-
3251 // Account with line unfrozen (proving operations normally work)
-
3252 // test: can make Payment on that line
-
3253 env(pay(alice, bob, G1["USD"](1)));
-
3254
-
3255 // test: can receive Payment on that line
-
3256 env(pay(bob, alice, G1["USD"](1)));
-
3257 env.close();
-
3258
-
3259 // Is created via a TrustSet with SetFreeze flag
-
3260 // test: sets LowFreeze | HighFreeze flags
-
3261 env(trust(G1, bob["USD"](0), tfSetFreeze));
-
3262 env.close();
-
3263
-
3264 {
-
3265 // Account with line frozen by issuer
-
3266 // test: can buy more assets on that line
-
3267 env(offer(bob, G1["USD"](5), XRP(25)));
-
3268 env.close();
-
3269 BEAST_EXPECT(ammAlice.expectBalances(
-
3270 XRP(525), G1["USD"](100), ammAlice.tokens()));
-
3271 }
-
3272
-
3273 {
-
3274 // test: can not sell assets from that line
-
3275 env(offer(bob, XRP(1), G1["USD"](5)), ter(tecUNFUNDED_OFFER));
-
3276
-
3277 // test: can receive Payment on that line
-
3278 env(pay(alice, bob, G1["USD"](1)));
-
3279
-
3280 // test: can not make Payment from that line
-
3281 env(pay(bob, alice, G1["USD"](1)), ter(tecPATH_DRY));
-
3282 }
-
3283
-
3284 {
-
3285 // check G1 account lines
-
3286 // test: shows freeze
-
3287 auto lines = getAccountLines(env, G1);
-
3288 Json::Value bobLine;
-
3289 for (auto const& it : lines[jss::lines])
-
3290 {
-
3291 if (it[jss::account] == bob.human())
-
3292 {
-
3293 bobLine = it;
-
3294 break;
-
3295 }
-
3296 }
-
3297 if (!BEAST_EXPECT(bobLine))
-
3298 return;
-
3299 BEAST_EXPECT(bobLine[jss::freeze] == true);
-
3300 BEAST_EXPECT(bobLine[jss::balance] == "-16");
-
3301 }
-
3302
-
3303 {
-
3304 // test: shows freeze peer
-
3305 auto lines = getAccountLines(env, bob);
-
3306 Json::Value g1Line;
-
3307 for (auto const& it : lines[jss::lines])
-
3308 {
-
3309 if (it[jss::account] == G1.human())
-
3310 {
-
3311 g1Line = it;
-
3312 break;
-
3313 }
-
3314 }
-
3315 if (!BEAST_EXPECT(g1Line))
-
3316 return;
-
3317 BEAST_EXPECT(g1Line[jss::freeze_peer] == true);
-
3318 BEAST_EXPECT(g1Line[jss::balance] == "16");
-
3319 }
-
3320
-
3321 {
-
3322 // Is cleared via a TrustSet with ClearFreeze flag
-
3323 // test: sets LowFreeze | HighFreeze flags
-
3324 env(trust(G1, bob["USD"](0), tfClearFreeze));
-
3325 auto affected = env.meta()->getJson(
-
3326 JsonOptions::none)[sfAffectedNodes.fieldName];
-
3327 if (!BEAST_EXPECT(checkArraySize(affected, 2u)))
-
3328 return;
-
3329 auto ff =
-
3330 affected[1u][sfModifiedNode.fieldName][sfFinalFields.fieldName];
-
3331 BEAST_EXPECT(
-
3332 ff[sfLowLimit.fieldName] ==
-
3333 G1["USD"](0).value().getJson(JsonOptions::none));
-
3334 BEAST_EXPECT(!(ff[jss::Flags].asUInt() & lsfLowFreeze));
-
3335 BEAST_EXPECT(!(ff[jss::Flags].asUInt() & lsfHighFreeze));
-
3336 env.close();
-
3337 }
-
3338 }
+
3241 // Account with line unfrozen (proving operations normally work)
+
3242 // test: can make Payment on that line
+
3243 env(pay(alice, bob, G1["USD"](1)));
+
3244
+
3245 // test: can receive Payment on that line
+
3246 env(pay(bob, alice, G1["USD"](1)));
+
3247 env.close();
+
3248
+
3249 // Is created via a TrustSet with SetFreeze flag
+
3250 // test: sets LowFreeze | HighFreeze flags
+
3251 env(trust(G1, bob["USD"](0), tfSetFreeze));
+
3252 env.close();
+
3253
+
3254 {
+
3255 // Account with line frozen by issuer
+
3256 // test: can buy more assets on that line
+
3257 env(offer(bob, G1["USD"](5), XRP(25)));
+
3258 env.close();
+
3259 BEAST_EXPECT(ammAlice.expectBalances(
+
3260 XRP(525), G1["USD"](100), ammAlice.tokens()));
+
3261 }
+
3262
+
3263 {
+
3264 // test: can not sell assets from that line
+
3265 env(offer(bob, XRP(1), G1["USD"](5)), ter(tecUNFUNDED_OFFER));
+
3266
+
3267 // test: can receive Payment on that line
+
3268 env(pay(alice, bob, G1["USD"](1)));
+
3269
+
3270 // test: can not make Payment from that line
+
3271 env(pay(bob, alice, G1["USD"](1)), ter(tecPATH_DRY));
+
3272 }
+
3273
+
3274 {
+
3275 // check G1 account lines
+
3276 // test: shows freeze
+
3277 auto lines = getAccountLines(env, G1);
+
3278 Json::Value bobLine;
+
3279 for (auto const& it : lines[jss::lines])
+
3280 {
+
3281 if (it[jss::account] == bob.human())
+
3282 {
+
3283 bobLine = it;
+
3284 break;
+
3285 }
+
3286 }
+
3287 if (!BEAST_EXPECT(bobLine))
+
3288 return;
+
3289 BEAST_EXPECT(bobLine[jss::freeze] == true);
+
3290 BEAST_EXPECT(bobLine[jss::balance] == "-16");
+
3291 }
+
3292
+
3293 {
+
3294 // test: shows freeze peer
+
3295 auto lines = getAccountLines(env, bob);
+
3296 Json::Value g1Line;
+
3297 for (auto const& it : lines[jss::lines])
+
3298 {
+
3299 if (it[jss::account] == G1.human())
+
3300 {
+
3301 g1Line = it;
+
3302 break;
+
3303 }
+
3304 }
+
3305 if (!BEAST_EXPECT(g1Line))
+
3306 return;
+
3307 BEAST_EXPECT(g1Line[jss::freeze_peer] == true);
+
3308 BEAST_EXPECT(g1Line[jss::balance] == "16");
+
3309 }
+
3310
+
3311 {
+
3312 // Is cleared via a TrustSet with ClearFreeze flag
+
3313 // test: sets LowFreeze | HighFreeze flags
+
3314 env(trust(G1, bob["USD"](0), tfClearFreeze));
+
3315 auto affected = env.meta()->getJson(
+
3316 JsonOptions::none)[sfAffectedNodes.fieldName];
+
3317 if (!BEAST_EXPECT(checkArraySize(affected, 2u)))
+
3318 return;
+
3319 auto ff =
+
3320 affected[1u][sfModifiedNode.fieldName][sfFinalFields.fieldName];
+
3321 BEAST_EXPECT(
+
3322 ff[sfLowLimit.fieldName] ==
+
3323 G1["USD"](0).value().getJson(JsonOptions::none));
+
3324 BEAST_EXPECT(!(ff[jss::Flags].asUInt() & lsfLowFreeze));
+
3325 BEAST_EXPECT(!(ff[jss::Flags].asUInt() & lsfHighFreeze));
+
3326 env.close();
+
3327 }
+
3328 }
-
3339
-
3340 void
-
- -
3342 {
-
3343 testcase("Global Freeze");
-
3344
-
3345 using namespace test::jtx;
-
3346 Env env(*this, features);
-
3347
-
3348 Account G1{"G1"};
-
3349 Account A1{"A1"};
-
3350 Account A2{"A2"};
-
3351 Account A3{"A3"};
-
3352 Account A4{"A4"};
-
3353
-
3354 env.fund(XRP(12'000), G1);
-
3355 env.fund(XRP(1'000), A1);
-
3356 env.fund(XRP(20'000), A2, A3, A4);
-
3357 env.close();
-
3358
-
3359 env.trust(G1["USD"](1'200), A1);
-
3360 env.trust(G1["USD"](200), A2);
-
3361 env.trust(G1["BTC"](100), A3);
-
3362 env.trust(G1["BTC"](100), A4);
-
3363 env.close();
-
3364
-
3365 env(pay(G1, A1, G1["USD"](1'000)));
-
3366 env(pay(G1, A2, G1["USD"](100)));
-
3367 env(pay(G1, A3, G1["BTC"](100)));
-
3368 env(pay(G1, A4, G1["BTC"](100)));
-
3369 env.close();
-
3370
-
3371 AMM ammG1(env, G1, XRP(10'000), G1["USD"](100));
-
3372 env(offer(A1, XRP(10'000), G1["USD"](100)), txflags(tfPassive));
-
3373 env(offer(A2, G1["USD"](100), XRP(10'000)), txflags(tfPassive));
-
3374 env.close();
-
3375
-
3376 {
-
3377 // Account without GlobalFreeze (proving operations normally
-
3378 // work)
-
3379 // test: visible offers where taker_pays is unfrozen issuer
-
3380 auto offers = env.rpc(
-
3381 "book_offers",
-
3382 std::string("USD/") + G1.human(),
-
3383 "XRP")[jss::result][jss::offers];
-
3384 if (!BEAST_EXPECT(checkArraySize(offers, 1u)))
-
3385 return;
-
3386 std::set<std::string> accounts;
-
3387 for (auto const& offer : offers)
-
3388 {
-
3389 accounts.insert(offer[jss::Account].asString());
-
3390 }
-
3391 BEAST_EXPECT(accounts.find(A2.human()) != std::end(accounts));
-
3392
-
3393 // test: visible offers where taker_gets is unfrozen issuer
-
3394 offers = env.rpc(
-
3395 "book_offers",
-
3396 "XRP",
-
3397 std::string("USD/") + G1.human())[jss::result][jss::offers];
-
3398 if (!BEAST_EXPECT(checkArraySize(offers, 1u)))
-
3399 return;
-
3400 accounts.clear();
-
3401 for (auto const& offer : offers)
-
3402 {
-
3403 accounts.insert(offer[jss::Account].asString());
-
3404 }
-
3405 BEAST_EXPECT(accounts.find(A1.human()) != std::end(accounts));
-
3406 }
-
3407
-
3408 {
-
3409 // Offers/Payments
-
3410 // test: assets can be bought on the market
-
3411 // env(offer(A3, G1["BTC"](1), XRP(1)));
-
3412 AMM ammA3(env, A3, G1["BTC"](1), XRP(1));
-
3413
-
3414 // test: assets can be sold on the market
-
3415 // AMM is bidirectional
-
3416
-
3417 // test: direct issues can be sent
-
3418 env(pay(G1, A2, G1["USD"](1)));
-
3419
-
3420 // test: direct redemptions can be sent
-
3421 env(pay(A2, G1, G1["USD"](1)));
-
3422
-
3423 // test: via rippling can be sent
-
3424 env(pay(A2, A1, G1["USD"](1)));
-
3425
-
3426 // test: via rippling can be sent back
-
3427 env(pay(A1, A2, G1["USD"](1)));
- -
3429 }
-
3430
-
3431 {
-
3432 // Account with GlobalFreeze
-
3433 // set GlobalFreeze first
-
3434 // test: SetFlag GlobalFreeze will toggle back to freeze
-
3435 env.require(nflags(G1, asfGlobalFreeze));
-
3436 env(fset(G1, asfGlobalFreeze));
-
3437 env.require(flags(G1, asfGlobalFreeze));
-
3438 env.require(nflags(G1, asfNoFreeze));
-
3439
-
3440 // test: assets can't be bought on the market
-
3441 AMM ammA3(env, A3, G1["BTC"](1), XRP(1), ter(tecFROZEN));
-
3442
-
3443 // test: assets can't be sold on the market
-
3444 // AMM is bidirectional
-
3445 }
+
3329
+
3330 void
+
+ +
3332 {
+
3333 testcase("Global Freeze");
+
3334
+
3335 using namespace test::jtx;
+
3336 Env env(*this, features);
+
3337
+
3338 Account G1{"G1"};
+
3339 Account A1{"A1"};
+
3340 Account A2{"A2"};
+
3341 Account A3{"A3"};
+
3342 Account A4{"A4"};
+
3343
+
3344 env.fund(XRP(12'000), G1);
+
3345 env.fund(XRP(1'000), A1);
+
3346 env.fund(XRP(20'000), A2, A3, A4);
+
3347 env.close();
+
3348
+
3349 env.trust(G1["USD"](1'200), A1);
+
3350 env.trust(G1["USD"](200), A2);
+
3351 env.trust(G1["BTC"](100), A3);
+
3352 env.trust(G1["BTC"](100), A4);
+
3353 env.close();
+
3354
+
3355 env(pay(G1, A1, G1["USD"](1'000)));
+
3356 env(pay(G1, A2, G1["USD"](100)));
+
3357 env(pay(G1, A3, G1["BTC"](100)));
+
3358 env(pay(G1, A4, G1["BTC"](100)));
+
3359 env.close();
+
3360
+
3361 AMM ammG1(env, G1, XRP(10'000), G1["USD"](100));
+
3362 env(offer(A1, XRP(10'000), G1["USD"](100)), txflags(tfPassive));
+
3363 env(offer(A2, G1["USD"](100), XRP(10'000)), txflags(tfPassive));
+
3364 env.close();
+
3365
+
3366 {
+
3367 // Account without GlobalFreeze (proving operations normally
+
3368 // work)
+
3369 // test: visible offers where taker_pays is unfrozen issuer
+
3370 auto offers = env.rpc(
+
3371 "book_offers",
+
3372 std::string("USD/") + G1.human(),
+
3373 "XRP")[jss::result][jss::offers];
+
3374 if (!BEAST_EXPECT(checkArraySize(offers, 1u)))
+
3375 return;
+
3376 std::set<std::string> accounts;
+
3377 for (auto const& offer : offers)
+
3378 {
+
3379 accounts.insert(offer[jss::Account].asString());
+
3380 }
+
3381 BEAST_EXPECT(accounts.find(A2.human()) != std::end(accounts));
+
3382
+
3383 // test: visible offers where taker_gets is unfrozen issuer
+
3384 offers = env.rpc(
+
3385 "book_offers",
+
3386 "XRP",
+
3387 std::string("USD/") + G1.human())[jss::result][jss::offers];
+
3388 if (!BEAST_EXPECT(checkArraySize(offers, 1u)))
+
3389 return;
+
3390 accounts.clear();
+
3391 for (auto const& offer : offers)
+
3392 {
+
3393 accounts.insert(offer[jss::Account].asString());
+
3394 }
+
3395 BEAST_EXPECT(accounts.find(A1.human()) != std::end(accounts));
+
3396 }
+
3397
+
3398 {
+
3399 // Offers/Payments
+
3400 // test: assets can be bought on the market
+
3401 // env(offer(A3, G1["BTC"](1), XRP(1)));
+
3402 AMM ammA3(env, A3, G1["BTC"](1), XRP(1));
+
3403
+
3404 // test: assets can be sold on the market
+
3405 // AMM is bidirectional
+
3406
+
3407 // test: direct issues can be sent
+
3408 env(pay(G1, A2, G1["USD"](1)));
+
3409
+
3410 // test: direct redemptions can be sent
+
3411 env(pay(A2, G1, G1["USD"](1)));
+
3412
+
3413 // test: via rippling can be sent
+
3414 env(pay(A2, A1, G1["USD"](1)));
+
3415
+
3416 // test: via rippling can be sent back
+
3417 env(pay(A1, A2, G1["USD"](1)));
+ +
3419 }
+
3420
+
3421 {
+
3422 // Account with GlobalFreeze
+
3423 // set GlobalFreeze first
+
3424 // test: SetFlag GlobalFreeze will toggle back to freeze
+
3425 env.require(nflags(G1, asfGlobalFreeze));
+
3426 env(fset(G1, asfGlobalFreeze));
+
3427 env.require(flags(G1, asfGlobalFreeze));
+
3428 env.require(nflags(G1, asfNoFreeze));
+
3429
+
3430 // test: assets can't be bought on the market
+
3431 AMM ammA3(env, A3, G1["BTC"](1), XRP(1), ter(tecFROZEN));
+
3432
+
3433 // test: assets can't be sold on the market
+
3434 // AMM is bidirectional
+
3435 }
+
3436
+
3437 {
+
3438 // test: book_offers shows offers
+
3439 // (should these actually be filtered?)
+
3440 auto offers = env.rpc(
+
3441 "book_offers",
+
3442 "XRP",
+
3443 std::string("USD/") + G1.human())[jss::result][jss::offers];
+
3444 if (!BEAST_EXPECT(checkArraySize(offers, 1u)))
+
3445 return;
3446
-
3447 {
-
3448 // test: book_offers shows offers
-
3449 // (should these actually be filtered?)
-
3450 auto offers = env.rpc(
-
3451 "book_offers",
-
3452 "XRP",
-
3453 std::string("USD/") + G1.human())[jss::result][jss::offers];
-
3454 if (!BEAST_EXPECT(checkArraySize(offers, 1u)))
-
3455 return;
-
3456
-
3457 offers = env.rpc(
-
3458 "book_offers",
-
3459 std::string("USD/") + G1.human(),
-
3460 "XRP")[jss::result][jss::offers];
-
3461 if (!BEAST_EXPECT(checkArraySize(offers, 1u)))
-
3462 return;
-
3463 }
-
3464
-
3465 {
-
3466 // Payments
-
3467 // test: direct issues can be sent
-
3468 env(pay(G1, A2, G1["USD"](1)));
-
3469
-
3470 // test: direct redemptions can be sent
-
3471 env(pay(A2, G1, G1["USD"](1)));
+
3447 offers = env.rpc(
+
3448 "book_offers",
+
3449 std::string("USD/") + G1.human(),
+
3450 "XRP")[jss::result][jss::offers];
+
3451 if (!BEAST_EXPECT(checkArraySize(offers, 1u)))
+
3452 return;
+
3453 }
+
3454
+
3455 {
+
3456 // Payments
+
3457 // test: direct issues can be sent
+
3458 env(pay(G1, A2, G1["USD"](1)));
+
3459
+
3460 // test: direct redemptions can be sent
+
3461 env(pay(A2, G1, G1["USD"](1)));
+
3462
+
3463 // test: via rippling cant be sent
+
3464 env(pay(A2, A1, G1["USD"](1)), ter(tecPATH_DRY));
+
3465 }
+
3466 }
+
+
3467
+
3468 void
+
+ +
3470 {
+
3471 testcase("Offers for Frozen Trust Lines");
3472
-
3473 // test: via rippling cant be sent
-
3474 env(pay(A2, A1, G1["USD"](1)), ter(tecPATH_DRY));
-
3475 }
-
3476 }
-
-
3477
-
3478 void
-
- -
3480 {
-
3481 testcase("Offers for Frozen Trust Lines");
-
3482
-
3483 using namespace test::jtx;
-
3484 Env env(*this, features);
-
3485
-
3486 Account G1{"G1"};
-
3487 Account A2{"A2"};
-
3488 Account A3{"A3"};
-
3489 Account A4{"A4"};
-
3490
-
3491 env.fund(XRP(2'000), G1, A3, A4);
-
3492 env.fund(XRP(2'000), A2);
-
3493 env.close();
-
3494
-
3495 env.trust(G1["USD"](1'000), A2);
-
3496 env.trust(G1["USD"](2'000), A3);
-
3497 env.trust(G1["USD"](2'001), A4);
-
3498 env.close();
-
3499
-
3500 env(pay(G1, A3, G1["USD"](2'000)));
-
3501 env(pay(G1, A4, G1["USD"](2'001)));
-
3502 env.close();
+
3473 using namespace test::jtx;
+
3474 Env env(*this, features);
+
3475
+
3476 Account G1{"G1"};
+
3477 Account A2{"A2"};
+
3478 Account A3{"A3"};
+
3479 Account A4{"A4"};
+
3480
+
3481 env.fund(XRP(2'000), G1, A3, A4);
+
3482 env.fund(XRP(2'000), A2);
+
3483 env.close();
+
3484
+
3485 env.trust(G1["USD"](1'000), A2);
+
3486 env.trust(G1["USD"](2'000), A3);
+
3487 env.trust(G1["USD"](2'001), A4);
+
3488 env.close();
+
3489
+
3490 env(pay(G1, A3, G1["USD"](2'000)));
+
3491 env(pay(G1, A4, G1["USD"](2'001)));
+
3492 env.close();
+
3493
+
3494 AMM ammA3(env, A3, XRP(1'000), G1["USD"](1'001));
+
3495
+
3496 // removal after successful payment
+
3497 // test: make a payment with partially consuming offer
+
3498 env(pay(A2, G1, G1["USD"](1)), paths(G1["USD"]), sendmax(XRP(1)));
+
3499 env.close();
+
3500
+
3501 BEAST_EXPECT(
+
3502 ammA3.expectBalances(XRP(1'001), G1["USD"](1'000), ammA3.tokens()));
3503
-
3504 AMM ammA3(env, A3, XRP(1'000), G1["USD"](1'001));
-
3505
-
3506 // removal after successful payment
-
3507 // test: make a payment with partially consuming offer
-
3508 env(pay(A2, G1, G1["USD"](1)), paths(G1["USD"]), sendmax(XRP(1)));
-
3509 env.close();
+
3504 // test: someone else creates an offer providing liquidity
+
3505 env(offer(A4, XRP(999), G1["USD"](999)));
+
3506 env.close();
+
3507 // The offer consumes AMM offer
+
3508 BEAST_EXPECT(
+
3509 ammA3.expectBalances(XRP(1'000), G1["USD"](1'001), ammA3.tokens()));
3510
-
3511 BEAST_EXPECT(
-
3512 ammA3.expectBalances(XRP(1'001), G1["USD"](1'000), ammA3.tokens()));
-
3513
-
3514 // test: someone else creates an offer providing liquidity
-
3515 env(offer(A4, XRP(999), G1["USD"](999)));
-
3516 env.close();
-
3517 // The offer consumes AMM offer
-
3518 BEAST_EXPECT(
-
3519 ammA3.expectBalances(XRP(1'000), G1["USD"](1'001), ammA3.tokens()));
-
3520
-
3521 // test: AMM line is frozen
-
3522 auto const a3am =
-
3523 STAmount{Issue{to_currency("USD"), ammA3.ammAccount()}, 0};
-
3524 env(trust(G1, a3am, tfSetFreeze));
-
3525 auto const info = ammA3.ammRpcInfo();
-
3526 BEAST_EXPECT(info[jss::amm][jss::asset2_frozen].asBool());
-
3527 env.close();
-
3528
-
3529 // test: Can make a payment via the new offer
-
3530 env(pay(A2, G1, G1["USD"](1)), paths(G1["USD"]), sendmax(XRP(1)));
-
3531 env.close();
-
3532 // AMM is not consumed
-
3533 BEAST_EXPECT(
-
3534 ammA3.expectBalances(XRP(1'000), G1["USD"](1'001), ammA3.tokens()));
-
3535
-
3536 // removal buy successful OfferCreate
-
3537 // test: freeze the new offer
-
3538 env(trust(G1, A4["USD"](0), tfSetFreeze));
-
3539 env.close();
+
3511 // test: AMM line is frozen
+
3512 auto const a3am =
+
3513 STAmount{Issue{to_currency("USD"), ammA3.ammAccount()}, 0};
+
3514 env(trust(G1, a3am, tfSetFreeze));
+
3515 auto const info = ammA3.ammRpcInfo();
+
3516 BEAST_EXPECT(info[jss::amm][jss::asset2_frozen].asBool());
+
3517 env.close();
+
3518
+
3519 // test: Can make a payment via the new offer
+
3520 env(pay(A2, G1, G1["USD"](1)), paths(G1["USD"]), sendmax(XRP(1)));
+
3521 env.close();
+
3522 // AMM is not consumed
+
3523 BEAST_EXPECT(
+
3524 ammA3.expectBalances(XRP(1'000), G1["USD"](1'001), ammA3.tokens()));
+
3525
+
3526 // removal buy successful OfferCreate
+
3527 // test: freeze the new offer
+
3528 env(trust(G1, A4["USD"](0), tfSetFreeze));
+
3529 env.close();
+
3530
+
3531 // test: can no longer create a crossing offer
+
3532 env(offer(A2, G1["USD"](999), XRP(999)));
+
3533 env.close();
+
3534
+
3535 // test: offer was removed by offer_create
+
3536 auto offers = getAccountOffers(env, A4)[jss::offers];
+
3537 if (!BEAST_EXPECT(checkArraySize(offers, 0u)))
+
3538 return;
+
3539 }
+
3540
-
3541 // test: can no longer create a crossing offer
-
3542 env(offer(A2, G1["USD"](999), XRP(999)));
-
3543 env.close();
-
3544
-
3545 // test: offer was removed by offer_create
-
3546 auto offers = getAccountOffers(env, A4)[jss::offers];
-
3547 if (!BEAST_EXPECT(checkArraySize(offers, 0u)))
-
3548 return;
-
3549 }
+
3541 void
+
+ +
3543 {
+
3544 testcase("Multisign AMM Transactions");
+
3545
+
3546 using namespace jtx;
+
3547 Env env{*this, features};
+
3548 Account const bogie{"bogie", KeyType::secp256k1};
+
3549 Account const alice{"alice", KeyType::secp256k1};
+
3550 Account const becky{"becky", KeyType::ed25519};
+
3551 Account const zelda{"zelda", KeyType::secp256k1};
+
3552 fund(env, gw, {alice, becky, zelda}, XRP(20'000), {USD(20'000)});
+
3553
+
3554 // alice uses a regular key with the master disabled.
+
3555 Account const alie{"alie", KeyType::secp256k1};
+
3556 env(regkey(alice, alie));
+ +
3558
+
3559 // Attach signers to alice.
+
3560 env(signers(alice, 2, {{becky, 1}, {bogie, 1}}), sig(alie));
+
3561 env.close();
+
3562 int const signerListOwners{features[featureMultiSignReserve] ? 2 : 5};
+
3563 env.require(owners(alice, signerListOwners + 0));
+
3564
+
3565 msig const ms{becky, bogie};
+
3566
+
3567 // Multisign all AMM transactions
+
3568 AMM ammAlice(
+
3569 env,
+
3570 alice,
+
3571 XRP(10'000),
+
3572 USD(10'000),
+
3573 false,
+
3574 0,
+
3575 ammCrtFee(env).drops(),
+ + +
3578 ms,
+
3579 ter(tesSUCCESS));
+
3580 BEAST_EXPECT(ammAlice.expectBalances(
+
3581 XRP(10'000), USD(10'000), ammAlice.tokens()));
+
3582
+
3583 ammAlice.deposit(alice, 1'000'000);
+
3584 BEAST_EXPECT(ammAlice.expectBalances(
+
3585 XRP(11'000), USD(11'000), IOUAmount{11'000'000, 0}));
+
3586
+
3587 ammAlice.withdraw(alice, 1'000'000);
+
3588 BEAST_EXPECT(ammAlice.expectBalances(
+
3589 XRP(10'000), USD(10'000), ammAlice.tokens()));
+
3590
+
3591 ammAlice.vote({}, 1'000);
+
3592 BEAST_EXPECT(ammAlice.expectTradingFee(1'000));
+
3593
+
3594 env(ammAlice.bid({.account = alice, .bidMin = 100}), ms).close();
+
3595 BEAST_EXPECT(ammAlice.expectAuctionSlot(100, 0, IOUAmount{4'000}));
+
3596 // 4000 tokens burnt
+
3597 BEAST_EXPECT(ammAlice.expectBalances(
+
3598 XRP(10'000), USD(10'000), IOUAmount{9'996'000, 0}));
+
3599 }
-
3550
-
3551 void
-
- -
3553 {
-
3554 testcase("Multisign AMM Transactions");
-
3555
-
3556 using namespace jtx;
-
3557 Env env{*this, features};
-
3558 Account const bogie{"bogie", KeyType::secp256k1};
-
3559 Account const alice{"alice", KeyType::secp256k1};
-
3560 Account const becky{"becky", KeyType::ed25519};
-
3561 Account const zelda{"zelda", KeyType::secp256k1};
-
3562 fund(env, gw, {alice, becky, zelda}, XRP(20'000), {USD(20'000)});
-
3563
-
3564 // alice uses a regular key with the master disabled.
-
3565 Account const alie{"alie", KeyType::secp256k1};
-
3566 env(regkey(alice, alie));
- -
3568
-
3569 // Attach signers to alice.
-
3570 env(signers(alice, 2, {{becky, 1}, {bogie, 1}}), sig(alie));
-
3571 env.close();
-
3572 int const signerListOwners{features[featureMultiSignReserve] ? 2 : 5};
-
3573 env.require(owners(alice, signerListOwners + 0));
-
3574
-
3575 msig const ms{becky, bogie};
-
3576
-
3577 // Multisign all AMM transactions
-
3578 AMM ammAlice(
-
3579 env,
-
3580 alice,
-
3581 XRP(10'000),
-
3582 USD(10'000),
-
3583 false,
-
3584 0,
-
3585 ammCrtFee(env).drops(),
- - -
3588 ms,
-
3589 ter(tesSUCCESS));
-
3590 BEAST_EXPECT(ammAlice.expectBalances(
-
3591 XRP(10'000), USD(10'000), ammAlice.tokens()));
-
3592
-
3593 ammAlice.deposit(alice, 1'000'000);
-
3594 BEAST_EXPECT(ammAlice.expectBalances(
-
3595 XRP(11'000), USD(11'000), IOUAmount{11'000'000, 0}));
-
3596
-
3597 ammAlice.withdraw(alice, 1'000'000);
-
3598 BEAST_EXPECT(ammAlice.expectBalances(
-
3599 XRP(10'000), USD(10'000), ammAlice.tokens()));
3600
-
3601 ammAlice.vote({}, 1'000);
-
3602 BEAST_EXPECT(ammAlice.expectTradingFee(1'000));
-
3603
-
3604 env(ammAlice.bid({.account = alice, .bidMin = 100}), ms).close();
-
3605 BEAST_EXPECT(ammAlice.expectAuctionSlot(100, 0, IOUAmount{4'000}));
-
3606 // 4000 tokens burnt
-
3607 BEAST_EXPECT(ammAlice.expectBalances(
-
3608 XRP(10'000), USD(10'000), IOUAmount{9'996'000, 0}));
-
3609 }
-
-
3610
-
3611 void
-
- -
3613 {
-
3614 testcase("To Strand");
-
3615
-
3616 using namespace jtx;
-
3617
-
3618 // cannot have more than one offer with the same output issue
-
3619
-
3620 Env env(*this, features);
+
3601 void
+
+ +
3603 {
+
3604 testcase("To Strand");
+
3605
+
3606 using namespace jtx;
+
3607
+
3608 // cannot have more than one offer with the same output issue
+
3609
+
3610 Env env(*this, features);
+
3611
+
3612 fund(
+
3613 env,
+
3614 gw,
+
3615 {alice, bob, carol},
+
3616 XRP(10'000),
+
3617 {USD(2'000), EUR(1'000)});
+
3618
+
3619 AMM bobXRP_USD(env, bob, XRP(1'000), USD(1'000));
+
3620 AMM bobUSD_EUR(env, bob, USD(1'000), EUR(1'000));
3621
-
3622 fund(
-
3623 env,
-
3624 gw,
-
3625 {alice, bob, carol},
-
3626 XRP(10'000),
-
3627 {USD(2'000), EUR(1'000)});
-
3628
-
3629 AMM bobXRP_USD(env, bob, XRP(1'000), USD(1'000));
-
3630 AMM bobUSD_EUR(env, bob, USD(1'000), EUR(1'000));
-
3631
-
3632 // payment path: XRP -> XRP/USD -> USD/EUR -> EUR/USD
-
3633 env(pay(alice, carol, USD(100)),
-
3634 path(~USD, ~EUR, ~USD),
-
3635 sendmax(XRP(200)),
- - -
3638 }
+
3622 // payment path: XRP -> XRP/USD -> USD/EUR -> EUR/USD
+
3623 env(pay(alice, carol, USD(100)),
+
3624 path(~USD, ~EUR, ~USD),
+
3625 sendmax(XRP(200)),
+ + +
3628 }
-
3639
-
3640 void
-
- -
3642 {
-
3643 using namespace jtx;
-
3644 testcase("RIPD1373");
-
3645
-
3646 {
-
3647 Env env(*this, features);
-
3648 auto const BobUSD = bob["USD"];
-
3649 auto const BobEUR = bob["EUR"];
-
3650 fund(env, gw, {alice, bob}, XRP(10'000));
-
3651 env.trust(USD(1'000), alice, bob);
-
3652 env.trust(EUR(1'000), alice, bob);
-
3653 env.close();
-
3654 fund(
-
3655 env,
-
3656 bob,
-
3657 {alice, gw},
-
3658 {BobUSD(100), BobEUR(100)},
-
3659 Fund::IOUOnly);
-
3660 env.close();
-
3661
-
3662 AMM ammBobXRP_USD(env, bob, XRP(100), BobUSD(100));
-
3663 env(offer(gw, XRP(100), USD(100)), txflags(tfPassive));
+
3629
+
3630 void
+
+ +
3632 {
+
3633 using namespace jtx;
+
3634 testcase("RIPD1373");
+
3635
+
3636 {
+
3637 Env env(*this, features);
+
3638 auto const BobUSD = bob["USD"];
+
3639 auto const BobEUR = bob["EUR"];
+
3640 fund(env, gw, {alice, bob}, XRP(10'000));
+
3641 env.trust(USD(1'000), alice, bob);
+
3642 env.trust(EUR(1'000), alice, bob);
+
3643 env.close();
+
3644 fund(
+
3645 env,
+
3646 bob,
+
3647 {alice, gw},
+
3648 {BobUSD(100), BobEUR(100)},
+
3649 Fund::IOUOnly);
+
3650 env.close();
+
3651
+
3652 AMM ammBobXRP_USD(env, bob, XRP(100), BobUSD(100));
+
3653 env(offer(gw, XRP(100), USD(100)), txflags(tfPassive));
+
3654
+
3655 AMM ammBobUSD_EUR(env, bob, BobUSD(100), BobEUR(100));
+
3656 env(offer(gw, USD(100), EUR(100)), txflags(tfPassive));
+
3657
+
3658 Path const p = [&] {
+
3659 Path result;
+
3660 result.push_back(allpe(gw, BobUSD));
+
3661 result.push_back(cpe(EUR.currency));
+
3662 return result;
+
3663 }();
3664
-
3665 AMM ammBobUSD_EUR(env, bob, BobUSD(100), BobEUR(100));
-
3666 env(offer(gw, USD(100), EUR(100)), txflags(tfPassive));
-
3667
-
3668 Path const p = [&] {
-
3669 Path result;
-
3670 result.push_back(allpe(gw, BobUSD));
-
3671 result.push_back(cpe(EUR.currency));
-
3672 return result;
-
3673 }();
-
3674
-
3675 PathSet paths(p);
+
3665 PathSet paths(p);
+
3666
+
3667 env(pay(alice, alice, EUR(1)),
+
3668 json(paths.json()),
+
3669 sendmax(XRP(10)),
+ +
3671 ter(temBAD_PATH));
+
3672 }
+
3673
+
3674 {
+
3675 Env env(*this, features);
3676
-
3677 env(pay(alice, alice, EUR(1)),
-
3678 json(paths.json()),
-
3679 sendmax(XRP(10)),
- -
3681 ter(temBAD_PATH));
-
3682 }
-
3683
-
3684 {
-
3685 Env env(*this, features);
-
3686
-
3687 fund(env, gw, {alice, bob, carol}, XRP(10'000), {USD(100)});
-
3688
-
3689 AMM ammBob(env, bob, XRP(100), USD(100));
+
3677 fund(env, gw, {alice, bob, carol}, XRP(10'000), {USD(100)});
+
3678
+
3679 AMM ammBob(env, bob, XRP(100), USD(100));
+
3680
+
3681 // payment path: XRP -> XRP/USD -> USD/XRP
+
3682 env(pay(alice, carol, XRP(100)),
+
3683 path(~USD, ~XRP),
+ + +
3686 }
+
3687
+
3688 {
+
3689 Env env(*this, features);
3690
-
3691 // payment path: XRP -> XRP/USD -> USD/XRP
-
3692 env(pay(alice, carol, XRP(100)),
-
3693 path(~USD, ~XRP),
- - -
3696 }
-
3697
-
3698 {
-
3699 Env env(*this, features);
-
3700
-
3701 fund(env, gw, {alice, bob, carol}, XRP(10'000), {USD(100)});
-
3702
-
3703 AMM ammBob(env, bob, XRP(100), USD(100));
-
3704
-
3705 // payment path: XRP -> XRP/USD -> USD/XRP
-
3706 env(pay(alice, carol, XRP(100)),
-
3707 path(~USD, ~XRP),
-
3708 sendmax(XRP(200)),
- - -
3711 }
-
3712 }
+
3691 fund(env, gw, {alice, bob, carol}, XRP(10'000), {USD(100)});
+
3692
+
3693 AMM ammBob(env, bob, XRP(100), USD(100));
+
3694
+
3695 // payment path: XRP -> XRP/USD -> USD/XRP
+
3696 env(pay(alice, carol, XRP(100)),
+
3697 path(~USD, ~XRP),
+
3698 sendmax(XRP(200)),
+ + +
3701 }
+
3702 }
-
3713
-
3714 void
-
- -
3716 {
-
3717 testcase("test loop");
-
3718 using namespace jtx;
-
3719
-
3720 auto const CNY = gw["CNY"];
-
3721
-
3722 {
-
3723 Env env(*this, features);
+
3703
+
3704 void
+
+ +
3706 {
+
3707 testcase("test loop");
+
3708 using namespace jtx;
+
3709
+
3710 auto const CNY = gw["CNY"];
+
3711
+
3712 {
+
3713 Env env(*this, features);
+
3714
+
3715 env.fund(XRP(10'000), alice, bob, carol, gw);
+
3716 env.close();
+
3717 env.trust(USD(10'000), alice, bob, carol);
+
3718 env.close();
+
3719 env(pay(gw, bob, USD(100)));
+
3720 env(pay(gw, alice, USD(100)));
+
3721 env.close();
+
3722
+
3723 AMM ammBob(env, bob, XRP(100), USD(100));
3724
-
3725 env.fund(XRP(10'000), alice, bob, carol, gw);
-
3726 env.close();
-
3727 env.trust(USD(10'000), alice, bob, carol);
-
3728 env.close();
-
3729 env(pay(gw, bob, USD(100)));
-
3730 env(pay(gw, alice, USD(100)));
-
3731 env.close();
+
3725 // payment path: USD -> USD/XRP -> XRP/USD
+
3726 env(pay(alice, carol, USD(100)),
+
3727 sendmax(USD(100)),
+
3728 path(~XRP, ~USD),
+ + +
3731 }
3732
-
3733 AMM ammBob(env, bob, XRP(100), USD(100));
-
3734
-
3735 // payment path: USD -> USD/XRP -> XRP/USD
-
3736 env(pay(alice, carol, USD(100)),
-
3737 sendmax(USD(100)),
-
3738 path(~XRP, ~USD),
- - -
3741 }
-
3742
-
3743 {
-
3744 Env env(*this, features);
+
3733 {
+
3734 Env env(*this, features);
+
3735
+
3736 env.fund(XRP(10'000), alice, bob, carol, gw);
+
3737 env.close();
+
3738 env.trust(USD(10'000), alice, bob, carol);
+
3739 env.trust(EUR(10'000), alice, bob, carol);
+
3740 env.trust(CNY(10'000), alice, bob, carol);
+
3741
+
3742 env(pay(gw, bob, USD(200)));
+
3743 env(pay(gw, bob, EUR(200)));
+
3744 env(pay(gw, bob, CNY(100)));
3745
-
3746 env.fund(XRP(10'000), alice, bob, carol, gw);
-
3747 env.close();
-
3748 env.trust(USD(10'000), alice, bob, carol);
-
3749 env.trust(EUR(10'000), alice, bob, carol);
-
3750 env.trust(CNY(10'000), alice, bob, carol);
-
3751
-
3752 env(pay(gw, bob, USD(200)));
-
3753 env(pay(gw, bob, EUR(200)));
-
3754 env(pay(gw, bob, CNY(100)));
-
3755
-
3756 AMM ammBobXRP_USD(env, bob, XRP(100), USD(100));
-
3757 AMM ammBobUSD_EUR(env, bob, USD(100), EUR(100));
-
3758 AMM ammBobEUR_CNY(env, bob, EUR(100), CNY(100));
-
3759
-
3760 // payment path: XRP->XRP/USD->USD/EUR->USD/CNY
-
3761 env(pay(alice, carol, CNY(100)),
-
3762 sendmax(XRP(100)),
-
3763 path(~USD, ~EUR, ~USD, ~CNY),
- - -
3766 }
-
3767 }
+
3746 AMM ammBobXRP_USD(env, bob, XRP(100), USD(100));
+
3747 AMM ammBobUSD_EUR(env, bob, USD(100), EUR(100));
+
3748 AMM ammBobEUR_CNY(env, bob, EUR(100), CNY(100));
+
3749
+
3750 // payment path: XRP->XRP/USD->USD/EUR->USD/CNY
+
3751 env(pay(alice, carol, CNY(100)),
+
3752 sendmax(XRP(100)),
+
3753 path(~USD, ~EUR, ~USD, ~CNY),
+ + +
3756 }
+
3757 }
-
3768
-
3769 void
-
- -
3771 {
- - -
3774 receive_max();
-
3775 path_find_01();
-
3776 path_find_02();
-
3777 path_find_05();
-
3778 path_find_06();
-
3779 }
+
3758
+
3759 void
+
+ +
3761 {
+ + +
3764 receive_max();
+
3765 path_find_01();
+
3766 path_find_02();
+
3767 path_find_05();
+
3768 path_find_06();
+
3769 }
-
3780
-
3781 void
-
- -
3783 {
-
3784 using namespace jtx;
- -
3786
- - - -
3790 testTransferRateNoOwnerFee(all - fixAMMv1_1 - fixAMMv1_3);
- - -
3793 }
+
3770
+
3771 void
+
+ +
3773 {
+
3774 using namespace jtx;
+ +
3776
+ + + +
3780 testTransferRateNoOwnerFee(all - fixAMMv1_1 - fixAMMv1_3);
+ + +
3783 }
-
3794
-
3795 void
-
- -
3797 {
-
3798 using namespace jtx;
- - -
3801 testStepLimit(all - fixAMMv1_1 - fixAMMv1_3);
-
3802 }
+
3784
+
3785 void
+
+ +
3787 {
+
3788 using namespace jtx;
+ + +
3791 testStepLimit(all - fixAMMv1_1 - fixAMMv1_3);
+
3792 }
-
3803
-
3804 void
-
- -
3806 {
-
3807 using namespace jtx;
- - -
3810 test_convert_all_of_an_asset(all - fixAMMv1_1 - fixAMMv1_3);
-
3811 }
+
3793
+
3794 void
+
+ +
3796 {
+
3797 using namespace jtx;
+ + +
3800 test_convert_all_of_an_asset(all - fixAMMv1_1 - fixAMMv1_3);
+
3801 }
-
3812
-
3813 void
-
- -
3815 {
-
3816 auto const supported{jtx::testable_amendments()};
-
3817 testPayment(supported - featureDepositPreauth);
-
3818 testPayment(supported);
-
3819 testPayIOU();
+
3802
+
3803 void
+
+ +
3805 {
+
3806 auto const supported{jtx::testable_amendments()};
+
3807 testPayment(supported - featureDepositPreauth);
+
3808 testPayment(supported);
+
3809 testPayIOU();
+
3810 }
+
+
3811
+
3812 void
+
+ +
3814 {
+
3815 using namespace test::jtx;
+
3816 auto const sa = testable_amendments();
+
3817 testRippleState(sa);
+
3818 testGlobalFreeze(sa);
+
3820 }
3821
3822 void
- +
3824 {
-
3825 using namespace test::jtx;
-
3826 auto const sa = testable_amendments();
-
3827 testRippleState(sa);
-
3828 testGlobalFreeze(sa);
- -
3830 }
+
3825 using namespace jtx;
+
3826 auto const all = testable_amendments();
+
3827
+ +
3829 all - featureMultiSignReserve - featureExpandedSignerList);
+
3830 testTxMultisign(all - featureExpandedSignerList);
+ +
3832 }
-
3831
-
3832 void
-
- -
3834 {
-
3835 using namespace jtx;
-
3836 auto const all = testable_amendments();
-
3837
- -
3839 all - featureMultiSignReserve - featureExpandedSignerList);
-
3840 testTxMultisign(all - featureExpandedSignerList);
- -
3842 }
+
3833
+
3834 void
+
+ +
3836 {
+
3837 using namespace jtx;
+
3838 auto const all = testable_amendments();
+
3839
+ + +
3842 testLoop(all);
+
3843 }
-
3843
-
3844 void
-
- -
3846 {
-
3847 using namespace jtx;
-
3848 auto const all = testable_amendments();
-
3849
- - -
3852 testLoop(all);
-
3853 }
+
3844
+
3845 void
+
+
3846 run() override
+
3847 {
+
3848 testOffers();
+
3849 testPaths();
+
3850 testFlow();
+ + + +
3854 testFreeze();
+
3855 testMultisign();
+
3856 testPayStrand();
+
3857 }
-
3854
-
3855 void
-
-
3856 run() override
-
3857 {
-
3858 testOffers();
-
3859 testPaths();
-
3860 testFlow();
- - - -
3864 testFreeze();
-
3865 testMultisign();
-
3866 testPayStrand();
-
3867 }
+
3858};
-
3868};
-
-
3869
-
3870BEAST_DEFINE_TESTSUITE_PRIO(AMMExtended, app, ripple, 1);
-
3871
-
3872} // namespace test
-
3873} // namespace ripple
+
3859
+
3860BEAST_DEFINE_TESTSUITE_PRIO(AMMExtended, app, ripple, 1);
+
3861
+
3862} // namespace test
+
3863} // namespace ripple
Represents a JSON value.
Definition json_value.h:149
A generic endpoint for log messages.
Definition Journal.h:60
@@ -4243,62 +4233,62 @@ $(document).ready(function() { init_codefold(0); });
Tests of AMM that use offers too.
-
void testGlobalFreeze(FeatureBitset features)
- - -
void testOfferCrossWithXRP(FeatureBitset features)
-
void testCurrencyConversionEntire(FeatureBitset features)
- -
void testFalseDry(FeatureBitset features)
- -
void testOfferCrossWithLimitOverride(FeatureBitset features)
-
void testTransferRateOffer(FeatureBitset features)
- - -
void testBookStep(FeatureBitset features)
- -
void testBridgedCross(FeatureBitset features)
-
void test_convert_all_of_an_asset(FeatureBitset features)
-
void testGatewayCrossCurrency(FeatureBitset features)
-
void testRequireAuth(FeatureBitset features)
- -
void testPayment(FeatureBitset features)
- -
void testOfferFeesConsumeFunds(FeatureBitset features)
- - -
void testOffersWhenFrozen(FeatureBitset features)
-
void testSellFlagExceedLimit(FeatureBitset features)
-
void testCrossCurrencyBridged(FeatureBitset features)
-
void testBadPathAssert(FeatureBitset features)
-
void testLoop(FeatureBitset features)
- -
void testOfferCreateThenCross(FeatureBitset features)
-
void testToStrand(FeatureBitset features)
-
void run() override
Runs the suite.
+
void testGlobalFreeze(FeatureBitset features)
+ + +
void testOfferCrossWithXRP(FeatureBitset features)
+
void testCurrencyConversionEntire(FeatureBitset features)
+ +
void testFalseDry(FeatureBitset features)
+ +
void testOfferCrossWithLimitOverride(FeatureBitset features)
+
void testTransferRateOffer(FeatureBitset features)
+ + +
void testBookStep(FeatureBitset features)
+ +
void testBridgedCross(FeatureBitset features)
+
void test_convert_all_of_an_asset(FeatureBitset features)
+
void testGatewayCrossCurrency(FeatureBitset features)
+
void testRequireAuth(FeatureBitset features)
+ +
void testPayment(FeatureBitset features)
+ +
void testOfferFeesConsumeFunds(FeatureBitset features)
+ + +
void testOffersWhenFrozen(FeatureBitset features)
+
void testSellFlagExceedLimit(FeatureBitset features)
+
void testCrossCurrencyBridged(FeatureBitset features)
+
void testBadPathAssert(FeatureBitset features)
+
void testLoop(FeatureBitset features)
+ +
void testOfferCreateThenCross(FeatureBitset features)
+
void testToStrand(FeatureBitset features)
+
void run() override
Runs the suite.
void testFillModes(FeatureBitset features)
- -
void testMissingAuth(FeatureBitset features)
- -
void testRIPD1373(FeatureBitset features)
-
void testCrossCurrencyEndXRP(FeatureBitset features)
- -
void testCurrencyConversionInParts(FeatureBitset features)
- -
void testTransferRateNoOwnerFee(FeatureBitset features)
-
void testRippleState(FeatureBitset features)
- + +
void testMissingAuth(FeatureBitset features)
+ +
void testRIPD1373(FeatureBitset features)
+
void testCrossCurrencyEndXRP(FeatureBitset features)
+ +
void testCurrencyConversionInParts(FeatureBitset features)
+ +
void testTransferRateNoOwnerFee(FeatureBitset features)
+
void testRippleState(FeatureBitset features)
+
void testRmFundedOffer(FeatureBitset features)
-
void testSelfIssueOffer(FeatureBitset features)
-
void testDirectToDirectPath(FeatureBitset features)
- -
void testStepLimit(FeatureBitset features)
- +
void testSelfIssueOffer(FeatureBitset features)
+
void testDirectToDirectPath(FeatureBitset features)
+ +
void testStepLimit(FeatureBitset features)
+
void testEnforceNoRipple(FeatureBitset features)
-
void testCrossCurrencyStartXRP(FeatureBitset features)
-
void testSellWithFillOrKill(FeatureBitset features)
-
void testTxMultisign(FeatureBitset features)
-
void testSellFlagBasic(FeatureBitset features)
+
void testCrossCurrencyStartXRP(FeatureBitset features)
+
void testSellWithFillOrKill(FeatureBitset features)
+
void testTxMultisign(FeatureBitset features)
+
void testSellFlagBasic(FeatureBitset features)
Represents an XRP or IOU quantity This customizes the string conversion and supports XRP conversions ...
T tie(T... args)
diff --git a/CreateOffer_8cpp_source.html b/CreateOffer_8cpp_source.html index 0b07d0224d..3c21f3914b 100644 --- a/CreateOffer_8cpp_source.html +++ b/CreateOffer_8cpp_source.html @@ -897,173 +897,171 @@ $(document).ready(function() { init_codefold(0); });
795 if (bFillOrKill)
796 {
797 JLOG(j_.trace()) << "Fill or Kill: offer killed";
-
798 if (sb.rules().enabled(fix1578))
-
799 return {tecKILLED, false};
-
800 return {tesSUCCESS, false};
-
801 }
-
802
-
803 // For 'immediate or cancel' offers, the amount remaining doesn't get
-
804 // placed - it gets canceled and the operation succeeds.
-
805 if (bImmediateOrCancel)
-
806 {
-
807 JLOG(j_.trace()) << "Immediate or cancel: offer canceled";
-
808 if (!crossed && sb.rules().enabled(featureImmediateOfferKilled))
-
809 // If the ImmediateOfferKilled amendment is enabled, any
-
810 // ImmediateOrCancel offer that transfers absolutely no funds
-
811 // returns tecKILLED rather than tesSUCCESS. Motivation for the
-
812 // change is here: https://github.com/ripple/rippled/issues/4115
-
813 return {tecKILLED, false};
-
814 return {tesSUCCESS, true};
-
815 }
-
816
-
817 auto const sleCreator = sb.peek(keylet::account(account_));
-
818 if (!sleCreator)
-
819 return {tefINTERNAL, false};
-
820
-
821 {
-
822 XRPAmount reserve =
-
823 sb.fees().accountReserve(sleCreator->getFieldU32(sfOwnerCount) + 1);
-
824
-
825 if (mPriorBalance < reserve)
-
826 {
-
827 // If we are here, the signing account had an insufficient reserve
-
828 // *prior* to our processing. If something actually crossed, then
-
829 // we allow this; otherwise, we just claim a fee.
-
830 if (!crossed)
-
831 result = tecINSUF_RESERVE_OFFER;
-
832
-
833 if (result != tesSUCCESS)
-
834 {
-
835 JLOG(j_.debug()) << "final result: " << transToken(result);
-
836 }
-
837
-
838 return {result, true};
-
839 }
-
840 }
-
841
-
842 // We need to place the remainder of the offer into its order book.
-
843 auto const offer_index = keylet::offer(account_, offerSequence);
-
844
-
845 // Add offer to owner's directory.
-
846 auto const ownerNode = sb.dirInsert(
- -
848
-
849 if (!ownerNode)
-
850 {
-
851 // LCOV_EXCL_START
-
852 JLOG(j_.debug())
-
853 << "final result: failed to add offer to owner's directory";
-
854 return {tecDIR_FULL, true};
-
855 // LCOV_EXCL_STOP
-
856 }
-
857
-
858 // Update owner count.
-
859 adjustOwnerCount(sb, sleCreator, 1, viewJ);
-
860
-
861 JLOG(j_.trace()) << "adding to book: " << to_string(saTakerPays.issue())
-
862 << " : " << to_string(saTakerGets.issue())
-
863 << (domainID ? (" : " + to_string(*domainID)) : "");
+
798 return {tecKILLED, false};
+
799 }
+
800
+
801 // For 'immediate or cancel' offers, the amount remaining doesn't get
+
802 // placed - it gets canceled and the operation succeeds.
+
803 if (bImmediateOrCancel)
+
804 {
+
805 JLOG(j_.trace()) << "Immediate or cancel: offer canceled";
+
806 if (!crossed && sb.rules().enabled(featureImmediateOfferKilled))
+
807 // If the ImmediateOfferKilled amendment is enabled, any
+
808 // ImmediateOrCancel offer that transfers absolutely no funds
+
809 // returns tecKILLED rather than tesSUCCESS. Motivation for the
+
810 // change is here: https://github.com/ripple/rippled/issues/4115
+
811 return {tecKILLED, false};
+
812 return {tesSUCCESS, true};
+
813 }
+
814
+
815 auto const sleCreator = sb.peek(keylet::account(account_));
+
816 if (!sleCreator)
+
817 return {tefINTERNAL, false};
+
818
+
819 {
+
820 XRPAmount reserve =
+
821 sb.fees().accountReserve(sleCreator->getFieldU32(sfOwnerCount) + 1);
+
822
+
823 if (mPriorBalance < reserve)
+
824 {
+
825 // If we are here, the signing account had an insufficient reserve
+
826 // *prior* to our processing. If something actually crossed, then
+
827 // we allow this; otherwise, we just claim a fee.
+
828 if (!crossed)
+
829 result = tecINSUF_RESERVE_OFFER;
+
830
+
831 if (result != tesSUCCESS)
+
832 {
+
833 JLOG(j_.debug()) << "final result: " << transToken(result);
+
834 }
+
835
+
836 return {result, true};
+
837 }
+
838 }
+
839
+
840 // We need to place the remainder of the offer into its order book.
+
841 auto const offer_index = keylet::offer(account_, offerSequence);
+
842
+
843 // Add offer to owner's directory.
+
844 auto const ownerNode = sb.dirInsert(
+ +
846
+
847 if (!ownerNode)
+
848 {
+
849 // LCOV_EXCL_START
+
850 JLOG(j_.debug())
+
851 << "final result: failed to add offer to owner's directory";
+
852 return {tecDIR_FULL, true};
+
853 // LCOV_EXCL_STOP
+
854 }
+
855
+
856 // Update owner count.
+
857 adjustOwnerCount(sb, sleCreator, 1, viewJ);
+
858
+
859 JLOG(j_.trace()) << "adding to book: " << to_string(saTakerPays.issue())
+
860 << " : " << to_string(saTakerGets.issue())
+
861 << (domainID ? (" : " + to_string(*domainID)) : "");
+
862
+
863 Book const book{saTakerPays.issue(), saTakerGets.issue(), domainID};
864
-
865 Book const book{saTakerPays.issue(), saTakerGets.issue(), domainID};
-
866
-
867 // Add offer to order book, using the original rate
-
868 // before any crossing occured.
+
865 // Add offer to order book, using the original rate
+
866 // before any crossing occured.
+
867 //
+
868 // Regular offer - BookDirectory points to open directory
869 //
-
870 // Regular offer - BookDirectory points to open directory
-
871 //
-
872 // Domain offer (w/o hyrbid) - BookDirectory points to domain
-
873 // directory
-
874 //
-
875 // Hybrid domain offer - BookDirectory points to domain directory,
-
876 // and AdditionalBooks field stores one entry that points to the open
-
877 // directory
-
878 auto dir = keylet::quality(keylet::book(book), uRate);
-
879 bool const bookExisted = static_cast<bool>(sb.peek(dir));
-
880
-
881 auto setBookDir = [&](SLE::ref sle,
-
882 std::optional<uint256> const& maybeDomain) {
-
883 sle->setFieldH160(sfTakerPaysCurrency, saTakerPays.issue().currency);
-
884 sle->setFieldH160(sfTakerPaysIssuer, saTakerPays.issue().account);
-
885 sle->setFieldH160(sfTakerGetsCurrency, saTakerGets.issue().currency);
-
886 sle->setFieldH160(sfTakerGetsIssuer, saTakerGets.issue().account);
-
887 sle->setFieldU64(sfExchangeRate, uRate);
-
888 if (maybeDomain)
-
889 sle->setFieldH256(sfDomainID, *maybeDomain);
-
890 };
-
891
-
892 auto const bookNode = sb.dirAppend(dir, offer_index, [&](SLE::ref sle) {
-
893 // sets domainID on book directory if it's a domain offer
-
894 setBookDir(sle, domainID);
-
895 });
-
896
-
897 if (!bookNode)
-
898 {
-
899 // LCOV_EXCL_START
-
900 JLOG(j_.debug()) << "final result: failed to add offer to book";
-
901 return {tecDIR_FULL, true};
-
902 // LCOV_EXCL_STOP
-
903 }
-
904
-
905 auto sleOffer = std::make_shared<SLE>(offer_index);
-
906 sleOffer->setAccountID(sfAccount, account_);
-
907 sleOffer->setFieldU32(sfSequence, offerSequence);
-
908 sleOffer->setFieldH256(sfBookDirectory, dir.key);
-
909 sleOffer->setFieldAmount(sfTakerPays, saTakerPays);
-
910 sleOffer->setFieldAmount(sfTakerGets, saTakerGets);
-
911 sleOffer->setFieldU64(sfOwnerNode, *ownerNode);
-
912 sleOffer->setFieldU64(sfBookNode, *bookNode);
-
913 if (expiration)
-
914 sleOffer->setFieldU32(sfExpiration, *expiration);
-
915 if (bPassive)
-
916 sleOffer->setFlag(lsfPassive);
-
917 if (bSell)
-
918 sleOffer->setFlag(lsfSell);
-
919 if (domainID)
-
920 sleOffer->setFieldH256(sfDomainID, *domainID);
-
921
-
922 // if it's a hybrid offer, set hybrid flag, and create an open dir
-
923 if (bHybrid)
-
924 {
-
925 auto const res = applyHybrid(
-
926 sb, sleOffer, offer_index, saTakerPays, saTakerGets, setBookDir);
-
927 if (res != tesSUCCESS)
-
928 return {res, true}; // LCOV_EXCL_LINE
-
929 }
+
870 // Domain offer (w/o hyrbid) - BookDirectory points to domain
+
871 // directory
+
872 //
+
873 // Hybrid domain offer - BookDirectory points to domain directory,
+
874 // and AdditionalBooks field stores one entry that points to the open
+
875 // directory
+
876 auto dir = keylet::quality(keylet::book(book), uRate);
+
877 bool const bookExisted = static_cast<bool>(sb.peek(dir));
+
878
+
879 auto setBookDir = [&](SLE::ref sle,
+
880 std::optional<uint256> const& maybeDomain) {
+
881 sle->setFieldH160(sfTakerPaysCurrency, saTakerPays.issue().currency);
+
882 sle->setFieldH160(sfTakerPaysIssuer, saTakerPays.issue().account);
+
883 sle->setFieldH160(sfTakerGetsCurrency, saTakerGets.issue().currency);
+
884 sle->setFieldH160(sfTakerGetsIssuer, saTakerGets.issue().account);
+
885 sle->setFieldU64(sfExchangeRate, uRate);
+
886 if (maybeDomain)
+
887 sle->setFieldH256(sfDomainID, *maybeDomain);
+
888 };
+
889
+
890 auto const bookNode = sb.dirAppend(dir, offer_index, [&](SLE::ref sle) {
+
891 // sets domainID on book directory if it's a domain offer
+
892 setBookDir(sle, domainID);
+
893 });
+
894
+
895 if (!bookNode)
+
896 {
+
897 // LCOV_EXCL_START
+
898 JLOG(j_.debug()) << "final result: failed to add offer to book";
+
899 return {tecDIR_FULL, true};
+
900 // LCOV_EXCL_STOP
+
901 }
+
902
+
903 auto sleOffer = std::make_shared<SLE>(offer_index);
+
904 sleOffer->setAccountID(sfAccount, account_);
+
905 sleOffer->setFieldU32(sfSequence, offerSequence);
+
906 sleOffer->setFieldH256(sfBookDirectory, dir.key);
+
907 sleOffer->setFieldAmount(sfTakerPays, saTakerPays);
+
908 sleOffer->setFieldAmount(sfTakerGets, saTakerGets);
+
909 sleOffer->setFieldU64(sfOwnerNode, *ownerNode);
+
910 sleOffer->setFieldU64(sfBookNode, *bookNode);
+
911 if (expiration)
+
912 sleOffer->setFieldU32(sfExpiration, *expiration);
+
913 if (bPassive)
+
914 sleOffer->setFlag(lsfPassive);
+
915 if (bSell)
+
916 sleOffer->setFlag(lsfSell);
+
917 if (domainID)
+
918 sleOffer->setFieldH256(sfDomainID, *domainID);
+
919
+
920 // if it's a hybrid offer, set hybrid flag, and create an open dir
+
921 if (bHybrid)
+
922 {
+
923 auto const res = applyHybrid(
+
924 sb, sleOffer, offer_index, saTakerPays, saTakerGets, setBookDir);
+
925 if (res != tesSUCCESS)
+
926 return {res, true}; // LCOV_EXCL_LINE
+
927 }
+
928
+
929 sb.insert(sleOffer);
930
-
931 sb.insert(sleOffer);
-
932
-
933 if (!bookExisted)
- +
931 if (!bookExisted)
+ +
933
+
934 JLOG(j_.debug()) << "final result: success";
935
-
936 JLOG(j_.debug()) << "final result: success";
-
937
-
938 return {tesSUCCESS, true};
-
939}
+
936 return {tesSUCCESS, true};
+
937}
-
940
-
941TER
-
- -
943{
-
944 // This is the ledger view that we work against. Transactions are applied
-
945 // as we go on processing transactions.
-
946 Sandbox sb(&ctx_.view());
-
947
-
948 // This is a ledger with just the fees paid and any unfunded or expired
-
949 // offers we encounter removed. It's used when handling Fill-or-Kill offers,
-
950 // if the order isn't going to be placed, to avoid wasting the work we did.
-
951 Sandbox sbCancel(&ctx_.view());
-
952
-
953 auto const result = applyGuts(sb, sbCancel);
-
954 if (result.second)
-
955 sb.apply(ctx_.rawView());
-
956 else
-
957 sbCancel.apply(ctx_.rawView());
-
958 return result.first;
-
959}
+
938
+
939TER
+
+ +
941{
+
942 // This is the ledger view that we work against. Transactions are applied
+
943 // as we go on processing transactions.
+
944 Sandbox sb(&ctx_.view());
+
945
+
946 // This is a ledger with just the fees paid and any unfunded or expired
+
947 // offers we encounter removed. It's used when handling Fill-or-Kill offers,
+
948 // if the order isn't going to be placed, to avoid wasting the work we did.
+
949 Sandbox sbCancel(&ctx_.view());
+
950
+
951 auto const result = applyGuts(sb, sbCancel);
+
952 if (result.second)
+
953 sb.apply(ctx_.rawView());
+
954 else
+
955 sbCancel.apply(ctx_.rawView());
+
956 return result.first;
+
957}
-
960
-
961} // namespace ripple
+
958
+
959} // namespace ripple
A generic endpoint for log messages.
Definition Journal.h:60
Stream fatal() const
Definition Journal.h:352
@@ -1087,7 +1085,7 @@ $(document).ready(function() { init_codefold(0); });
static NotTEC preflight(PreflightContext const &ctx)
Enforce constraints beyond those of the Transactor base class.
static TxConsequences makeTxConsequences(PreflightContext const &ctx)
TER applyHybrid(Sandbox &sb, std::shared_ptr< STLedgerEntry > sleOffer, Keylet const &offer_index, STAmount const &saTakerPays, STAmount const &saTakerGets, std::function< void(SLE::ref, std::optional< uint256 >)> const &setDir)
-
TER doApply() override
Precondition: fee collection is likely.
+
TER doApply() override
Precondition: fee collection is likely.
static bool checkExtraFeatures(PreflightContext const &ctx)
std::pair< TER, bool > applyGuts(Sandbox &view, Sandbox &view_cancel)
A currency issued by an account.
Definition Issue.h:33
diff --git a/CreateOffer_8h_source.html b/CreateOffer_8h_source.html index 45d91cfba7..48074cabd3 100644 --- a/CreateOffer_8h_source.html +++ b/CreateOffer_8h_source.html @@ -196,7 +196,7 @@ $(document).ready(function() { init_codefold(0); });
static NotTEC preflight(PreflightContext const &ctx)
Enforce constraints beyond those of the Transactor base class.
static TxConsequences makeTxConsequences(PreflightContext const &ctx)
TER applyHybrid(Sandbox &sb, std::shared_ptr< STLedgerEntry > sleOffer, Keylet const &offer_index, STAmount const &saTakerPays, STAmount const &saTakerGets, std::function< void(SLE::ref, std::optional< uint256 >)> const &setDir)
-
TER doApply() override
Precondition: fee collection is likely.
+
TER doApply() override
Precondition: fee collection is likely.
static bool checkExtraFeatures(PreflightContext const &ctx)
std::pair< TER, bool > applyGuts(Sandbox &view, Sandbox &view_cancel)
A currency issued by an account.
Definition Issue.h:33
diff --git a/Feature__test_8cpp_source.html b/Feature__test_8cpp_source.html index 8560704f50..2e8e2714a5 100644 --- a/Feature__test_8cpp_source.html +++ b/Feature__test_8cpp_source.html @@ -230,515 +230,514 @@ $(document).ready(function() { init_codefold(0); });
143 featureToName(fixTrustLinesToSelf) == "fixTrustLinesToSelf");
144 BEAST_EXPECT(featureToName(featureFlow) == "Flow");
145 BEAST_EXPECT(featureToName(featureNegativeUNL) == "NegativeUNL");
-
146 BEAST_EXPECT(featureToName(fix1578) == "fix1578");
-
147 BEAST_EXPECT(
-
148 featureToName(fixTakerDryOfferRemoval) ==
-
149 "fixTakerDryOfferRemoval");
-
150 }
+
146 BEAST_EXPECT(
+
147 featureToName(fixTakerDryOfferRemoval) ==
+
148 "fixTakerDryOfferRemoval");
+
149 }
-
151
-
152 void
-
- -
154 {
-
155 testcase("No Params, None Enabled");
-
156
-
157 using namespace test::jtx;
-
158 Env env{*this};
-
159
- - -
162
-
163 auto jrr = env.rpc("feature")[jss::result];
-
164 if (!BEAST_EXPECT(jrr.isMember(jss::features)))
-
165 return;
-
166 for (auto const& feature : jrr[jss::features])
-
167 {
-
168 if (!BEAST_EXPECT(feature.isMember(jss::name)))
-
169 return;
-
170 // default config - so all should be disabled, and
-
171 // supported. Some may be vetoed.
-
172 bool expectVeto =
-
173 (votes.at(feature[jss::name].asString()) ==
- -
175 bool expectObsolete =
-
176 (votes.at(feature[jss::name].asString()) ==
- -
178 BEAST_EXPECTS(
-
179 feature.isMember(jss::enabled) &&
-
180 !feature[jss::enabled].asBool(),
-
181 feature[jss::name].asString() + " enabled");
-
182 BEAST_EXPECTS(
-
183 feature.isMember(jss::vetoed) &&
-
184 feature[jss::vetoed].isBool() == !expectObsolete &&
-
185 (!feature[jss::vetoed].isBool() ||
-
186 feature[jss::vetoed].asBool() == expectVeto) &&
-
187 (feature[jss::vetoed].isBool() ||
-
188 feature[jss::vetoed].asString() == "Obsolete"),
-
189 feature[jss::name].asString() + " vetoed");
-
190 BEAST_EXPECTS(
-
191 feature.isMember(jss::supported) &&
-
192 feature[jss::supported].asBool(),
-
193 feature[jss::name].asString() + " supported");
-
194 }
-
195 }
+
150
+
151 void
+
+ +
153 {
+
154 testcase("No Params, None Enabled");
+
155
+
156 using namespace test::jtx;
+
157 Env env{*this};
+
158
+ + +
161
+
162 auto jrr = env.rpc("feature")[jss::result];
+
163 if (!BEAST_EXPECT(jrr.isMember(jss::features)))
+
164 return;
+
165 for (auto const& feature : jrr[jss::features])
+
166 {
+
167 if (!BEAST_EXPECT(feature.isMember(jss::name)))
+
168 return;
+
169 // default config - so all should be disabled, and
+
170 // supported. Some may be vetoed.
+
171 bool expectVeto =
+
172 (votes.at(feature[jss::name].asString()) ==
+ +
174 bool expectObsolete =
+
175 (votes.at(feature[jss::name].asString()) ==
+ +
177 BEAST_EXPECTS(
+
178 feature.isMember(jss::enabled) &&
+
179 !feature[jss::enabled].asBool(),
+
180 feature[jss::name].asString() + " enabled");
+
181 BEAST_EXPECTS(
+
182 feature.isMember(jss::vetoed) &&
+
183 feature[jss::vetoed].isBool() == !expectObsolete &&
+
184 (!feature[jss::vetoed].isBool() ||
+
185 feature[jss::vetoed].asBool() == expectVeto) &&
+
186 (feature[jss::vetoed].isBool() ||
+
187 feature[jss::vetoed].asString() == "Obsolete"),
+
188 feature[jss::name].asString() + " vetoed");
+
189 BEAST_EXPECTS(
+
190 feature.isMember(jss::supported) &&
+
191 feature[jss::supported].asBool(),
+
192 feature[jss::name].asString() + " supported");
+
193 }
+
194 }
-
196
-
197 void
-
- -
199 {
-
200 testcase("Feature Param");
-
201
-
202 using namespace test::jtx;
-
203 Env env{*this};
-
204
-
205 auto jrr = env.rpc("feature", "MultiSignReserve")[jss::result];
-
206 BEAST_EXPECTS(jrr[jss::status] == jss::success, "status");
-
207 jrr.removeMember(jss::status);
-
208 BEAST_EXPECT(jrr.size() == 1);
-
209 BEAST_EXPECT(
-
210 jrr.isMember("586480873651E106F1D6339B0C4A8945BA705A777F3F4524626FF"
-
211 "1FC07EFE41D"));
-
212 auto feature = *(jrr.begin());
-
213
-
214 BEAST_EXPECTS(feature[jss::name] == "MultiSignReserve", "name");
-
215 BEAST_EXPECTS(!feature[jss::enabled].asBool(), "enabled");
-
216 BEAST_EXPECTS(
-
217 feature[jss::vetoed].isBool() && !feature[jss::vetoed].asBool(),
-
218 "vetoed");
-
219 BEAST_EXPECTS(feature[jss::supported].asBool(), "supported");
-
220
-
221 // feature names are case-sensitive - expect error here
-
222 jrr = env.rpc("feature", "multiSignReserve")[jss::result];
-
223 BEAST_EXPECT(jrr[jss::error] == "badFeature");
-
224 BEAST_EXPECT(jrr[jss::error_message] == "Feature unknown or invalid.");
-
225 }
+
195
+
196 void
+
+ +
198 {
+
199 testcase("Feature Param");
+
200
+
201 using namespace test::jtx;
+
202 Env env{*this};
+
203
+
204 auto jrr = env.rpc("feature", "MultiSignReserve")[jss::result];
+
205 BEAST_EXPECTS(jrr[jss::status] == jss::success, "status");
+
206 jrr.removeMember(jss::status);
+
207 BEAST_EXPECT(jrr.size() == 1);
+
208 BEAST_EXPECT(
+
209 jrr.isMember("586480873651E106F1D6339B0C4A8945BA705A777F3F4524626FF"
+
210 "1FC07EFE41D"));
+
211 auto feature = *(jrr.begin());
+
212
+
213 BEAST_EXPECTS(feature[jss::name] == "MultiSignReserve", "name");
+
214 BEAST_EXPECTS(!feature[jss::enabled].asBool(), "enabled");
+
215 BEAST_EXPECTS(
+
216 feature[jss::vetoed].isBool() && !feature[jss::vetoed].asBool(),
+
217 "vetoed");
+
218 BEAST_EXPECTS(feature[jss::supported].asBool(), "supported");
+
219
+
220 // feature names are case-sensitive - expect error here
+
221 jrr = env.rpc("feature", "multiSignReserve")[jss::result];
+
222 BEAST_EXPECT(jrr[jss::error] == "badFeature");
+
223 BEAST_EXPECT(jrr[jss::error_message] == "Feature unknown or invalid.");
+
224 }
-
226
-
227 void
-
- -
229 {
-
230 testcase("Invalid Feature");
-
231
-
232 using namespace test::jtx;
-
233 Env env{*this};
-
234
-
235 auto testInvalidParam = [&](auto const& param) {
-
236 Json::Value params;
-
237 params[jss::feature] = param;
-
238 auto jrr =
-
239 env.rpc("json", "feature", to_string(params))[jss::result];
-
240 BEAST_EXPECT(jrr[jss::error] == "invalidParams");
-
241 BEAST_EXPECT(jrr[jss::error_message] == "Invalid parameters.");
-
242 };
-
243
-
244 testInvalidParam(1);
-
245 testInvalidParam(1.1);
-
246 testInvalidParam(true);
-
247 testInvalidParam(Json::Value(Json::nullValue));
-
248 testInvalidParam(Json::Value(Json::objectValue));
-
249 testInvalidParam(Json::Value(Json::arrayValue));
-
250
-
251 {
-
252 auto jrr = env.rpc("feature", "AllTheThings")[jss::result];
-
253 BEAST_EXPECT(jrr[jss::error] == "badFeature");
-
254 BEAST_EXPECT(
-
255 jrr[jss::error_message] == "Feature unknown or invalid.");
-
256 }
-
257 }
+
225
+
226 void
+
+ +
228 {
+
229 testcase("Invalid Feature");
+
230
+
231 using namespace test::jtx;
+
232 Env env{*this};
+
233
+
234 auto testInvalidParam = [&](auto const& param) {
+
235 Json::Value params;
+
236 params[jss::feature] = param;
+
237 auto jrr =
+
238 env.rpc("json", "feature", to_string(params))[jss::result];
+
239 BEAST_EXPECT(jrr[jss::error] == "invalidParams");
+
240 BEAST_EXPECT(jrr[jss::error_message] == "Invalid parameters.");
+
241 };
+
242
+
243 testInvalidParam(1);
+
244 testInvalidParam(1.1);
+
245 testInvalidParam(true);
+
246 testInvalidParam(Json::Value(Json::nullValue));
+
247 testInvalidParam(Json::Value(Json::objectValue));
+
248 testInvalidParam(Json::Value(Json::arrayValue));
+
249
+
250 {
+
251 auto jrr = env.rpc("feature", "AllTheThings")[jss::result];
+
252 BEAST_EXPECT(jrr[jss::error] == "badFeature");
+
253 BEAST_EXPECT(
+
254 jrr[jss::error_message] == "Feature unknown or invalid.");
+
255 }
+
256 }
-
258
-
259 void
-
- -
261 {
-
262 testcase("Feature Without Admin");
-
263
-
264 using namespace test::jtx;
-
265 Env env{*this, envconfig([](std::unique_ptr<Config> cfg) {
-
266 (*cfg)["port_rpc"].set("admin", "");
-
267 (*cfg)["port_ws"].set("admin", "");
-
268 return cfg;
-
269 })};
-
270
-
271 {
-
272 auto result = env.rpc("feature")[jss::result];
-
273 BEAST_EXPECT(result.isMember(jss::features));
-
274 // There should be at least 50 amendments. Don't do exact
-
275 // comparison to avoid maintenance as more amendments are added in
-
276 // the future.
-
277 BEAST_EXPECT(result[jss::features].size() >= 50);
-
278 for (auto it = result[jss::features].begin();
-
279 it != result[jss::features].end();
-
280 ++it)
-
281 {
-
282 uint256 id;
-
283 (void)id.parseHex(it.key().asString().c_str());
-
284 if (!BEAST_EXPECT((*it).isMember(jss::name)))
-
285 return;
-
286 bool expectEnabled =
-
287 env.app().getAmendmentTable().isEnabled(id);
-
288 bool expectSupported =
-
289 env.app().getAmendmentTable().isSupported(id);
-
290 BEAST_EXPECTS(
-
291 (*it).isMember(jss::enabled) &&
-
292 (*it)[jss::enabled].asBool() == expectEnabled,
-
293 (*it)[jss::name].asString() + " enabled");
-
294 BEAST_EXPECTS(
-
295 (*it).isMember(jss::supported) &&
-
296 (*it)[jss::supported].asBool() == expectSupported,
-
297 (*it)[jss::name].asString() + " supported");
-
298 BEAST_EXPECT(!(*it).isMember(jss::vetoed));
-
299 BEAST_EXPECT(!(*it).isMember(jss::majority));
-
300 BEAST_EXPECT(!(*it).isMember(jss::count));
-
301 BEAST_EXPECT(!(*it).isMember(jss::validations));
-
302 BEAST_EXPECT(!(*it).isMember(jss::threshold));
-
303 }
-
304 }
-
305
-
306 {
-
307 Json::Value params;
-
308 // invalid feature
-
309 params[jss::feature] =
-
310 "1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCD"
-
311 "EF";
-
312 auto const result =
-
313 env.rpc("json", "feature", to_string(params))[jss::result];
-
314 BEAST_EXPECTS(
-
315 result[jss::error] == "badFeature", result.toStyledString());
-
316 BEAST_EXPECT(
-
317 result[jss::error_message] == "Feature unknown or invalid.");
-
318 }
-
319
-
320 {
-
321 Json::Value params;
-
322 params[jss::feature] =
-
323 "93E516234E35E08CA689FA33A6D38E103881F8DCB53023F728C307AA89D515"
-
324 "A7";
-
325 // invalid param
-
326 params[jss::vetoed] = true;
-
327 auto const result =
-
328 env.rpc("json", "feature", to_string(params))[jss::result];
-
329 BEAST_EXPECTS(
-
330 result[jss::error] == "noPermission",
-
331 result[jss::error].asString());
-
332 BEAST_EXPECT(
-
333 result[jss::error_message] ==
-
334 "You don't have permission for this command.");
-
335 }
-
336
-
337 {
-
338 std::string const feature =
-
339 "C4483A1896170C66C098DEA5B0E024309C60DC960DE5F01CD7AF986AA3D9AD"
-
340 "37";
-
341 Json::Value params;
-
342 params[jss::feature] = feature;
-
343 auto const result =
-
344 env.rpc("json", "feature", to_string(params))[jss::result];
-
345 BEAST_EXPECT(result.isMember(feature));
-
346 auto const amendmentResult = result[feature];
-
347 BEAST_EXPECT(amendmentResult[jss::enabled].asBool() == false);
-
348 BEAST_EXPECT(amendmentResult[jss::supported].asBool() == true);
-
349 BEAST_EXPECT(
-
350 amendmentResult[jss::name].asString() ==
-
351 "fixMasterKeyAsRegularKey");
-
352 }
-
353 }
+
257
+
258 void
+
+ +
260 {
+
261 testcase("Feature Without Admin");
+
262
+
263 using namespace test::jtx;
+
264 Env env{*this, envconfig([](std::unique_ptr<Config> cfg) {
+
265 (*cfg)["port_rpc"].set("admin", "");
+
266 (*cfg)["port_ws"].set("admin", "");
+
267 return cfg;
+
268 })};
+
269
+
270 {
+
271 auto result = env.rpc("feature")[jss::result];
+
272 BEAST_EXPECT(result.isMember(jss::features));
+
273 // There should be at least 50 amendments. Don't do exact
+
274 // comparison to avoid maintenance as more amendments are added in
+
275 // the future.
+
276 BEAST_EXPECT(result[jss::features].size() >= 50);
+
277 for (auto it = result[jss::features].begin();
+
278 it != result[jss::features].end();
+
279 ++it)
+
280 {
+
281 uint256 id;
+
282 (void)id.parseHex(it.key().asString().c_str());
+
283 if (!BEAST_EXPECT((*it).isMember(jss::name)))
+
284 return;
+
285 bool expectEnabled =
+
286 env.app().getAmendmentTable().isEnabled(id);
+
287 bool expectSupported =
+
288 env.app().getAmendmentTable().isSupported(id);
+
289 BEAST_EXPECTS(
+
290 (*it).isMember(jss::enabled) &&
+
291 (*it)[jss::enabled].asBool() == expectEnabled,
+
292 (*it)[jss::name].asString() + " enabled");
+
293 BEAST_EXPECTS(
+
294 (*it).isMember(jss::supported) &&
+
295 (*it)[jss::supported].asBool() == expectSupported,
+
296 (*it)[jss::name].asString() + " supported");
+
297 BEAST_EXPECT(!(*it).isMember(jss::vetoed));
+
298 BEAST_EXPECT(!(*it).isMember(jss::majority));
+
299 BEAST_EXPECT(!(*it).isMember(jss::count));
+
300 BEAST_EXPECT(!(*it).isMember(jss::validations));
+
301 BEAST_EXPECT(!(*it).isMember(jss::threshold));
+
302 }
+
303 }
+
304
+
305 {
+
306 Json::Value params;
+
307 // invalid feature
+
308 params[jss::feature] =
+
309 "1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCD"
+
310 "EF";
+
311 auto const result =
+
312 env.rpc("json", "feature", to_string(params))[jss::result];
+
313 BEAST_EXPECTS(
+
314 result[jss::error] == "badFeature", result.toStyledString());
+
315 BEAST_EXPECT(
+
316 result[jss::error_message] == "Feature unknown or invalid.");
+
317 }
+
318
+
319 {
+
320 Json::Value params;
+
321 params[jss::feature] =
+
322 "93E516234E35E08CA689FA33A6D38E103881F8DCB53023F728C307AA89D515"
+
323 "A7";
+
324 // invalid param
+
325 params[jss::vetoed] = true;
+
326 auto const result =
+
327 env.rpc("json", "feature", to_string(params))[jss::result];
+
328 BEAST_EXPECTS(
+
329 result[jss::error] == "noPermission",
+
330 result[jss::error].asString());
+
331 BEAST_EXPECT(
+
332 result[jss::error_message] ==
+
333 "You don't have permission for this command.");
+
334 }
+
335
+
336 {
+
337 std::string const feature =
+
338 "C4483A1896170C66C098DEA5B0E024309C60DC960DE5F01CD7AF986AA3D9AD"
+
339 "37";
+
340 Json::Value params;
+
341 params[jss::feature] = feature;
+
342 auto const result =
+
343 env.rpc("json", "feature", to_string(params))[jss::result];
+
344 BEAST_EXPECT(result.isMember(feature));
+
345 auto const amendmentResult = result[feature];
+
346 BEAST_EXPECT(amendmentResult[jss::enabled].asBool() == false);
+
347 BEAST_EXPECT(amendmentResult[jss::supported].asBool() == true);
+
348 BEAST_EXPECT(
+
349 amendmentResult[jss::name].asString() ==
+
350 "fixMasterKeyAsRegularKey");
+
351 }
+
352 }
-
354
-
355 void
-
- -
357 {
-
358 testcase("No Params, Some Enabled");
-
359
-
360 using namespace test::jtx;
-
361 Env env{
-
362 *this, FeatureBitset(featureDepositAuth, featureDepositPreauth)};
-
363
- - -
366
-
367 auto jrr = env.rpc("feature")[jss::result];
-
368 if (!BEAST_EXPECT(jrr.isMember(jss::features)))
-
369 return;
-
370 for (auto it = jrr[jss::features].begin();
-
371 it != jrr[jss::features].end();
-
372 ++it)
-
373 {
-
374 uint256 id;
-
375 (void)id.parseHex(it.key().asString().c_str());
-
376 if (!BEAST_EXPECT((*it).isMember(jss::name)))
-
377 return;
-
378 bool expectEnabled = env.app().getAmendmentTable().isEnabled(id);
-
379 bool expectSupported =
-
380 env.app().getAmendmentTable().isSupported(id);
-
381 bool expectVeto =
-
382 (votes.at((*it)[jss::name].asString()) ==
- -
384 bool expectObsolete =
-
385 (votes.at((*it)[jss::name].asString()) ==
- -
387 BEAST_EXPECTS(
-
388 (*it).isMember(jss::enabled) &&
-
389 (*it)[jss::enabled].asBool() == expectEnabled,
-
390 (*it)[jss::name].asString() + " enabled");
-
391 if (expectEnabled)
-
392 BEAST_EXPECTS(
-
393 !(*it).isMember(jss::vetoed),
-
394 (*it)[jss::name].asString() + " vetoed");
-
395 else
-
396 BEAST_EXPECTS(
-
397 (*it).isMember(jss::vetoed) &&
-
398 (*it)[jss::vetoed].isBool() == !expectObsolete &&
-
399 (!(*it)[jss::vetoed].isBool() ||
-
400 (*it)[jss::vetoed].asBool() == expectVeto) &&
-
401 ((*it)[jss::vetoed].isBool() ||
-
402 (*it)[jss::vetoed].asString() == "Obsolete"),
-
403 (*it)[jss::name].asString() + " vetoed");
-
404 BEAST_EXPECTS(
-
405 (*it).isMember(jss::supported) &&
-
406 (*it)[jss::supported].asBool() == expectSupported,
-
407 (*it)[jss::name].asString() + " supported");
-
408 }
-
409 }
+
353
+
354 void
+
+ +
356 {
+
357 testcase("No Params, Some Enabled");
+
358
+
359 using namespace test::jtx;
+
360 Env env{
+
361 *this, FeatureBitset(featureDepositAuth, featureDepositPreauth)};
+
362
+ + +
365
+
366 auto jrr = env.rpc("feature")[jss::result];
+
367 if (!BEAST_EXPECT(jrr.isMember(jss::features)))
+
368 return;
+
369 for (auto it = jrr[jss::features].begin();
+
370 it != jrr[jss::features].end();
+
371 ++it)
+
372 {
+
373 uint256 id;
+
374 (void)id.parseHex(it.key().asString().c_str());
+
375 if (!BEAST_EXPECT((*it).isMember(jss::name)))
+
376 return;
+
377 bool expectEnabled = env.app().getAmendmentTable().isEnabled(id);
+
378 bool expectSupported =
+
379 env.app().getAmendmentTable().isSupported(id);
+
380 bool expectVeto =
+
381 (votes.at((*it)[jss::name].asString()) ==
+ +
383 bool expectObsolete =
+
384 (votes.at((*it)[jss::name].asString()) ==
+ +
386 BEAST_EXPECTS(
+
387 (*it).isMember(jss::enabled) &&
+
388 (*it)[jss::enabled].asBool() == expectEnabled,
+
389 (*it)[jss::name].asString() + " enabled");
+
390 if (expectEnabled)
+
391 BEAST_EXPECTS(
+
392 !(*it).isMember(jss::vetoed),
+
393 (*it)[jss::name].asString() + " vetoed");
+
394 else
+
395 BEAST_EXPECTS(
+
396 (*it).isMember(jss::vetoed) &&
+
397 (*it)[jss::vetoed].isBool() == !expectObsolete &&
+
398 (!(*it)[jss::vetoed].isBool() ||
+
399 (*it)[jss::vetoed].asBool() == expectVeto) &&
+
400 ((*it)[jss::vetoed].isBool() ||
+
401 (*it)[jss::vetoed].asString() == "Obsolete"),
+
402 (*it)[jss::name].asString() + " vetoed");
+
403 BEAST_EXPECTS(
+
404 (*it).isMember(jss::supported) &&
+
405 (*it)[jss::supported].asBool() == expectSupported,
+
406 (*it)[jss::name].asString() + " supported");
+
407 }
+
408 }
-
410
-
411 void
-
- -
413 {
-
414 testcase("With Majorities");
-
415
-
416 using namespace test::jtx;
-
417 Env env{*this, envconfig(validator, "")};
-
418
-
419 auto jrr = env.rpc("feature")[jss::result];
-
420 if (!BEAST_EXPECT(jrr.isMember(jss::features)))
-
421 return;
-
422
-
423 // at this point, there are no majorities so no fields related to
-
424 // amendment voting
-
425 for (auto const& feature : jrr[jss::features])
-
426 {
-
427 if (!BEAST_EXPECT(feature.isMember(jss::name)))
-
428 return;
-
429 BEAST_EXPECTS(
-
430 !feature.isMember(jss::majority),
-
431 feature[jss::name].asString() + " majority");
-
432 BEAST_EXPECTS(
-
433 !feature.isMember(jss::count),
-
434 feature[jss::name].asString() + " count");
-
435 BEAST_EXPECTS(
-
436 !feature.isMember(jss::threshold),
-
437 feature[jss::name].asString() + " threshold");
-
438 BEAST_EXPECTS(
-
439 !feature.isMember(jss::validations),
-
440 feature[jss::name].asString() + " validations");
-
441 BEAST_EXPECTS(
-
442 !feature.isMember(jss::vote),
-
443 feature[jss::name].asString() + " vote");
-
444 }
-
445
-
446 auto majorities = getMajorityAmendments(*env.closed());
-
447 if (!BEAST_EXPECT(majorities.empty()))
-
448 return;
-
449
-
450 // close ledgers until the amendments show up.
-
451 for (auto i = 0; i <= 256; ++i)
-
452 {
-
453 env.close();
-
454 majorities = getMajorityAmendments(*env.closed());
-
455 if (!majorities.empty())
-
456 break;
-
457 }
-
458
-
459 // There should be at least 5 amendments. Don't do exact comparison
-
460 // to avoid maintenance as more amendments are added in the future.
-
461 BEAST_EXPECT(majorities.size() >= 5);
- - -
464
-
465 jrr = env.rpc("feature")[jss::result];
-
466 if (!BEAST_EXPECT(jrr.isMember(jss::features)))
-
467 return;
-
468 for (auto const& feature : jrr[jss::features])
-
469 {
-
470 if (!BEAST_EXPECT(feature.isMember(jss::name)))
-
471 return;
-
472 bool expectVeto =
-
473 (votes.at(feature[jss::name].asString()) ==
- -
475 bool expectObsolete =
-
476 (votes.at(feature[jss::name].asString()) ==
- -
478 BEAST_EXPECTS(
-
479 (expectVeto || expectObsolete) ^
-
480 feature.isMember(jss::majority),
-
481 feature[jss::name].asString() + " majority");
-
482 BEAST_EXPECTS(
-
483 feature.isMember(jss::vetoed) &&
-
484 feature[jss::vetoed].isBool() == !expectObsolete &&
-
485 (!feature[jss::vetoed].isBool() ||
-
486 feature[jss::vetoed].asBool() == expectVeto) &&
-
487 (feature[jss::vetoed].isBool() ||
-
488 feature[jss::vetoed].asString() == "Obsolete"),
-
489 feature[jss::name].asString() + " vetoed");
-
490 BEAST_EXPECTS(
-
491 feature.isMember(jss::count),
-
492 feature[jss::name].asString() + " count");
-
493 BEAST_EXPECTS(
-
494 feature.isMember(jss::threshold),
-
495 feature[jss::name].asString() + " threshold");
-
496 BEAST_EXPECTS(
-
497 feature.isMember(jss::validations),
-
498 feature[jss::name].asString() + " validations");
-
499 BEAST_EXPECT(
-
500 feature[jss::count] ==
-
501 ((expectVeto || expectObsolete) ? 0 : 1));
-
502 BEAST_EXPECT(feature[jss::threshold] == 1);
-
503 BEAST_EXPECT(feature[jss::validations] == 1);
-
504 BEAST_EXPECTS(
-
505 expectVeto || expectObsolete || feature[jss::majority] == 2540,
-
506 "Majority: " + feature[jss::majority].asString());
-
507 }
-
508 }
+
409
+
410 void
+
+ +
412 {
+
413 testcase("With Majorities");
+
414
+
415 using namespace test::jtx;
+
416 Env env{*this, envconfig(validator, "")};
+
417
+
418 auto jrr = env.rpc("feature")[jss::result];
+
419 if (!BEAST_EXPECT(jrr.isMember(jss::features)))
+
420 return;
+
421
+
422 // at this point, there are no majorities so no fields related to
+
423 // amendment voting
+
424 for (auto const& feature : jrr[jss::features])
+
425 {
+
426 if (!BEAST_EXPECT(feature.isMember(jss::name)))
+
427 return;
+
428 BEAST_EXPECTS(
+
429 !feature.isMember(jss::majority),
+
430 feature[jss::name].asString() + " majority");
+
431 BEAST_EXPECTS(
+
432 !feature.isMember(jss::count),
+
433 feature[jss::name].asString() + " count");
+
434 BEAST_EXPECTS(
+
435 !feature.isMember(jss::threshold),
+
436 feature[jss::name].asString() + " threshold");
+
437 BEAST_EXPECTS(
+
438 !feature.isMember(jss::validations),
+
439 feature[jss::name].asString() + " validations");
+
440 BEAST_EXPECTS(
+
441 !feature.isMember(jss::vote),
+
442 feature[jss::name].asString() + " vote");
+
443 }
+
444
+
445 auto majorities = getMajorityAmendments(*env.closed());
+
446 if (!BEAST_EXPECT(majorities.empty()))
+
447 return;
+
448
+
449 // close ledgers until the amendments show up.
+
450 for (auto i = 0; i <= 256; ++i)
+
451 {
+
452 env.close();
+
453 majorities = getMajorityAmendments(*env.closed());
+
454 if (!majorities.empty())
+
455 break;
+
456 }
+
457
+
458 // There should be at least 5 amendments. Don't do exact comparison
+
459 // to avoid maintenance as more amendments are added in the future.
+
460 BEAST_EXPECT(majorities.size() >= 5);
+ + +
463
+
464 jrr = env.rpc("feature")[jss::result];
+
465 if (!BEAST_EXPECT(jrr.isMember(jss::features)))
+
466 return;
+
467 for (auto const& feature : jrr[jss::features])
+
468 {
+
469 if (!BEAST_EXPECT(feature.isMember(jss::name)))
+
470 return;
+
471 bool expectVeto =
+
472 (votes.at(feature[jss::name].asString()) ==
+ +
474 bool expectObsolete =
+
475 (votes.at(feature[jss::name].asString()) ==
+ +
477 BEAST_EXPECTS(
+
478 (expectVeto || expectObsolete) ^
+
479 feature.isMember(jss::majority),
+
480 feature[jss::name].asString() + " majority");
+
481 BEAST_EXPECTS(
+
482 feature.isMember(jss::vetoed) &&
+
483 feature[jss::vetoed].isBool() == !expectObsolete &&
+
484 (!feature[jss::vetoed].isBool() ||
+
485 feature[jss::vetoed].asBool() == expectVeto) &&
+
486 (feature[jss::vetoed].isBool() ||
+
487 feature[jss::vetoed].asString() == "Obsolete"),
+
488 feature[jss::name].asString() + " vetoed");
+
489 BEAST_EXPECTS(
+
490 feature.isMember(jss::count),
+
491 feature[jss::name].asString() + " count");
+
492 BEAST_EXPECTS(
+
493 feature.isMember(jss::threshold),
+
494 feature[jss::name].asString() + " threshold");
+
495 BEAST_EXPECTS(
+
496 feature.isMember(jss::validations),
+
497 feature[jss::name].asString() + " validations");
+
498 BEAST_EXPECT(
+
499 feature[jss::count] ==
+
500 ((expectVeto || expectObsolete) ? 0 : 1));
+
501 BEAST_EXPECT(feature[jss::threshold] == 1);
+
502 BEAST_EXPECT(feature[jss::validations] == 1);
+
503 BEAST_EXPECTS(
+
504 expectVeto || expectObsolete || feature[jss::majority] == 2540,
+
505 "Majority: " + feature[jss::majority].asString());
+
506 }
+
507 }
-
509
-
510 void
-
- -
512 {
-
513 testcase("Veto");
-
514
-
515 using namespace test::jtx;
-
516 Env env{*this, FeatureBitset(featureMultiSignReserve)};
-
517 constexpr char const* featureName = "MultiSignReserve";
-
518
-
519 auto jrr = env.rpc("feature", featureName)[jss::result];
-
520 if (!BEAST_EXPECTS(jrr[jss::status] == jss::success, "status"))
-
521 return;
-
522 jrr.removeMember(jss::status);
-
523 if (!BEAST_EXPECT(jrr.size() == 1))
-
524 return;
-
525 auto feature = *(jrr.begin());
-
526 BEAST_EXPECTS(feature[jss::name] == featureName, "name");
-
527 BEAST_EXPECTS(
-
528 feature[jss::vetoed].isBool() && !feature[jss::vetoed].asBool(),
-
529 "vetoed");
-
530
-
531 jrr = env.rpc("feature", featureName, "reject")[jss::result];
-
532 if (!BEAST_EXPECTS(jrr[jss::status] == jss::success, "status"))
-
533 return;
-
534 jrr.removeMember(jss::status);
-
535 if (!BEAST_EXPECT(jrr.size() == 1))
-
536 return;
-
537 feature = *(jrr.begin());
-
538 BEAST_EXPECTS(feature[jss::name] == featureName, "name");
-
539 BEAST_EXPECTS(
-
540 feature[jss::vetoed].isBool() && feature[jss::vetoed].asBool(),
-
541 "vetoed");
-
542
-
543 jrr = env.rpc("feature", featureName, "accept")[jss::result];
-
544 if (!BEAST_EXPECTS(jrr[jss::status] == jss::success, "status"))
-
545 return;
-
546 jrr.removeMember(jss::status);
-
547 if (!BEAST_EXPECT(jrr.size() == 1))
-
548 return;
-
549 feature = *(jrr.begin());
-
550 BEAST_EXPECTS(feature[jss::name] == featureName, "name");
-
551 BEAST_EXPECTS(
-
552 feature[jss::vetoed].isBool() && !feature[jss::vetoed].asBool(),
-
553 "vetoed");
-
554
-
555 // anything other than accept or reject is an error
-
556 jrr = env.rpc("feature", featureName, "maybe");
-
557 BEAST_EXPECT(jrr[jss::error] == "invalidParams");
-
558 BEAST_EXPECT(jrr[jss::error_message] == "Invalid parameters.");
-
559 }
+
508
+
509 void
+
+ +
511 {
+
512 testcase("Veto");
+
513
+
514 using namespace test::jtx;
+
515 Env env{*this, FeatureBitset(featureMultiSignReserve)};
+
516 constexpr char const* featureName = "MultiSignReserve";
+
517
+
518 auto jrr = env.rpc("feature", featureName)[jss::result];
+
519 if (!BEAST_EXPECTS(jrr[jss::status] == jss::success, "status"))
+
520 return;
+
521 jrr.removeMember(jss::status);
+
522 if (!BEAST_EXPECT(jrr.size() == 1))
+
523 return;
+
524 auto feature = *(jrr.begin());
+
525 BEAST_EXPECTS(feature[jss::name] == featureName, "name");
+
526 BEAST_EXPECTS(
+
527 feature[jss::vetoed].isBool() && !feature[jss::vetoed].asBool(),
+
528 "vetoed");
+
529
+
530 jrr = env.rpc("feature", featureName, "reject")[jss::result];
+
531 if (!BEAST_EXPECTS(jrr[jss::status] == jss::success, "status"))
+
532 return;
+
533 jrr.removeMember(jss::status);
+
534 if (!BEAST_EXPECT(jrr.size() == 1))
+
535 return;
+
536 feature = *(jrr.begin());
+
537 BEAST_EXPECTS(feature[jss::name] == featureName, "name");
+
538 BEAST_EXPECTS(
+
539 feature[jss::vetoed].isBool() && feature[jss::vetoed].asBool(),
+
540 "vetoed");
+
541
+
542 jrr = env.rpc("feature", featureName, "accept")[jss::result];
+
543 if (!BEAST_EXPECTS(jrr[jss::status] == jss::success, "status"))
+
544 return;
+
545 jrr.removeMember(jss::status);
+
546 if (!BEAST_EXPECT(jrr.size() == 1))
+
547 return;
+
548 feature = *(jrr.begin());
+
549 BEAST_EXPECTS(feature[jss::name] == featureName, "name");
+
550 BEAST_EXPECTS(
+
551 feature[jss::vetoed].isBool() && !feature[jss::vetoed].asBool(),
+
552 "vetoed");
+
553
+
554 // anything other than accept or reject is an error
+
555 jrr = env.rpc("feature", featureName, "maybe");
+
556 BEAST_EXPECT(jrr[jss::error] == "invalidParams");
+
557 BEAST_EXPECT(jrr[jss::error_message] == "Invalid parameters.");
+
558 }
-
560
-
561 void
-
- -
563 {
-
564 testcase("Obsolete");
-
565
-
566 using namespace test::jtx;
-
567 Env env{*this};
-
568 constexpr char const* featureName = "NonFungibleTokensV1";
-
569
-
570 auto jrr = env.rpc("feature", featureName)[jss::result];
-
571 if (!BEAST_EXPECTS(jrr[jss::status] == jss::success, "status"))
-
572 return;
-
573 jrr.removeMember(jss::status);
-
574 if (!BEAST_EXPECT(jrr.size() == 1))
-
575 return;
-
576 auto feature = *(jrr.begin());
-
577 BEAST_EXPECTS(feature[jss::name] == featureName, "name");
-
578 BEAST_EXPECTS(
-
579 feature[jss::vetoed].isString() &&
-
580 feature[jss::vetoed].asString() == "Obsolete",
-
581 "vetoed");
-
582
-
583 jrr = env.rpc("feature", featureName, "reject")[jss::result];
-
584 if (!BEAST_EXPECTS(jrr[jss::status] == jss::success, "status"))
-
585 return;
-
586 jrr.removeMember(jss::status);
-
587 if (!BEAST_EXPECT(jrr.size() == 1))
-
588 return;
-
589 feature = *(jrr.begin());
-
590 BEAST_EXPECTS(feature[jss::name] == featureName, "name");
-
591 BEAST_EXPECTS(
-
592 feature[jss::vetoed].isString() &&
-
593 feature[jss::vetoed].asString() == "Obsolete",
-
594 "vetoed");
-
595
-
596 jrr = env.rpc("feature", featureName, "accept")[jss::result];
-
597 if (!BEAST_EXPECTS(jrr[jss::status] == jss::success, "status"))
-
598 return;
-
599 jrr.removeMember(jss::status);
-
600 if (!BEAST_EXPECT(jrr.size() == 1))
-
601 return;
-
602 feature = *(jrr.begin());
-
603 BEAST_EXPECTS(feature[jss::name] == featureName, "name");
-
604 BEAST_EXPECTS(
-
605 feature[jss::vetoed].isString() &&
-
606 feature[jss::vetoed].asString() == "Obsolete",
-
607 "vetoed");
-
608
-
609 // anything other than accept or reject is an error
-
610 jrr = env.rpc("feature", featureName, "maybe");
-
611 BEAST_EXPECT(jrr[jss::error] == "invalidParams");
-
612 BEAST_EXPECT(jrr[jss::error_message] == "Invalid parameters.");
-
613 }
+
559
+
560 void
+
+ +
562 {
+
563 testcase("Obsolete");
+
564
+
565 using namespace test::jtx;
+
566 Env env{*this};
+
567 constexpr char const* featureName = "NonFungibleTokensV1";
+
568
+
569 auto jrr = env.rpc("feature", featureName)[jss::result];
+
570 if (!BEAST_EXPECTS(jrr[jss::status] == jss::success, "status"))
+
571 return;
+
572 jrr.removeMember(jss::status);
+
573 if (!BEAST_EXPECT(jrr.size() == 1))
+
574 return;
+
575 auto feature = *(jrr.begin());
+
576 BEAST_EXPECTS(feature[jss::name] == featureName, "name");
+
577 BEAST_EXPECTS(
+
578 feature[jss::vetoed].isString() &&
+
579 feature[jss::vetoed].asString() == "Obsolete",
+
580 "vetoed");
+
581
+
582 jrr = env.rpc("feature", featureName, "reject")[jss::result];
+
583 if (!BEAST_EXPECTS(jrr[jss::status] == jss::success, "status"))
+
584 return;
+
585 jrr.removeMember(jss::status);
+
586 if (!BEAST_EXPECT(jrr.size() == 1))
+
587 return;
+
588 feature = *(jrr.begin());
+
589 BEAST_EXPECTS(feature[jss::name] == featureName, "name");
+
590 BEAST_EXPECTS(
+
591 feature[jss::vetoed].isString() &&
+
592 feature[jss::vetoed].asString() == "Obsolete",
+
593 "vetoed");
+
594
+
595 jrr = env.rpc("feature", featureName, "accept")[jss::result];
+
596 if (!BEAST_EXPECTS(jrr[jss::status] == jss::success, "status"))
+
597 return;
+
598 jrr.removeMember(jss::status);
+
599 if (!BEAST_EXPECT(jrr.size() == 1))
+
600 return;
+
601 feature = *(jrr.begin());
+
602 BEAST_EXPECTS(feature[jss::name] == featureName, "name");
+
603 BEAST_EXPECTS(
+
604 feature[jss::vetoed].isString() &&
+
605 feature[jss::vetoed].asString() == "Obsolete",
+
606 "vetoed");
+
607
+
608 // anything other than accept or reject is an error
+
609 jrr = env.rpc("feature", featureName, "maybe");
+
610 BEAST_EXPECT(jrr[jss::error] == "invalidParams");
+
611 BEAST_EXPECT(jrr[jss::error_message] == "Invalid parameters.");
+
612 }
-
614
-
615public:
-
616 void
-
-
617 run() override
-
618 {
- - -
621 testNoParams();
- - -
624 testNonAdmin();
- - -
627 testVeto();
-
628 testObsolete();
-
629 }
+
613
+
614public:
+
615 void
+
+
616 run() override
+
617 {
+ + +
620 testNoParams();
+ + +
623 testNonAdmin();
+ + +
626 testVeto();
+
627 testObsolete();
+
628 }
-
630};
+
629};
-
631
-
632BEAST_DEFINE_TESTSUITE(Feature, rpc, ripple);
-
633
-
634} // namespace ripple
+
630
+
631BEAST_DEFINE_TESTSUITE(Feature, rpc, ripple);
+
632
+
633} // namespace ripple
T at(T... args)
Represents a JSON value.
Definition json_value.h:149
@@ -747,17 +746,17 @@ $(document).ready(function() { init_codefold(0); });
void fail(String const &reason, char const *file, int line)
Record a failure.
Definition suite.h:533
- - + + - - - + + + - - - -
void run() override
Runs the suite.
+ + + +
void run() override
Runs the suite.
@ nullValue
'null' value
Definition json_value.h:38
diff --git a/NoRipple__test_8cpp_source.html b/NoRipple__test_8cpp_source.html index 2618c02709..0f3fbfc028 100644 --- a/NoRipple__test_8cpp_source.html +++ b/NoRipple__test_8cpp_source.html @@ -172,241 +172,232 @@ $(document).ready(function() { init_codefold(0); });
85 auto const bob = Account("bob");
86 auto const carol = Account("carol");
87
-
88 // fix1578 changes the return code. Verify expected behavior
-
89 // without and with fix1578.
-
90 for (auto const& tweakedFeatures :
-
91 {features - fix1578, features | fix1578})
-
92 {
-
93 Env env(*this, tweakedFeatures);
-
94
-
95 env.fund(XRP(10000), gw, alice, bob, carol);
-
96 env.close();
-
97
-
98 env.trust(alice["USD"](100), bob);
-
99 env.trust(bob["USD"](100), carol);
-
100 env.close();
-
101
-
102 // After this payment alice has a -50 USD balance with bob, and
-
103 // bob has a -50 USD balance with carol. So neither alice nor
-
104 // bob should be able to clear the noRipple flag.
-
105 env(pay(alice, carol, carol["USD"](50)), path(bob));
-
106 env.close();
-
107
-
108 TER const terNeg{
-
109 tweakedFeatures[fix1578] ? TER{tecNO_PERMISSION}
-
110 : TER{tesSUCCESS}};
-
111
-
112 env(trust(alice, bob["USD"](100), bob, tfSetNoRipple), ter(terNeg));
-
113 env(trust(bob, carol["USD"](100), carol, tfSetNoRipple),
-
114 ter(terNeg));
-
115 env.close();
-
116
-
117 Json::Value params;
-
118 params[jss::source_account] = alice.human();
-
119 params[jss::destination_account] = carol.human();
-
120 params[jss::destination_amount] = [] {
-
121 Json::Value dest_amt;
-
122 dest_amt[jss::currency] = "USD";
-
123 dest_amt[jss::value] = "1";
-
124 dest_amt[jss::issuer] = Account("carol").human();
-
125 return dest_amt;
-
126 }();
-
127
-
128 auto const resp =
-
129 env.rpc("json", "ripple_path_find", to_string(params));
-
130 BEAST_EXPECT(resp[jss::result][jss::alternatives].size() == 1);
-
131
-
132 auto getAccountLines = [&env](Account const& acct) {
-
133 auto const r = jtx::getAccountLines(env, acct);
-
134 return r[jss::lines];
-
135 };
-
136 {
-
137 auto const aliceLines = getAccountLines(alice);
-
138 BEAST_EXPECT(aliceLines.size() == 1);
-
139 BEAST_EXPECT(aliceLines[0u][jss::no_ripple].asBool() == false);
-
140
-
141 auto const bobLines = getAccountLines(bob);
-
142 BEAST_EXPECT(bobLines.size() == 2);
-
143 BEAST_EXPECT(bobLines[0u][jss::no_ripple].asBool() == false);
-
144 BEAST_EXPECT(bobLines[1u][jss::no_ripple].asBool() == false);
-
145 }
-
146
-
147 // Now carol sends the 50 USD back to alice. Then alice and
-
148 // bob can set the noRipple flag.
-
149 env(pay(carol, alice, alice["USD"](50)), path(bob));
-
150 env.close();
+
88 Env env(*this, features);
+
89
+
90 env.fund(XRP(10000), gw, alice, bob, carol);
+
91 env.close();
+
92
+
93 env.trust(alice["USD"](100), bob);
+
94 env.trust(bob["USD"](100), carol);
+
95 env.close();
+
96
+
97 // After this payment alice has a -50 USD balance with bob, and
+
98 // bob has a -50 USD balance with carol. So neither alice nor
+
99 // bob should be able to clear the noRipple flag.
+
100 env(pay(alice, carol, carol["USD"](50)), path(bob));
+
101 env.close();
+
102
+
103 TER const terNeg{TER{tecNO_PERMISSION}};
+
104
+
105 env(trust(alice, bob["USD"](100), bob, tfSetNoRipple), ter(terNeg));
+
106 env(trust(bob, carol["USD"](100), carol, tfSetNoRipple), ter(terNeg));
+
107 env.close();
+
108
+
109 Json::Value params;
+
110 params[jss::source_account] = alice.human();
+
111 params[jss::destination_account] = carol.human();
+
112 params[jss::destination_amount] = [] {
+
113 Json::Value dest_amt;
+
114 dest_amt[jss::currency] = "USD";
+
115 dest_amt[jss::value] = "1";
+
116 dest_amt[jss::issuer] = Account("carol").human();
+
117 return dest_amt;
+
118 }();
+
119
+
120 auto const resp =
+
121 env.rpc("json", "ripple_path_find", to_string(params));
+
122 BEAST_EXPECT(resp[jss::result][jss::alternatives].size() == 1);
+
123
+
124 auto getAccountLines = [&env](Account const& acct) {
+
125 auto const r = jtx::getAccountLines(env, acct);
+
126 return r[jss::lines];
+
127 };
+
128 {
+
129 auto const aliceLines = getAccountLines(alice);
+
130 BEAST_EXPECT(aliceLines.size() == 1);
+
131 BEAST_EXPECT(aliceLines[0u][jss::no_ripple].asBool() == false);
+
132
+
133 auto const bobLines = getAccountLines(bob);
+
134 BEAST_EXPECT(bobLines.size() == 2);
+
135 BEAST_EXPECT(bobLines[0u][jss::no_ripple].asBool() == false);
+
136 BEAST_EXPECT(bobLines[1u][jss::no_ripple].asBool() == false);
+
137 }
+
138
+
139 // Now carol sends the 50 USD back to alice. Then alice and
+
140 // bob can set the noRipple flag.
+
141 env(pay(carol, alice, alice["USD"](50)), path(bob));
+
142 env.close();
+
143
+
144 env(trust(alice, bob["USD"](100), bob, tfSetNoRipple));
+
145 env(trust(bob, carol["USD"](100), carol, tfSetNoRipple));
+
146 env.close();
+
147 {
+
148 auto const aliceLines = getAccountLines(alice);
+
149 BEAST_EXPECT(aliceLines.size() == 1);
+
150 BEAST_EXPECT(aliceLines[0u].isMember(jss::no_ripple));
151
-
152 env(trust(alice, bob["USD"](100), bob, tfSetNoRipple));
-
153 env(trust(bob, carol["USD"](100), carol, tfSetNoRipple));
-
154 env.close();
-
155 {
-
156 auto const aliceLines = getAccountLines(alice);
-
157 BEAST_EXPECT(aliceLines.size() == 1);
-
158 BEAST_EXPECT(aliceLines[0u].isMember(jss::no_ripple));
-
159
-
160 auto const bobLines = getAccountLines(bob);
-
161 BEAST_EXPECT(bobLines.size() == 2);
-
162 BEAST_EXPECT(bobLines[0u].isMember(jss::no_ripple_peer));
-
163 BEAST_EXPECT(bobLines[1u].isMember(jss::no_ripple));
-
164 }
-
165 }
-
166 }
+
152 auto const bobLines = getAccountLines(bob);
+
153 BEAST_EXPECT(bobLines.size() == 2);
+
154 BEAST_EXPECT(bobLines[0u].isMember(jss::no_ripple_peer));
+
155 BEAST_EXPECT(bobLines[1u].isMember(jss::no_ripple));
+
156 }
+
157 }
-
167
-
168 void
-
- -
170 {
-
171 testcase("pairwise NoRipple");
+
158
+
159 void
+
+ +
161 {
+
162 testcase("pairwise NoRipple");
+
163
+
164 using namespace jtx;
+
165 Env env(*this, features);
+
166
+
167 auto const alice = Account("alice");
+
168 auto const bob = Account("bob");
+
169 auto const carol = Account("carol");
+
170
+
171 env.fund(XRP(10000), alice, bob, carol);
172
-
173 using namespace jtx;
-
174 Env env(*this, features);
+
173 env(trust(bob, alice["USD"](100)));
+
174 env(trust(carol, bob["USD"](100)));
175
-
176 auto const alice = Account("alice");
-
177 auto const bob = Account("bob");
-
178 auto const carol = Account("carol");
+
176 env(trust(bob, alice["USD"](100), alice, tfSetNoRipple));
+
177 env(trust(bob, carol["USD"](100), carol, tfSetNoRipple));
+
178 env.close();
179
-
180 env.fund(XRP(10000), alice, bob, carol);
-
181
-
182 env(trust(bob, alice["USD"](100)));
-
183 env(trust(carol, bob["USD"](100)));
-
184
-
185 env(trust(bob, alice["USD"](100), alice, tfSetNoRipple));
-
186 env(trust(bob, carol["USD"](100), carol, tfSetNoRipple));
-
187 env.close();
-
188
-
189 Json::Value params;
-
190 params[jss::source_account] = alice.human();
-
191 params[jss::destination_account] = carol.human();
-
192 params[jss::destination_amount] = [] {
-
193 Json::Value dest_amt;
-
194 dest_amt[jss::currency] = "USD";
-
195 dest_amt[jss::value] = "1";
-
196 dest_amt[jss::issuer] = Account("carol").human();
-
197 return dest_amt;
-
198 }();
-
199
-
200 Json::Value const resp{
-
201 env.rpc("json", "ripple_path_find", to_string(params))};
-
202 BEAST_EXPECT(resp[jss::result][jss::alternatives].size() == 0);
-
203
-
204 env(pay(alice, carol, bob["USD"](50)), ter(tecPATH_DRY));
-
205 }
+
180 Json::Value params;
+
181 params[jss::source_account] = alice.human();
+
182 params[jss::destination_account] = carol.human();
+
183 params[jss::destination_amount] = [] {
+
184 Json::Value dest_amt;
+
185 dest_amt[jss::currency] = "USD";
+
186 dest_amt[jss::value] = "1";
+
187 dest_amt[jss::issuer] = Account("carol").human();
+
188 return dest_amt;
+
189 }();
+
190
+
191 Json::Value const resp{
+
192 env.rpc("json", "ripple_path_find", to_string(params))};
+
193 BEAST_EXPECT(resp[jss::result][jss::alternatives].size() == 0);
+
194
+
195 env(pay(alice, carol, bob["USD"](50)), ter(tecPATH_DRY));
+
196 }
-
206
-
207 void
-
-
208 testDefaultRipple(FeatureBitset features, unsigned int apiVersion)
-
209 {
-
210 testcase(
-
211 "Set default ripple on an account and check new trustlines "
-
212 "Version " +
-
213 std::to_string(apiVersion));
+
197
+
198 void
+
+
199 testDefaultRipple(FeatureBitset features, unsigned int apiVersion)
+
200 {
+
201 testcase(
+
202 "Set default ripple on an account and check new trustlines "
+
203 "Version " +
+
204 std::to_string(apiVersion));
+
205
+
206 using namespace jtx;
+
207 Env env(*this, features);
+
208
+
209 auto const gw = Account("gateway");
+
210 auto const alice = Account("alice");
+
211 auto const bob = Account("bob");
+
212
+
213 env.fund(XRP(10000), gw, noripple(alice, bob));
214
-
215 using namespace jtx;
-
216 Env env(*this, features);
-
217
-
218 auto const gw = Account("gateway");
-
219 auto const alice = Account("alice");
-
220 auto const bob = Account("bob");
-
221
-
222 env.fund(XRP(10000), gw, noripple(alice, bob));
+
215 env(fset(bob, asfDefaultRipple));
+
216
+
217 auto const USD = gw["USD"];
+
218
+
219 env(trust(gw, USD(100), alice, 0));
+
220 env(trust(gw, USD(100), bob, 0));
+
221 Json::Value params;
+
222 params[jss::api_version] = apiVersion;
223
-
224 env(fset(bob, asfDefaultRipple));
-
225
-
226 auto const USD = gw["USD"];
+
224 {
+
225 params[jss::account] = gw.human();
+
226 params[jss::peer] = alice.human();
227
-
228 env(trust(gw, USD(100), alice, 0));
-
229 env(trust(gw, USD(100), bob, 0));
-
230 Json::Value params;
-
231 params[jss::api_version] = apiVersion;
-
232
-
233 {
-
234 params[jss::account] = gw.human();
-
235 params[jss::peer] = alice.human();
-
236
-
237 auto lines = env.rpc("json", "account_lines", to_string(params));
-
238 auto const& line0 = lines[jss::result][jss::lines][0u];
-
239 BEAST_EXPECT(line0[jss::no_ripple_peer].asBool() == true);
-
240 }
-
241 {
-
242 params[jss::account] = alice.human();
-
243 params[jss::peer] = gw.human();
-
244
-
245 auto lines = env.rpc("json", "account_lines", to_string(params));
-
246 auto const& line0 = lines[jss::result][jss::lines][0u];
-
247 BEAST_EXPECT(line0[jss::no_ripple].asBool() == true);
-
248 }
-
249 {
-
250 params[jss::account] = gw.human();
-
251 params[jss::peer] = bob.human();
-
252
-
253 auto lines = env.rpc("json", "account_lines", to_string(params));
-
254 auto const& line0 = lines[jss::result][jss::lines][0u];
-
255 BEAST_EXPECT(line0[jss::no_ripple].asBool() == false);
-
256 }
-
257 {
-
258 params[jss::account] = bob.human();
-
259 params[jss::peer] = gw.human();
-
260
-
261 auto lines = env.rpc("json", "account_lines", to_string(params));
-
262 auto const& line0 = lines[jss::result][jss::lines][0u];
-
263 BEAST_EXPECT(line0[jss::no_ripple_peer].asBool() == false);
-
264 }
-
265 {
-
266 // test for transactions
-
267 {
-
268 params[jss::account] = bob.human();
-
269 params[jss::role] = "gateway";
-
270 params[jss::transactions] = "asdf";
-
271
-
272 auto lines =
-
273 env.rpc("json", "noripple_check", to_string(params));
-
274 if (apiVersion < 2u)
-
275 BEAST_EXPECT(lines[jss::result][jss::status] == "success");
-
276 else
-
277 BEAST_EXPECT(
-
278 lines[jss::result][jss::error] == "invalidParams");
-
279 }
-
280 }
-
281 }
+
228 auto lines = env.rpc("json", "account_lines", to_string(params));
+
229 auto const& line0 = lines[jss::result][jss::lines][0u];
+
230 BEAST_EXPECT(line0[jss::no_ripple_peer].asBool() == true);
+
231 }
+
232 {
+
233 params[jss::account] = alice.human();
+
234 params[jss::peer] = gw.human();
+
235
+
236 auto lines = env.rpc("json", "account_lines", to_string(params));
+
237 auto const& line0 = lines[jss::result][jss::lines][0u];
+
238 BEAST_EXPECT(line0[jss::no_ripple].asBool() == true);
+
239 }
+
240 {
+
241 params[jss::account] = gw.human();
+
242 params[jss::peer] = bob.human();
+
243
+
244 auto lines = env.rpc("json", "account_lines", to_string(params));
+
245 auto const& line0 = lines[jss::result][jss::lines][0u];
+
246 BEAST_EXPECT(line0[jss::no_ripple].asBool() == false);
+
247 }
+
248 {
+
249 params[jss::account] = bob.human();
+
250 params[jss::peer] = gw.human();
+
251
+
252 auto lines = env.rpc("json", "account_lines", to_string(params));
+
253 auto const& line0 = lines[jss::result][jss::lines][0u];
+
254 BEAST_EXPECT(line0[jss::no_ripple_peer].asBool() == false);
+
255 }
+
256 {
+
257 // test for transactions
+
258 {
+
259 params[jss::account] = bob.human();
+
260 params[jss::role] = "gateway";
+
261 params[jss::transactions] = "asdf";
+
262
+
263 auto lines =
+
264 env.rpc("json", "noripple_check", to_string(params));
+
265 if (apiVersion < 2u)
+
266 BEAST_EXPECT(lines[jss::result][jss::status] == "success");
+
267 else
+
268 BEAST_EXPECT(
+
269 lines[jss::result][jss::error] == "invalidParams");
+
270 }
+
271 }
+
272 }
-
282
-
283 void
-
-
284 run() override
-
285 {
- -
287
-
288 auto withFeatsTests = [this](FeatureBitset features) {
-
289 forAllApiVersions([&, this](unsigned testVersion) {
-
290 testDefaultRipple(features, testVersion);
-
291 });
-
292 testNegativeBalance(features);
-
293 testPairwise(features);
-
294 };
-
295 using namespace jtx;
-
296 auto const sa = testable_amendments();
-
297 withFeatsTests(sa - featurePermissionedDEX);
-
298 withFeatsTests(sa);
-
299 }
+
273
+
274 void
+
+
275 run() override
+
276 {
+ +
278
+
279 auto withFeatsTests = [this](FeatureBitset features) {
+
280 forAllApiVersions([&, this](unsigned testVersion) {
+
281 testDefaultRipple(features, testVersion);
+
282 });
+
283 testNegativeBalance(features);
+
284 testPairwise(features);
+
285 };
+
286 using namespace jtx;
+
287 auto const sa = testable_amendments();
+
288 withFeatsTests(sa - featurePermissionedDEX);
+
289 withFeatsTests(sa);
+
290 }
-
300};
+
291};
-
301
-
302BEAST_DEFINE_TESTSUITE(NoRipple, rpc, ripple);
-
303
-
304} // namespace test
-
305} // namespace ripple
+
292
+
293BEAST_DEFINE_TESTSUITE(NoRipple, rpc, ripple);
+
294
+
295} // namespace test
+
296} // namespace ripple
Represents a JSON value.
Definition json_value.h:149
A testsuite class.
Definition suite.h:55
testcase_t testcase
Memberspace for declaring test cases.
Definition suite.h:155
-
void testDefaultRipple(FeatureBitset features, unsigned int apiVersion)
-
void testPairwise(FeatureBitset features)
-
void run() override
Runs the suite.
+
void testDefaultRipple(FeatureBitset features, unsigned int apiVersion)
+
void testPairwise(FeatureBitset features)
+
void run() override
Runs the suite.
void testNegativeBalance(FeatureBitset features)
Immutable cryptographic account descriptor.
Definition Account.h:39
@@ -433,7 +424,6 @@ $(document).ready(function() { init_codefold(0); });
void forAllApiVersions(Fn const &fn, Args &&... args)
Definition ApiVersion.h:101
@ tecNO_PERMISSION
Definition TER.h:305
@ tecPATH_DRY
Definition TER.h:294
-
@ tesSUCCESS
Definition TER.h:244
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:630
constexpr std::uint32_t tfSetNoRipple
Definition TxFlags.h:116
T to_string(T... args)
diff --git a/Offer__test_8cpp_source.html b/Offer__test_8cpp_source.html index e9817f4ae6..ed7be441e0 100644 --- a/Offer__test_8cpp_source.html +++ b/Offer__test_8cpp_source.html @@ -957,4773 +957,4765 @@ $(document).ready(function() { init_codefold(0); });
846 // Fill or Kill - unless we fully cross, just charge a fee and don't
847 // place the offer on the books. But also clean up expired offers
848 // that are discovered along the way.
-
849 //
-
850 // fix1578 changes the return code. Verify expected behavior
-
851 // without and with fix1578.
-
852 for (auto const& tweakedFeatures :
-
853 {features - fix1578, features | fix1578})
-
854 {
-
855 Env env{*this, tweakedFeatures};
+
849 {
+
850 Env env{*this, features};
+
851
+
852 auto const f = env.current()->fees().base;
+
853
+
854 env.fund(startBalance, gw, alice, bob);
+
855 env.close();
856
-
857 auto const f = env.current()->fees().base;
-
858
-
859 env.fund(startBalance, gw, alice, bob);
-
860 env.close();
+
857 // bob creates an offer that expires before the next ledger close.
+
858 env(offer(bob, USD(500), XRP(500)),
+
859 json(sfExpiration.fieldName, lastClose(env) + 1),
+
860 ter(tesSUCCESS));
861
-
862 // bob creates an offer that expires before the next ledger close.
-
863 env(offer(bob, USD(500), XRP(500)),
-
864 json(sfExpiration.fieldName, lastClose(env) + 1),
-
865 ter(tesSUCCESS));
-
866
-
867 // The offer expires (it's not removed yet).
+
862 // The offer expires (it's not removed yet).
+
863 env.close();
+
864 env.require(owners(bob, 1), offers(bob, 1));
+
865
+
866 // bob creates the offer that will be crossed.
+
867 env(offer(bob, USD(500), XRP(500)), ter(tesSUCCESS));
868 env.close();
-
869 env.require(owners(bob, 1), offers(bob, 1));
+
869 env.require(owners(bob, 2), offers(bob, 2));
870
-
871 // bob creates the offer that will be crossed.
-
872 env(offer(bob, USD(500), XRP(500)), ter(tesSUCCESS));
-
873 env.close();
-
874 env.require(owners(bob, 2), offers(bob, 2));
-
875
-
876 env(trust(alice, USD(1000)), ter(tesSUCCESS));
-
877 env(pay(gw, alice, USD(1000)), ter(tesSUCCESS));
-
878
-
879 // Order that can't be filled but will remove bob's expired offer:
-
880 {
-
881 TER const killedCode{
-
882 tweakedFeatures[fix1578] ? TER{tecKILLED}
-
883 : TER{tesSUCCESS}};
-
884 env(offer(alice, XRP(1000), USD(1000)),
- -
886 ter(killedCode));
-
887 }
-
888 env.require(
-
889 balance(alice, startBalance - (f * 2)),
-
890 balance(alice, USD(1000)),
-
891 owners(alice, 1),
-
892 offers(alice, 0),
-
893 balance(bob, startBalance - (f * 2)),
-
894 balance(bob, USD(none)),
-
895 owners(bob, 1),
-
896 offers(bob, 1));
-
897
-
898 // Order that can be filled
-
899 env(offer(alice, XRP(500), USD(500)),
- -
901 ter(tesSUCCESS));
-
902
-
903 env.require(
-
904 balance(alice, startBalance - (f * 3) + XRP(500)),
-
905 balance(alice, USD(500)),
-
906 owners(alice, 1),
-
907 offers(alice, 0),
-
908 balance(bob, startBalance - (f * 2) - XRP(500)),
-
909 balance(bob, USD(500)),
-
910 owners(bob, 1),
-
911 offers(bob, 0));
-
912 }
+
871 env(trust(alice, USD(1000)), ter(tesSUCCESS));
+
872 env(pay(gw, alice, USD(1000)), ter(tesSUCCESS));
+
873
+
874 // Order that can't be filled but will remove bob's expired offer:
+
875 {
+
876 TER const killedCode{TER{tecKILLED}};
+
877 env(offer(alice, XRP(1000), USD(1000)),
+ +
879 ter(killedCode));
+
880 }
+
881 env.require(
+
882 balance(alice, startBalance - (f * 2)),
+
883 balance(alice, USD(1000)),
+
884 owners(alice, 1),
+
885 offers(alice, 0),
+
886 balance(bob, startBalance - (f * 2)),
+
887 balance(bob, USD(none)),
+
888 owners(bob, 1),
+
889 offers(bob, 1));
+
890
+
891 // Order that can be filled
+
892 env(offer(alice, XRP(500), USD(500)),
+ +
894 ter(tesSUCCESS));
+
895
+
896 env.require(
+
897 balance(alice, startBalance - (f * 3) + XRP(500)),
+
898 balance(alice, USD(500)),
+
899 owners(alice, 1),
+
900 offers(alice, 0),
+
901 balance(bob, startBalance - (f * 2) - XRP(500)),
+
902 balance(bob, USD(500)),
+
903 owners(bob, 1),
+
904 offers(bob, 0));
+
905 }
+
906
+
907 // Immediate or Cancel - cross as much as possible
+
908 // and add nothing on the books:
+
909 {
+
910 Env env{*this, features};
+
911
+
912 auto const f = env.current()->fees().base;
913
-
914 // Immediate or Cancel - cross as much as possible
-
915 // and add nothing on the books:
-
916 {
-
917 Env env{*this, features};
-
918
-
919 auto const f = env.current()->fees().base;
-
920
-
921 env.fund(startBalance, gw, alice, bob);
-
922 env.close();
-
923
-
924 env(trust(alice, USD(1000)), ter(tesSUCCESS));
-
925 env(pay(gw, alice, USD(1000)), ter(tesSUCCESS));
-
926
-
927 // No cross:
-
928 {
-
929 TER const expectedCode = features[featureImmediateOfferKilled]
-
930 ? static_cast<TER>(tecKILLED)
-
931 : static_cast<TER>(tesSUCCESS);
-
932 env(offer(alice, XRP(1000), USD(1000)),
- -
934 ter(expectedCode));
-
935 }
-
936
-
937 env.require(
-
938 balance(alice, startBalance - f - f),
-
939 balance(alice, USD(1000)),
-
940 owners(alice, 1),
-
941 offers(alice, 0));
-
942
-
943 // Partially cross:
-
944 env(offer(bob, USD(50), XRP(50)), ter(tesSUCCESS));
-
945 env(offer(alice, XRP(1000), USD(1000)),
- -
947 ter(tesSUCCESS));
-
948
-
949 env.require(
-
950 balance(alice, startBalance - f - f - f + XRP(50)),
-
951 balance(alice, USD(950)),
-
952 owners(alice, 1),
-
953 offers(alice, 0),
-
954 balance(bob, startBalance - f - XRP(50)),
-
955 balance(bob, USD(50)),
-
956 owners(bob, 1),
-
957 offers(bob, 0));
-
958
-
959 // Fully cross:
-
960 env(offer(bob, USD(50), XRP(50)), ter(tesSUCCESS));
-
961 env(offer(alice, XRP(50), USD(50)),
- -
963 ter(tesSUCCESS));
-
964
-
965 env.require(
-
966 balance(alice, startBalance - f - f - f - f + XRP(100)),
-
967 balance(alice, USD(900)),
-
968 owners(alice, 1),
-
969 offers(alice, 0),
-
970 balance(bob, startBalance - f - f - XRP(100)),
-
971 balance(bob, USD(100)),
-
972 owners(bob, 1),
-
973 offers(bob, 0));
-
974 }
+
914 env.fund(startBalance, gw, alice, bob);
+
915 env.close();
+
916
+
917 env(trust(alice, USD(1000)), ter(tesSUCCESS));
+
918 env(pay(gw, alice, USD(1000)), ter(tesSUCCESS));
+
919
+
920 // No cross:
+
921 {
+
922 TER const expectedCode = features[featureImmediateOfferKilled]
+
923 ? static_cast<TER>(tecKILLED)
+
924 : static_cast<TER>(tesSUCCESS);
+
925 env(offer(alice, XRP(1000), USD(1000)),
+ +
927 ter(expectedCode));
+
928 }
+
929
+
930 env.require(
+
931 balance(alice, startBalance - f - f),
+
932 balance(alice, USD(1000)),
+
933 owners(alice, 1),
+
934 offers(alice, 0));
+
935
+
936 // Partially cross:
+
937 env(offer(bob, USD(50), XRP(50)), ter(tesSUCCESS));
+
938 env(offer(alice, XRP(1000), USD(1000)),
+ +
940 ter(tesSUCCESS));
+
941
+
942 env.require(
+
943 balance(alice, startBalance - f - f - f + XRP(50)),
+
944 balance(alice, USD(950)),
+
945 owners(alice, 1),
+
946 offers(alice, 0),
+
947 balance(bob, startBalance - f - XRP(50)),
+
948 balance(bob, USD(50)),
+
949 owners(bob, 1),
+
950 offers(bob, 0));
+
951
+
952 // Fully cross:
+
953 env(offer(bob, USD(50), XRP(50)), ter(tesSUCCESS));
+
954 env(offer(alice, XRP(50), USD(50)),
+ +
956 ter(tesSUCCESS));
+
957
+
958 env.require(
+
959 balance(alice, startBalance - f - f - f - f + XRP(100)),
+
960 balance(alice, USD(900)),
+
961 owners(alice, 1),
+
962 offers(alice, 0),
+
963 balance(bob, startBalance - f - f - XRP(100)),
+
964 balance(bob, USD(100)),
+
965 owners(bob, 1),
+
966 offers(bob, 0));
+
967 }
+
968
+
969 // tfPassive -- place the offer without crossing it.
+
970 {
+
971 Env env(*this, features);
+
972
+
973 env.fund(startBalance, gw, alice, bob);
+
974 env.close();
975
-
976 // tfPassive -- place the offer without crossing it.
-
977 {
-
978 Env env(*this, features);
-
979
-
980 env.fund(startBalance, gw, alice, bob);
-
981 env.close();
-
982
-
983 env(trust(bob, USD(1000)));
-
984 env.close();
-
985
-
986 env(pay(gw, bob, USD(1000)));
-
987 env.close();
-
988
-
989 env(offer(alice, USD(1000), XRP(2000)));
-
990 env.close();
-
991
-
992 auto const aliceOffers = offersOnAccount(env, alice);
-
993 BEAST_EXPECT(aliceOffers.size() == 1);
-
994 for (auto offerPtr : aliceOffers)
-
995 {
-
996 auto const& offer = *offerPtr;
-
997 BEAST_EXPECT(offer[sfTakerGets] == XRP(2000));
-
998 BEAST_EXPECT(offer[sfTakerPays] == USD(1000));
-
999 }
-
1000
-
1001 // bob creates a passive offer that could cross alice's.
-
1002 // bob's offer should stay in the ledger.
-
1003 env(offer(bob, XRP(2000), USD(1000), tfPassive));
-
1004 env.close();
-
1005 env.require(offers(alice, 1));
-
1006
-
1007 auto const bobOffers = offersOnAccount(env, bob);
-
1008 BEAST_EXPECT(bobOffers.size() == 1);
-
1009 for (auto offerPtr : bobOffers)
-
1010 {
-
1011 auto const& offer = *offerPtr;
-
1012 BEAST_EXPECT(offer[sfTakerGets] == USD(1000));
-
1013 BEAST_EXPECT(offer[sfTakerPays] == XRP(2000));
-
1014 }
+
976 env(trust(bob, USD(1000)));
+
977 env.close();
+
978
+
979 env(pay(gw, bob, USD(1000)));
+
980 env.close();
+
981
+
982 env(offer(alice, USD(1000), XRP(2000)));
+
983 env.close();
+
984
+
985 auto const aliceOffers = offersOnAccount(env, alice);
+
986 BEAST_EXPECT(aliceOffers.size() == 1);
+
987 for (auto offerPtr : aliceOffers)
+
988 {
+
989 auto const& offer = *offerPtr;
+
990 BEAST_EXPECT(offer[sfTakerGets] == XRP(2000));
+
991 BEAST_EXPECT(offer[sfTakerPays] == USD(1000));
+
992 }
+
993
+
994 // bob creates a passive offer that could cross alice's.
+
995 // bob's offer should stay in the ledger.
+
996 env(offer(bob, XRP(2000), USD(1000), tfPassive));
+
997 env.close();
+
998 env.require(offers(alice, 1));
+
999
+
1000 auto const bobOffers = offersOnAccount(env, bob);
+
1001 BEAST_EXPECT(bobOffers.size() == 1);
+
1002 for (auto offerPtr : bobOffers)
+
1003 {
+
1004 auto const& offer = *offerPtr;
+
1005 BEAST_EXPECT(offer[sfTakerGets] == USD(1000));
+
1006 BEAST_EXPECT(offer[sfTakerPays] == XRP(2000));
+
1007 }
+
1008
+
1009 // It should be possible for gw to cross both of those offers.
+
1010 env(offer(gw, XRP(2000), USD(1000)));
+
1011 env.close();
+
1012 env.require(offers(alice, 0));
+
1013 env.require(offers(gw, 0));
+
1014 env.require(offers(bob, 1));
1015
-
1016 // It should be possible for gw to cross both of those offers.
-
1017 env(offer(gw, XRP(2000), USD(1000)));
-
1018 env.close();
-
1019 env.require(offers(alice, 0));
-
1020 env.require(offers(gw, 0));
-
1021 env.require(offers(bob, 1));
-
1022
-
1023 env(offer(gw, USD(1000), XRP(2000)));
-
1024 env.close();
-
1025 env.require(offers(bob, 0));
-
1026 env.require(offers(gw, 0));
-
1027 }
+
1016 env(offer(gw, USD(1000), XRP(2000)));
+
1017 env.close();
+
1018 env.require(offers(bob, 0));
+
1019 env.require(offers(gw, 0));
+
1020 }
+
1021
+
1022 // tfPassive -- cross only offers of better quality.
+
1023 {
+
1024 Env env(*this, features);
+
1025
+
1026 env.fund(startBalance, gw, "alice", "bob");
+
1027 env.close();
1028
-
1029 // tfPassive -- cross only offers of better quality.
-
1030 {
-
1031 Env env(*this, features);
-
1032
-
1033 env.fund(startBalance, gw, "alice", "bob");
+
1029 env(trust("bob", USD(1000)));
+
1030 env.close();
+
1031
+
1032 env(pay(gw, "bob", USD(1000)));
+
1033 env(offer("alice", USD(500), XRP(1001)));
1034 env.close();
1035
-
1036 env(trust("bob", USD(1000)));
+
1036 env(offer("alice", USD(500), XRP(1000)));
1037 env.close();
1038
-
1039 env(pay(gw, "bob", USD(1000)));
-
1040 env(offer("alice", USD(500), XRP(1001)));
-
1041 env.close();
-
1042
-
1043 env(offer("alice", USD(500), XRP(1000)));
-
1044 env.close();
-
1045
-
1046 auto const aliceOffers = offersOnAccount(env, "alice");
-
1047 BEAST_EXPECT(aliceOffers.size() == 2);
+
1039 auto const aliceOffers = offersOnAccount(env, "alice");
+
1040 BEAST_EXPECT(aliceOffers.size() == 2);
+
1041
+
1042 // bob creates a passive offer. That offer should cross one
+
1043 // of alice's (the one with better quality) and leave alice's
+
1044 // other offer untouched.
+
1045 env(offer("bob", XRP(2000), USD(1000), tfPassive));
+
1046 env.close();
+
1047 env.require(offers("alice", 1));
1048
-
1049 // bob creates a passive offer. That offer should cross one
-
1050 // of alice's (the one with better quality) and leave alice's
-
1051 // other offer untouched.
-
1052 env(offer("bob", XRP(2000), USD(1000), tfPassive));
-
1053 env.close();
-
1054 env.require(offers("alice", 1));
-
1055
-
1056 auto const bobOffers = offersOnAccount(env, "bob");
-
1057 BEAST_EXPECT(bobOffers.size() == 1);
-
1058 for (auto offerPtr : bobOffers)
-
1059 {
-
1060 auto const& offer = *offerPtr;
-
1061 BEAST_EXPECT(offer[sfTakerGets] == USD(499.5));
-
1062 BEAST_EXPECT(offer[sfTakerPays] == XRP(999));
-
1063 }
-
1064 }
-
1065 }
+
1049 auto const bobOffers = offersOnAccount(env, "bob");
+
1050 BEAST_EXPECT(bobOffers.size() == 1);
+
1051 for (auto offerPtr : bobOffers)
+
1052 {
+
1053 auto const& offer = *offerPtr;
+
1054 BEAST_EXPECT(offer[sfTakerGets] == USD(499.5));
+
1055 BEAST_EXPECT(offer[sfTakerPays] == XRP(999));
+
1056 }
+
1057 }
+
1058 }
+
1059
+
1060 void
+
+ +
1062 {
+
1063 testcase("Malformed Detection");
+
1064
+
1065 using namespace jtx;
1066
-
1067 void
-
- -
1069 {
-
1070 testcase("Malformed Detection");
+
1067 auto const startBalance = XRP(1000000);
+
1068 auto const gw = Account{"gateway"};
+
1069 auto const alice = Account{"alice"};
+
1070 auto const USD = gw["USD"];
1071
-
1072 using namespace jtx;
+
1072 Env env{*this, features};
1073
-
1074 auto const startBalance = XRP(1000000);
-
1075 auto const gw = Account{"gateway"};
-
1076 auto const alice = Account{"alice"};
-
1077 auto const USD = gw["USD"];
-
1078
-
1079 Env env{*this, features};
-
1080
-
1081 env.fund(startBalance, gw, alice);
-
1082 env.close();
+
1074 env.fund(startBalance, gw, alice);
+
1075 env.close();
+
1076
+
1077 // Order that has invalid flags
+
1078 env(offer(alice, USD(1000), XRP(1000)),
+ + +
1081 env.require(
+
1082 balance(alice, startBalance), owners(alice, 0), offers(alice, 0));
1083
-
1084 // Order that has invalid flags
+
1084 // Order with incompatible flags
1085 env(offer(alice, USD(1000), XRP(1000)),
- +
1088 env.require(
1089 balance(alice, startBalance), owners(alice, 0), offers(alice, 0));
1090
-
1091 // Order with incompatible flags
-
1092 env(offer(alice, USD(1000), XRP(1000)),
- - -
1095 env.require(
-
1096 balance(alice, startBalance), owners(alice, 0), offers(alice, 0));
-
1097
-
1098 // Sell and buy the same asset
-
1099 {
-
1100 // Alice tries an XRP to XRP order:
-
1101 env(offer(alice, XRP(1000), XRP(1000)), ter(temBAD_OFFER));
-
1102 env.require(owners(alice, 0), offers(alice, 0));
+
1091 // Sell and buy the same asset
+
1092 {
+
1093 // Alice tries an XRP to XRP order:
+
1094 env(offer(alice, XRP(1000), XRP(1000)), ter(temBAD_OFFER));
+
1095 env.require(owners(alice, 0), offers(alice, 0));
+
1096
+
1097 // Alice tries an IOU to IOU order:
+
1098 env(trust(alice, USD(1000)), ter(tesSUCCESS));
+
1099 env(pay(gw, alice, USD(1000)), ter(tesSUCCESS));
+
1100 env(offer(alice, USD(1000), USD(1000)), ter(temREDUNDANT));
+
1101 env.require(owners(alice, 1), offers(alice, 0));
+
1102 }
1103
-
1104 // Alice tries an IOU to IOU order:
-
1105 env(trust(alice, USD(1000)), ter(tesSUCCESS));
-
1106 env(pay(gw, alice, USD(1000)), ter(tesSUCCESS));
-
1107 env(offer(alice, USD(1000), USD(1000)), ter(temREDUNDANT));
-
1108 env.require(owners(alice, 1), offers(alice, 0));
-
1109 }
-
1110
-
1111 // Offers with negative amounts
-
1112 {
-
1113 env(offer(alice, -USD(1000), XRP(1000)), ter(temBAD_OFFER));
-
1114 env.require(owners(alice, 1), offers(alice, 0));
-
1115
-
1116 env(offer(alice, USD(1000), -XRP(1000)), ter(temBAD_OFFER));
-
1117 env.require(owners(alice, 1), offers(alice, 0));
-
1118 }
-
1119
-
1120 // Offer with a bad expiration
-
1121 {
-
1122 env(offer(alice, USD(1000), XRP(1000)),
-
1123 json(sfExpiration.fieldName, std::uint32_t(0)),
- -
1125 env.require(owners(alice, 1), offers(alice, 0));
-
1126 }
-
1127
-
1128 // Offer with a bad offer sequence
-
1129 {
-
1130 env(offer(alice, USD(1000), XRP(1000)),
-
1131 json(jss::OfferSequence, std::uint32_t(0)),
- -
1133 env.require(owners(alice, 1), offers(alice, 0));
-
1134 }
-
1135
-
1136 // Use XRP as a currency code
-
1137 {
-
1138 auto const BAD = IOU(gw, badCurrency());
-
1139
-
1140 env(offer(alice, XRP(1000), BAD(1000)), ter(temBAD_CURRENCY));
-
1141 env.require(owners(alice, 1), offers(alice, 0));
-
1142 }
-
1143 }
+
1104 // Offers with negative amounts
+
1105 {
+
1106 env(offer(alice, -USD(1000), XRP(1000)), ter(temBAD_OFFER));
+
1107 env.require(owners(alice, 1), offers(alice, 0));
+
1108
+
1109 env(offer(alice, USD(1000), -XRP(1000)), ter(temBAD_OFFER));
+
1110 env.require(owners(alice, 1), offers(alice, 0));
+
1111 }
+
1112
+
1113 // Offer with a bad expiration
+
1114 {
+
1115 env(offer(alice, USD(1000), XRP(1000)),
+
1116 json(sfExpiration.fieldName, std::uint32_t(0)),
+ +
1118 env.require(owners(alice, 1), offers(alice, 0));
+
1119 }
+
1120
+
1121 // Offer with a bad offer sequence
+
1122 {
+
1123 env(offer(alice, USD(1000), XRP(1000)),
+
1124 json(jss::OfferSequence, std::uint32_t(0)),
+ +
1126 env.require(owners(alice, 1), offers(alice, 0));
+
1127 }
+
1128
+
1129 // Use XRP as a currency code
+
1130 {
+
1131 auto const BAD = IOU(gw, badCurrency());
+
1132
+
1133 env(offer(alice, XRP(1000), BAD(1000)), ter(temBAD_CURRENCY));
+
1134 env.require(owners(alice, 1), offers(alice, 0));
+
1135 }
+
1136 }
+
1137
+
1138 void
+
+ +
1140 {
+
1141 testcase("Offer Expiration");
+
1142
+
1143 using namespace jtx;
1144
-
1145 void
-
- -
1147 {
-
1148 testcase("Offer Expiration");
+
1145 auto const gw = Account{"gateway"};
+
1146 auto const alice = Account{"alice"};
+
1147 auto const bob = Account{"bob"};
+
1148 auto const USD = gw["USD"];
1149
-
1150 using namespace jtx;
-
1151
-
1152 auto const gw = Account{"gateway"};
-
1153 auto const alice = Account{"alice"};
-
1154 auto const bob = Account{"bob"};
-
1155 auto const USD = gw["USD"];
-
1156
-
1157 auto const startBalance = XRP(1000000);
-
1158 auto const usdOffer = USD(1000);
-
1159 auto const xrpOffer = XRP(1000);
+
1150 auto const startBalance = XRP(1000000);
+
1151 auto const usdOffer = USD(1000);
+
1152 auto const xrpOffer = XRP(1000);
+
1153
+
1154 Env env{*this, features};
+
1155
+
1156 env.fund(startBalance, gw, alice, bob);
+
1157 env.close();
+
1158
+
1159 auto const f = env.current()->fees().base;
1160
-
1161 Env env{*this, features};
-
1162
-
1163 env.fund(startBalance, gw, alice, bob);
-
1164 env.close();
-
1165
-
1166 auto const f = env.current()->fees().base;
-
1167
-
1168 env(trust(alice, usdOffer), ter(tesSUCCESS));
-
1169 env(pay(gw, alice, usdOffer), ter(tesSUCCESS));
-
1170 env.close();
-
1171 env.require(
-
1172 balance(alice, startBalance - f),
-
1173 balance(alice, usdOffer),
-
1174 offers(alice, 0),
-
1175 owners(alice, 1));
-
1176
-
1177 // Place an offer that should have already expired.
-
1178 // The DepositPreauth amendment changes the return code; adapt to that.
-
1179 bool const featPreauth{features[featureDepositPreauth]};
-
1180
-
1181 env(offer(alice, xrpOffer, usdOffer),
-
1182 json(sfExpiration.fieldName, lastClose(env)),
-
1183 ter(featPreauth ? TER{tecEXPIRED} : TER{tesSUCCESS}));
+
1161 env(trust(alice, usdOffer), ter(tesSUCCESS));
+
1162 env(pay(gw, alice, usdOffer), ter(tesSUCCESS));
+
1163 env.close();
+
1164 env.require(
+
1165 balance(alice, startBalance - f),
+
1166 balance(alice, usdOffer),
+
1167 offers(alice, 0),
+
1168 owners(alice, 1));
+
1169
+
1170 // Place an offer that should have already expired.
+
1171 // The DepositPreauth amendment changes the return code; adapt to that.
+
1172 bool const featPreauth{features[featureDepositPreauth]};
+
1173
+
1174 env(offer(alice, xrpOffer, usdOffer),
+
1175 json(sfExpiration.fieldName, lastClose(env)),
+
1176 ter(featPreauth ? TER{tecEXPIRED} : TER{tesSUCCESS}));
+
1177
+
1178 env.require(
+
1179 balance(alice, startBalance - f - f),
+
1180 balance(alice, usdOffer),
+
1181 offers(alice, 0),
+
1182 owners(alice, 1));
+
1183 env.close();
1184
-
1185 env.require(
-
1186 balance(alice, startBalance - f - f),
-
1187 balance(alice, usdOffer),
-
1188 offers(alice, 0),
-
1189 owners(alice, 1));
-
1190 env.close();
-
1191
-
1192 // Add an offer that expires before the next ledger close
-
1193 env(offer(alice, xrpOffer, usdOffer),
-
1194 json(sfExpiration.fieldName, lastClose(env) + 1),
-
1195 ter(tesSUCCESS));
-
1196 env.require(
-
1197 balance(alice, startBalance - f - f - f),
-
1198 balance(alice, usdOffer),
-
1199 offers(alice, 1),
-
1200 owners(alice, 2));
-
1201
-
1202 // The offer expires (it's not removed yet)
-
1203 env.close();
-
1204 env.require(
-
1205 balance(alice, startBalance - f - f - f),
-
1206 balance(alice, usdOffer),
-
1207 offers(alice, 1),
-
1208 owners(alice, 2));
-
1209
-
1210 // Add offer - the expired offer is removed
-
1211 env(offer(bob, usdOffer, xrpOffer), ter(tesSUCCESS));
-
1212 env.require(
-
1213 balance(alice, startBalance - f - f - f),
-
1214 balance(alice, usdOffer),
-
1215 offers(alice, 0),
-
1216 owners(alice, 1),
-
1217 balance(bob, startBalance - f),
-
1218 balance(bob, USD(none)),
-
1219 offers(bob, 1),
-
1220 owners(bob, 1));
-
1221 }
+
1185 // Add an offer that expires before the next ledger close
+
1186 env(offer(alice, xrpOffer, usdOffer),
+
1187 json(sfExpiration.fieldName, lastClose(env) + 1),
+
1188 ter(tesSUCCESS));
+
1189 env.require(
+
1190 balance(alice, startBalance - f - f - f),
+
1191 balance(alice, usdOffer),
+
1192 offers(alice, 1),
+
1193 owners(alice, 2));
+
1194
+
1195 // The offer expires (it's not removed yet)
+
1196 env.close();
+
1197 env.require(
+
1198 balance(alice, startBalance - f - f - f),
+
1199 balance(alice, usdOffer),
+
1200 offers(alice, 1),
+
1201 owners(alice, 2));
+
1202
+
1203 // Add offer - the expired offer is removed
+
1204 env(offer(bob, usdOffer, xrpOffer), ter(tesSUCCESS));
+
1205 env.require(
+
1206 balance(alice, startBalance - f - f - f),
+
1207 balance(alice, usdOffer),
+
1208 offers(alice, 0),
+
1209 owners(alice, 1),
+
1210 balance(bob, startBalance - f),
+
1211 balance(bob, USD(none)),
+
1212 offers(bob, 1),
+
1213 owners(bob, 1));
+
1214 }
+
1215
+
1216 void
+
+ +
1218 {
+
1219 testcase("Unfunded Crossing");
+
1220
+
1221 using namespace jtx;
1222
-
1223 void
-
- -
1225 {
-
1226 testcase("Unfunded Crossing");
-
1227
-
1228 using namespace jtx;
-
1229
-
1230 auto const gw = Account{"gateway"};
-
1231 auto const USD = gw["USD"];
-
1232
-
1233 auto const usdOffer = USD(1000);
-
1234 auto const xrpOffer = XRP(1000);
-
1235
-
1236 Env env{*this, features};
-
1237
-
1238 env.fund(XRP(1000000), gw);
-
1239 env.close();
-
1240
-
1241 // The fee that's charged for transactions
-
1242 auto const f = env.current()->fees().base;
+
1223 auto const gw = Account{"gateway"};
+
1224 auto const USD = gw["USD"];
+
1225
+
1226 auto const usdOffer = USD(1000);
+
1227 auto const xrpOffer = XRP(1000);
+
1228
+
1229 Env env{*this, features};
+
1230
+
1231 env.fund(XRP(1000000), gw);
+
1232 env.close();
+
1233
+
1234 // The fee that's charged for transactions
+
1235 auto const f = env.current()->fees().base;
+
1236
+
1237 // Account is at the reserve, and will dip below once
+
1238 // fees are subtracted.
+
1239 env.fund(reserve(env, 0), "alice");
+
1240 env.close();
+
1241 env(offer("alice", usdOffer, xrpOffer), ter(tecUNFUNDED_OFFER));
+
1242 env.require(balance("alice", reserve(env, 0) - f), owners("alice", 0));
1243
-
1244 // Account is at the reserve, and will dip below once
-
1245 // fees are subtracted.
-
1246 env.fund(reserve(env, 0), "alice");
+
1244 // Account has just enough for the reserve and the
+
1245 // fee.
+
1246 env.fund(reserve(env, 0) + f, "bob");
1247 env.close();
-
1248 env(offer("alice", usdOffer, xrpOffer), ter(tecUNFUNDED_OFFER));
-
1249 env.require(balance("alice", reserve(env, 0) - f), owners("alice", 0));
+
1248 env(offer("bob", usdOffer, xrpOffer), ter(tecUNFUNDED_OFFER));
+
1249 env.require(balance("bob", reserve(env, 0)), owners("bob", 0));
1250
-
1251 // Account has just enough for the reserve and the
-
1252 // fee.
-
1253 env.fund(reserve(env, 0) + f, "bob");
-
1254 env.close();
-
1255 env(offer("bob", usdOffer, xrpOffer), ter(tecUNFUNDED_OFFER));
-
1256 env.require(balance("bob", reserve(env, 0)), owners("bob", 0));
-
1257
-
1258 // Account has enough for the reserve, the fee and
-
1259 // the offer, and a bit more, but not enough for the
-
1260 // reserve after the offer is placed.
-
1261 env.fund(reserve(env, 0) + f + XRP(1), "carol");
-
1262 env.close();
-
1263 env(offer("carol", usdOffer, xrpOffer), ter(tecINSUF_RESERVE_OFFER));
-
1264 env.require(
-
1265 balance("carol", reserve(env, 0) + XRP(1)), owners("carol", 0));
+
1251 // Account has enough for the reserve, the fee and
+
1252 // the offer, and a bit more, but not enough for the
+
1253 // reserve after the offer is placed.
+
1254 env.fund(reserve(env, 0) + f + XRP(1), "carol");
+
1255 env.close();
+
1256 env(offer("carol", usdOffer, xrpOffer), ter(tecINSUF_RESERVE_OFFER));
+
1257 env.require(
+
1258 balance("carol", reserve(env, 0) + XRP(1)), owners("carol", 0));
+
1259
+
1260 // Account has enough for the reserve plus one
+
1261 // offer, and the fee.
+
1262 env.fund(reserve(env, 1) + f, "dan");
+
1263 env.close();
+
1264 env(offer("dan", usdOffer, xrpOffer), ter(tesSUCCESS));
+
1265 env.require(balance("dan", reserve(env, 1)), owners("dan", 1));
1266
1267 // Account has enough for the reserve plus one
-
1268 // offer, and the fee.
-
1269 env.fund(reserve(env, 1) + f, "dan");
+
1268 // offer, the fee and the entire offer amount.
+
1269 env.fund(reserve(env, 1) + f + xrpOffer, "eve");
1270 env.close();
-
1271 env(offer("dan", usdOffer, xrpOffer), ter(tesSUCCESS));
-
1272 env.require(balance("dan", reserve(env, 1)), owners("dan", 1));
-
1273
-
1274 // Account has enough for the reserve plus one
-
1275 // offer, the fee and the entire offer amount.
-
1276 env.fund(reserve(env, 1) + f + xrpOffer, "eve");
-
1277 env.close();
-
1278 env(offer("eve", usdOffer, xrpOffer), ter(tesSUCCESS));
-
1279 env.require(
-
1280 balance("eve", reserve(env, 1) + xrpOffer), owners("eve", 1));
-
1281 }
+
1271 env(offer("eve", usdOffer, xrpOffer), ter(tesSUCCESS));
+
1272 env.require(
+
1273 balance("eve", reserve(env, 1) + xrpOffer), owners("eve", 1));
+
1274 }
+
1275
+
1276 void
+
+
1277 testSelfCross(bool use_partner, FeatureBitset features)
+
1278 {
+
1279 testcase(
+
1280 std::string("Self-crossing") +
+
1281 (use_partner ? ", with partner account" : ""));
1282
-
1283 void
-
-
1284 testSelfCross(bool use_partner, FeatureBitset features)
-
1285 {
-
1286 testcase(
-
1287 std::string("Self-crossing") +
-
1288 (use_partner ? ", with partner account" : ""));
+
1283 using namespace jtx;
+
1284
+
1285 auto const gw = Account{"gateway"};
+
1286 auto const partner = Account{"partner"};
+
1287 auto const USD = gw["USD"];
+
1288 auto const BTC = gw["BTC"];
1289
-
1290 using namespace jtx;
-
1291
-
1292 auto const gw = Account{"gateway"};
-
1293 auto const partner = Account{"partner"};
-
1294 auto const USD = gw["USD"];
-
1295 auto const BTC = gw["BTC"];
-
1296
-
1297 Env env{*this, features};
-
1298 env.close();
-
1299
-
1300 env.fund(XRP(10000), gw);
-
1301 if (use_partner)
-
1302 {
-
1303 env.fund(XRP(10000), partner);
-
1304 env.close();
-
1305 env(trust(partner, USD(100)));
-
1306 env(trust(partner, BTC(500)));
-
1307 env.close();
-
1308 env(pay(gw, partner, USD(100)));
-
1309 env(pay(gw, partner, BTC(500)));
-
1310 }
-
1311 auto const& account_to_test = use_partner ? partner : gw;
-
1312
-
1313 env.close();
-
1314 env.require(offers(account_to_test, 0));
-
1315
-
1316 // PART 1:
-
1317 // we will make two offers that can be used to bridge BTC to USD
-
1318 // through XRP
-
1319 env(offer(account_to_test, BTC(250), XRP(1000)));
-
1320 env.require(offers(account_to_test, 1));
+
1290 Env env{*this, features};
+
1291 env.close();
+
1292
+
1293 env.fund(XRP(10000), gw);
+
1294 if (use_partner)
+
1295 {
+
1296 env.fund(XRP(10000), partner);
+
1297 env.close();
+
1298 env(trust(partner, USD(100)));
+
1299 env(trust(partner, BTC(500)));
+
1300 env.close();
+
1301 env(pay(gw, partner, USD(100)));
+
1302 env(pay(gw, partner, BTC(500)));
+
1303 }
+
1304 auto const& account_to_test = use_partner ? partner : gw;
+
1305
+
1306 env.close();
+
1307 env.require(offers(account_to_test, 0));
+
1308
+
1309 // PART 1:
+
1310 // we will make two offers that can be used to bridge BTC to USD
+
1311 // through XRP
+
1312 env(offer(account_to_test, BTC(250), XRP(1000)));
+
1313 env.require(offers(account_to_test, 1));
+
1314
+
1315 // validate that the book now shows a BTC for XRP offer
+
1316 BEAST_EXPECT(isOffer(env, account_to_test, BTC(250), XRP(1000)));
+
1317
+
1318 auto const secondLegSeq = env.seq(account_to_test);
+
1319 env(offer(account_to_test, XRP(1000), USD(50)));
+
1320 env.require(offers(account_to_test, 2));
1321
-
1322 // validate that the book now shows a BTC for XRP offer
-
1323 BEAST_EXPECT(isOffer(env, account_to_test, BTC(250), XRP(1000)));
+
1322 // validate that the book also shows a XRP for USD offer
+
1323 BEAST_EXPECT(isOffer(env, account_to_test, XRP(1000), USD(50)));
1324
-
1325 auto const secondLegSeq = env.seq(account_to_test);
-
1326 env(offer(account_to_test, XRP(1000), USD(50)));
-
1327 env.require(offers(account_to_test, 2));
+
1325 // now make an offer that will cross and auto-bridge, meaning
+
1326 // the outstanding offers will be taken leaving us with none
+
1327 env(offer(account_to_test, USD(50), BTC(250)));
1328
-
1329 // validate that the book also shows a XRP for USD offer
-
1330 BEAST_EXPECT(isOffer(env, account_to_test, XRP(1000), USD(50)));
-
1331
-
1332 // now make an offer that will cross and auto-bridge, meaning
-
1333 // the outstanding offers will be taken leaving us with none
-
1334 env(offer(account_to_test, USD(50), BTC(250)));
-
1335
-
1336 auto jrr = getBookOffers(env, USD, BTC);
-
1337 BEAST_EXPECT(jrr[jss::offers].isArray());
-
1338 BEAST_EXPECT(jrr[jss::offers].size() == 0);
-
1339
-
1340 jrr = getBookOffers(env, BTC, XRP);
-
1341 BEAST_EXPECT(jrr[jss::offers].isArray());
-
1342 BEAST_EXPECT(jrr[jss::offers].size() == 0);
-
1343
-
1344 // NOTE :
-
1345 // At this point, all offers are expected to be consumed.
-
1346 {
-
1347 auto acctOffers = offersOnAccount(env, account_to_test);
-
1348
-
1349 BEAST_EXPECT(acctOffers.size() == 0);
-
1350 for (auto const& offerPtr : acctOffers)
-
1351 {
-
1352 auto const& offer = *offerPtr;
-
1353 BEAST_EXPECT(offer[sfLedgerEntryType] == ltOFFER);
-
1354 BEAST_EXPECT(offer[sfTakerGets] == USD(0));
-
1355 BEAST_EXPECT(offer[sfTakerPays] == XRP(0));
-
1356 }
-
1357 }
-
1358
-
1359 // cancel that lingering second offer so that it doesn't interfere
-
1360 // with the next set of offers we test. This will not be needed once
-
1361 // the bridging bug is fixed
-
1362 env(offer_cancel(account_to_test, secondLegSeq));
-
1363 env.require(offers(account_to_test, 0));
-
1364
-
1365 // PART 2:
-
1366 // simple direct crossing BTC to USD and then USD to BTC which causes
-
1367 // the first offer to be replaced
-
1368 env(offer(account_to_test, BTC(250), USD(50)));
-
1369 env.require(offers(account_to_test, 1));
-
1370
-
1371 // validate that the book shows one BTC for USD offer and no USD for
-
1372 // BTC offers
-
1373 BEAST_EXPECT(isOffer(env, account_to_test, BTC(250), USD(50)));
-
1374
-
1375 jrr = getBookOffers(env, USD, BTC);
-
1376 BEAST_EXPECT(jrr[jss::offers].isArray());
-
1377 BEAST_EXPECT(jrr[jss::offers].size() == 0);
-
1378
-
1379 // this second offer would self-cross directly, so it causes the first
-
1380 // offer by the same owner/taker to be removed
-
1381 env(offer(account_to_test, USD(50), BTC(250)));
-
1382 env.require(offers(account_to_test, 1));
-
1383
-
1384 // validate that we now have just the second offer...the first
-
1385 // was removed
-
1386 jrr = getBookOffers(env, BTC, USD);
-
1387 BEAST_EXPECT(jrr[jss::offers].isArray());
-
1388 BEAST_EXPECT(jrr[jss::offers].size() == 0);
-
1389
-
1390 BEAST_EXPECT(isOffer(env, account_to_test, USD(50), BTC(250)));
-
1391 }
+
1329 auto jrr = getBookOffers(env, USD, BTC);
+
1330 BEAST_EXPECT(jrr[jss::offers].isArray());
+
1331 BEAST_EXPECT(jrr[jss::offers].size() == 0);
+
1332
+
1333 jrr = getBookOffers(env, BTC, XRP);
+
1334 BEAST_EXPECT(jrr[jss::offers].isArray());
+
1335 BEAST_EXPECT(jrr[jss::offers].size() == 0);
+
1336
+
1337 // NOTE :
+
1338 // At this point, all offers are expected to be consumed.
+
1339 {
+
1340 auto acctOffers = offersOnAccount(env, account_to_test);
+
1341
+
1342 BEAST_EXPECT(acctOffers.size() == 0);
+
1343 for (auto const& offerPtr : acctOffers)
+
1344 {
+
1345 auto const& offer = *offerPtr;
+
1346 BEAST_EXPECT(offer[sfLedgerEntryType] == ltOFFER);
+
1347 BEAST_EXPECT(offer[sfTakerGets] == USD(0));
+
1348 BEAST_EXPECT(offer[sfTakerPays] == XRP(0));
+
1349 }
+
1350 }
+
1351
+
1352 // cancel that lingering second offer so that it doesn't interfere
+
1353 // with the next set of offers we test. This will not be needed once
+
1354 // the bridging bug is fixed
+
1355 env(offer_cancel(account_to_test, secondLegSeq));
+
1356 env.require(offers(account_to_test, 0));
+
1357
+
1358 // PART 2:
+
1359 // simple direct crossing BTC to USD and then USD to BTC which causes
+
1360 // the first offer to be replaced
+
1361 env(offer(account_to_test, BTC(250), USD(50)));
+
1362 env.require(offers(account_to_test, 1));
+
1363
+
1364 // validate that the book shows one BTC for USD offer and no USD for
+
1365 // BTC offers
+
1366 BEAST_EXPECT(isOffer(env, account_to_test, BTC(250), USD(50)));
+
1367
+
1368 jrr = getBookOffers(env, USD, BTC);
+
1369 BEAST_EXPECT(jrr[jss::offers].isArray());
+
1370 BEAST_EXPECT(jrr[jss::offers].size() == 0);
+
1371
+
1372 // this second offer would self-cross directly, so it causes the first
+
1373 // offer by the same owner/taker to be removed
+
1374 env(offer(account_to_test, USD(50), BTC(250)));
+
1375 env.require(offers(account_to_test, 1));
+
1376
+
1377 // validate that we now have just the second offer...the first
+
1378 // was removed
+
1379 jrr = getBookOffers(env, BTC, USD);
+
1380 BEAST_EXPECT(jrr[jss::offers].isArray());
+
1381 BEAST_EXPECT(jrr[jss::offers].size() == 0);
+
1382
+
1383 BEAST_EXPECT(isOffer(env, account_to_test, USD(50), BTC(250)));
+
1384 }
+
1385
+
1386 void
+
+ +
1388 {
+
1389 // This test creates an offer test for negative balance
+
1390 // with transfer fees and miniscule funds.
+
1391 testcase("Negative Balance");
1392
-
1393 void
-
- -
1395 {
-
1396 // This test creates an offer test for negative balance
-
1397 // with transfer fees and miniscule funds.
-
1398 testcase("Negative Balance");
-
1399
-
1400 using namespace jtx;
+
1393 using namespace jtx;
+
1394
+
1395 // This is one of the few tests where fixReducedOffersV2 changes the
+
1396 // results. So test both with and without fixReducedOffersV2.
+
1397 for (FeatureBitset localFeatures :
+
1398 {features - fixReducedOffersV2, features | fixReducedOffersV2})
+
1399 {
+
1400 Env env{*this, localFeatures};
1401
-
1402 // This is one of the few tests where fixReducedOffersV2 changes the
-
1403 // results. So test both with and without fixReducedOffersV2.
-
1404 for (FeatureBitset localFeatures :
-
1405 {features - fixReducedOffersV2, features | fixReducedOffersV2})
-
1406 {
-
1407 Env env{*this, localFeatures};
-
1408
-
1409 auto const gw = Account{"gateway"};
-
1410 auto const alice = Account{"alice"};
-
1411 auto const bob = Account{"bob"};
-
1412 auto const USD = gw["USD"];
-
1413 auto const BTC = gw["BTC"];
-
1414
-
1415 // these *interesting* amounts were taken
-
1416 // from the original JS test that was ported here
-
1417 auto const gw_initial_balance = drops(1149999730);
-
1418 auto const alice_initial_balance = drops(499946999680);
-
1419 auto const bob_initial_balance = drops(10199999920);
-
1420 auto const small_amount =
-
1421 STAmount{bob["USD"].issue(), UINT64_C(2710505431213761), -33};
+
1402 auto const gw = Account{"gateway"};
+
1403 auto const alice = Account{"alice"};
+
1404 auto const bob = Account{"bob"};
+
1405 auto const USD = gw["USD"];
+
1406 auto const BTC = gw["BTC"];
+
1407
+
1408 // these *interesting* amounts were taken
+
1409 // from the original JS test that was ported here
+
1410 auto const gw_initial_balance = drops(1149999730);
+
1411 auto const alice_initial_balance = drops(499946999680);
+
1412 auto const bob_initial_balance = drops(10199999920);
+
1413 auto const small_amount =
+
1414 STAmount{bob["USD"].issue(), UINT64_C(2710505431213761), -33};
+
1415
+
1416 env.fund(gw_initial_balance, gw);
+
1417 env.fund(alice_initial_balance, alice);
+
1418 env.fund(bob_initial_balance, bob);
+
1419 env.close();
+
1420
+
1421 env(rate(gw, 1.005));
1422
-
1423 env.fund(gw_initial_balance, gw);
-
1424 env.fund(alice_initial_balance, alice);
-
1425 env.fund(bob_initial_balance, bob);
-
1426 env.close();
-
1427
-
1428 env(rate(gw, 1.005));
+
1423 env(trust(alice, USD(500)));
+
1424 env(trust(bob, USD(50)));
+
1425 env(trust(gw, alice["USD"](100)));
+
1426
+
1427 env(pay(gw, alice, alice["USD"](50)));
+
1428 env(pay(gw, bob, small_amount));
1429
-
1430 env(trust(alice, USD(500)));
-
1431 env(trust(bob, USD(50)));
-
1432 env(trust(gw, alice["USD"](100)));
-
1433
-
1434 env(pay(gw, alice, alice["USD"](50)));
-
1435 env(pay(gw, bob, small_amount));
-
1436
-
1437 env(offer(alice, USD(50), XRP(150000)));
-
1438
-
1439 // unfund the offer
-
1440 env(pay(alice, gw, USD(100)));
-
1441
-
1442 // drop the trust line (set to 0)
-
1443 env(trust(gw, alice["USD"](0)));
-
1444
-
1445 // verify balances
-
1446 auto jrr = ledgerEntryState(env, alice, gw, "USD");
-
1447 BEAST_EXPECT(
-
1448 jrr[jss::node][sfBalance.fieldName][jss::value] == "50");
-
1449
-
1450 jrr = ledgerEntryState(env, bob, gw, "USD");
-
1451 BEAST_EXPECT(
-
1452 jrr[jss::node][sfBalance.fieldName][jss::value] ==
-
1453 "-2710505431213761e-33");
-
1454
-
1455 // create crossing offer
-
1456 std::uint32_t const bobOfferSeq = env.seq(bob);
-
1457 env(offer(bob, XRP(2000), USD(1)));
-
1458
-
1459 if (localFeatures[fixReducedOffersV2])
-
1460 {
-
1461 // With the rounding introduced by fixReducedOffersV2, bob's
-
1462 // offer does not cross alice's offer and goes straight into
-
1463 // the ledger.
-
1464 jrr = ledgerEntryState(env, bob, gw, "USD");
-
1465 BEAST_EXPECT(
-
1466 jrr[jss::node][sfBalance.fieldName][jss::value] ==
-
1467 "-2710505431213761e-33");
+
1430 env(offer(alice, USD(50), XRP(150000)));
+
1431
+
1432 // unfund the offer
+
1433 env(pay(alice, gw, USD(100)));
+
1434
+
1435 // drop the trust line (set to 0)
+
1436 env(trust(gw, alice["USD"](0)));
+
1437
+
1438 // verify balances
+
1439 auto jrr = ledgerEntryState(env, alice, gw, "USD");
+
1440 BEAST_EXPECT(
+
1441 jrr[jss::node][sfBalance.fieldName][jss::value] == "50");
+
1442
+
1443 jrr = ledgerEntryState(env, bob, gw, "USD");
+
1444 BEAST_EXPECT(
+
1445 jrr[jss::node][sfBalance.fieldName][jss::value] ==
+
1446 "-2710505431213761e-33");
+
1447
+
1448 // create crossing offer
+
1449 std::uint32_t const bobOfferSeq = env.seq(bob);
+
1450 env(offer(bob, XRP(2000), USD(1)));
+
1451
+
1452 if (localFeatures[fixReducedOffersV2])
+
1453 {
+
1454 // With the rounding introduced by fixReducedOffersV2, bob's
+
1455 // offer does not cross alice's offer and goes straight into
+
1456 // the ledger.
+
1457 jrr = ledgerEntryState(env, bob, gw, "USD");
+
1458 BEAST_EXPECT(
+
1459 jrr[jss::node][sfBalance.fieldName][jss::value] ==
+
1460 "-2710505431213761e-33");
+
1461
+
1462 Json::Value const bobOffer =
+
1463 ledgerEntryOffer(env, bob, bobOfferSeq)[jss::node];
+
1464 BEAST_EXPECT(bobOffer[sfTakerGets.jsonName][jss::value] == "1");
+
1465 BEAST_EXPECT(bobOffer[sfTakerPays.jsonName] == "2000000000");
+
1466 return;
+
1467 }
1468
-
1469 Json::Value const bobOffer =
-
1470 ledgerEntryOffer(env, bob, bobOfferSeq)[jss::node];
-
1471 BEAST_EXPECT(bobOffer[sfTakerGets.jsonName][jss::value] == "1");
-
1472 BEAST_EXPECT(bobOffer[sfTakerPays.jsonName] == "2000000000");
-
1473 return;
-
1474 }
-
1475
-
1476 // verify balances again.
-
1477 //
-
1478 // NOTE:
-
1479 // Here a difference in the rounding modes of our two offer
-
1480 // crossing algorithms becomes apparent. The old offer crossing
-
1481 // would consume small_amount and transfer no XRP. The new offer
-
1482 // crossing transfers a single drop, rather than no drops.
-
1483 auto const crossingDelta = drops(1);
-
1484
-
1485 jrr = ledgerEntryState(env, alice, gw, "USD");
-
1486 BEAST_EXPECT(
-
1487 jrr[jss::node][sfBalance.fieldName][jss::value] == "50");
-
1488 BEAST_EXPECT(
-
1489 env.balance(alice, xrpIssue()) ==
-
1490 alice_initial_balance - env.current()->fees().base * 3 -
-
1491 crossingDelta);
-
1492
-
1493 jrr = ledgerEntryState(env, bob, gw, "USD");
-
1494 BEAST_EXPECT(
-
1495 jrr[jss::node][sfBalance.fieldName][jss::value] == "0");
-
1496 BEAST_EXPECT(
-
1497 env.balance(bob, xrpIssue()) ==
-
1498 bob_initial_balance - env.current()->fees().base * 2 +
-
1499 crossingDelta);
-
1500 }
-
1501 }
+
1469 // verify balances again.
+
1470 //
+
1471 // NOTE:
+
1472 // Here a difference in the rounding modes of our two offer
+
1473 // crossing algorithms becomes apparent. The old offer crossing
+
1474 // would consume small_amount and transfer no XRP. The new offer
+
1475 // crossing transfers a single drop, rather than no drops.
+
1476 auto const crossingDelta = drops(1);
+
1477
+
1478 jrr = ledgerEntryState(env, alice, gw, "USD");
+
1479 BEAST_EXPECT(
+
1480 jrr[jss::node][sfBalance.fieldName][jss::value] == "50");
+
1481 BEAST_EXPECT(
+
1482 env.balance(alice, xrpIssue()) ==
+
1483 alice_initial_balance - env.current()->fees().base * 3 -
+
1484 crossingDelta);
+
1485
+
1486 jrr = ledgerEntryState(env, bob, gw, "USD");
+
1487 BEAST_EXPECT(
+
1488 jrr[jss::node][sfBalance.fieldName][jss::value] == "0");
+
1489 BEAST_EXPECT(
+
1490 env.balance(bob, xrpIssue()) ==
+
1491 bob_initial_balance - env.current()->fees().base * 2 +
+
1492 crossingDelta);
+
1493 }
+
1494 }
+
1495
+
1496 void
+
+
1497 testOfferCrossWithXRP(bool reverse_order, FeatureBitset features)
+
1498 {
+
1499 testcase(
+
1500 std::string("Offer Crossing with XRP, ") +
+
1501 (reverse_order ? "Reverse" : "Normal") + " order");
1502
-
1503 void
-
-
1504 testOfferCrossWithXRP(bool reverse_order, FeatureBitset features)
-
1505 {
-
1506 testcase(
-
1507 std::string("Offer Crossing with XRP, ") +
-
1508 (reverse_order ? "Reverse" : "Normal") + " order");
-
1509
-
1510 using namespace jtx;
+
1503 using namespace jtx;
+
1504
+
1505 Env env{*this, features};
+
1506
+
1507 auto const gw = Account{"gateway"};
+
1508 auto const alice = Account{"alice"};
+
1509 auto const bob = Account{"bob"};
+
1510 auto const USD = gw["USD"];
1511
-
1512 Env env{*this, features};
-
1513
-
1514 auto const gw = Account{"gateway"};
-
1515 auto const alice = Account{"alice"};
-
1516 auto const bob = Account{"bob"};
-
1517 auto const USD = gw["USD"];
-
1518
-
1519 env.fund(XRP(10000), gw, alice, bob);
-
1520 env.close();
-
1521
-
1522 env(trust(alice, USD(1000)));
-
1523 env(trust(bob, USD(1000)));
+
1512 env.fund(XRP(10000), gw, alice, bob);
+
1513 env.close();
+
1514
+
1515 env(trust(alice, USD(1000)));
+
1516 env(trust(bob, USD(1000)));
+
1517
+
1518 env(pay(gw, alice, alice["USD"](500)));
+
1519
+
1520 if (reverse_order)
+
1521 env(offer(bob, USD(1), XRP(4000)));
+
1522
+
1523 env(offer(alice, XRP(150000), USD(50)));
1524
-
1525 env(pay(gw, alice, alice["USD"](500)));
-
1526
-
1527 if (reverse_order)
-
1528 env(offer(bob, USD(1), XRP(4000)));
-
1529
-
1530 env(offer(alice, XRP(150000), USD(50)));
+
1525 if (!reverse_order)
+
1526 env(offer(bob, USD(1), XRP(4000)));
+
1527
+
1528 // Existing offer pays better than this wants.
+
1529 // Fully consume existing offer.
+
1530 // Pay 1 USD, get 4000 XRP.
1531
-
1532 if (!reverse_order)
-
1533 env(offer(bob, USD(1), XRP(4000)));
-
1534
-
1535 // Existing offer pays better than this wants.
-
1536 // Fully consume existing offer.
-
1537 // Pay 1 USD, get 4000 XRP.
-
1538
-
1539 auto jrr = ledgerEntryState(env, bob, gw, "USD");
-
1540 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-1");
-
1541 jrr = ledgerEntryRoot(env, bob);
-
1542 BEAST_EXPECT(
-
1543 jrr[jss::node][sfBalance.fieldName] ==
-
1544 to_string((XRP(10000) - XRP(reverse_order ? 4000 : 3000) -
-
1545 env.current()->fees().base * 2)
-
1546 .xrp()));
-
1547
-
1548 jrr = ledgerEntryState(env, alice, gw, "USD");
-
1549 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-499");
-
1550 jrr = ledgerEntryRoot(env, alice);
-
1551 BEAST_EXPECT(
-
1552 jrr[jss::node][sfBalance.fieldName] ==
-
1553 to_string((XRP(10000) + XRP(reverse_order ? 4000 : 3000) -
-
1554 env.current()->fees().base * 2)
-
1555 .xrp()));
-
1556 }
+
1532 auto jrr = ledgerEntryState(env, bob, gw, "USD");
+
1533 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-1");
+
1534 jrr = ledgerEntryRoot(env, bob);
+
1535 BEAST_EXPECT(
+
1536 jrr[jss::node][sfBalance.fieldName] ==
+
1537 to_string((XRP(10000) - XRP(reverse_order ? 4000 : 3000) -
+
1538 env.current()->fees().base * 2)
+
1539 .xrp()));
+
1540
+
1541 jrr = ledgerEntryState(env, alice, gw, "USD");
+
1542 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-499");
+
1543 jrr = ledgerEntryRoot(env, alice);
+
1544 BEAST_EXPECT(
+
1545 jrr[jss::node][sfBalance.fieldName] ==
+
1546 to_string((XRP(10000) + XRP(reverse_order ? 4000 : 3000) -
+
1547 env.current()->fees().base * 2)
+
1548 .xrp()));
+
1549 }
+
1550
+
1551 void
+
+ +
1553 {
+
1554 testcase("Offer Crossing with Limit Override");
+
1555
+
1556 using namespace jtx;
1557
-
1558 void
-
- -
1560 {
-
1561 testcase("Offer Crossing with Limit Override");
-
1562
-
1563 using namespace jtx;
+
1558 Env env{*this, features};
+
1559
+
1560 auto const gw = Account{"gateway"};
+
1561 auto const alice = Account{"alice"};
+
1562 auto const bob = Account{"bob"};
+
1563 auto const USD = gw["USD"];
1564
-
1565 Env env{*this, features};
-
1566
-
1567 auto const gw = Account{"gateway"};
-
1568 auto const alice = Account{"alice"};
-
1569 auto const bob = Account{"bob"};
-
1570 auto const USD = gw["USD"];
+
1565 env.fund(XRP(100000), gw, alice, bob);
+
1566 env.close();
+
1567
+
1568 env(trust(alice, USD(1000)));
+
1569
+
1570 env(pay(gw, alice, alice["USD"](500)));
1571
-
1572 env.fund(XRP(100000), gw, alice, bob);
-
1573 env.close();
+
1572 env(offer(alice, XRP(150000), USD(50)));
+
1573 env(offer(bob, USD(1), XRP(3000)));
1574
-
1575 env(trust(alice, USD(1000)));
-
1576
-
1577 env(pay(gw, alice, alice["USD"](500)));
-
1578
-
1579 env(offer(alice, XRP(150000), USD(50)));
-
1580 env(offer(bob, USD(1), XRP(3000)));
-
1581
-
1582 auto jrr = ledgerEntryState(env, bob, gw, "USD");
-
1583 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-1");
-
1584 jrr = ledgerEntryRoot(env, bob);
-
1585 BEAST_EXPECT(
-
1586 jrr[jss::node][sfBalance.fieldName] ==
-
1587 to_string((XRP(100000) - XRP(3000) - env.current()->fees().base * 1)
-
1588 .xrp()));
-
1589
-
1590 jrr = ledgerEntryState(env, alice, gw, "USD");
-
1591 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-499");
-
1592 jrr = ledgerEntryRoot(env, alice);
-
1593 BEAST_EXPECT(
-
1594 jrr[jss::node][sfBalance.fieldName] ==
-
1595 to_string((XRP(100000) + XRP(3000) - env.current()->fees().base * 2)
-
1596 .xrp()));
-
1597 }
+
1575 auto jrr = ledgerEntryState(env, bob, gw, "USD");
+
1576 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-1");
+
1577 jrr = ledgerEntryRoot(env, bob);
+
1578 BEAST_EXPECT(
+
1579 jrr[jss::node][sfBalance.fieldName] ==
+
1580 to_string((XRP(100000) - XRP(3000) - env.current()->fees().base * 1)
+
1581 .xrp()));
+
1582
+
1583 jrr = ledgerEntryState(env, alice, gw, "USD");
+
1584 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-499");
+
1585 jrr = ledgerEntryRoot(env, alice);
+
1586 BEAST_EXPECT(
+
1587 jrr[jss::node][sfBalance.fieldName] ==
+
1588 to_string((XRP(100000) + XRP(3000) - env.current()->fees().base * 2)
+
1589 .xrp()));
+
1590 }
+
1591
+
1592 void
+
+ +
1594 {
+
1595 testcase("Offer Accept then Cancel.");
+
1596
+
1597 using namespace jtx;
1598
-
1599 void
-
- -
1601 {
-
1602 testcase("Offer Accept then Cancel.");
-
1603
-
1604 using namespace jtx;
-
1605
-
1606 Env env{*this, features};
-
1607
-
1608 auto const USD = env.master["USD"];
+
1599 Env env{*this, features};
+
1600
+
1601 auto const USD = env.master["USD"];
+
1602
+
1603 auto const nextOfferSeq = env.seq(env.master);
+
1604 env(offer(env.master, XRP(500), USD(100)));
+
1605 env.close();
+
1606
+
1607 env(offer_cancel(env.master, nextOfferSeq));
+
1608 BEAST_EXPECT(env.seq(env.master) == nextOfferSeq + 2);
1609
-
1610 auto const nextOfferSeq = env.seq(env.master);
-
1611 env(offer(env.master, XRP(500), USD(100)));
+
1610 // ledger_accept, call twice and verify no odd behavior
+
1611 env.close();
1612 env.close();
-
1613
-
1614 env(offer_cancel(env.master, nextOfferSeq));
-
1615 BEAST_EXPECT(env.seq(env.master) == nextOfferSeq + 2);
-
1616
-
1617 // ledger_accept, call twice and verify no odd behavior
-
1618 env.close();
-
1619 env.close();
-
1620 BEAST_EXPECT(env.seq(env.master) == nextOfferSeq + 2);
-
1621 }
+
1613 BEAST_EXPECT(env.seq(env.master) == nextOfferSeq + 2);
+
1614 }
+
1615
+
1616 void
+
+ +
1618 {
+
1619 testcase("Offer Cancel Past and Future Sequence.");
+
1620
+
1621 using namespace jtx;
1622
-
1623 void
-
- -
1625 {
-
1626 testcase("Offer Cancel Past and Future Sequence.");
-
1627
-
1628 using namespace jtx;
-
1629
-
1630 Env env{*this, features};
-
1631
-
1632 auto const alice = Account{"alice"};
-
1633
-
1634 auto const nextOfferSeq = env.seq(env.master);
-
1635 env.fund(XRP(10000), alice);
-
1636 env.close();
-
1637
-
1638 env(offer_cancel(env.master, nextOfferSeq));
-
1639
-
1640 env(offer_cancel(env.master, env.seq(env.master)),
- -
1642
-
1643 env(offer_cancel(env.master, env.seq(env.master) + 1),
- -
1645
-
1646 env.close();
-
1647 }
+
1623 Env env{*this, features};
+
1624
+
1625 auto const alice = Account{"alice"};
+
1626
+
1627 auto const nextOfferSeq = env.seq(env.master);
+
1628 env.fund(XRP(10000), alice);
+
1629 env.close();
+
1630
+
1631 env(offer_cancel(env.master, nextOfferSeq));
+
1632
+
1633 env(offer_cancel(env.master, env.seq(env.master)),
+ +
1635
+
1636 env(offer_cancel(env.master, env.seq(env.master) + 1),
+ +
1638
+
1639 env.close();
+
1640 }
+
1641
+
1642 void
+
+ +
1644 {
+
1645 testcase("Currency Conversion: Entire Offer");
+
1646
+
1647 using namespace jtx;
1648
-
1649 void
-
- -
1651 {
-
1652 testcase("Currency Conversion: Entire Offer");
-
1653
-
1654 using namespace jtx;
+
1649 Env env{*this, features};
+
1650
+
1651 auto const gw = Account{"gateway"};
+
1652 auto const alice = Account{"alice"};
+
1653 auto const bob = Account{"bob"};
+
1654 auto const USD = gw["USD"];
1655
-
1656 Env env{*this, features};
-
1657
-
1658 auto const gw = Account{"gateway"};
-
1659 auto const alice = Account{"alice"};
-
1660 auto const bob = Account{"bob"};
-
1661 auto const USD = gw["USD"];
+
1656 env.fund(XRP(10000), gw, alice, bob);
+
1657 env.close();
+
1658 env.require(owners(bob, 0));
+
1659
+
1660 env(trust(alice, USD(100)));
+
1661 env(trust(bob, USD(1000)));
1662
-
1663 env.fund(XRP(10000), gw, alice, bob);
-
1664 env.close();
-
1665 env.require(owners(bob, 0));
-
1666
-
1667 env(trust(alice, USD(100)));
-
1668 env(trust(bob, USD(1000)));
-
1669
-
1670 env.require(owners(alice, 1), owners(bob, 1));
-
1671
-
1672 env(pay(gw, alice, alice["USD"](100)));
-
1673 auto const bobOfferSeq = env.seq(bob);
-
1674 env(offer(bob, USD(100), XRP(500)));
-
1675
-
1676 env.require(owners(alice, 1), owners(bob, 2));
-
1677 auto jro = ledgerEntryOffer(env, bob, bobOfferSeq);
-
1678 BEAST_EXPECT(
-
1679 jro[jss::node][jss::TakerGets] == XRP(500).value().getText());
-
1680 BEAST_EXPECT(
-
1681 jro[jss::node][jss::TakerPays] ==
-
1682 USD(100).value().getJson(JsonOptions::none));
-
1683
-
1684 env(pay(alice, alice, XRP(500)), sendmax(USD(100)));
-
1685
-
1686 auto jrr = ledgerEntryState(env, alice, gw, "USD");
-
1687 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "0");
-
1688 jrr = ledgerEntryRoot(env, alice);
-
1689 BEAST_EXPECT(
-
1690 jrr[jss::node][sfBalance.fieldName] ==
-
1691 to_string((XRP(10000) + XRP(500) - env.current()->fees().base * 2)
-
1692 .xrp()));
-
1693
-
1694 jrr = ledgerEntryState(env, bob, gw, "USD");
-
1695 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-100");
-
1696
-
1697 jro = ledgerEntryOffer(env, bob, bobOfferSeq);
-
1698 BEAST_EXPECT(jro[jss::error] == "entryNotFound");
-
1699
-
1700 env.require(owners(alice, 1), owners(bob, 1));
-
1701 }
+
1663 env.require(owners(alice, 1), owners(bob, 1));
+
1664
+
1665 env(pay(gw, alice, alice["USD"](100)));
+
1666 auto const bobOfferSeq = env.seq(bob);
+
1667 env(offer(bob, USD(100), XRP(500)));
+
1668
+
1669 env.require(owners(alice, 1), owners(bob, 2));
+
1670 auto jro = ledgerEntryOffer(env, bob, bobOfferSeq);
+
1671 BEAST_EXPECT(
+
1672 jro[jss::node][jss::TakerGets] == XRP(500).value().getText());
+
1673 BEAST_EXPECT(
+
1674 jro[jss::node][jss::TakerPays] ==
+
1675 USD(100).value().getJson(JsonOptions::none));
+
1676
+
1677 env(pay(alice, alice, XRP(500)), sendmax(USD(100)));
+
1678
+
1679 auto jrr = ledgerEntryState(env, alice, gw, "USD");
+
1680 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "0");
+
1681 jrr = ledgerEntryRoot(env, alice);
+
1682 BEAST_EXPECT(
+
1683 jrr[jss::node][sfBalance.fieldName] ==
+
1684 to_string((XRP(10000) + XRP(500) - env.current()->fees().base * 2)
+
1685 .xrp()));
+
1686
+
1687 jrr = ledgerEntryState(env, bob, gw, "USD");
+
1688 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-100");
+
1689
+
1690 jro = ledgerEntryOffer(env, bob, bobOfferSeq);
+
1691 BEAST_EXPECT(jro[jss::error] == "entryNotFound");
+
1692
+
1693 env.require(owners(alice, 1), owners(bob, 1));
+
1694 }
+
1695
+
1696 void
+
+ +
1698 {
+
1699 testcase("Currency Conversion: Offerer Into Debt");
+
1700
+
1701 using namespace jtx;
1702
-
1703 void
-
- -
1705 {
-
1706 testcase("Currency Conversion: Offerer Into Debt");
-
1707
-
1708 using namespace jtx;
-
1709
-
1710 Env env{*this, features};
+
1703 Env env{*this, features};
+
1704
+
1705 auto const alice = Account{"alice"};
+
1706 auto const bob = Account{"bob"};
+
1707 auto const carol = Account{"carol"};
+
1708
+
1709 env.fund(XRP(10000), alice, bob, carol);
+
1710 env.close();
1711
-
1712 auto const alice = Account{"alice"};
-
1713 auto const bob = Account{"bob"};
-
1714 auto const carol = Account{"carol"};
+
1712 env(trust(alice, carol["EUR"](2000)));
+
1713 env(trust(bob, alice["USD"](100)));
+
1714 env(trust(carol, bob["EUR"](1000)));
1715
-
1716 env.fund(XRP(10000), alice, bob, carol);
-
1717 env.close();
-
1718
-
1719 env(trust(alice, carol["EUR"](2000)));
-
1720 env(trust(bob, alice["USD"](100)));
-
1721 env(trust(carol, bob["EUR"](1000)));
-
1722
-
1723 auto const bobOfferSeq = env.seq(bob);
-
1724 env(offer(bob, alice["USD"](50), carol["EUR"](200)),
- -
1726
-
1727 env(offer(alice, carol["EUR"](200), alice["USD"](50)));
-
1728
-
1729 auto jro = ledgerEntryOffer(env, bob, bobOfferSeq);
-
1730 BEAST_EXPECT(jro[jss::error] == "entryNotFound");
-
1731 }
+
1716 auto const bobOfferSeq = env.seq(bob);
+
1717 env(offer(bob, alice["USD"](50), carol["EUR"](200)),
+ +
1719
+
1720 env(offer(alice, carol["EUR"](200), alice["USD"](50)));
+
1721
+
1722 auto jro = ledgerEntryOffer(env, bob, bobOfferSeq);
+
1723 BEAST_EXPECT(jro[jss::error] == "entryNotFound");
+
1724 }
+
1725
+
1726 void
+
+ +
1728 {
+
1729 testcase("Currency Conversion: In Parts");
+
1730
+
1731 using namespace jtx;
1732
-
1733 void
-
- -
1735 {
-
1736 testcase("Currency Conversion: In Parts");
-
1737
-
1738 using namespace jtx;
+
1733 Env env{*this, features};
+
1734
+
1735 auto const gw = Account{"gateway"};
+
1736 auto const alice = Account{"alice"};
+
1737 auto const bob = Account{"bob"};
+
1738 auto const USD = gw["USD"];
1739
-
1740 Env env{*this, features};
-
1741
-
1742 auto const gw = Account{"gateway"};
-
1743 auto const alice = Account{"alice"};
-
1744 auto const bob = Account{"bob"};
-
1745 auto const USD = gw["USD"];
-
1746
-
1747 env.fund(XRP(10000), gw, alice, bob);
-
1748 env.close();
-
1749
-
1750 env(trust(alice, USD(200)));
-
1751 env(trust(bob, USD(1000)));
+
1740 env.fund(XRP(10000), gw, alice, bob);
+
1741 env.close();
+
1742
+
1743 env(trust(alice, USD(200)));
+
1744 env(trust(bob, USD(1000)));
+
1745
+
1746 env(pay(gw, alice, alice["USD"](200)));
+
1747
+
1748 auto const bobOfferSeq = env.seq(bob);
+
1749 env(offer(bob, USD(100), XRP(500)));
+
1750
+
1751 env(pay(alice, alice, XRP(200)), sendmax(USD(100)));
1752
-
1753 env(pay(gw, alice, alice["USD"](200)));
-
1754
-
1755 auto const bobOfferSeq = env.seq(bob);
-
1756 env(offer(bob, USD(100), XRP(500)));
-
1757
-
1758 env(pay(alice, alice, XRP(200)), sendmax(USD(100)));
-
1759
-
1760 // The previous payment reduced the remaining offer amount by 200 XRP
-
1761 auto jro = ledgerEntryOffer(env, bob, bobOfferSeq);
-
1762 BEAST_EXPECT(
-
1763 jro[jss::node][jss::TakerGets] == XRP(300).value().getText());
-
1764 BEAST_EXPECT(
-
1765 jro[jss::node][jss::TakerPays] ==
-
1766 USD(60).value().getJson(JsonOptions::none));
-
1767
-
1768 // the balance between alice and gw is 160 USD..200 less the 40 taken
-
1769 // by the offer
-
1770 auto jrr = ledgerEntryState(env, alice, gw, "USD");
-
1771 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-160");
-
1772 // alice now has 200 more XRP from the payment
-
1773 jrr = ledgerEntryRoot(env, alice);
-
1774 BEAST_EXPECT(
-
1775 jrr[jss::node][sfBalance.fieldName] ==
-
1776 to_string((XRP(10000) + XRP(200) - env.current()->fees().base * 2)
-
1777 .xrp()));
-
1778
-
1779 // bob got 40 USD from partial consumption of the offer
-
1780 jrr = ledgerEntryState(env, bob, gw, "USD");
-
1781 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-40");
-
1782
-
1783 // Alice converts USD to XRP which should fail
-
1784 // due to PartialPayment.
-
1785 env(pay(alice, alice, XRP(600)),
-
1786 sendmax(USD(100)),
- -
1788
-
1789 // Alice converts USD to XRP, should succeed because
-
1790 // we permit partial payment
-
1791 env(pay(alice, alice, XRP(600)),
-
1792 sendmax(USD(100)),
- -
1794
-
1795 // Verify the offer was consumed
-
1796 jro = ledgerEntryOffer(env, bob, bobOfferSeq);
-
1797 BEAST_EXPECT(jro[jss::error] == "entryNotFound");
-
1798
-
1799 // verify balances look right after the partial payment
-
1800 // only 300 XRP should be have been payed since that's all
-
1801 // that remained in the offer from bob. The alice balance is now
-
1802 // 100 USD because another 60 USD were transferred to bob in the second
-
1803 // payment
-
1804 jrr = ledgerEntryState(env, alice, gw, "USD");
-
1805 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-100");
-
1806 jrr = ledgerEntryRoot(env, alice);
-
1807 BEAST_EXPECT(
-
1808 jrr[jss::node][sfBalance.fieldName] ==
-
1809 to_string((XRP(10000) + XRP(200) + XRP(300) -
-
1810 env.current()->fees().base * 4)
-
1811 .xrp()));
-
1812
-
1813 // bob now has 100 USD - 40 from the first payment and 60 from the
-
1814 // second (partial) payment
-
1815 jrr = ledgerEntryState(env, bob, gw, "USD");
-
1816 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-100");
-
1817 }
+
1753 // The previous payment reduced the remaining offer amount by 200 XRP
+
1754 auto jro = ledgerEntryOffer(env, bob, bobOfferSeq);
+
1755 BEAST_EXPECT(
+
1756 jro[jss::node][jss::TakerGets] == XRP(300).value().getText());
+
1757 BEAST_EXPECT(
+
1758 jro[jss::node][jss::TakerPays] ==
+
1759 USD(60).value().getJson(JsonOptions::none));
+
1760
+
1761 // the balance between alice and gw is 160 USD..200 less the 40 taken
+
1762 // by the offer
+
1763 auto jrr = ledgerEntryState(env, alice, gw, "USD");
+
1764 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-160");
+
1765 // alice now has 200 more XRP from the payment
+
1766 jrr = ledgerEntryRoot(env, alice);
+
1767 BEAST_EXPECT(
+
1768 jrr[jss::node][sfBalance.fieldName] ==
+
1769 to_string((XRP(10000) + XRP(200) - env.current()->fees().base * 2)
+
1770 .xrp()));
+
1771
+
1772 // bob got 40 USD from partial consumption of the offer
+
1773 jrr = ledgerEntryState(env, bob, gw, "USD");
+
1774 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-40");
+
1775
+
1776 // Alice converts USD to XRP which should fail
+
1777 // due to PartialPayment.
+
1778 env(pay(alice, alice, XRP(600)),
+
1779 sendmax(USD(100)),
+ +
1781
+
1782 // Alice converts USD to XRP, should succeed because
+
1783 // we permit partial payment
+
1784 env(pay(alice, alice, XRP(600)),
+
1785 sendmax(USD(100)),
+ +
1787
+
1788 // Verify the offer was consumed
+
1789 jro = ledgerEntryOffer(env, bob, bobOfferSeq);
+
1790 BEAST_EXPECT(jro[jss::error] == "entryNotFound");
+
1791
+
1792 // verify balances look right after the partial payment
+
1793 // only 300 XRP should be have been payed since that's all
+
1794 // that remained in the offer from bob. The alice balance is now
+
1795 // 100 USD because another 60 USD were transferred to bob in the second
+
1796 // payment
+
1797 jrr = ledgerEntryState(env, alice, gw, "USD");
+
1798 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-100");
+
1799 jrr = ledgerEntryRoot(env, alice);
+
1800 BEAST_EXPECT(
+
1801 jrr[jss::node][sfBalance.fieldName] ==
+
1802 to_string((XRP(10000) + XRP(200) + XRP(300) -
+
1803 env.current()->fees().base * 4)
+
1804 .xrp()));
+
1805
+
1806 // bob now has 100 USD - 40 from the first payment and 60 from the
+
1807 // second (partial) payment
+
1808 jrr = ledgerEntryState(env, bob, gw, "USD");
+
1809 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-100");
+
1810 }
+
1811
+
1812 void
+
+ +
1814 {
+
1815 testcase("Cross Currency Payment: Start with XRP");
+
1816
+
1817 using namespace jtx;
1818
-
1819 void
-
- -
1821 {
-
1822 testcase("Cross Currency Payment: Start with XRP");
-
1823
-
1824 using namespace jtx;
-
1825
-
1826 Env env{*this, features};
-
1827
-
1828 auto const gw = Account{"gateway"};
-
1829 auto const alice = Account{"alice"};
-
1830 auto const bob = Account{"bob"};
-
1831 auto const carol = Account{"carol"};
-
1832 auto const USD = gw["USD"];
-
1833
-
1834 env.fund(XRP(10000), gw, alice, bob, carol);
-
1835 env.close();
-
1836
-
1837 env(trust(carol, USD(1000)));
-
1838 env(trust(bob, USD(2000)));
+
1819 Env env{*this, features};
+
1820
+
1821 auto const gw = Account{"gateway"};
+
1822 auto const alice = Account{"alice"};
+
1823 auto const bob = Account{"bob"};
+
1824 auto const carol = Account{"carol"};
+
1825 auto const USD = gw["USD"];
+
1826
+
1827 env.fund(XRP(10000), gw, alice, bob, carol);
+
1828 env.close();
+
1829
+
1830 env(trust(carol, USD(1000)));
+
1831 env(trust(bob, USD(2000)));
+
1832
+
1833 env(pay(gw, carol, carol["USD"](500)));
+
1834
+
1835 auto const carolOfferSeq = env.seq(carol);
+
1836 env(offer(carol, XRP(500), USD(50)));
+
1837
+
1838 env(pay(alice, bob, USD(25)), sendmax(XRP(333)));
1839
-
1840 env(pay(gw, carol, carol["USD"](500)));
-
1841
-
1842 auto const carolOfferSeq = env.seq(carol);
-
1843 env(offer(carol, XRP(500), USD(50)));
-
1844
-
1845 env(pay(alice, bob, USD(25)), sendmax(XRP(333)));
-
1846
-
1847 auto jrr = ledgerEntryState(env, bob, gw, "USD");
-
1848 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-25");
-
1849
-
1850 jrr = ledgerEntryState(env, carol, gw, "USD");
-
1851 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-475");
-
1852
-
1853 auto jro = ledgerEntryOffer(env, carol, carolOfferSeq);
-
1854 BEAST_EXPECT(
-
1855 jro[jss::node][jss::TakerGets] ==
-
1856 USD(25).value().getJson(JsonOptions::none));
-
1857 BEAST_EXPECT(
-
1858 jro[jss::node][jss::TakerPays] == XRP(250).value().getText());
-
1859 }
+
1840 auto jrr = ledgerEntryState(env, bob, gw, "USD");
+
1841 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-25");
+
1842
+
1843 jrr = ledgerEntryState(env, carol, gw, "USD");
+
1844 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-475");
+
1845
+
1846 auto jro = ledgerEntryOffer(env, carol, carolOfferSeq);
+
1847 BEAST_EXPECT(
+
1848 jro[jss::node][jss::TakerGets] ==
+
1849 USD(25).value().getJson(JsonOptions::none));
+
1850 BEAST_EXPECT(
+
1851 jro[jss::node][jss::TakerPays] == XRP(250).value().getText());
+
1852 }
+
1853
+
1854 void
+
+ +
1856 {
+
1857 testcase("Cross Currency Payment: End with XRP");
+
1858
+
1859 using namespace jtx;
1860
-
1861 void
-
- -
1863 {
-
1864 testcase("Cross Currency Payment: End with XRP");
-
1865
-
1866 using namespace jtx;
-
1867
-
1868 Env env{*this, features};
-
1869
-
1870 auto const gw = Account{"gateway"};
-
1871 auto const alice = Account{"alice"};
-
1872 auto const bob = Account{"bob"};
-
1873 auto const carol = Account{"carol"};
-
1874 auto const USD = gw["USD"];
-
1875
-
1876 env.fund(XRP(10000), gw, alice, bob, carol);
-
1877 env.close();
-
1878
-
1879 env(trust(alice, USD(1000)));
-
1880 env(trust(carol, USD(2000)));
+
1861 Env env{*this, features};
+
1862
+
1863 auto const gw = Account{"gateway"};
+
1864 auto const alice = Account{"alice"};
+
1865 auto const bob = Account{"bob"};
+
1866 auto const carol = Account{"carol"};
+
1867 auto const USD = gw["USD"];
+
1868
+
1869 env.fund(XRP(10000), gw, alice, bob, carol);
+
1870 env.close();
+
1871
+
1872 env(trust(alice, USD(1000)));
+
1873 env(trust(carol, USD(2000)));
+
1874
+
1875 env(pay(gw, alice, alice["USD"](500)));
+
1876
+
1877 auto const carolOfferSeq = env.seq(carol);
+
1878 env(offer(carol, USD(50), XRP(500)));
+
1879
+
1880 env(pay(alice, bob, XRP(250)), sendmax(USD(333)));
1881
-
1882 env(pay(gw, alice, alice["USD"](500)));
-
1883
-
1884 auto const carolOfferSeq = env.seq(carol);
-
1885 env(offer(carol, USD(50), XRP(500)));
-
1886
-
1887 env(pay(alice, bob, XRP(250)), sendmax(USD(333)));
-
1888
-
1889 auto jrr = ledgerEntryState(env, alice, gw, "USD");
-
1890 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-475");
-
1891
-
1892 jrr = ledgerEntryState(env, carol, gw, "USD");
-
1893 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-25");
-
1894
-
1895 jrr = ledgerEntryRoot(env, bob);
-
1896 BEAST_EXPECT(
-
1897 jrr[jss::node][sfBalance.fieldName] ==
- -
1899 XRP(10000).value().mantissa() + XRP(250).value().mantissa()));
-
1900
-
1901 auto jro = ledgerEntryOffer(env, carol, carolOfferSeq);
-
1902 BEAST_EXPECT(
-
1903 jro[jss::node][jss::TakerGets] == XRP(250).value().getText());
-
1904 BEAST_EXPECT(
-
1905 jro[jss::node][jss::TakerPays] ==
-
1906 USD(25).value().getJson(JsonOptions::none));
-
1907 }
+
1882 auto jrr = ledgerEntryState(env, alice, gw, "USD");
+
1883 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-475");
+
1884
+
1885 jrr = ledgerEntryState(env, carol, gw, "USD");
+
1886 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-25");
+
1887
+
1888 jrr = ledgerEntryRoot(env, bob);
+
1889 BEAST_EXPECT(
+
1890 jrr[jss::node][sfBalance.fieldName] ==
+ +
1892 XRP(10000).value().mantissa() + XRP(250).value().mantissa()));
+
1893
+
1894 auto jro = ledgerEntryOffer(env, carol, carolOfferSeq);
+
1895 BEAST_EXPECT(
+
1896 jro[jss::node][jss::TakerGets] == XRP(250).value().getText());
+
1897 BEAST_EXPECT(
+
1898 jro[jss::node][jss::TakerPays] ==
+
1899 USD(25).value().getJson(JsonOptions::none));
+
1900 }
+
1901
+
1902 void
+
+ +
1904 {
+
1905 testcase("Cross Currency Payment: Bridged");
+
1906
+
1907 using namespace jtx;
1908
-
1909 void
-
- -
1911 {
-
1912 testcase("Cross Currency Payment: Bridged");
-
1913
-
1914 using namespace jtx;
-
1915
-
1916 Env env{*this, features};
-
1917
-
1918 auto const gw1 = Account{"gateway_1"};
-
1919 auto const gw2 = Account{"gateway_2"};
-
1920 auto const alice = Account{"alice"};
-
1921 auto const bob = Account{"bob"};
-
1922 auto const carol = Account{"carol"};
-
1923 auto const dan = Account{"dan"};
-
1924 auto const USD = gw1["USD"];
-
1925 auto const EUR = gw2["EUR"];
-
1926
-
1927 env.fund(XRP(10000), gw1, gw2, alice, bob, carol, dan);
-
1928 env.close();
-
1929
-
1930 env(trust(alice, USD(1000)));
-
1931 env(trust(bob, EUR(1000)));
-
1932 env(trust(carol, USD(1000)));
-
1933 env(trust(dan, EUR(1000)));
-
1934
-
1935 env(pay(gw1, alice, alice["USD"](500)));
-
1936 env(pay(gw2, dan, dan["EUR"](400)));
-
1937
-
1938 auto const carolOfferSeq = env.seq(carol);
-
1939 env(offer(carol, USD(50), XRP(500)));
+
1909 Env env{*this, features};
+
1910
+
1911 auto const gw1 = Account{"gateway_1"};
+
1912 auto const gw2 = Account{"gateway_2"};
+
1913 auto const alice = Account{"alice"};
+
1914 auto const bob = Account{"bob"};
+
1915 auto const carol = Account{"carol"};
+
1916 auto const dan = Account{"dan"};
+
1917 auto const USD = gw1["USD"];
+
1918 auto const EUR = gw2["EUR"];
+
1919
+
1920 env.fund(XRP(10000), gw1, gw2, alice, bob, carol, dan);
+
1921 env.close();
+
1922
+
1923 env(trust(alice, USD(1000)));
+
1924 env(trust(bob, EUR(1000)));
+
1925 env(trust(carol, USD(1000)));
+
1926 env(trust(dan, EUR(1000)));
+
1927
+
1928 env(pay(gw1, alice, alice["USD"](500)));
+
1929 env(pay(gw2, dan, dan["EUR"](400)));
+
1930
+
1931 auto const carolOfferSeq = env.seq(carol);
+
1932 env(offer(carol, USD(50), XRP(500)));
+
1933
+
1934 auto const danOfferSeq = env.seq(dan);
+
1935 env(offer(dan, XRP(500), EUR(50)));
+
1936
+ +
1938 jtp[0u][0u][jss::currency] = "XRP";
+
1939 env(pay(alice, bob, EUR(30)), json(jss::Paths, jtp), sendmax(USD(333)));
1940
-
1941 auto const danOfferSeq = env.seq(dan);
-
1942 env(offer(dan, XRP(500), EUR(50)));
+
1941 auto jrr = ledgerEntryState(env, alice, gw1, "USD");
+
1942 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "470");
1943
- -
1945 jtp[0u][0u][jss::currency] = "XRP";
-
1946 env(pay(alice, bob, EUR(30)), json(jss::Paths, jtp), sendmax(USD(333)));
-
1947
-
1948 auto jrr = ledgerEntryState(env, alice, gw1, "USD");
-
1949 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "470");
-
1950
-
1951 jrr = ledgerEntryState(env, bob, gw2, "EUR");
-
1952 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-30");
-
1953
-
1954 jrr = ledgerEntryState(env, carol, gw1, "USD");
-
1955 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-30");
-
1956
-
1957 jrr = ledgerEntryState(env, dan, gw2, "EUR");
-
1958 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-370");
+
1944 jrr = ledgerEntryState(env, bob, gw2, "EUR");
+
1945 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-30");
+
1946
+
1947 jrr = ledgerEntryState(env, carol, gw1, "USD");
+
1948 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-30");
+
1949
+
1950 jrr = ledgerEntryState(env, dan, gw2, "EUR");
+
1951 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-370");
+
1952
+
1953 auto jro = ledgerEntryOffer(env, carol, carolOfferSeq);
+
1954 BEAST_EXPECT(
+
1955 jro[jss::node][jss::TakerGets] == XRP(200).value().getText());
+
1956 BEAST_EXPECT(
+
1957 jro[jss::node][jss::TakerPays] ==
+
1958 USD(20).value().getJson(JsonOptions::none));
1959
-
1960 auto jro = ledgerEntryOffer(env, carol, carolOfferSeq);
+
1960 jro = ledgerEntryOffer(env, dan, danOfferSeq);
1961 BEAST_EXPECT(
-
1962 jro[jss::node][jss::TakerGets] == XRP(200).value().getText());
-
1963 BEAST_EXPECT(
-
1964 jro[jss::node][jss::TakerPays] ==
-
1965 USD(20).value().getJson(JsonOptions::none));
-
1966
-
1967 jro = ledgerEntryOffer(env, dan, danOfferSeq);
-
1968 BEAST_EXPECT(
-
1969 jro[jss::node][jss::TakerGets] ==
-
1970 gw2["EUR"](20).value().getJson(JsonOptions::none));
-
1971 BEAST_EXPECT(
-
1972 jro[jss::node][jss::TakerPays] == XRP(200).value().getText());
-
1973 }
+
1962 jro[jss::node][jss::TakerGets] ==
+
1963 gw2["EUR"](20).value().getJson(JsonOptions::none));
+
1964 BEAST_EXPECT(
+
1965 jro[jss::node][jss::TakerPays] == XRP(200).value().getText());
+
1966 }
-
1974
-
1975 void
-
- -
1977 {
-
1978 // At least with Taker bridging, a sensitivity was identified if the
-
1979 // second leg goes dry before the first one. This test exercises that
-
1980 // case.
-
1981 testcase("Auto Bridged Second Leg Dry");
-
1982
-
1983 using namespace jtx;
-
1984 Env env(*this, features);
+
1967
+
1968 void
+
+ +
1970 {
+
1971 // At least with Taker bridging, a sensitivity was identified if the
+
1972 // second leg goes dry before the first one. This test exercises that
+
1973 // case.
+
1974 testcase("Auto Bridged Second Leg Dry");
+
1975
+
1976 using namespace jtx;
+
1977 Env env(*this, features);
+
1978
+
1979 Account const alice{"alice"};
+
1980 Account const bob{"bob"};
+
1981 Account const carol{"carol"};
+
1982 Account const gw{"gateway"};
+
1983 auto const USD = gw["USD"];
+
1984 auto const EUR = gw["EUR"];
1985
-
1986 Account const alice{"alice"};
-
1987 Account const bob{"bob"};
-
1988 Account const carol{"carol"};
-
1989 Account const gw{"gateway"};
-
1990 auto const USD = gw["USD"];
-
1991 auto const EUR = gw["EUR"];
-
1992
-
1993 env.fund(XRP(100000000), alice, bob, carol, gw);
-
1994 env.close();
+
1986 env.fund(XRP(100000000), alice, bob, carol, gw);
+
1987 env.close();
+
1988
+
1989 env.trust(USD(10), alice);
+
1990 env.close();
+
1991 env(pay(gw, alice, USD(10)));
+
1992 env.trust(USD(10), carol);
+
1993 env.close();
+
1994 env(pay(gw, carol, USD(3)));
1995
-
1996 env.trust(USD(10), alice);
-
1997 env.close();
-
1998 env(pay(gw, alice, USD(10)));
-
1999 env.trust(USD(10), carol);
-
2000 env.close();
-
2001 env(pay(gw, carol, USD(3)));
+
1996 env(offer(alice, EUR(2), XRP(1)));
+
1997 env(offer(alice, EUR(2), XRP(1)));
+
1998
+
1999 env(offer(alice, XRP(1), USD(4)));
+
2000 env(offer(carol, XRP(1), USD(3)));
+
2001 env.close();
2002
-
2003 env(offer(alice, EUR(2), XRP(1)));
-
2004 env(offer(alice, EUR(2), XRP(1)));
-
2005
-
2006 env(offer(alice, XRP(1), USD(4)));
-
2007 env(offer(carol, XRP(1), USD(3)));
-
2008 env.close();
-
2009
-
2010 // Bob offers to buy 10 USD for 10 EUR.
-
2011 // 1. He spends 2 EUR taking Alice's auto-bridged offers and
-
2012 // gets 4 USD for that.
-
2013 // 2. He spends another 2 EUR taking Alice's last EUR->XRP offer and
-
2014 // Carol's XRP-USD offer. He gets 3 USD for that.
-
2015 // The key for this test is that Alice's XRP->USD leg goes dry before
-
2016 // Alice's EUR->XRP. The XRP->USD leg is the second leg which showed
-
2017 // some sensitivity.
-
2018 env.trust(EUR(10), bob);
-
2019 env.close();
-
2020 env(pay(gw, bob, EUR(10)));
-
2021 env.close();
-
2022 env(offer(bob, USD(10), EUR(10)));
-
2023 env.close();
-
2024
-
2025 env.require(balance(bob, USD(7)));
-
2026 env.require(balance(bob, EUR(6)));
-
2027 env.require(offers(bob, 1));
-
2028 env.require(owners(bob, 3));
-
2029
-
2030 env.require(balance(alice, USD(6)));
-
2031 env.require(balance(alice, EUR(4)));
-
2032 env.require(offers(alice, 0));
-
2033 env.require(owners(alice, 2));
+
2003 // Bob offers to buy 10 USD for 10 EUR.
+
2004 // 1. He spends 2 EUR taking Alice's auto-bridged offers and
+
2005 // gets 4 USD for that.
+
2006 // 2. He spends another 2 EUR taking Alice's last EUR->XRP offer and
+
2007 // Carol's XRP-USD offer. He gets 3 USD for that.
+
2008 // The key for this test is that Alice's XRP->USD leg goes dry before
+
2009 // Alice's EUR->XRP. The XRP->USD leg is the second leg which showed
+
2010 // some sensitivity.
+
2011 env.trust(EUR(10), bob);
+
2012 env.close();
+
2013 env(pay(gw, bob, EUR(10)));
+
2014 env.close();
+
2015 env(offer(bob, USD(10), EUR(10)));
+
2016 env.close();
+
2017
+
2018 env.require(balance(bob, USD(7)));
+
2019 env.require(balance(bob, EUR(6)));
+
2020 env.require(offers(bob, 1));
+
2021 env.require(owners(bob, 3));
+
2022
+
2023 env.require(balance(alice, USD(6)));
+
2024 env.require(balance(alice, EUR(4)));
+
2025 env.require(offers(alice, 0));
+
2026 env.require(owners(alice, 2));
+
2027
+
2028 env.require(balance(carol, USD(0)));
+
2029 env.require(balance(carol, EUR(none)));
+
2030
+
2031 env.require(offers(carol, 0));
+
2032 env.require(owners(carol, 1));
+
2033 }
+
2034
-
2035 env.require(balance(carol, USD(0)));
-
2036 env.require(balance(carol, EUR(none)));
-
2037
-
2038 env.require(offers(carol, 0));
-
2039 env.require(owners(carol, 1));
-
2040 }
-
+
2035 void
+
+ +
2037 {
+
2038 testcase("Offer Fees Consume Funds");
+
2039
+
2040 using namespace jtx;
2041
-
2042 void
-
- -
2044 {
-
2045 testcase("Offer Fees Consume Funds");
-
2046
-
2047 using namespace jtx;
-
2048
-
2049 Env env{*this, features};
-
2050
-
2051 auto const gw1 = Account{"gateway_1"};
-
2052 auto const gw2 = Account{"gateway_2"};
-
2053 auto const gw3 = Account{"gateway_3"};
-
2054 auto const alice = Account{"alice"};
-
2055 auto const bob = Account{"bob"};
-
2056 auto const USD1 = gw1["USD"];
-
2057 auto const USD2 = gw2["USD"];
-
2058 auto const USD3 = gw3["USD"];
-
2059
-
2060 // Provide micro amounts to compensate for fees to make results round
-
2061 // nice.
-
2062 // reserve: Alice has 3 entries in the ledger, via trust lines
-
2063 // fees:
-
2064 // 1 for each trust limit == 3 (alice < mtgox/amazon/bitstamp) +
-
2065 // 1 for payment == 4
-
2066 auto const starting_xrp = XRP(100) +
-
2067 env.current()->fees().accountReserve(3) +
-
2068 env.current()->fees().base * 4;
-
2069
-
2070 env.fund(starting_xrp, gw1, gw2, gw3, alice, bob);
-
2071 env.close();
-
2072
-
2073 env(trust(alice, USD1(1000)));
-
2074 env(trust(alice, USD2(1000)));
-
2075 env(trust(alice, USD3(1000)));
-
2076 env(trust(bob, USD1(1000)));
-
2077 env(trust(bob, USD2(1000)));
+
2042 Env env{*this, features};
+
2043
+
2044 auto const gw1 = Account{"gateway_1"};
+
2045 auto const gw2 = Account{"gateway_2"};
+
2046 auto const gw3 = Account{"gateway_3"};
+
2047 auto const alice = Account{"alice"};
+
2048 auto const bob = Account{"bob"};
+
2049 auto const USD1 = gw1["USD"];
+
2050 auto const USD2 = gw2["USD"];
+
2051 auto const USD3 = gw3["USD"];
+
2052
+
2053 // Provide micro amounts to compensate for fees to make results round
+
2054 // nice.
+
2055 // reserve: Alice has 3 entries in the ledger, via trust lines
+
2056 // fees:
+
2057 // 1 for each trust limit == 3 (alice < mtgox/amazon/bitstamp) +
+
2058 // 1 for payment == 4
+
2059 auto const starting_xrp = XRP(100) +
+
2060 env.current()->fees().accountReserve(3) +
+
2061 env.current()->fees().base * 4;
+
2062
+
2063 env.fund(starting_xrp, gw1, gw2, gw3, alice, bob);
+
2064 env.close();
+
2065
+
2066 env(trust(alice, USD1(1000)));
+
2067 env(trust(alice, USD2(1000)));
+
2068 env(trust(alice, USD3(1000)));
+
2069 env(trust(bob, USD1(1000)));
+
2070 env(trust(bob, USD2(1000)));
+
2071
+
2072 env(pay(gw1, bob, bob["USD"](500)));
+
2073
+
2074 env(offer(bob, XRP(200), USD1(200)));
+
2075 // Alice has 350 fees - a reserve of 50 = 250 reserve = 100 available.
+
2076 // Ask for more than available to prove reserve works.
+
2077 env(offer(alice, USD1(200), XRP(200)));
2078
-
2079 env(pay(gw1, bob, bob["USD"](500)));
-
2080
-
2081 env(offer(bob, XRP(200), USD1(200)));
-
2082 // Alice has 350 fees - a reserve of 50 = 250 reserve = 100 available.
-
2083 // Ask for more than available to prove reserve works.
-
2084 env(offer(alice, USD1(200), XRP(200)));
+
2079 auto jrr = ledgerEntryState(env, alice, gw1, "USD");
+
2080 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "100");
+
2081 jrr = ledgerEntryRoot(env, alice);
+
2082 BEAST_EXPECT(
+
2083 jrr[jss::node][sfBalance.fieldName] ==
+
2084 STAmount(env.current()->fees().accountReserve(3)).getText());
2085
-
2086 auto jrr = ledgerEntryState(env, alice, gw1, "USD");
-
2087 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "100");
-
2088 jrr = ledgerEntryRoot(env, alice);
-
2089 BEAST_EXPECT(
-
2090 jrr[jss::node][sfBalance.fieldName] ==
-
2091 STAmount(env.current()->fees().accountReserve(3)).getText());
-
2092
-
2093 jrr = ledgerEntryState(env, bob, gw1, "USD");
-
2094 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-400");
-
2095 }
+
2086 jrr = ledgerEntryState(env, bob, gw1, "USD");
+
2087 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-400");
+
2088 }
+
2089
+
2090 void
+
+ +
2092 {
+
2093 testcase("Offer Create, then Cross");
+
2094
+
2095 using namespace jtx;
2096
-
2097 void
-
- -
2099 {
-
2100 testcase("Offer Create, then Cross");
-
2101
-
2102 using namespace jtx;
-
2103
-
2104 for (auto NumberSwitchOver : {false, true})
-
2105 {
-
2106 Env env{*this, features};
-
2107 if (NumberSwitchOver)
-
2108 env.enableFeature(fixUniversalNumber);
-
2109 else
-
2110 env.disableFeature(fixUniversalNumber);
-
2111
-
2112 auto const gw = Account{"gateway"};
-
2113 auto const alice = Account{"alice"};
-
2114 auto const bob = Account{"bob"};
-
2115 auto const USD = gw["USD"];
-
2116
-
2117 env.fund(XRP(10000), gw, alice, bob);
-
2118 env.close();
-
2119
-
2120 env(rate(gw, 1.005));
+
2097 for (auto NumberSwitchOver : {false, true})
+
2098 {
+
2099 Env env{*this, features};
+
2100 if (NumberSwitchOver)
+
2101 env.enableFeature(fixUniversalNumber);
+
2102 else
+
2103 env.disableFeature(fixUniversalNumber);
+
2104
+
2105 auto const gw = Account{"gateway"};
+
2106 auto const alice = Account{"alice"};
+
2107 auto const bob = Account{"bob"};
+
2108 auto const USD = gw["USD"];
+
2109
+
2110 env.fund(XRP(10000), gw, alice, bob);
+
2111 env.close();
+
2112
+
2113 env(rate(gw, 1.005));
+
2114
+
2115 env(trust(alice, USD(1000)));
+
2116 env(trust(bob, USD(1000)));
+
2117 env(trust(gw, alice["USD"](50)));
+
2118
+
2119 env(pay(gw, bob, bob["USD"](1)));
+
2120 env(pay(alice, gw, USD(50)));
2121
-
2122 env(trust(alice, USD(1000)));
-
2123 env(trust(bob, USD(1000)));
-
2124 env(trust(gw, alice["USD"](50)));
-
2125
-
2126 env(pay(gw, bob, bob["USD"](1)));
-
2127 env(pay(alice, gw, USD(50)));
-
2128
-
2129 env(trust(gw, alice["USD"](0)));
-
2130
-
2131 env(offer(alice, USD(50), XRP(150000)));
-
2132 env(offer(bob, XRP(100), USD(0.1)));
-
2133
-
2134 auto jrr = ledgerEntryState(env, alice, gw, "USD");
-
2135 BEAST_EXPECT(
-
2136 jrr[jss::node][sfBalance.fieldName][jss::value] ==
-
2137 "49.96666666666667");
-
2138
-
2139 jrr = ledgerEntryState(env, bob, gw, "USD");
-
2140 Json::Value const bobsUSD =
-
2141 jrr[jss::node][sfBalance.fieldName][jss::value];
-
2142 if (!NumberSwitchOver)
-
2143 {
-
2144 BEAST_EXPECT(bobsUSD == "-0.966500000033334");
-
2145 }
-
2146 else
-
2147 {
-
2148 BEAST_EXPECT(bobsUSD == "-0.9665000000333333");
-
2149 }
-
2150 }
-
2151 }
+
2122 env(trust(gw, alice["USD"](0)));
+
2123
+
2124 env(offer(alice, USD(50), XRP(150000)));
+
2125 env(offer(bob, XRP(100), USD(0.1)));
+
2126
+
2127 auto jrr = ledgerEntryState(env, alice, gw, "USD");
+
2128 BEAST_EXPECT(
+
2129 jrr[jss::node][sfBalance.fieldName][jss::value] ==
+
2130 "49.96666666666667");
+
2131
+
2132 jrr = ledgerEntryState(env, bob, gw, "USD");
+
2133 Json::Value const bobsUSD =
+
2134 jrr[jss::node][sfBalance.fieldName][jss::value];
+
2135 if (!NumberSwitchOver)
+
2136 {
+
2137 BEAST_EXPECT(bobsUSD == "-0.966500000033334");
+
2138 }
+
2139 else
+
2140 {
+
2141 BEAST_EXPECT(bobsUSD == "-0.9665000000333333");
+
2142 }
+
2143 }
+
2144 }
+
2145
+
2146 void
+
+ +
2148 {
+
2149 testcase("Offer tfSell: Basic Sell");
+
2150
+
2151 using namespace jtx;
2152
-
2153 void
-
- -
2155 {
-
2156 testcase("Offer tfSell: Basic Sell");
-
2157
-
2158 using namespace jtx;
+
2153 Env env{*this, features};
+
2154
+
2155 auto const gw = Account{"gateway"};
+
2156 auto const alice = Account{"alice"};
+
2157 auto const bob = Account{"bob"};
+
2158 auto const USD = gw["USD"];
2159
-
2160 Env env{*this, features};
-
2161
-
2162 auto const gw = Account{"gateway"};
-
2163 auto const alice = Account{"alice"};
-
2164 auto const bob = Account{"bob"};
-
2165 auto const USD = gw["USD"];
+
2160 auto const starting_xrp = XRP(100) +
+
2161 env.current()->fees().accountReserve(1) +
+
2162 env.current()->fees().base * 2;
+
2163
+
2164 env.fund(starting_xrp, gw, alice, bob);
+
2165 env.close();
2166
-
2167 auto const starting_xrp = XRP(100) +
-
2168 env.current()->fees().accountReserve(1) +
-
2169 env.current()->fees().base * 2;
-
2170
-
2171 env.fund(starting_xrp, gw, alice, bob);
-
2172 env.close();
-
2173
-
2174 env(trust(alice, USD(1000)));
-
2175 env(trust(bob, USD(1000)));
-
2176
-
2177 env(pay(gw, bob, bob["USD"](500)));
-
2178
-
2179 env(offer(bob, XRP(200), USD(200)), json(jss::Flags, tfSell));
-
2180 // Alice has 350 + fees - a reserve of 50 = 250 reserve = 100 available.
-
2181 // Alice has 350 + fees - a reserve of 50 = 250 reserve = 100 available.
-
2182 // Ask for more than available to prove reserve works.
-
2183 env(offer(alice, USD(200), XRP(200)), json(jss::Flags, tfSell));
+
2167 env(trust(alice, USD(1000)));
+
2168 env(trust(bob, USD(1000)));
+
2169
+
2170 env(pay(gw, bob, bob["USD"](500)));
+
2171
+
2172 env(offer(bob, XRP(200), USD(200)), json(jss::Flags, tfSell));
+
2173 // Alice has 350 + fees - a reserve of 50 = 250 reserve = 100 available.
+
2174 // Alice has 350 + fees - a reserve of 50 = 250 reserve = 100 available.
+
2175 // Ask for more than available to prove reserve works.
+
2176 env(offer(alice, USD(200), XRP(200)), json(jss::Flags, tfSell));
+
2177
+
2178 auto jrr = ledgerEntryState(env, alice, gw, "USD");
+
2179 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-100");
+
2180 jrr = ledgerEntryRoot(env, alice);
+
2181 BEAST_EXPECT(
+
2182 jrr[jss::node][sfBalance.fieldName] ==
+
2183 STAmount(env.current()->fees().accountReserve(1)).getText());
2184
-
2185 auto jrr = ledgerEntryState(env, alice, gw, "USD");
-
2186 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-100");
-
2187 jrr = ledgerEntryRoot(env, alice);
-
2188 BEAST_EXPECT(
-
2189 jrr[jss::node][sfBalance.fieldName] ==
-
2190 STAmount(env.current()->fees().accountReserve(1)).getText());
-
2191
-
2192 jrr = ledgerEntryState(env, bob, gw, "USD");
-
2193 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-400");
-
2194 }
+
2185 jrr = ledgerEntryState(env, bob, gw, "USD");
+
2186 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-400");
+
2187 }
+
2188
+
2189 void
+
+ +
2191 {
+
2192 testcase("Offer tfSell: 2x Sell Exceed Limit");
+
2193
+
2194 using namespace jtx;
2195
-
2196 void
-
- -
2198 {
-
2199 testcase("Offer tfSell: 2x Sell Exceed Limit");
-
2200
-
2201 using namespace jtx;
+
2196 Env env{*this, features};
+
2197
+
2198 auto const gw = Account{"gateway"};
+
2199 auto const alice = Account{"alice"};
+
2200 auto const bob = Account{"bob"};
+
2201 auto const USD = gw["USD"];
2202
-
2203 Env env{*this, features};
-
2204
-
2205 auto const gw = Account{"gateway"};
-
2206 auto const alice = Account{"alice"};
-
2207 auto const bob = Account{"bob"};
-
2208 auto const USD = gw["USD"];
+
2203 auto const starting_xrp = XRP(100) +
+
2204 env.current()->fees().accountReserve(1) +
+
2205 env.current()->fees().base * 2;
+
2206
+
2207 env.fund(starting_xrp, gw, alice, bob);
+
2208 env.close();
2209
-
2210 auto const starting_xrp = XRP(100) +
-
2211 env.current()->fees().accountReserve(1) +
-
2212 env.current()->fees().base * 2;
-
2213
-
2214 env.fund(starting_xrp, gw, alice, bob);
-
2215 env.close();
-
2216
-
2217 env(trust(alice, USD(150)));
-
2218 env(trust(bob, USD(1000)));
-
2219
-
2220 env(pay(gw, bob, bob["USD"](500)));
-
2221
-
2222 env(offer(bob, XRP(100), USD(200)));
-
2223 // Alice has 350 fees - a reserve of 50 = 250 reserve = 100 available.
-
2224 // Ask for more than available to prove reserve works.
-
2225 // Taker pays 100 USD for 100 XRP.
-
2226 // Selling XRP.
-
2227 // Will sell all 100 XRP and get more USD than asked for.
-
2228 env(offer(alice, USD(100), XRP(100)), json(jss::Flags, tfSell));
+
2210 env(trust(alice, USD(150)));
+
2211 env(trust(bob, USD(1000)));
+
2212
+
2213 env(pay(gw, bob, bob["USD"](500)));
+
2214
+
2215 env(offer(bob, XRP(100), USD(200)));
+
2216 // Alice has 350 fees - a reserve of 50 = 250 reserve = 100 available.
+
2217 // Ask for more than available to prove reserve works.
+
2218 // Taker pays 100 USD for 100 XRP.
+
2219 // Selling XRP.
+
2220 // Will sell all 100 XRP and get more USD than asked for.
+
2221 env(offer(alice, USD(100), XRP(100)), json(jss::Flags, tfSell));
+
2222
+
2223 auto jrr = ledgerEntryState(env, alice, gw, "USD");
+
2224 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-200");
+
2225 jrr = ledgerEntryRoot(env, alice);
+
2226 BEAST_EXPECT(
+
2227 jrr[jss::node][sfBalance.fieldName] ==
+
2228 STAmount(env.current()->fees().accountReserve(1)).getText());
2229
-
2230 auto jrr = ledgerEntryState(env, alice, gw, "USD");
-
2231 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-200");
-
2232 jrr = ledgerEntryRoot(env, alice);
-
2233 BEAST_EXPECT(
-
2234 jrr[jss::node][sfBalance.fieldName] ==
-
2235 STAmount(env.current()->fees().accountReserve(1)).getText());
-
2236
-
2237 jrr = ledgerEntryState(env, bob, gw, "USD");
-
2238 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-300");
-
2239 }
+
2230 jrr = ledgerEntryState(env, bob, gw, "USD");
+
2231 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-300");
+
2232 }
+
2233
+
2234 void
+
+ +
2236 {
+
2237 testcase("Client Issue #535: Gateway Cross Currency");
+
2238
+
2239 using namespace jtx;
2240
-
2241 void
-
- -
2243 {
-
2244 testcase("Client Issue #535: Gateway Cross Currency");
-
2245
-
2246 using namespace jtx;
-
2247
-
2248 Env env{*this, features};
-
2249
-
2250 auto const gw = Account{"gateway"};
-
2251 auto const alice = Account{"alice"};
-
2252 auto const bob = Account{"bob"};
-
2253 auto const XTS = gw["XTS"];
-
2254 auto const XXX = gw["XXX"];
+
2241 Env env{*this, features};
+
2242
+
2243 auto const gw = Account{"gateway"};
+
2244 auto const alice = Account{"alice"};
+
2245 auto const bob = Account{"bob"};
+
2246 auto const XTS = gw["XTS"];
+
2247 auto const XXX = gw["XXX"];
+
2248
+
2249 auto const starting_xrp = XRP(100.1) +
+
2250 env.current()->fees().accountReserve(1) +
+
2251 env.current()->fees().base * 2;
+
2252
+
2253 env.fund(starting_xrp, gw, alice, bob);
+
2254 env.close();
2255
-
2256 auto const starting_xrp = XRP(100.1) +
-
2257 env.current()->fees().accountReserve(1) +
-
2258 env.current()->fees().base * 2;
-
2259
-
2260 env.fund(starting_xrp, gw, alice, bob);
-
2261 env.close();
-
2262
-
2263 env(trust(alice, XTS(1000)));
-
2264 env(trust(alice, XXX(1000)));
-
2265 env(trust(bob, XTS(1000)));
-
2266 env(trust(bob, XXX(1000)));
+
2256 env(trust(alice, XTS(1000)));
+
2257 env(trust(alice, XXX(1000)));
+
2258 env(trust(bob, XTS(1000)));
+
2259 env(trust(bob, XXX(1000)));
+
2260
+
2261 env(pay(gw, alice, alice["XTS"](100)));
+
2262 env(pay(gw, alice, alice["XXX"](100)));
+
2263 env(pay(gw, bob, bob["XTS"](100)));
+
2264 env(pay(gw, bob, bob["XXX"](100)));
+
2265
+
2266 env(offer(alice, XTS(100), XXX(100)));
2267
-
2268 env(pay(gw, alice, alice["XTS"](100)));
-
2269 env(pay(gw, alice, alice["XXX"](100)));
-
2270 env(pay(gw, bob, bob["XTS"](100)));
-
2271 env(pay(gw, bob, bob["XXX"](100)));
-
2272
-
2273 env(offer(alice, XTS(100), XXX(100)));
-
2274
-
2275 // WS client is used here because the RPC client could not
-
2276 // be convinced to pass the build_path argument
-
2277 auto wsc = makeWSClient(env.app().config());
-
2278 Json::Value payment;
-
2279 payment[jss::secret] = toBase58(generateSeed("bob"));
-
2280 payment[jss::id] = env.seq(bob);
-
2281 payment[jss::build_path] = true;
-
2282 payment[jss::tx_json] = pay(bob, bob, bob["XXX"](1));
-
2283 payment[jss::tx_json][jss::Sequence] =
-
2284 env.current()
-
2285 ->read(keylet::account(bob.id()))
-
2286 ->getFieldU32(sfSequence);
-
2287 payment[jss::tx_json][jss::Fee] = to_string(env.current()->fees().base);
-
2288 payment[jss::tx_json][jss::SendMax] =
-
2289 bob["XTS"](1.5).value().getJson(JsonOptions::none);
-
2290 auto jrr = wsc->invoke("submit", payment);
-
2291 BEAST_EXPECT(jrr[jss::status] == "success");
-
2292 BEAST_EXPECT(jrr[jss::result][jss::engine_result] == "tesSUCCESS");
-
2293 if (wsc->version() == 2)
-
2294 {
-
2295 BEAST_EXPECT(
-
2296 jrr.isMember(jss::jsonrpc) && jrr[jss::jsonrpc] == "2.0");
-
2297 BEAST_EXPECT(
-
2298 jrr.isMember(jss::ripplerpc) && jrr[jss::ripplerpc] == "2.0");
-
2299 BEAST_EXPECT(jrr.isMember(jss::id) && jrr[jss::id] == 5);
-
2300 }
-
2301
-
2302 jrr = ledgerEntryState(env, alice, gw, "XTS");
+
2268 // WS client is used here because the RPC client could not
+
2269 // be convinced to pass the build_path argument
+
2270 auto wsc = makeWSClient(env.app().config());
+
2271 Json::Value payment;
+
2272 payment[jss::secret] = toBase58(generateSeed("bob"));
+
2273 payment[jss::id] = env.seq(bob);
+
2274 payment[jss::build_path] = true;
+
2275 payment[jss::tx_json] = pay(bob, bob, bob["XXX"](1));
+
2276 payment[jss::tx_json][jss::Sequence] =
+
2277 env.current()
+
2278 ->read(keylet::account(bob.id()))
+
2279 ->getFieldU32(sfSequence);
+
2280 payment[jss::tx_json][jss::Fee] = to_string(env.current()->fees().base);
+
2281 payment[jss::tx_json][jss::SendMax] =
+
2282 bob["XTS"](1.5).value().getJson(JsonOptions::none);
+
2283 auto jrr = wsc->invoke("submit", payment);
+
2284 BEAST_EXPECT(jrr[jss::status] == "success");
+
2285 BEAST_EXPECT(jrr[jss::result][jss::engine_result] == "tesSUCCESS");
+
2286 if (wsc->version() == 2)
+
2287 {
+
2288 BEAST_EXPECT(
+
2289 jrr.isMember(jss::jsonrpc) && jrr[jss::jsonrpc] == "2.0");
+
2290 BEAST_EXPECT(
+
2291 jrr.isMember(jss::ripplerpc) && jrr[jss::ripplerpc] == "2.0");
+
2292 BEAST_EXPECT(jrr.isMember(jss::id) && jrr[jss::id] == 5);
+
2293 }
+
2294
+
2295 jrr = ledgerEntryState(env, alice, gw, "XTS");
+
2296 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-101");
+
2297 jrr = ledgerEntryState(env, alice, gw, "XXX");
+
2298 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-99");
+
2299
+
2300 jrr = ledgerEntryState(env, bob, gw, "XTS");
+
2301 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-99");
+
2302 jrr = ledgerEntryState(env, bob, gw, "XXX");
2303 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-101");
-
2304 jrr = ledgerEntryState(env, alice, gw, "XXX");
-
2305 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-99");
-
2306
-
2307 jrr = ledgerEntryState(env, bob, gw, "XTS");
-
2308 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-99");
-
2309 jrr = ledgerEntryState(env, bob, gw, "XXX");
-
2310 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-101");
-
2311 }
+
2304 }
-
2312
-
2313 // Helper function that validates a *defaulted* trustline: one that has
-
2314 // no unusual flags set and doesn't have high or low limits set. Such a
-
2315 // trustline may have an actual balance (it can be created automatically
-
2316 // if a user places an offer to acquire an IOU for which they don't have
-
2317 // a trust line defined). If the trustline is not defaulted then the tests
-
2318 // will not pass.
-
2319 void
-
- -
2321 jtx::Env& env,
-
2322 jtx::Account const& account,
-
2323 jtx::PrettyAmount const& expectBalance)
-
2324 {
-
2325 auto const sleTrust =
-
2326 env.le(keylet::line(account.id(), expectBalance.value().issue()));
-
2327 BEAST_EXPECT(sleTrust);
-
2328 if (sleTrust)
-
2329 {
-
2330 Issue const issue = expectBalance.value().issue();
-
2331 bool const accountLow = account.id() < issue.account;
-
2332
-
2333 STAmount low{issue};
-
2334 STAmount high{issue};
-
2335
-
2336 low.setIssuer(accountLow ? account.id() : issue.account);
-
2337 high.setIssuer(accountLow ? issue.account : account.id());
+
2305
+
2306 // Helper function that validates a *defaulted* trustline: one that has
+
2307 // no unusual flags set and doesn't have high or low limits set. Such a
+
2308 // trustline may have an actual balance (it can be created automatically
+
2309 // if a user places an offer to acquire an IOU for which they don't have
+
2310 // a trust line defined). If the trustline is not defaulted then the tests
+
2311 // will not pass.
+
2312 void
+
+ +
2314 jtx::Env& env,
+
2315 jtx::Account const& account,
+
2316 jtx::PrettyAmount const& expectBalance)
+
2317 {
+
2318 auto const sleTrust =
+
2319 env.le(keylet::line(account.id(), expectBalance.value().issue()));
+
2320 BEAST_EXPECT(sleTrust);
+
2321 if (sleTrust)
+
2322 {
+
2323 Issue const issue = expectBalance.value().issue();
+
2324 bool const accountLow = account.id() < issue.account;
+
2325
+
2326 STAmount low{issue};
+
2327 STAmount high{issue};
+
2328
+
2329 low.setIssuer(accountLow ? account.id() : issue.account);
+
2330 high.setIssuer(accountLow ? issue.account : account.id());
+
2331
+
2332 BEAST_EXPECT(sleTrust->getFieldAmount(sfLowLimit) == low);
+
2333 BEAST_EXPECT(sleTrust->getFieldAmount(sfHighLimit) == high);
+
2334
+
2335 STAmount actualBalance{sleTrust->getFieldAmount(sfBalance)};
+
2336 if (!accountLow)
+
2337 actualBalance.negate();
2338
-
2339 BEAST_EXPECT(sleTrust->getFieldAmount(sfLowLimit) == low);
-
2340 BEAST_EXPECT(sleTrust->getFieldAmount(sfHighLimit) == high);
-
2341
-
2342 STAmount actualBalance{sleTrust->getFieldAmount(sfBalance)};
-
2343 if (!accountLow)
-
2344 actualBalance.negate();
-
2345
-
2346 BEAST_EXPECT(actualBalance == expectBalance);
-
2347 }
-
2348 }
+
2339 BEAST_EXPECT(actualBalance == expectBalance);
+
2340 }
+
2341 }
-
2349
-
2350 void
-
- -
2352 {
-
2353 // Test a number of different corner cases regarding adding a
-
2354 // possibly crossable offer to an account. The test is table
-
2355 // driven so it should be easy to add or remove tests.
-
2356 testcase("Partial Crossing");
+
2342
+
2343 void
+
+ +
2345 {
+
2346 // Test a number of different corner cases regarding adding a
+
2347 // possibly crossable offer to an account. The test is table
+
2348 // driven so it should be easy to add or remove tests.
+
2349 testcase("Partial Crossing");
+
2350
+
2351 using namespace jtx;
+
2352
+
2353 auto const gw = Account("gateway");
+
2354 auto const USD = gw["USD"];
+
2355
+
2356 Env env{*this, features};
2357
-
2358 using namespace jtx;
-
2359
-
2360 auto const gw = Account("gateway");
-
2361 auto const USD = gw["USD"];
-
2362
-
2363 Env env{*this, features};
-
2364
-
2365 env.fund(XRP(10000000), gw);
-
2366 env.close();
-
2367
-
2368 // The fee that's charged for transactions
-
2369 auto const f = env.current()->fees().base;
-
2370
-
2371 // To keep things simple all offers are 1 : 1 for XRP : USD.
-
2372 enum preTrustType { noPreTrust, gwPreTrust, acctPreTrust };
-
2373 struct TestData
-
2374 {
-
2375 std::string account; // Account operated on
-
2376 STAmount fundXrp; // Account funded with
-
2377 int bookAmount; // USD -> XRP offer on the books
-
2378 preTrustType preTrust; // If true, pre-establish trust line
-
2379 int offerAmount; // Account offers this much XRP -> USD
-
2380 TER tec; // Returned tec code
-
2381 STAmount spentXrp; // Amount removed from fundXrp
-
2382 PrettyAmount balanceUsd; // Balance on account end
-
2383 int offers; // Offers on account
-
2384 int owners; // Owners on account
-
2385 };
-
2386
-
2387 // clang-format off
-
2388 TestData const tests[]{
-
2389 // acct fundXrp bookAmt preTrust offerAmt tec spentXrp balanceUSD offers owners
-
2390 {"ann", reserve(env, 0) + 0 * f, 1, noPreTrust, 1000, tecUNFUNDED_OFFER, f, USD( 0), 0, 0}, // Account is at the reserve, and will dip below once fees are subtracted.
-
2391 {"bev", reserve(env, 0) + 1 * f, 1, noPreTrust, 1000, tecUNFUNDED_OFFER, f, USD( 0), 0, 0}, // Account has just enough for the reserve and the fee.
-
2392 {"cam", reserve(env, 0) + 2 * f, 0, noPreTrust, 1000, tecINSUF_RESERVE_OFFER, f, USD( 0), 0, 0}, // Account has enough for the reserve, the fee and the offer, and a bit more, but not enough for the reserve after the offer is placed.
-
2393 {"deb", drops(10) + reserve(env, 0) + 1 * f, 1, noPreTrust, 1000, tesSUCCESS, drops(10) + f, USD(0.00001), 0, 1}, // Account has enough to buy a little USD then the offer runs dry.
-
2394 {"eve", reserve(env, 1) + 0 * f, 0, noPreTrust, 1000, tesSUCCESS, f, USD( 0), 1, 1}, // No offer to cross
-
2395 {"flo", reserve(env, 1) + 0 * f, 1, noPreTrust, 1000, tesSUCCESS, XRP( 1) + f, USD( 1), 0, 1},
-
2396 {"gay", reserve(env, 1) + 1 * f, 1000, noPreTrust, 1000, tesSUCCESS, XRP( 50) + f, USD( 50), 0, 1},
-
2397 {"hye", XRP(1000) + 1 * f, 1000, noPreTrust, 1000, tesSUCCESS, XRP( 800) + f, USD( 800), 0, 1},
-
2398 {"ivy", XRP( 1) + reserve(env, 1) + 1 * f, 1, noPreTrust, 1000, tesSUCCESS, XRP( 1) + f, USD( 1), 0, 1},
-
2399 {"joy", XRP( 1) + reserve(env, 2) + 1 * f, 1, noPreTrust, 1000, tesSUCCESS, XRP( 1) + f, USD( 1), 1, 2},
-
2400 {"kim", XRP( 900) + reserve(env, 2) + 1 * f, 999, noPreTrust, 1000, tesSUCCESS, XRP( 999) + f, USD( 999), 0, 1},
-
2401 {"liz", XRP( 998) + reserve(env, 0) + 1 * f, 999, noPreTrust, 1000, tesSUCCESS, XRP( 998) + f, USD( 998), 0, 1},
-
2402 {"meg", XRP( 998) + reserve(env, 1) + 1 * f, 999, noPreTrust, 1000, tesSUCCESS, XRP( 999) + f, USD( 999), 0, 1},
-
2403 {"nia", XRP( 998) + reserve(env, 2) + 1 * f, 999, noPreTrust, 1000, tesSUCCESS, XRP( 999) + f, USD( 999), 1, 2},
-
2404 {"ova", XRP( 999) + reserve(env, 0) + 1 * f, 1000, noPreTrust, 1000, tesSUCCESS, XRP( 999) + f, USD( 999), 0, 1},
-
2405 {"pam", XRP( 999) + reserve(env, 1) + 1 * f, 1000, noPreTrust, 1000, tesSUCCESS, XRP(1000) + f, USD( 1000), 0, 1},
-
2406 {"rae", XRP( 999) + reserve(env, 2) + 1 * f, 1000, noPreTrust, 1000, tesSUCCESS, XRP(1000) + f, USD( 1000), 0, 1},
-
2407 {"sue", XRP(1000) + reserve(env, 2) + 1 * f, 0, noPreTrust, 1000, tesSUCCESS, f, USD( 0), 1, 1},
-
2408 //---------------- Pre-established trust lines ---------------------
-
2409 {"abe", reserve(env, 0) + 0 * f, 1, gwPreTrust, 1000, tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
-
2410 {"bud", reserve(env, 0) + 1 * f, 1, gwPreTrust, 1000, tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
-
2411 {"che", reserve(env, 0) + 2 * f, 0, gwPreTrust, 1000, tecINSUF_RESERVE_OFFER, f, USD( 0), 0, 0},
-
2412 {"dan", drops(10) + reserve(env, 0) + 1 * f, 1, gwPreTrust, 1000, tesSUCCESS, drops(10) + f, USD(0.00001), 0, 0},
-
2413 {"eli", XRP( 20) + reserve(env, 0) + 1 * f, 1000, gwPreTrust, 1000, tesSUCCESS, XRP(20) + 1 * f, USD( 20), 0, 0},
-
2414 {"fyn", reserve(env, 1) + 0 * f, 0, gwPreTrust, 1000, tesSUCCESS, f, USD( 0), 1, 1},
-
2415 {"gar", reserve(env, 1) + 0 * f, 1, gwPreTrust, 1000, tesSUCCESS, XRP( 1) + f, USD( 1), 1, 1},
-
2416 {"hal", reserve(env, 1) + 1 * f, 1, gwPreTrust, 1000, tesSUCCESS, XRP( 1) + f, USD( 1), 1, 1},
-
2417
-
2418 {"ned", reserve(env, 1) + 0 * f, 1, acctPreTrust, 1000, tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
-
2419 {"ole", reserve(env, 1) + 1 * f, 1, acctPreTrust, 1000, tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
-
2420 {"pat", reserve(env, 1) + 2 * f, 0, acctPreTrust, 1000, tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
-
2421 {"quy", reserve(env, 1) + 2 * f, 1, acctPreTrust, 1000, tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
-
2422 {"ron", reserve(env, 1) + 3 * f, 0, acctPreTrust, 1000, tecINSUF_RESERVE_OFFER, 2 * f, USD( 0), 0, 1},
-
2423 {"syd", drops(10) + reserve(env, 1) + 2 * f, 1, acctPreTrust, 1000, tesSUCCESS, drops(10) + 2 * f, USD(0.00001), 0, 1},
-
2424 {"ted", XRP( 20) + reserve(env, 1) + 2 * f, 1000, acctPreTrust, 1000, tesSUCCESS, XRP(20) + 2 * f, USD( 20), 0, 1},
-
2425 {"uli", reserve(env, 2) + 0 * f, 0, acctPreTrust, 1000, tecINSUF_RESERVE_OFFER, 2 * f, USD( 0), 0, 1},
-
2426 {"vic", reserve(env, 2) + 0 * f, 1, acctPreTrust, 1000, tesSUCCESS, XRP( 1) + 2 * f, USD( 1), 0, 1},
-
2427 {"wes", reserve(env, 2) + 1 * f, 0, acctPreTrust, 1000, tesSUCCESS, 2 * f, USD( 0), 1, 2},
-
2428 {"xan", reserve(env, 2) + 1 * f, 1, acctPreTrust, 1000, tesSUCCESS, XRP( 1) + 2 * f, USD( 1), 1, 2},
-
2429 };
-
2430 // clang-format on
-
2431
-
2432 for (auto const& t : tests)
-
2433 {
-
2434 auto const acct = Account(t.account);
-
2435 env.fund(t.fundXrp, acct);
-
2436 env.close();
-
2437
-
2438 // Make sure gateway has no current offers.
-
2439 env.require(offers(gw, 0));
+
2358 env.fund(XRP(10000000), gw);
+
2359 env.close();
+
2360
+
2361 // The fee that's charged for transactions
+
2362 auto const f = env.current()->fees().base;
+
2363
+
2364 // To keep things simple all offers are 1 : 1 for XRP : USD.
+
2365 enum preTrustType { noPreTrust, gwPreTrust, acctPreTrust };
+
2366 struct TestData
+
2367 {
+
2368 std::string account; // Account operated on
+
2369 STAmount fundXrp; // Account funded with
+
2370 int bookAmount; // USD -> XRP offer on the books
+
2371 preTrustType preTrust; // If true, pre-establish trust line
+
2372 int offerAmount; // Account offers this much XRP -> USD
+
2373 TER tec; // Returned tec code
+
2374 STAmount spentXrp; // Amount removed from fundXrp
+
2375 PrettyAmount balanceUsd; // Balance on account end
+
2376 int offers; // Offers on account
+
2377 int owners; // Owners on account
+
2378 };
+
2379
+
2380 // clang-format off
+
2381 TestData const tests[]{
+
2382 // acct fundXrp bookAmt preTrust offerAmt tec spentXrp balanceUSD offers owners
+
2383 {"ann", reserve(env, 0) + 0 * f, 1, noPreTrust, 1000, tecUNFUNDED_OFFER, f, USD( 0), 0, 0}, // Account is at the reserve, and will dip below once fees are subtracted.
+
2384 {"bev", reserve(env, 0) + 1 * f, 1, noPreTrust, 1000, tecUNFUNDED_OFFER, f, USD( 0), 0, 0}, // Account has just enough for the reserve and the fee.
+
2385 {"cam", reserve(env, 0) + 2 * f, 0, noPreTrust, 1000, tecINSUF_RESERVE_OFFER, f, USD( 0), 0, 0}, // Account has enough for the reserve, the fee and the offer, and a bit more, but not enough for the reserve after the offer is placed.
+
2386 {"deb", drops(10) + reserve(env, 0) + 1 * f, 1, noPreTrust, 1000, tesSUCCESS, drops(10) + f, USD(0.00001), 0, 1}, // Account has enough to buy a little USD then the offer runs dry.
+
2387 {"eve", reserve(env, 1) + 0 * f, 0, noPreTrust, 1000, tesSUCCESS, f, USD( 0), 1, 1}, // No offer to cross
+
2388 {"flo", reserve(env, 1) + 0 * f, 1, noPreTrust, 1000, tesSUCCESS, XRP( 1) + f, USD( 1), 0, 1},
+
2389 {"gay", reserve(env, 1) + 1 * f, 1000, noPreTrust, 1000, tesSUCCESS, XRP( 50) + f, USD( 50), 0, 1},
+
2390 {"hye", XRP(1000) + 1 * f, 1000, noPreTrust, 1000, tesSUCCESS, XRP( 800) + f, USD( 800), 0, 1},
+
2391 {"ivy", XRP( 1) + reserve(env, 1) + 1 * f, 1, noPreTrust, 1000, tesSUCCESS, XRP( 1) + f, USD( 1), 0, 1},
+
2392 {"joy", XRP( 1) + reserve(env, 2) + 1 * f, 1, noPreTrust, 1000, tesSUCCESS, XRP( 1) + f, USD( 1), 1, 2},
+
2393 {"kim", XRP( 900) + reserve(env, 2) + 1 * f, 999, noPreTrust, 1000, tesSUCCESS, XRP( 999) + f, USD( 999), 0, 1},
+
2394 {"liz", XRP( 998) + reserve(env, 0) + 1 * f, 999, noPreTrust, 1000, tesSUCCESS, XRP( 998) + f, USD( 998), 0, 1},
+
2395 {"meg", XRP( 998) + reserve(env, 1) + 1 * f, 999, noPreTrust, 1000, tesSUCCESS, XRP( 999) + f, USD( 999), 0, 1},
+
2396 {"nia", XRP( 998) + reserve(env, 2) + 1 * f, 999, noPreTrust, 1000, tesSUCCESS, XRP( 999) + f, USD( 999), 1, 2},
+
2397 {"ova", XRP( 999) + reserve(env, 0) + 1 * f, 1000, noPreTrust, 1000, tesSUCCESS, XRP( 999) + f, USD( 999), 0, 1},
+
2398 {"pam", XRP( 999) + reserve(env, 1) + 1 * f, 1000, noPreTrust, 1000, tesSUCCESS, XRP(1000) + f, USD( 1000), 0, 1},
+
2399 {"rae", XRP( 999) + reserve(env, 2) + 1 * f, 1000, noPreTrust, 1000, tesSUCCESS, XRP(1000) + f, USD( 1000), 0, 1},
+
2400 {"sue", XRP(1000) + reserve(env, 2) + 1 * f, 0, noPreTrust, 1000, tesSUCCESS, f, USD( 0), 1, 1},
+
2401 //---------------- Pre-established trust lines ---------------------
+
2402 {"abe", reserve(env, 0) + 0 * f, 1, gwPreTrust, 1000, tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
+
2403 {"bud", reserve(env, 0) + 1 * f, 1, gwPreTrust, 1000, tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
+
2404 {"che", reserve(env, 0) + 2 * f, 0, gwPreTrust, 1000, tecINSUF_RESERVE_OFFER, f, USD( 0), 0, 0},
+
2405 {"dan", drops(10) + reserve(env, 0) + 1 * f, 1, gwPreTrust, 1000, tesSUCCESS, drops(10) + f, USD(0.00001), 0, 0},
+
2406 {"eli", XRP( 20) + reserve(env, 0) + 1 * f, 1000, gwPreTrust, 1000, tesSUCCESS, XRP(20) + 1 * f, USD( 20), 0, 0},
+
2407 {"fyn", reserve(env, 1) + 0 * f, 0, gwPreTrust, 1000, tesSUCCESS, f, USD( 0), 1, 1},
+
2408 {"gar", reserve(env, 1) + 0 * f, 1, gwPreTrust, 1000, tesSUCCESS, XRP( 1) + f, USD( 1), 1, 1},
+
2409 {"hal", reserve(env, 1) + 1 * f, 1, gwPreTrust, 1000, tesSUCCESS, XRP( 1) + f, USD( 1), 1, 1},
+
2410
+
2411 {"ned", reserve(env, 1) + 0 * f, 1, acctPreTrust, 1000, tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
+
2412 {"ole", reserve(env, 1) + 1 * f, 1, acctPreTrust, 1000, tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
+
2413 {"pat", reserve(env, 1) + 2 * f, 0, acctPreTrust, 1000, tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
+
2414 {"quy", reserve(env, 1) + 2 * f, 1, acctPreTrust, 1000, tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
+
2415 {"ron", reserve(env, 1) + 3 * f, 0, acctPreTrust, 1000, tecINSUF_RESERVE_OFFER, 2 * f, USD( 0), 0, 1},
+
2416 {"syd", drops(10) + reserve(env, 1) + 2 * f, 1, acctPreTrust, 1000, tesSUCCESS, drops(10) + 2 * f, USD(0.00001), 0, 1},
+
2417 {"ted", XRP( 20) + reserve(env, 1) + 2 * f, 1000, acctPreTrust, 1000, tesSUCCESS, XRP(20) + 2 * f, USD( 20), 0, 1},
+
2418 {"uli", reserve(env, 2) + 0 * f, 0, acctPreTrust, 1000, tecINSUF_RESERVE_OFFER, 2 * f, USD( 0), 0, 1},
+
2419 {"vic", reserve(env, 2) + 0 * f, 1, acctPreTrust, 1000, tesSUCCESS, XRP( 1) + 2 * f, USD( 1), 0, 1},
+
2420 {"wes", reserve(env, 2) + 1 * f, 0, acctPreTrust, 1000, tesSUCCESS, 2 * f, USD( 0), 1, 2},
+
2421 {"xan", reserve(env, 2) + 1 * f, 1, acctPreTrust, 1000, tesSUCCESS, XRP( 1) + 2 * f, USD( 1), 1, 2},
+
2422 };
+
2423 // clang-format on
+
2424
+
2425 for (auto const& t : tests)
+
2426 {
+
2427 auto const acct = Account(t.account);
+
2428 env.fund(t.fundXrp, acct);
+
2429 env.close();
+
2430
+
2431 // Make sure gateway has no current offers.
+
2432 env.require(offers(gw, 0));
+
2433
+
2434 // The gateway optionally creates an offer that would be crossed.
+
2435 auto const book = t.bookAmount;
+
2436 if (book)
+
2437 env(offer(gw, XRP(book), USD(book)));
+
2438 env.close();
+
2439 std::uint32_t const gwOfferSeq = env.seq(gw) - 1;
2440
-
2441 // The gateway optionally creates an offer that would be crossed.
-
2442 auto const book = t.bookAmount;
-
2443 if (book)
-
2444 env(offer(gw, XRP(book), USD(book)));
-
2445 env.close();
-
2446 std::uint32_t const gwOfferSeq = env.seq(gw) - 1;
-
2447
-
2448 // Optionally pre-establish a trustline between gw and acct.
-
2449 if (t.preTrust == gwPreTrust)
-
2450 env(trust(gw, acct["USD"](1)));
+
2441 // Optionally pre-establish a trustline between gw and acct.
+
2442 if (t.preTrust == gwPreTrust)
+
2443 env(trust(gw, acct["USD"](1)));
+
2444 env.close();
+
2445
+
2446 // Optionally pre-establish a trustline between acct and gw.
+
2447 // Note this is not really part of the test, so we expect there
+
2448 // to be enough XRP reserve for acct to create the trust line.
+
2449 if (t.preTrust == acctPreTrust)
+
2450 env(trust(acct, USD(1)));
2451 env.close();
2452
-
2453 // Optionally pre-establish a trustline between acct and gw.
-
2454 // Note this is not really part of the test, so we expect there
-
2455 // to be enough XRP reserve for acct to create the trust line.
-
2456 if (t.preTrust == acctPreTrust)
-
2457 env(trust(acct, USD(1)));
-
2458 env.close();
-
2459
-
2460 {
-
2461 // Acct creates an offer. This is the heart of the test.
-
2462 auto const acctOffer = t.offerAmount;
-
2463 env(offer(acct, USD(acctOffer), XRP(acctOffer)), ter(t.tec));
-
2464 env.close();
-
2465 }
-
2466 std::uint32_t const acctOfferSeq = env.seq(acct) - 1;
-
2467
-
2468 BEAST_EXPECT(env.balance(acct, USD.issue()) == t.balanceUsd);
-
2469 BEAST_EXPECT(
-
2470 env.balance(acct, xrpIssue()) == t.fundXrp - t.spentXrp);
-
2471 env.require(offers(acct, t.offers));
-
2472 env.require(owners(acct, t.owners));
-
2473
-
2474 auto acctOffers = offersOnAccount(env, acct);
-
2475 BEAST_EXPECT(acctOffers.size() == t.offers);
-
2476 if (acctOffers.size() && t.offers)
-
2477 {
-
2478 auto const& acctOffer = *(acctOffers.front());
-
2479
-
2480 auto const leftover = t.offerAmount - t.bookAmount;
-
2481 BEAST_EXPECT(acctOffer[sfTakerGets] == XRP(leftover));
-
2482 BEAST_EXPECT(acctOffer[sfTakerPays] == USD(leftover));
-
2483 }
-
2484
-
2485 if (t.preTrust == noPreTrust)
-
2486 {
-
2487 if (t.balanceUsd.value().signum())
-
2488 {
-
2489 // Verify the correct contents of the trustline
-
2490 verifyDefaultTrustline(env, acct, t.balanceUsd);
+
2453 {
+
2454 // Acct creates an offer. This is the heart of the test.
+
2455 auto const acctOffer = t.offerAmount;
+
2456 env(offer(acct, USD(acctOffer), XRP(acctOffer)), ter(t.tec));
+
2457 env.close();
+
2458 }
+
2459 std::uint32_t const acctOfferSeq = env.seq(acct) - 1;
+
2460
+
2461 BEAST_EXPECT(env.balance(acct, USD.issue()) == t.balanceUsd);
+
2462 BEAST_EXPECT(
+
2463 env.balance(acct, xrpIssue()) == t.fundXrp - t.spentXrp);
+
2464 env.require(offers(acct, t.offers));
+
2465 env.require(owners(acct, t.owners));
+
2466
+
2467 auto acctOffers = offersOnAccount(env, acct);
+
2468 BEAST_EXPECT(acctOffers.size() == t.offers);
+
2469 if (acctOffers.size() && t.offers)
+
2470 {
+
2471 auto const& acctOffer = *(acctOffers.front());
+
2472
+
2473 auto const leftover = t.offerAmount - t.bookAmount;
+
2474 BEAST_EXPECT(acctOffer[sfTakerGets] == XRP(leftover));
+
2475 BEAST_EXPECT(acctOffer[sfTakerPays] == USD(leftover));
+
2476 }
+
2477
+
2478 if (t.preTrust == noPreTrust)
+
2479 {
+
2480 if (t.balanceUsd.value().signum())
+
2481 {
+
2482 // Verify the correct contents of the trustline
+
2483 verifyDefaultTrustline(env, acct, t.balanceUsd);
+
2484 }
+
2485 else
+
2486 {
+
2487 // Verify that no trustline was created.
+
2488 auto const sleTrust =
+
2489 env.le(keylet::line(acct, USD.issue()));
+
2490 BEAST_EXPECT(!sleTrust);
2491 }
-
2492 else
-
2493 {
-
2494 // Verify that no trustline was created.
-
2495 auto const sleTrust =
-
2496 env.le(keylet::line(acct, USD.issue()));
-
2497 BEAST_EXPECT(!sleTrust);
-
2498 }
-
2499 }
-
2500
-
2501 // Give the next loop a clean slate by canceling any left-overs
-
2502 // in the offers.
-
2503 env(offer_cancel(acct, acctOfferSeq));
-
2504 env(offer_cancel(gw, gwOfferSeq));
-
2505 env.close();
-
2506 }
-
2507 }
+
2492 }
+
2493
+
2494 // Give the next loop a clean slate by canceling any left-overs
+
2495 // in the offers.
+
2496 env(offer_cancel(acct, acctOfferSeq));
+
2497 env(offer_cancel(gw, gwOfferSeq));
+
2498 env.close();
+
2499 }
+
2500 }
+
2501
+
2502 void
+
+ +
2504 {
+
2505 testcase("XRP Direct Crossing");
+
2506
+
2507 using namespace jtx;
2508
-
2509 void
-
- -
2511 {
-
2512 testcase("XRP Direct Crossing");
+
2509 auto const gw = Account("gateway");
+
2510 auto const alice = Account("alice");
+
2511 auto const bob = Account("bob");
+
2512 auto const USD = gw["USD"];
2513
-
2514 using namespace jtx;
-
2515
-
2516 auto const gw = Account("gateway");
-
2517 auto const alice = Account("alice");
-
2518 auto const bob = Account("bob");
-
2519 auto const USD = gw["USD"];
-
2520
-
2521 auto const usdOffer = USD(1000);
-
2522 auto const xrpOffer = XRP(1000);
-
2523
-
2524 Env env{*this, features};
-
2525
-
2526 env.fund(XRP(1000000), gw, bob);
-
2527 env.close();
-
2528
-
2529 // The fee that's charged for transactions.
-
2530 auto const fee = env.current()->fees().base;
+
2514 auto const usdOffer = USD(1000);
+
2515 auto const xrpOffer = XRP(1000);
+
2516
+
2517 Env env{*this, features};
+
2518
+
2519 env.fund(XRP(1000000), gw, bob);
+
2520 env.close();
+
2521
+
2522 // The fee that's charged for transactions.
+
2523 auto const fee = env.current()->fees().base;
+
2524
+
2525 // alice's account has enough for the reserve, one trust line plus two
+
2526 // offers, and two fees.
+
2527 env.fund(reserve(env, 2) + fee * 2, alice);
+
2528 env.close();
+
2529
+
2530 env(trust(alice, usdOffer));
2531
-
2532 // alice's account has enough for the reserve, one trust line plus two
-
2533 // offers, and two fees.
-
2534 env.fund(reserve(env, 2) + fee * 2, alice);
+
2532 env.close();
+
2533
+
2534 env(pay(gw, alice, usdOffer));
2535 env.close();
-
2536
-
2537 env(trust(alice, usdOffer));
-
2538
-
2539 env.close();
-
2540
-
2541 env(pay(gw, alice, usdOffer));
-
2542 env.close();
-
2543 env.require(balance(alice, usdOffer), offers(alice, 0), offers(bob, 0));
-
2544
-
2545 // The scenario:
-
2546 // o alice has USD but wants XRP.
-
2547 // o bob has XRP but wants USD.
-
2548 auto const alicesXRP = env.balance(alice);
-
2549 auto const bobsXRP = env.balance(bob);
-
2550
-
2551 env(offer(alice, xrpOffer, usdOffer));
-
2552 env.close();
-
2553 env(offer(bob, usdOffer, xrpOffer));
-
2554
-
2555 env.close();
-
2556 env.require(
-
2557 balance(alice, USD(0)),
-
2558 balance(bob, usdOffer),
-
2559 balance(alice, alicesXRP + xrpOffer - fee),
-
2560 balance(bob, bobsXRP - xrpOffer - fee),
-
2561 offers(alice, 0),
-
2562 offers(bob, 0));
-
2563
-
2564 verifyDefaultTrustline(env, bob, usdOffer);
-
2565
-
2566 // Make two more offers that leave one of the offers non-dry.
-
2567 env(offer(alice, USD(999), XRP(999)));
-
2568 env(offer(bob, xrpOffer, usdOffer));
-
2569
-
2570 env.close();
-
2571 env.require(balance(alice, USD(999)));
-
2572 env.require(balance(bob, USD(1)));
-
2573 env.require(offers(alice, 0));
-
2574 verifyDefaultTrustline(env, bob, USD(1));
-
2575 {
-
2576 auto const bobsOffers = offersOnAccount(env, bob);
-
2577 BEAST_EXPECT(bobsOffers.size() == 1);
-
2578 auto const& bobsOffer = *(bobsOffers.front());
-
2579
-
2580 BEAST_EXPECT(bobsOffer[sfLedgerEntryType] == ltOFFER);
-
2581 BEAST_EXPECT(bobsOffer[sfTakerGets] == USD(1));
-
2582 BEAST_EXPECT(bobsOffer[sfTakerPays] == XRP(1));
-
2583 }
-
2584 }
+
2536 env.require(balance(alice, usdOffer), offers(alice, 0), offers(bob, 0));
+
2537
+
2538 // The scenario:
+
2539 // o alice has USD but wants XRP.
+
2540 // o bob has XRP but wants USD.
+
2541 auto const alicesXRP = env.balance(alice);
+
2542 auto const bobsXRP = env.balance(bob);
+
2543
+
2544 env(offer(alice, xrpOffer, usdOffer));
+
2545 env.close();
+
2546 env(offer(bob, usdOffer, xrpOffer));
+
2547
+
2548 env.close();
+
2549 env.require(
+
2550 balance(alice, USD(0)),
+
2551 balance(bob, usdOffer),
+
2552 balance(alice, alicesXRP + xrpOffer - fee),
+
2553 balance(bob, bobsXRP - xrpOffer - fee),
+
2554 offers(alice, 0),
+
2555 offers(bob, 0));
+
2556
+
2557 verifyDefaultTrustline(env, bob, usdOffer);
+
2558
+
2559 // Make two more offers that leave one of the offers non-dry.
+
2560 env(offer(alice, USD(999), XRP(999)));
+
2561 env(offer(bob, xrpOffer, usdOffer));
+
2562
+
2563 env.close();
+
2564 env.require(balance(alice, USD(999)));
+
2565 env.require(balance(bob, USD(1)));
+
2566 env.require(offers(alice, 0));
+
2567 verifyDefaultTrustline(env, bob, USD(1));
+
2568 {
+
2569 auto const bobsOffers = offersOnAccount(env, bob);
+
2570 BEAST_EXPECT(bobsOffers.size() == 1);
+
2571 auto const& bobsOffer = *(bobsOffers.front());
+
2572
+
2573 BEAST_EXPECT(bobsOffer[sfLedgerEntryType] == ltOFFER);
+
2574 BEAST_EXPECT(bobsOffer[sfTakerGets] == USD(1));
+
2575 BEAST_EXPECT(bobsOffer[sfTakerPays] == XRP(1));
+
2576 }
+
2577 }
+
2578
+
2579 void
+
+ +
2581 {
+
2582 testcase("Direct Crossing");
+
2583
+
2584 using namespace jtx;
2585
-
2586 void
-
- -
2588 {
-
2589 testcase("Direct Crossing");
-
2590
-
2591 using namespace jtx;
-
2592
-
2593 auto const gw = Account("gateway");
-
2594 auto const alice = Account("alice");
-
2595 auto const bob = Account("bob");
-
2596 auto const USD = gw["USD"];
-
2597 auto const EUR = gw["EUR"];
-
2598
-
2599 auto const usdOffer = USD(1000);
-
2600 auto const eurOffer = EUR(1000);
-
2601
-
2602 Env env{*this, features};
-
2603
-
2604 env.fund(XRP(1000000), gw);
-
2605 env.close();
-
2606
-
2607 // The fee that's charged for transactions.
-
2608 auto const fee = env.current()->fees().base;
-
2609
-
2610 // Each account has enough for the reserve, two trust lines, one
-
2611 // offer, and two fees.
-
2612 env.fund(reserve(env, 3) + fee * 3, alice);
-
2613 env.fund(reserve(env, 3) + fee * 2, bob);
-
2614 env.close();
-
2615
-
2616 env(trust(alice, usdOffer));
-
2617 env(trust(bob, eurOffer));
-
2618 env.close();
-
2619
-
2620 env(pay(gw, alice, usdOffer));
-
2621 env(pay(gw, bob, eurOffer));
-
2622 env.close();
-
2623
-
2624 env.require(balance(alice, usdOffer), balance(bob, eurOffer));
-
2625
-
2626 // The scenario:
-
2627 // o alice has USD but wants EUR.
-
2628 // o bob has EUR but wants USD.
-
2629 env(offer(alice, eurOffer, usdOffer));
-
2630 env(offer(bob, usdOffer, eurOffer));
+
2586 auto const gw = Account("gateway");
+
2587 auto const alice = Account("alice");
+
2588 auto const bob = Account("bob");
+
2589 auto const USD = gw["USD"];
+
2590 auto const EUR = gw["EUR"];
+
2591
+
2592 auto const usdOffer = USD(1000);
+
2593 auto const eurOffer = EUR(1000);
+
2594
+
2595 Env env{*this, features};
+
2596
+
2597 env.fund(XRP(1000000), gw);
+
2598 env.close();
+
2599
+
2600 // The fee that's charged for transactions.
+
2601 auto const fee = env.current()->fees().base;
+
2602
+
2603 // Each account has enough for the reserve, two trust lines, one
+
2604 // offer, and two fees.
+
2605 env.fund(reserve(env, 3) + fee * 3, alice);
+
2606 env.fund(reserve(env, 3) + fee * 2, bob);
+
2607 env.close();
+
2608
+
2609 env(trust(alice, usdOffer));
+
2610 env(trust(bob, eurOffer));
+
2611 env.close();
+
2612
+
2613 env(pay(gw, alice, usdOffer));
+
2614 env(pay(gw, bob, eurOffer));
+
2615 env.close();
+
2616
+
2617 env.require(balance(alice, usdOffer), balance(bob, eurOffer));
+
2618
+
2619 // The scenario:
+
2620 // o alice has USD but wants EUR.
+
2621 // o bob has EUR but wants USD.
+
2622 env(offer(alice, eurOffer, usdOffer));
+
2623 env(offer(bob, usdOffer, eurOffer));
+
2624
+
2625 env.close();
+
2626 env.require(
+
2627 balance(alice, eurOffer),
+
2628 balance(bob, usdOffer),
+
2629 offers(alice, 0),
+
2630 offers(bob, 0));
2631
-
2632 env.close();
-
2633 env.require(
-
2634 balance(alice, eurOffer),
-
2635 balance(bob, usdOffer),
-
2636 offers(alice, 0),
-
2637 offers(bob, 0));
-
2638
-
2639 // Alice's offer crossing created a default EUR trustline and
-
2640 // Bob's offer crossing created a default USD trustline:
-
2641 verifyDefaultTrustline(env, alice, eurOffer);
-
2642 verifyDefaultTrustline(env, bob, usdOffer);
-
2643
-
2644 // Make two more offers that leave one of the offers non-dry.
-
2645 // Guarantee the order of application by putting a close()
-
2646 // between them.
-
2647 env(offer(bob, eurOffer, usdOffer));
-
2648 env.close();
-
2649
-
2650 env(offer(alice, USD(999), eurOffer));
-
2651 env.close();
-
2652
-
2653 env.require(offers(alice, 0));
-
2654 env.require(offers(bob, 1));
-
2655
-
2656 env.require(balance(alice, USD(999)));
-
2657 env.require(balance(alice, EUR(1)));
-
2658 env.require(balance(bob, USD(1)));
-
2659 env.require(balance(bob, EUR(999)));
-
2660
-
2661 {
-
2662 auto bobsOffers = offersOnAccount(env, bob);
-
2663 if (BEAST_EXPECT(bobsOffers.size() == 1))
-
2664 {
-
2665 auto const& bobsOffer = *(bobsOffers.front());
-
2666
-
2667 BEAST_EXPECT(bobsOffer[sfTakerGets] == USD(1));
-
2668 BEAST_EXPECT(bobsOffer[sfTakerPays] == EUR(1));
-
2669 }
-
2670 }
-
2671
-
2672 // alice makes one more offer that cleans out bob's offer.
-
2673 env(offer(alice, USD(1), EUR(1)));
-
2674 env.close();
+
2632 // Alice's offer crossing created a default EUR trustline and
+
2633 // Bob's offer crossing created a default USD trustline:
+
2634 verifyDefaultTrustline(env, alice, eurOffer);
+
2635 verifyDefaultTrustline(env, bob, usdOffer);
+
2636
+
2637 // Make two more offers that leave one of the offers non-dry.
+
2638 // Guarantee the order of application by putting a close()
+
2639 // between them.
+
2640 env(offer(bob, eurOffer, usdOffer));
+
2641 env.close();
+
2642
+
2643 env(offer(alice, USD(999), eurOffer));
+
2644 env.close();
+
2645
+
2646 env.require(offers(alice, 0));
+
2647 env.require(offers(bob, 1));
+
2648
+
2649 env.require(balance(alice, USD(999)));
+
2650 env.require(balance(alice, EUR(1)));
+
2651 env.require(balance(bob, USD(1)));
+
2652 env.require(balance(bob, EUR(999)));
+
2653
+
2654 {
+
2655 auto bobsOffers = offersOnAccount(env, bob);
+
2656 if (BEAST_EXPECT(bobsOffers.size() == 1))
+
2657 {
+
2658 auto const& bobsOffer = *(bobsOffers.front());
+
2659
+
2660 BEAST_EXPECT(bobsOffer[sfTakerGets] == USD(1));
+
2661 BEAST_EXPECT(bobsOffer[sfTakerPays] == EUR(1));
+
2662 }
+
2663 }
+
2664
+
2665 // alice makes one more offer that cleans out bob's offer.
+
2666 env(offer(alice, USD(1), EUR(1)));
+
2667 env.close();
+
2668
+
2669 env.require(balance(alice, USD(1000)));
+
2670 env.require(balance(alice, EUR(none)));
+
2671 env.require(balance(bob, USD(none)));
+
2672 env.require(balance(bob, EUR(1000)));
+
2673 env.require(offers(alice, 0));
+
2674 env.require(offers(bob, 0));
2675
-
2676 env.require(balance(alice, USD(1000)));
-
2677 env.require(balance(alice, EUR(none)));
-
2678 env.require(balance(bob, USD(none)));
-
2679 env.require(balance(bob, EUR(1000)));
-
2680 env.require(offers(alice, 0));
-
2681 env.require(offers(bob, 0));
-
2682
-
2683 // The two trustlines that were generated by offers should be gone.
-
2684 BEAST_EXPECT(!env.le(keylet::line(alice.id(), EUR.issue())));
-
2685 BEAST_EXPECT(!env.le(keylet::line(bob.id(), USD.issue())));
-
2686
-
2687 // Make two more offers that leave one of the offers non-dry. We
-
2688 // need to properly sequence the transactions:
-
2689 env(offer(alice, EUR(999), usdOffer));
-
2690 env.close();
-
2691
-
2692 env(offer(bob, usdOffer, eurOffer));
-
2693 env.close();
-
2694
-
2695 env.require(offers(alice, 0));
-
2696 env.require(offers(bob, 0));
-
2697
-
2698 env.require(balance(alice, USD(0)));
-
2699 env.require(balance(alice, EUR(999)));
-
2700 env.require(balance(bob, USD(1000)));
-
2701 env.require(balance(bob, EUR(1)));
-
2702 }
+
2676 // The two trustlines that were generated by offers should be gone.
+
2677 BEAST_EXPECT(!env.le(keylet::line(alice.id(), EUR.issue())));
+
2678 BEAST_EXPECT(!env.le(keylet::line(bob.id(), USD.issue())));
+
2679
+
2680 // Make two more offers that leave one of the offers non-dry. We
+
2681 // need to properly sequence the transactions:
+
2682 env(offer(alice, EUR(999), usdOffer));
+
2683 env.close();
+
2684
+
2685 env(offer(bob, usdOffer, eurOffer));
+
2686 env.close();
+
2687
+
2688 env.require(offers(alice, 0));
+
2689 env.require(offers(bob, 0));
+
2690
+
2691 env.require(balance(alice, USD(0)));
+
2692 env.require(balance(alice, EUR(999)));
+
2693 env.require(balance(bob, USD(1000)));
+
2694 env.require(balance(bob, EUR(1)));
+
2695 }
+
2696
+
2697 void
+
+ +
2699 {
+
2700 testcase("Bridged Crossing");
+
2701
+
2702 using namespace jtx;
2703
-
2704 void
-
- -
2706 {
-
2707 testcase("Bridged Crossing");
-
2708
-
2709 using namespace jtx;
+
2704 auto const gw = Account("gateway");
+
2705 auto const alice = Account("alice");
+
2706 auto const bob = Account("bob");
+
2707 auto const carol = Account("carol");
+
2708 auto const USD = gw["USD"];
+
2709 auto const EUR = gw["EUR"];
2710
-
2711 auto const gw = Account("gateway");
-
2712 auto const alice = Account("alice");
-
2713 auto const bob = Account("bob");
-
2714 auto const carol = Account("carol");
-
2715 auto const USD = gw["USD"];
-
2716 auto const EUR = gw["EUR"];
-
2717
-
2718 auto const usdOffer = USD(1000);
-
2719 auto const eurOffer = EUR(1000);
-
2720
-
2721 Env env{*this, features};
-
2722
-
2723 env.fund(XRP(1000000), gw, alice, bob, carol);
+
2711 auto const usdOffer = USD(1000);
+
2712 auto const eurOffer = EUR(1000);
+
2713
+
2714 Env env{*this, features};
+
2715
+
2716 env.fund(XRP(1000000), gw, alice, bob, carol);
+
2717 env.close();
+
2718
+
2719 env(trust(alice, usdOffer));
+
2720 env(trust(carol, eurOffer));
+
2721 env.close();
+
2722 env(pay(gw, alice, usdOffer));
+
2723 env(pay(gw, carol, eurOffer));
2724 env.close();
2725
-
2726 env(trust(alice, usdOffer));
-
2727 env(trust(carol, eurOffer));
-
2728 env.close();
-
2729 env(pay(gw, alice, usdOffer));
-
2730 env(pay(gw, carol, eurOffer));
-
2731 env.close();
-
2732
-
2733 // The scenario:
-
2734 // o alice has USD but wants XRP.
-
2735 // o bob has XRP but wants EUR.
-
2736 // o carol has EUR but wants USD.
-
2737 // Note that carol's offer must come last. If carol's offer is placed
-
2738 // before bob's or alice's, then autobridging will not occur.
-
2739 env(offer(alice, XRP(1000), usdOffer));
-
2740 env(offer(bob, eurOffer, XRP(1000)));
-
2741 auto const bobXrpBalance = env.balance(bob);
-
2742 env.close();
-
2743
-
2744 // carol makes an offer that partially consumes alice and bob's offers.
-
2745 env(offer(carol, USD(400), EUR(400)));
-
2746 env.close();
-
2747
-
2748 env.require(
-
2749 balance(alice, USD(600)),
-
2750 balance(bob, EUR(400)),
-
2751 balance(carol, USD(400)),
-
2752 balance(bob, bobXrpBalance - XRP(400)),
-
2753 offers(carol, 0));
-
2754 verifyDefaultTrustline(env, bob, EUR(400));
-
2755 verifyDefaultTrustline(env, carol, USD(400));
-
2756 {
-
2757 auto const alicesOffers = offersOnAccount(env, alice);
-
2758 BEAST_EXPECT(alicesOffers.size() == 1);
-
2759 auto const& alicesOffer = *(alicesOffers.front());
-
2760
-
2761 BEAST_EXPECT(alicesOffer[sfLedgerEntryType] == ltOFFER);
-
2762 BEAST_EXPECT(alicesOffer[sfTakerGets] == USD(600));
-
2763 BEAST_EXPECT(alicesOffer[sfTakerPays] == XRP(600));
-
2764 }
-
2765 {
-
2766 auto const bobsOffers = offersOnAccount(env, bob);
-
2767 BEAST_EXPECT(bobsOffers.size() == 1);
-
2768 auto const& bobsOffer = *(bobsOffers.front());
-
2769
-
2770 BEAST_EXPECT(bobsOffer[sfLedgerEntryType] == ltOFFER);
-
2771 BEAST_EXPECT(bobsOffer[sfTakerGets] == XRP(600));
-
2772 BEAST_EXPECT(bobsOffer[sfTakerPays] == EUR(600));
-
2773 }
-
2774
-
2775 // carol makes an offer that exactly consumes alice and bob's offers.
-
2776 env(offer(carol, USD(600), EUR(600)));
-
2777 env.close();
-
2778
-
2779 env.require(
-
2780 balance(alice, USD(0)),
-
2781 balance(bob, eurOffer),
-
2782 balance(carol, usdOffer),
-
2783 balance(bob, bobXrpBalance - XRP(1000)),
-
2784 offers(bob, 0),
-
2785 offers(carol, 0));
-
2786 verifyDefaultTrustline(env, bob, EUR(1000));
-
2787 verifyDefaultTrustline(env, carol, USD(1000));
+
2726 // The scenario:
+
2727 // o alice has USD but wants XRP.
+
2728 // o bob has XRP but wants EUR.
+
2729 // o carol has EUR but wants USD.
+
2730 // Note that carol's offer must come last. If carol's offer is placed
+
2731 // before bob's or alice's, then autobridging will not occur.
+
2732 env(offer(alice, XRP(1000), usdOffer));
+
2733 env(offer(bob, eurOffer, XRP(1000)));
+
2734 auto const bobXrpBalance = env.balance(bob);
+
2735 env.close();
+
2736
+
2737 // carol makes an offer that partially consumes alice and bob's offers.
+
2738 env(offer(carol, USD(400), EUR(400)));
+
2739 env.close();
+
2740
+
2741 env.require(
+
2742 balance(alice, USD(600)),
+
2743 balance(bob, EUR(400)),
+
2744 balance(carol, USD(400)),
+
2745 balance(bob, bobXrpBalance - XRP(400)),
+
2746 offers(carol, 0));
+
2747 verifyDefaultTrustline(env, bob, EUR(400));
+
2748 verifyDefaultTrustline(env, carol, USD(400));
+
2749 {
+
2750 auto const alicesOffers = offersOnAccount(env, alice);
+
2751 BEAST_EXPECT(alicesOffers.size() == 1);
+
2752 auto const& alicesOffer = *(alicesOffers.front());
+
2753
+
2754 BEAST_EXPECT(alicesOffer[sfLedgerEntryType] == ltOFFER);
+
2755 BEAST_EXPECT(alicesOffer[sfTakerGets] == USD(600));
+
2756 BEAST_EXPECT(alicesOffer[sfTakerPays] == XRP(600));
+
2757 }
+
2758 {
+
2759 auto const bobsOffers = offersOnAccount(env, bob);
+
2760 BEAST_EXPECT(bobsOffers.size() == 1);
+
2761 auto const& bobsOffer = *(bobsOffers.front());
+
2762
+
2763 BEAST_EXPECT(bobsOffer[sfLedgerEntryType] == ltOFFER);
+
2764 BEAST_EXPECT(bobsOffer[sfTakerGets] == XRP(600));
+
2765 BEAST_EXPECT(bobsOffer[sfTakerPays] == EUR(600));
+
2766 }
+
2767
+
2768 // carol makes an offer that exactly consumes alice and bob's offers.
+
2769 env(offer(carol, USD(600), EUR(600)));
+
2770 env.close();
+
2771
+
2772 env.require(
+
2773 balance(alice, USD(0)),
+
2774 balance(bob, eurOffer),
+
2775 balance(carol, usdOffer),
+
2776 balance(bob, bobXrpBalance - XRP(1000)),
+
2777 offers(bob, 0),
+
2778 offers(carol, 0));
+
2779 verifyDefaultTrustline(env, bob, EUR(1000));
+
2780 verifyDefaultTrustline(env, carol, USD(1000));
+
2781
+
2782 // In pre-flow code alice's offer is left empty in the ledger.
+
2783 auto const alicesOffers = offersOnAccount(env, alice);
+
2784 if (alicesOffers.size() != 0)
+
2785 {
+
2786 BEAST_EXPECT(alicesOffers.size() == 1);
+
2787 auto const& alicesOffer = *(alicesOffers.front());
2788
-
2789 // In pre-flow code alice's offer is left empty in the ledger.
-
2790 auto const alicesOffers = offersOnAccount(env, alice);
-
2791 if (alicesOffers.size() != 0)
-
2792 {
-
2793 BEAST_EXPECT(alicesOffers.size() == 1);
-
2794 auto const& alicesOffer = *(alicesOffers.front());
-
2795
-
2796 BEAST_EXPECT(alicesOffer[sfLedgerEntryType] == ltOFFER);
-
2797 BEAST_EXPECT(alicesOffer[sfTakerGets] == USD(0));
-
2798 BEAST_EXPECT(alicesOffer[sfTakerPays] == XRP(0));
-
2799 }
-
2800 }
+
2789 BEAST_EXPECT(alicesOffer[sfLedgerEntryType] == ltOFFER);
+
2790 BEAST_EXPECT(alicesOffer[sfTakerGets] == USD(0));
+
2791 BEAST_EXPECT(alicesOffer[sfTakerPays] == XRP(0));
+
2792 }
+
2793 }
-
2801
-
2802 void
-
- -
2804 {
-
2805 // Test a number of different corner cases regarding offer crossing
-
2806 // when the tfSell flag is set. The test is table driven so it
-
2807 // should be easy to add or remove tests.
-
2808 testcase("Sell Offer");
+
2794
+
2795 void
+
+ +
2797 {
+
2798 // Test a number of different corner cases regarding offer crossing
+
2799 // when the tfSell flag is set. The test is table driven so it
+
2800 // should be easy to add or remove tests.
+
2801 testcase("Sell Offer");
+
2802
+
2803 using namespace jtx;
+
2804
+
2805 auto const gw = Account("gateway");
+
2806 auto const USD = gw["USD"];
+
2807
+
2808 Env env{*this, features};
2809
-
2810 using namespace jtx;
-
2811
-
2812 auto const gw = Account("gateway");
-
2813 auto const USD = gw["USD"];
-
2814
-
2815 Env env{*this, features};
-
2816
-
2817 env.fund(XRP(10000000), gw);
-
2818 env.close();
-
2819
-
2820 // The fee that's charged for transactions
-
2821 auto const f = env.current()->fees().base;
-
2822
-
2823 // To keep things simple all offers are 1 : 1 for XRP : USD.
-
2824 enum preTrustType { noPreTrust, gwPreTrust, acctPreTrust };
-
2825 struct TestData
-
2826 {
-
2827 std::string account; // Account operated on
-
2828 STAmount fundXrp; // XRP acct funded with
-
2829 STAmount fundUSD; // USD acct funded with
-
2830 STAmount gwGets; // gw's offer
-
2831 STAmount gwPays; //
-
2832 STAmount acctGets; // acct's offer
-
2833 STAmount acctPays; //
-
2834 TER tec; // Returned tec code
-
2835 STAmount spentXrp; // Amount removed from fundXrp
-
2836 STAmount finalUsd; // Final USD balance on acct
-
2837 int offers; // Offers on acct
-
2838 int owners; // Owners on acct
-
2839 STAmount takerGets; // Remainder of acct's offer
-
2840 STAmount takerPays; //
-
2841
-
2842 // Constructor with takerGets/takerPays
-
2843 TestData(
-
2844 std::string&& account_, // Account operated on
-
2845 STAmount const& fundXrp_, // XRP acct funded with
-
2846 STAmount const& fundUSD_, // USD acct funded with
-
2847 STAmount const& gwGets_, // gw's offer
-
2848 STAmount const& gwPays_, //
-
2849 STAmount const& acctGets_, // acct's offer
-
2850 STAmount const& acctPays_, //
-
2851 TER tec_, // Returned tec code
-
2852 STAmount const& spentXrp_, // Amount removed from fundXrp
-
2853 STAmount const& finalUsd_, // Final USD balance on acct
-
2854 int offers_, // Offers on acct
-
2855 int owners_, // Owners on acct
-
2856 STAmount const& takerGets_, // Remainder of acct's offer
-
2857 STAmount const& takerPays_) //
-
2858 : account(std::move(account_))
-
2859 , fundXrp(fundXrp_)
-
2860 , fundUSD(fundUSD_)
-
2861 , gwGets(gwGets_)
-
2862 , gwPays(gwPays_)
-
2863 , acctGets(acctGets_)
-
2864 , acctPays(acctPays_)
-
2865 , tec(tec_)
-
2866 , spentXrp(spentXrp_)
-
2867 , finalUsd(finalUsd_)
-
2868 , offers(offers_)
-
2869 , owners(owners_)
-
2870 , takerGets(takerGets_)
-
2871 , takerPays(takerPays_)
-
2872 {
-
2873 }
-
2874
-
2875 // Constructor without takerGets/takerPays
-
2876 TestData(
-
2877 std::string&& account_, // Account operated on
-
2878 STAmount const& fundXrp_, // XRP acct funded with
-
2879 STAmount const& fundUSD_, // USD acct funded with
-
2880 STAmount const& gwGets_, // gw's offer
-
2881 STAmount const& gwPays_, //
-
2882 STAmount const& acctGets_, // acct's offer
-
2883 STAmount const& acctPays_, //
-
2884 TER tec_, // Returned tec code
-
2885 STAmount const& spentXrp_, // Amount removed from fundXrp
-
2886 STAmount const& finalUsd_, // Final USD balance on acct
-
2887 int offers_, // Offers on acct
-
2888 int owners_) // Owners on acct
-
2889 : TestData(
-
2890 std::move(account_),
-
2891 fundXrp_,
-
2892 fundUSD_,
-
2893 gwGets_,
-
2894 gwPays_,
-
2895 acctGets_,
-
2896 acctPays_,
-
2897 tec_,
-
2898 spentXrp_,
-
2899 finalUsd_,
-
2900 offers_,
-
2901 owners_,
-
2902 STAmount{0},
-
2903 STAmount{0})
-
2904 {
-
2905 }
-
2906 };
-
2907
-
2908 // clang-format off
-
2909 TestData const tests[]{
-
2910 // acct pays XRP
-
2911 // acct fundXrp fundUSD gwGets gwPays acctGets acctPays tec spentXrp finalUSD offers owners takerGets takerPays
-
2912 {"ann", XRP(10) + reserve(env, 0) + 1 * f, USD( 0), XRP(10), USD( 5), USD(10), XRP(10), tecINSUF_RESERVE_OFFER, XRP( 0) + (1 * f), USD( 0), 0, 0},
-
2913 {"bev", XRP(10) + reserve(env, 1) + 1 * f, USD( 0), XRP(10), USD( 5), USD(10), XRP(10), tesSUCCESS, XRP( 0) + (1 * f), USD( 0), 1, 1, XRP(10), USD(10)},
-
2914 {"cam", XRP(10) + reserve(env, 0) + 1 * f, USD( 0), XRP(10), USD(10), USD(10), XRP(10), tesSUCCESS, XRP( 10) + (1 * f), USD(10), 0, 1},
-
2915 {"deb", XRP(10) + reserve(env, 0) + 1 * f, USD( 0), XRP(10), USD(20), USD(10), XRP(10), tesSUCCESS, XRP( 10) + (1 * f), USD(20), 0, 1},
-
2916 {"eve", XRP(10) + reserve(env, 0) + 1 * f, USD( 0), XRP(10), USD(20), USD( 5), XRP( 5), tesSUCCESS, XRP( 5) + (1 * f), USD(10), 0, 1},
-
2917 {"flo", XRP(10) + reserve(env, 0) + 1 * f, USD( 0), XRP(10), USD(20), USD(20), XRP(20), tesSUCCESS, XRP( 10) + (1 * f), USD(20), 0, 1},
-
2918 {"gay", XRP(20) + reserve(env, 1) + 1 * f, USD( 0), XRP(10), USD(20), USD(20), XRP(20), tesSUCCESS, XRP( 10) + (1 * f), USD(20), 0, 1},
-
2919 {"hye", XRP(20) + reserve(env, 2) + 1 * f, USD( 0), XRP(10), USD(20), USD(20), XRP(20), tesSUCCESS, XRP( 10) + (1 * f), USD(20), 1, 2, XRP(10), USD(10)},
-
2920 // acct pays USD
-
2921 {"meg", reserve(env, 1) + 2 * f, USD(10), USD(10), XRP( 5), XRP(10), USD(10), tecINSUF_RESERVE_OFFER, XRP( 0) + (2 * f), USD(10), 0, 1},
-
2922 {"nia", reserve(env, 2) + 2 * f, USD(10), USD(10), XRP( 5), XRP(10), USD(10), tesSUCCESS, XRP( 0) + (2 * f), USD(10), 1, 2, USD(10), XRP(10)},
-
2923 {"ova", reserve(env, 1) + 2 * f, USD(10), USD(10), XRP(10), XRP(10), USD(10), tesSUCCESS, XRP(-10) + (2 * f), USD( 0), 0, 1},
-
2924 {"pam", reserve(env, 1) + 2 * f, USD(10), USD(10), XRP(20), XRP(10), USD(10), tesSUCCESS, XRP(-20) + (2 * f), USD( 0), 0, 1},
-
2925 {"qui", reserve(env, 1) + 2 * f, USD(10), USD(20), XRP(40), XRP(10), USD(10), tesSUCCESS, XRP(-20) + (2 * f), USD( 0), 0, 1},
-
2926 {"rae", reserve(env, 2) + 2 * f, USD(10), USD( 5), XRP( 5), XRP(10), USD(10), tesSUCCESS, XRP( -5) + (2 * f), USD( 5), 1, 2, USD( 5), XRP( 5)},
-
2927 {"sue", reserve(env, 2) + 2 * f, USD(10), USD( 5), XRP(10), XRP(10), USD(10), tesSUCCESS, XRP(-10) + (2 * f), USD( 5), 1, 2, USD( 5), XRP( 5)},
-
2928 };
-
2929 // clang-format on
-
2930
-
2931 auto const zeroUsd = USD(0);
-
2932 for (auto const& t : tests)
-
2933 {
-
2934 // Make sure gateway has no current offers.
-
2935 env.require(offers(gw, 0));
-
2936
-
2937 auto const acct = Account(t.account);
-
2938
-
2939 env.fund(t.fundXrp, acct);
-
2940 env.close();
-
2941
-
2942 // Optionally give acct some USD. This is not part of the test,
-
2943 // so we assume that acct has sufficient USD to cover the reserve
-
2944 // on the trust line.
-
2945 if (t.fundUSD != zeroUsd)
-
2946 {
-
2947 env(trust(acct, t.fundUSD));
-
2948 env.close();
-
2949 env(pay(gw, acct, t.fundUSD));
-
2950 env.close();
-
2951 }
-
2952
-
2953 env(offer(gw, t.gwGets, t.gwPays));
-
2954 env.close();
-
2955 std::uint32_t const gwOfferSeq = env.seq(gw) - 1;
-
2956
-
2957 // Acct creates a tfSell offer. This is the heart of the test.
-
2958 env(offer(acct, t.acctGets, t.acctPays, tfSell), ter(t.tec));
-
2959 env.close();
-
2960 std::uint32_t const acctOfferSeq = env.seq(acct) - 1;
+
2810 env.fund(XRP(10000000), gw);
+
2811 env.close();
+
2812
+
2813 // The fee that's charged for transactions
+
2814 auto const f = env.current()->fees().base;
+
2815
+
2816 // To keep things simple all offers are 1 : 1 for XRP : USD.
+
2817 enum preTrustType { noPreTrust, gwPreTrust, acctPreTrust };
+
2818 struct TestData
+
2819 {
+
2820 std::string account; // Account operated on
+
2821 STAmount fundXrp; // XRP acct funded with
+
2822 STAmount fundUSD; // USD acct funded with
+
2823 STAmount gwGets; // gw's offer
+
2824 STAmount gwPays; //
+
2825 STAmount acctGets; // acct's offer
+
2826 STAmount acctPays; //
+
2827 TER tec; // Returned tec code
+
2828 STAmount spentXrp; // Amount removed from fundXrp
+
2829 STAmount finalUsd; // Final USD balance on acct
+
2830 int offers; // Offers on acct
+
2831 int owners; // Owners on acct
+
2832 STAmount takerGets; // Remainder of acct's offer
+
2833 STAmount takerPays; //
+
2834
+
2835 // Constructor with takerGets/takerPays
+
2836 TestData(
+
2837 std::string&& account_, // Account operated on
+
2838 STAmount const& fundXrp_, // XRP acct funded with
+
2839 STAmount const& fundUSD_, // USD acct funded with
+
2840 STAmount const& gwGets_, // gw's offer
+
2841 STAmount const& gwPays_, //
+
2842 STAmount const& acctGets_, // acct's offer
+
2843 STAmount const& acctPays_, //
+
2844 TER tec_, // Returned tec code
+
2845 STAmount const& spentXrp_, // Amount removed from fundXrp
+
2846 STAmount const& finalUsd_, // Final USD balance on acct
+
2847 int offers_, // Offers on acct
+
2848 int owners_, // Owners on acct
+
2849 STAmount const& takerGets_, // Remainder of acct's offer
+
2850 STAmount const& takerPays_) //
+
2851 : account(std::move(account_))
+
2852 , fundXrp(fundXrp_)
+
2853 , fundUSD(fundUSD_)
+
2854 , gwGets(gwGets_)
+
2855 , gwPays(gwPays_)
+
2856 , acctGets(acctGets_)
+
2857 , acctPays(acctPays_)
+
2858 , tec(tec_)
+
2859 , spentXrp(spentXrp_)
+
2860 , finalUsd(finalUsd_)
+
2861 , offers(offers_)
+
2862 , owners(owners_)
+
2863 , takerGets(takerGets_)
+
2864 , takerPays(takerPays_)
+
2865 {
+
2866 }
+
2867
+
2868 // Constructor without takerGets/takerPays
+
2869 TestData(
+
2870 std::string&& account_, // Account operated on
+
2871 STAmount const& fundXrp_, // XRP acct funded with
+
2872 STAmount const& fundUSD_, // USD acct funded with
+
2873 STAmount const& gwGets_, // gw's offer
+
2874 STAmount const& gwPays_, //
+
2875 STAmount const& acctGets_, // acct's offer
+
2876 STAmount const& acctPays_, //
+
2877 TER tec_, // Returned tec code
+
2878 STAmount const& spentXrp_, // Amount removed from fundXrp
+
2879 STAmount const& finalUsd_, // Final USD balance on acct
+
2880 int offers_, // Offers on acct
+
2881 int owners_) // Owners on acct
+
2882 : TestData(
+
2883 std::move(account_),
+
2884 fundXrp_,
+
2885 fundUSD_,
+
2886 gwGets_,
+
2887 gwPays_,
+
2888 acctGets_,
+
2889 acctPays_,
+
2890 tec_,
+
2891 spentXrp_,
+
2892 finalUsd_,
+
2893 offers_,
+
2894 owners_,
+
2895 STAmount{0},
+
2896 STAmount{0})
+
2897 {
+
2898 }
+
2899 };
+
2900
+
2901 // clang-format off
+
2902 TestData const tests[]{
+
2903 // acct pays XRP
+
2904 // acct fundXrp fundUSD gwGets gwPays acctGets acctPays tec spentXrp finalUSD offers owners takerGets takerPays
+
2905 {"ann", XRP(10) + reserve(env, 0) + 1 * f, USD( 0), XRP(10), USD( 5), USD(10), XRP(10), tecINSUF_RESERVE_OFFER, XRP( 0) + (1 * f), USD( 0), 0, 0},
+
2906 {"bev", XRP(10) + reserve(env, 1) + 1 * f, USD( 0), XRP(10), USD( 5), USD(10), XRP(10), tesSUCCESS, XRP( 0) + (1 * f), USD( 0), 1, 1, XRP(10), USD(10)},
+
2907 {"cam", XRP(10) + reserve(env, 0) + 1 * f, USD( 0), XRP(10), USD(10), USD(10), XRP(10), tesSUCCESS, XRP( 10) + (1 * f), USD(10), 0, 1},
+
2908 {"deb", XRP(10) + reserve(env, 0) + 1 * f, USD( 0), XRP(10), USD(20), USD(10), XRP(10), tesSUCCESS, XRP( 10) + (1 * f), USD(20), 0, 1},
+
2909 {"eve", XRP(10) + reserve(env, 0) + 1 * f, USD( 0), XRP(10), USD(20), USD( 5), XRP( 5), tesSUCCESS, XRP( 5) + (1 * f), USD(10), 0, 1},
+
2910 {"flo", XRP(10) + reserve(env, 0) + 1 * f, USD( 0), XRP(10), USD(20), USD(20), XRP(20), tesSUCCESS, XRP( 10) + (1 * f), USD(20), 0, 1},
+
2911 {"gay", XRP(20) + reserve(env, 1) + 1 * f, USD( 0), XRP(10), USD(20), USD(20), XRP(20), tesSUCCESS, XRP( 10) + (1 * f), USD(20), 0, 1},
+
2912 {"hye", XRP(20) + reserve(env, 2) + 1 * f, USD( 0), XRP(10), USD(20), USD(20), XRP(20), tesSUCCESS, XRP( 10) + (1 * f), USD(20), 1, 2, XRP(10), USD(10)},
+
2913 // acct pays USD
+
2914 {"meg", reserve(env, 1) + 2 * f, USD(10), USD(10), XRP( 5), XRP(10), USD(10), tecINSUF_RESERVE_OFFER, XRP( 0) + (2 * f), USD(10), 0, 1},
+
2915 {"nia", reserve(env, 2) + 2 * f, USD(10), USD(10), XRP( 5), XRP(10), USD(10), tesSUCCESS, XRP( 0) + (2 * f), USD(10), 1, 2, USD(10), XRP(10)},
+
2916 {"ova", reserve(env, 1) + 2 * f, USD(10), USD(10), XRP(10), XRP(10), USD(10), tesSUCCESS, XRP(-10) + (2 * f), USD( 0), 0, 1},
+
2917 {"pam", reserve(env, 1) + 2 * f, USD(10), USD(10), XRP(20), XRP(10), USD(10), tesSUCCESS, XRP(-20) + (2 * f), USD( 0), 0, 1},
+
2918 {"qui", reserve(env, 1) + 2 * f, USD(10), USD(20), XRP(40), XRP(10), USD(10), tesSUCCESS, XRP(-20) + (2 * f), USD( 0), 0, 1},
+
2919 {"rae", reserve(env, 2) + 2 * f, USD(10), USD( 5), XRP( 5), XRP(10), USD(10), tesSUCCESS, XRP( -5) + (2 * f), USD( 5), 1, 2, USD( 5), XRP( 5)},
+
2920 {"sue", reserve(env, 2) + 2 * f, USD(10), USD( 5), XRP(10), XRP(10), USD(10), tesSUCCESS, XRP(-10) + (2 * f), USD( 5), 1, 2, USD( 5), XRP( 5)},
+
2921 };
+
2922 // clang-format on
+
2923
+
2924 auto const zeroUsd = USD(0);
+
2925 for (auto const& t : tests)
+
2926 {
+
2927 // Make sure gateway has no current offers.
+
2928 env.require(offers(gw, 0));
+
2929
+
2930 auto const acct = Account(t.account);
+
2931
+
2932 env.fund(t.fundXrp, acct);
+
2933 env.close();
+
2934
+
2935 // Optionally give acct some USD. This is not part of the test,
+
2936 // so we assume that acct has sufficient USD to cover the reserve
+
2937 // on the trust line.
+
2938 if (t.fundUSD != zeroUsd)
+
2939 {
+
2940 env(trust(acct, t.fundUSD));
+
2941 env.close();
+
2942 env(pay(gw, acct, t.fundUSD));
+
2943 env.close();
+
2944 }
+
2945
+
2946 env(offer(gw, t.gwGets, t.gwPays));
+
2947 env.close();
+
2948 std::uint32_t const gwOfferSeq = env.seq(gw) - 1;
+
2949
+
2950 // Acct creates a tfSell offer. This is the heart of the test.
+
2951 env(offer(acct, t.acctGets, t.acctPays, tfSell), ter(t.tec));
+
2952 env.close();
+
2953 std::uint32_t const acctOfferSeq = env.seq(acct) - 1;
+
2954
+
2955 // Check results
+
2956 BEAST_EXPECT(env.balance(acct, USD.issue()) == t.finalUsd);
+
2957 BEAST_EXPECT(
+
2958 env.balance(acct, xrpIssue()) == t.fundXrp - t.spentXrp);
+
2959 env.require(offers(acct, t.offers));
+
2960 env.require(owners(acct, t.owners));
2961
-
2962 // Check results
-
2963 BEAST_EXPECT(env.balance(acct, USD.issue()) == t.finalUsd);
-
2964 BEAST_EXPECT(
-
2965 env.balance(acct, xrpIssue()) == t.fundXrp - t.spentXrp);
-
2966 env.require(offers(acct, t.offers));
-
2967 env.require(owners(acct, t.owners));
-
2968
-
2969 if (t.offers)
-
2970 {
-
2971 auto const acctOffers = offersOnAccount(env, acct);
-
2972 if (acctOffers.size() > 0)
-
2973 {
-
2974 BEAST_EXPECT(acctOffers.size() == 1);
-
2975 auto const& acctOffer = *(acctOffers.front());
-
2976
-
2977 BEAST_EXPECT(acctOffer[sfLedgerEntryType] == ltOFFER);
-
2978 BEAST_EXPECT(acctOffer[sfTakerGets] == t.takerGets);
-
2979 BEAST_EXPECT(acctOffer[sfTakerPays] == t.takerPays);
-
2980 }
-
2981 }
-
2982
-
2983 // Give the next loop a clean slate by canceling any left-overs
-
2984 // in the offers.
-
2985 env(offer_cancel(acct, acctOfferSeq));
-
2986 env(offer_cancel(gw, gwOfferSeq));
-
2987 env.close();
-
2988 }
-
2989 }
+
2962 if (t.offers)
+
2963 {
+
2964 auto const acctOffers = offersOnAccount(env, acct);
+
2965 if (acctOffers.size() > 0)
+
2966 {
+
2967 BEAST_EXPECT(acctOffers.size() == 1);
+
2968 auto const& acctOffer = *(acctOffers.front());
+
2969
+
2970 BEAST_EXPECT(acctOffer[sfLedgerEntryType] == ltOFFER);
+
2971 BEAST_EXPECT(acctOffer[sfTakerGets] == t.takerGets);
+
2972 BEAST_EXPECT(acctOffer[sfTakerPays] == t.takerPays);
+
2973 }
+
2974 }
+
2975
+
2976 // Give the next loop a clean slate by canceling any left-overs
+
2977 // in the offers.
+
2978 env(offer_cancel(acct, acctOfferSeq));
+
2979 env(offer_cancel(gw, gwOfferSeq));
+
2980 env.close();
+
2981 }
+
2982 }
+
2983
+
2984 void
+
+ +
2986 {
+
2987 // Test a number of different corner cases regarding offer crossing
+
2988 // when both the tfSell flag and tfFillOrKill flags are set.
+
2989 testcase("Combine tfSell with tfFillOrKill");
2990
-
2991 void
-
- -
2993 {
-
2994 // Test a number of different corner cases regarding offer crossing
-
2995 // when both the tfSell flag and tfFillOrKill flags are set.
-
2996 testcase("Combine tfSell with tfFillOrKill");
+
2991 using namespace jtx;
+
2992
+
2993 auto const gw = Account("gateway");
+
2994 auto const alice = Account("alice");
+
2995 auto const bob = Account("bob");
+
2996 auto const USD = gw["USD"];
2997
-
2998 using namespace jtx;
+
2998 Env env{*this, features};
2999
-
3000 auto const gw = Account("gateway");
-
3001 auto const alice = Account("alice");
-
3002 auto const bob = Account("bob");
-
3003 auto const USD = gw["USD"];
-
3004
-
3005 Env env{*this, features};
-
3006
-
3007 env.fund(XRP(10000000), gw, alice, bob);
+
3000 env.fund(XRP(10000000), gw, alice, bob);
+
3001 env.close();
+
3002
+
3003 // Code returned if an offer is killed.
+
3004 TER const killedCode{TER{tecKILLED}};
+
3005
+
3006 // bob offers XRP for USD.
+
3007 env(trust(bob, USD(200)));
3008 env.close();
-
3009
-
3010 // Code returned if an offer is killed.
-
3011 TER const killedCode{
-
3012 features[fix1578] ? TER{tecKILLED} : TER{tesSUCCESS}};
-
3013
-
3014 // bob offers XRP for USD.
-
3015 env(trust(bob, USD(200)));
-
3016 env.close();
-
3017 env(pay(gw, bob, USD(100)));
-
3018 env.close();
-
3019 env(offer(bob, XRP(2000), USD(20)));
-
3020 env.close();
-
3021 {
-
3022 // alice submits a tfSell | tfFillOrKill offer that does not cross.
-
3023 env(offer(alice, USD(21), XRP(2100), tfSell | tfFillOrKill),
-
3024 ter(killedCode));
-
3025 env.close();
-
3026 env.require(balance(alice, USD(none)));
-
3027 env.require(offers(alice, 0));
-
3028 env.require(balance(bob, USD(100)));
-
3029 }
-
3030 {
-
3031 // alice submits a tfSell | tfFillOrKill offer that crosses.
-
3032 // Even though tfSell is present it doesn't matter this time.
-
3033 env(offer(alice, USD(20), XRP(2000), tfSell | tfFillOrKill));
-
3034 env.close();
-
3035 env.require(balance(alice, USD(20)));
-
3036 env.require(offers(alice, 0));
-
3037 env.require(balance(bob, USD(80)));
-
3038 }
-
3039 {
-
3040 // alice submits a tfSell | tfFillOrKill offer that crosses and
-
3041 // returns more than was asked for (because of the tfSell flag).
-
3042 env(offer(bob, XRP(2000), USD(20)));
-
3043 env.close();
-
3044 env(offer(alice, USD(10), XRP(1500), tfSell | tfFillOrKill));
-
3045 env.close();
-
3046 env.require(balance(alice, USD(35)));
-
3047 env.require(offers(alice, 0));
-
3048 env.require(balance(bob, USD(65)));
-
3049 }
-
3050 {
-
3051 // alice submits a tfSell | tfFillOrKill offer that doesn't cross.
-
3052 // This would have succeeded with a regular tfSell, but the
-
3053 // fillOrKill prevents the transaction from crossing since not
-
3054 // all of the offer is consumed.
-
3055
-
3056 // We're using bob's left-over offer for XRP(500), USD(5)
-
3057 env(offer(alice, USD(1), XRP(501), tfSell | tfFillOrKill),
-
3058 ter(killedCode));
-
3059 env.close();
-
3060 env.require(balance(alice, USD(35)));
-
3061 env.require(offers(alice, 0));
-
3062 env.require(balance(bob, USD(65)));
-
3063 }
-
3064 {
-
3065 // Alice submits a tfSell | tfFillOrKill offer that finishes
-
3066 // off the remainder of bob's offer.
-
3067
-
3068 // We're using bob's left-over offer for XRP(500), USD(5)
-
3069 env(offer(alice, USD(1), XRP(500), tfSell | tfFillOrKill));
-
3070 env.close();
-
3071 env.require(balance(alice, USD(40)));
-
3072 env.require(offers(alice, 0));
-
3073 env.require(balance(bob, USD(60)));
-
3074 }
-
3075 }
+
3009 env(pay(gw, bob, USD(100)));
+
3010 env.close();
+
3011 env(offer(bob, XRP(2000), USD(20)));
+
3012 env.close();
+
3013 {
+
3014 // alice submits a tfSell | tfFillOrKill offer that does not cross.
+
3015 env(offer(alice, USD(21), XRP(2100), tfSell | tfFillOrKill),
+
3016 ter(killedCode));
+
3017 env.close();
+
3018 env.require(balance(alice, USD(none)));
+
3019 env.require(offers(alice, 0));
+
3020 env.require(balance(bob, USD(100)));
+
3021 }
+
3022 {
+
3023 // alice submits a tfSell | tfFillOrKill offer that crosses.
+
3024 // Even though tfSell is present it doesn't matter this time.
+
3025 env(offer(alice, USD(20), XRP(2000), tfSell | tfFillOrKill));
+
3026 env.close();
+
3027 env.require(balance(alice, USD(20)));
+
3028 env.require(offers(alice, 0));
+
3029 env.require(balance(bob, USD(80)));
+
3030 }
+
3031 {
+
3032 // alice submits a tfSell | tfFillOrKill offer that crosses and
+
3033 // returns more than was asked for (because of the tfSell flag).
+
3034 env(offer(bob, XRP(2000), USD(20)));
+
3035 env.close();
+
3036 env(offer(alice, USD(10), XRP(1500), tfSell | tfFillOrKill));
+
3037 env.close();
+
3038 env.require(balance(alice, USD(35)));
+
3039 env.require(offers(alice, 0));
+
3040 env.require(balance(bob, USD(65)));
+
3041 }
+
3042 {
+
3043 // alice submits a tfSell | tfFillOrKill offer that doesn't cross.
+
3044 // This would have succeeded with a regular tfSell, but the
+
3045 // fillOrKill prevents the transaction from crossing since not
+
3046 // all of the offer is consumed.
+
3047
+
3048 // We're using bob's left-over offer for XRP(500), USD(5)
+
3049 env(offer(alice, USD(1), XRP(501), tfSell | tfFillOrKill),
+
3050 ter(killedCode));
+
3051 env.close();
+
3052 env.require(balance(alice, USD(35)));
+
3053 env.require(offers(alice, 0));
+
3054 env.require(balance(bob, USD(65)));
+
3055 }
+
3056 {
+
3057 // Alice submits a tfSell | tfFillOrKill offer that finishes
+
3058 // off the remainder of bob's offer.
+
3059
+
3060 // We're using bob's left-over offer for XRP(500), USD(5)
+
3061 env(offer(alice, USD(1), XRP(500), tfSell | tfFillOrKill));
+
3062 env.close();
+
3063 env.require(balance(alice, USD(40)));
+
3064 env.require(offers(alice, 0));
+
3065 env.require(balance(bob, USD(60)));
+
3066 }
+
3067 }
-
3076
-
3077 void
-
- -
3079 {
-
3080 testcase("Transfer Rate Offer");
-
3081
-
3082 using namespace jtx;
+
3068
+
3069 void
+
+ +
3071 {
+
3072 testcase("Transfer Rate Offer");
+
3073
+
3074 using namespace jtx;
+
3075
+
3076 auto const gw1 = Account("gateway1");
+
3077 auto const USD = gw1["USD"];
+
3078
+
3079 Env env{*this, features};
+
3080
+
3081 // The fee that's charged for transactions.
+
3082 auto const fee = env.current()->fees().base;
3083
-
3084 auto const gw1 = Account("gateway1");
-
3085 auto const USD = gw1["USD"];
+
3084 env.fund(XRP(100000), gw1);
+
3085 env.close();
3086
-
3087 Env env{*this, features};
-
3088
-
3089 // The fee that's charged for transactions.
-
3090 auto const fee = env.current()->fees().base;
-
3091
-
3092 env.fund(XRP(100000), gw1);
-
3093 env.close();
-
3094
-
3095 env(rate(gw1, 1.25));
-
3096 {
-
3097 auto const ann = Account("ann");
-
3098 auto const bob = Account("bob");
-
3099 env.fund(XRP(100) + reserve(env, 2) + (fee * 2), ann, bob);
-
3100 env.close();
-
3101
-
3102 env(trust(ann, USD(200)));
-
3103 env(trust(bob, USD(200)));
-
3104 env.close();
-
3105
-
3106 env(pay(gw1, bob, USD(125)));
-
3107 env.close();
-
3108
-
3109 // bob offers to sell USD(100) for XRP. alice takes bob's offer.
-
3110 // Notice that although bob only offered USD(100), USD(125) was
-
3111 // removed from his account due to the gateway fee.
-
3112 //
-
3113 // A comparable payment would look like this:
-
3114 // env (pay (bob, alice, USD(100)), sendmax(USD(125)))
-
3115 env(offer(bob, XRP(1), USD(100)));
-
3116 env.close();
-
3117
-
3118 env(offer(ann, USD(100), XRP(1)));
-
3119 env.close();
-
3120
-
3121 env.require(balance(ann, USD(100)));
-
3122 env.require(balance(ann, XRP(99) + reserve(env, 2)));
-
3123 env.require(offers(ann, 0));
-
3124
-
3125 env.require(balance(bob, USD(0)));
-
3126 env.require(balance(bob, XRP(101) + reserve(env, 2)));
-
3127 env.require(offers(bob, 0));
-
3128 }
-
3129 {
-
3130 // Reverse the order, so the offer in the books is to sell XRP
-
3131 // in return for USD. Gateway rate should still apply identically.
-
3132 auto const che = Account("che");
-
3133 auto const deb = Account("deb");
-
3134 env.fund(XRP(100) + reserve(env, 2) + (fee * 2), che, deb);
-
3135 env.close();
-
3136
-
3137 env(trust(che, USD(200)));
-
3138 env(trust(deb, USD(200)));
-
3139 env.close();
-
3140
-
3141 env(pay(gw1, deb, USD(125)));
-
3142 env.close();
-
3143
-
3144 env(offer(che, USD(100), XRP(1)));
-
3145 env.close();
-
3146
-
3147 env(offer(deb, XRP(1), USD(100)));
-
3148 env.close();
-
3149
-
3150 env.require(balance(che, USD(100)));
-
3151 env.require(balance(che, XRP(99) + reserve(env, 2)));
-
3152 env.require(offers(che, 0));
+
3087 env(rate(gw1, 1.25));
+
3088 {
+
3089 auto const ann = Account("ann");
+
3090 auto const bob = Account("bob");
+
3091 env.fund(XRP(100) + reserve(env, 2) + (fee * 2), ann, bob);
+
3092 env.close();
+
3093
+
3094 env(trust(ann, USD(200)));
+
3095 env(trust(bob, USD(200)));
+
3096 env.close();
+
3097
+
3098 env(pay(gw1, bob, USD(125)));
+
3099 env.close();
+
3100
+
3101 // bob offers to sell USD(100) for XRP. alice takes bob's offer.
+
3102 // Notice that although bob only offered USD(100), USD(125) was
+
3103 // removed from his account due to the gateway fee.
+
3104 //
+
3105 // A comparable payment would look like this:
+
3106 // env (pay (bob, alice, USD(100)), sendmax(USD(125)))
+
3107 env(offer(bob, XRP(1), USD(100)));
+
3108 env.close();
+
3109
+
3110 env(offer(ann, USD(100), XRP(1)));
+
3111 env.close();
+
3112
+
3113 env.require(balance(ann, USD(100)));
+
3114 env.require(balance(ann, XRP(99) + reserve(env, 2)));
+
3115 env.require(offers(ann, 0));
+
3116
+
3117 env.require(balance(bob, USD(0)));
+
3118 env.require(balance(bob, XRP(101) + reserve(env, 2)));
+
3119 env.require(offers(bob, 0));
+
3120 }
+
3121 {
+
3122 // Reverse the order, so the offer in the books is to sell XRP
+
3123 // in return for USD. Gateway rate should still apply identically.
+
3124 auto const che = Account("che");
+
3125 auto const deb = Account("deb");
+
3126 env.fund(XRP(100) + reserve(env, 2) + (fee * 2), che, deb);
+
3127 env.close();
+
3128
+
3129 env(trust(che, USD(200)));
+
3130 env(trust(deb, USD(200)));
+
3131 env.close();
+
3132
+
3133 env(pay(gw1, deb, USD(125)));
+
3134 env.close();
+
3135
+
3136 env(offer(che, USD(100), XRP(1)));
+
3137 env.close();
+
3138
+
3139 env(offer(deb, XRP(1), USD(100)));
+
3140 env.close();
+
3141
+
3142 env.require(balance(che, USD(100)));
+
3143 env.require(balance(che, XRP(99) + reserve(env, 2)));
+
3144 env.require(offers(che, 0));
+
3145
+
3146 env.require(balance(deb, USD(0)));
+
3147 env.require(balance(deb, XRP(101) + reserve(env, 2)));
+
3148 env.require(offers(deb, 0));
+
3149 }
+
3150 {
+
3151 auto const eve = Account("eve");
+
3152 auto const fyn = Account("fyn");
3153
-
3154 env.require(balance(deb, USD(0)));
-
3155 env.require(balance(deb, XRP(101) + reserve(env, 2)));
-
3156 env.require(offers(deb, 0));
-
3157 }
-
3158 {
-
3159 auto const eve = Account("eve");
-
3160 auto const fyn = Account("fyn");
-
3161
-
3162 env.fund(XRP(20000) + (fee * 2), eve, fyn);
+
3154 env.fund(XRP(20000) + (fee * 2), eve, fyn);
+
3155 env.close();
+
3156
+
3157 env(trust(eve, USD(1000)));
+
3158 env(trust(fyn, USD(1000)));
+
3159 env.close();
+
3160
+
3161 env(pay(gw1, eve, USD(100)));
+
3162 env(pay(gw1, fyn, USD(100)));
3163 env.close();
3164
-
3165 env(trust(eve, USD(1000)));
-
3166 env(trust(fyn, USD(1000)));
-
3167 env.close();
-
3168
-
3169 env(pay(gw1, eve, USD(100)));
-
3170 env(pay(gw1, fyn, USD(100)));
-
3171 env.close();
-
3172
-
3173 // This test verifies that the amount removed from an offer
-
3174 // accounts for the transfer fee that is removed from the
-
3175 // account but not from the remaining offer.
-
3176 env(offer(eve, USD(10), XRP(4000)));
-
3177 env.close();
-
3178 std::uint32_t const eveOfferSeq = env.seq(eve) - 1;
-
3179
-
3180 env(offer(fyn, XRP(2000), USD(5)));
-
3181 env.close();
-
3182
-
3183 env.require(balance(eve, USD(105)));
-
3184 env.require(balance(eve, XRP(18000)));
-
3185 auto const evesOffers = offersOnAccount(env, eve);
-
3186 BEAST_EXPECT(evesOffers.size() == 1);
-
3187 if (evesOffers.size() != 0)
-
3188 {
-
3189 auto const& evesOffer = *(evesOffers.front());
-
3190 BEAST_EXPECT(evesOffer[sfLedgerEntryType] == ltOFFER);
-
3191 BEAST_EXPECT(evesOffer[sfTakerGets] == XRP(2000));
-
3192 BEAST_EXPECT(evesOffer[sfTakerPays] == USD(5));
-
3193 }
-
3194 env(offer_cancel(eve, eveOfferSeq)); // For later tests
+
3165 // This test verifies that the amount removed from an offer
+
3166 // accounts for the transfer fee that is removed from the
+
3167 // account but not from the remaining offer.
+
3168 env(offer(eve, USD(10), XRP(4000)));
+
3169 env.close();
+
3170 std::uint32_t const eveOfferSeq = env.seq(eve) - 1;
+
3171
+
3172 env(offer(fyn, XRP(2000), USD(5)));
+
3173 env.close();
+
3174
+
3175 env.require(balance(eve, USD(105)));
+
3176 env.require(balance(eve, XRP(18000)));
+
3177 auto const evesOffers = offersOnAccount(env, eve);
+
3178 BEAST_EXPECT(evesOffers.size() == 1);
+
3179 if (evesOffers.size() != 0)
+
3180 {
+
3181 auto const& evesOffer = *(evesOffers.front());
+
3182 BEAST_EXPECT(evesOffer[sfLedgerEntryType] == ltOFFER);
+
3183 BEAST_EXPECT(evesOffer[sfTakerGets] == XRP(2000));
+
3184 BEAST_EXPECT(evesOffer[sfTakerPays] == USD(5));
+
3185 }
+
3186 env(offer_cancel(eve, eveOfferSeq)); // For later tests
+
3187
+
3188 env.require(balance(fyn, USD(93.75)));
+
3189 env.require(balance(fyn, XRP(22000)));
+
3190 env.require(offers(fyn, 0));
+
3191 }
+
3192 // Start messing with two non-native currencies.
+
3193 auto const gw2 = Account("gateway2");
+
3194 auto const EUR = gw2["EUR"];
3195
-
3196 env.require(balance(fyn, USD(93.75)));
-
3197 env.require(balance(fyn, XRP(22000)));
-
3198 env.require(offers(fyn, 0));
-
3199 }
-
3200 // Start messing with two non-native currencies.
-
3201 auto const gw2 = Account("gateway2");
-
3202 auto const EUR = gw2["EUR"];
-
3203
-
3204 env.fund(XRP(100000), gw2);
-
3205 env.close();
-
3206
-
3207 env(rate(gw2, 1.5));
-
3208 {
-
3209 // Remove XRP from the equation. Give the two currencies two
-
3210 // different transfer rates so we can see both transfer rates
-
3211 // apply in the same transaction.
-
3212 auto const gay = Account("gay");
-
3213 auto const hal = Account("hal");
-
3214 env.fund(reserve(env, 3) + (fee * 3), gay, hal);
-
3215 env.close();
-
3216
-
3217 env(trust(gay, USD(200)));
-
3218 env(trust(gay, EUR(200)));
-
3219 env(trust(hal, USD(200)));
-
3220 env(trust(hal, EUR(200)));
-
3221 env.close();
-
3222
-
3223 env(pay(gw1, gay, USD(125)));
-
3224 env(pay(gw2, hal, EUR(150)));
-
3225 env.close();
-
3226
-
3227 env(offer(gay, EUR(100), USD(100)));
-
3228 env.close();
+
3196 env.fund(XRP(100000), gw2);
+
3197 env.close();
+
3198
+
3199 env(rate(gw2, 1.5));
+
3200 {
+
3201 // Remove XRP from the equation. Give the two currencies two
+
3202 // different transfer rates so we can see both transfer rates
+
3203 // apply in the same transaction.
+
3204 auto const gay = Account("gay");
+
3205 auto const hal = Account("hal");
+
3206 env.fund(reserve(env, 3) + (fee * 3), gay, hal);
+
3207 env.close();
+
3208
+
3209 env(trust(gay, USD(200)));
+
3210 env(trust(gay, EUR(200)));
+
3211 env(trust(hal, USD(200)));
+
3212 env(trust(hal, EUR(200)));
+
3213 env.close();
+
3214
+
3215 env(pay(gw1, gay, USD(125)));
+
3216 env(pay(gw2, hal, EUR(150)));
+
3217 env.close();
+
3218
+
3219 env(offer(gay, EUR(100), USD(100)));
+
3220 env.close();
+
3221
+
3222 env(offer(hal, USD(100), EUR(100)));
+
3223 env.close();
+
3224
+
3225 env.require(balance(gay, USD(0)));
+
3226 env.require(balance(gay, EUR(100)));
+
3227 env.require(balance(gay, reserve(env, 3)));
+
3228 env.require(offers(gay, 0));
3229
-
3230 env(offer(hal, USD(100), EUR(100)));
-
3231 env.close();
-
3232
-
3233 env.require(balance(gay, USD(0)));
-
3234 env.require(balance(gay, EUR(100)));
-
3235 env.require(balance(gay, reserve(env, 3)));
-
3236 env.require(offers(gay, 0));
-
3237
-
3238 env.require(balance(hal, USD(100)));
-
3239 env.require(balance(hal, EUR(0)));
-
3240 env.require(balance(hal, reserve(env, 3)));
-
3241 env.require(offers(hal, 0));
-
3242 }
-
3243 {
-
3244 // A trust line's QualityIn should not affect offer crossing.
-
3245 auto const ivy = Account("ivy");
-
3246 auto const joe = Account("joe");
-
3247 env.fund(reserve(env, 3) + (fee * 3), ivy, joe);
-
3248 env.close();
-
3249
-
3250 env(trust(ivy, USD(400)), qualityInPercent(90));
-
3251 env(trust(ivy, EUR(400)), qualityInPercent(80));
-
3252 env(trust(joe, USD(400)), qualityInPercent(70));
-
3253 env(trust(joe, EUR(400)), qualityInPercent(60));
-
3254 env.close();
-
3255
-
3256 env(pay(gw1, ivy, USD(270)), sendmax(USD(500)));
-
3257 env(pay(gw2, joe, EUR(150)), sendmax(EUR(300)));
+
3230 env.require(balance(hal, USD(100)));
+
3231 env.require(balance(hal, EUR(0)));
+
3232 env.require(balance(hal, reserve(env, 3)));
+
3233 env.require(offers(hal, 0));
+
3234 }
+
3235 {
+
3236 // A trust line's QualityIn should not affect offer crossing.
+
3237 auto const ivy = Account("ivy");
+
3238 auto const joe = Account("joe");
+
3239 env.fund(reserve(env, 3) + (fee * 3), ivy, joe);
+
3240 env.close();
+
3241
+
3242 env(trust(ivy, USD(400)), qualityInPercent(90));
+
3243 env(trust(ivy, EUR(400)), qualityInPercent(80));
+
3244 env(trust(joe, USD(400)), qualityInPercent(70));
+
3245 env(trust(joe, EUR(400)), qualityInPercent(60));
+
3246 env.close();
+
3247
+
3248 env(pay(gw1, ivy, USD(270)), sendmax(USD(500)));
+
3249 env(pay(gw2, joe, EUR(150)), sendmax(EUR(300)));
+
3250 env.close();
+
3251 env.require(balance(ivy, USD(300)));
+
3252 env.require(balance(joe, EUR(250)));
+
3253
+
3254 env(offer(ivy, EUR(100), USD(200)));
+
3255 env.close();
+
3256
+
3257 env(offer(joe, USD(200), EUR(100)));
3258 env.close();
-
3259 env.require(balance(ivy, USD(300)));
-
3260 env.require(balance(joe, EUR(250)));
-
3261
-
3262 env(offer(ivy, EUR(100), USD(200)));
-
3263 env.close();
+
3259
+
3260 env.require(balance(ivy, USD(50)));
+
3261 env.require(balance(ivy, EUR(100)));
+
3262 env.require(balance(ivy, reserve(env, 3)));
+
3263 env.require(offers(ivy, 0));
3264
-
3265 env(offer(joe, USD(200), EUR(100)));
-
3266 env.close();
-
3267
-
3268 env.require(balance(ivy, USD(50)));
-
3269 env.require(balance(ivy, EUR(100)));
-
3270 env.require(balance(ivy, reserve(env, 3)));
-
3271 env.require(offers(ivy, 0));
-
3272
-
3273 env.require(balance(joe, USD(200)));
-
3274 env.require(balance(joe, EUR(100)));
-
3275 env.require(balance(joe, reserve(env, 3)));
-
3276 env.require(offers(joe, 0));
-
3277 }
-
3278 {
-
3279 // A trust line's QualityOut should not affect offer crossing.
-
3280 auto const kim = Account("kim");
-
3281 auto const K_BUX = kim["BUX"];
-
3282 auto const lex = Account("lex");
-
3283 auto const meg = Account("meg");
-
3284 auto const ned = Account("ned");
-
3285 auto const N_BUX = ned["BUX"];
-
3286
-
3287 // Verify trust line QualityOut affects payments.
-
3288 env.fund(reserve(env, 4) + (fee * 4), kim, lex, meg, ned);
-
3289 env.close();
+
3265 env.require(balance(joe, USD(200)));
+
3266 env.require(balance(joe, EUR(100)));
+
3267 env.require(balance(joe, reserve(env, 3)));
+
3268 env.require(offers(joe, 0));
+
3269 }
+
3270 {
+
3271 // A trust line's QualityOut should not affect offer crossing.
+
3272 auto const kim = Account("kim");
+
3273 auto const K_BUX = kim["BUX"];
+
3274 auto const lex = Account("lex");
+
3275 auto const meg = Account("meg");
+
3276 auto const ned = Account("ned");
+
3277 auto const N_BUX = ned["BUX"];
+
3278
+
3279 // Verify trust line QualityOut affects payments.
+
3280 env.fund(reserve(env, 4) + (fee * 4), kim, lex, meg, ned);
+
3281 env.close();
+
3282
+
3283 env(trust(lex, K_BUX(400)));
+
3284 env(trust(lex, N_BUX(200)), qualityOutPercent(120));
+
3285 env(trust(meg, N_BUX(100)));
+
3286 env.close();
+
3287 env(pay(ned, lex, N_BUX(100)));
+
3288 env.close();
+
3289 env.require(balance(lex, N_BUX(100)));
3290
-
3291 env(trust(lex, K_BUX(400)));
-
3292 env(trust(lex, N_BUX(200)), qualityOutPercent(120));
-
3293 env(trust(meg, N_BUX(100)));
-
3294 env.close();
-
3295 env(pay(ned, lex, N_BUX(100)));
-
3296 env.close();
-
3297 env.require(balance(lex, N_BUX(100)));
-
3298
-
3299 env(pay(kim, meg, N_BUX(60)), path(lex, ned), sendmax(K_BUX(200)));
-
3300 env.close();
-
3301
-
3302 env.require(balance(kim, K_BUX(none)));
-
3303 env.require(balance(kim, N_BUX(none)));
-
3304 env.require(balance(lex, K_BUX(72)));
-
3305 env.require(balance(lex, N_BUX(40)));
-
3306 env.require(balance(meg, K_BUX(none)));
-
3307 env.require(balance(meg, N_BUX(60)));
-
3308 env.require(balance(ned, K_BUX(none)));
-
3309 env.require(balance(ned, N_BUX(none)));
-
3310
-
3311 // Now verify that offer crossing is unaffected by QualityOut.
-
3312 env(offer(lex, K_BUX(30), N_BUX(30)));
-
3313 env.close();
-
3314
-
3315 env(offer(kim, N_BUX(30), K_BUX(30)));
-
3316 env.close();
-
3317
-
3318 env.require(balance(kim, K_BUX(none)));
-
3319 env.require(balance(kim, N_BUX(30)));
-
3320 env.require(balance(lex, K_BUX(102)));
-
3321 env.require(balance(lex, N_BUX(10)));
-
3322 env.require(balance(meg, K_BUX(none)));
-
3323 env.require(balance(meg, N_BUX(60)));
-
3324 env.require(balance(ned, K_BUX(-30)));
-
3325 env.require(balance(ned, N_BUX(none)));
-
3326 }
-
3327 {
-
3328 // Make sure things work right when we're auto-bridging as well.
-
3329 auto const ova = Account("ova");
-
3330 auto const pat = Account("pat");
-
3331 auto const qae = Account("qae");
-
3332 env.fund(XRP(2) + reserve(env, 3) + (fee * 3), ova, pat, qae);
-
3333 env.close();
-
3334
-
3335 // o ova has USD but wants XRP.
-
3336 // o pat has XRP but wants EUR.
-
3337 // o qae has EUR but wants USD.
-
3338 env(trust(ova, USD(200)));
-
3339 env(trust(ova, EUR(200)));
-
3340 env(trust(pat, USD(200)));
-
3341 env(trust(pat, EUR(200)));
-
3342 env(trust(qae, USD(200)));
-
3343 env(trust(qae, EUR(200)));
+
3291 env(pay(kim, meg, N_BUX(60)), path(lex, ned), sendmax(K_BUX(200)));
+
3292 env.close();
+
3293
+
3294 env.require(balance(kim, K_BUX(none)));
+
3295 env.require(balance(kim, N_BUX(none)));
+
3296 env.require(balance(lex, K_BUX(72)));
+
3297 env.require(balance(lex, N_BUX(40)));
+
3298 env.require(balance(meg, K_BUX(none)));
+
3299 env.require(balance(meg, N_BUX(60)));
+
3300 env.require(balance(ned, K_BUX(none)));
+
3301 env.require(balance(ned, N_BUX(none)));
+
3302
+
3303 // Now verify that offer crossing is unaffected by QualityOut.
+
3304 env(offer(lex, K_BUX(30), N_BUX(30)));
+
3305 env.close();
+
3306
+
3307 env(offer(kim, N_BUX(30), K_BUX(30)));
+
3308 env.close();
+
3309
+
3310 env.require(balance(kim, K_BUX(none)));
+
3311 env.require(balance(kim, N_BUX(30)));
+
3312 env.require(balance(lex, K_BUX(102)));
+
3313 env.require(balance(lex, N_BUX(10)));
+
3314 env.require(balance(meg, K_BUX(none)));
+
3315 env.require(balance(meg, N_BUX(60)));
+
3316 env.require(balance(ned, K_BUX(-30)));
+
3317 env.require(balance(ned, N_BUX(none)));
+
3318 }
+
3319 {
+
3320 // Make sure things work right when we're auto-bridging as well.
+
3321 auto const ova = Account("ova");
+
3322 auto const pat = Account("pat");
+
3323 auto const qae = Account("qae");
+
3324 env.fund(XRP(2) + reserve(env, 3) + (fee * 3), ova, pat, qae);
+
3325 env.close();
+
3326
+
3327 // o ova has USD but wants XRP.
+
3328 // o pat has XRP but wants EUR.
+
3329 // o qae has EUR but wants USD.
+
3330 env(trust(ova, USD(200)));
+
3331 env(trust(ova, EUR(200)));
+
3332 env(trust(pat, USD(200)));
+
3333 env(trust(pat, EUR(200)));
+
3334 env(trust(qae, USD(200)));
+
3335 env(trust(qae, EUR(200)));
+
3336 env.close();
+
3337
+
3338 env(pay(gw1, ova, USD(125)));
+
3339 env(pay(gw2, qae, EUR(150)));
+
3340 env.close();
+
3341
+
3342 env(offer(ova, XRP(2), USD(100)));
+
3343 env(offer(pat, EUR(100), XRP(2)));
3344 env.close();
3345
-
3346 env(pay(gw1, ova, USD(125)));
-
3347 env(pay(gw2, qae, EUR(150)));
-
3348 env.close();
-
3349
-
3350 env(offer(ova, XRP(2), USD(100)));
-
3351 env(offer(pat, EUR(100), XRP(2)));
-
3352 env.close();
-
3353
-
3354 env(offer(qae, USD(100), EUR(100)));
-
3355 env.close();
-
3356
-
3357 env.require(balance(ova, USD(0)));
-
3358 env.require(balance(ova, EUR(0)));
-
3359 env.require(balance(ova, XRP(4) + reserve(env, 3)));
-
3360
-
3361 // In pre-flow code ova's offer is left empty in the ledger.
-
3362 auto const ovasOffers = offersOnAccount(env, ova);
-
3363 if (ovasOffers.size() != 0)
-
3364 {
-
3365 BEAST_EXPECT(ovasOffers.size() == 1);
-
3366 auto const& ovasOffer = *(ovasOffers.front());
-
3367
-
3368 BEAST_EXPECT(ovasOffer[sfLedgerEntryType] == ltOFFER);
-
3369 BEAST_EXPECT(ovasOffer[sfTakerGets] == USD(0));
-
3370 BEAST_EXPECT(ovasOffer[sfTakerPays] == XRP(0));
-
3371 }
-
3372
-
3373 env.require(balance(pat, USD(0)));
-
3374 env.require(balance(pat, EUR(100)));
-
3375 env.require(balance(pat, XRP(0) + reserve(env, 3)));
-
3376 env.require(offers(pat, 0));
-
3377
-
3378 env.require(balance(qae, USD(100)));
-
3379 env.require(balance(qae, EUR(0)));
-
3380 env.require(balance(qae, XRP(2) + reserve(env, 3)));
-
3381 env.require(offers(qae, 0));
-
3382 }
-
3383 }
+
3346 env(offer(qae, USD(100), EUR(100)));
+
3347 env.close();
+
3348
+
3349 env.require(balance(ova, USD(0)));
+
3350 env.require(balance(ova, EUR(0)));
+
3351 env.require(balance(ova, XRP(4) + reserve(env, 3)));
+
3352
+
3353 // In pre-flow code ova's offer is left empty in the ledger.
+
3354 auto const ovasOffers = offersOnAccount(env, ova);
+
3355 if (ovasOffers.size() != 0)
+
3356 {
+
3357 BEAST_EXPECT(ovasOffers.size() == 1);
+
3358 auto const& ovasOffer = *(ovasOffers.front());
+
3359
+
3360 BEAST_EXPECT(ovasOffer[sfLedgerEntryType] == ltOFFER);
+
3361 BEAST_EXPECT(ovasOffer[sfTakerGets] == USD(0));
+
3362 BEAST_EXPECT(ovasOffer[sfTakerPays] == XRP(0));
+
3363 }
+
3364
+
3365 env.require(balance(pat, USD(0)));
+
3366 env.require(balance(pat, EUR(100)));
+
3367 env.require(balance(pat, XRP(0) + reserve(env, 3)));
+
3368 env.require(offers(pat, 0));
+
3369
+
3370 env.require(balance(qae, USD(100)));
+
3371 env.require(balance(qae, EUR(0)));
+
3372 env.require(balance(qae, XRP(2) + reserve(env, 3)));
+
3373 env.require(offers(qae, 0));
+
3374 }
+
3375 }
-
3384
-
3385 void
-
- -
3387 {
-
3388 // The following test verifies some correct but slightly surprising
-
3389 // behavior in offer crossing. The scenario:
+
3376
+
3377 void
+
+ +
3379 {
+
3380 // The following test verifies some correct but slightly surprising
+
3381 // behavior in offer crossing. The scenario:
+
3382 //
+
3383 // o An entity has created one or more offers.
+
3384 // o The entity creates another offer that can be directly crossed
+
3385 // (not autobridged) by the previously created offer(s).
+
3386 // o Rather than self crossing the offers, delete the old offer(s).
+
3387 //
+
3388 // See a more complete explanation in the comments for
+
3389 // BookOfferCrossingStep::limitSelfCrossQuality().
3390 //
-
3391 // o An entity has created one or more offers.
-
3392 // o The entity creates another offer that can be directly crossed
-
3393 // (not autobridged) by the previously created offer(s).
-
3394 // o Rather than self crossing the offers, delete the old offer(s).
-
3395 //
-
3396 // See a more complete explanation in the comments for
-
3397 // BookOfferCrossingStep::limitSelfCrossQuality().
-
3398 //
-
3399 // Note that, in this particular example, one offer causes several
-
3400 // crossable offers (worth considerably more than the new offer)
-
3401 // to be removed from the book.
-
3402 using namespace jtx;
-
3403
-
3404 auto const gw = Account("gateway");
-
3405 auto const USD = gw["USD"];
-
3406
-
3407 Env env{*this, features};
-
3408
-
3409 // The fee that's charged for transactions.
-
3410 auto const fee = env.current()->fees().base;
-
3411 auto const startBalance = XRP(1000000);
-
3412
-
3413 env.fund(startBalance + (fee * 4), gw);
-
3414 env.close();
-
3415
-
3416 env(offer(gw, USD(60), XRP(600)));
-
3417 env.close();
-
3418 env(offer(gw, USD(60), XRP(600)));
-
3419 env.close();
-
3420 env(offer(gw, USD(60), XRP(600)));
-
3421 env.close();
-
3422
-
3423 env.require(owners(gw, 3));
-
3424 env.require(balance(gw, startBalance + fee));
-
3425
-
3426 auto gwOffers = offersOnAccount(env, gw);
-
3427 BEAST_EXPECT(gwOffers.size() == 3);
-
3428 for (auto const& offerPtr : gwOffers)
-
3429 {
-
3430 auto const& offer = *offerPtr;
-
3431 BEAST_EXPECT(offer[sfLedgerEntryType] == ltOFFER);
-
3432 BEAST_EXPECT(offer[sfTakerGets] == XRP(600));
-
3433 BEAST_EXPECT(offer[sfTakerPays] == USD(60));
-
3434 }
+
3391 // Note that, in this particular example, one offer causes several
+
3392 // crossable offers (worth considerably more than the new offer)
+
3393 // to be removed from the book.
+
3394 using namespace jtx;
+
3395
+
3396 auto const gw = Account("gateway");
+
3397 auto const USD = gw["USD"];
+
3398
+
3399 Env env{*this, features};
+
3400
+
3401 // The fee that's charged for transactions.
+
3402 auto const fee = env.current()->fees().base;
+
3403 auto const startBalance = XRP(1000000);
+
3404
+
3405 env.fund(startBalance + (fee * 4), gw);
+
3406 env.close();
+
3407
+
3408 env(offer(gw, USD(60), XRP(600)));
+
3409 env.close();
+
3410 env(offer(gw, USD(60), XRP(600)));
+
3411 env.close();
+
3412 env(offer(gw, USD(60), XRP(600)));
+
3413 env.close();
+
3414
+
3415 env.require(owners(gw, 3));
+
3416 env.require(balance(gw, startBalance + fee));
+
3417
+
3418 auto gwOffers = offersOnAccount(env, gw);
+
3419 BEAST_EXPECT(gwOffers.size() == 3);
+
3420 for (auto const& offerPtr : gwOffers)
+
3421 {
+
3422 auto const& offer = *offerPtr;
+
3423 BEAST_EXPECT(offer[sfLedgerEntryType] == ltOFFER);
+
3424 BEAST_EXPECT(offer[sfTakerGets] == XRP(600));
+
3425 BEAST_EXPECT(offer[sfTakerPays] == USD(60));
+
3426 }
+
3427
+
3428 // Since this offer crosses the first offers, the previous offers
+
3429 // will be deleted and this offer will be put on the order book.
+
3430 env(offer(gw, XRP(1000), USD(100)));
+
3431 env.close();
+
3432 env.require(owners(gw, 1));
+
3433 env.require(offers(gw, 1));
+
3434 env.require(balance(gw, startBalance));
3435
-
3436 // Since this offer crosses the first offers, the previous offers
-
3437 // will be deleted and this offer will be put on the order book.
-
3438 env(offer(gw, XRP(1000), USD(100)));
-
3439 env.close();
-
3440 env.require(owners(gw, 1));
-
3441 env.require(offers(gw, 1));
-
3442 env.require(balance(gw, startBalance));
-
3443
-
3444 gwOffers = offersOnAccount(env, gw);
-
3445 BEAST_EXPECT(gwOffers.size() == 1);
-
3446 for (auto const& offerPtr : gwOffers)
-
3447 {
-
3448 auto const& offer = *offerPtr;
-
3449 BEAST_EXPECT(offer[sfLedgerEntryType] == ltOFFER);
-
3450 BEAST_EXPECT(offer[sfTakerGets] == USD(100));
-
3451 BEAST_EXPECT(offer[sfTakerPays] == XRP(1000));
-
3452 }
-
3453 }
+
3436 gwOffers = offersOnAccount(env, gw);
+
3437 BEAST_EXPECT(gwOffers.size() == 1);
+
3438 for (auto const& offerPtr : gwOffers)
+
3439 {
+
3440 auto const& offer = *offerPtr;
+
3441 BEAST_EXPECT(offer[sfLedgerEntryType] == ltOFFER);
+
3442 BEAST_EXPECT(offer[sfTakerGets] == USD(100));
+
3443 BEAST_EXPECT(offer[sfTakerPays] == XRP(1000));
+
3444 }
+
3445 }
-
3454
-
3455 void
-
- -
3457 {
-
3458 using namespace jtx;
+
3446
+
3447 void
+
+ +
3449 {
+
3450 using namespace jtx;
+
3451
+
3452 auto const gw1 = Account("gateway1");
+
3453 auto const gw2 = Account("gateway2");
+
3454 auto const alice = Account("alice");
+
3455 auto const USD = gw1["USD"];
+
3456 auto const EUR = gw2["EUR"];
+
3457
+
3458 Env env{*this, features};
3459
-
3460 auto const gw1 = Account("gateway1");
-
3461 auto const gw2 = Account("gateway2");
-
3462 auto const alice = Account("alice");
-
3463 auto const USD = gw1["USD"];
-
3464 auto const EUR = gw2["EUR"];
+
3460 env.fund(XRP(1000000), gw1, gw2);
+
3461 env.close();
+
3462
+
3463 // The fee that's charged for transactions.
+
3464 auto const f = env.current()->fees().base;
3465
-
3466 Env env{*this, features};
-
3467
-
3468 env.fund(XRP(1000000), gw1, gw2);
-
3469 env.close();
-
3470
-
3471 // The fee that's charged for transactions.
-
3472 auto const f = env.current()->fees().base;
-
3473
-
3474 // Test cases
-
3475 struct TestData
-
3476 {
-
3477 std::string acct; // Account operated on
-
3478 STAmount fundXRP; // XRP acct funded with
-
3479 STAmount fundUSD; // USD acct funded with
-
3480 STAmount fundEUR; // EUR acct funded with
-
3481 TER firstOfferTec; // tec code on first offer
-
3482 TER secondOfferTec; // tec code on second offer
-
3483 };
-
3484
-
3485 // clang-format off
-
3486 TestData const tests[]{
-
3487 // acct fundXRP fundUSD fundEUR firstOfferTec secondOfferTec
-
3488 {"ann", reserve(env, 3) + f * 4, USD(1000), EUR(1000), tesSUCCESS, tesSUCCESS},
-
3489 {"bev", reserve(env, 3) + f * 4, USD( 1), EUR(1000), tesSUCCESS, tesSUCCESS},
-
3490 {"cam", reserve(env, 3) + f * 4, USD(1000), EUR( 1), tesSUCCESS, tesSUCCESS},
-
3491 {"deb", reserve(env, 3) + f * 4, USD( 0), EUR( 1), tesSUCCESS, tecUNFUNDED_OFFER},
-
3492 {"eve", reserve(env, 3) + f * 4, USD( 1), EUR( 0), tecUNFUNDED_OFFER, tesSUCCESS},
-
3493 {"flo", reserve(env, 3) + 0, USD(1000), EUR(1000), tecINSUF_RESERVE_OFFER, tecINSUF_RESERVE_OFFER},
-
3494 };
-
3495 //clang-format on
-
3496
-
3497 for (auto const& t : tests)
-
3498 {
-
3499 auto const acct = Account{t.acct};
-
3500 env.fund(t.fundXRP, acct);
-
3501 env.close();
-
3502
-
3503 env(trust(acct, USD(1000)));
-
3504 env(trust(acct, EUR(1000)));
-
3505 env.close();
-
3506
-
3507 if (t.fundUSD > USD(0))
-
3508 env(pay(gw1, acct, t.fundUSD));
-
3509 if (t.fundEUR > EUR(0))
-
3510 env(pay(gw2, acct, t.fundEUR));
-
3511 env.close();
-
3512
-
3513 env(offer(acct, USD(500), EUR(600)), ter(t.firstOfferTec));
-
3514 env.close();
-
3515 std::uint32_t const firstOfferSeq = env.seq(acct) - 1;
-
3516
-
3517 int offerCount = t.firstOfferTec == tesSUCCESS ? 1 : 0;
-
3518 env.require(owners(acct, 2 + offerCount));
-
3519 env.require(balance(acct, t.fundUSD));
-
3520 env.require(balance(acct, t.fundEUR));
-
3521
-
3522 auto acctOffers = offersOnAccount(env, acct);
-
3523 BEAST_EXPECT(acctOffers.size() == offerCount);
-
3524 for (auto const& offerPtr : acctOffers)
-
3525 {
-
3526 auto const& offer = *offerPtr;
-
3527 BEAST_EXPECT(offer[sfLedgerEntryType] == ltOFFER);
-
3528 BEAST_EXPECT(offer[sfTakerGets] == EUR(600));
-
3529 BEAST_EXPECT(offer[sfTakerPays] == USD(500));
-
3530 }
-
3531
-
3532 env(offer(acct, EUR(600), USD(500)), ter(t.secondOfferTec));
-
3533 env.close();
-
3534 std::uint32_t const secondOfferSeq = env.seq(acct) - 1;
-
3535
-
3536 offerCount = t.secondOfferTec == tesSUCCESS ? 1 : offerCount;
-
3537 env.require(owners(acct, 2 + offerCount));
-
3538 env.require(balance(acct, t.fundUSD));
-
3539 env.require(balance(acct, t.fundEUR));
-
3540
-
3541 acctOffers = offersOnAccount(env, acct);
-
3542 BEAST_EXPECT(acctOffers.size() == offerCount);
-
3543 for (auto const& offerPtr : acctOffers)
-
3544 {
-
3545 auto const& offer = *offerPtr;
-
3546 BEAST_EXPECT(offer[sfLedgerEntryType] == ltOFFER);
-
3547 if (offer[sfSequence] == firstOfferSeq)
-
3548 {
-
3549 BEAST_EXPECT(offer[sfTakerGets] == EUR(600));
-
3550 BEAST_EXPECT(offer[sfTakerPays] == USD(500));
-
3551 }
-
3552 else
-
3553 {
-
3554 BEAST_EXPECT(offer[sfTakerGets] == USD(500));
-
3555 BEAST_EXPECT(offer[sfTakerPays] == EUR(600));
-
3556 }
-
3557 }
+
3466 // Test cases
+
3467 struct TestData
+
3468 {
+
3469 std::string acct; // Account operated on
+
3470 STAmount fundXRP; // XRP acct funded with
+
3471 STAmount fundUSD; // USD acct funded with
+
3472 STAmount fundEUR; // EUR acct funded with
+
3473 TER firstOfferTec; // tec code on first offer
+
3474 TER secondOfferTec; // tec code on second offer
+
3475 };
+
3476
+
3477 // clang-format off
+
3478 TestData const tests[]{
+
3479 // acct fundXRP fundUSD fundEUR firstOfferTec secondOfferTec
+
3480 {"ann", reserve(env, 3) + f * 4, USD(1000), EUR(1000), tesSUCCESS, tesSUCCESS},
+
3481 {"bev", reserve(env, 3) + f * 4, USD( 1), EUR(1000), tesSUCCESS, tesSUCCESS},
+
3482 {"cam", reserve(env, 3) + f * 4, USD(1000), EUR( 1), tesSUCCESS, tesSUCCESS},
+
3483 {"deb", reserve(env, 3) + f * 4, USD( 0), EUR( 1), tesSUCCESS, tecUNFUNDED_OFFER},
+
3484 {"eve", reserve(env, 3) + f * 4, USD( 1), EUR( 0), tecUNFUNDED_OFFER, tesSUCCESS},
+
3485 {"flo", reserve(env, 3) + 0, USD(1000), EUR(1000), tecINSUF_RESERVE_OFFER, tecINSUF_RESERVE_OFFER},
+
3486 };
+
3487 //clang-format on
+
3488
+
3489 for (auto const& t : tests)
+
3490 {
+
3491 auto const acct = Account{t.acct};
+
3492 env.fund(t.fundXRP, acct);
+
3493 env.close();
+
3494
+
3495 env(trust(acct, USD(1000)));
+
3496 env(trust(acct, EUR(1000)));
+
3497 env.close();
+
3498
+
3499 if (t.fundUSD > USD(0))
+
3500 env(pay(gw1, acct, t.fundUSD));
+
3501 if (t.fundEUR > EUR(0))
+
3502 env(pay(gw2, acct, t.fundEUR));
+
3503 env.close();
+
3504
+
3505 env(offer(acct, USD(500), EUR(600)), ter(t.firstOfferTec));
+
3506 env.close();
+
3507 std::uint32_t const firstOfferSeq = env.seq(acct) - 1;
+
3508
+
3509 int offerCount = t.firstOfferTec == tesSUCCESS ? 1 : 0;
+
3510 env.require(owners(acct, 2 + offerCount));
+
3511 env.require(balance(acct, t.fundUSD));
+
3512 env.require(balance(acct, t.fundEUR));
+
3513
+
3514 auto acctOffers = offersOnAccount(env, acct);
+
3515 BEAST_EXPECT(acctOffers.size() == offerCount);
+
3516 for (auto const& offerPtr : acctOffers)
+
3517 {
+
3518 auto const& offer = *offerPtr;
+
3519 BEAST_EXPECT(offer[sfLedgerEntryType] == ltOFFER);
+
3520 BEAST_EXPECT(offer[sfTakerGets] == EUR(600));
+
3521 BEAST_EXPECT(offer[sfTakerPays] == USD(500));
+
3522 }
+
3523
+
3524 env(offer(acct, EUR(600), USD(500)), ter(t.secondOfferTec));
+
3525 env.close();
+
3526 std::uint32_t const secondOfferSeq = env.seq(acct) - 1;
+
3527
+
3528 offerCount = t.secondOfferTec == tesSUCCESS ? 1 : offerCount;
+
3529 env.require(owners(acct, 2 + offerCount));
+
3530 env.require(balance(acct, t.fundUSD));
+
3531 env.require(balance(acct, t.fundEUR));
+
3532
+
3533 acctOffers = offersOnAccount(env, acct);
+
3534 BEAST_EXPECT(acctOffers.size() == offerCount);
+
3535 for (auto const& offerPtr : acctOffers)
+
3536 {
+
3537 auto const& offer = *offerPtr;
+
3538 BEAST_EXPECT(offer[sfLedgerEntryType] == ltOFFER);
+
3539 if (offer[sfSequence] == firstOfferSeq)
+
3540 {
+
3541 BEAST_EXPECT(offer[sfTakerGets] == EUR(600));
+
3542 BEAST_EXPECT(offer[sfTakerPays] == USD(500));
+
3543 }
+
3544 else
+
3545 {
+
3546 BEAST_EXPECT(offer[sfTakerGets] == USD(500));
+
3547 BEAST_EXPECT(offer[sfTakerPays] == EUR(600));
+
3548 }
+
3549 }
+
3550
+
3551 // Remove any offers from acct for the next pass.
+
3552 env(offer_cancel(acct, firstOfferSeq));
+
3553 env.close();
+
3554 env(offer_cancel(acct, secondOfferSeq));
+
3555 env.close();
+
3556 }
+
3557 }
+
3558
-
3559 // Remove any offers from acct for the next pass.
-
3560 env(offer_cancel(acct, firstOfferSeq));
-
3561 env.close();
-
3562 env(offer_cancel(acct, secondOfferSeq));
-
3563 env.close();
-
3564 }
+
3559 void
+
+ +
3561 {
+
3562 testcase("Self Cross Offer");
+
3563 testSelfCrossOffer1(features);
+
3564 testSelfCrossOffer2(features);
3565 }
3566
3567 void
- +
3569 {
-
3570 testcase("Self Cross Offer");
-
3571 testSelfCrossOffer1(features);
-
3572 testSelfCrossOffer2(features);
-
3573 }
-
-
3574
-
3575 void
-
- -
3577 {
-
3578 // Folks who issue their own currency have, in effect, as many
-
3579 // funds as they are trusted for. This test used to fail because
-
3580 // self-issuing was not properly checked. Verify that it works
-
3581 // correctly now.
-
3582 using namespace jtx;
-
3583
-
3584 Env env{*this, features};
+
3570 // Folks who issue their own currency have, in effect, as many
+
3571 // funds as they are trusted for. This test used to fail because
+
3572 // self-issuing was not properly checked. Verify that it works
+
3573 // correctly now.
+
3574 using namespace jtx;
+
3575
+
3576 Env env{*this, features};
+
3577
+
3578 auto const alice = Account("alice");
+
3579 auto const bob = Account("bob");
+
3580 auto const USD = bob["USD"];
+
3581 auto const f = env.current()->fees().base;
+
3582
+
3583 env.fund(XRP(50000) + f, alice, bob);
+
3584 env.close();
3585
-
3586 auto const alice = Account("alice");
-
3587 auto const bob = Account("bob");
-
3588 auto const USD = bob["USD"];
-
3589 auto const f = env.current()->fees().base;
-
3590
-
3591 env.fund(XRP(50000) + f, alice, bob);
-
3592 env.close();
-
3593
-
3594 env(offer(alice, USD(5000), XRP(50000)));
-
3595 env.close();
-
3596
-
3597 // This offer should take alice's offer up to Alice's reserve.
-
3598 env(offer(bob, XRP(50000), USD(5000)));
-
3599 env.close();
-
3600
-
3601 // alice's offer should have been removed, since she's down to her
-
3602 // XRP reserve.
-
3603 env.require(balance(alice, XRP(250)));
-
3604 env.require(owners(alice, 1));
-
3605 env.require(lines(alice, 1));
-
3606
-
3607 // However bob's offer should be in the ledger, since it was not
-
3608 // fully crossed.
-
3609 auto const bobOffers = offersOnAccount(env, bob);
-
3610 BEAST_EXPECT(bobOffers.size() == 1);
-
3611 for (auto const& offerPtr : bobOffers)
-
3612 {
-
3613 auto const& offer = *offerPtr;
-
3614 BEAST_EXPECT(offer[sfLedgerEntryType] == ltOFFER);
-
3615 BEAST_EXPECT(offer[sfTakerGets] == USD(25));
-
3616 BEAST_EXPECT(offer[sfTakerPays] == XRP(250));
-
3617 }
-
3618 }
+
3586 env(offer(alice, USD(5000), XRP(50000)));
+
3587 env.close();
+
3588
+
3589 // This offer should take alice's offer up to Alice's reserve.
+
3590 env(offer(bob, XRP(50000), USD(5000)));
+
3591 env.close();
+
3592
+
3593 // alice's offer should have been removed, since she's down to her
+
3594 // XRP reserve.
+
3595 env.require(balance(alice, XRP(250)));
+
3596 env.require(owners(alice, 1));
+
3597 env.require(lines(alice, 1));
+
3598
+
3599 // However bob's offer should be in the ledger, since it was not
+
3600 // fully crossed.
+
3601 auto const bobOffers = offersOnAccount(env, bob);
+
3602 BEAST_EXPECT(bobOffers.size() == 1);
+
3603 for (auto const& offerPtr : bobOffers)
+
3604 {
+
3605 auto const& offer = *offerPtr;
+
3606 BEAST_EXPECT(offer[sfLedgerEntryType] == ltOFFER);
+
3607 BEAST_EXPECT(offer[sfTakerGets] == USD(25));
+
3608 BEAST_EXPECT(offer[sfTakerPays] == XRP(250));
+
3609 }
+
3610 }
+
3611
+
3612 void
+
+ +
3614 {
+
3615 // At one point in the past this invalid path caused an assert. It
+
3616 // should not be possible for user-supplied data to cause an assert.
+
3617 // Make sure the assert is gone.
+
3618 testcase("Bad path assert");
3619
-
3620 void
-
- -
3622 {
-
3623 // At one point in the past this invalid path caused an assert. It
-
3624 // should not be possible for user-supplied data to cause an assert.
-
3625 // Make sure the assert is gone.
-
3626 testcase("Bad path assert");
-
3627
-
3628 using namespace jtx;
-
3629
-
3630 Env env{*this, features};
-
3631
-
3632 // The fee that's charged for transactions.
-
3633 auto const fee = env.current()->fees().base;
-
3634 {
-
3635 // A trust line's QualityOut should not affect offer crossing.
-
3636 auto const ann = Account("ann");
-
3637 auto const A_BUX = ann["BUX"];
-
3638 auto const bob = Account("bob");
-
3639 auto const cam = Account("cam");
-
3640 auto const dan = Account("dan");
-
3641 auto const D_BUX = dan["BUX"];
-
3642
-
3643 // Verify trust line QualityOut affects payments.
-
3644 env.fund(reserve(env, 4) + (fee * 4), ann, bob, cam, dan);
-
3645 env.close();
+
3620 using namespace jtx;
+
3621
+
3622 Env env{*this, features};
+
3623
+
3624 // The fee that's charged for transactions.
+
3625 auto const fee = env.current()->fees().base;
+
3626 {
+
3627 // A trust line's QualityOut should not affect offer crossing.
+
3628 auto const ann = Account("ann");
+
3629 auto const A_BUX = ann["BUX"];
+
3630 auto const bob = Account("bob");
+
3631 auto const cam = Account("cam");
+
3632 auto const dan = Account("dan");
+
3633 auto const D_BUX = dan["BUX"];
+
3634
+
3635 // Verify trust line QualityOut affects payments.
+
3636 env.fund(reserve(env, 4) + (fee * 4), ann, bob, cam, dan);
+
3637 env.close();
+
3638
+
3639 env(trust(bob, A_BUX(400)));
+
3640 env(trust(bob, D_BUX(200)), qualityOutPercent(120));
+
3641 env(trust(cam, D_BUX(100)));
+
3642 env.close();
+
3643 env(pay(dan, bob, D_BUX(100)));
+
3644 env.close();
+
3645 env.require(balance(bob, D_BUX(100)));
3646
-
3647 env(trust(bob, A_BUX(400)));
-
3648 env(trust(bob, D_BUX(200)), qualityOutPercent(120));
-
3649 env(trust(cam, D_BUX(100)));
-
3650 env.close();
-
3651 env(pay(dan, bob, D_BUX(100)));
-
3652 env.close();
-
3653 env.require(balance(bob, D_BUX(100)));
-
3654
-
3655 env(pay(ann, cam, D_BUX(60)), path(bob, dan), sendmax(A_BUX(200)));
-
3656 env.close();
-
3657
-
3658 env.require(balance(ann, A_BUX(none)));
-
3659 env.require(balance(ann, D_BUX(none)));
-
3660 env.require(balance(bob, A_BUX(72)));
-
3661 env.require(balance(bob, D_BUX(40)));
-
3662 env.require(balance(cam, A_BUX(none)));
-
3663 env.require(balance(cam, D_BUX(60)));
-
3664 env.require(balance(dan, A_BUX(none)));
-
3665 env.require(balance(dan, D_BUX(none)));
-
3666
-
3667 env(offer(bob, A_BUX(30), D_BUX(30)));
-
3668 env.close();
-
3669
-
3670 env(trust(ann, D_BUX(100)));
-
3671 env.close();
-
3672
-
3673 // This payment caused the assert.
-
3674 env(pay(ann, ann, D_BUX(30)),
-
3675 path(A_BUX, D_BUX),
-
3676 sendmax(A_BUX(30)),
-
3677 ter(temBAD_PATH));
-
3678 env.close();
-
3679
-
3680 env.require(balance(ann, A_BUX(none)));
-
3681 env.require(balance(ann, D_BUX(0)));
-
3682 env.require(balance(bob, A_BUX(72)));
-
3683 env.require(balance(bob, D_BUX(40)));
-
3684 env.require(balance(cam, A_BUX(none)));
-
3685 env.require(balance(cam, D_BUX(60)));
-
3686 env.require(balance(dan, A_BUX(0)));
-
3687 env.require(balance(dan, D_BUX(none)));
-
3688 }
-
3689 }
+
3647 env(pay(ann, cam, D_BUX(60)), path(bob, dan), sendmax(A_BUX(200)));
+
3648 env.close();
+
3649
+
3650 env.require(balance(ann, A_BUX(none)));
+
3651 env.require(balance(ann, D_BUX(none)));
+
3652 env.require(balance(bob, A_BUX(72)));
+
3653 env.require(balance(bob, D_BUX(40)));
+
3654 env.require(balance(cam, A_BUX(none)));
+
3655 env.require(balance(cam, D_BUX(60)));
+
3656 env.require(balance(dan, A_BUX(none)));
+
3657 env.require(balance(dan, D_BUX(none)));
+
3658
+
3659 env(offer(bob, A_BUX(30), D_BUX(30)));
+
3660 env.close();
+
3661
+
3662 env(trust(ann, D_BUX(100)));
+
3663 env.close();
+
3664
+
3665 // This payment caused the assert.
+
3666 env(pay(ann, ann, D_BUX(30)),
+
3667 path(A_BUX, D_BUX),
+
3668 sendmax(A_BUX(30)),
+
3669 ter(temBAD_PATH));
+
3670 env.close();
+
3671
+
3672 env.require(balance(ann, A_BUX(none)));
+
3673 env.require(balance(ann, D_BUX(0)));
+
3674 env.require(balance(bob, A_BUX(72)));
+
3675 env.require(balance(bob, D_BUX(40)));
+
3676 env.require(balance(cam, A_BUX(none)));
+
3677 env.require(balance(cam, D_BUX(60)));
+
3678 env.require(balance(dan, A_BUX(0)));
+
3679 env.require(balance(dan, D_BUX(none)));
+
3680 }
+
3681 }
-
3690
-
3691 void
-
- -
3693 {
-
3694 // The offer crossing code expects that a DirectStep is always
-
3695 // preceded by a BookStep. In one instance the default path
-
3696 // was not matching that assumption. Here we recreate that case
-
3697 // so we can prove the bug stays fixed.
-
3698 testcase("Direct to Direct path");
-
3699
-
3700 using namespace jtx;
+
3682
+
3683 void
+
+ +
3685 {
+
3686 // The offer crossing code expects that a DirectStep is always
+
3687 // preceded by a BookStep. In one instance the default path
+
3688 // was not matching that assumption. Here we recreate that case
+
3689 // so we can prove the bug stays fixed.
+
3690 testcase("Direct to Direct path");
+
3691
+
3692 using namespace jtx;
+
3693
+
3694 Env env{*this, features};
+
3695
+
3696 auto const ann = Account("ann");
+
3697 auto const bob = Account("bob");
+
3698 auto const cam = Account("cam");
+
3699 auto const A_BUX = ann["BUX"];
+
3700 auto const B_BUX = bob["BUX"];
3701
-
3702 Env env{*this, features};
-
3703
-
3704 auto const ann = Account("ann");
-
3705 auto const bob = Account("bob");
-
3706 auto const cam = Account("cam");
-
3707 auto const A_BUX = ann["BUX"];
-
3708 auto const B_BUX = bob["BUX"];
-
3709
-
3710 auto const fee = env.current()->fees().base;
-
3711 env.fund(reserve(env, 4) + (fee * 5), ann, bob, cam);
-
3712 env.close();
+
3702 auto const fee = env.current()->fees().base;
+
3703 env.fund(reserve(env, 4) + (fee * 5), ann, bob, cam);
+
3704 env.close();
+
3705
+
3706 env(trust(ann, B_BUX(40)));
+
3707 env(trust(cam, A_BUX(40)));
+
3708 env(trust(cam, B_BUX(40)));
+
3709 env.close();
+
3710
+
3711 env(pay(ann, cam, A_BUX(35)));
+
3712 env(pay(bob, cam, B_BUX(35)));
3713
-
3714 env(trust(ann, B_BUX(40)));
-
3715 env(trust(cam, A_BUX(40)));
-
3716 env(trust(cam, B_BUX(40)));
-
3717 env.close();
-
3718
-
3719 env(pay(ann, cam, A_BUX(35)));
-
3720 env(pay(bob, cam, B_BUX(35)));
-
3721
-
3722 env(offer(bob, A_BUX(30), B_BUX(30)));
-
3723 env.close();
-
3724
-
3725 // cam puts an offer on the books that her upcoming offer could cross.
-
3726 // But this offer should be deleted, not crossed, by her upcoming
-
3727 // offer.
-
3728 env(offer(cam, A_BUX(29), B_BUX(30), tfPassive));
-
3729 env.close();
-
3730 env.require(balance(cam, A_BUX(35)));
-
3731 env.require(balance(cam, B_BUX(35)));
-
3732 env.require(offers(cam, 1));
-
3733
-
3734 // This offer caused the assert.
-
3735 env(offer(cam, B_BUX(30), A_BUX(30)));
-
3736 env.close();
-
3737
-
3738 env.require(balance(bob, A_BUX(30)));
-
3739 env.require(balance(cam, A_BUX(5)));
-
3740 env.require(balance(cam, B_BUX(65)));
-
3741 env.require(offers(cam, 0));
-
3742 }
+
3714 env(offer(bob, A_BUX(30), B_BUX(30)));
+
3715 env.close();
+
3716
+
3717 // cam puts an offer on the books that her upcoming offer could cross.
+
3718 // But this offer should be deleted, not crossed, by her upcoming
+
3719 // offer.
+
3720 env(offer(cam, A_BUX(29), B_BUX(30), tfPassive));
+
3721 env.close();
+
3722 env.require(balance(cam, A_BUX(35)));
+
3723 env.require(balance(cam, B_BUX(35)));
+
3724 env.require(offers(cam, 1));
+
3725
+
3726 // This offer caused the assert.
+
3727 env(offer(cam, B_BUX(30), A_BUX(30)));
+
3728 env.close();
+
3729
+
3730 env.require(balance(bob, A_BUX(30)));
+
3731 env.require(balance(cam, A_BUX(5)));
+
3732 env.require(balance(cam, B_BUX(65)));
+
3733 env.require(offers(cam, 0));
+
3734 }
+
3735
+
3736 void
+
+ +
3738 {
+
3739 // The Flow offer crossing code used to assert if an offer was made
+
3740 // for more XRP than the offering account held. This unit test
+
3741 // reproduces that failing case.
+
3742 testcase("Self crossing low quality offer");
3743
-
3744 void
-
- -
3746 {
-
3747 // The Flow offer crossing code used to assert if an offer was made
-
3748 // for more XRP than the offering account held. This unit test
-
3749 // reproduces that failing case.
-
3750 testcase("Self crossing low quality offer");
+
3744 using namespace jtx;
+
3745
+
3746 Env env{*this, features};
+
3747
+
3748 auto const ann = Account("ann");
+
3749 auto const gw = Account("gateway");
+
3750 auto const BTC = gw["BTC"];
3751
-
3752 using namespace jtx;
-
3753
-
3754 Env env{*this, features};
-
3755
-
3756 auto const ann = Account("ann");
-
3757 auto const gw = Account("gateway");
-
3758 auto const BTC = gw["BTC"];
-
3759
-
3760 auto const fee = env.current()->fees().base;
-
3761 env.fund(reserve(env, 2) + drops(9999640) + (fee), ann);
-
3762 env.fund(reserve(env, 2) + (fee * 4), gw);
-
3763 env.close();
-
3764
-
3765 env(rate(gw, 1.002));
-
3766 env(trust(ann, BTC(10)));
-
3767 env.close();
-
3768
-
3769 env(pay(gw, ann, BTC(2.856)));
-
3770 env.close();
+
3752 auto const fee = env.current()->fees().base;
+
3753 env.fund(reserve(env, 2) + drops(9999640) + (fee), ann);
+
3754 env.fund(reserve(env, 2) + (fee * 4), gw);
+
3755 env.close();
+
3756
+
3757 env(rate(gw, 1.002));
+
3758 env(trust(ann, BTC(10)));
+
3759 env.close();
+
3760
+
3761 env(pay(gw, ann, BTC(2.856)));
+
3762 env.close();
+
3763
+
3764 env(offer(ann, drops(365611702030), BTC(5.713)));
+
3765 env.close();
+
3766
+
3767 // This offer caused the assert.
+
3768 env(offer(ann, BTC(0.687), drops(20000000000)),
+ +
3770 }
+
3771
-
3772 env(offer(ann, drops(365611702030), BTC(5.713)));
-
3773 env.close();
-
3774
-
3775 // This offer caused the assert.
-
3776 env(offer(ann, BTC(0.687), drops(20000000000)),
- -
3778 }
-
-
3779
-
3780 void
-
- -
3782 {
-
3783 // The Flow offer crossing code had a case where it was not rounding
-
3784 // the offer crossing correctly after a partial crossing. The
-
3785 // failing case was found on the network. Here we add the case to
-
3786 // the unit tests.
-
3787 testcase("Offer In Scaling");
-
3788
-
3789 using namespace jtx;
-
3790
-
3791 Env env{*this, features};
-
3792
-
3793 auto const gw = Account("gateway");
-
3794 auto const alice = Account("alice");
-
3795 auto const bob = Account("bob");
-
3796 auto const CNY = gw["CNY"];
+
3772 void
+
+ +
3774 {
+
3775 // The Flow offer crossing code had a case where it was not rounding
+
3776 // the offer crossing correctly after a partial crossing. The
+
3777 // failing case was found on the network. Here we add the case to
+
3778 // the unit tests.
+
3779 testcase("Offer In Scaling");
+
3780
+
3781 using namespace jtx;
+
3782
+
3783 Env env{*this, features};
+
3784
+
3785 auto const gw = Account("gateway");
+
3786 auto const alice = Account("alice");
+
3787 auto const bob = Account("bob");
+
3788 auto const CNY = gw["CNY"];
+
3789
+
3790 auto const fee = env.current()->fees().base;
+
3791 env.fund(reserve(env, 2) + drops(400000000000) + (fee), alice, bob);
+
3792 env.fund(reserve(env, 2) + (fee * 4), gw);
+
3793 env.close();
+
3794
+
3795 env(trust(bob, CNY(500)));
+
3796 env.close();
3797
-
3798 auto const fee = env.current()->fees().base;
-
3799 env.fund(reserve(env, 2) + drops(400000000000) + (fee), alice, bob);
-
3800 env.fund(reserve(env, 2) + (fee * 4), gw);
-
3801 env.close();
-
3802
-
3803 env(trust(bob, CNY(500)));
-
3804 env.close();
-
3805
-
3806 env(pay(gw, bob, CNY(300)));
-
3807 env.close();
-
3808
-
3809 env(offer(bob, drops(5400000000), CNY(216.054)));
-
3810 env.close();
-
3811
-
3812 // This offer did not round result of partial crossing correctly.
-
3813 env(offer(alice, CNY(13562.0001), drops(339000000000)));
-
3814 env.close();
-
3815
-
3816 auto const aliceOffers = offersOnAccount(env, alice);
-
3817 BEAST_EXPECT(aliceOffers.size() == 1);
-
3818 for (auto const& offerPtr : aliceOffers)
-
3819 {
-
3820 auto const& offer = *offerPtr;
-
3821 BEAST_EXPECT(offer[sfLedgerEntryType] == ltOFFER);
-
3822 BEAST_EXPECT(offer[sfTakerGets] == drops(333599446582));
-
3823 BEAST_EXPECT(offer[sfTakerPays] == CNY(13345.9461));
-
3824 }
-
3825 }
+
3798 env(pay(gw, bob, CNY(300)));
+
3799 env.close();
+
3800
+
3801 env(offer(bob, drops(5400000000), CNY(216.054)));
+
3802 env.close();
+
3803
+
3804 // This offer did not round result of partial crossing correctly.
+
3805 env(offer(alice, CNY(13562.0001), drops(339000000000)));
+
3806 env.close();
+
3807
+
3808 auto const aliceOffers = offersOnAccount(env, alice);
+
3809 BEAST_EXPECT(aliceOffers.size() == 1);
+
3810 for (auto const& offerPtr : aliceOffers)
+
3811 {
+
3812 auto const& offer = *offerPtr;
+
3813 BEAST_EXPECT(offer[sfLedgerEntryType] == ltOFFER);
+
3814 BEAST_EXPECT(offer[sfTakerGets] == drops(333599446582));
+
3815 BEAST_EXPECT(offer[sfTakerPays] == CNY(13345.9461));
+
3816 }
+
3817 }
+
3818
+
3819 void
+
+ +
3821 {
+
3822 // After adding the previous case, there were still failing rounding
+
3823 // cases in Flow offer crossing. This one was because the gateway
+
3824 // transfer rate was not being correctly handled.
+
3825 testcase("Offer In Scaling With Xfer Rate");
3826
-
3827 void
-
- -
3829 {
-
3830 // After adding the previous case, there were still failing rounding
-
3831 // cases in Flow offer crossing. This one was because the gateway
-
3832 // transfer rate was not being correctly handled.
-
3833 testcase("Offer In Scaling With Xfer Rate");
-
3834
-
3835 using namespace jtx;
+
3827 using namespace jtx;
+
3828
+
3829 Env env{*this, features};
+
3830
+
3831 auto const gw = Account("gateway");
+
3832 auto const alice = Account("alice");
+
3833 auto const bob = Account("bob");
+
3834 auto const BTC = gw["BTC"];
+
3835 auto const JPY = gw["JPY"];
3836
-
3837 Env env{*this, features};
-
3838
-
3839 auto const gw = Account("gateway");
-
3840 auto const alice = Account("alice");
-
3841 auto const bob = Account("bob");
-
3842 auto const BTC = gw["BTC"];
-
3843 auto const JPY = gw["JPY"];
-
3844
-
3845 auto const fee = env.current()->fees().base;
-
3846 env.fund(reserve(env, 2) + drops(400000000000) + (fee), alice, bob);
-
3847 env.fund(reserve(env, 2) + (fee * 4), gw);
-
3848 env.close();
-
3849
-
3850 env(rate(gw, 1.002));
-
3851 env(trust(alice, JPY(4000)));
-
3852 env(trust(bob, BTC(2)));
-
3853 env.close();
-
3854
-
3855 env(pay(gw, alice, JPY(3699.034802280317)));
-
3856 env(pay(gw, bob, BTC(1.156722559140311)));
-
3857 env.close();
-
3858
-
3859 env(offer(bob, JPY(1241.913390770747), BTC(0.01969825690469254)));
-
3860 env.close();
-
3861
-
3862 // This offer did not round result of partial crossing correctly.
-
3863 env(offer(alice, BTC(0.05507568706427876), JPY(3472.696773391072)));
-
3864 env.close();
-
3865
-
3866 auto const aliceOffers = offersOnAccount(env, alice);
-
3867 BEAST_EXPECT(aliceOffers.size() == 1);
-
3868 for (auto const& offerPtr : aliceOffers)
-
3869 {
-
3870 auto const& offer = *offerPtr;
-
3871 BEAST_EXPECT(offer[sfLedgerEntryType] == ltOFFER);
-
3872 BEAST_EXPECT(
-
3873 offer[sfTakerGets] ==
-
3874 STAmount(JPY.issue(), std::uint64_t(2230682446713524ul), -12));
-
3875 BEAST_EXPECT(offer[sfTakerPays] == BTC(0.035378));
-
3876 }
-
3877 }
+
3837 auto const fee = env.current()->fees().base;
+
3838 env.fund(reserve(env, 2) + drops(400000000000) + (fee), alice, bob);
+
3839 env.fund(reserve(env, 2) + (fee * 4), gw);
+
3840 env.close();
+
3841
+
3842 env(rate(gw, 1.002));
+
3843 env(trust(alice, JPY(4000)));
+
3844 env(trust(bob, BTC(2)));
+
3845 env.close();
+
3846
+
3847 env(pay(gw, alice, JPY(3699.034802280317)));
+
3848 env(pay(gw, bob, BTC(1.156722559140311)));
+
3849 env.close();
+
3850
+
3851 env(offer(bob, JPY(1241.913390770747), BTC(0.01969825690469254)));
+
3852 env.close();
+
3853
+
3854 // This offer did not round result of partial crossing correctly.
+
3855 env(offer(alice, BTC(0.05507568706427876), JPY(3472.696773391072)));
+
3856 env.close();
+
3857
+
3858 auto const aliceOffers = offersOnAccount(env, alice);
+
3859 BEAST_EXPECT(aliceOffers.size() == 1);
+
3860 for (auto const& offerPtr : aliceOffers)
+
3861 {
+
3862 auto const& offer = *offerPtr;
+
3863 BEAST_EXPECT(offer[sfLedgerEntryType] == ltOFFER);
+
3864 BEAST_EXPECT(
+
3865 offer[sfTakerGets] ==
+
3866 STAmount(JPY.issue(), std::uint64_t(2230682446713524ul), -12));
+
3867 BEAST_EXPECT(offer[sfTakerPays] == BTC(0.035378));
+
3868 }
+
3869 }
+
3870
+
3871 void
+
+ +
3873 {
+
3874 // Another instance where Flow offer crossing was not always
+
3875 // working right was if the Taker had fewer funds than the Offer
+
3876 // was offering. The basis for this test came off the network.
+
3877 testcase("Offer Threshold With Reduced Funds");
3878
-
3879 void
-
- -
3881 {
-
3882 // Another instance where Flow offer crossing was not always
-
3883 // working right was if the Taker had fewer funds than the Offer
-
3884 // was offering. The basis for this test came off the network.
-
3885 testcase("Offer Threshold With Reduced Funds");
-
3886
-
3887 using namespace jtx;
-
3888
-
3889 Env env{*this, features};
-
3890
-
3891 auto const gw1 = Account("gw1");
-
3892 auto const gw2 = Account("gw2");
-
3893 auto const alice = Account("alice");
-
3894 auto const bob = Account("bob");
-
3895 auto const USD = gw1["USD"];
-
3896 auto const JPY = gw2["JPY"];
-
3897
-
3898 auto const fee = env.current()->fees().base;
-
3899 env.fund(reserve(env, 2) + drops(400000000000) + (fee), alice, bob);
-
3900 env.fund(reserve(env, 2) + (fee * 4), gw1, gw2);
-
3901 env.close();
-
3902
-
3903 env(rate(gw1, 1.002));
-
3904 env(trust(alice, USD(1000)));
-
3905 env(trust(bob, JPY(100000)));
-
3906 env.close();
-
3907
-
3908 env(
-
3909 pay(gw1,
-
3910 alice,
-
3911 STAmount{USD.issue(), std::uint64_t(2185410179555600), -14}));
-
3912 env(
-
3913 pay(gw2,
-
3914 bob,
-
3915 STAmount{JPY.issue(), std::uint64_t(6351823459548956), -12}));
-
3916 env.close();
-
3917
-
3918 env(offer(
-
3919 bob,
-
3920 STAmount{USD.issue(), std::uint64_t(4371257532306000), -17},
-
3921 STAmount{JPY.issue(), std::uint64_t(4573216636606000), -15}));
-
3922 env.close();
-
3923
-
3924 // This offer did not partially cross correctly.
-
3925 env(offer(
-
3926 alice,
-
3927 STAmount{JPY.issue(), std::uint64_t(2291181510070762), -12},
-
3928 STAmount{USD.issue(), std::uint64_t(2190218999914694), -14}));
-
3929 env.close();
-
3930
-
3931 auto const aliceOffers = offersOnAccount(env, alice);
-
3932 BEAST_EXPECT(aliceOffers.size() == 1);
-
3933 for (auto const& offerPtr : aliceOffers)
-
3934 {
-
3935 auto const& offer = *offerPtr;
-
3936 BEAST_EXPECT(offer[sfLedgerEntryType] == ltOFFER);
-
3937 BEAST_EXPECT(
-
3938 offer[sfTakerGets] ==
-
3939 STAmount(USD.issue(), std::uint64_t(2185847305256635), -14));
-
3940 BEAST_EXPECT(
-
3941 offer[sfTakerPays] ==
-
3942 STAmount(JPY.issue(), std::uint64_t(2286608293434156), -12));
-
3943 }
-
3944 }
+
3879 using namespace jtx;
+
3880
+
3881 Env env{*this, features};
+
3882
+
3883 auto const gw1 = Account("gw1");
+
3884 auto const gw2 = Account("gw2");
+
3885 auto const alice = Account("alice");
+
3886 auto const bob = Account("bob");
+
3887 auto const USD = gw1["USD"];
+
3888 auto const JPY = gw2["JPY"];
+
3889
+
3890 auto const fee = env.current()->fees().base;
+
3891 env.fund(reserve(env, 2) + drops(400000000000) + (fee), alice, bob);
+
3892 env.fund(reserve(env, 2) + (fee * 4), gw1, gw2);
+
3893 env.close();
+
3894
+
3895 env(rate(gw1, 1.002));
+
3896 env(trust(alice, USD(1000)));
+
3897 env(trust(bob, JPY(100000)));
+
3898 env.close();
+
3899
+
3900 env(
+
3901 pay(gw1,
+
3902 alice,
+
3903 STAmount{USD.issue(), std::uint64_t(2185410179555600), -14}));
+
3904 env(
+
3905 pay(gw2,
+
3906 bob,
+
3907 STAmount{JPY.issue(), std::uint64_t(6351823459548956), -12}));
+
3908 env.close();
+
3909
+
3910 env(offer(
+
3911 bob,
+
3912 STAmount{USD.issue(), std::uint64_t(4371257532306000), -17},
+
3913 STAmount{JPY.issue(), std::uint64_t(4573216636606000), -15}));
+
3914 env.close();
+
3915
+
3916 // This offer did not partially cross correctly.
+
3917 env(offer(
+
3918 alice,
+
3919 STAmount{JPY.issue(), std::uint64_t(2291181510070762), -12},
+
3920 STAmount{USD.issue(), std::uint64_t(2190218999914694), -14}));
+
3921 env.close();
+
3922
+
3923 auto const aliceOffers = offersOnAccount(env, alice);
+
3924 BEAST_EXPECT(aliceOffers.size() == 1);
+
3925 for (auto const& offerPtr : aliceOffers)
+
3926 {
+
3927 auto const& offer = *offerPtr;
+
3928 BEAST_EXPECT(offer[sfLedgerEntryType] == ltOFFER);
+
3929 BEAST_EXPECT(
+
3930 offer[sfTakerGets] ==
+
3931 STAmount(USD.issue(), std::uint64_t(2185847305256635), -14));
+
3932 BEAST_EXPECT(
+
3933 offer[sfTakerPays] ==
+
3934 STAmount(JPY.issue(), std::uint64_t(2286608293434156), -12));
+
3935 }
+
3936 }
-
3945
-
3946 void
-
- -
3948 {
-
3949 testcase("Tiny Offer");
-
3950
-
3951 using namespace jtx;
-
3952
-
3953 Env env{*this, features};
-
3954
-
3955 auto const gw = Account("gw");
-
3956 auto const alice = Account("alice");
-
3957 auto const bob = Account("bob");
-
3958 auto const CNY = gw["CNY"];
-
3959 auto const fee = env.current()->fees().base;
-
3960 auto const startXrpBalance = drops(400000000000) + (fee * 2);
-
3961
-
3962 env.fund(startXrpBalance, gw, alice, bob);
-
3963 env.close();
+
3937
+
3938 void
+
+ +
3940 {
+
3941 testcase("Tiny Offer");
+
3942
+
3943 using namespace jtx;
+
3944
+
3945 Env env{*this, features};
+
3946
+
3947 auto const gw = Account("gw");
+
3948 auto const alice = Account("alice");
+
3949 auto const bob = Account("bob");
+
3950 auto const CNY = gw["CNY"];
+
3951 auto const fee = env.current()->fees().base;
+
3952 auto const startXrpBalance = drops(400000000000) + (fee * 2);
+
3953
+
3954 env.fund(startXrpBalance, gw, alice, bob);
+
3955 env.close();
+
3956
+
3957 env(trust(bob, CNY(100000)));
+
3958 env.close();
+
3959
+
3960 // Place alice's tiny offer in the book first. Let's see what happens
+
3961 // when a reasonable offer crosses it.
+
3962 STAmount const alicesCnyOffer{
+
3963 CNY.issue(), std::uint64_t(4926000000000000), -23};
3964
-
3965 env(trust(bob, CNY(100000)));
+
3965 env(offer(alice, alicesCnyOffer, drops(1), tfPassive));
3966 env.close();
3967
-
3968 // Place alice's tiny offer in the book first. Let's see what happens
-
3969 // when a reasonable offer crosses it.
-
3970 STAmount const alicesCnyOffer{
-
3971 CNY.issue(), std::uint64_t(4926000000000000), -23};
-
3972
-
3973 env(offer(alice, alicesCnyOffer, drops(1), tfPassive));
-
3974 env.close();
-
3975
-
3976 // bob places an ordinary offer
-
3977 STAmount const bobsCnyStartBalance{
-
3978 CNY.issue(), std::uint64_t(3767479960090235), -15};
-
3979 env(pay(gw, bob, bobsCnyStartBalance));
-
3980 env.close();
-
3981
-
3982 env(offer(
-
3983 bob,
-
3984 drops(203),
-
3985 STAmount{CNY.issue(), std::uint64_t(1000000000000000), -20}));
-
3986 env.close();
-
3987
-
3988 env.require(balance(alice, alicesCnyOffer));
-
3989 env.require(balance(alice, startXrpBalance - fee - drops(1)));
-
3990 env.require(balance(bob, bobsCnyStartBalance - alicesCnyOffer));
-
3991 env.require(balance(bob, startXrpBalance - (fee * 2) + drops(1)));
-
3992 }
+
3968 // bob places an ordinary offer
+
3969 STAmount const bobsCnyStartBalance{
+
3970 CNY.issue(), std::uint64_t(3767479960090235), -15};
+
3971 env(pay(gw, bob, bobsCnyStartBalance));
+
3972 env.close();
+
3973
+
3974 env(offer(
+
3975 bob,
+
3976 drops(203),
+
3977 STAmount{CNY.issue(), std::uint64_t(1000000000000000), -20}));
+
3978 env.close();
+
3979
+
3980 env.require(balance(alice, alicesCnyOffer));
+
3981 env.require(balance(alice, startXrpBalance - fee - drops(1)));
+
3982 env.require(balance(bob, bobsCnyStartBalance - alicesCnyOffer));
+
3983 env.require(balance(bob, startXrpBalance - (fee * 2) + drops(1)));
+
3984 }
-
3993
-
3994 void
-
- -
3996 {
-
3997 testcase("Self Pay Xfer Fee");
-
3998 // The old offer crossing code does not charge a transfer fee
-
3999 // if alice pays alice. That's different from how payments work.
-
4000 // Payments always charge a transfer fee even if the money is staying
-
4001 // in the same hands.
+
3985
+
3986 void
+
+ +
3988 {
+
3989 testcase("Self Pay Xfer Fee");
+
3990 // The old offer crossing code does not charge a transfer fee
+
3991 // if alice pays alice. That's different from how payments work.
+
3992 // Payments always charge a transfer fee even if the money is staying
+
3993 // in the same hands.
+
3994 //
+
3995 // What's an example where alice pays alice? There are three actors:
+
3996 // gw, alice, and bob.
+
3997 //
+
3998 // 1. gw issues BTC and USD. qw charges a 0.2% transfer fee.
+
3999 //
+
4000 // 2. alice makes an offer to buy XRP and sell USD.
+
4001 // 3. bob makes an offer to buy BTC and sell XRP.
4002 //
-
4003 // What's an example where alice pays alice? There are three actors:
-
4004 // gw, alice, and bob.
-
4005 //
-
4006 // 1. gw issues BTC and USD. qw charges a 0.2% transfer fee.
-
4007 //
-
4008 // 2. alice makes an offer to buy XRP and sell USD.
-
4009 // 3. bob makes an offer to buy BTC and sell XRP.
+
4003 // 4. alice now makes an offer to sell BTC and buy USD.
+
4004 //
+
4005 // This last offer crosses using auto-bridging.
+
4006 // o alice's last offer sells BTC to...
+
4007 // o bob' offer which takes alice's BTC and sells XRP to...
+
4008 // o alice's first offer which takes bob's XRP and sells USD to...
+
4009 // o alice's last offer.
4010 //
-
4011 // 4. alice now makes an offer to sell BTC and buy USD.
+
4011 // So alice sells USD to herself.
4012 //
-
4013 // This last offer crosses using auto-bridging.
-
4014 // o alice's last offer sells BTC to...
-
4015 // o bob' offer which takes alice's BTC and sells XRP to...
-
4016 // o alice's first offer which takes bob's XRP and sells USD to...
-
4017 // o alice's last offer.
-
4018 //
-
4019 // So alice sells USD to herself.
+
4013 // There are six cases that we need to test:
+
4014 // o alice crosses her own offer on the first leg (BTC).
+
4015 // o alice crosses her own offer on the second leg (USD).
+
4016 // o alice crosses her own offers on both legs.
+
4017 // All three cases need to be tested:
+
4018 // o In reverse (alice has enough BTC to cover her offer) and
+
4019 // o Forward (alice owns less BTC than is in her final offer.
4020 //
-
4021 // There are six cases that we need to test:
-
4022 // o alice crosses her own offer on the first leg (BTC).
-
4023 // o alice crosses her own offer on the second leg (USD).
-
4024 // o alice crosses her own offers on both legs.
-
4025 // All three cases need to be tested:
-
4026 // o In reverse (alice has enough BTC to cover her offer) and
-
4027 // o Forward (alice owns less BTC than is in her final offer.
-
4028 //
-
4029 // It turns out that two of the forward cases fail for a different
-
4030 // reason. They are therefore commented out here, But they are
-
4031 // revisited in the testSelfPayUnlimitedFunds() unit test.
-
4032
-
4033 using namespace jtx;
+
4021 // It turns out that two of the forward cases fail for a different
+
4022 // reason. They are therefore commented out here, But they are
+
4023 // revisited in the testSelfPayUnlimitedFunds() unit test.
+
4024
+
4025 using namespace jtx;
+
4026
+
4027 Env env{*this, features};
+
4028 auto const baseFee = env.current()->fees().base.drops();
+
4029
+
4030 auto const gw = Account("gw");
+
4031 auto const BTC = gw["BTC"];
+
4032 auto const USD = gw["USD"];
+
4033 auto const startXrpBalance = XRP(4000000);
4034
-
4035 Env env{*this, features};
-
4036 auto const baseFee = env.current()->fees().base.drops();
+
4035 env.fund(startXrpBalance, gw);
+
4036 env.close();
4037
-
4038 auto const gw = Account("gw");
-
4039 auto const BTC = gw["BTC"];
-
4040 auto const USD = gw["USD"];
-
4041 auto const startXrpBalance = XRP(4000000);
-
4042
-
4043 env.fund(startXrpBalance, gw);
-
4044 env.close();
-
4045
-
4046 env(rate(gw, 1.25));
-
4047 env.close();
-
4048
-
4049 // Test cases
-
4050 struct Actor
+
4038 env(rate(gw, 1.25));
+
4039 env.close();
+
4040
+
4041 // Test cases
+
4042 struct Actor
+
4043 {
+
4044 Account acct;
+
4045 int offers; // offers on account after crossing
+
4046 PrettyAmount xrp; // final expected after crossing
+
4047 PrettyAmount btc; // final expected after crossing
+
4048 PrettyAmount usd; // final expected after crossing
+
4049 };
+
4050 struct TestData
4051 {
-
4052 Account acct;
-
4053 int offers; // offers on account after crossing
-
4054 PrettyAmount xrp; // final expected after crossing
-
4055 PrettyAmount btc; // final expected after crossing
-
4056 PrettyAmount usd; // final expected after crossing
-
4057 };
-
4058 struct TestData
-
4059 {
-
4060 // The first three three integers give the *index* in actors
-
4061 // to assign each of the three roles. By using indices it is
-
4062 // easy for alice to own the offer in the first leg, the second
-
4063 // leg, or both.
-
4064 std::size_t self;
-
4065 std::size_t leg0;
-
4066 std::size_t leg1;
-
4067 PrettyAmount btcStart;
-
4068 std::vector<Actor> actors;
-
4069 };
-
4070
-
4071 // clang-format off
-
4072 TestData const tests[]{
-
4073 // btcStart --------------------- actor[0] --------------------- -------------------- actor[1] -------------------
-
4074 {0, 0, 1, BTC(20), {{"ann", 0, drops(3900000'000000 - 4 * baseFee), BTC(20.0), USD(3000)}, {"abe", 0, drops(4100000'000000 - 3 * baseFee), BTC( 0), USD(750)}}}, // no BTC xfer fee
-
4075 {0, 1, 0, BTC(20), {{"bev", 0, drops(4100000'000000 - 4 * baseFee), BTC( 7.5), USD(2000)}, {"bob", 0, drops(3900000'000000 - 3 * baseFee), BTC(10), USD( 0)}}}, // no USD xfer fee
-
4076 {0, 0, 0, BTC(20), {{"cam", 0, drops(4000000'000000 - 5 * baseFee), BTC(20.0), USD(2000)} }}, // no xfer fee
-
4077 {0, 1, 0, BTC( 5), {{"deb", 1, drops(4040000'000000 - 4 * baseFee), BTC( 0.0), USD(2000)}, {"dan", 1, drops(3960000'000000 - 3 * baseFee), BTC( 4), USD( 0)}}}, // no USD xfer fee
-
4078 };
-
4079 // clang-format on
-
4080
-
4081 for (auto const& t : tests)
-
4082 {
-
4083 Account const& self = t.actors[t.self].acct;
-
4084 Account const& leg0 = t.actors[t.leg0].acct;
-
4085 Account const& leg1 = t.actors[t.leg1].acct;
-
4086
-
4087 for (auto const& actor : t.actors)
-
4088 {
-
4089 env.fund(XRP(4000000), actor.acct);
-
4090 env.close();
-
4091
-
4092 env(trust(actor.acct, BTC(40)));
-
4093 env(trust(actor.acct, USD(8000)));
-
4094 env.close();
-
4095 }
-
4096
-
4097 env(pay(gw, self, t.btcStart));
-
4098 env(pay(gw, self, USD(2000)));
-
4099 if (self.id() != leg1.id())
-
4100 env(pay(gw, leg1, USD(2000)));
-
4101 env.close();
-
4102
-
4103 // Get the initial offers in place. Remember their sequences
-
4104 // so we can delete them later.
-
4105 env(offer(leg0, BTC(10), XRP(100000), tfPassive));
-
4106 env.close();
-
4107 std::uint32_t const leg0OfferSeq = env.seq(leg0) - 1;
-
4108
-
4109 env(offer(leg1, XRP(100000), USD(1000), tfPassive));
-
4110 env.close();
-
4111 std::uint32_t const leg1OfferSeq = env.seq(leg1) - 1;
-
4112
-
4113 // This is the offer that matters.
-
4114 env(offer(self, USD(1000), BTC(10)));
-
4115 env.close();
-
4116 std::uint32_t const selfOfferSeq = env.seq(self) - 1;
-
4117
-
4118 // Verify results.
-
4119 for (auto const& actor : t.actors)
-
4120 {
-
4121 // Sometimes Taker crossing gets lazy about deleting offers.
-
4122 // Treat an empty offer as though it is deleted.
-
4123 auto actorOffers = offersOnAccount(env, actor.acct);
-
4124 auto const offerCount = std::distance(
-
4125 actorOffers.begin(),
- -
4127 actorOffers.begin(),
-
4128 actorOffers.end(),
- -
4130 return (*offer)[sfTakerGets].signum() == 0;
-
4131 }));
-
4132 BEAST_EXPECT(offerCount == actor.offers);
-
4133
-
4134 env.require(balance(actor.acct, actor.xrp));
-
4135 env.require(balance(actor.acct, actor.btc));
-
4136 env.require(balance(actor.acct, actor.usd));
-
4137 }
-
4138 // Remove any offers that might be left hanging around. They
-
4139 // could bollix up later loops.
-
4140 env(offer_cancel(leg0, leg0OfferSeq));
-
4141 env.close();
-
4142 env(offer_cancel(leg1, leg1OfferSeq));
-
4143 env.close();
-
4144 env(offer_cancel(self, selfOfferSeq));
-
4145 env.close();
-
4146 }
-
4147 }
+
4052 // The first three three integers give the *index* in actors
+
4053 // to assign each of the three roles. By using indices it is
+
4054 // easy for alice to own the offer in the first leg, the second
+
4055 // leg, or both.
+
4056 std::size_t self;
+
4057 std::size_t leg0;
+
4058 std::size_t leg1;
+
4059 PrettyAmount btcStart;
+
4060 std::vector<Actor> actors;
+
4061 };
+
4062
+
4063 // clang-format off
+
4064 TestData const tests[]{
+
4065 // btcStart --------------------- actor[0] --------------------- -------------------- actor[1] -------------------
+
4066 {0, 0, 1, BTC(20), {{"ann", 0, drops(3900000'000000 - 4 * baseFee), BTC(20.0), USD(3000)}, {"abe", 0, drops(4100000'000000 - 3 * baseFee), BTC( 0), USD(750)}}}, // no BTC xfer fee
+
4067 {0, 1, 0, BTC(20), {{"bev", 0, drops(4100000'000000 - 4 * baseFee), BTC( 7.5), USD(2000)}, {"bob", 0, drops(3900000'000000 - 3 * baseFee), BTC(10), USD( 0)}}}, // no USD xfer fee
+
4068 {0, 0, 0, BTC(20), {{"cam", 0, drops(4000000'000000 - 5 * baseFee), BTC(20.0), USD(2000)} }}, // no xfer fee
+
4069 {0, 1, 0, BTC( 5), {{"deb", 1, drops(4040000'000000 - 4 * baseFee), BTC( 0.0), USD(2000)}, {"dan", 1, drops(3960000'000000 - 3 * baseFee), BTC( 4), USD( 0)}}}, // no USD xfer fee
+
4070 };
+
4071 // clang-format on
+
4072
+
4073 for (auto const& t : tests)
+
4074 {
+
4075 Account const& self = t.actors[t.self].acct;
+
4076 Account const& leg0 = t.actors[t.leg0].acct;
+
4077 Account const& leg1 = t.actors[t.leg1].acct;
+
4078
+
4079 for (auto const& actor : t.actors)
+
4080 {
+
4081 env.fund(XRP(4000000), actor.acct);
+
4082 env.close();
+
4083
+
4084 env(trust(actor.acct, BTC(40)));
+
4085 env(trust(actor.acct, USD(8000)));
+
4086 env.close();
+
4087 }
+
4088
+
4089 env(pay(gw, self, t.btcStart));
+
4090 env(pay(gw, self, USD(2000)));
+
4091 if (self.id() != leg1.id())
+
4092 env(pay(gw, leg1, USD(2000)));
+
4093 env.close();
+
4094
+
4095 // Get the initial offers in place. Remember their sequences
+
4096 // so we can delete them later.
+
4097 env(offer(leg0, BTC(10), XRP(100000), tfPassive));
+
4098 env.close();
+
4099 std::uint32_t const leg0OfferSeq = env.seq(leg0) - 1;
+
4100
+
4101 env(offer(leg1, XRP(100000), USD(1000), tfPassive));
+
4102 env.close();
+
4103 std::uint32_t const leg1OfferSeq = env.seq(leg1) - 1;
+
4104
+
4105 // This is the offer that matters.
+
4106 env(offer(self, USD(1000), BTC(10)));
+
4107 env.close();
+
4108 std::uint32_t const selfOfferSeq = env.seq(self) - 1;
+
4109
+
4110 // Verify results.
+
4111 for (auto const& actor : t.actors)
+
4112 {
+
4113 // Sometimes Taker crossing gets lazy about deleting offers.
+
4114 // Treat an empty offer as though it is deleted.
+
4115 auto actorOffers = offersOnAccount(env, actor.acct);
+
4116 auto const offerCount = std::distance(
+
4117 actorOffers.begin(),
+ +
4119 actorOffers.begin(),
+
4120 actorOffers.end(),
+ +
4122 return (*offer)[sfTakerGets].signum() == 0;
+
4123 }));
+
4124 BEAST_EXPECT(offerCount == actor.offers);
+
4125
+
4126 env.require(balance(actor.acct, actor.xrp));
+
4127 env.require(balance(actor.acct, actor.btc));
+
4128 env.require(balance(actor.acct, actor.usd));
+
4129 }
+
4130 // Remove any offers that might be left hanging around. They
+
4131 // could bollix up later loops.
+
4132 env(offer_cancel(leg0, leg0OfferSeq));
+
4133 env.close();
+
4134 env(offer_cancel(leg1, leg1OfferSeq));
+
4135 env.close();
+
4136 env(offer_cancel(self, selfOfferSeq));
+
4137 env.close();
+
4138 }
+
4139 }
-
4148
-
4149 void
-
- -
4151 {
-
4152 testcase("Self Pay Unlimited Funds");
-
4153 // The Taker offer crossing code recognized when Alice was paying
-
4154 // Alice the same denomination. In this case, as long as Alice
-
4155 // has a little bit of that denomination, it treats Alice as though
-
4156 // she has unlimited funds in that denomination.
-
4157 //
-
4158 // Huh? What kind of sense does that make?
-
4159 //
-
4160 // One way to think about it is to break a single payment into a
-
4161 // series of very small payments executed sequentially but very
-
4162 // quickly. Alice needs to pay herself 1 USD, but she only has
-
4163 // 0.01 USD. Alice says, "Hey Alice, let me pay you a penny."
-
4164 // Alice does this, taking the penny out of her pocket and then
-
4165 // putting it back in her pocket. Then she says, "Hey Alice,
-
4166 // I found another penny. I can pay you another penny." Repeat
-
4167 // these steps 100 times and Alice has paid herself 1 USD even though
-
4168 // she only owns 0.01 USD.
+
4140
+
4141 void
+
+ +
4143 {
+
4144 testcase("Self Pay Unlimited Funds");
+
4145 // The Taker offer crossing code recognized when Alice was paying
+
4146 // Alice the same denomination. In this case, as long as Alice
+
4147 // has a little bit of that denomination, it treats Alice as though
+
4148 // she has unlimited funds in that denomination.
+
4149 //
+
4150 // Huh? What kind of sense does that make?
+
4151 //
+
4152 // One way to think about it is to break a single payment into a
+
4153 // series of very small payments executed sequentially but very
+
4154 // quickly. Alice needs to pay herself 1 USD, but she only has
+
4155 // 0.01 USD. Alice says, "Hey Alice, let me pay you a penny."
+
4156 // Alice does this, taking the penny out of her pocket and then
+
4157 // putting it back in her pocket. Then she says, "Hey Alice,
+
4158 // I found another penny. I can pay you another penny." Repeat
+
4159 // these steps 100 times and Alice has paid herself 1 USD even though
+
4160 // she only owns 0.01 USD.
+
4161 //
+
4162 // That's all very nice, but the payment code does not support this
+
4163 // optimization. In part that's because the payment code can
+
4164 // operate on a whole batch of offers. As a matter of fact, it can
+
4165 // deal in two consecutive batches of offers. It would take a great
+
4166 // deal of sorting out to figure out which offers in the two batches
+
4167 // had the same owner and give them special processing. And,
+
4168 // honestly, it's a weird little corner case.
4169 //
-
4170 // That's all very nice, but the payment code does not support this
-
4171 // optimization. In part that's because the payment code can
-
4172 // operate on a whole batch of offers. As a matter of fact, it can
-
4173 // deal in two consecutive batches of offers. It would take a great
-
4174 // deal of sorting out to figure out which offers in the two batches
-
4175 // had the same owner and give them special processing. And,
-
4176 // honestly, it's a weird little corner case.
-
4177 //
-
4178 // So, since Flow offer crossing uses the payments engine, Flow
-
4179 // offer crossing no longer supports this optimization.
-
4180 //
-
4181 // The following test shows the difference in the behaviors between
-
4182 // Taker offer crossing and Flow offer crossing.
-
4183
-
4184 using namespace jtx;
+
4170 // So, since Flow offer crossing uses the payments engine, Flow
+
4171 // offer crossing no longer supports this optimization.
+
4172 //
+
4173 // The following test shows the difference in the behaviors between
+
4174 // Taker offer crossing and Flow offer crossing.
+
4175
+
4176 using namespace jtx;
+
4177
+
4178 Env env{*this, features};
+
4179 auto const baseFee = env.current()->fees().base.drops();
+
4180
+
4181 auto const gw = Account("gw");
+
4182 auto const BTC = gw["BTC"];
+
4183 auto const USD = gw["USD"];
+
4184 auto const startXrpBalance = XRP(4000000);
4185
-
4186 Env env{*this, features};
-
4187 auto const baseFee = env.current()->fees().base.drops();
+
4186 env.fund(startXrpBalance, gw);
+
4187 env.close();
4188
-
4189 auto const gw = Account("gw");
-
4190 auto const BTC = gw["BTC"];
-
4191 auto const USD = gw["USD"];
-
4192 auto const startXrpBalance = XRP(4000000);
-
4193
-
4194 env.fund(startXrpBalance, gw);
-
4195 env.close();
-
4196
-
4197 env(rate(gw, 1.25));
-
4198 env.close();
-
4199
-
4200 // Test cases
-
4201 struct Actor
+
4189 env(rate(gw, 1.25));
+
4190 env.close();
+
4191
+
4192 // Test cases
+
4193 struct Actor
+
4194 {
+
4195 Account acct;
+
4196 int offers; // offers on account after crossing
+
4197 PrettyAmount xrp; // final expected after crossing
+
4198 PrettyAmount btc; // final expected after crossing
+
4199 PrettyAmount usd; // final expected after crossing
+
4200 };
+
4201 struct TestData
4202 {
-
4203 Account acct;
-
4204 int offers; // offers on account after crossing
-
4205 PrettyAmount xrp; // final expected after crossing
-
4206 PrettyAmount btc; // final expected after crossing
-
4207 PrettyAmount usd; // final expected after crossing
-
4208 };
-
4209 struct TestData
-
4210 {
-
4211 // The first three three integers give the *index* in actors
-
4212 // to assign each of the three roles. By using indices it is
-
4213 // easy for alice to own the offer in the first leg, the second
-
4214 // leg, or both.
-
4215 std::size_t self;
-
4216 std::size_t leg0;
-
4217 std::size_t leg1;
-
4218 PrettyAmount btcStart;
-
4219 std::vector<Actor> actors;
-
4220 };
+
4203 // The first three three integers give the *index* in actors
+
4204 // to assign each of the three roles. By using indices it is
+
4205 // easy for alice to own the offer in the first leg, the second
+
4206 // leg, or both.
+
4207 std::size_t self;
+
4208 std::size_t leg0;
+
4209 std::size_t leg1;
+
4210 PrettyAmount btcStart;
+
4211 std::vector<Actor> actors;
+
4212 };
+
4213
+
4214 // clang-format off
+
4215 TestData const tests[]{
+
4216 // btcStart ------------------- actor[0] -------------------- ------------------- actor[1] --------------------
+
4217 {0, 0, 1, BTC(5), {{"gay", 1, drops(3950000'000000 - 4 * baseFee), BTC(5), USD(2500)}, {"gar", 1, drops(4050000'000000 - 3 * baseFee), BTC(0), USD(1375)}}}, // no BTC xfer fee
+
4218 {0, 0, 0, BTC(5), {{"hye", 2, drops(4000000'000000 - 5 * baseFee), BTC(5), USD(2000)} }} // no xfer fee
+
4219 };
+
4220 // clang-format on
4221
-
4222 // clang-format off
-
4223 TestData const tests[]{
-
4224 // btcStart ------------------- actor[0] -------------------- ------------------- actor[1] --------------------
-
4225 {0, 0, 1, BTC(5), {{"gay", 1, drops(3950000'000000 - 4 * baseFee), BTC(5), USD(2500)}, {"gar", 1, drops(4050000'000000 - 3 * baseFee), BTC(0), USD(1375)}}}, // no BTC xfer fee
-
4226 {0, 0, 0, BTC(5), {{"hye", 2, drops(4000000'000000 - 5 * baseFee), BTC(5), USD(2000)} }} // no xfer fee
-
4227 };
-
4228 // clang-format on
-
4229
-
4230 for (auto const& t : tests)
-
4231 {
-
4232 Account const& self = t.actors[t.self].acct;
-
4233 Account const& leg0 = t.actors[t.leg0].acct;
-
4234 Account const& leg1 = t.actors[t.leg1].acct;
-
4235
-
4236 for (auto const& actor : t.actors)
-
4237 {
-
4238 env.fund(XRP(4000000), actor.acct);
-
4239 env.close();
-
4240
-
4241 env(trust(actor.acct, BTC(40)));
-
4242 env(trust(actor.acct, USD(8000)));
-
4243 env.close();
-
4244 }
-
4245
-
4246 env(pay(gw, self, t.btcStart));
-
4247 env(pay(gw, self, USD(2000)));
-
4248 if (self.id() != leg1.id())
-
4249 env(pay(gw, leg1, USD(2000)));
-
4250 env.close();
-
4251
-
4252 // Get the initial offers in place. Remember their sequences
-
4253 // so we can delete them later.
-
4254 env(offer(leg0, BTC(10), XRP(100000), tfPassive));
-
4255 env.close();
-
4256 std::uint32_t const leg0OfferSeq = env.seq(leg0) - 1;
-
4257
-
4258 env(offer(leg1, XRP(100000), USD(1000), tfPassive));
-
4259 env.close();
-
4260 std::uint32_t const leg1OfferSeq = env.seq(leg1) - 1;
-
4261
-
4262 // This is the offer that matters.
-
4263 env(offer(self, USD(1000), BTC(10)));
-
4264 env.close();
-
4265 std::uint32_t const selfOfferSeq = env.seq(self) - 1;
-
4266
-
4267 // Verify results.
-
4268 for (auto const& actor : t.actors)
-
4269 {
-
4270 // Sometimes Taker offer crossing gets lazy about deleting
-
4271 // offers. Treat an empty offer as though it is deleted.
-
4272 auto actorOffers = offersOnAccount(env, actor.acct);
-
4273 auto const offerCount = std::distance(
-
4274 actorOffers.begin(),
- -
4276 actorOffers.begin(),
-
4277 actorOffers.end(),
- -
4279 return (*offer)[sfTakerGets].signum() == 0;
-
4280 }));
-
4281 BEAST_EXPECT(offerCount == actor.offers);
-
4282
-
4283 env.require(balance(actor.acct, actor.xrp));
-
4284 env.require(balance(actor.acct, actor.btc));
-
4285 env.require(balance(actor.acct, actor.usd));
-
4286 }
-
4287 // Remove any offers that might be left hanging around. They
-
4288 // could bollix up later loops.
-
4289 env(offer_cancel(leg0, leg0OfferSeq));
-
4290 env.close();
-
4291 env(offer_cancel(leg1, leg1OfferSeq));
-
4292 env.close();
-
4293 env(offer_cancel(self, selfOfferSeq));
-
4294 env.close();
-
4295 }
-
4296 }
+
4222 for (auto const& t : tests)
+
4223 {
+
4224 Account const& self = t.actors[t.self].acct;
+
4225 Account const& leg0 = t.actors[t.leg0].acct;
+
4226 Account const& leg1 = t.actors[t.leg1].acct;
+
4227
+
4228 for (auto const& actor : t.actors)
+
4229 {
+
4230 env.fund(XRP(4000000), actor.acct);
+
4231 env.close();
+
4232
+
4233 env(trust(actor.acct, BTC(40)));
+
4234 env(trust(actor.acct, USD(8000)));
+
4235 env.close();
+
4236 }
+
4237
+
4238 env(pay(gw, self, t.btcStart));
+
4239 env(pay(gw, self, USD(2000)));
+
4240 if (self.id() != leg1.id())
+
4241 env(pay(gw, leg1, USD(2000)));
+
4242 env.close();
+
4243
+
4244 // Get the initial offers in place. Remember their sequences
+
4245 // so we can delete them later.
+
4246 env(offer(leg0, BTC(10), XRP(100000), tfPassive));
+
4247 env.close();
+
4248 std::uint32_t const leg0OfferSeq = env.seq(leg0) - 1;
+
4249
+
4250 env(offer(leg1, XRP(100000), USD(1000), tfPassive));
+
4251 env.close();
+
4252 std::uint32_t const leg1OfferSeq = env.seq(leg1) - 1;
+
4253
+
4254 // This is the offer that matters.
+
4255 env(offer(self, USD(1000), BTC(10)));
+
4256 env.close();
+
4257 std::uint32_t const selfOfferSeq = env.seq(self) - 1;
+
4258
+
4259 // Verify results.
+
4260 for (auto const& actor : t.actors)
+
4261 {
+
4262 // Sometimes Taker offer crossing gets lazy about deleting
+
4263 // offers. Treat an empty offer as though it is deleted.
+
4264 auto actorOffers = offersOnAccount(env, actor.acct);
+
4265 auto const offerCount = std::distance(
+
4266 actorOffers.begin(),
+ +
4268 actorOffers.begin(),
+
4269 actorOffers.end(),
+ +
4271 return (*offer)[sfTakerGets].signum() == 0;
+
4272 }));
+
4273 BEAST_EXPECT(offerCount == actor.offers);
+
4274
+
4275 env.require(balance(actor.acct, actor.xrp));
+
4276 env.require(balance(actor.acct, actor.btc));
+
4277 env.require(balance(actor.acct, actor.usd));
+
4278 }
+
4279 // Remove any offers that might be left hanging around. They
+
4280 // could bollix up later loops.
+
4281 env(offer_cancel(leg0, leg0OfferSeq));
+
4282 env.close();
+
4283 env(offer_cancel(leg1, leg1OfferSeq));
+
4284 env.close();
+
4285 env(offer_cancel(self, selfOfferSeq));
+
4286 env.close();
+
4287 }
+
4288 }
-
4297
-
4298 void
-
- -
4300 {
-
4301 testcase("lsfRequireAuth");
-
4302
-
4303 using namespace jtx;
-
4304
-
4305 Env env{*this, features};
-
4306
-
4307 auto const gw = Account("gw");
-
4308 auto const alice = Account("alice");
-
4309 auto const bob = Account("bob");
-
4310 auto const gwUSD = gw["USD"];
-
4311 auto const aliceUSD = alice["USD"];
-
4312 auto const bobUSD = bob["USD"];
-
4313
-
4314 env.fund(XRP(400000), gw, alice, bob);
-
4315 env.close();
-
4316
-
4317 // GW requires authorization for holders of its IOUs
-
4318 env(fset(gw, asfRequireAuth));
-
4319 env.close();
-
4320
-
4321 // Properly set trust and have gw authorize bob and alice
-
4322 env(trust(gw, bobUSD(100)), txflags(tfSetfAuth));
-
4323 env(trust(bob, gwUSD(100)));
-
4324 env(trust(gw, aliceUSD(100)), txflags(tfSetfAuth));
-
4325 env(trust(alice, gwUSD(100)));
-
4326 // Alice is able to place the offer since the GW has authorized her
-
4327 env(offer(alice, gwUSD(40), XRP(4000)));
-
4328 env.close();
+
4289
+
4290 void
+
+ +
4292 {
+
4293 testcase("lsfRequireAuth");
+
4294
+
4295 using namespace jtx;
+
4296
+
4297 Env env{*this, features};
+
4298
+
4299 auto const gw = Account("gw");
+
4300 auto const alice = Account("alice");
+
4301 auto const bob = Account("bob");
+
4302 auto const gwUSD = gw["USD"];
+
4303 auto const aliceUSD = alice["USD"];
+
4304 auto const bobUSD = bob["USD"];
+
4305
+
4306 env.fund(XRP(400000), gw, alice, bob);
+
4307 env.close();
+
4308
+
4309 // GW requires authorization for holders of its IOUs
+
4310 env(fset(gw, asfRequireAuth));
+
4311 env.close();
+
4312
+
4313 // Properly set trust and have gw authorize bob and alice
+
4314 env(trust(gw, bobUSD(100)), txflags(tfSetfAuth));
+
4315 env(trust(bob, gwUSD(100)));
+
4316 env(trust(gw, aliceUSD(100)), txflags(tfSetfAuth));
+
4317 env(trust(alice, gwUSD(100)));
+
4318 // Alice is able to place the offer since the GW has authorized her
+
4319 env(offer(alice, gwUSD(40), XRP(4000)));
+
4320 env.close();
+
4321
+
4322 env.require(offers(alice, 1));
+
4323 env.require(balance(alice, gwUSD(0)));
+
4324
+
4325 env(pay(gw, bob, gwUSD(50)));
+
4326 env.close();
+
4327
+
4328 env.require(balance(bob, gwUSD(50)));
4329
-
4330 env.require(offers(alice, 1));
-
4331 env.require(balance(alice, gwUSD(0)));
-
4332
-
4333 env(pay(gw, bob, gwUSD(50)));
-
4334 env.close();
-
4335
-
4336 env.require(balance(bob, gwUSD(50)));
-
4337
-
4338 // Bob's offer should cross Alice's
-
4339 env(offer(bob, XRP(4000), gwUSD(40)));
-
4340 env.close();
-
4341
-
4342 env.require(offers(alice, 0));
-
4343 env.require(balance(alice, gwUSD(40)));
-
4344
-
4345 env.require(offers(bob, 0));
-
4346 env.require(balance(bob, gwUSD(10)));
-
4347 }
+
4330 // Bob's offer should cross Alice's
+
4331 env(offer(bob, XRP(4000), gwUSD(40)));
+
4332 env.close();
+
4333
+
4334 env.require(offers(alice, 0));
+
4335 env.require(balance(alice, gwUSD(40)));
+
4336
+
4337 env.require(offers(bob, 0));
+
4338 env.require(balance(bob, gwUSD(10)));
+
4339 }
-
4348
-
4349 void
-
- -
4351 {
-
4352 testcase("Missing Auth");
-
4353 // 1. alice creates an offer to acquire USD/gw, an asset for which
-
4354 // she does not have a trust line. At some point in the future,
-
4355 // gw adds lsfRequireAuth. Then, later, alice's offer is crossed.
-
4356 // Alice's offer is deleted, not consumed, since alice is not
-
4357 // authorized to hold USD/gw.
+
4340
+
4341 void
+
+ +
4343 {
+
4344 testcase("Missing Auth");
+
4345 // 1. alice creates an offer to acquire USD/gw, an asset for which
+
4346 // she does not have a trust line. At some point in the future,
+
4347 // gw adds lsfRequireAuth. Then, later, alice's offer is crossed.
+
4348 // Alice's offer is deleted, not consumed, since alice is not
+
4349 // authorized to hold USD/gw.
+
4350 //
+
4351 // 2. alice tries to create an offer for USD/gw, now that gw has
+
4352 // lsfRequireAuth set. This time the offer create fails because
+
4353 // alice is not authorized to hold USD/gw.
+
4354 //
+
4355 // 3. Next, gw creates a trust line to alice, but does not set
+
4356 // tfSetfAuth on that trust line. alice attempts to create an
+
4357 // offer and again fails.
4358 //
-
4359 // 2. alice tries to create an offer for USD/gw, now that gw has
-
4360 // lsfRequireAuth set. This time the offer create fails because
-
4361 // alice is not authorized to hold USD/gw.
-
4362 //
-
4363 // 3. Next, gw creates a trust line to alice, but does not set
-
4364 // tfSetfAuth on that trust line. alice attempts to create an
-
4365 // offer and again fails.
-
4366 //
-
4367 // 4. Finally, gw sets tsfSetAuth on the trust line authorizing
-
4368 // alice to own USD/gw. At this point alice successfully
-
4369 // creates and crosses an offer for USD/gw.
-
4370
-
4371 using namespace jtx;
-
4372
-
4373 Env env{*this, features};
-
4374
-
4375 auto const gw = Account("gw");
-
4376 auto const alice = Account("alice");
-
4377 auto const bob = Account("bob");
-
4378 auto const gwUSD = gw["USD"];
-
4379 auto const aliceUSD = alice["USD"];
-
4380 auto const bobUSD = bob["USD"];
-
4381
-
4382 env.fund(XRP(400000), gw, alice, bob);
+
4359 // 4. Finally, gw sets tsfSetAuth on the trust line authorizing
+
4360 // alice to own USD/gw. At this point alice successfully
+
4361 // creates and crosses an offer for USD/gw.
+
4362
+
4363 using namespace jtx;
+
4364
+
4365 Env env{*this, features};
+
4366
+
4367 auto const gw = Account("gw");
+
4368 auto const alice = Account("alice");
+
4369 auto const bob = Account("bob");
+
4370 auto const gwUSD = gw["USD"];
+
4371 auto const aliceUSD = alice["USD"];
+
4372 auto const bobUSD = bob["USD"];
+
4373
+
4374 env.fund(XRP(400000), gw, alice, bob);
+
4375 env.close();
+
4376
+
4377 env(offer(alice, gwUSD(40), XRP(4000)));
+
4378 env.close();
+
4379
+
4380 env.require(offers(alice, 1));
+
4381 env.require(balance(alice, gwUSD(none)));
+
4382 env(fset(gw, asfRequireAuth));
4383 env.close();
4384
-
4385 env(offer(alice, gwUSD(40), XRP(4000)));
+
4385 env(trust(gw, bobUSD(100)), txflags(tfSetfAuth));
4386 env.close();
-
4387
-
4388 env.require(offers(alice, 1));
-
4389 env.require(balance(alice, gwUSD(none)));
-
4390 env(fset(gw, asfRequireAuth));
+
4387 env(trust(bob, gwUSD(100)));
+
4388 env.close();
+
4389
+
4390 env(pay(gw, bob, gwUSD(50)));
4391 env.close();
-
4392
-
4393 env(trust(gw, bobUSD(100)), txflags(tfSetfAuth));
-
4394 env.close();
-
4395 env(trust(bob, gwUSD(100)));
-
4396 env.close();
-
4397
-
4398 env(pay(gw, bob, gwUSD(50)));
-
4399 env.close();
-
4400 env.require(balance(bob, gwUSD(50)));
-
4401
-
4402 // gw now requires authorization and bob has gwUSD(50). Let's see if
-
4403 // bob can cross alice's offer.
-
4404 //
-
4405 // Bob's offer shouldn't cross and alice's unauthorized offer should be
-
4406 // deleted.
-
4407 env(offer(bob, XRP(4000), gwUSD(40)));
-
4408 env.close();
-
4409 std::uint32_t const bobOfferSeq = env.seq(bob) - 1;
-
4410
-
4411 env.require(offers(alice, 0));
-
4412 // alice's unauthorized offer is deleted & bob's offer not crossed.
-
4413 env.require(balance(alice, gwUSD(none)));
-
4414 env.require(offers(bob, 1));
-
4415 env.require(balance(bob, gwUSD(50)));
-
4416
-
4417 // See if alice can create an offer without authorization. alice
-
4418 // should not be able to create the offer and bob's offer should be
-
4419 // untouched.
-
4420 env(offer(alice, gwUSD(40), XRP(4000)), ter(tecNO_LINE));
-
4421 env.close();
-
4422
-
4423 env.require(offers(alice, 0));
-
4424 env.require(balance(alice, gwUSD(none)));
+
4392 env.require(balance(bob, gwUSD(50)));
+
4393
+
4394 // gw now requires authorization and bob has gwUSD(50). Let's see if
+
4395 // bob can cross alice's offer.
+
4396 //
+
4397 // Bob's offer shouldn't cross and alice's unauthorized offer should be
+
4398 // deleted.
+
4399 env(offer(bob, XRP(4000), gwUSD(40)));
+
4400 env.close();
+
4401 std::uint32_t const bobOfferSeq = env.seq(bob) - 1;
+
4402
+
4403 env.require(offers(alice, 0));
+
4404 // alice's unauthorized offer is deleted & bob's offer not crossed.
+
4405 env.require(balance(alice, gwUSD(none)));
+
4406 env.require(offers(bob, 1));
+
4407 env.require(balance(bob, gwUSD(50)));
+
4408
+
4409 // See if alice can create an offer without authorization. alice
+
4410 // should not be able to create the offer and bob's offer should be
+
4411 // untouched.
+
4412 env(offer(alice, gwUSD(40), XRP(4000)), ter(tecNO_LINE));
+
4413 env.close();
+
4414
+
4415 env.require(offers(alice, 0));
+
4416 env.require(balance(alice, gwUSD(none)));
+
4417
+
4418 env.require(offers(bob, 1));
+
4419 env.require(balance(bob, gwUSD(50)));
+
4420
+
4421 // Set up a trust line for alice, but don't authorize it. alice
+
4422 // should still not be able to create an offer for USD/gw.
+
4423 env(trust(gw, aliceUSD(100)));
+
4424 env.close();
4425
-
4426 env.require(offers(bob, 1));
-
4427 env.require(balance(bob, gwUSD(50)));
+
4426 env(offer(alice, gwUSD(40), XRP(4000)), ter(tecNO_AUTH));
+
4427 env.close();
4428
-
4429 // Set up a trust line for alice, but don't authorize it. alice
-
4430 // should still not be able to create an offer for USD/gw.
-
4431 env(trust(gw, aliceUSD(100)));
-
4432 env.close();
-
4433
-
4434 env(offer(alice, gwUSD(40), XRP(4000)), ter(tecNO_AUTH));
-
4435 env.close();
-
4436
-
4437 env.require(offers(alice, 0));
-
4438 env.require(balance(alice, gwUSD(0)));
+
4429 env.require(offers(alice, 0));
+
4430 env.require(balance(alice, gwUSD(0)));
+
4431
+
4432 env.require(offers(bob, 1));
+
4433 env.require(balance(bob, gwUSD(50)));
+
4434
+
4435 // Delete bob's offer so alice can create an offer without crossing.
+
4436 env(offer_cancel(bob, bobOfferSeq));
+
4437 env.close();
+
4438 env.require(offers(bob, 0));
4439
-
4440 env.require(offers(bob, 1));
-
4441 env.require(balance(bob, gwUSD(50)));
-
4442
-
4443 // Delete bob's offer so alice can create an offer without crossing.
-
4444 env(offer_cancel(bob, bobOfferSeq));
-
4445 env.close();
-
4446 env.require(offers(bob, 0));
-
4447
-
4448 // Finally, set up an authorized trust line for alice. Now alice's
-
4449 // offer should succeed. Note that, since this is an offer rather
-
4450 // than a payment, alice does not need to set a trust line limit.
-
4451 env(trust(gw, aliceUSD(100)), txflags(tfSetfAuth));
-
4452 env.close();
-
4453
-
4454 env(offer(alice, gwUSD(40), XRP(4000)));
-
4455 env.close();
-
4456
-
4457 env.require(offers(alice, 1));
-
4458
-
4459 // Now bob creates his offer again. alice's offer should cross.
-
4460 env(offer(bob, XRP(4000), gwUSD(40)));
-
4461 env.close();
-
4462
-
4463 env.require(offers(alice, 0));
-
4464 env.require(balance(alice, gwUSD(40)));
-
4465
-
4466 env.require(offers(bob, 0));
-
4467 env.require(balance(bob, gwUSD(10)));
-
4468 }
+
4440 // Finally, set up an authorized trust line for alice. Now alice's
+
4441 // offer should succeed. Note that, since this is an offer rather
+
4442 // than a payment, alice does not need to set a trust line limit.
+
4443 env(trust(gw, aliceUSD(100)), txflags(tfSetfAuth));
+
4444 env.close();
+
4445
+
4446 env(offer(alice, gwUSD(40), XRP(4000)));
+
4447 env.close();
+
4448
+
4449 env.require(offers(alice, 1));
+
4450
+
4451 // Now bob creates his offer again. alice's offer should cross.
+
4452 env(offer(bob, XRP(4000), gwUSD(40)));
+
4453 env.close();
+
4454
+
4455 env.require(offers(alice, 0));
+
4456 env.require(balance(alice, gwUSD(40)));
+
4457
+
4458 env.require(offers(bob, 0));
+
4459 env.require(balance(bob, gwUSD(10)));
+
4460 }
+
4461
+
4462 void
+
+ +
4464 {
+
4465 testcase("RippleConnect Smoketest payment flow");
+
4466 using namespace jtx;
+
4467
+
4468 Env env{*this, features};
4469
-
4470 void
-
- -
4472 {
-
4473 testcase("RippleConnect Smoketest payment flow");
-
4474 using namespace jtx;
-
4475
-
4476 Env env{*this, features};
+
4470 // This test mimics the payment flow used in the Ripple Connect
+
4471 // smoke test. The players:
+
4472 // A USD gateway with hot and cold wallets
+
4473 // A EUR gateway with hot and cold walllets
+
4474 // A MM gateway that will provide offers from USD->EUR and EUR->USD
+
4475 // A path from hot US to cold EUR is found and then used to send
+
4476 // USD for EUR that goes through the market maker
4477
-
4478 // This test mimics the payment flow used in the Ripple Connect
-
4479 // smoke test. The players:
-
4480 // A USD gateway with hot and cold wallets
-
4481 // A EUR gateway with hot and cold walllets
-
4482 // A MM gateway that will provide offers from USD->EUR and EUR->USD
-
4483 // A path from hot US to cold EUR is found and then used to send
-
4484 // USD for EUR that goes through the market maker
-
4485
-
4486 auto const hotUS = Account("hotUS");
-
4487 auto const coldUS = Account("coldUS");
-
4488 auto const hotEU = Account("hotEU");
-
4489 auto const coldEU = Account("coldEU");
-
4490 auto const mm = Account("mm");
-
4491
-
4492 auto const USD = coldUS["USD"];
-
4493 auto const EUR = coldEU["EUR"];
-
4494
-
4495 env.fund(XRP(100000), hotUS, coldUS, hotEU, coldEU, mm);
+
4478 auto const hotUS = Account("hotUS");
+
4479 auto const coldUS = Account("coldUS");
+
4480 auto const hotEU = Account("hotEU");
+
4481 auto const coldEU = Account("coldEU");
+
4482 auto const mm = Account("mm");
+
4483
+
4484 auto const USD = coldUS["USD"];
+
4485 auto const EUR = coldEU["EUR"];
+
4486
+
4487 env.fund(XRP(100000), hotUS, coldUS, hotEU, coldEU, mm);
+
4488 env.close();
+
4489
+
4490 // Cold wallets require trust but will ripple by default
+
4491 for (auto const& cold : {coldUS, coldEU})
+
4492 {
+
4493 env(fset(cold, asfRequireAuth));
+
4494 env(fset(cold, asfDefaultRipple));
+
4495 }
4496 env.close();
4497
-
4498 // Cold wallets require trust but will ripple by default
-
4499 for (auto const& cold : {coldUS, coldEU})
-
4500 {
-
4501 env(fset(cold, asfRequireAuth));
-
4502 env(fset(cold, asfDefaultRipple));
-
4503 }
+
4498 // Each hot wallet trusts the related cold wallet for a large amount
+
4499 env(trust(hotUS, USD(10000000)), txflags(tfSetNoRipple));
+
4500 env(trust(hotEU, EUR(10000000)), txflags(tfSetNoRipple));
+
4501 // Market maker trusts both cold wallets for a large amount
+
4502 env(trust(mm, USD(10000000)), txflags(tfSetNoRipple));
+
4503 env(trust(mm, EUR(10000000)), txflags(tfSetNoRipple));
4504 env.close();
4505
-
4506 // Each hot wallet trusts the related cold wallet for a large amount
-
4507 env(trust(hotUS, USD(10000000)), txflags(tfSetNoRipple));
-
4508 env(trust(hotEU, EUR(10000000)), txflags(tfSetNoRipple));
-
4509 // Market maker trusts both cold wallets for a large amount
-
4510 env(trust(mm, USD(10000000)), txflags(tfSetNoRipple));
-
4511 env(trust(mm, EUR(10000000)), txflags(tfSetNoRipple));
-
4512 env.close();
-
4513
-
4514 // Gateways authorize the trustlines of hot and market maker
-
4515 env(trust(coldUS, USD(0), hotUS, tfSetfAuth));
-
4516 env(trust(coldEU, EUR(0), hotEU, tfSetfAuth));
-
4517 env(trust(coldUS, USD(0), mm, tfSetfAuth));
-
4518 env(trust(coldEU, EUR(0), mm, tfSetfAuth));
-
4519 env.close();
-
4520
-
4521 // Issue currency from cold wallets to hot and market maker
-
4522 env(pay(coldUS, hotUS, USD(5000000)));
-
4523 env(pay(coldEU, hotEU, EUR(5000000)));
-
4524 env(pay(coldUS, mm, USD(5000000)));
-
4525 env(pay(coldEU, mm, EUR(5000000)));
-
4526 env.close();
-
4527
-
4528 // MM places offers
-
4529 float const rate = 0.9f; // 0.9 USD = 1 EUR
-
4530 env(offer(mm, EUR(4000000 * rate), USD(4000000)),
-
4531 json(jss::Flags, tfSell));
-
4532
-
4533 float const reverseRate = 1.0f / rate * 1.00101f;
-
4534 env(offer(mm, USD(4000000 * reverseRate), EUR(4000000)),
-
4535 json(jss::Flags, tfSell));
-
4536 env.close();
-
4537
-
4538 // There should be a path available from hot US to cold EUR
-
4539 {
-
4540 Json::Value jvParams;
-
4541 jvParams[jss::destination_account] = coldEU.human();
-
4542 jvParams[jss::destination_amount][jss::issuer] = coldEU.human();
-
4543 jvParams[jss::destination_amount][jss::currency] = "EUR";
-
4544 jvParams[jss::destination_amount][jss::value] = 10;
-
4545 jvParams[jss::source_account] = hotUS.human();
-
4546
-
4547 Json::Value const jrr{env.rpc(
-
4548 "json", "ripple_path_find", to_string(jvParams))[jss::result]};
-
4549
-
4550 BEAST_EXPECT(jrr[jss::status] == "success");
-
4551 BEAST_EXPECT(
-
4552 jrr[jss::alternatives].isArray() &&
-
4553 jrr[jss::alternatives].size() > 0);
-
4554 }
-
4555 // Send the payment using the found path.
-
4556 env(pay(hotUS, coldEU, EUR(10)), sendmax(USD(11.1223326)));
-
4557 }
+
4506 // Gateways authorize the trustlines of hot and market maker
+
4507 env(trust(coldUS, USD(0), hotUS, tfSetfAuth));
+
4508 env(trust(coldEU, EUR(0), hotEU, tfSetfAuth));
+
4509 env(trust(coldUS, USD(0), mm, tfSetfAuth));
+
4510 env(trust(coldEU, EUR(0), mm, tfSetfAuth));
+
4511 env.close();
+
4512
+
4513 // Issue currency from cold wallets to hot and market maker
+
4514 env(pay(coldUS, hotUS, USD(5000000)));
+
4515 env(pay(coldEU, hotEU, EUR(5000000)));
+
4516 env(pay(coldUS, mm, USD(5000000)));
+
4517 env(pay(coldEU, mm, EUR(5000000)));
+
4518 env.close();
+
4519
+
4520 // MM places offers
+
4521 float const rate = 0.9f; // 0.9 USD = 1 EUR
+
4522 env(offer(mm, EUR(4000000 * rate), USD(4000000)),
+
4523 json(jss::Flags, tfSell));
+
4524
+
4525 float const reverseRate = 1.0f / rate * 1.00101f;
+
4526 env(offer(mm, USD(4000000 * reverseRate), EUR(4000000)),
+
4527 json(jss::Flags, tfSell));
+
4528 env.close();
+
4529
+
4530 // There should be a path available from hot US to cold EUR
+
4531 {
+
4532 Json::Value jvParams;
+
4533 jvParams[jss::destination_account] = coldEU.human();
+
4534 jvParams[jss::destination_amount][jss::issuer] = coldEU.human();
+
4535 jvParams[jss::destination_amount][jss::currency] = "EUR";
+
4536 jvParams[jss::destination_amount][jss::value] = 10;
+
4537 jvParams[jss::source_account] = hotUS.human();
+
4538
+
4539 Json::Value const jrr{env.rpc(
+
4540 "json", "ripple_path_find", to_string(jvParams))[jss::result]};
+
4541
+
4542 BEAST_EXPECT(jrr[jss::status] == "success");
+
4543 BEAST_EXPECT(
+
4544 jrr[jss::alternatives].isArray() &&
+
4545 jrr[jss::alternatives].size() > 0);
+
4546 }
+
4547 // Send the payment using the found path.
+
4548 env(pay(hotUS, coldEU, EUR(10)), sendmax(USD(11.1223326)));
+
4549 }
-
4558
-
4559 void
-
- -
4561 {
-
4562 testcase("Self Auth");
-
4563
-
4564 using namespace jtx;
-
4565
-
4566 Env env{*this, features};
+
4550
+
4551 void
+
+ +
4553 {
+
4554 testcase("Self Auth");
+
4555
+
4556 using namespace jtx;
+
4557
+
4558 Env env{*this, features};
+
4559
+
4560 auto const gw = Account("gw");
+
4561 auto const alice = Account("alice");
+
4562 auto const gwUSD = gw["USD"];
+
4563 auto const aliceUSD = alice["USD"];
+
4564
+
4565 env.fund(XRP(400000), gw, alice);
+
4566 env.close();
4567
-
4568 auto const gw = Account("gw");
-
4569 auto const alice = Account("alice");
-
4570 auto const gwUSD = gw["USD"];
-
4571 auto const aliceUSD = alice["USD"];
-
4572
-
4573 env.fund(XRP(400000), gw, alice);
-
4574 env.close();
-
4575
-
4576 // Test that gw can create an offer to buy gw's currency.
-
4577 env(offer(gw, gwUSD(40), XRP(4000)));
-
4578 env.close();
-
4579 std::uint32_t const gwOfferSeq = env.seq(gw) - 1;
-
4580 env.require(offers(gw, 1));
-
4581
-
4582 // Since gw has an offer out, gw should not be able to set RequireAuth.
-
4583 env(fset(gw, asfRequireAuth), ter(tecOWNERS));
-
4584 env.close();
-
4585
-
4586 // Cancel gw's offer so we can set RequireAuth.
-
4587 env(offer_cancel(gw, gwOfferSeq));
-
4588 env.close();
-
4589 env.require(offers(gw, 0));
-
4590
-
4591 // gw now requires authorization for holders of its IOUs
-
4592 env(fset(gw, asfRequireAuth));
-
4593 env.close();
-
4594
-
4595 // The test behaves differently with or without DepositPreauth.
-
4596 bool const preauth = features[featureDepositPreauth];
-
4597
-
4598 // Before DepositPreauth an account with lsfRequireAuth set could not
-
4599 // create an offer to buy their own currency. After DepositPreauth
-
4600 // they can.
-
4601 env(offer(gw, gwUSD(40), XRP(4000)),
-
4602 ter(preauth ? TER{tesSUCCESS} : TER{tecNO_LINE}));
-
4603 env.close();
-
4604
-
4605 env.require(offers(gw, preauth ? 1 : 0));
-
4606
-
4607 if (!preauth)
-
4608 // The rest of the test verifies DepositPreauth behavior.
-
4609 return;
+
4568 // Test that gw can create an offer to buy gw's currency.
+
4569 env(offer(gw, gwUSD(40), XRP(4000)));
+
4570 env.close();
+
4571 std::uint32_t const gwOfferSeq = env.seq(gw) - 1;
+
4572 env.require(offers(gw, 1));
+
4573
+
4574 // Since gw has an offer out, gw should not be able to set RequireAuth.
+
4575 env(fset(gw, asfRequireAuth), ter(tecOWNERS));
+
4576 env.close();
+
4577
+
4578 // Cancel gw's offer so we can set RequireAuth.
+
4579 env(offer_cancel(gw, gwOfferSeq));
+
4580 env.close();
+
4581 env.require(offers(gw, 0));
+
4582
+
4583 // gw now requires authorization for holders of its IOUs
+
4584 env(fset(gw, asfRequireAuth));
+
4585 env.close();
+
4586
+
4587 // The test behaves differently with or without DepositPreauth.
+
4588 bool const preauth = features[featureDepositPreauth];
+
4589
+
4590 // Before DepositPreauth an account with lsfRequireAuth set could not
+
4591 // create an offer to buy their own currency. After DepositPreauth
+
4592 // they can.
+
4593 env(offer(gw, gwUSD(40), XRP(4000)),
+
4594 ter(preauth ? TER{tesSUCCESS} : TER{tecNO_LINE}));
+
4595 env.close();
+
4596
+
4597 env.require(offers(gw, preauth ? 1 : 0));
+
4598
+
4599 if (!preauth)
+
4600 // The rest of the test verifies DepositPreauth behavior.
+
4601 return;
+
4602
+
4603 // Set up an authorized trust line and pay alice gwUSD 50.
+
4604 env(trust(gw, aliceUSD(100)), txflags(tfSetfAuth));
+
4605 env(trust(alice, gwUSD(100)));
+
4606 env.close();
+
4607
+
4608 env(pay(gw, alice, gwUSD(50)));
+
4609 env.close();
4610
-
4611 // Set up an authorized trust line and pay alice gwUSD 50.
-
4612 env(trust(gw, aliceUSD(100)), txflags(tfSetfAuth));
-
4613 env(trust(alice, gwUSD(100)));
-
4614 env.close();
-
4615
-
4616 env(pay(gw, alice, gwUSD(50)));
-
4617 env.close();
-
4618
-
4619 env.require(balance(alice, gwUSD(50)));
-
4620
-
4621 // alice's offer should cross gw's
-
4622 env(offer(alice, XRP(4000), gwUSD(40)));
-
4623 env.close();
-
4624
-
4625 env.require(offers(alice, 0));
-
4626 env.require(balance(alice, gwUSD(10)));
-
4627
-
4628 env.require(offers(gw, 0));
-
4629 }
+
4611 env.require(balance(alice, gwUSD(50)));
+
4612
+
4613 // alice's offer should cross gw's
+
4614 env(offer(alice, XRP(4000), gwUSD(40)));
+
4615 env.close();
+
4616
+
4617 env.require(offers(alice, 0));
+
4618 env.require(balance(alice, gwUSD(10)));
+
4619
+
4620 env.require(offers(gw, 0));
+
4621 }
+
4622
+
4623 void
+
+ +
4625 {
+
4626 // Show that an offer who's issuer has been deleted cannot be crossed.
+
4627 using namespace jtx;
+
4628
+
4629 testcase("Deleted offer issuer");
4630
-
4631 void
-
- -
4633 {
-
4634 // Show that an offer who's issuer has been deleted cannot be crossed.
-
4635 using namespace jtx;
-
4636
-
4637 testcase("Deleted offer issuer");
-
4638
-
4639 auto trustLineExists = [](jtx::Env const& env,
-
4640 jtx::Account const& src,
-
4641 jtx::Account const& dst,
-
4642 Currency const& cur) -> bool {
-
4643 return bool(env.le(keylet::line(src, dst, cur)));
-
4644 };
-
4645
-
4646 Account const alice("alice");
-
4647 Account const becky("becky");
-
4648 Account const carol("carol");
-
4649 Account const gw("gateway");
-
4650 auto const USD = gw["USD"];
-
4651 auto const BUX = alice["BUX"];
-
4652
-
4653 Env env{*this, features};
-
4654
-
4655 env.fund(XRP(10000), alice, becky, carol, noripple(gw));
-
4656 env.close();
-
4657 env.trust(USD(1000), becky);
-
4658 env(pay(gw, becky, USD(5)));
-
4659 env.close();
-
4660 BEAST_EXPECT(trustLineExists(env, gw, becky, USD.currency));
+
4631 auto trustLineExists = [](jtx::Env const& env,
+
4632 jtx::Account const& src,
+
4633 jtx::Account const& dst,
+
4634 Currency const& cur) -> bool {
+
4635 return bool(env.le(keylet::line(src, dst, cur)));
+
4636 };
+
4637
+
4638 Account const alice("alice");
+
4639 Account const becky("becky");
+
4640 Account const carol("carol");
+
4641 Account const gw("gateway");
+
4642 auto const USD = gw["USD"];
+
4643 auto const BUX = alice["BUX"];
+
4644
+
4645 Env env{*this, features};
+
4646
+
4647 env.fund(XRP(10000), alice, becky, carol, noripple(gw));
+
4648 env.close();
+
4649 env.trust(USD(1000), becky);
+
4650 env(pay(gw, becky, USD(5)));
+
4651 env.close();
+
4652 BEAST_EXPECT(trustLineExists(env, gw, becky, USD.currency));
+
4653
+
4654 // Make offers that produce USD and can be crossed two ways:
+
4655 // direct XRP -> USD
+
4656 // direct BUX -> USD
+
4657 env(offer(becky, XRP(2), USD(2)), txflags(tfPassive));
+
4658 std::uint32_t const beckyBuxUsdSeq{env.seq(becky)};
+
4659 env(offer(becky, BUX(3), USD(3)), txflags(tfPassive));
+
4660 env.close();
4661
-
4662 // Make offers that produce USD and can be crossed two ways:
-
4663 // direct XRP -> USD
-
4664 // direct BUX -> USD
-
4665 env(offer(becky, XRP(2), USD(2)), txflags(tfPassive));
-
4666 std::uint32_t const beckyBuxUsdSeq{env.seq(becky)};
-
4667 env(offer(becky, BUX(3), USD(3)), txflags(tfPassive));
-
4668 env.close();
+
4662 // becky keeps the offers, but removes the trustline.
+
4663 env(pay(becky, gw, USD(5)));
+
4664 env.trust(USD(0), becky);
+
4665 env.close();
+
4666 BEAST_EXPECT(!trustLineExists(env, gw, becky, USD.currency));
+
4667 BEAST_EXPECT(isOffer(env, becky, XRP(2), USD(2)));
+
4668 BEAST_EXPECT(isOffer(env, becky, BUX(3), USD(3)));
4669
-
4670 // becky keeps the offers, but removes the trustline.
-
4671 env(pay(becky, gw, USD(5)));
-
4672 env.trust(USD(0), becky);
-
4673 env.close();
-
4674 BEAST_EXPECT(!trustLineExists(env, gw, becky, USD.currency));
-
4675 BEAST_EXPECT(isOffer(env, becky, XRP(2), USD(2)));
-
4676 BEAST_EXPECT(isOffer(env, becky, BUX(3), USD(3)));
-
4677
-
4678 // Delete gw's account.
-
4679 {
-
4680 // The ledger sequence needs to far enough ahead of the account
-
4681 // sequence before the account can be deleted.
-
4682 int const delta =
-
4683 [&env, &gw, openLedgerSeq = env.current()->seq()]() -> int {
-
4684 std::uint32_t const gwSeq{env.seq(gw)};
-
4685 if (gwSeq + 255 > openLedgerSeq)
-
4686 return gwSeq - openLedgerSeq + 255;
-
4687 return 0;
-
4688 }();
+
4670 // Delete gw's account.
+
4671 {
+
4672 // The ledger sequence needs to far enough ahead of the account
+
4673 // sequence before the account can be deleted.
+
4674 int const delta =
+
4675 [&env, &gw, openLedgerSeq = env.current()->seq()]() -> int {
+
4676 std::uint32_t const gwSeq{env.seq(gw)};
+
4677 if (gwSeq + 255 > openLedgerSeq)
+
4678 return gwSeq - openLedgerSeq + 255;
+
4679 return 0;
+
4680 }();
+
4681
+
4682 for (int i = 0; i < delta; ++i)
+
4683 env.close();
+
4684
+
4685 // Account deletion has a high fee. Account for that.
+
4686 env(acctdelete(gw, alice),
+
4687 fee(drops(env.current()->fees().increment)));
+
4688 env.close();
4689
-
4690 for (int i = 0; i < delta; ++i)
-
4691 env.close();
-
4692
-
4693 // Account deletion has a high fee. Account for that.
-
4694 env(acctdelete(gw, alice),
-
4695 fee(drops(env.current()->fees().increment)));
-
4696 env.close();
-
4697
-
4698 // Verify that gw's account root is gone from the ledger.
-
4699 BEAST_EXPECT(!env.closed()->exists(keylet::account(gw.id())));
-
4700 }
+
4690 // Verify that gw's account root is gone from the ledger.
+
4691 BEAST_EXPECT(!env.closed()->exists(keylet::account(gw.id())));
+
4692 }
+
4693
+
4694 // alice crosses becky's first offer. The offer create fails because
+
4695 // the USD issuer is not in the ledger.
+
4696 env(offer(alice, USD(2), XRP(2)), ter(tecNO_ISSUER));
+
4697 env.close();
+
4698 env.require(offers(alice, 0));
+
4699 BEAST_EXPECT(isOffer(env, becky, XRP(2), USD(2)));
+
4700 BEAST_EXPECT(isOffer(env, becky, BUX(3), USD(3)));
4701
-
4702 // alice crosses becky's first offer. The offer create fails because
-
4703 // the USD issuer is not in the ledger.
-
4704 env(offer(alice, USD(2), XRP(2)), ter(tecNO_ISSUER));
-
4705 env.close();
-
4706 env.require(offers(alice, 0));
-
4707 BEAST_EXPECT(isOffer(env, becky, XRP(2), USD(2)));
-
4708 BEAST_EXPECT(isOffer(env, becky, BUX(3), USD(3)));
-
4709
-
4710 // alice crosses becky's second offer. Again, the offer create fails
-
4711 // because the USD issuer is not in the ledger.
-
4712 env(offer(alice, USD(3), BUX(3)), ter(tecNO_ISSUER));
-
4713 env.require(offers(alice, 0));
-
4714 BEAST_EXPECT(isOffer(env, becky, XRP(2), USD(2)));
-
4715 BEAST_EXPECT(isOffer(env, becky, BUX(3), USD(3)));
-
4716
-
4717 // Cancel becky's BUX -> USD offer so we can try auto-bridging.
-
4718 env(offer_cancel(becky, beckyBuxUsdSeq));
-
4719 env.close();
-
4720 BEAST_EXPECT(!isOffer(env, becky, BUX(3), USD(3)));
+
4702 // alice crosses becky's second offer. Again, the offer create fails
+
4703 // because the USD issuer is not in the ledger.
+
4704 env(offer(alice, USD(3), BUX(3)), ter(tecNO_ISSUER));
+
4705 env.require(offers(alice, 0));
+
4706 BEAST_EXPECT(isOffer(env, becky, XRP(2), USD(2)));
+
4707 BEAST_EXPECT(isOffer(env, becky, BUX(3), USD(3)));
+
4708
+
4709 // Cancel becky's BUX -> USD offer so we can try auto-bridging.
+
4710 env(offer_cancel(becky, beckyBuxUsdSeq));
+
4711 env.close();
+
4712 BEAST_EXPECT(!isOffer(env, becky, BUX(3), USD(3)));
+
4713
+
4714 // alice creates an offer that can be auto-bridged with becky's
+
4715 // remaining offer.
+
4716 env.trust(BUX(1000), carol);
+
4717 env(pay(alice, carol, BUX(2)));
+
4718
+
4719 env(offer(alice, BUX(2), XRP(2)));
+
4720 env.close();
4721
-
4722 // alice creates an offer that can be auto-bridged with becky's
-
4723 // remaining offer.
-
4724 env.trust(BUX(1000), carol);
-
4725 env(pay(alice, carol, BUX(2)));
-
4726
-
4727 env(offer(alice, BUX(2), XRP(2)));
-
4728 env.close();
+
4722 // carol attempts the auto-bridge. Again, the offer create fails
+
4723 // because the USD issuer is not in the ledger.
+
4724 env(offer(carol, USD(2), BUX(2)), ter(tecNO_ISSUER));
+
4725 env.close();
+
4726 BEAST_EXPECT(isOffer(env, alice, BUX(2), XRP(2)));
+
4727 BEAST_EXPECT(isOffer(env, becky, XRP(2), USD(2)));
+
4728 }
+
4729
-
4730 // carol attempts the auto-bridge. Again, the offer create fails
-
4731 // because the USD issuer is not in the ledger.
-
4732 env(offer(carol, USD(2), BUX(2)), ter(tecNO_ISSUER));
-
4733 env.close();
-
4734 BEAST_EXPECT(isOffer(env, alice, BUX(2), XRP(2)));
-
4735 BEAST_EXPECT(isOffer(env, becky, XRP(2), USD(2)));
-
4736 }
-
-
4737
-
4738 void
-
- -
4740 {
-
4741 testcase("Tick Size");
-
4742
-
4743 using namespace jtx;
-
4744
-
4745 // Try to set tick size out of range
-
4746 {
-
4747 Env env{*this, features};
-
4748 auto const gw = Account{"gateway"};
-
4749 env.fund(XRP(10000), gw);
-
4750 env.close();
+
4730 void
+
+ +
4732 {
+
4733 testcase("Tick Size");
+
4734
+
4735 using namespace jtx;
+
4736
+
4737 // Try to set tick size out of range
+
4738 {
+
4739 Env env{*this, features};
+
4740 auto const gw = Account{"gateway"};
+
4741 env.fund(XRP(10000), gw);
+
4742 env.close();
+
4743
+
4744 auto txn = noop(gw);
+
4745 txn[sfTickSize.fieldName] = Quality::minTickSize - 1;
+
4746 env(txn, ter(temBAD_TICK_SIZE));
+
4747
+
4748 txn[sfTickSize.fieldName] = Quality::minTickSize;
+
4749 env(txn);
+
4750 BEAST_EXPECT((*env.le(gw))[sfTickSize] == Quality::minTickSize);
4751
-
4752 auto txn = noop(gw);
-
4753 txn[sfTickSize.fieldName] = Quality::minTickSize - 1;
-
4754 env(txn, ter(temBAD_TICK_SIZE));
-
4755
-
4756 txn[sfTickSize.fieldName] = Quality::minTickSize;
-
4757 env(txn);
-
4758 BEAST_EXPECT((*env.le(gw))[sfTickSize] == Quality::minTickSize);
-
4759
-
4760 txn = noop(gw);
-
4761 txn[sfTickSize.fieldName] = Quality::maxTickSize;
-
4762 env(txn);
-
4763 BEAST_EXPECT(!env.le(gw)->isFieldPresent(sfTickSize));
-
4764
-
4765 txn = noop(gw);
-
4766 txn[sfTickSize.fieldName] = Quality::maxTickSize - 1;
+
4752 txn = noop(gw);
+
4753 txn[sfTickSize.fieldName] = Quality::maxTickSize;
+
4754 env(txn);
+
4755 BEAST_EXPECT(!env.le(gw)->isFieldPresent(sfTickSize));
+
4756
+
4757 txn = noop(gw);
+
4758 txn[sfTickSize.fieldName] = Quality::maxTickSize - 1;
+
4759 env(txn);
+
4760 BEAST_EXPECT((*env.le(gw))[sfTickSize] == Quality::maxTickSize - 1);
+
4761
+
4762 txn = noop(gw);
+
4763 txn[sfTickSize.fieldName] = Quality::maxTickSize + 1;
+
4764 env(txn, ter(temBAD_TICK_SIZE));
+
4765
+
4766 txn[sfTickSize.fieldName] = 0;
4767 env(txn);
-
4768 BEAST_EXPECT((*env.le(gw))[sfTickSize] == Quality::maxTickSize - 1);
-
4769
-
4770 txn = noop(gw);
-
4771 txn[sfTickSize.fieldName] = Quality::maxTickSize + 1;
-
4772 env(txn, ter(temBAD_TICK_SIZE));
-
4773
-
4774 txn[sfTickSize.fieldName] = 0;
-
4775 env(txn);
-
4776 BEAST_EXPECT(!env.le(gw)->isFieldPresent(sfTickSize));
-
4777 }
-
4778
-
4779 Env env{*this, features};
-
4780 auto const gw = Account{"gateway"};
-
4781 auto const alice = Account{"alice"};
-
4782 auto const XTS = gw["XTS"];
-
4783 auto const XXX = gw["XXX"];
-
4784
-
4785 env.fund(XRP(10000), gw, alice);
-
4786 env.close();
+
4768 BEAST_EXPECT(!env.le(gw)->isFieldPresent(sfTickSize));
+
4769 }
+
4770
+
4771 Env env{*this, features};
+
4772 auto const gw = Account{"gateway"};
+
4773 auto const alice = Account{"alice"};
+
4774 auto const XTS = gw["XTS"];
+
4775 auto const XXX = gw["XXX"];
+
4776
+
4777 env.fund(XRP(10000), gw, alice);
+
4778 env.close();
+
4779
+
4780 {
+
4781 // Gateway sets its tick size to 5
+
4782 auto txn = noop(gw);
+
4783 txn[sfTickSize.fieldName] = 5;
+
4784 env(txn);
+
4785 BEAST_EXPECT((*env.le(gw))[sfTickSize] == 5);
+
4786 }
4787
-
4788 {
-
4789 // Gateway sets its tick size to 5
-
4790 auto txn = noop(gw);
-
4791 txn[sfTickSize.fieldName] = 5;
-
4792 env(txn);
-
4793 BEAST_EXPECT((*env.le(gw))[sfTickSize] == 5);
-
4794 }
-
4795
-
4796 env(trust(alice, XTS(1000)));
-
4797 env(trust(alice, XXX(1000)));
+
4788 env(trust(alice, XTS(1000)));
+
4789 env(trust(alice, XXX(1000)));
+
4790
+
4791 env(pay(gw, alice, alice["XTS"](100)));
+
4792 env(pay(gw, alice, alice["XXX"](100)));
+
4793
+
4794 env(offer(alice, XTS(10), XXX(30)));
+
4795 env(offer(alice, XTS(30), XXX(10)));
+
4796 env(offer(alice, XTS(10), XXX(30)), json(jss::Flags, tfSell));
+
4797 env(offer(alice, XTS(30), XXX(10)), json(jss::Flags, tfSell));
4798
-
4799 env(pay(gw, alice, alice["XTS"](100)));
-
4800 env(pay(gw, alice, alice["XXX"](100)));
-
4801
-
4802 env(offer(alice, XTS(10), XXX(30)));
-
4803 env(offer(alice, XTS(30), XXX(10)));
-
4804 env(offer(alice, XTS(10), XXX(30)), json(jss::Flags, tfSell));
-
4805 env(offer(alice, XTS(30), XXX(10)), json(jss::Flags, tfSell));
-
4806
- - -
4809 *env.current(), alice, [&](std::shared_ptr<SLE const> const& sle) {
-
4810 if (sle->getType() == ltOFFER)
-
4811 offers.emplace(
-
4812 (*sle)[sfSequence],
-
4813 std::make_pair(
-
4814 (*sle)[sfTakerPays], (*sle)[sfTakerGets]));
-
4815 });
-
4816
-
4817 // first offer
-
4818 auto it = offers.begin();
-
4819 BEAST_EXPECT(it != offers.end());
-
4820 BEAST_EXPECT(
-
4821 it->second.first == XTS(10) && it->second.second < XXX(30) &&
-
4822 it->second.second > XXX(29.9994));
-
4823
-
4824 // second offer
-
4825 ++it;
-
4826 BEAST_EXPECT(it != offers.end());
-
4827 BEAST_EXPECT(
-
4828 it->second.first == XTS(30) && it->second.second == XXX(10));
-
4829
-
4830 // third offer
-
4831 ++it;
-
4832 BEAST_EXPECT(it != offers.end());
-
4833 BEAST_EXPECT(
-
4834 it->second.first == XTS(10.0002) && it->second.second == XXX(30));
-
4835
-
4836 // fourth offer
-
4837 // exact TakerPays is XTS(1/.033333)
-
4838 ++it;
-
4839 BEAST_EXPECT(it != offers.end());
-
4840 BEAST_EXPECT(
-
4841 it->second.first == XTS(30) && it->second.second == XXX(10));
-
4842
-
4843 BEAST_EXPECT(++it == offers.end());
-
4844 }
+ + +
4801 *env.current(), alice, [&](std::shared_ptr<SLE const> const& sle) {
+
4802 if (sle->getType() == ltOFFER)
+
4803 offers.emplace(
+
4804 (*sle)[sfSequence],
+
4805 std::make_pair(
+
4806 (*sle)[sfTakerPays], (*sle)[sfTakerGets]));
+
4807 });
+
4808
+
4809 // first offer
+
4810 auto it = offers.begin();
+
4811 BEAST_EXPECT(it != offers.end());
+
4812 BEAST_EXPECT(
+
4813 it->second.first == XTS(10) && it->second.second < XXX(30) &&
+
4814 it->second.second > XXX(29.9994));
+
4815
+
4816 // second offer
+
4817 ++it;
+
4818 BEAST_EXPECT(it != offers.end());
+
4819 BEAST_EXPECT(
+
4820 it->second.first == XTS(30) && it->second.second == XXX(10));
+
4821
+
4822 // third offer
+
4823 ++it;
+
4824 BEAST_EXPECT(it != offers.end());
+
4825 BEAST_EXPECT(
+
4826 it->second.first == XTS(10.0002) && it->second.second == XXX(30));
+
4827
+
4828 // fourth offer
+
4829 // exact TakerPays is XTS(1/.033333)
+
4830 ++it;
+
4831 BEAST_EXPECT(it != offers.end());
+
4832 BEAST_EXPECT(
+
4833 it->second.first == XTS(30) && it->second.second == XXX(10));
+
4834
+
4835 BEAST_EXPECT(++it == offers.end());
+
4836 }
-
4845
-
4846 // Helper function that returns offers on an account sorted by sequence.
- -
- -
4849 {
- -
4851 offersOnAccount(env, acct)};
-
4852 std::sort(
-
4853 offers.begin(),
-
4854 offers.end(),
-
4855 [](std::shared_ptr<SLE const> const& rhs,
-
4856 std::shared_ptr<SLE const> const& lhs) {
-
4857 return (*rhs)[sfSequence] < (*lhs)[sfSequence];
-
4858 });
-
4859 return offers;
-
4860 }
+
4837
+
4838 // Helper function that returns offers on an account sorted by sequence.
+ +
+ +
4841 {
+ +
4843 offersOnAccount(env, acct)};
+
4844 std::sort(
+
4845 offers.begin(),
+
4846 offers.end(),
+
4847 [](std::shared_ptr<SLE const> const& rhs,
+
4848 std::shared_ptr<SLE const> const& lhs) {
+
4849 return (*rhs)[sfSequence] < (*lhs)[sfSequence];
+
4850 });
+
4851 return offers;
+
4852 }
-
4861
-
4862 void
-
- -
4864 {
-
4865 testcase("Ticket Offers");
-
4866
-
4867 using namespace jtx;
-
4868
-
4869 // Two goals for this test.
-
4870 //
-
4871 // o Verify that offers can be created using tickets.
-
4872 //
-
4873 // o Show that offers in the _same_ order book remain in
-
4874 // chronological order regardless of sequence/ticket numbers.
-
4875 Env env{*this, features};
-
4876 auto const gw = Account{"gateway"};
-
4877 auto const alice = Account{"alice"};
-
4878 auto const bob = Account{"bob"};
-
4879 auto const USD = gw["USD"];
-
4880
-
4881 env.fund(XRP(10000), gw, alice, bob);
-
4882 env.close();
-
4883
-
4884 env(trust(alice, USD(1000)));
-
4885 env(trust(bob, USD(1000)));
-
4886 env.close();
-
4887
-
4888 env(pay(gw, alice, USD(200)));
-
4889 env.close();
-
4890
-
4891 // Create four offers from the same account with identical quality
-
4892 // so they go in the same order book. Each offer goes in a different
-
4893 // ledger so the chronology is clear.
-
4894 std::uint32_t const offerId_0{env.seq(alice)};
-
4895 env(offer(alice, XRP(50), USD(50)));
-
4896 env.close();
-
4897
-
4898 // Create two tickets.
-
4899 std::uint32_t const ticketSeq{env.seq(alice) + 1};
-
4900 env(ticket::create(alice, 2));
-
4901 env.close();
-
4902
-
4903 // Create another sequence-based offer.
-
4904 std::uint32_t const offerId_1{env.seq(alice)};
-
4905 BEAST_EXPECT(offerId_1 == offerId_0 + 4);
-
4906 env(offer(alice, XRP(50), USD(50)));
-
4907 env.close();
-
4908
-
4909 // Create two ticket based offers in reverse order.
-
4910 std::uint32_t const offerId_2{ticketSeq + 1};
-
4911 env(offer(alice, XRP(50), USD(50)), ticket::use(offerId_2));
-
4912 env.close();
-
4913
-
4914 // Create the last offer.
-
4915 std::uint32_t const offerId_3{ticketSeq};
-
4916 env(offer(alice, XRP(50), USD(50)), ticket::use(offerId_3));
-
4917 env.close();
-
4918
-
4919 // Verify that all of alice's offers are present.
-
4920 {
-
4921 auto offers = sortedOffersOnAccount(env, alice);
-
4922 BEAST_EXPECT(offers.size() == 4);
-
4923 BEAST_EXPECT(offers[0]->getFieldU32(sfSequence) == offerId_0);
-
4924 BEAST_EXPECT(offers[1]->getFieldU32(sfSequence) == offerId_3);
-
4925 BEAST_EXPECT(offers[2]->getFieldU32(sfSequence) == offerId_2);
-
4926 BEAST_EXPECT(offers[3]->getFieldU32(sfSequence) == offerId_1);
-
4927 env.require(balance(alice, USD(200)));
-
4928 env.require(owners(alice, 5));
-
4929 }
-
4930
-
4931 // Cross alice's first offer.
-
4932 env(offer(bob, USD(50), XRP(50)));
-
4933 env.close();
-
4934
-
4935 // Verify that the first offer alice created was consumed.
-
4936 {
-
4937 auto offers = sortedOffersOnAccount(env, alice);
-
4938 BEAST_EXPECT(offers.size() == 3);
-
4939 BEAST_EXPECT(offers[0]->getFieldU32(sfSequence) == offerId_3);
-
4940 BEAST_EXPECT(offers[1]->getFieldU32(sfSequence) == offerId_2);
-
4941 BEAST_EXPECT(offers[2]->getFieldU32(sfSequence) == offerId_1);
-
4942 }
-
4943
-
4944 // Cross alice's second offer.
-
4945 env(offer(bob, USD(50), XRP(50)));
-
4946 env.close();
+
4853
+
4854 void
+
+ +
4856 {
+
4857 testcase("Ticket Offers");
+
4858
+
4859 using namespace jtx;
+
4860
+
4861 // Two goals for this test.
+
4862 //
+
4863 // o Verify that offers can be created using tickets.
+
4864 //
+
4865 // o Show that offers in the _same_ order book remain in
+
4866 // chronological order regardless of sequence/ticket numbers.
+
4867 Env env{*this, features};
+
4868 auto const gw = Account{"gateway"};
+
4869 auto const alice = Account{"alice"};
+
4870 auto const bob = Account{"bob"};
+
4871 auto const USD = gw["USD"];
+
4872
+
4873 env.fund(XRP(10000), gw, alice, bob);
+
4874 env.close();
+
4875
+
4876 env(trust(alice, USD(1000)));
+
4877 env(trust(bob, USD(1000)));
+
4878 env.close();
+
4879
+
4880 env(pay(gw, alice, USD(200)));
+
4881 env.close();
+
4882
+
4883 // Create four offers from the same account with identical quality
+
4884 // so they go in the same order book. Each offer goes in a different
+
4885 // ledger so the chronology is clear.
+
4886 std::uint32_t const offerId_0{env.seq(alice)};
+
4887 env(offer(alice, XRP(50), USD(50)));
+
4888 env.close();
+
4889
+
4890 // Create two tickets.
+
4891 std::uint32_t const ticketSeq{env.seq(alice) + 1};
+
4892 env(ticket::create(alice, 2));
+
4893 env.close();
+
4894
+
4895 // Create another sequence-based offer.
+
4896 std::uint32_t const offerId_1{env.seq(alice)};
+
4897 BEAST_EXPECT(offerId_1 == offerId_0 + 4);
+
4898 env(offer(alice, XRP(50), USD(50)));
+
4899 env.close();
+
4900
+
4901 // Create two ticket based offers in reverse order.
+
4902 std::uint32_t const offerId_2{ticketSeq + 1};
+
4903 env(offer(alice, XRP(50), USD(50)), ticket::use(offerId_2));
+
4904 env.close();
+
4905
+
4906 // Create the last offer.
+
4907 std::uint32_t const offerId_3{ticketSeq};
+
4908 env(offer(alice, XRP(50), USD(50)), ticket::use(offerId_3));
+
4909 env.close();
+
4910
+
4911 // Verify that all of alice's offers are present.
+
4912 {
+
4913 auto offers = sortedOffersOnAccount(env, alice);
+
4914 BEAST_EXPECT(offers.size() == 4);
+
4915 BEAST_EXPECT(offers[0]->getFieldU32(sfSequence) == offerId_0);
+
4916 BEAST_EXPECT(offers[1]->getFieldU32(sfSequence) == offerId_3);
+
4917 BEAST_EXPECT(offers[2]->getFieldU32(sfSequence) == offerId_2);
+
4918 BEAST_EXPECT(offers[3]->getFieldU32(sfSequence) == offerId_1);
+
4919 env.require(balance(alice, USD(200)));
+
4920 env.require(owners(alice, 5));
+
4921 }
+
4922
+
4923 // Cross alice's first offer.
+
4924 env(offer(bob, USD(50), XRP(50)));
+
4925 env.close();
+
4926
+
4927 // Verify that the first offer alice created was consumed.
+
4928 {
+
4929 auto offers = sortedOffersOnAccount(env, alice);
+
4930 BEAST_EXPECT(offers.size() == 3);
+
4931 BEAST_EXPECT(offers[0]->getFieldU32(sfSequence) == offerId_3);
+
4932 BEAST_EXPECT(offers[1]->getFieldU32(sfSequence) == offerId_2);
+
4933 BEAST_EXPECT(offers[2]->getFieldU32(sfSequence) == offerId_1);
+
4934 }
+
4935
+
4936 // Cross alice's second offer.
+
4937 env(offer(bob, USD(50), XRP(50)));
+
4938 env.close();
+
4939
+
4940 // Verify that the second offer alice created was consumed.
+
4941 {
+
4942 auto offers = sortedOffersOnAccount(env, alice);
+
4943 BEAST_EXPECT(offers.size() == 2);
+
4944 BEAST_EXPECT(offers[0]->getFieldU32(sfSequence) == offerId_3);
+
4945 BEAST_EXPECT(offers[1]->getFieldU32(sfSequence) == offerId_2);
+
4946 }
4947
-
4948 // Verify that the second offer alice created was consumed.
-
4949 {
-
4950 auto offers = sortedOffersOnAccount(env, alice);
-
4951 BEAST_EXPECT(offers.size() == 2);
-
4952 BEAST_EXPECT(offers[0]->getFieldU32(sfSequence) == offerId_3);
-
4953 BEAST_EXPECT(offers[1]->getFieldU32(sfSequence) == offerId_2);
-
4954 }
-
4955
-
4956 // Cross alice's third offer.
-
4957 env(offer(bob, USD(50), XRP(50)));
-
4958 env.close();
-
4959
-
4960 // Verify that the third offer alice created was consumed.
-
4961 {
-
4962 auto offers = sortedOffersOnAccount(env, alice);
-
4963 BEAST_EXPECT(offers.size() == 1);
-
4964 BEAST_EXPECT(offers[0]->getFieldU32(sfSequence) == offerId_3);
-
4965 }
-
4966
-
4967 // Cross alice's last offer.
-
4968 env(offer(bob, USD(50), XRP(50)));
-
4969 env.close();
-
4970
-
4971 // Verify that the third offer alice created was consumed.
-
4972 {
-
4973 auto offers = sortedOffersOnAccount(env, alice);
-
4974 BEAST_EXPECT(offers.size() == 0);
-
4975 }
-
4976 env.require(balance(alice, USD(0)));
-
4977 env.require(owners(alice, 1));
-
4978 env.require(balance(bob, USD(200)));
-
4979 env.require(owners(bob, 1));
-
4980 }
+
4948 // Cross alice's third offer.
+
4949 env(offer(bob, USD(50), XRP(50)));
+
4950 env.close();
+
4951
+
4952 // Verify that the third offer alice created was consumed.
+
4953 {
+
4954 auto offers = sortedOffersOnAccount(env, alice);
+
4955 BEAST_EXPECT(offers.size() == 1);
+
4956 BEAST_EXPECT(offers[0]->getFieldU32(sfSequence) == offerId_3);
+
4957 }
+
4958
+
4959 // Cross alice's last offer.
+
4960 env(offer(bob, USD(50), XRP(50)));
+
4961 env.close();
+
4962
+
4963 // Verify that the third offer alice created was consumed.
+
4964 {
+
4965 auto offers = sortedOffersOnAccount(env, alice);
+
4966 BEAST_EXPECT(offers.size() == 0);
+
4967 }
+
4968 env.require(balance(alice, USD(0)));
+
4969 env.require(owners(alice, 1));
+
4970 env.require(balance(bob, USD(200)));
+
4971 env.require(owners(bob, 1));
+
4972 }
-
4981
-
4982 void
-
- -
4984 {
-
4985 testcase("Ticket Cancel Offers");
-
4986
-
4987 using namespace jtx;
-
4988
-
4989 // Verify that offers created with or without tickets can be canceled
-
4990 // by transactions with or without tickets.
-
4991 Env env{*this, features};
-
4992 auto const gw = Account{"gateway"};
-
4993 auto const alice = Account{"alice"};
-
4994 auto const USD = gw["USD"];
-
4995
-
4996 env.fund(XRP(10000), gw, alice);
-
4997 env.close();
-
4998
-
4999 env(trust(alice, USD(1000)));
-
5000 env.close();
-
5001 env.require(owners(alice, 1), tickets(alice, 0));
-
5002
-
5003 env(pay(gw, alice, USD(200)));
-
5004 env.close();
-
5005
-
5006 // Create the first of four offers using a sequence.
-
5007 std::uint32_t const offerSeqId_0{env.seq(alice)};
-
5008 env(offer(alice, XRP(50), USD(50)));
-
5009 env.close();
-
5010 env.require(owners(alice, 2), tickets(alice, 0));
-
5011
-
5012 // Create four tickets.
-
5013 std::uint32_t const ticketSeq{env.seq(alice) + 1};
-
5014 env(ticket::create(alice, 4));
-
5015 env.close();
-
5016 env.require(owners(alice, 6), tickets(alice, 4));
-
5017
-
5018 // Create the second (also sequence-based) offer.
-
5019 std::uint32_t const offerSeqId_1{env.seq(alice)};
-
5020 BEAST_EXPECT(offerSeqId_1 == offerSeqId_0 + 6);
-
5021 env(offer(alice, XRP(50), USD(50)));
-
5022 env.close();
-
5023
-
5024 // Create the third (ticket-based) offer.
-
5025 std::uint32_t const offerTixId_0{ticketSeq + 1};
-
5026 env(offer(alice, XRP(50), USD(50)), ticket::use(offerTixId_0));
-
5027 env.close();
-
5028
-
5029 // Create the last offer.
-
5030 std::uint32_t const offerTixId_1{ticketSeq};
-
5031 env(offer(alice, XRP(50), USD(50)), ticket::use(offerTixId_1));
-
5032 env.close();
-
5033
-
5034 // Verify that all of alice's offers are present.
-
5035 {
-
5036 auto offers = sortedOffersOnAccount(env, alice);
-
5037 BEAST_EXPECT(offers.size() == 4);
-
5038 BEAST_EXPECT(offers[0]->getFieldU32(sfSequence) == offerSeqId_0);
-
5039 BEAST_EXPECT(offers[1]->getFieldU32(sfSequence) == offerTixId_1);
-
5040 BEAST_EXPECT(offers[2]->getFieldU32(sfSequence) == offerTixId_0);
-
5041 BEAST_EXPECT(offers[3]->getFieldU32(sfSequence) == offerSeqId_1);
-
5042 env.require(balance(alice, USD(200)));
-
5043 env.require(owners(alice, 7));
-
5044 }
-
5045
-
5046 // Use a ticket to cancel an offer created with a sequence.
-
5047 env(offer_cancel(alice, offerSeqId_0), ticket::use(ticketSeq + 2));
-
5048 env.close();
-
5049
-
5050 // Verify that offerSeqId_0 was canceled.
-
5051 {
-
5052 auto offers = sortedOffersOnAccount(env, alice);
-
5053 BEAST_EXPECT(offers.size() == 3);
-
5054 BEAST_EXPECT(offers[0]->getFieldU32(sfSequence) == offerTixId_1);
-
5055 BEAST_EXPECT(offers[1]->getFieldU32(sfSequence) == offerTixId_0);
-
5056 BEAST_EXPECT(offers[2]->getFieldU32(sfSequence) == offerSeqId_1);
-
5057 }
-
5058
-
5059 // Use a ticket to cancel an offer created with a ticket.
-
5060 env(offer_cancel(alice, offerTixId_0), ticket::use(ticketSeq + 3));
-
5061 env.close();
+
4973
+
4974 void
+
+ +
4976 {
+
4977 testcase("Ticket Cancel Offers");
+
4978
+
4979 using namespace jtx;
+
4980
+
4981 // Verify that offers created with or without tickets can be canceled
+
4982 // by transactions with or without tickets.
+
4983 Env env{*this, features};
+
4984 auto const gw = Account{"gateway"};
+
4985 auto const alice = Account{"alice"};
+
4986 auto const USD = gw["USD"];
+
4987
+
4988 env.fund(XRP(10000), gw, alice);
+
4989 env.close();
+
4990
+
4991 env(trust(alice, USD(1000)));
+
4992 env.close();
+
4993 env.require(owners(alice, 1), tickets(alice, 0));
+
4994
+
4995 env(pay(gw, alice, USD(200)));
+
4996 env.close();
+
4997
+
4998 // Create the first of four offers using a sequence.
+
4999 std::uint32_t const offerSeqId_0{env.seq(alice)};
+
5000 env(offer(alice, XRP(50), USD(50)));
+
5001 env.close();
+
5002 env.require(owners(alice, 2), tickets(alice, 0));
+
5003
+
5004 // Create four tickets.
+
5005 std::uint32_t const ticketSeq{env.seq(alice) + 1};
+
5006 env(ticket::create(alice, 4));
+
5007 env.close();
+
5008 env.require(owners(alice, 6), tickets(alice, 4));
+
5009
+
5010 // Create the second (also sequence-based) offer.
+
5011 std::uint32_t const offerSeqId_1{env.seq(alice)};
+
5012 BEAST_EXPECT(offerSeqId_1 == offerSeqId_0 + 6);
+
5013 env(offer(alice, XRP(50), USD(50)));
+
5014 env.close();
+
5015
+
5016 // Create the third (ticket-based) offer.
+
5017 std::uint32_t const offerTixId_0{ticketSeq + 1};
+
5018 env(offer(alice, XRP(50), USD(50)), ticket::use(offerTixId_0));
+
5019 env.close();
+
5020
+
5021 // Create the last offer.
+
5022 std::uint32_t const offerTixId_1{ticketSeq};
+
5023 env(offer(alice, XRP(50), USD(50)), ticket::use(offerTixId_1));
+
5024 env.close();
+
5025
+
5026 // Verify that all of alice's offers are present.
+
5027 {
+
5028 auto offers = sortedOffersOnAccount(env, alice);
+
5029 BEAST_EXPECT(offers.size() == 4);
+
5030 BEAST_EXPECT(offers[0]->getFieldU32(sfSequence) == offerSeqId_0);
+
5031 BEAST_EXPECT(offers[1]->getFieldU32(sfSequence) == offerTixId_1);
+
5032 BEAST_EXPECT(offers[2]->getFieldU32(sfSequence) == offerTixId_0);
+
5033 BEAST_EXPECT(offers[3]->getFieldU32(sfSequence) == offerSeqId_1);
+
5034 env.require(balance(alice, USD(200)));
+
5035 env.require(owners(alice, 7));
+
5036 }
+
5037
+
5038 // Use a ticket to cancel an offer created with a sequence.
+
5039 env(offer_cancel(alice, offerSeqId_0), ticket::use(ticketSeq + 2));
+
5040 env.close();
+
5041
+
5042 // Verify that offerSeqId_0 was canceled.
+
5043 {
+
5044 auto offers = sortedOffersOnAccount(env, alice);
+
5045 BEAST_EXPECT(offers.size() == 3);
+
5046 BEAST_EXPECT(offers[0]->getFieldU32(sfSequence) == offerTixId_1);
+
5047 BEAST_EXPECT(offers[1]->getFieldU32(sfSequence) == offerTixId_0);
+
5048 BEAST_EXPECT(offers[2]->getFieldU32(sfSequence) == offerSeqId_1);
+
5049 }
+
5050
+
5051 // Use a ticket to cancel an offer created with a ticket.
+
5052 env(offer_cancel(alice, offerTixId_0), ticket::use(ticketSeq + 3));
+
5053 env.close();
+
5054
+
5055 // Verify that offerTixId_0 was canceled.
+
5056 {
+
5057 auto offers = sortedOffersOnAccount(env, alice);
+
5058 BEAST_EXPECT(offers.size() == 2);
+
5059 BEAST_EXPECT(offers[0]->getFieldU32(sfSequence) == offerTixId_1);
+
5060 BEAST_EXPECT(offers[1]->getFieldU32(sfSequence) == offerSeqId_1);
+
5061 }
5062
-
5063 // Verify that offerTixId_0 was canceled.
-
5064 {
-
5065 auto offers = sortedOffersOnAccount(env, alice);
-
5066 BEAST_EXPECT(offers.size() == 2);
-
5067 BEAST_EXPECT(offers[0]->getFieldU32(sfSequence) == offerTixId_1);
-
5068 BEAST_EXPECT(offers[1]->getFieldU32(sfSequence) == offerSeqId_1);
-
5069 }
-
5070
-
5071 // All of alice's tickets should now be used up.
-
5072 env.require(owners(alice, 3), tickets(alice, 0));
-
5073
-
5074 // Use a sequence to cancel an offer created with a ticket.
-
5075 env(offer_cancel(alice, offerTixId_1));
-
5076 env.close();
-
5077
-
5078 // Verify that offerTixId_1 was canceled.
-
5079 {
-
5080 auto offers = sortedOffersOnAccount(env, alice);
-
5081 BEAST_EXPECT(offers.size() == 1);
-
5082 BEAST_EXPECT(offers[0]->getFieldU32(sfSequence) == offerSeqId_1);
-
5083 }
-
5084
-
5085 // Use a sequence to cancel an offer created with a sequence.
-
5086 env(offer_cancel(alice, offerSeqId_1));
-
5087 env.close();
-
5088
-
5089 // Verify that offerSeqId_1 was canceled.
-
5090 // All of alice's tickets should now be used up.
-
5091 env.require(owners(alice, 1), tickets(alice, 0), offers(alice, 0));
-
5092 }
+
5063 // All of alice's tickets should now be used up.
+
5064 env.require(owners(alice, 3), tickets(alice, 0));
+
5065
+
5066 // Use a sequence to cancel an offer created with a ticket.
+
5067 env(offer_cancel(alice, offerTixId_1));
+
5068 env.close();
+
5069
+
5070 // Verify that offerTixId_1 was canceled.
+
5071 {
+
5072 auto offers = sortedOffersOnAccount(env, alice);
+
5073 BEAST_EXPECT(offers.size() == 1);
+
5074 BEAST_EXPECT(offers[0]->getFieldU32(sfSequence) == offerSeqId_1);
+
5075 }
+
5076
+
5077 // Use a sequence to cancel an offer created with a sequence.
+
5078 env(offer_cancel(alice, offerSeqId_1));
+
5079 env.close();
+
5080
+
5081 // Verify that offerSeqId_1 was canceled.
+
5082 // All of alice's tickets should now be used up.
+
5083 env.require(owners(alice, 1), tickets(alice, 0), offers(alice, 0));
+
5084 }
+
5085
+
5086 void
+
+ +
5088 {
+
5089 // An assert was falsely triggering when computing rates for offers.
+
5090 // This unit test would trigger that assert (which has been removed).
+
5091 testcase("incorrect assert fixed");
+
5092 using namespace jtx;
5093
-
5094 void
-
- -
5096 {
-
5097 // An assert was falsely triggering when computing rates for offers.
-
5098 // This unit test would trigger that assert (which has been removed).
-
5099 testcase("incorrect assert fixed");
-
5100 using namespace jtx;
-
5101
-
5102 Env env{*this};
-
5103 auto const alice = Account("alice");
-
5104 auto const USD = alice["USD"];
-
5105
-
5106 env.fund(XRP(10000), alice);
-
5107 env.close();
-
5108 env(offer(alice, XRP(100000000000), USD(100000000)));
-
5109 pass();
-
5110 }
+
5094 Env env{*this};
+
5095 auto const alice = Account("alice");
+
5096 auto const USD = alice["USD"];
+
5097
+
5098 env.fund(XRP(10000), alice);
+
5099 env.close();
+
5100 env(offer(alice, XRP(100000000000), USD(100000000)));
+
5101 pass();
+
5102 }
-
5111
-
5112 void
-
- -
5114 {
-
5115 testcase("fixFillOrKill");
-
5116 using namespace jtx;
-
5117 Env env(*this, features);
-
5118 Account const issuer("issuer");
-
5119 Account const maker("maker");
-
5120 Account const taker("taker");
-
5121 auto const USD = issuer["USD"];
-
5122 auto const EUR = issuer["EUR"];
+
5103
+
5104 void
+
+ +
5106 {
+
5107 testcase("fixFillOrKill");
+
5108 using namespace jtx;
+
5109 Env env(*this, features);
+
5110 Account const issuer("issuer");
+
5111 Account const maker("maker");
+
5112 Account const taker("taker");
+
5113 auto const USD = issuer["USD"];
+
5114 auto const EUR = issuer["EUR"];
+
5115
+
5116 env.fund(XRP(1'000), issuer);
+
5117 env.fund(XRP(1'000), maker, taker);
+
5118 env.close();
+
5119
+
5120 env.trust(USD(1'000), maker, taker);
+
5121 env.trust(EUR(1'000), maker, taker);
+
5122 env.close();
5123
-
5124 env.fund(XRP(1'000), issuer);
-
5125 env.fund(XRP(1'000), maker, taker);
-
5126 env.close();
-
5127
-
5128 env.trust(USD(1'000), maker, taker);
-
5129 env.trust(EUR(1'000), maker, taker);
-
5130 env.close();
-
5131
-
5132 env(pay(issuer, maker, USD(1'000)));
-
5133 env(pay(issuer, taker, USD(1'000)));
-
5134 env(pay(issuer, maker, EUR(1'000)));
-
5135 env.close();
-
5136
-
5137 auto makerUSDBalance = env.balance(maker, USD).value();
-
5138 auto takerUSDBalance = env.balance(taker, USD).value();
-
5139 auto makerEURBalance = env.balance(maker, EUR).value();
-
5140 auto takerEURBalance = env.balance(taker, EUR).value();
-
5141 auto makerXRPBalance = env.balance(maker, XRP).value();
-
5142 auto takerXRPBalance = env.balance(taker, XRP).value();
+
5124 env(pay(issuer, maker, USD(1'000)));
+
5125 env(pay(issuer, taker, USD(1'000)));
+
5126 env(pay(issuer, maker, EUR(1'000)));
+
5127 env.close();
+
5128
+
5129 auto makerUSDBalance = env.balance(maker, USD).value();
+
5130 auto takerUSDBalance = env.balance(taker, USD).value();
+
5131 auto makerEURBalance = env.balance(maker, EUR).value();
+
5132 auto takerEURBalance = env.balance(taker, EUR).value();
+
5133 auto makerXRPBalance = env.balance(maker, XRP).value();
+
5134 auto takerXRPBalance = env.balance(taker, XRP).value();
+
5135
+
5136 // tfFillOrKill, TakerPays must be filled
+
5137 {
+
5138 TER const err =
+
5139 features[fixFillOrKill] ? TER(tesSUCCESS) : tecKILLED;
+
5140
+
5141 env(offer(maker, XRP(100), USD(100)));
+
5142 env.close();
5143
-
5144 // tfFillOrKill, TakerPays must be filled
-
5145 {
-
5146 TER const err =
-
5147 features[fixFillOrKill] ? TER(tesSUCCESS) : tecKILLED;
+
5144 env(offer(taker, USD(100), XRP(101)),
+ +
5146 ter(err));
+
5147 env.close();
5148
-
5149 env(offer(maker, XRP(100), USD(100)));
-
5150 env.close();
-
5151
-
5152 env(offer(taker, USD(100), XRP(101)),
- -
5154 ter(err));
-
5155 env.close();
-
5156
-
5157 makerXRPBalance -= txfee(env, 1);
-
5158 takerXRPBalance -= txfee(env, 1);
-
5159 if (err == tesSUCCESS)
-
5160 {
-
5161 makerUSDBalance -= USD(100);
-
5162 takerUSDBalance += USD(100);
-
5163 makerXRPBalance += XRP(100).value();
-
5164 takerXRPBalance -= XRP(100).value();
-
5165 }
-
5166 BEAST_EXPECT(expectOffers(env, taker, 0));
+
5149 makerXRPBalance -= txfee(env, 1);
+
5150 takerXRPBalance -= txfee(env, 1);
+
5151 if (err == tesSUCCESS)
+
5152 {
+
5153 makerUSDBalance -= USD(100);
+
5154 takerUSDBalance += USD(100);
+
5155 makerXRPBalance += XRP(100).value();
+
5156 takerXRPBalance -= XRP(100).value();
+
5157 }
+
5158 BEAST_EXPECT(expectOffers(env, taker, 0));
+
5159
+
5160 env(offer(maker, USD(100), XRP(100)));
+
5161 env.close();
+
5162
+
5163 env(offer(taker, XRP(100), USD(101)),
+ +
5165 ter(err));
+
5166 env.close();
5167
-
5168 env(offer(maker, USD(100), XRP(100)));
-
5169 env.close();
-
5170
-
5171 env(offer(taker, XRP(100), USD(101)),
- -
5173 ter(err));
-
5174 env.close();
-
5175
-
5176 makerXRPBalance -= txfee(env, 1);
-
5177 takerXRPBalance -= txfee(env, 1);
-
5178 if (err == tesSUCCESS)
-
5179 {
-
5180 makerUSDBalance += USD(100);
-
5181 takerUSDBalance -= USD(100);
-
5182 makerXRPBalance -= XRP(100).value();
-
5183 takerXRPBalance += XRP(100).value();
-
5184 }
-
5185 BEAST_EXPECT(expectOffers(env, taker, 0));
+
5168 makerXRPBalance -= txfee(env, 1);
+
5169 takerXRPBalance -= txfee(env, 1);
+
5170 if (err == tesSUCCESS)
+
5171 {
+
5172 makerUSDBalance += USD(100);
+
5173 takerUSDBalance -= USD(100);
+
5174 makerXRPBalance -= XRP(100).value();
+
5175 takerXRPBalance += XRP(100).value();
+
5176 }
+
5177 BEAST_EXPECT(expectOffers(env, taker, 0));
+
5178
+
5179 env(offer(maker, USD(100), EUR(100)));
+
5180 env.close();
+
5181
+
5182 env(offer(taker, EUR(100), USD(101)),
+ +
5184 ter(err));
+
5185 env.close();
5186
-
5187 env(offer(maker, USD(100), EUR(100)));
-
5188 env.close();
-
5189
-
5190 env(offer(taker, EUR(100), USD(101)),
- -
5192 ter(err));
-
5193 env.close();
-
5194
-
5195 makerXRPBalance -= txfee(env, 1);
-
5196 takerXRPBalance -= txfee(env, 1);
-
5197 if (err == tesSUCCESS)
-
5198 {
-
5199 makerUSDBalance += USD(100);
-
5200 takerUSDBalance -= USD(100);
-
5201 makerEURBalance -= EUR(100);
-
5202 takerEURBalance += EUR(100);
-
5203 }
-
5204 BEAST_EXPECT(expectOffers(env, taker, 0));
-
5205 }
-
5206
-
5207 // tfFillOrKill + tfSell, TakerGets must be filled
-
5208 {
-
5209 env(offer(maker, XRP(101), USD(101)));
-
5210 env.close();
-
5211
-
5212 env(offer(taker, USD(100), XRP(101)),
- -
5214 env.close();
-
5215
-
5216 makerUSDBalance -= USD(101);
-
5217 takerUSDBalance += USD(101);
-
5218 makerXRPBalance += XRP(101).value() - txfee(env, 1);
-
5219 takerXRPBalance -= XRP(101).value() + txfee(env, 1);
-
5220 BEAST_EXPECT(expectOffers(env, taker, 0));
-
5221
-
5222 env(offer(maker, USD(101), XRP(101)));
-
5223 env.close();
-
5224
-
5225 env(offer(taker, XRP(100), USD(101)),
- -
5227 env.close();
-
5228
-
5229 makerUSDBalance += USD(101);
-
5230 takerUSDBalance -= USD(101);
-
5231 makerXRPBalance -= XRP(101).value() + txfee(env, 1);
-
5232 takerXRPBalance += XRP(101).value() - txfee(env, 1);
-
5233 BEAST_EXPECT(expectOffers(env, taker, 0));
-
5234
-
5235 env(offer(maker, USD(101), EUR(101)));
-
5236 env.close();
-
5237
-
5238 env(offer(taker, EUR(100), USD(101)),
- -
5240 env.close();
-
5241
-
5242 makerUSDBalance += USD(101);
-
5243 takerUSDBalance -= USD(101);
-
5244 makerEURBalance -= EUR(101);
-
5245 takerEURBalance += EUR(101);
-
5246 makerXRPBalance -= txfee(env, 1);
-
5247 takerXRPBalance -= txfee(env, 1);
-
5248 BEAST_EXPECT(expectOffers(env, taker, 0));
-
5249 }
-
5250
-
5251 // Fail regardless of fixFillOrKill amendment
-
5252 for (auto const flags : {tfFillOrKill, tfFillOrKill + tfSell})
-
5253 {
-
5254 env(offer(maker, XRP(100), USD(100)));
-
5255 env.close();
-
5256
-
5257 env(offer(taker, USD(100), XRP(99)),
-
5258 txflags(flags),
-
5259 ter(tecKILLED));
-
5260 env.close();
-
5261
-
5262 makerXRPBalance -= txfee(env, 1);
-
5263 takerXRPBalance -= txfee(env, 1);
-
5264 BEAST_EXPECT(expectOffers(env, taker, 0));
+
5187 makerXRPBalance -= txfee(env, 1);
+
5188 takerXRPBalance -= txfee(env, 1);
+
5189 if (err == tesSUCCESS)
+
5190 {
+
5191 makerUSDBalance += USD(100);
+
5192 takerUSDBalance -= USD(100);
+
5193 makerEURBalance -= EUR(100);
+
5194 takerEURBalance += EUR(100);
+
5195 }
+
5196 BEAST_EXPECT(expectOffers(env, taker, 0));
+
5197 }
+
5198
+
5199 // tfFillOrKill + tfSell, TakerGets must be filled
+
5200 {
+
5201 env(offer(maker, XRP(101), USD(101)));
+
5202 env.close();
+
5203
+
5204 env(offer(taker, USD(100), XRP(101)),
+ +
5206 env.close();
+
5207
+
5208 makerUSDBalance -= USD(101);
+
5209 takerUSDBalance += USD(101);
+
5210 makerXRPBalance += XRP(101).value() - txfee(env, 1);
+
5211 takerXRPBalance -= XRP(101).value() + txfee(env, 1);
+
5212 BEAST_EXPECT(expectOffers(env, taker, 0));
+
5213
+
5214 env(offer(maker, USD(101), XRP(101)));
+
5215 env.close();
+
5216
+
5217 env(offer(taker, XRP(100), USD(101)),
+ +
5219 env.close();
+
5220
+
5221 makerUSDBalance += USD(101);
+
5222 takerUSDBalance -= USD(101);
+
5223 makerXRPBalance -= XRP(101).value() + txfee(env, 1);
+
5224 takerXRPBalance += XRP(101).value() - txfee(env, 1);
+
5225 BEAST_EXPECT(expectOffers(env, taker, 0));
+
5226
+
5227 env(offer(maker, USD(101), EUR(101)));
+
5228 env.close();
+
5229
+
5230 env(offer(taker, EUR(100), USD(101)),
+ +
5232 env.close();
+
5233
+
5234 makerUSDBalance += USD(101);
+
5235 takerUSDBalance -= USD(101);
+
5236 makerEURBalance -= EUR(101);
+
5237 takerEURBalance += EUR(101);
+
5238 makerXRPBalance -= txfee(env, 1);
+
5239 takerXRPBalance -= txfee(env, 1);
+
5240 BEAST_EXPECT(expectOffers(env, taker, 0));
+
5241 }
+
5242
+
5243 // Fail regardless of fixFillOrKill amendment
+
5244 for (auto const flags : {tfFillOrKill, tfFillOrKill + tfSell})
+
5245 {
+
5246 env(offer(maker, XRP(100), USD(100)));
+
5247 env.close();
+
5248
+
5249 env(offer(taker, USD(100), XRP(99)),
+
5250 txflags(flags),
+
5251 ter(tecKILLED));
+
5252 env.close();
+
5253
+
5254 makerXRPBalance -= txfee(env, 1);
+
5255 takerXRPBalance -= txfee(env, 1);
+
5256 BEAST_EXPECT(expectOffers(env, taker, 0));
+
5257
+
5258 env(offer(maker, USD(100), XRP(100)));
+
5259 env.close();
+
5260
+
5261 env(offer(taker, XRP(100), USD(99)),
+
5262 txflags(flags),
+
5263 ter(tecKILLED));
+
5264 env.close();
5265
-
5266 env(offer(maker, USD(100), XRP(100)));
-
5267 env.close();
-
5268
-
5269 env(offer(taker, XRP(100), USD(99)),
-
5270 txflags(flags),
-
5271 ter(tecKILLED));
-
5272 env.close();
-
5273
-
5274 makerXRPBalance -= txfee(env, 1);
-
5275 takerXRPBalance -= txfee(env, 1);
-
5276 BEAST_EXPECT(expectOffers(env, taker, 0));
+
5266 makerXRPBalance -= txfee(env, 1);
+
5267 takerXRPBalance -= txfee(env, 1);
+
5268 BEAST_EXPECT(expectOffers(env, taker, 0));
+
5269
+
5270 env(offer(maker, USD(100), EUR(100)));
+
5271 env.close();
+
5272
+
5273 env(offer(taker, EUR(100), USD(99)),
+
5274 txflags(flags),
+
5275 ter(tecKILLED));
+
5276 env.close();
5277
-
5278 env(offer(maker, USD(100), EUR(100)));
-
5279 env.close();
-
5280
-
5281 env(offer(taker, EUR(100), USD(99)),
-
5282 txflags(flags),
-
5283 ter(tecKILLED));
-
5284 env.close();
-
5285
-
5286 makerXRPBalance -= txfee(env, 1);
-
5287 takerXRPBalance -= txfee(env, 1);
-
5288 BEAST_EXPECT(expectOffers(env, taker, 0));
-
5289 }
-
5290
-
5291 BEAST_EXPECT(
-
5292 env.balance(maker, USD) == makerUSDBalance &&
-
5293 env.balance(taker, USD) == takerUSDBalance &&
-
5294 env.balance(maker, EUR) == makerEURBalance &&
-
5295 env.balance(taker, EUR) == takerEURBalance &&
-
5296 env.balance(maker, XRP) == makerXRPBalance &&
-
5297 env.balance(taker, XRP) == takerXRPBalance);
-
5298 }
+
5278 makerXRPBalance -= txfee(env, 1);
+
5279 takerXRPBalance -= txfee(env, 1);
+
5280 BEAST_EXPECT(expectOffers(env, taker, 0));
+
5281 }
+
5282
+
5283 BEAST_EXPECT(
+
5284 env.balance(maker, USD) == makerUSDBalance &&
+
5285 env.balance(taker, USD) == takerUSDBalance &&
+
5286 env.balance(maker, EUR) == makerEURBalance &&
+
5287 env.balance(taker, EUR) == takerEURBalance &&
+
5288 env.balance(maker, XRP) == makerXRPBalance &&
+
5289 env.balance(taker, XRP) == takerXRPBalance);
+
5290 }
-
5299
-
5300 void
-
- -
5302 {
-
5303 testCanceledOffer(features);
-
5304 testRmFundedOffer(features);
-
5305 testTinyPayment(features);
-
5306 testXRPTinyPayment(features);
-
5307 testEnforceNoRipple(features);
-
5308 testInsufficientReserve(features);
-
5309 testFillModes(features);
-
5310 testMalformed(features);
-
5311 testExpiration(features);
-
5312 testUnfundedCross(features);
-
5313 testSelfCross(false, features);
-
5314 testSelfCross(true, features);
-
5315 testNegativeBalance(features);
-
5316 testOfferCrossWithXRP(true, features);
-
5317 testOfferCrossWithXRP(false, features);
- -
5319 testOfferAcceptThenCancel(features);
- - - - -
5324 testCrossCurrencyStartXRP(features);
-
5325 testCrossCurrencyEndXRP(features);
-
5326 testCrossCurrencyBridged(features);
-
5327 testBridgedSecondLegDry(features);
-
5328 testOfferFeesConsumeFunds(features);
-
5329 testOfferCreateThenCross(features);
-
5330 testSellFlagBasic(features);
-
5331 testSellFlagExceedLimit(features);
-
5332 testGatewayCrossCurrency(features);
-
5333 testPartialCross(features);
-
5334 testXRPDirectCross(features);
-
5335 testDirectCross(features);
-
5336 testBridgedCross(features);
-
5337 testSellOffer(features);
-
5338 testSellWithFillOrKill(features);
-
5339 testTransferRateOffer(features);
-
5340 testSelfCrossOffer(features);
-
5341 testSelfIssueOffer(features);
-
5342 testBadPathAssert(features);
-
5343 testDirectToDirectPath(features);
- -
5345 testOfferInScaling(features);
- - -
5348 testTinyOffer(features);
-
5349 testSelfPayXferFeeOffer(features);
-
5350 testSelfPayUnlimitedFunds(features);
-
5351 testRequireAuth(features);
-
5352 testMissingAuth(features);
-
5353 testRCSmoketest(features);
-
5354 testSelfAuth(features);
-
5355 testDeletedOfferIssuer(features);
-
5356 testTickSize(features);
-
5357 testTicketOffer(features);
-
5358 testTicketCancelOffer(features);
- - -
5361 testFillOrKill(features);
-
5362 }
+
5291
+
5292 void
+
+ +
5294 {
+
5295 testCanceledOffer(features);
+
5296 testRmFundedOffer(features);
+
5297 testTinyPayment(features);
+
5298 testXRPTinyPayment(features);
+
5299 testEnforceNoRipple(features);
+
5300 testInsufficientReserve(features);
+
5301 testFillModes(features);
+
5302 testMalformed(features);
+
5303 testExpiration(features);
+
5304 testUnfundedCross(features);
+
5305 testSelfCross(false, features);
+
5306 testSelfCross(true, features);
+
5307 testNegativeBalance(features);
+
5308 testOfferCrossWithXRP(true, features);
+
5309 testOfferCrossWithXRP(false, features);
+ +
5311 testOfferAcceptThenCancel(features);
+ + + + +
5316 testCrossCurrencyStartXRP(features);
+
5317 testCrossCurrencyEndXRP(features);
+
5318 testCrossCurrencyBridged(features);
+
5319 testBridgedSecondLegDry(features);
+
5320 testOfferFeesConsumeFunds(features);
+
5321 testOfferCreateThenCross(features);
+
5322 testSellFlagBasic(features);
+
5323 testSellFlagExceedLimit(features);
+
5324 testGatewayCrossCurrency(features);
+
5325 testPartialCross(features);
+
5326 testXRPDirectCross(features);
+
5327 testDirectCross(features);
+
5328 testBridgedCross(features);
+
5329 testSellOffer(features);
+
5330 testSellWithFillOrKill(features);
+
5331 testTransferRateOffer(features);
+
5332 testSelfCrossOffer(features);
+
5333 testSelfIssueOffer(features);
+
5334 testBadPathAssert(features);
+
5335 testDirectToDirectPath(features);
+ +
5337 testOfferInScaling(features);
+ + +
5340 testTinyOffer(features);
+
5341 testSelfPayXferFeeOffer(features);
+
5342 testSelfPayUnlimitedFunds(features);
+
5343 testRequireAuth(features);
+
5344 testMissingAuth(features);
+
5345 testRCSmoketest(features);
+
5346 testSelfAuth(features);
+
5347 testDeletedOfferIssuer(features);
+
5348 testTickSize(features);
+
5349 testTicketOffer(features);
+
5350 testTicketCancelOffer(features);
+ + +
5353 testFillOrKill(features);
+
5354 }
-
5363
-
5364 void
-
-
5365 run(std::uint32_t instance, bool last = false)
-
5366 {
-
5367 using namespace jtx;
-
5368 static FeatureBitset const all{testable_amendments()};
-
5369 static FeatureBitset const takerDryOffer{fixTakerDryOfferRemoval};
-
5370 static FeatureBitset const rmSmallIncreasedQOffers{
-
5371 fixRmSmallIncreasedQOffers};
-
5372 static FeatureBitset const immediateOfferKilled{
-
5373 featureImmediateOfferKilled};
-
5374 FeatureBitset const fillOrKill{fixFillOrKill};
-
5375 FeatureBitset const permDEX{featurePermissionedDEX};
-
5376
-
5377 static std::array<FeatureBitset, 6> const feats{
-
5378 all - takerDryOffer - immediateOfferKilled - permDEX,
-
5379 all - immediateOfferKilled - permDEX,
-
5380 all - rmSmallIncreasedQOffers - immediateOfferKilled - fillOrKill -
-
5381 permDEX,
-
5382 all - fillOrKill - permDEX,
-
5383 all - permDEX,
-
5384 all};
-
5385
-
5386 if (BEAST_EXPECT(instance < feats.size()))
-
5387 {
-
5388 testAll(feats[instance]);
-
5389 }
-
5390 BEAST_EXPECT(!last || instance == feats.size() - 1);
-
5391 }
+
5355
+
5356 void
+
+
5357 run(std::uint32_t instance, bool last = false)
+
5358 {
+
5359 using namespace jtx;
+
5360 static FeatureBitset const all{testable_amendments()};
+
5361 static FeatureBitset const takerDryOffer{fixTakerDryOfferRemoval};
+
5362 static FeatureBitset const rmSmallIncreasedQOffers{
+
5363 fixRmSmallIncreasedQOffers};
+
5364 static FeatureBitset const immediateOfferKilled{
+
5365 featureImmediateOfferKilled};
+
5366 FeatureBitset const fillOrKill{fixFillOrKill};
+
5367 FeatureBitset const permDEX{featurePermissionedDEX};
+
5368
+
5369 static std::array<FeatureBitset, 6> const feats{
+
5370 all - takerDryOffer - immediateOfferKilled - permDEX,
+
5371 all - immediateOfferKilled - permDEX,
+
5372 all - rmSmallIncreasedQOffers - immediateOfferKilled - fillOrKill -
+
5373 permDEX,
+
5374 all - fillOrKill - permDEX,
+
5375 all - permDEX,
+
5376 all};
+
5377
+
5378 if (BEAST_EXPECT(instance < feats.size()))
+
5379 {
+
5380 testAll(feats[instance]);
+
5381 }
+
5382 BEAST_EXPECT(!last || instance == feats.size() - 1);
+
5383 }
+
+
5384
+
5385 void
+
+
5386 run() override
+
5387 {
+
5388 run(0);
+ +
5390 }
+
+
5391};
5392
-
5393 void
-
-
5394 run() override
-
5395 {
-
5396 run(0);
- -
5398 }
+
+ +
5394{
+
5395 void
+
+
5396 run() override
+
5397 {
+ +
5399 }
-
5399};
+
5400};
-
5400
-
- -
5402{
-
5403 void
-
-
5404 run() override
-
5405 {
- -
5407 }
+
5401
+
+ +
5403{
+
5404 void
+
+
5405 run() override
+
5406 {
+ +
5408 }
-
5408};
+
5409};
-
5409
-
- -
5411{
-
5412 void
-
-
5413 run() override
-
5414 {
- -
5416 }
+
5410
+
+ +
5412{
+
5413 void
+
+
5414 run() override
+
5415 {
+ +
5417 }
-
5417};
+
5418};
-
5418
-
- -
5420{
-
5421 void
-
-
5422 run() override
-
5423 {
- -
5425 }
+
5419
+
+ +
5421{
+
5422 void
+
+
5423 run() override
+
5424 {
+ +
5426 }
-
5426};
+
5427};
-
5427
-
- -
5429{
-
5430 void
-
-
5431 run() override
-
5432 {
- -
5434 }
+
5428
+
+ +
5430{
+
5431 void
+
+
5432 run() override
+
5433 {
+
5434 OfferBaseUtil_test::run(5, true);
+
5435 }
-
5435};
+
5436};
-
5436
-
- -
5438{
-
5439 void
-
-
5440 run() override
-
5441 {
-
5442 OfferBaseUtil_test::run(5, true);
-
5443 }
+
5437
+
+ +
5439{
+
5440 void
+
+
5441 run() override
+
5442 {
+
5443 using namespace jtx;
+ +
5445 FeatureBitset const immediateOfferKilled{featureImmediateOfferKilled};
+
5446 FeatureBitset const takerDryOffer{fixTakerDryOfferRemoval};
+
5447 FeatureBitset const fillOrKill{fixFillOrKill};
+
5448 FeatureBitset const permDEX{featurePermissionedDEX};
+
5449
+
5450 testAll(all - immediateOfferKilled - permDEX);
+
5451 testAll(all - immediateOfferKilled - fillOrKill - permDEX);
+
5452 testAll(all - fillOrKill - permDEX);
+
5453 testAll(all - permDEX);
+
5454 testAll(all);
+
5455
+
5456 testAll(all - takerDryOffer - permDEX);
+
5457 }
-
5444};
-
-
5445
-
- -
5447{
-
5448 void
-
-
5449 run() override
-
5450 {
-
5451 using namespace jtx;
- -
5453 FeatureBitset const immediateOfferKilled{featureImmediateOfferKilled};
-
5454 FeatureBitset const takerDryOffer{fixTakerDryOfferRemoval};
-
5455 FeatureBitset const fillOrKill{fixFillOrKill};
-
5456 FeatureBitset const permDEX{featurePermissionedDEX};
-
5457
-
5458 testAll(all - immediateOfferKilled - permDEX);
-
5459 testAll(all - immediateOfferKilled - fillOrKill - permDEX);
-
5460 testAll(all - fillOrKill - permDEX);
-
5461 testAll(all - permDEX);
-
5462 testAll(all);
-
5463
-
5464 testAll(all - takerDryOffer - permDEX);
-
5465 }
-
-
5466};
+
5458};
+
5459
+
5460BEAST_DEFINE_TESTSUITE_PRIO(OfferBaseUtil, app, ripple, 2);
+
5461BEAST_DEFINE_TESTSUITE_PRIO(OfferWTakerDryOffer, app, ripple, 2);
+
5462BEAST_DEFINE_TESTSUITE_PRIO(OfferWOSmallQOffers, app, ripple, 2);
+
5463BEAST_DEFINE_TESTSUITE_PRIO(OfferWOFillOrKill, app, ripple, 2);
+
5464BEAST_DEFINE_TESTSUITE_PRIO(OfferWOPermDEX, app, ripple, 2);
+
5465BEAST_DEFINE_TESTSUITE_PRIO(OfferAllFeatures, app, ripple, 2);
+
5466BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(Offer_manual, app, ripple, 20);
5467
-
5468BEAST_DEFINE_TESTSUITE_PRIO(OfferBaseUtil, app, ripple, 2);
-
5469BEAST_DEFINE_TESTSUITE_PRIO(OfferWTakerDryOffer, app, ripple, 2);
-
5470BEAST_DEFINE_TESTSUITE_PRIO(OfferWOSmallQOffers, app, ripple, 2);
-
5471BEAST_DEFINE_TESTSUITE_PRIO(OfferWOFillOrKill, app, ripple, 2);
-
5472BEAST_DEFINE_TESTSUITE_PRIO(OfferWOPermDEX, app, ripple, 2);
-
5473BEAST_DEFINE_TESTSUITE_PRIO(OfferAllFeatures, app, ripple, 2);
-
5474BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(Offer_manual, app, ripple, 20);
-
5475
-
5476} // namespace test
-
5477} // namespace ripple
+
5468} // namespace test
+
5469} // namespace ripple
Represents a JSON value.
Definition json_value.h:149
@@ -5741,89 +5733,89 @@ $(document).ready(function() { init_codefold(0); }); - -
void run() override
Runs the suite.
+ +
void run() override
Runs the suite.
-
void testSelfCrossOffer2(FeatureBitset features)
-
void run() override
Runs the suite.
-
void testMissingAuth(FeatureBitset features)
-
void testSelfAuth(FeatureBitset features)
-
void testSelfCross(bool use_partner, FeatureBitset features)
-
void testCrossCurrencyBridged(FeatureBitset features)
-
void testAll(FeatureBitset features)
-
void testSelfIssueOffer(FeatureBitset features)
-
void testRCSmoketest(FeatureBitset features)
-
void testExpiration(FeatureBitset features)
-
void testUnfundedCross(FeatureBitset features)
-
void testCrossCurrencyStartXRP(FeatureBitset features)
+
void testSelfCrossOffer2(FeatureBitset features)
+
void run() override
Runs the suite.
+
void testMissingAuth(FeatureBitset features)
+
void testSelfAuth(FeatureBitset features)
+
void testSelfCross(bool use_partner, FeatureBitset features)
+
void testCrossCurrencyBridged(FeatureBitset features)
+
void testAll(FeatureBitset features)
+
void testSelfIssueOffer(FeatureBitset features)
+
void testRCSmoketest(FeatureBitset features)
+
void testExpiration(FeatureBitset features)
+
void testUnfundedCross(FeatureBitset features)
+
void testCrossCurrencyStartXRP(FeatureBitset features)
static std::vector< std::shared_ptr< SLE const > > offersOnAccount(jtx::Env &env, jtx::Account account)
void testRmSmallIncreasedQOffersIOU(FeatureBitset features)
-
void testSellWithFillOrKill(FeatureBitset features)
-
void testTinyOffer(FeatureBitset features)
+
void testSellWithFillOrKill(FeatureBitset features)
+
void testTinyOffer(FeatureBitset features)
void testInsufficientReserve(FeatureBitset features)
-
void testDirectCross(FeatureBitset features)
-
void testOfferThresholdWithReducedFunds(FeatureBitset features)
-
void testRequireAuth(FeatureBitset features)
-
void verifyDefaultTrustline(jtx::Env &env, jtx::Account const &account, jtx::PrettyAmount const &expectBalance)
+
void testDirectCross(FeatureBitset features)
+
void testOfferThresholdWithReducedFunds(FeatureBitset features)
+
void testRequireAuth(FeatureBitset features)
+
void verifyDefaultTrustline(jtx::Env &env, jtx::Account const &account, jtx::PrettyAmount const &expectBalance)
void testRmSmallIncreasedQOffersXRP(FeatureBitset features)
-
void testDirectToDirectPath(FeatureBitset features)
+
void testDirectToDirectPath(FeatureBitset features)
void testRmFundedOffer(FeatureBitset features)
-
void testOfferFeesConsumeFunds(FeatureBitset features)
-
void testTickSize(FeatureBitset features)
-
void testTicketOffer(FeatureBitset features)
-
void testOfferCreateThenCross(FeatureBitset features)
-
void testFillOrKill(FeatureBitset features)
-
void testSelfPayUnlimitedFunds(FeatureBitset features)
-
void testOfferCancelPastAndFuture(FeatureBitset features)
-
void testSellFlagBasic(FeatureBitset features)
-
void testBridgedCross(FeatureBitset features)
-
void testXRPDirectCross(FeatureBitset features)
-
void testDeletedOfferIssuer(FeatureBitset features)
+
void testOfferFeesConsumeFunds(FeatureBitset features)
+
void testTickSize(FeatureBitset features)
+
void testTicketOffer(FeatureBitset features)
+
void testOfferCreateThenCross(FeatureBitset features)
+
void testFillOrKill(FeatureBitset features)
+
void testSelfPayUnlimitedFunds(FeatureBitset features)
+
void testOfferCancelPastAndFuture(FeatureBitset features)
+
void testSellFlagBasic(FeatureBitset features)
+
void testBridgedCross(FeatureBitset features)
+
void testXRPDirectCross(FeatureBitset features)
+
void testDeletedOfferIssuer(FeatureBitset features)
void testXRPTinyPayment(FeatureBitset features)
- -
void testTransferRateOffer(FeatureBitset features)
-
void testPartialCross(FeatureBitset features)
-
static std::vector< std::shared_ptr< SLE const > > sortedOffersOnAccount(jtx::Env &env, jtx::Account const &acct)
-
void testCurrencyConversionIntoDebt(FeatureBitset features)
-
void testMalformed(FeatureBitset features)
-
void run(std::uint32_t instance, bool last=false)
-
void testOfferCrossWithXRP(bool reverse_order, FeatureBitset features)
+ +
void testTransferRateOffer(FeatureBitset features)
+
void testPartialCross(FeatureBitset features)
+
static std::vector< std::shared_ptr< SLE const > > sortedOffersOnAccount(jtx::Env &env, jtx::Account const &acct)
+
void testCurrencyConversionIntoDebt(FeatureBitset features)
+
void testMalformed(FeatureBitset features)
+
void run(std::uint32_t instance, bool last=false)
+
void testOfferCrossWithXRP(bool reverse_order, FeatureBitset features)
void testFillModes(FeatureBitset features)
-
void testOfferInScaling(FeatureBitset features)
-
void testOfferInScalingWithXferRate(FeatureBitset features)
+
void testOfferInScaling(FeatureBitset features)
+
void testOfferInScalingWithXferRate(FeatureBitset features)
static auto ledgerEntryOffer(jtx::Env &env, jtx::Account const &acct, std::uint32_t offer_seq)
-
void testCurrencyConversionEntire(FeatureBitset features)
-
void testSelfPayXferFeeOffer(FeatureBitset features)
-
void testCurrencyConversionInParts(FeatureBitset features)
-
void testBridgedSecondLegDry(FeatureBitset features)
-
void testSellOffer(FeatureBitset features)
-
void testCrossCurrencyEndXRP(FeatureBitset features)
-
void testGatewayCrossCurrency(FeatureBitset features)
-
void testNegativeBalance(FeatureBitset features)
+
void testCurrencyConversionEntire(FeatureBitset features)
+
void testSelfPayXferFeeOffer(FeatureBitset features)
+
void testCurrencyConversionInParts(FeatureBitset features)
+
void testBridgedSecondLegDry(FeatureBitset features)
+
void testSellOffer(FeatureBitset features)
+
void testCrossCurrencyEndXRP(FeatureBitset features)
+
void testGatewayCrossCurrency(FeatureBitset features)
+
void testNegativeBalance(FeatureBitset features)
static auto getBookOffers(jtx::Env &env, Issue const &taker_pays, Issue const &taker_gets)
-
void testSelfCrossOffer(FeatureBitset features)
+
void testSelfCrossOffer(FeatureBitset features)
std::uint32_t lastClose(jtx::Env &env)
-
void testSelfCrossOffer1(FeatureBitset features)
+
void testSelfCrossOffer1(FeatureBitset features)
XRPAmount reserve(jtx::Env &env, std::uint32_t count)
-
void testOfferCrossWithLimitOverride(FeatureBitset features)
-
void testTicketCancelOffer(FeatureBitset features)
-
void testSelfCrossLowQualityOffer(FeatureBitset features)
-
void testOfferAcceptThenCancel(FeatureBitset features)
-
void testSellFlagExceedLimit(FeatureBitset features)
+
void testOfferCrossWithLimitOverride(FeatureBitset features)
+
void testTicketCancelOffer(FeatureBitset features)
+
void testSelfCrossLowQualityOffer(FeatureBitset features)
+
void testOfferAcceptThenCancel(FeatureBitset features)
+
void testSellFlagExceedLimit(FeatureBitset features)
void testCanceledOffer(FeatureBitset features)
-
void testBadPathAssert(FeatureBitset features)
+
void testBadPathAssert(FeatureBitset features)
void testTinyPayment(FeatureBitset features)
void testEnforceNoRipple(FeatureBitset features)
- -
void run() override
Runs the suite.
- -
void run() override
Runs the suite.
- -
void run() override
Runs the suite.
- -
void run() override
Runs the suite.
- -
void run() override
Runs the suite.
+ +
void run() override
Runs the suite.
+ +
void run() override
Runs the suite.
+ +
void run() override
Runs the suite.
+ +
void run() override
Runs the suite.
+ +
void run() override
Runs the suite.
Immutable cryptographic account descriptor.
Definition Account.h:39
diff --git a/SetTrust_8cpp_source.html b/SetTrust_8cpp_source.html index daafa8c240..643636a030 100644 --- a/SetTrust_8cpp_source.html +++ b/SetTrust_8cpp_source.html @@ -668,7 +668,7 @@ $(document).ready(function() { init_codefold(0); });
576 if ((bHigh ? saHighBalance : saLowBalance) >= beast::zero)
577 uFlagsOut |= (bHigh ? lsfHighNoRipple : lsfLowNoRipple);
578
-
579 else if (view().rules().enabled(fix1578))
+
579 else
580 // Cannot set noRipple on a negative balance.
581 return tecNO_PERMISSION;
582 }
diff --git a/classripple_1_1CreateOffer.html b/classripple_1_1CreateOffer.html index 386ad616af..20d533d601 100644 --- a/classripple_1_1CreateOffer.html +++ b/classripple_1_1CreateOffer.html @@ -612,7 +612,7 @@ Static Private Member Functions

Implements ripple::Transactor.

-

Definition at line 942 of file CreateOffer.cpp.

+

Definition at line 940 of file CreateOffer.cpp.

diff --git a/classripple_1_1Feature__test.html b/classripple_1_1Feature__test.html index 75918a373f..59783ea60b 100644 --- a/classripple_1_1Feature__test.html +++ b/classripple_1_1Feature__test.html @@ -339,7 +339,7 @@ Private Attributes
-

Definition at line 153 of file Feature_test.cpp.

+

Definition at line 152 of file Feature_test.cpp.

@@ -366,7 +366,7 @@ Private Attributes
-

Definition at line 198 of file Feature_test.cpp.

+

Definition at line 197 of file Feature_test.cpp.

@@ -393,7 +393,7 @@ Private Attributes
-

Definition at line 228 of file Feature_test.cpp.

+

Definition at line 227 of file Feature_test.cpp.

@@ -420,7 +420,7 @@ Private Attributes
-

Definition at line 260 of file Feature_test.cpp.

+

Definition at line 259 of file Feature_test.cpp.

@@ -447,7 +447,7 @@ Private Attributes
-

Definition at line 356 of file Feature_test.cpp.

+

Definition at line 355 of file Feature_test.cpp.

@@ -474,7 +474,7 @@ Private Attributes
-

Definition at line 412 of file Feature_test.cpp.

+

Definition at line 411 of file Feature_test.cpp.

@@ -501,7 +501,7 @@ Private Attributes
-

Definition at line 511 of file Feature_test.cpp.

+

Definition at line 510 of file Feature_test.cpp.

@@ -528,7 +528,7 @@ Private Attributes
-

Definition at line 562 of file Feature_test.cpp.

+

Definition at line 561 of file Feature_test.cpp.

@@ -559,7 +559,7 @@ Private Attributes

Implements beast::unit_test::suite.

-

Definition at line 617 of file Feature_test.cpp.

+

Definition at line 616 of file Feature_test.cpp.

diff --git a/classripple_1_1test_1_1NoRipple__test.html b/classripple_1_1test_1_1NoRipple__test.html index b66f2e3e5a..5826e75635 100644 --- a/classripple_1_1test_1_1NoRipple__test.html +++ b/classripple_1_1test_1_1NoRipple__test.html @@ -305,7 +305,7 @@ Private Attributes
-

Definition at line 169 of file NoRipple_test.cpp.

+

Definition at line 160 of file NoRipple_test.cpp.

@@ -335,7 +335,7 @@ Private Attributes
-

Definition at line 208 of file NoRipple_test.cpp.

+

Definition at line 199 of file NoRipple_test.cpp.

@@ -366,7 +366,7 @@ Private Attributes

Implements beast::unit_test::suite.

-

Definition at line 284 of file NoRipple_test.cpp.

+

Definition at line 275 of file NoRipple_test.cpp.

diff --git a/classripple_1_1test_1_1OfferAllFeatures__test.html b/classripple_1_1test_1_1OfferAllFeatures__test.html index a6cd976b04..b22730669f 100644 --- a/classripple_1_1test_1_1OfferAllFeatures__test.html +++ b/classripple_1_1test_1_1OfferAllFeatures__test.html @@ -382,7 +382,7 @@ Private Attributes

Detailed Description

-

Definition at line 5437 of file Offer_test.cpp.

+

Definition at line 5429 of file Offer_test.cpp.

Member Function Documentation

◆ run() [1/2]

@@ -411,7 +411,7 @@ Private Attributes

Implements beast::unit_test::suite.

-

Definition at line 5440 of file Offer_test.cpp.

+

Definition at line 5432 of file Offer_test.cpp.

@@ -883,7 +883,7 @@ Private Attributes
-

Definition at line 1068 of file Offer_test.cpp.

+

Definition at line 1061 of file Offer_test.cpp.

@@ -911,7 +911,7 @@ Private Attributes
-

Definition at line 1146 of file Offer_test.cpp.

+

Definition at line 1139 of file Offer_test.cpp.

@@ -939,7 +939,7 @@ Private Attributes
-

Definition at line 1224 of file Offer_test.cpp.

+

Definition at line 1217 of file Offer_test.cpp.

@@ -977,7 +977,7 @@ Private Attributes
-

Definition at line 1284 of file Offer_test.cpp.

+

Definition at line 1277 of file Offer_test.cpp.

@@ -1005,7 +1005,7 @@ Private Attributes
-

Definition at line 1394 of file Offer_test.cpp.

+

Definition at line 1387 of file Offer_test.cpp.

@@ -1043,7 +1043,7 @@ Private Attributes
-

Definition at line 1504 of file Offer_test.cpp.

+

Definition at line 1497 of file Offer_test.cpp.

@@ -1071,7 +1071,7 @@ Private Attributes
-

Definition at line 1559 of file Offer_test.cpp.

+

Definition at line 1552 of file Offer_test.cpp.

@@ -1099,7 +1099,7 @@ Private Attributes
-

Definition at line 1600 of file Offer_test.cpp.

+

Definition at line 1593 of file Offer_test.cpp.

@@ -1127,7 +1127,7 @@ Private Attributes
-

Definition at line 1624 of file Offer_test.cpp.

+

Definition at line 1617 of file Offer_test.cpp.

@@ -1155,7 +1155,7 @@ Private Attributes
-

Definition at line 1650 of file Offer_test.cpp.

+

Definition at line 1643 of file Offer_test.cpp.

@@ -1183,7 +1183,7 @@ Private Attributes
-

Definition at line 1704 of file Offer_test.cpp.

+

Definition at line 1697 of file Offer_test.cpp.

@@ -1211,7 +1211,7 @@ Private Attributes
-

Definition at line 1734 of file Offer_test.cpp.

+

Definition at line 1727 of file Offer_test.cpp.

@@ -1239,7 +1239,7 @@ Private Attributes
-

Definition at line 1820 of file Offer_test.cpp.

+

Definition at line 1813 of file Offer_test.cpp.

@@ -1267,7 +1267,7 @@ Private Attributes
-

Definition at line 1862 of file Offer_test.cpp.

+

Definition at line 1855 of file Offer_test.cpp.

@@ -1295,7 +1295,7 @@ Private Attributes
-

Definition at line 1910 of file Offer_test.cpp.

+

Definition at line 1903 of file Offer_test.cpp.

@@ -1323,7 +1323,7 @@ Private Attributes
-

Definition at line 1976 of file Offer_test.cpp.

+

Definition at line 1969 of file Offer_test.cpp.

@@ -1351,7 +1351,7 @@ Private Attributes
-

Definition at line 2043 of file Offer_test.cpp.

+

Definition at line 2036 of file Offer_test.cpp.

@@ -1379,7 +1379,7 @@ Private Attributes
-

Definition at line 2098 of file Offer_test.cpp.

+

Definition at line 2091 of file Offer_test.cpp.

@@ -1407,7 +1407,7 @@ Private Attributes
-

Definition at line 2154 of file Offer_test.cpp.

+

Definition at line 2147 of file Offer_test.cpp.

@@ -1435,7 +1435,7 @@ Private Attributes
-

Definition at line 2197 of file Offer_test.cpp.

+

Definition at line 2190 of file Offer_test.cpp.

@@ -1463,7 +1463,7 @@ Private Attributes
-

Definition at line 2242 of file Offer_test.cpp.

+

Definition at line 2235 of file Offer_test.cpp.

@@ -1507,7 +1507,7 @@ Private Attributes
-

Definition at line 2320 of file Offer_test.cpp.

+

Definition at line 2313 of file Offer_test.cpp.

@@ -1535,7 +1535,7 @@ Private Attributes
-

Definition at line 2351 of file Offer_test.cpp.

+

Definition at line 2344 of file Offer_test.cpp.

@@ -1563,7 +1563,7 @@ Private Attributes
-

Definition at line 2510 of file Offer_test.cpp.

+

Definition at line 2503 of file Offer_test.cpp.

@@ -1591,7 +1591,7 @@ Private Attributes
-

Definition at line 2587 of file Offer_test.cpp.

+

Definition at line 2580 of file Offer_test.cpp.

@@ -1619,7 +1619,7 @@ Private Attributes
-

Definition at line 2705 of file Offer_test.cpp.

+

Definition at line 2698 of file Offer_test.cpp.

@@ -1647,7 +1647,7 @@ Private Attributes
-

Definition at line 2803 of file Offer_test.cpp.

+

Definition at line 2796 of file Offer_test.cpp.

@@ -1675,7 +1675,7 @@ Private Attributes
-

Definition at line 2992 of file Offer_test.cpp.

+

Definition at line 2985 of file Offer_test.cpp.

@@ -1703,7 +1703,7 @@ Private Attributes
-

Definition at line 3078 of file Offer_test.cpp.

+

Definition at line 3070 of file Offer_test.cpp.

@@ -1731,7 +1731,7 @@ Private Attributes
-

Definition at line 3386 of file Offer_test.cpp.

+

Definition at line 3378 of file Offer_test.cpp.

@@ -1759,7 +1759,7 @@ Private Attributes
-

Definition at line 3456 of file Offer_test.cpp.

+

Definition at line 3448 of file Offer_test.cpp.

@@ -1787,7 +1787,7 @@ Private Attributes
-

Definition at line 3568 of file Offer_test.cpp.

+

Definition at line 3560 of file Offer_test.cpp.

@@ -1815,7 +1815,7 @@ Private Attributes
-

Definition at line 3576 of file Offer_test.cpp.

+

Definition at line 3568 of file Offer_test.cpp.

@@ -1843,7 +1843,7 @@ Private Attributes
-

Definition at line 3621 of file Offer_test.cpp.

+

Definition at line 3613 of file Offer_test.cpp.

@@ -1871,7 +1871,7 @@ Private Attributes
-

Definition at line 3692 of file Offer_test.cpp.

+

Definition at line 3684 of file Offer_test.cpp.

@@ -1899,7 +1899,7 @@ Private Attributes
-

Definition at line 3745 of file Offer_test.cpp.

+

Definition at line 3737 of file Offer_test.cpp.

@@ -1927,7 +1927,7 @@ Private Attributes
-

Definition at line 3781 of file Offer_test.cpp.

+

Definition at line 3773 of file Offer_test.cpp.

@@ -1955,7 +1955,7 @@ Private Attributes
-

Definition at line 3828 of file Offer_test.cpp.

+

Definition at line 3820 of file Offer_test.cpp.

@@ -1983,7 +1983,7 @@ Private Attributes
-

Definition at line 3880 of file Offer_test.cpp.

+

Definition at line 3872 of file Offer_test.cpp.

@@ -2011,7 +2011,7 @@ Private Attributes
-

Definition at line 3947 of file Offer_test.cpp.

+

Definition at line 3939 of file Offer_test.cpp.

@@ -2039,7 +2039,7 @@ Private Attributes
-

Definition at line 3995 of file Offer_test.cpp.

+

Definition at line 3987 of file Offer_test.cpp.

@@ -2067,7 +2067,7 @@ Private Attributes
-

Definition at line 4150 of file Offer_test.cpp.

+

Definition at line 4142 of file Offer_test.cpp.

@@ -2095,7 +2095,7 @@ Private Attributes
-

Definition at line 4299 of file Offer_test.cpp.

+

Definition at line 4291 of file Offer_test.cpp.

@@ -2123,7 +2123,7 @@ Private Attributes
-

Definition at line 4350 of file Offer_test.cpp.

+

Definition at line 4342 of file Offer_test.cpp.

@@ -2151,7 +2151,7 @@ Private Attributes
-

Definition at line 4471 of file Offer_test.cpp.

+

Definition at line 4463 of file Offer_test.cpp.

@@ -2179,7 +2179,7 @@ Private Attributes
-

Definition at line 4560 of file Offer_test.cpp.

+

Definition at line 4552 of file Offer_test.cpp.

@@ -2207,7 +2207,7 @@ Private Attributes
-

Definition at line 4632 of file Offer_test.cpp.

+

Definition at line 4624 of file Offer_test.cpp.

@@ -2235,7 +2235,7 @@ Private Attributes
-

Definition at line 4739 of file Offer_test.cpp.

+

Definition at line 4731 of file Offer_test.cpp.

@@ -2273,7 +2273,7 @@ Private Attributes
-

Definition at line 4848 of file Offer_test.cpp.

+

Definition at line 4840 of file Offer_test.cpp.

@@ -2301,7 +2301,7 @@ Private Attributes
-

Definition at line 4863 of file Offer_test.cpp.

+

Definition at line 4855 of file Offer_test.cpp.

@@ -2329,7 +2329,7 @@ Private Attributes
-

Definition at line 4983 of file Offer_test.cpp.

+

Definition at line 4975 of file Offer_test.cpp.

@@ -2356,7 +2356,7 @@ Private Attributes
-

Definition at line 5095 of file Offer_test.cpp.

+

Definition at line 5087 of file Offer_test.cpp.

@@ -2384,7 +2384,7 @@ Private Attributes
-

Definition at line 5113 of file Offer_test.cpp.

+

Definition at line 5105 of file Offer_test.cpp.

@@ -2412,7 +2412,7 @@ Private Attributes
-

Definition at line 5301 of file Offer_test.cpp.

+

Definition at line 5293 of file Offer_test.cpp.

@@ -2450,7 +2450,7 @@ Private Attributes
-

Definition at line 5365 of file Offer_test.cpp.

+

Definition at line 5357 of file Offer_test.cpp.

diff --git a/classripple_1_1test_1_1OfferBaseUtil__test.html b/classripple_1_1test_1_1OfferBaseUtil__test.html index fc2033c2cc..309ae36731 100644 --- a/classripple_1_1test_1_1OfferBaseUtil__test.html +++ b/classripple_1_1test_1_1OfferBaseUtil__test.html @@ -780,7 +780,7 @@ Private Attributes
-

Definition at line 1068 of file Offer_test.cpp.

+

Definition at line 1061 of file Offer_test.cpp.

@@ -800,7 +800,7 @@ Private Attributes
-

Definition at line 1146 of file Offer_test.cpp.

+

Definition at line 1139 of file Offer_test.cpp.

@@ -820,7 +820,7 @@ Private Attributes
-

Definition at line 1224 of file Offer_test.cpp.

+

Definition at line 1217 of file Offer_test.cpp.

@@ -850,7 +850,7 @@ Private Attributes
-

Definition at line 1284 of file Offer_test.cpp.

+

Definition at line 1277 of file Offer_test.cpp.

@@ -870,7 +870,7 @@ Private Attributes
-

Definition at line 1394 of file Offer_test.cpp.

+

Definition at line 1387 of file Offer_test.cpp.

@@ -900,7 +900,7 @@ Private Attributes
-

Definition at line 1504 of file Offer_test.cpp.

+

Definition at line 1497 of file Offer_test.cpp.

@@ -920,7 +920,7 @@ Private Attributes
-

Definition at line 1559 of file Offer_test.cpp.

+

Definition at line 1552 of file Offer_test.cpp.

@@ -940,7 +940,7 @@ Private Attributes
-

Definition at line 1600 of file Offer_test.cpp.

+

Definition at line 1593 of file Offer_test.cpp.

@@ -960,7 +960,7 @@ Private Attributes
-

Definition at line 1624 of file Offer_test.cpp.

+

Definition at line 1617 of file Offer_test.cpp.

@@ -980,7 +980,7 @@ Private Attributes
-

Definition at line 1650 of file Offer_test.cpp.

+

Definition at line 1643 of file Offer_test.cpp.

@@ -1000,7 +1000,7 @@ Private Attributes
-

Definition at line 1704 of file Offer_test.cpp.

+

Definition at line 1697 of file Offer_test.cpp.

@@ -1020,7 +1020,7 @@ Private Attributes
-

Definition at line 1734 of file Offer_test.cpp.

+

Definition at line 1727 of file Offer_test.cpp.

@@ -1040,7 +1040,7 @@ Private Attributes
-

Definition at line 1820 of file Offer_test.cpp.

+

Definition at line 1813 of file Offer_test.cpp.

@@ -1060,7 +1060,7 @@ Private Attributes
-

Definition at line 1862 of file Offer_test.cpp.

+

Definition at line 1855 of file Offer_test.cpp.

@@ -1080,7 +1080,7 @@ Private Attributes
-

Definition at line 1910 of file Offer_test.cpp.

+

Definition at line 1903 of file Offer_test.cpp.

@@ -1100,7 +1100,7 @@ Private Attributes
-

Definition at line 1976 of file Offer_test.cpp.

+

Definition at line 1969 of file Offer_test.cpp.

@@ -1120,7 +1120,7 @@ Private Attributes
-

Definition at line 2043 of file Offer_test.cpp.

+

Definition at line 2036 of file Offer_test.cpp.

@@ -1140,7 +1140,7 @@ Private Attributes
-

Definition at line 2098 of file Offer_test.cpp.

+

Definition at line 2091 of file Offer_test.cpp.

@@ -1160,7 +1160,7 @@ Private Attributes
-

Definition at line 2154 of file Offer_test.cpp.

+

Definition at line 2147 of file Offer_test.cpp.

@@ -1180,7 +1180,7 @@ Private Attributes
-

Definition at line 2197 of file Offer_test.cpp.

+

Definition at line 2190 of file Offer_test.cpp.

@@ -1200,7 +1200,7 @@ Private Attributes
-

Definition at line 2242 of file Offer_test.cpp.

+

Definition at line 2235 of file Offer_test.cpp.

@@ -1236,7 +1236,7 @@ Private Attributes
-

Definition at line 2320 of file Offer_test.cpp.

+

Definition at line 2313 of file Offer_test.cpp.

@@ -1256,7 +1256,7 @@ Private Attributes
-

Definition at line 2351 of file Offer_test.cpp.

+

Definition at line 2344 of file Offer_test.cpp.

@@ -1276,7 +1276,7 @@ Private Attributes
-

Definition at line 2510 of file Offer_test.cpp.

+

Definition at line 2503 of file Offer_test.cpp.

@@ -1296,7 +1296,7 @@ Private Attributes
-

Definition at line 2587 of file Offer_test.cpp.

+

Definition at line 2580 of file Offer_test.cpp.

@@ -1316,7 +1316,7 @@ Private Attributes
-

Definition at line 2705 of file Offer_test.cpp.

+

Definition at line 2698 of file Offer_test.cpp.

@@ -1336,7 +1336,7 @@ Private Attributes
-

Definition at line 2803 of file Offer_test.cpp.

+

Definition at line 2796 of file Offer_test.cpp.

@@ -1356,7 +1356,7 @@ Private Attributes
-

Definition at line 2992 of file Offer_test.cpp.

+

Definition at line 2985 of file Offer_test.cpp.

@@ -1376,7 +1376,7 @@ Private Attributes
-

Definition at line 3078 of file Offer_test.cpp.

+

Definition at line 3070 of file Offer_test.cpp.

@@ -1396,7 +1396,7 @@ Private Attributes
-

Definition at line 3386 of file Offer_test.cpp.

+

Definition at line 3378 of file Offer_test.cpp.

@@ -1416,7 +1416,7 @@ Private Attributes
-

Definition at line 3456 of file Offer_test.cpp.

+

Definition at line 3448 of file Offer_test.cpp.

@@ -1436,7 +1436,7 @@ Private Attributes
-

Definition at line 3568 of file Offer_test.cpp.

+

Definition at line 3560 of file Offer_test.cpp.

@@ -1456,7 +1456,7 @@ Private Attributes
-

Definition at line 3576 of file Offer_test.cpp.

+

Definition at line 3568 of file Offer_test.cpp.

@@ -1476,7 +1476,7 @@ Private Attributes
-

Definition at line 3621 of file Offer_test.cpp.

+

Definition at line 3613 of file Offer_test.cpp.

@@ -1496,7 +1496,7 @@ Private Attributes
-

Definition at line 3692 of file Offer_test.cpp.

+

Definition at line 3684 of file Offer_test.cpp.

@@ -1516,7 +1516,7 @@ Private Attributes
-

Definition at line 3745 of file Offer_test.cpp.

+

Definition at line 3737 of file Offer_test.cpp.

@@ -1536,7 +1536,7 @@ Private Attributes
-

Definition at line 3781 of file Offer_test.cpp.

+

Definition at line 3773 of file Offer_test.cpp.

@@ -1556,7 +1556,7 @@ Private Attributes
-

Definition at line 3828 of file Offer_test.cpp.

+

Definition at line 3820 of file Offer_test.cpp.

@@ -1576,7 +1576,7 @@ Private Attributes
-

Definition at line 3880 of file Offer_test.cpp.

+

Definition at line 3872 of file Offer_test.cpp.

@@ -1596,7 +1596,7 @@ Private Attributes
-

Definition at line 3947 of file Offer_test.cpp.

+

Definition at line 3939 of file Offer_test.cpp.

@@ -1616,7 +1616,7 @@ Private Attributes
-

Definition at line 3995 of file Offer_test.cpp.

+

Definition at line 3987 of file Offer_test.cpp.

@@ -1636,7 +1636,7 @@ Private Attributes
-

Definition at line 4150 of file Offer_test.cpp.

+

Definition at line 4142 of file Offer_test.cpp.

@@ -1656,7 +1656,7 @@ Private Attributes
-

Definition at line 4299 of file Offer_test.cpp.

+

Definition at line 4291 of file Offer_test.cpp.

@@ -1676,7 +1676,7 @@ Private Attributes
-

Definition at line 4350 of file Offer_test.cpp.

+

Definition at line 4342 of file Offer_test.cpp.

@@ -1696,7 +1696,7 @@ Private Attributes
-

Definition at line 4471 of file Offer_test.cpp.

+

Definition at line 4463 of file Offer_test.cpp.

@@ -1716,7 +1716,7 @@ Private Attributes
-

Definition at line 4560 of file Offer_test.cpp.

+

Definition at line 4552 of file Offer_test.cpp.

@@ -1736,7 +1736,7 @@ Private Attributes
-

Definition at line 4632 of file Offer_test.cpp.

+

Definition at line 4624 of file Offer_test.cpp.

@@ -1756,7 +1756,7 @@ Private Attributes
-

Definition at line 4739 of file Offer_test.cpp.

+

Definition at line 4731 of file Offer_test.cpp.

@@ -1794,7 +1794,7 @@ Private Attributes
-

Definition at line 4848 of file Offer_test.cpp.

+

Definition at line 4840 of file Offer_test.cpp.

@@ -1814,7 +1814,7 @@ Private Attributes
-

Definition at line 4863 of file Offer_test.cpp.

+

Definition at line 4855 of file Offer_test.cpp.

@@ -1834,7 +1834,7 @@ Private Attributes
-

Definition at line 4983 of file Offer_test.cpp.

+

Definition at line 4975 of file Offer_test.cpp.

@@ -1853,7 +1853,7 @@ Private Attributes
-

Definition at line 5095 of file Offer_test.cpp.

+

Definition at line 5087 of file Offer_test.cpp.

@@ -1873,7 +1873,7 @@ Private Attributes
-

Definition at line 5113 of file Offer_test.cpp.

+

Definition at line 5105 of file Offer_test.cpp.

@@ -1893,7 +1893,7 @@ Private Attributes
-

Definition at line 5301 of file Offer_test.cpp.

+

Definition at line 5293 of file Offer_test.cpp.

@@ -1923,7 +1923,7 @@ Private Attributes
-

Definition at line 5365 of file Offer_test.cpp.

+

Definition at line 5357 of file Offer_test.cpp.

@@ -1956,7 +1956,7 @@ Private Attributes

Reimplemented in ripple::test::OfferWTakerDryOffer_test, ripple::test::OfferWOSmallQOffers_test, ripple::test::OfferWOFillOrKill_test, and ripple::test::OfferWOPermDEX_test.

-

Definition at line 5394 of file Offer_test.cpp.

+

Definition at line 5386 of file Offer_test.cpp.

diff --git a/classripple_1_1test_1_1OfferWOFillOrKill__test.html b/classripple_1_1test_1_1OfferWOFillOrKill__test.html index bb8d712f80..f5f0c92f3c 100644 --- a/classripple_1_1test_1_1OfferWOFillOrKill__test.html +++ b/classripple_1_1test_1_1OfferWOFillOrKill__test.html @@ -382,7 +382,7 @@ Private Attributes

Detailed Description

-

Definition at line 5419 of file Offer_test.cpp.

+

Definition at line 5411 of file Offer_test.cpp.

Member Function Documentation

◆ run() [1/2]

@@ -411,7 +411,7 @@ Private Attributes

Reimplemented from ripple::test::OfferBaseUtil_test.

-

Definition at line 5422 of file Offer_test.cpp.

+

Definition at line 5414 of file Offer_test.cpp.

@@ -883,7 +883,7 @@ Private Attributes
-

Definition at line 1068 of file Offer_test.cpp.

+

Definition at line 1061 of file Offer_test.cpp.

@@ -911,7 +911,7 @@ Private Attributes
-

Definition at line 1146 of file Offer_test.cpp.

+

Definition at line 1139 of file Offer_test.cpp.

@@ -939,7 +939,7 @@ Private Attributes
-

Definition at line 1224 of file Offer_test.cpp.

+

Definition at line 1217 of file Offer_test.cpp.

@@ -977,7 +977,7 @@ Private Attributes
-

Definition at line 1284 of file Offer_test.cpp.

+

Definition at line 1277 of file Offer_test.cpp.

@@ -1005,7 +1005,7 @@ Private Attributes
-

Definition at line 1394 of file Offer_test.cpp.

+

Definition at line 1387 of file Offer_test.cpp.

@@ -1043,7 +1043,7 @@ Private Attributes
-

Definition at line 1504 of file Offer_test.cpp.

+

Definition at line 1497 of file Offer_test.cpp.

@@ -1071,7 +1071,7 @@ Private Attributes
-

Definition at line 1559 of file Offer_test.cpp.

+

Definition at line 1552 of file Offer_test.cpp.

@@ -1099,7 +1099,7 @@ Private Attributes
-

Definition at line 1600 of file Offer_test.cpp.

+

Definition at line 1593 of file Offer_test.cpp.

@@ -1127,7 +1127,7 @@ Private Attributes
-

Definition at line 1624 of file Offer_test.cpp.

+

Definition at line 1617 of file Offer_test.cpp.

@@ -1155,7 +1155,7 @@ Private Attributes
-

Definition at line 1650 of file Offer_test.cpp.

+

Definition at line 1643 of file Offer_test.cpp.

@@ -1183,7 +1183,7 @@ Private Attributes
-

Definition at line 1704 of file Offer_test.cpp.

+

Definition at line 1697 of file Offer_test.cpp.

@@ -1211,7 +1211,7 @@ Private Attributes
-

Definition at line 1734 of file Offer_test.cpp.

+

Definition at line 1727 of file Offer_test.cpp.

@@ -1239,7 +1239,7 @@ Private Attributes
-

Definition at line 1820 of file Offer_test.cpp.

+

Definition at line 1813 of file Offer_test.cpp.

@@ -1267,7 +1267,7 @@ Private Attributes
-

Definition at line 1862 of file Offer_test.cpp.

+

Definition at line 1855 of file Offer_test.cpp.

@@ -1295,7 +1295,7 @@ Private Attributes
-

Definition at line 1910 of file Offer_test.cpp.

+

Definition at line 1903 of file Offer_test.cpp.

@@ -1323,7 +1323,7 @@ Private Attributes
-

Definition at line 1976 of file Offer_test.cpp.

+

Definition at line 1969 of file Offer_test.cpp.

@@ -1351,7 +1351,7 @@ Private Attributes
-

Definition at line 2043 of file Offer_test.cpp.

+

Definition at line 2036 of file Offer_test.cpp.

@@ -1379,7 +1379,7 @@ Private Attributes
-

Definition at line 2098 of file Offer_test.cpp.

+

Definition at line 2091 of file Offer_test.cpp.

@@ -1407,7 +1407,7 @@ Private Attributes
-

Definition at line 2154 of file Offer_test.cpp.

+

Definition at line 2147 of file Offer_test.cpp.

@@ -1435,7 +1435,7 @@ Private Attributes
-

Definition at line 2197 of file Offer_test.cpp.

+

Definition at line 2190 of file Offer_test.cpp.

@@ -1463,7 +1463,7 @@ Private Attributes
-

Definition at line 2242 of file Offer_test.cpp.

+

Definition at line 2235 of file Offer_test.cpp.

@@ -1507,7 +1507,7 @@ Private Attributes
-

Definition at line 2320 of file Offer_test.cpp.

+

Definition at line 2313 of file Offer_test.cpp.

@@ -1535,7 +1535,7 @@ Private Attributes
-

Definition at line 2351 of file Offer_test.cpp.

+

Definition at line 2344 of file Offer_test.cpp.

@@ -1563,7 +1563,7 @@ Private Attributes
-

Definition at line 2510 of file Offer_test.cpp.

+

Definition at line 2503 of file Offer_test.cpp.

@@ -1591,7 +1591,7 @@ Private Attributes
-

Definition at line 2587 of file Offer_test.cpp.

+

Definition at line 2580 of file Offer_test.cpp.

@@ -1619,7 +1619,7 @@ Private Attributes
-

Definition at line 2705 of file Offer_test.cpp.

+

Definition at line 2698 of file Offer_test.cpp.

@@ -1647,7 +1647,7 @@ Private Attributes
-

Definition at line 2803 of file Offer_test.cpp.

+

Definition at line 2796 of file Offer_test.cpp.

@@ -1675,7 +1675,7 @@ Private Attributes
-

Definition at line 2992 of file Offer_test.cpp.

+

Definition at line 2985 of file Offer_test.cpp.

@@ -1703,7 +1703,7 @@ Private Attributes
-

Definition at line 3078 of file Offer_test.cpp.

+

Definition at line 3070 of file Offer_test.cpp.

@@ -1731,7 +1731,7 @@ Private Attributes
-

Definition at line 3386 of file Offer_test.cpp.

+

Definition at line 3378 of file Offer_test.cpp.

@@ -1759,7 +1759,7 @@ Private Attributes
-

Definition at line 3456 of file Offer_test.cpp.

+

Definition at line 3448 of file Offer_test.cpp.

@@ -1787,7 +1787,7 @@ Private Attributes
-

Definition at line 3568 of file Offer_test.cpp.

+

Definition at line 3560 of file Offer_test.cpp.

@@ -1815,7 +1815,7 @@ Private Attributes
-

Definition at line 3576 of file Offer_test.cpp.

+

Definition at line 3568 of file Offer_test.cpp.

@@ -1843,7 +1843,7 @@ Private Attributes
-

Definition at line 3621 of file Offer_test.cpp.

+

Definition at line 3613 of file Offer_test.cpp.

@@ -1871,7 +1871,7 @@ Private Attributes
-

Definition at line 3692 of file Offer_test.cpp.

+

Definition at line 3684 of file Offer_test.cpp.

@@ -1899,7 +1899,7 @@ Private Attributes
-

Definition at line 3745 of file Offer_test.cpp.

+

Definition at line 3737 of file Offer_test.cpp.

@@ -1927,7 +1927,7 @@ Private Attributes
-

Definition at line 3781 of file Offer_test.cpp.

+

Definition at line 3773 of file Offer_test.cpp.

@@ -1955,7 +1955,7 @@ Private Attributes
-

Definition at line 3828 of file Offer_test.cpp.

+

Definition at line 3820 of file Offer_test.cpp.

@@ -1983,7 +1983,7 @@ Private Attributes
-

Definition at line 3880 of file Offer_test.cpp.

+

Definition at line 3872 of file Offer_test.cpp.

@@ -2011,7 +2011,7 @@ Private Attributes
-

Definition at line 3947 of file Offer_test.cpp.

+

Definition at line 3939 of file Offer_test.cpp.

@@ -2039,7 +2039,7 @@ Private Attributes
-

Definition at line 3995 of file Offer_test.cpp.

+

Definition at line 3987 of file Offer_test.cpp.

@@ -2067,7 +2067,7 @@ Private Attributes
-

Definition at line 4150 of file Offer_test.cpp.

+

Definition at line 4142 of file Offer_test.cpp.

@@ -2095,7 +2095,7 @@ Private Attributes
-

Definition at line 4299 of file Offer_test.cpp.

+

Definition at line 4291 of file Offer_test.cpp.

@@ -2123,7 +2123,7 @@ Private Attributes
-

Definition at line 4350 of file Offer_test.cpp.

+

Definition at line 4342 of file Offer_test.cpp.

@@ -2151,7 +2151,7 @@ Private Attributes
-

Definition at line 4471 of file Offer_test.cpp.

+

Definition at line 4463 of file Offer_test.cpp.

@@ -2179,7 +2179,7 @@ Private Attributes
-

Definition at line 4560 of file Offer_test.cpp.

+

Definition at line 4552 of file Offer_test.cpp.

@@ -2207,7 +2207,7 @@ Private Attributes
-

Definition at line 4632 of file Offer_test.cpp.

+

Definition at line 4624 of file Offer_test.cpp.

@@ -2235,7 +2235,7 @@ Private Attributes
-

Definition at line 4739 of file Offer_test.cpp.

+

Definition at line 4731 of file Offer_test.cpp.

@@ -2273,7 +2273,7 @@ Private Attributes
-

Definition at line 4848 of file Offer_test.cpp.

+

Definition at line 4840 of file Offer_test.cpp.

@@ -2301,7 +2301,7 @@ Private Attributes
-

Definition at line 4863 of file Offer_test.cpp.

+

Definition at line 4855 of file Offer_test.cpp.

@@ -2329,7 +2329,7 @@ Private Attributes
-

Definition at line 4983 of file Offer_test.cpp.

+

Definition at line 4975 of file Offer_test.cpp.

@@ -2356,7 +2356,7 @@ Private Attributes
-

Definition at line 5095 of file Offer_test.cpp.

+

Definition at line 5087 of file Offer_test.cpp.

@@ -2384,7 +2384,7 @@ Private Attributes
-

Definition at line 5113 of file Offer_test.cpp.

+

Definition at line 5105 of file Offer_test.cpp.

@@ -2412,7 +2412,7 @@ Private Attributes
-

Definition at line 5301 of file Offer_test.cpp.

+

Definition at line 5293 of file Offer_test.cpp.

@@ -2450,7 +2450,7 @@ Private Attributes
-

Definition at line 5365 of file Offer_test.cpp.

+

Definition at line 5357 of file Offer_test.cpp.

diff --git a/classripple_1_1test_1_1OfferWOPermDEX__test.html b/classripple_1_1test_1_1OfferWOPermDEX__test.html index 9c781ba660..6a15f826ba 100644 --- a/classripple_1_1test_1_1OfferWOPermDEX__test.html +++ b/classripple_1_1test_1_1OfferWOPermDEX__test.html @@ -382,7 +382,7 @@ Private Attributes

Detailed Description

-

Definition at line 5428 of file Offer_test.cpp.

+

Definition at line 5420 of file Offer_test.cpp.

Member Function Documentation

◆ run() [1/2]

@@ -411,7 +411,7 @@ Private Attributes

Reimplemented from ripple::test::OfferBaseUtil_test.

-

Definition at line 5431 of file Offer_test.cpp.

+

Definition at line 5423 of file Offer_test.cpp.

@@ -883,7 +883,7 @@ Private Attributes
-

Definition at line 1068 of file Offer_test.cpp.

+

Definition at line 1061 of file Offer_test.cpp.

@@ -911,7 +911,7 @@ Private Attributes
-

Definition at line 1146 of file Offer_test.cpp.

+

Definition at line 1139 of file Offer_test.cpp.

@@ -939,7 +939,7 @@ Private Attributes
-

Definition at line 1224 of file Offer_test.cpp.

+

Definition at line 1217 of file Offer_test.cpp.

@@ -977,7 +977,7 @@ Private Attributes
-

Definition at line 1284 of file Offer_test.cpp.

+

Definition at line 1277 of file Offer_test.cpp.

@@ -1005,7 +1005,7 @@ Private Attributes
-

Definition at line 1394 of file Offer_test.cpp.

+

Definition at line 1387 of file Offer_test.cpp.

@@ -1043,7 +1043,7 @@ Private Attributes
-

Definition at line 1504 of file Offer_test.cpp.

+

Definition at line 1497 of file Offer_test.cpp.

@@ -1071,7 +1071,7 @@ Private Attributes
-

Definition at line 1559 of file Offer_test.cpp.

+

Definition at line 1552 of file Offer_test.cpp.

@@ -1099,7 +1099,7 @@ Private Attributes
-

Definition at line 1600 of file Offer_test.cpp.

+

Definition at line 1593 of file Offer_test.cpp.

@@ -1127,7 +1127,7 @@ Private Attributes
-

Definition at line 1624 of file Offer_test.cpp.

+

Definition at line 1617 of file Offer_test.cpp.

@@ -1155,7 +1155,7 @@ Private Attributes
-

Definition at line 1650 of file Offer_test.cpp.

+

Definition at line 1643 of file Offer_test.cpp.

@@ -1183,7 +1183,7 @@ Private Attributes
-

Definition at line 1704 of file Offer_test.cpp.

+

Definition at line 1697 of file Offer_test.cpp.

@@ -1211,7 +1211,7 @@ Private Attributes
-

Definition at line 1734 of file Offer_test.cpp.

+

Definition at line 1727 of file Offer_test.cpp.

@@ -1239,7 +1239,7 @@ Private Attributes
-

Definition at line 1820 of file Offer_test.cpp.

+

Definition at line 1813 of file Offer_test.cpp.

@@ -1267,7 +1267,7 @@ Private Attributes
-

Definition at line 1862 of file Offer_test.cpp.

+

Definition at line 1855 of file Offer_test.cpp.

@@ -1295,7 +1295,7 @@ Private Attributes
-

Definition at line 1910 of file Offer_test.cpp.

+

Definition at line 1903 of file Offer_test.cpp.

@@ -1323,7 +1323,7 @@ Private Attributes
-

Definition at line 1976 of file Offer_test.cpp.

+

Definition at line 1969 of file Offer_test.cpp.

@@ -1351,7 +1351,7 @@ Private Attributes
-

Definition at line 2043 of file Offer_test.cpp.

+

Definition at line 2036 of file Offer_test.cpp.

@@ -1379,7 +1379,7 @@ Private Attributes
-

Definition at line 2098 of file Offer_test.cpp.

+

Definition at line 2091 of file Offer_test.cpp.

@@ -1407,7 +1407,7 @@ Private Attributes
-

Definition at line 2154 of file Offer_test.cpp.

+

Definition at line 2147 of file Offer_test.cpp.

@@ -1435,7 +1435,7 @@ Private Attributes
-

Definition at line 2197 of file Offer_test.cpp.

+

Definition at line 2190 of file Offer_test.cpp.

@@ -1463,7 +1463,7 @@ Private Attributes
-

Definition at line 2242 of file Offer_test.cpp.

+

Definition at line 2235 of file Offer_test.cpp.

@@ -1507,7 +1507,7 @@ Private Attributes
-

Definition at line 2320 of file Offer_test.cpp.

+

Definition at line 2313 of file Offer_test.cpp.

@@ -1535,7 +1535,7 @@ Private Attributes
-

Definition at line 2351 of file Offer_test.cpp.

+

Definition at line 2344 of file Offer_test.cpp.

@@ -1563,7 +1563,7 @@ Private Attributes
-

Definition at line 2510 of file Offer_test.cpp.

+

Definition at line 2503 of file Offer_test.cpp.

@@ -1591,7 +1591,7 @@ Private Attributes
-

Definition at line 2587 of file Offer_test.cpp.

+

Definition at line 2580 of file Offer_test.cpp.

@@ -1619,7 +1619,7 @@ Private Attributes
-

Definition at line 2705 of file Offer_test.cpp.

+

Definition at line 2698 of file Offer_test.cpp.

@@ -1647,7 +1647,7 @@ Private Attributes
-

Definition at line 2803 of file Offer_test.cpp.

+

Definition at line 2796 of file Offer_test.cpp.

@@ -1675,7 +1675,7 @@ Private Attributes
-

Definition at line 2992 of file Offer_test.cpp.

+

Definition at line 2985 of file Offer_test.cpp.

@@ -1703,7 +1703,7 @@ Private Attributes
-

Definition at line 3078 of file Offer_test.cpp.

+

Definition at line 3070 of file Offer_test.cpp.

@@ -1731,7 +1731,7 @@ Private Attributes
-

Definition at line 3386 of file Offer_test.cpp.

+

Definition at line 3378 of file Offer_test.cpp.

@@ -1759,7 +1759,7 @@ Private Attributes
-

Definition at line 3456 of file Offer_test.cpp.

+

Definition at line 3448 of file Offer_test.cpp.

@@ -1787,7 +1787,7 @@ Private Attributes
-

Definition at line 3568 of file Offer_test.cpp.

+

Definition at line 3560 of file Offer_test.cpp.

@@ -1815,7 +1815,7 @@ Private Attributes
-

Definition at line 3576 of file Offer_test.cpp.

+

Definition at line 3568 of file Offer_test.cpp.

@@ -1843,7 +1843,7 @@ Private Attributes
-

Definition at line 3621 of file Offer_test.cpp.

+

Definition at line 3613 of file Offer_test.cpp.

@@ -1871,7 +1871,7 @@ Private Attributes
-

Definition at line 3692 of file Offer_test.cpp.

+

Definition at line 3684 of file Offer_test.cpp.

@@ -1899,7 +1899,7 @@ Private Attributes
-

Definition at line 3745 of file Offer_test.cpp.

+

Definition at line 3737 of file Offer_test.cpp.

@@ -1927,7 +1927,7 @@ Private Attributes
-

Definition at line 3781 of file Offer_test.cpp.

+

Definition at line 3773 of file Offer_test.cpp.

@@ -1955,7 +1955,7 @@ Private Attributes
-

Definition at line 3828 of file Offer_test.cpp.

+

Definition at line 3820 of file Offer_test.cpp.

@@ -1983,7 +1983,7 @@ Private Attributes
-

Definition at line 3880 of file Offer_test.cpp.

+

Definition at line 3872 of file Offer_test.cpp.

@@ -2011,7 +2011,7 @@ Private Attributes
-

Definition at line 3947 of file Offer_test.cpp.

+

Definition at line 3939 of file Offer_test.cpp.

@@ -2039,7 +2039,7 @@ Private Attributes
-

Definition at line 3995 of file Offer_test.cpp.

+

Definition at line 3987 of file Offer_test.cpp.

@@ -2067,7 +2067,7 @@ Private Attributes
-

Definition at line 4150 of file Offer_test.cpp.

+

Definition at line 4142 of file Offer_test.cpp.

@@ -2095,7 +2095,7 @@ Private Attributes
-

Definition at line 4299 of file Offer_test.cpp.

+

Definition at line 4291 of file Offer_test.cpp.

@@ -2123,7 +2123,7 @@ Private Attributes
-

Definition at line 4350 of file Offer_test.cpp.

+

Definition at line 4342 of file Offer_test.cpp.

@@ -2151,7 +2151,7 @@ Private Attributes
-

Definition at line 4471 of file Offer_test.cpp.

+

Definition at line 4463 of file Offer_test.cpp.

@@ -2179,7 +2179,7 @@ Private Attributes
-

Definition at line 4560 of file Offer_test.cpp.

+

Definition at line 4552 of file Offer_test.cpp.

@@ -2207,7 +2207,7 @@ Private Attributes
-

Definition at line 4632 of file Offer_test.cpp.

+

Definition at line 4624 of file Offer_test.cpp.

@@ -2235,7 +2235,7 @@ Private Attributes
-

Definition at line 4739 of file Offer_test.cpp.

+

Definition at line 4731 of file Offer_test.cpp.

@@ -2273,7 +2273,7 @@ Private Attributes
-

Definition at line 4848 of file Offer_test.cpp.

+

Definition at line 4840 of file Offer_test.cpp.

@@ -2301,7 +2301,7 @@ Private Attributes
-

Definition at line 4863 of file Offer_test.cpp.

+

Definition at line 4855 of file Offer_test.cpp.

@@ -2329,7 +2329,7 @@ Private Attributes
-

Definition at line 4983 of file Offer_test.cpp.

+

Definition at line 4975 of file Offer_test.cpp.

@@ -2356,7 +2356,7 @@ Private Attributes
-

Definition at line 5095 of file Offer_test.cpp.

+

Definition at line 5087 of file Offer_test.cpp.

@@ -2384,7 +2384,7 @@ Private Attributes
-

Definition at line 5113 of file Offer_test.cpp.

+

Definition at line 5105 of file Offer_test.cpp.

@@ -2412,7 +2412,7 @@ Private Attributes
-

Definition at line 5301 of file Offer_test.cpp.

+

Definition at line 5293 of file Offer_test.cpp.

@@ -2450,7 +2450,7 @@ Private Attributes
-

Definition at line 5365 of file Offer_test.cpp.

+

Definition at line 5357 of file Offer_test.cpp.

diff --git a/classripple_1_1test_1_1OfferWOSmallQOffers__test.html b/classripple_1_1test_1_1OfferWOSmallQOffers__test.html index f37d2dc794..66a7fc1445 100644 --- a/classripple_1_1test_1_1OfferWOSmallQOffers__test.html +++ b/classripple_1_1test_1_1OfferWOSmallQOffers__test.html @@ -382,7 +382,7 @@ Private Attributes

Detailed Description

-

Definition at line 5410 of file Offer_test.cpp.

+

Definition at line 5402 of file Offer_test.cpp.

Member Function Documentation

◆ run() [1/2]

@@ -411,7 +411,7 @@ Private Attributes

Reimplemented from ripple::test::OfferBaseUtil_test.

-

Definition at line 5413 of file Offer_test.cpp.

+

Definition at line 5405 of file Offer_test.cpp.

@@ -883,7 +883,7 @@ Private Attributes
-

Definition at line 1068 of file Offer_test.cpp.

+

Definition at line 1061 of file Offer_test.cpp.

@@ -911,7 +911,7 @@ Private Attributes
-

Definition at line 1146 of file Offer_test.cpp.

+

Definition at line 1139 of file Offer_test.cpp.

@@ -939,7 +939,7 @@ Private Attributes
-

Definition at line 1224 of file Offer_test.cpp.

+

Definition at line 1217 of file Offer_test.cpp.

@@ -977,7 +977,7 @@ Private Attributes
-

Definition at line 1284 of file Offer_test.cpp.

+

Definition at line 1277 of file Offer_test.cpp.

@@ -1005,7 +1005,7 @@ Private Attributes
-

Definition at line 1394 of file Offer_test.cpp.

+

Definition at line 1387 of file Offer_test.cpp.

@@ -1043,7 +1043,7 @@ Private Attributes
-

Definition at line 1504 of file Offer_test.cpp.

+

Definition at line 1497 of file Offer_test.cpp.

@@ -1071,7 +1071,7 @@ Private Attributes
-

Definition at line 1559 of file Offer_test.cpp.

+

Definition at line 1552 of file Offer_test.cpp.

@@ -1099,7 +1099,7 @@ Private Attributes
-

Definition at line 1600 of file Offer_test.cpp.

+

Definition at line 1593 of file Offer_test.cpp.

@@ -1127,7 +1127,7 @@ Private Attributes
-

Definition at line 1624 of file Offer_test.cpp.

+

Definition at line 1617 of file Offer_test.cpp.

@@ -1155,7 +1155,7 @@ Private Attributes
-

Definition at line 1650 of file Offer_test.cpp.

+

Definition at line 1643 of file Offer_test.cpp.

@@ -1183,7 +1183,7 @@ Private Attributes
-

Definition at line 1704 of file Offer_test.cpp.

+

Definition at line 1697 of file Offer_test.cpp.

@@ -1211,7 +1211,7 @@ Private Attributes
-

Definition at line 1734 of file Offer_test.cpp.

+

Definition at line 1727 of file Offer_test.cpp.

@@ -1239,7 +1239,7 @@ Private Attributes
-

Definition at line 1820 of file Offer_test.cpp.

+

Definition at line 1813 of file Offer_test.cpp.

@@ -1267,7 +1267,7 @@ Private Attributes
-

Definition at line 1862 of file Offer_test.cpp.

+

Definition at line 1855 of file Offer_test.cpp.

@@ -1295,7 +1295,7 @@ Private Attributes
-

Definition at line 1910 of file Offer_test.cpp.

+

Definition at line 1903 of file Offer_test.cpp.

@@ -1323,7 +1323,7 @@ Private Attributes
-

Definition at line 1976 of file Offer_test.cpp.

+

Definition at line 1969 of file Offer_test.cpp.

@@ -1351,7 +1351,7 @@ Private Attributes
-

Definition at line 2043 of file Offer_test.cpp.

+

Definition at line 2036 of file Offer_test.cpp.

@@ -1379,7 +1379,7 @@ Private Attributes
-

Definition at line 2098 of file Offer_test.cpp.

+

Definition at line 2091 of file Offer_test.cpp.

@@ -1407,7 +1407,7 @@ Private Attributes
-

Definition at line 2154 of file Offer_test.cpp.

+

Definition at line 2147 of file Offer_test.cpp.

@@ -1435,7 +1435,7 @@ Private Attributes
-

Definition at line 2197 of file Offer_test.cpp.

+

Definition at line 2190 of file Offer_test.cpp.

@@ -1463,7 +1463,7 @@ Private Attributes
-

Definition at line 2242 of file Offer_test.cpp.

+

Definition at line 2235 of file Offer_test.cpp.

@@ -1507,7 +1507,7 @@ Private Attributes
-

Definition at line 2320 of file Offer_test.cpp.

+

Definition at line 2313 of file Offer_test.cpp.

@@ -1535,7 +1535,7 @@ Private Attributes
-

Definition at line 2351 of file Offer_test.cpp.

+

Definition at line 2344 of file Offer_test.cpp.

@@ -1563,7 +1563,7 @@ Private Attributes
-

Definition at line 2510 of file Offer_test.cpp.

+

Definition at line 2503 of file Offer_test.cpp.

@@ -1591,7 +1591,7 @@ Private Attributes
-

Definition at line 2587 of file Offer_test.cpp.

+

Definition at line 2580 of file Offer_test.cpp.

@@ -1619,7 +1619,7 @@ Private Attributes
-

Definition at line 2705 of file Offer_test.cpp.

+

Definition at line 2698 of file Offer_test.cpp.

@@ -1647,7 +1647,7 @@ Private Attributes
-

Definition at line 2803 of file Offer_test.cpp.

+

Definition at line 2796 of file Offer_test.cpp.

@@ -1675,7 +1675,7 @@ Private Attributes
-

Definition at line 2992 of file Offer_test.cpp.

+

Definition at line 2985 of file Offer_test.cpp.

@@ -1703,7 +1703,7 @@ Private Attributes
-

Definition at line 3078 of file Offer_test.cpp.

+

Definition at line 3070 of file Offer_test.cpp.

@@ -1731,7 +1731,7 @@ Private Attributes
-

Definition at line 3386 of file Offer_test.cpp.

+

Definition at line 3378 of file Offer_test.cpp.

@@ -1759,7 +1759,7 @@ Private Attributes
-

Definition at line 3456 of file Offer_test.cpp.

+

Definition at line 3448 of file Offer_test.cpp.

@@ -1787,7 +1787,7 @@ Private Attributes
-

Definition at line 3568 of file Offer_test.cpp.

+

Definition at line 3560 of file Offer_test.cpp.

@@ -1815,7 +1815,7 @@ Private Attributes
-

Definition at line 3576 of file Offer_test.cpp.

+

Definition at line 3568 of file Offer_test.cpp.

@@ -1843,7 +1843,7 @@ Private Attributes
-

Definition at line 3621 of file Offer_test.cpp.

+

Definition at line 3613 of file Offer_test.cpp.

@@ -1871,7 +1871,7 @@ Private Attributes
-

Definition at line 3692 of file Offer_test.cpp.

+

Definition at line 3684 of file Offer_test.cpp.

@@ -1899,7 +1899,7 @@ Private Attributes
-

Definition at line 3745 of file Offer_test.cpp.

+

Definition at line 3737 of file Offer_test.cpp.

@@ -1927,7 +1927,7 @@ Private Attributes
-

Definition at line 3781 of file Offer_test.cpp.

+

Definition at line 3773 of file Offer_test.cpp.

@@ -1955,7 +1955,7 @@ Private Attributes
-

Definition at line 3828 of file Offer_test.cpp.

+

Definition at line 3820 of file Offer_test.cpp.

@@ -1983,7 +1983,7 @@ Private Attributes
-

Definition at line 3880 of file Offer_test.cpp.

+

Definition at line 3872 of file Offer_test.cpp.

@@ -2011,7 +2011,7 @@ Private Attributes
-

Definition at line 3947 of file Offer_test.cpp.

+

Definition at line 3939 of file Offer_test.cpp.

@@ -2039,7 +2039,7 @@ Private Attributes
-

Definition at line 3995 of file Offer_test.cpp.

+

Definition at line 3987 of file Offer_test.cpp.

@@ -2067,7 +2067,7 @@ Private Attributes
-

Definition at line 4150 of file Offer_test.cpp.

+

Definition at line 4142 of file Offer_test.cpp.

@@ -2095,7 +2095,7 @@ Private Attributes
-

Definition at line 4299 of file Offer_test.cpp.

+

Definition at line 4291 of file Offer_test.cpp.

@@ -2123,7 +2123,7 @@ Private Attributes
-

Definition at line 4350 of file Offer_test.cpp.

+

Definition at line 4342 of file Offer_test.cpp.

@@ -2151,7 +2151,7 @@ Private Attributes
-

Definition at line 4471 of file Offer_test.cpp.

+

Definition at line 4463 of file Offer_test.cpp.

@@ -2179,7 +2179,7 @@ Private Attributes
-

Definition at line 4560 of file Offer_test.cpp.

+

Definition at line 4552 of file Offer_test.cpp.

@@ -2207,7 +2207,7 @@ Private Attributes
-

Definition at line 4632 of file Offer_test.cpp.

+

Definition at line 4624 of file Offer_test.cpp.

@@ -2235,7 +2235,7 @@ Private Attributes
-

Definition at line 4739 of file Offer_test.cpp.

+

Definition at line 4731 of file Offer_test.cpp.

@@ -2273,7 +2273,7 @@ Private Attributes
-

Definition at line 4848 of file Offer_test.cpp.

+

Definition at line 4840 of file Offer_test.cpp.

@@ -2301,7 +2301,7 @@ Private Attributes
-

Definition at line 4863 of file Offer_test.cpp.

+

Definition at line 4855 of file Offer_test.cpp.

@@ -2329,7 +2329,7 @@ Private Attributes
-

Definition at line 4983 of file Offer_test.cpp.

+

Definition at line 4975 of file Offer_test.cpp.

@@ -2356,7 +2356,7 @@ Private Attributes
-

Definition at line 5095 of file Offer_test.cpp.

+

Definition at line 5087 of file Offer_test.cpp.

@@ -2384,7 +2384,7 @@ Private Attributes
-

Definition at line 5113 of file Offer_test.cpp.

+

Definition at line 5105 of file Offer_test.cpp.

@@ -2412,7 +2412,7 @@ Private Attributes
-

Definition at line 5301 of file Offer_test.cpp.

+

Definition at line 5293 of file Offer_test.cpp.

@@ -2450,7 +2450,7 @@ Private Attributes
-

Definition at line 5365 of file Offer_test.cpp.

+

Definition at line 5357 of file Offer_test.cpp.

diff --git a/classripple_1_1test_1_1OfferWTakerDryOffer__test.html b/classripple_1_1test_1_1OfferWTakerDryOffer__test.html index 420f10ed40..9eecbada40 100644 --- a/classripple_1_1test_1_1OfferWTakerDryOffer__test.html +++ b/classripple_1_1test_1_1OfferWTakerDryOffer__test.html @@ -382,7 +382,7 @@ Private Attributes

Detailed Description

-

Definition at line 5401 of file Offer_test.cpp.

+

Definition at line 5393 of file Offer_test.cpp.

Member Function Documentation

◆ run() [1/2]

@@ -411,7 +411,7 @@ Private Attributes

Reimplemented from ripple::test::OfferBaseUtil_test.

-

Definition at line 5404 of file Offer_test.cpp.

+

Definition at line 5396 of file Offer_test.cpp.

@@ -883,7 +883,7 @@ Private Attributes
-

Definition at line 1068 of file Offer_test.cpp.

+

Definition at line 1061 of file Offer_test.cpp.

@@ -911,7 +911,7 @@ Private Attributes
-

Definition at line 1146 of file Offer_test.cpp.

+

Definition at line 1139 of file Offer_test.cpp.

@@ -939,7 +939,7 @@ Private Attributes
-

Definition at line 1224 of file Offer_test.cpp.

+

Definition at line 1217 of file Offer_test.cpp.

@@ -977,7 +977,7 @@ Private Attributes
-

Definition at line 1284 of file Offer_test.cpp.

+

Definition at line 1277 of file Offer_test.cpp.

@@ -1005,7 +1005,7 @@ Private Attributes
-

Definition at line 1394 of file Offer_test.cpp.

+

Definition at line 1387 of file Offer_test.cpp.

@@ -1043,7 +1043,7 @@ Private Attributes
-

Definition at line 1504 of file Offer_test.cpp.

+

Definition at line 1497 of file Offer_test.cpp.

@@ -1071,7 +1071,7 @@ Private Attributes
-

Definition at line 1559 of file Offer_test.cpp.

+

Definition at line 1552 of file Offer_test.cpp.

@@ -1099,7 +1099,7 @@ Private Attributes
-

Definition at line 1600 of file Offer_test.cpp.

+

Definition at line 1593 of file Offer_test.cpp.

@@ -1127,7 +1127,7 @@ Private Attributes
-

Definition at line 1624 of file Offer_test.cpp.

+

Definition at line 1617 of file Offer_test.cpp.

@@ -1155,7 +1155,7 @@ Private Attributes
-

Definition at line 1650 of file Offer_test.cpp.

+

Definition at line 1643 of file Offer_test.cpp.

@@ -1183,7 +1183,7 @@ Private Attributes
-

Definition at line 1704 of file Offer_test.cpp.

+

Definition at line 1697 of file Offer_test.cpp.

@@ -1211,7 +1211,7 @@ Private Attributes
-

Definition at line 1734 of file Offer_test.cpp.

+

Definition at line 1727 of file Offer_test.cpp.

@@ -1239,7 +1239,7 @@ Private Attributes
-

Definition at line 1820 of file Offer_test.cpp.

+

Definition at line 1813 of file Offer_test.cpp.

@@ -1267,7 +1267,7 @@ Private Attributes
-

Definition at line 1862 of file Offer_test.cpp.

+

Definition at line 1855 of file Offer_test.cpp.

@@ -1295,7 +1295,7 @@ Private Attributes
-

Definition at line 1910 of file Offer_test.cpp.

+

Definition at line 1903 of file Offer_test.cpp.

@@ -1323,7 +1323,7 @@ Private Attributes
-

Definition at line 1976 of file Offer_test.cpp.

+

Definition at line 1969 of file Offer_test.cpp.

@@ -1351,7 +1351,7 @@ Private Attributes
-

Definition at line 2043 of file Offer_test.cpp.

+

Definition at line 2036 of file Offer_test.cpp.

@@ -1379,7 +1379,7 @@ Private Attributes
-

Definition at line 2098 of file Offer_test.cpp.

+

Definition at line 2091 of file Offer_test.cpp.

@@ -1407,7 +1407,7 @@ Private Attributes
-

Definition at line 2154 of file Offer_test.cpp.

+

Definition at line 2147 of file Offer_test.cpp.

@@ -1435,7 +1435,7 @@ Private Attributes
-

Definition at line 2197 of file Offer_test.cpp.

+

Definition at line 2190 of file Offer_test.cpp.

@@ -1463,7 +1463,7 @@ Private Attributes
-

Definition at line 2242 of file Offer_test.cpp.

+

Definition at line 2235 of file Offer_test.cpp.

@@ -1507,7 +1507,7 @@ Private Attributes
-

Definition at line 2320 of file Offer_test.cpp.

+

Definition at line 2313 of file Offer_test.cpp.

@@ -1535,7 +1535,7 @@ Private Attributes
-

Definition at line 2351 of file Offer_test.cpp.

+

Definition at line 2344 of file Offer_test.cpp.

@@ -1563,7 +1563,7 @@ Private Attributes
-

Definition at line 2510 of file Offer_test.cpp.

+

Definition at line 2503 of file Offer_test.cpp.

@@ -1591,7 +1591,7 @@ Private Attributes
-

Definition at line 2587 of file Offer_test.cpp.

+

Definition at line 2580 of file Offer_test.cpp.

@@ -1619,7 +1619,7 @@ Private Attributes
-

Definition at line 2705 of file Offer_test.cpp.

+

Definition at line 2698 of file Offer_test.cpp.

@@ -1647,7 +1647,7 @@ Private Attributes
-

Definition at line 2803 of file Offer_test.cpp.

+

Definition at line 2796 of file Offer_test.cpp.

@@ -1675,7 +1675,7 @@ Private Attributes
-

Definition at line 2992 of file Offer_test.cpp.

+

Definition at line 2985 of file Offer_test.cpp.

@@ -1703,7 +1703,7 @@ Private Attributes
-

Definition at line 3078 of file Offer_test.cpp.

+

Definition at line 3070 of file Offer_test.cpp.

@@ -1731,7 +1731,7 @@ Private Attributes
-

Definition at line 3386 of file Offer_test.cpp.

+

Definition at line 3378 of file Offer_test.cpp.

@@ -1759,7 +1759,7 @@ Private Attributes
-

Definition at line 3456 of file Offer_test.cpp.

+

Definition at line 3448 of file Offer_test.cpp.

@@ -1787,7 +1787,7 @@ Private Attributes
-

Definition at line 3568 of file Offer_test.cpp.

+

Definition at line 3560 of file Offer_test.cpp.

@@ -1815,7 +1815,7 @@ Private Attributes
-

Definition at line 3576 of file Offer_test.cpp.

+

Definition at line 3568 of file Offer_test.cpp.

@@ -1843,7 +1843,7 @@ Private Attributes
-

Definition at line 3621 of file Offer_test.cpp.

+

Definition at line 3613 of file Offer_test.cpp.

@@ -1871,7 +1871,7 @@ Private Attributes
-

Definition at line 3692 of file Offer_test.cpp.

+

Definition at line 3684 of file Offer_test.cpp.

@@ -1899,7 +1899,7 @@ Private Attributes
-

Definition at line 3745 of file Offer_test.cpp.

+

Definition at line 3737 of file Offer_test.cpp.

@@ -1927,7 +1927,7 @@ Private Attributes
-

Definition at line 3781 of file Offer_test.cpp.

+

Definition at line 3773 of file Offer_test.cpp.

@@ -1955,7 +1955,7 @@ Private Attributes
-

Definition at line 3828 of file Offer_test.cpp.

+

Definition at line 3820 of file Offer_test.cpp.

@@ -1983,7 +1983,7 @@ Private Attributes
-

Definition at line 3880 of file Offer_test.cpp.

+

Definition at line 3872 of file Offer_test.cpp.

@@ -2011,7 +2011,7 @@ Private Attributes
-

Definition at line 3947 of file Offer_test.cpp.

+

Definition at line 3939 of file Offer_test.cpp.

@@ -2039,7 +2039,7 @@ Private Attributes
-

Definition at line 3995 of file Offer_test.cpp.

+

Definition at line 3987 of file Offer_test.cpp.

@@ -2067,7 +2067,7 @@ Private Attributes
-

Definition at line 4150 of file Offer_test.cpp.

+

Definition at line 4142 of file Offer_test.cpp.

@@ -2095,7 +2095,7 @@ Private Attributes
-

Definition at line 4299 of file Offer_test.cpp.

+

Definition at line 4291 of file Offer_test.cpp.

@@ -2123,7 +2123,7 @@ Private Attributes
-

Definition at line 4350 of file Offer_test.cpp.

+

Definition at line 4342 of file Offer_test.cpp.

@@ -2151,7 +2151,7 @@ Private Attributes
-

Definition at line 4471 of file Offer_test.cpp.

+

Definition at line 4463 of file Offer_test.cpp.

@@ -2179,7 +2179,7 @@ Private Attributes
-

Definition at line 4560 of file Offer_test.cpp.

+

Definition at line 4552 of file Offer_test.cpp.

@@ -2207,7 +2207,7 @@ Private Attributes
-

Definition at line 4632 of file Offer_test.cpp.

+

Definition at line 4624 of file Offer_test.cpp.

@@ -2235,7 +2235,7 @@ Private Attributes
-

Definition at line 4739 of file Offer_test.cpp.

+

Definition at line 4731 of file Offer_test.cpp.

@@ -2273,7 +2273,7 @@ Private Attributes
-

Definition at line 4848 of file Offer_test.cpp.

+

Definition at line 4840 of file Offer_test.cpp.

@@ -2301,7 +2301,7 @@ Private Attributes
-

Definition at line 4863 of file Offer_test.cpp.

+

Definition at line 4855 of file Offer_test.cpp.

@@ -2329,7 +2329,7 @@ Private Attributes
-

Definition at line 4983 of file Offer_test.cpp.

+

Definition at line 4975 of file Offer_test.cpp.

@@ -2356,7 +2356,7 @@ Private Attributes
-

Definition at line 5095 of file Offer_test.cpp.

+

Definition at line 5087 of file Offer_test.cpp.

@@ -2384,7 +2384,7 @@ Private Attributes
-

Definition at line 5113 of file Offer_test.cpp.

+

Definition at line 5105 of file Offer_test.cpp.

@@ -2412,7 +2412,7 @@ Private Attributes
-

Definition at line 5301 of file Offer_test.cpp.

+

Definition at line 5293 of file Offer_test.cpp.

@@ -2450,7 +2450,7 @@ Private Attributes
-

Definition at line 5365 of file Offer_test.cpp.

+

Definition at line 5357 of file Offer_test.cpp.

diff --git a/classripple_1_1test_1_1Offer__manual__test.html b/classripple_1_1test_1_1Offer__manual__test.html index e35b67854a..a062a4913f 100644 --- a/classripple_1_1test_1_1Offer__manual__test.html +++ b/classripple_1_1test_1_1Offer__manual__test.html @@ -382,7 +382,7 @@ Private Attributes

Detailed Description

-

Definition at line 5446 of file Offer_test.cpp.

+

Definition at line 5438 of file Offer_test.cpp.

Member Function Documentation

◆ run() [1/2]

@@ -411,7 +411,7 @@ Private Attributes

Implements beast::unit_test::suite.

-

Definition at line 5449 of file Offer_test.cpp.

+

Definition at line 5441 of file Offer_test.cpp.

@@ -883,7 +883,7 @@ Private Attributes
-

Definition at line 1068 of file Offer_test.cpp.

+

Definition at line 1061 of file Offer_test.cpp.

@@ -911,7 +911,7 @@ Private Attributes
-

Definition at line 1146 of file Offer_test.cpp.

+

Definition at line 1139 of file Offer_test.cpp.

@@ -939,7 +939,7 @@ Private Attributes
-

Definition at line 1224 of file Offer_test.cpp.

+

Definition at line 1217 of file Offer_test.cpp.

@@ -977,7 +977,7 @@ Private Attributes
-

Definition at line 1284 of file Offer_test.cpp.

+

Definition at line 1277 of file Offer_test.cpp.

@@ -1005,7 +1005,7 @@ Private Attributes
-

Definition at line 1394 of file Offer_test.cpp.

+

Definition at line 1387 of file Offer_test.cpp.

@@ -1043,7 +1043,7 @@ Private Attributes
-

Definition at line 1504 of file Offer_test.cpp.

+

Definition at line 1497 of file Offer_test.cpp.

@@ -1071,7 +1071,7 @@ Private Attributes
-

Definition at line 1559 of file Offer_test.cpp.

+

Definition at line 1552 of file Offer_test.cpp.

@@ -1099,7 +1099,7 @@ Private Attributes
-

Definition at line 1600 of file Offer_test.cpp.

+

Definition at line 1593 of file Offer_test.cpp.

@@ -1127,7 +1127,7 @@ Private Attributes
-

Definition at line 1624 of file Offer_test.cpp.

+

Definition at line 1617 of file Offer_test.cpp.

@@ -1155,7 +1155,7 @@ Private Attributes
-

Definition at line 1650 of file Offer_test.cpp.

+

Definition at line 1643 of file Offer_test.cpp.

@@ -1183,7 +1183,7 @@ Private Attributes
-

Definition at line 1704 of file Offer_test.cpp.

+

Definition at line 1697 of file Offer_test.cpp.

@@ -1211,7 +1211,7 @@ Private Attributes
-

Definition at line 1734 of file Offer_test.cpp.

+

Definition at line 1727 of file Offer_test.cpp.

@@ -1239,7 +1239,7 @@ Private Attributes
-

Definition at line 1820 of file Offer_test.cpp.

+

Definition at line 1813 of file Offer_test.cpp.

@@ -1267,7 +1267,7 @@ Private Attributes
-

Definition at line 1862 of file Offer_test.cpp.

+

Definition at line 1855 of file Offer_test.cpp.

@@ -1295,7 +1295,7 @@ Private Attributes
-

Definition at line 1910 of file Offer_test.cpp.

+

Definition at line 1903 of file Offer_test.cpp.

@@ -1323,7 +1323,7 @@ Private Attributes
-

Definition at line 1976 of file Offer_test.cpp.

+

Definition at line 1969 of file Offer_test.cpp.

@@ -1351,7 +1351,7 @@ Private Attributes
-

Definition at line 2043 of file Offer_test.cpp.

+

Definition at line 2036 of file Offer_test.cpp.

@@ -1379,7 +1379,7 @@ Private Attributes
-

Definition at line 2098 of file Offer_test.cpp.

+

Definition at line 2091 of file Offer_test.cpp.

@@ -1407,7 +1407,7 @@ Private Attributes
-

Definition at line 2154 of file Offer_test.cpp.

+

Definition at line 2147 of file Offer_test.cpp.

@@ -1435,7 +1435,7 @@ Private Attributes
-

Definition at line 2197 of file Offer_test.cpp.

+

Definition at line 2190 of file Offer_test.cpp.

@@ -1463,7 +1463,7 @@ Private Attributes
-

Definition at line 2242 of file Offer_test.cpp.

+

Definition at line 2235 of file Offer_test.cpp.

@@ -1507,7 +1507,7 @@ Private Attributes
-

Definition at line 2320 of file Offer_test.cpp.

+

Definition at line 2313 of file Offer_test.cpp.

@@ -1535,7 +1535,7 @@ Private Attributes
-

Definition at line 2351 of file Offer_test.cpp.

+

Definition at line 2344 of file Offer_test.cpp.

@@ -1563,7 +1563,7 @@ Private Attributes
-

Definition at line 2510 of file Offer_test.cpp.

+

Definition at line 2503 of file Offer_test.cpp.

@@ -1591,7 +1591,7 @@ Private Attributes
-

Definition at line 2587 of file Offer_test.cpp.

+

Definition at line 2580 of file Offer_test.cpp.

@@ -1619,7 +1619,7 @@ Private Attributes
-

Definition at line 2705 of file Offer_test.cpp.

+

Definition at line 2698 of file Offer_test.cpp.

@@ -1647,7 +1647,7 @@ Private Attributes
-

Definition at line 2803 of file Offer_test.cpp.

+

Definition at line 2796 of file Offer_test.cpp.

@@ -1675,7 +1675,7 @@ Private Attributes
-

Definition at line 2992 of file Offer_test.cpp.

+

Definition at line 2985 of file Offer_test.cpp.

@@ -1703,7 +1703,7 @@ Private Attributes
-

Definition at line 3078 of file Offer_test.cpp.

+

Definition at line 3070 of file Offer_test.cpp.

@@ -1731,7 +1731,7 @@ Private Attributes
-

Definition at line 3386 of file Offer_test.cpp.

+

Definition at line 3378 of file Offer_test.cpp.

@@ -1759,7 +1759,7 @@ Private Attributes
-

Definition at line 3456 of file Offer_test.cpp.

+

Definition at line 3448 of file Offer_test.cpp.

@@ -1787,7 +1787,7 @@ Private Attributes
-

Definition at line 3568 of file Offer_test.cpp.

+

Definition at line 3560 of file Offer_test.cpp.

@@ -1815,7 +1815,7 @@ Private Attributes
-

Definition at line 3576 of file Offer_test.cpp.

+

Definition at line 3568 of file Offer_test.cpp.

@@ -1843,7 +1843,7 @@ Private Attributes
-

Definition at line 3621 of file Offer_test.cpp.

+

Definition at line 3613 of file Offer_test.cpp.

@@ -1871,7 +1871,7 @@ Private Attributes
-

Definition at line 3692 of file Offer_test.cpp.

+

Definition at line 3684 of file Offer_test.cpp.

@@ -1899,7 +1899,7 @@ Private Attributes
-

Definition at line 3745 of file Offer_test.cpp.

+

Definition at line 3737 of file Offer_test.cpp.

@@ -1927,7 +1927,7 @@ Private Attributes
-

Definition at line 3781 of file Offer_test.cpp.

+

Definition at line 3773 of file Offer_test.cpp.

@@ -1955,7 +1955,7 @@ Private Attributes
-

Definition at line 3828 of file Offer_test.cpp.

+

Definition at line 3820 of file Offer_test.cpp.

@@ -1983,7 +1983,7 @@ Private Attributes
-

Definition at line 3880 of file Offer_test.cpp.

+

Definition at line 3872 of file Offer_test.cpp.

@@ -2011,7 +2011,7 @@ Private Attributes
-

Definition at line 3947 of file Offer_test.cpp.

+

Definition at line 3939 of file Offer_test.cpp.

@@ -2039,7 +2039,7 @@ Private Attributes
-

Definition at line 3995 of file Offer_test.cpp.

+

Definition at line 3987 of file Offer_test.cpp.

@@ -2067,7 +2067,7 @@ Private Attributes
-

Definition at line 4150 of file Offer_test.cpp.

+

Definition at line 4142 of file Offer_test.cpp.

@@ -2095,7 +2095,7 @@ Private Attributes
-

Definition at line 4299 of file Offer_test.cpp.

+

Definition at line 4291 of file Offer_test.cpp.

@@ -2123,7 +2123,7 @@ Private Attributes
-

Definition at line 4350 of file Offer_test.cpp.

+

Definition at line 4342 of file Offer_test.cpp.

@@ -2151,7 +2151,7 @@ Private Attributes
-

Definition at line 4471 of file Offer_test.cpp.

+

Definition at line 4463 of file Offer_test.cpp.

@@ -2179,7 +2179,7 @@ Private Attributes
-

Definition at line 4560 of file Offer_test.cpp.

+

Definition at line 4552 of file Offer_test.cpp.

@@ -2207,7 +2207,7 @@ Private Attributes
-

Definition at line 4632 of file Offer_test.cpp.

+

Definition at line 4624 of file Offer_test.cpp.

@@ -2235,7 +2235,7 @@ Private Attributes
-

Definition at line 4739 of file Offer_test.cpp.

+

Definition at line 4731 of file Offer_test.cpp.

@@ -2273,7 +2273,7 @@ Private Attributes
-

Definition at line 4848 of file Offer_test.cpp.

+

Definition at line 4840 of file Offer_test.cpp.

@@ -2301,7 +2301,7 @@ Private Attributes
-

Definition at line 4863 of file Offer_test.cpp.

+

Definition at line 4855 of file Offer_test.cpp.

@@ -2329,7 +2329,7 @@ Private Attributes
-

Definition at line 4983 of file Offer_test.cpp.

+

Definition at line 4975 of file Offer_test.cpp.

@@ -2356,7 +2356,7 @@ Private Attributes
-

Definition at line 5095 of file Offer_test.cpp.

+

Definition at line 5087 of file Offer_test.cpp.

@@ -2384,7 +2384,7 @@ Private Attributes
-

Definition at line 5113 of file Offer_test.cpp.

+

Definition at line 5105 of file Offer_test.cpp.

@@ -2412,7 +2412,7 @@ Private Attributes
-

Definition at line 5301 of file Offer_test.cpp.

+

Definition at line 5293 of file Offer_test.cpp.

@@ -2450,7 +2450,7 @@ Private Attributes
-

Definition at line 5365 of file Offer_test.cpp.

+

Definition at line 5357 of file Offer_test.cpp.

diff --git a/structripple_1_1test_1_1AMMExtended__test.html b/structripple_1_1test_1_1AMMExtended__test.html index 72fb76214f..a14f7efcd9 100644 --- a/structripple_1_1test_1_1AMMExtended__test.html +++ b/structripple_1_1test_1_1AMMExtended__test.html @@ -547,7 +547,7 @@ Private Attributes
-

Definition at line 307 of file AMMExtended_test.cpp.

+

Definition at line 298 of file AMMExtended_test.cpp.

@@ -575,7 +575,7 @@ Private Attributes
-

Definition at line 337 of file AMMExtended_test.cpp.

+

Definition at line 328 of file AMMExtended_test.cpp.

@@ -603,7 +603,7 @@ Private Attributes
-

Definition at line 369 of file AMMExtended_test.cpp.

+

Definition at line 360 of file AMMExtended_test.cpp.

@@ -631,7 +631,7 @@ Private Attributes
-

Definition at line 403 of file AMMExtended_test.cpp.

+

Definition at line 394 of file AMMExtended_test.cpp.

@@ -659,7 +659,7 @@ Private Attributes
-

Definition at line 441 of file AMMExtended_test.cpp.

+

Definition at line 432 of file AMMExtended_test.cpp.

@@ -687,7 +687,7 @@ Private Attributes
-

Definition at line 465 of file AMMExtended_test.cpp.

+

Definition at line 456 of file AMMExtended_test.cpp.

@@ -715,7 +715,7 @@ Private Attributes
-

Definition at line 490 of file AMMExtended_test.cpp.

+

Definition at line 481 of file AMMExtended_test.cpp.

@@ -743,7 +743,7 @@ Private Attributes
-

Definition at line 540 of file AMMExtended_test.cpp.

+

Definition at line 531 of file AMMExtended_test.cpp.

@@ -771,7 +771,7 @@ Private Attributes
-

Definition at line 601 of file AMMExtended_test.cpp.

+

Definition at line 592 of file AMMExtended_test.cpp.

@@ -799,7 +799,7 @@ Private Attributes
-

Definition at line 632 of file AMMExtended_test.cpp.

+

Definition at line 623 of file AMMExtended_test.cpp.

@@ -827,7 +827,7 @@ Private Attributes
-

Definition at line 656 of file AMMExtended_test.cpp.

+

Definition at line 647 of file AMMExtended_test.cpp.

@@ -855,7 +855,7 @@ Private Attributes
-

Definition at line 691 of file AMMExtended_test.cpp.

+

Definition at line 682 of file AMMExtended_test.cpp.

@@ -883,7 +883,7 @@ Private Attributes
-

Definition at line 752 of file AMMExtended_test.cpp.

+

Definition at line 743 of file AMMExtended_test.cpp.

@@ -911,7 +911,7 @@ Private Attributes
-

Definition at line 861 of file AMMExtended_test.cpp.

+

Definition at line 852 of file AMMExtended_test.cpp.

@@ -939,7 +939,7 @@ Private Attributes
-

Definition at line 938 of file AMMExtended_test.cpp.

+

Definition at line 928 of file AMMExtended_test.cpp.

@@ -967,7 +967,7 @@ Private Attributes
-

Definition at line 1151 of file AMMExtended_test.cpp.

+

Definition at line 1141 of file AMMExtended_test.cpp.

@@ -995,7 +995,7 @@ Private Attributes
-

Definition at line 1177 of file AMMExtended_test.cpp.

+

Definition at line 1167 of file AMMExtended_test.cpp.

@@ -1023,7 +1023,7 @@ Private Attributes
-

Definition at line 1247 of file AMMExtended_test.cpp.

+

Definition at line 1237 of file AMMExtended_test.cpp.

@@ -1051,7 +1051,7 @@ Private Attributes
-

Definition at line 1330 of file AMMExtended_test.cpp.

+

Definition at line 1320 of file AMMExtended_test.cpp.

@@ -1079,7 +1079,7 @@ Private Attributes
-

Definition at line 1379 of file AMMExtended_test.cpp.

+

Definition at line 1369 of file AMMExtended_test.cpp.

@@ -1106,7 +1106,7 @@ Private Attributes
-

Definition at line 1447 of file AMMExtended_test.cpp.

+

Definition at line 1437 of file AMMExtended_test.cpp.

@@ -1133,7 +1133,7 @@ Private Attributes
-

Definition at line 1480 of file AMMExtended_test.cpp.

+

Definition at line 1470 of file AMMExtended_test.cpp.

@@ -1160,7 +1160,7 @@ Private Attributes
-

Definition at line 1519 of file AMMExtended_test.cpp.

+

Definition at line 1509 of file AMMExtended_test.cpp.

@@ -1187,7 +1187,7 @@ Private Attributes
-

Definition at line 1546 of file AMMExtended_test.cpp.

+

Definition at line 1536 of file AMMExtended_test.cpp.

@@ -1214,7 +1214,7 @@ Private Attributes
-

Definition at line 1590 of file AMMExtended_test.cpp.

+

Definition at line 1580 of file AMMExtended_test.cpp.

@@ -1241,7 +1241,7 @@ Private Attributes
-

Definition at line 1679 of file AMMExtended_test.cpp.

+

Definition at line 1669 of file AMMExtended_test.cpp.

@@ -1268,7 +1268,7 @@ Private Attributes
-

Definition at line 1716 of file AMMExtended_test.cpp.

+

Definition at line 1706 of file AMMExtended_test.cpp.

@@ -1295,7 +1295,7 @@ Private Attributes
-

Definition at line 1846 of file AMMExtended_test.cpp.

+

Definition at line 1836 of file AMMExtended_test.cpp.

@@ -1323,7 +1323,7 @@ Private Attributes
-

Definition at line 1890 of file AMMExtended_test.cpp.

+

Definition at line 1880 of file AMMExtended_test.cpp.

@@ -1351,7 +1351,7 @@ Private Attributes
-

Definition at line 1931 of file AMMExtended_test.cpp.

+

Definition at line 1921 of file AMMExtended_test.cpp.

@@ -1381,7 +1381,7 @@ Private Attributes

25% on 56.3368EUR is paid in tr fee 56.3368*1.25 = 70.4210EUR

25% on 56.3368EUR is paid in tr fee 56.3368*1.25 = 70.4210EUR

-

Definition at line 2219 of file AMMExtended_test.cpp.

+

Definition at line 2209 of file AMMExtended_test.cpp.

@@ -1408,7 +1408,7 @@ Private Attributes
-

Definition at line 2787 of file AMMExtended_test.cpp.

+

Definition at line 2777 of file AMMExtended_test.cpp.

@@ -1435,7 +1435,7 @@ Private Attributes
-

Definition at line 2817 of file AMMExtended_test.cpp.

+

Definition at line 2807 of file AMMExtended_test.cpp.

@@ -1463,7 +1463,7 @@ Private Attributes
-

Definition at line 2896 of file AMMExtended_test.cpp.

+

Definition at line 2886 of file AMMExtended_test.cpp.

@@ -1491,7 +1491,7 @@ Private Attributes
-

Definition at line 2943 of file AMMExtended_test.cpp.

+

Definition at line 2933 of file AMMExtended_test.cpp.

@@ -1519,7 +1519,7 @@ Private Attributes
-

Definition at line 3064 of file AMMExtended_test.cpp.

+

Definition at line 3054 of file AMMExtended_test.cpp.

@@ -1546,7 +1546,7 @@ Private Attributes
-

Definition at line 3114 of file AMMExtended_test.cpp.

+

Definition at line 3104 of file AMMExtended_test.cpp.

@@ -1574,7 +1574,7 @@ Private Attributes
-

Definition at line 3208 of file AMMExtended_test.cpp.

+

Definition at line 3198 of file AMMExtended_test.cpp.

@@ -1602,7 +1602,7 @@ Private Attributes
-

Definition at line 3341 of file AMMExtended_test.cpp.

+

Definition at line 3331 of file AMMExtended_test.cpp.

@@ -1630,7 +1630,7 @@ Private Attributes
-

Definition at line 3479 of file AMMExtended_test.cpp.

+

Definition at line 3469 of file AMMExtended_test.cpp.

@@ -1658,7 +1658,7 @@ Private Attributes
-

Definition at line 3552 of file AMMExtended_test.cpp.

+

Definition at line 3542 of file AMMExtended_test.cpp.

@@ -1686,7 +1686,7 @@ Private Attributes
-

Definition at line 3612 of file AMMExtended_test.cpp.

+

Definition at line 3602 of file AMMExtended_test.cpp.

@@ -1714,7 +1714,7 @@ Private Attributes
-

Definition at line 3641 of file AMMExtended_test.cpp.

+

Definition at line 3631 of file AMMExtended_test.cpp.

@@ -1742,7 +1742,7 @@ Private Attributes
-

Definition at line 3715 of file AMMExtended_test.cpp.

+

Definition at line 3705 of file AMMExtended_test.cpp.

@@ -1769,7 +1769,7 @@ Private Attributes
-

Definition at line 3770 of file AMMExtended_test.cpp.

+

Definition at line 3760 of file AMMExtended_test.cpp.

@@ -1796,7 +1796,7 @@ Private Attributes
-

Definition at line 3782 of file AMMExtended_test.cpp.

+

Definition at line 3772 of file AMMExtended_test.cpp.

@@ -1823,7 +1823,7 @@ Private Attributes
-

Definition at line 3796 of file AMMExtended_test.cpp.

+

Definition at line 3786 of file AMMExtended_test.cpp.

@@ -1850,7 +1850,7 @@ Private Attributes
-

Definition at line 3805 of file AMMExtended_test.cpp.

+

Definition at line 3795 of file AMMExtended_test.cpp.

@@ -1877,7 +1877,7 @@ Private Attributes
-

Definition at line 3814 of file AMMExtended_test.cpp.

+

Definition at line 3804 of file AMMExtended_test.cpp.

@@ -1904,7 +1904,7 @@ Private Attributes
-

Definition at line 3823 of file AMMExtended_test.cpp.

+

Definition at line 3813 of file AMMExtended_test.cpp.

@@ -1931,7 +1931,7 @@ Private Attributes
-

Definition at line 3833 of file AMMExtended_test.cpp.

+

Definition at line 3823 of file AMMExtended_test.cpp.

@@ -1958,7 +1958,7 @@ Private Attributes
-

Definition at line 3845 of file AMMExtended_test.cpp.

+

Definition at line 3835 of file AMMExtended_test.cpp.

@@ -1989,7 +1989,7 @@ Private Attributes

Implements beast::unit_test::suite.

-

Definition at line 3856 of file AMMExtended_test.cpp.

+

Definition at line 3846 of file AMMExtended_test.cpp.