From 4758938d9fa0e80663503b8720b554e0ab51612c Mon Sep 17 00:00:00 2001 From: bthomee Date: Wed, 29 Oct 2025 10:37:10 -0700 Subject: [PATCH] deploy: 80a3ae6386b257bff2475ac8055b3422be707127 --- OfferStream_8cpp_source.html | 551 +- OfferStream_8h_source.html | 6 +- Offer__test_8cpp_source.html | 10119 ++++++++-------- classripple_1_1FlowOfferStream.html | 4 +- classripple_1_1OfferStream.html | 2 +- classripple_1_1TOfferStreamBase.html | 2 +- ...ple_1_1test_1_1OfferAllFeatures__test.html | 124 +- ...ripple_1_1test_1_1OfferBaseUtil__test.html | 122 +- ...le_1_1test_1_1OfferWOFillOrKill__test.html | 124 +- ...ipple_1_1test_1_1OfferWOPermDEX__test.html | 124 +- ..._1_1test_1_1OfferWOSmallQOffers__test.html | 124 +- ..._1_1test_1_1OfferWTakerDryOffer__test.html | 124 +- ...ripple_1_1test_1_1Offer__manual__test.html | 124 +- 13 files changed, 5740 insertions(+), 5810 deletions(-) diff --git a/OfferStream_8cpp_source.html b/OfferStream_8cpp_source.html index 9e6a0bafaa..7c6905c1f1 100644 --- a/OfferStream_8cpp_source.html +++ b/OfferStream_8cpp_source.html @@ -254,290 +254,287 @@ $(document).ready(function() { init_codefold(0); });
158 !std::is_same_v<TTakerGets, XRPAmount>,
159 "Cannot have XRP/XRP offers");
160
-
161 if (!view_.rules().enabled(fixRmSmallIncreasedQOffers))
-
162 return false;
-
163
-
164 // Consider removing the offer if:
-
165 // o `TakerPays` is XRP (because of XRP drops granularity) or
-
166 // o `TakerPays` and `TakerGets` are both IOU and `TakerPays`<`TakerGets`
-
167 constexpr bool const inIsXRP = std::is_same_v<TTakerPays, XRPAmount>;
-
168 constexpr bool const outIsXRP = std::is_same_v<TTakerGets, XRPAmount>;
-
169
-
170 if constexpr (outIsXRP)
-
171 {
-
172 // If `TakerGets` is XRP, the worst this offer's quality can change is
-
173 // to about 10^-81 `TakerPays` and 1 drop `TakerGets`. This will be
-
174 // remarkably good quality for any realistic asset, so these offers
-
175 // don't need this extra check.
-
176 return false;
-
177 }
-
178
-
179 TAmounts<TTakerPays, TTakerGets> const ofrAmts{
-
180 toAmount<TTakerPays>(offer_.amount().in),
-
181 toAmount<TTakerGets>(offer_.amount().out)};
-
182
-
183 if constexpr (!inIsXRP && !outIsXRP)
-
184 {
-
185 if (ofrAmts.in >= ofrAmts.out)
-
186 return false;
-
187 }
+
161 // Consider removing the offer if:
+
162 // o `TakerPays` is XRP (because of XRP drops granularity) or
+
163 // o `TakerPays` and `TakerGets` are both IOU and `TakerPays`<`TakerGets`
+
164 constexpr bool const inIsXRP = std::is_same_v<TTakerPays, XRPAmount>;
+
165 constexpr bool const outIsXRP = std::is_same_v<TTakerGets, XRPAmount>;
+
166
+
167 if constexpr (outIsXRP)
+
168 {
+
169 // If `TakerGets` is XRP, the worst this offer's quality can change is
+
170 // to about 10^-81 `TakerPays` and 1 drop `TakerGets`. This will be
+
171 // remarkably good quality for any realistic asset, so these offers
+
172 // don't need this extra check.
+
173 return false;
+
174 }
+
175
+
176 TAmounts<TTakerPays, TTakerGets> const ofrAmts{
+
177 toAmount<TTakerPays>(offer_.amount().in),
+
178 toAmount<TTakerGets>(offer_.amount().out)};
+
179
+
180 if constexpr (!inIsXRP && !outIsXRP)
+
181 {
+
182 if (ofrAmts.in >= ofrAmts.out)
+
183 return false;
+
184 }
+
185
+
186 TTakerGets const ownerFunds = toAmount<TTakerGets>(*ownerFunds_);
+
187 bool const fixReduced = view_.rules().enabled(fixReducedOffersV1);
188
-
189 TTakerGets const ownerFunds = toAmount<TTakerGets>(*ownerFunds_);
-
190 bool const fixReduced = view_.rules().enabled(fixReducedOffersV1);
-
191
-
192 auto const effectiveAmounts = [&] {
-
193 if (offer_.owner() != offer_.issueOut().account &&
-
194 ownerFunds < ofrAmts.out)
-
195 {
-
196 // adjust the amounts by owner funds.
-
197 //
-
198 // It turns out we can prevent order book blocking by rounding down
-
199 // the ceil_out() result. This adjustment changes transaction
-
200 // results, so it must be made under an amendment.
-
201 if (fixReduced)
-
202 return offer_.quality().ceil_out_strict(
-
203 ofrAmts, ownerFunds, /* roundUp */ false);
-
204
-
205 return offer_.quality().ceil_out(ofrAmts, ownerFunds);
-
206 }
-
207 return ofrAmts;
-
208 }();
-
209
-
210 // If either the effective in or out are zero then remove the offer.
-
211 // This can happen with fixReducedOffersV1 since it rounds down.
-
212 if (fixReduced &&
-
213 (effectiveAmounts.in.signum() <= 0 ||
-
214 effectiveAmounts.out.signum() <= 0))
-
215 return true;
+
189 auto const effectiveAmounts = [&] {
+
190 if (offer_.owner() != offer_.issueOut().account &&
+
191 ownerFunds < ofrAmts.out)
+
192 {
+
193 // adjust the amounts by owner funds.
+
194 //
+
195 // It turns out we can prevent order book blocking by rounding down
+
196 // the ceil_out() result. This adjustment changes transaction
+
197 // results, so it must be made under an amendment.
+
198 if (fixReduced)
+
199 return offer_.quality().ceil_out_strict(
+
200 ofrAmts, ownerFunds, /* roundUp */ false);
+
201
+
202 return offer_.quality().ceil_out(ofrAmts, ownerFunds);
+
203 }
+
204 return ofrAmts;
+
205 }();
+
206
+
207 // If either the effective in or out are zero then remove the offer.
+
208 // This can happen with fixReducedOffersV1 since it rounds down.
+
209 if (fixReduced &&
+
210 (effectiveAmounts.in.signum() <= 0 ||
+
211 effectiveAmounts.out.signum() <= 0))
+
212 return true;
+
213
+
214 if (effectiveAmounts.in > TTakerPays::minPositiveAmount())
+
215 return false;
216
-
217 if (effectiveAmounts.in > TTakerPays::minPositiveAmount())
-
218 return false;
-
219
-
220 Quality const effectiveQuality{effectiveAmounts};
-
221 return effectiveQuality < offer_.quality();
-
222}
+
217 Quality const effectiveQuality{effectiveAmounts};
+
218 return effectiveQuality < offer_.quality();
+
219}
-
223
-
224template <class TIn, class TOut>
-
225bool
-
- -
227{
-
228 // Modifying the order or logic of these
-
229 // operations causes a protocol breaking change.
+
220
+
221template <class TIn, class TOut>
+
222bool
+
+ +
224{
+
225 // Modifying the order or logic of these
+
226 // operations causes a protocol breaking change.
+
227
+
228 if (!validBook_)
+
229 return false;
230
-
231 if (!validBook_)
-
232 return false;
-
233
-
234 for (;;)
-
235 {
-
236 ownerFunds_ = std::nullopt;
-
237 // BookTip::step deletes the current offer from the view before
-
238 // advancing to the next (unless the ledger entry is missing).
-
239 if (!tip_.step(j_))
-
240 return false;
-
241
-
242 std::shared_ptr<SLE> entry = tip_.entry();
-
243
-
244 // If we exceed the maximum number of allowed steps, we're done.
-
245 if (!counter_.step())
-
246 return false;
-
247
-
248 // Remove if missing
-
249 if (!entry)
-
250 {
-
251 erase(view_);
-
252 erase(cancelView_);
-
253 continue;
-
254 }
-
255
-
256 // Remove if expired
-
257 using d = NetClock::duration;
-
258 using tp = NetClock::time_point;
-
259 if (entry->isFieldPresent(sfExpiration) &&
-
260 tp{d{(*entry)[sfExpiration]}} <= expire_)
-
261 {
-
262 JLOG(j_.trace()) << "Removing expired offer " << entry->key();
-
263 permRmOffer(entry->key());
-
264 continue;
-
265 }
-
266
-
267 offer_ = TOffer<TIn, TOut>(entry, tip_.quality());
-
268
-
269 auto const amount(offer_.amount());
-
270
-
271 // Remove if either amount is zero
-
272 if (amount.empty())
-
273 {
-
274 JLOG(j_.warn()) << "Removing bad offer " << entry->key();
-
275 permRmOffer(entry->key());
-
276 offer_ = TOffer<TIn, TOut>{};
-
277 continue;
-
278 }
-
279
-
280 bool const deepFrozen = isDeepFrozen(
-
281 view_,
-
282 offer_.owner(),
-
283 offer_.issueIn().currency,
-
284 offer_.issueIn().account);
-
285 if (deepFrozen)
-
286 {
-
287 JLOG(j_.trace())
-
288 << "Removing deep frozen unfunded offer " << entry->key();
-
289 permRmOffer(entry->key());
-
290 offer_ = TOffer<TIn, TOut>{};
-
291 continue;
-
292 }
-
293
-
294 if (entry->isFieldPresent(sfDomainID) &&
- -
296 view_, entry->key(), entry->getFieldH256(sfDomainID), j_))
-
297 {
-
298 JLOG(j_.trace())
-
299 << "Removing offer no longer in domain " << entry->key();
-
300 permRmOffer(entry->key());
-
301 offer_ = TOffer<TIn, TOut>{};
-
302 continue;
-
303 }
-
304
-
305 // Calculate owner funds
-
306 ownerFunds_ = accountFundsHelper(
-
307 view_,
-
308 offer_.owner(),
-
309 amount.out,
-
310 offer_.issueOut(),
- -
312 j_);
-
313
-
314 // Check for unfunded offer
-
315 if (*ownerFunds_ <= beast::zero)
-
316 {
-
317 // If the owner's balance in the pristine view is the same,
-
318 // we haven't modified the balance and therefore the
-
319 // offer is "found unfunded" versus "became unfunded"
-
320 auto const original_funds = accountFundsHelper(
-
321 cancelView_,
-
322 offer_.owner(),
-
323 amount.out,
-
324 offer_.issueOut(),
- -
326 j_);
-
327
-
328 if (original_funds == *ownerFunds_)
-
329 {
-
330 permRmOffer(entry->key());
-
331 JLOG(j_.trace()) << "Removing unfunded offer " << entry->key();
-
332 }
-
333 else
-
334 {
-
335 JLOG(j_.trace())
-
336 << "Removing became unfunded offer " << entry->key();
-
337 }
-
338 offer_ = TOffer<TIn, TOut>{};
-
339 // See comment at top of loop for how the offer is removed
-
340 continue;
-
341 }
-
342
-
343 bool const rmSmallIncreasedQOffer = [&] {
-
344 bool const inIsXRP = isXRP(offer_.issueIn());
-
345 bool const outIsXRP = isXRP(offer_.issueOut());
-
346 if (inIsXRP && !outIsXRP)
-
347 {
-
348 // Without the `if constexpr`, the
-
349 // `shouldRmSmallIncreasedQOffer` template will be instantiated
-
350 // even if it is never used. This can cause compiler errors in
-
351 // some cases, hence the `if constexpr` guard.
-
352 // Note that TIn can be XRPAmount or STAmount, and TOut can be
-
353 // IOUAmount or STAmount.
-
354 if constexpr (!(std::is_same_v<TIn, IOUAmount> ||
- -
356 return shouldRmSmallIncreasedQOffer<XRPAmount, IOUAmount>();
-
357 }
-
358 if (!inIsXRP && outIsXRP)
-
359 {
-
360 // See comment above for `if constexpr` rationale
-
361 if constexpr (!(std::is_same_v<TIn, XRPAmount> ||
- -
363 return shouldRmSmallIncreasedQOffer<IOUAmount, XRPAmount>();
-
364 }
-
365 if (!inIsXRP && !outIsXRP)
-
366 {
-
367 // See comment above for `if constexpr` rationale
-
368 if constexpr (!(std::is_same_v<TIn, XRPAmount> ||
- -
370 return shouldRmSmallIncreasedQOffer<IOUAmount, IOUAmount>();
-
371 }
-
372 // LCOV_EXCL_START
-
373 UNREACHABLE(
-
374 "rippls::TOfferStreamBase::step::rmSmallIncreasedQOffer : XRP "
-
375 "vs XRP offer");
-
376 return false;
-
377 // LCOV_EXCL_STOP
-
378 }();
-
379
-
380 if (rmSmallIncreasedQOffer)
-
381 {
-
382 auto const original_funds = accountFundsHelper(
-
383 cancelView_,
-
384 offer_.owner(),
-
385 amount.out,
-
386 offer_.issueOut(),
- -
388 j_);
-
389
-
390 if (original_funds == *ownerFunds_)
-
391 {
-
392 permRmOffer(entry->key());
-
393 JLOG(j_.trace())
-
394 << "Removing tiny offer due to reduced quality "
-
395 << entry->key();
-
396 }
-
397 else
-
398 {
-
399 JLOG(j_.trace()) << "Removing tiny offer that became tiny due "
-
400 "to reduced quality "
-
401 << entry->key();
-
402 }
-
403 offer_ = TOffer<TIn, TOut>{};
-
404 // See comment at top of loop for how the offer is removed
-
405 continue;
-
406 }
+
231 for (;;)
+
232 {
+
233 ownerFunds_ = std::nullopt;
+
234 // BookTip::step deletes the current offer from the view before
+
235 // advancing to the next (unless the ledger entry is missing).
+
236 if (!tip_.step(j_))
+
237 return false;
+
238
+
239 std::shared_ptr<SLE> entry = tip_.entry();
+
240
+
241 // If we exceed the maximum number of allowed steps, we're done.
+
242 if (!counter_.step())
+
243 return false;
+
244
+
245 // Remove if missing
+
246 if (!entry)
+
247 {
+
248 erase(view_);
+
249 erase(cancelView_);
+
250 continue;
+
251 }
+
252
+
253 // Remove if expired
+
254 using d = NetClock::duration;
+
255 using tp = NetClock::time_point;
+
256 if (entry->isFieldPresent(sfExpiration) &&
+
257 tp{d{(*entry)[sfExpiration]}} <= expire_)
+
258 {
+
259 JLOG(j_.trace()) << "Removing expired offer " << entry->key();
+
260 permRmOffer(entry->key());
+
261 continue;
+
262 }
+
263
+
264 offer_ = TOffer<TIn, TOut>(entry, tip_.quality());
+
265
+
266 auto const amount(offer_.amount());
+
267
+
268 // Remove if either amount is zero
+
269 if (amount.empty())
+
270 {
+
271 JLOG(j_.warn()) << "Removing bad offer " << entry->key();
+
272 permRmOffer(entry->key());
+
273 offer_ = TOffer<TIn, TOut>{};
+
274 continue;
+
275 }
+
276
+
277 bool const deepFrozen = isDeepFrozen(
+
278 view_,
+
279 offer_.owner(),
+
280 offer_.issueIn().currency,
+
281 offer_.issueIn().account);
+
282 if (deepFrozen)
+
283 {
+
284 JLOG(j_.trace())
+
285 << "Removing deep frozen unfunded offer " << entry->key();
+
286 permRmOffer(entry->key());
+
287 offer_ = TOffer<TIn, TOut>{};
+
288 continue;
+
289 }
+
290
+
291 if (entry->isFieldPresent(sfDomainID) &&
+ +
293 view_, entry->key(), entry->getFieldH256(sfDomainID), j_))
+
294 {
+
295 JLOG(j_.trace())
+
296 << "Removing offer no longer in domain " << entry->key();
+
297 permRmOffer(entry->key());
+
298 offer_ = TOffer<TIn, TOut>{};
+
299 continue;
+
300 }
+
301
+
302 // Calculate owner funds
+
303 ownerFunds_ = accountFundsHelper(
+
304 view_,
+
305 offer_.owner(),
+
306 amount.out,
+
307 offer_.issueOut(),
+ +
309 j_);
+
310
+
311 // Check for unfunded offer
+
312 if (*ownerFunds_ <= beast::zero)
+
313 {
+
314 // If the owner's balance in the pristine view is the same,
+
315 // we haven't modified the balance and therefore the
+
316 // offer is "found unfunded" versus "became unfunded"
+
317 auto const original_funds = accountFundsHelper(
+
318 cancelView_,
+
319 offer_.owner(),
+
320 amount.out,
+
321 offer_.issueOut(),
+ +
323 j_);
+
324
+
325 if (original_funds == *ownerFunds_)
+
326 {
+
327 permRmOffer(entry->key());
+
328 JLOG(j_.trace()) << "Removing unfunded offer " << entry->key();
+
329 }
+
330 else
+
331 {
+
332 JLOG(j_.trace())
+
333 << "Removing became unfunded offer " << entry->key();
+
334 }
+
335 offer_ = TOffer<TIn, TOut>{};
+
336 // See comment at top of loop for how the offer is removed
+
337 continue;
+
338 }
+
339
+
340 bool const rmSmallIncreasedQOffer = [&] {
+
341 bool const inIsXRP = isXRP(offer_.issueIn());
+
342 bool const outIsXRP = isXRP(offer_.issueOut());
+
343 if (inIsXRP && !outIsXRP)
+
344 {
+
345 // Without the `if constexpr`, the
+
346 // `shouldRmSmallIncreasedQOffer` template will be instantiated
+
347 // even if it is never used. This can cause compiler errors in
+
348 // some cases, hence the `if constexpr` guard.
+
349 // Note that TIn can be XRPAmount or STAmount, and TOut can be
+
350 // IOUAmount or STAmount.
+
351 if constexpr (!(std::is_same_v<TIn, IOUAmount> ||
+ +
353 return shouldRmSmallIncreasedQOffer<XRPAmount, IOUAmount>();
+
354 }
+
355 if (!inIsXRP && outIsXRP)
+
356 {
+
357 // See comment above for `if constexpr` rationale
+
358 if constexpr (!(std::is_same_v<TIn, XRPAmount> ||
+ +
360 return shouldRmSmallIncreasedQOffer<IOUAmount, XRPAmount>();
+
361 }
+
362 if (!inIsXRP && !outIsXRP)
+
363 {
+
364 // See comment above for `if constexpr` rationale
+
365 if constexpr (!(std::is_same_v<TIn, XRPAmount> ||
+ +
367 return shouldRmSmallIncreasedQOffer<IOUAmount, IOUAmount>();
+
368 }
+
369 // LCOV_EXCL_START
+
370 UNREACHABLE(
+
371 "rippls::TOfferStreamBase::step::rmSmallIncreasedQOffer : XRP "
+
372 "vs XRP offer");
+
373 return false;
+
374 // LCOV_EXCL_STOP
+
375 }();
+
376
+
377 if (rmSmallIncreasedQOffer)
+
378 {
+
379 auto const original_funds = accountFundsHelper(
+
380 cancelView_,
+
381 offer_.owner(),
+
382 amount.out,
+
383 offer_.issueOut(),
+ +
385 j_);
+
386
+
387 if (original_funds == *ownerFunds_)
+
388 {
+
389 permRmOffer(entry->key());
+
390 JLOG(j_.trace())
+
391 << "Removing tiny offer due to reduced quality "
+
392 << entry->key();
+
393 }
+
394 else
+
395 {
+
396 JLOG(j_.trace()) << "Removing tiny offer that became tiny due "
+
397 "to reduced quality "
+
398 << entry->key();
+
399 }
+
400 offer_ = TOffer<TIn, TOut>{};
+
401 // See comment at top of loop for how the offer is removed
+
402 continue;
+
403 }
+
404
+
405 break;
+
406 }
407
-
408 break;
-
409 }
+
408 return true;
+
409}
+
+
410
-
411 return true;
-
412}
+
411void
+
+
412OfferStream::permRmOffer(uint256 const& offerIndex)
+
413{
+
414 offerDelete(cancelView_, cancelView_.peek(keylet::offer(offerIndex)), j_);
+
415}
+
416
+
417template <class TIn, class TOut>
+
418void
+
+ +
420{
+
421 permToRemove_.insert(offerIndex);
+
422}
-
413
-
414void
-
-
415OfferStream::permRmOffer(uint256 const& offerIndex)
-
416{
-
417 offerDelete(cancelView_, cancelView_.peek(keylet::offer(offerIndex)), j_);
-
418}
-
-
419
-
420template <class TIn, class TOut>
-
421void
-
- -
423{
-
424 permToRemove_.insert(offerIndex);
-
425}
-
-
426
-
427template class FlowOfferStream<STAmount, STAmount>;
-
428template class FlowOfferStream<IOUAmount, IOUAmount>;
-
429template class FlowOfferStream<XRPAmount, IOUAmount>;
-
430template class FlowOfferStream<IOUAmount, XRPAmount>;
-
431
-
432template class TOfferStreamBase<STAmount, STAmount>;
-
433template class TOfferStreamBase<IOUAmount, IOUAmount>;
-
434template class TOfferStreamBase<XRPAmount, IOUAmount>;
-
435template class TOfferStreamBase<IOUAmount, XRPAmount>;
-
436} // namespace ripple
+
423
+
424template class FlowOfferStream<STAmount, STAmount>;
+
425template class FlowOfferStream<IOUAmount, IOUAmount>;
+
426template class FlowOfferStream<XRPAmount, IOUAmount>;
+
427template class FlowOfferStream<IOUAmount, XRPAmount>;
+
428
+
429template class TOfferStreamBase<STAmount, STAmount>;
+
430template class TOfferStreamBase<IOUAmount, IOUAmount>;
+
431template class TOfferStreamBase<XRPAmount, IOUAmount>;
+
432template class TOfferStreamBase<IOUAmount, XRPAmount>;
+
433} // namespace ripple
@@ -563,7 +560,7 @@ $(document).ready(function() { init_codefold(0); });
Definition OfferStream.h:40
Definition OfferStream.h:37
void erase(ApplyView &view)
-
bool step()
Advance to the next valid offer.
+
bool step()
Advance to the next valid offer.
TOfferStreamBase(ApplyView &view, ApplyView &cancelView, Book const &book, NetClock::time_point when, StepCounter &counter, beast::Journal journal)
bool shouldRmSmallIncreasedQOffer() const
bool validBook_
Definition OfferStream.h:75
diff --git a/OfferStream_8h_source.html b/OfferStream_8h_source.html index f01f77fc31..94d492a81a 100644 --- a/OfferStream_8h_source.html +++ b/OfferStream_8h_source.html @@ -261,10 +261,10 @@ $(document).ready(function() { init_codefold(0); });
Specifies an order book.
Definition Book.h:36
Presents and consumes the offers in an order book.
boost::container::flat_set< uint256 > const & permToRemove() const
-
void permRmOffer(uint256 const &offerIndex) override
+
void permRmOffer(uint256 const &offerIndex) override
boost::container::flat_set< uint256 > permToRemove_
Presents and consumes the offers in an order book.
-
void permRmOffer(uint256 const &offerIndex) override
+
void permRmOffer(uint256 const &offerIndex) override
Definition STAmount.h:50
Definition OfferStream.h:40
std::uint32_t count_
Definition OfferStream.h:43
@@ -276,7 +276,7 @@ $(document).ready(function() { init_codefold(0); });
Definition OfferStream.h:37
std::optional< TOut > ownerFunds_
Definition OfferStream.h:79
void erase(ApplyView &view)
-
bool step()
Advance to the next valid offer.
+
bool step()
Advance to the next valid offer.
BookTip tip_
Definition OfferStream.h:77
beast::Journal const j_
Definition OfferStream.h:71
virtual ~TOfferStreamBase()=default
diff --git a/Offer__test_8cpp_source.html b/Offer__test_8cpp_source.html index ed7be441e0..f3d3732746 100644 --- a/Offer__test_8cpp_source.html +++ b/Offer__test_8cpp_source.html @@ -467,5255 +467,5188 @@ $(document).ready(function() { init_codefold(0); });
366 env(offer(alice, USD(1), aliceTakerGets));
367 env.close();
368
-
369 if (features[fixRmSmallIncreasedQOffers])
-
370 {
-
371 env.require(
-
372 offers(carol, 0),
-
373 balance(
-
374 carol,
-
375 initialCarolUSD)); // offer is removed but not taken
-
376 if (crossBothOffers)
-
377 {
-
378 env.require(
-
379 offers(alice, 0),
-
380 balance(alice, USD(1))); // alice's offer is crossed
-
381 }
-
382 else
-
383 {
-
384 env.require(
-
385 offers(alice, 1),
-
386 balance(
-
387 alice, USD(0))); // alice's offer is not crossed
-
388 }
-
389 }
-
390 else
-
391 {
-
392 env.require(
-
393 offers(alice, 1),
-
394 offers(bob, 1),
-
395 offers(carol, 1),
-
396 balance(alice, USD(0)),
-
397 balance(
-
398 carol,
-
399 initialCarolUSD)); // offer is not crossed at all
-
400 }
-
401 }
-
402
-
403 // Test payments
-
404 for (auto partialPayment : {false, true})
-
405 {
-
406 Env env{*this, features};
+
369 env.require(
+
370 offers(carol, 0),
+
371 balance(
+
372 carol,
+
373 initialCarolUSD)); // offer is removed but not taken
+
374 if (crossBothOffers)
+
375 {
+
376 env.require(
+
377 offers(alice, 0),
+
378 balance(alice, USD(1))); // alice's offer is crossed
+
379 }
+
380 else
+
381 {
+
382 env.require(
+
383 offers(alice, 1),
+
384 balance(alice, USD(0))); // alice's offer is not crossed
+
385 }
+
386 }
+
387
+
388 // Test payments
+
389 for (auto partialPayment : {false, true})
+
390 {
+
391 Env env{*this, features};
+
392
+
393 env.fund(XRP(10000), alice, bob, carol, gw);
+
394 env.close();
+
395 env.trust(USD(1000), alice, bob, carol);
+
396 env.close();
+
397 auto const initialCarolUSD = USD(0.999);
+
398 env(pay(gw, carol, initialCarolUSD));
+
399 env.close();
+
400 env(pay(gw, bob, USD(100)));
+
401 env.close();
+
402 env(offer(carol, drops(1), USD(1)));
+
403 env.close();
+
404 env(offer(bob, drops(2), USD(2), tfPassive));
+
405 env.close();
+
406 env.require(offers(bob, 1), offers(carol, 1));
407
-
408 env.fund(XRP(10000), alice, bob, carol, gw);
-
409 env.close();
-
410 env.trust(USD(1000), alice, bob, carol);
-
411 env.close();
-
412 auto const initialCarolUSD = USD(0.999);
-
413 env(pay(gw, carol, initialCarolUSD));
-
414 env.close();
-
415 env(pay(gw, bob, USD(100)));
-
416 env.close();
-
417 env(offer(carol, drops(1), USD(1)));
-
418 env.close();
-
419 env(offer(bob, drops(2), USD(2), tfPassive));
+
408 std::uint32_t const flags = partialPayment
+
409 ? (tfNoRippleDirect | tfPartialPayment)
+
410 : tfNoRippleDirect;
+
411
+
412 TER const expectedTer =
+
413 partialPayment ? TER{tesSUCCESS} : TER{tecPATH_PARTIAL};
+
414
+
415 env(pay(alice, bob, USD(5)),
+
416 path(~USD),
+
417 sendmax(XRP(1)),
+
418 txflags(flags),
+
419 ter(expectedTer));
420 env.close();
-
421 env.require(offers(bob, 1), offers(carol, 1));
-
422
-
423 std::uint32_t const flags = partialPayment
-
424 ? (tfNoRippleDirect | tfPartialPayment)
-
425 : tfNoRippleDirect;
-
426
-
427 TER const expectedTer =
-
428 partialPayment ? TER{tesSUCCESS} : TER{tecPATH_PARTIAL};
-
429
-
430 env(pay(alice, bob, USD(5)),
-
431 path(~USD),
-
432 sendmax(XRP(1)),
-
433 txflags(flags),
-
434 ter(expectedTer));
-
435 env.close();
-
436
-
437 if (features[fixRmSmallIncreasedQOffers])
-
438 {
-
439 if (expectedTer == tesSUCCESS)
-
440 {
-
441 env.require(offers(carol, 0));
-
442 env.require(balance(
-
443 carol,
-
444 initialCarolUSD)); // offer is removed but not taken
-
445 }
-
446 else
-
447 {
-
448 // TODO: Offers are not removed when payments fail
-
449 // If that is addressed, the test should show that carol's
-
450 // offer is removed but not taken, as in the other branch of
-
451 // this if statement
-
452 }
-
453 }
-
454 else
-
455 {
-
456 if (partialPayment)
-
457 {
-
458 env.require(offers(carol, 0));
-
459 env.require(
-
460 balance(carol, USD(0))); // offer is removed and taken
-
461 }
-
462 else
-
463 {
-
464 // offer is not removed or taken
-
465 BEAST_EXPECT(isOffer(env, carol, drops(1), USD(1)));
-
466 }
-
467 }
-
468 }
-
469 }
+
421
+
422 if (expectedTer == tesSUCCESS)
+
423 {
+
424 env.require(offers(carol, 0));
+
425 env.require(balance(
+
426 carol,
+
427 initialCarolUSD)); // offer is removed but not taken
+
428 }
+
429 else
+
430 {
+
431 // TODO: Offers are not removed when payments fail
+
432 // If that is addressed, the test should show that carol's
+
433 // offer is removed but not taken, as in the other branch of
+
434 // this if statement
+
435 }
+
436 }
+
437 }
-
470
-
471 void
-
- -
473 {
-
474 testcase("Rm small increased q offers IOU");
-
475
-
476 // Carol places an offer, but cannot fully fund the offer. When her
-
477 // funding is taken into account, the offer's quality drops below its
-
478 // initial quality and has an input amount of 1 drop. This is removed as
-
479 // an offer that may block offer books.
-
480
-
481 using namespace jtx;
-
482 using namespace std::chrono_literals;
-
483 auto const alice = Account{"alice"};
-
484 auto const bob = Account{"bob"};
-
485 auto const carol = Account{"carol"};
-
486 auto const gw = Account{"gw"};
-
487
-
488 auto const USD = gw["USD"];
-
489 auto const EUR = gw["EUR"];
-
490
-
491 auto tinyAmount = [&](IOU const& iou) -> PrettyAmount {
-
492 STAmount amt(
-
493 iou.issue(),
-
494 /*mantissa*/ 1,
-
495 /*exponent*/ -81);
-
496 return PrettyAmount(amt, iou.account.name());
-
497 };
-
498
-
499 // Test offer crossing
-
500 for (auto crossBothOffers : {false, true})
-
501 {
-
502 Env env{*this, features};
-
503
-
504 env.fund(XRP(10000), alice, bob, carol, gw);
-
505 env.close();
-
506 env.trust(USD(1000), alice, bob, carol);
-
507 env.trust(EUR(1000), alice, bob, carol);
-
508 // underfund carol's offer
-
509 auto initialCarolUSD = tinyAmount(USD);
-
510 env(pay(gw, carol, initialCarolUSD));
-
511 env(pay(gw, bob, USD(100)));
-
512 env(pay(gw, alice, EUR(100)));
-
513 env.close();
-
514 // This offer is underfunded
-
515 env(offer(carol, EUR(1), USD(10)));
-
516 env.close();
-
517 // offer at a lower quality
-
518 env(offer(bob, EUR(1), USD(5), tfPassive));
-
519 env.close();
-
520 env.require(offers(bob, 1), offers(carol, 1));
-
521
-
522 // alice places an offer that crosses carol's; depending on
-
523 // "crossBothOffers" it may cross bob's as well
-
524 // Whatever
-
525 auto aliceTakerGets = crossBothOffers ? EUR(0.2) : EUR(0.1);
-
526 env(offer(alice, USD(1), aliceTakerGets));
-
527 env.close();
-
528
-
529 if (features[fixRmSmallIncreasedQOffers])
-
530 {
-
531 env.require(
-
532 offers(carol, 0),
-
533 balance(
-
534 carol,
-
535 initialCarolUSD)); // offer is removed but not taken
-
536 if (crossBothOffers)
-
537 {
-
538 env.require(
-
539 offers(alice, 0),
-
540 balance(alice, USD(1))); // alice's offer is crossed
-
541 }
-
542 else
-
543 {
-
544 env.require(
-
545 offers(alice, 1),
-
546 balance(
-
547 alice, USD(0))); // alice's offer is not crossed
-
548 }
-
549 }
-
550 else
-
551 {
-
552 env.require(
-
553 offers(alice, 1),
-
554 offers(bob, 1),
-
555 offers(carol, 1),
-
556 balance(alice, USD(0)),
-
557 balance(
-
558 carol,
-
559 initialCarolUSD)); // offer is not crossed at all
-
560 }
-
561 }
-
562
-
563 // Test payments
-
564 for (auto partialPayment : {false, true})
-
565 {
-
566 Env env{*this, features};
-
567
-
568 env.fund(XRP(10000), alice, bob, carol, gw);
-
569 env.close();
-
570 env.trust(USD(1000), alice, bob, carol);
-
571 env.trust(EUR(1000), alice, bob, carol);
-
572 env.close();
-
573 // underfund carol's offer
-
574 auto const initialCarolUSD = tinyAmount(USD);
-
575 env(pay(gw, carol, initialCarolUSD));
-
576 env(pay(gw, bob, USD(100)));
-
577 env(pay(gw, alice, EUR(100)));
-
578 env.close();
-
579 // This offer is underfunded
-
580 env(offer(carol, EUR(1), USD(2)));
-
581 env.close();
-
582 env(offer(bob, EUR(2), USD(4), tfPassive));
-
583 env.close();
-
584 env.require(offers(bob, 1), offers(carol, 1));
+
438
+
439 void
+
+ +
441 {
+
442 testcase("Rm small increased q offers IOU");
+
443
+
444 // Carol places an offer, but cannot fully fund the offer. When her
+
445 // funding is taken into account, the offer's quality drops below its
+
446 // initial quality and has an input amount of 1 drop. This is removed as
+
447 // an offer that may block offer books.
+
448
+
449 using namespace jtx;
+
450 using namespace std::chrono_literals;
+
451 auto const alice = Account{"alice"};
+
452 auto const bob = Account{"bob"};
+
453 auto const carol = Account{"carol"};
+
454 auto const gw = Account{"gw"};
+
455
+
456 auto const USD = gw["USD"];
+
457 auto const EUR = gw["EUR"];
+
458
+
459 auto tinyAmount = [&](IOU const& iou) -> PrettyAmount {
+
460 STAmount amt(
+
461 iou.issue(),
+
462 /*mantissa*/ 1,
+
463 /*exponent*/ -81);
+
464 return PrettyAmount(amt, iou.account.name());
+
465 };
+
466
+
467 // Test offer crossing
+
468 for (auto crossBothOffers : {false, true})
+
469 {
+
470 Env env{*this, features};
+
471
+
472 env.fund(XRP(10000), alice, bob, carol, gw);
+
473 env.close();
+
474 env.trust(USD(1000), alice, bob, carol);
+
475 env.trust(EUR(1000), alice, bob, carol);
+
476 // underfund carol's offer
+
477 auto initialCarolUSD = tinyAmount(USD);
+
478 env(pay(gw, carol, initialCarolUSD));
+
479 env(pay(gw, bob, USD(100)));
+
480 env(pay(gw, alice, EUR(100)));
+
481 env.close();
+
482 // This offer is underfunded
+
483 env(offer(carol, EUR(1), USD(10)));
+
484 env.close();
+
485 // offer at a lower quality
+
486 env(offer(bob, EUR(1), USD(5), tfPassive));
+
487 env.close();
+
488 env.require(offers(bob, 1), offers(carol, 1));
+
489
+
490 // alice places an offer that crosses carol's; depending on
+
491 // "crossBothOffers" it may cross bob's as well
+
492 // Whatever
+
493 auto aliceTakerGets = crossBothOffers ? EUR(0.2) : EUR(0.1);
+
494 env(offer(alice, USD(1), aliceTakerGets));
+
495 env.close();
+
496
+
497 env.require(
+
498 offers(carol, 0),
+
499 balance(
+
500 carol,
+
501 initialCarolUSD)); // offer is removed but not taken
+
502 if (crossBothOffers)
+
503 {
+
504 env.require(
+
505 offers(alice, 0),
+
506 balance(alice, USD(1))); // alice's offer is crossed
+
507 }
+
508 else
+
509 {
+
510 env.require(
+
511 offers(alice, 1),
+
512 balance(alice, USD(0))); // alice's offer is not crossed
+
513 }
+
514 }
+
515
+
516 // Test payments
+
517 for (auto partialPayment : {false, true})
+
518 {
+
519 Env env{*this, features};
+
520
+
521 env.fund(XRP(10000), alice, bob, carol, gw);
+
522 env.close();
+
523 env.trust(USD(1000), alice, bob, carol);
+
524 env.trust(EUR(1000), alice, bob, carol);
+
525 env.close();
+
526 // underfund carol's offer
+
527 auto const initialCarolUSD = tinyAmount(USD);
+
528 env(pay(gw, carol, initialCarolUSD));
+
529 env(pay(gw, bob, USD(100)));
+
530 env(pay(gw, alice, EUR(100)));
+
531 env.close();
+
532 // This offer is underfunded
+
533 env(offer(carol, EUR(1), USD(2)));
+
534 env.close();
+
535 env(offer(bob, EUR(2), USD(4), tfPassive));
+
536 env.close();
+
537 env.require(offers(bob, 1), offers(carol, 1));
+
538
+
539 std::uint32_t const flags = partialPayment
+ + +
542
+
543 TER const expectedTer =
+
544 partialPayment ? TER{tesSUCCESS} : TER{tecPATH_PARTIAL};
+
545
+
546 env(pay(alice, bob, USD(5)),
+
547 path(~USD),
+
548 sendmax(EUR(10)),
+
549 txflags(flags),
+
550 ter(expectedTer));
+
551 env.close();
+
552
+
553 if (expectedTer == tesSUCCESS)
+
554 {
+
555 env.require(offers(carol, 0));
+
556 env.require(balance(
+
557 carol,
+
558 initialCarolUSD)); // offer is removed but not taken
+
559 }
+
560 else
+
561 {
+
562 // TODO: Offers are not removed when payments fail
+
563 // If that is addressed, the test should show that carol's
+
564 // offer is removed but not taken, as in the other branch of
+
565 // this if statement
+
566 }
+
567 }
+
568 }
+
+
569
+
570 void
+
+ +
572 {
+
573 testcase("Enforce No Ripple");
+
574
+
575 using namespace jtx;
+
576
+
577 auto const gw = Account{"gateway"};
+
578 auto const USD = gw["USD"];
+
579 auto const BTC = gw["BTC"];
+
580 auto const EUR = gw["EUR"];
+
581 Account const alice{"alice"};
+
582 Account const bob{"bob"};
+
583 Account const carol{"carol"};
+
584 Account const dan{"dan"};
585
-
586 std::uint32_t const flags = partialPayment
- - +
586 {
+
587 // No ripple with an implied account step after an offer
+
588 Env env{*this, features};
589
-
590 TER const expectedTer =
-
591 partialPayment ? TER{tesSUCCESS} : TER{tecPATH_PARTIAL};
-
592
-
593 env(pay(alice, bob, USD(5)),
-
594 path(~USD),
-
595 sendmax(EUR(10)),
-
596 txflags(flags),
-
597 ter(expectedTer));
-
598 env.close();
-
599
-
600 if (features[fixRmSmallIncreasedQOffers])
-
601 {
-
602 if (expectedTer == tesSUCCESS)
-
603 {
-
604 env.require(offers(carol, 0));
-
605 env.require(balance(
-
606 carol,
-
607 initialCarolUSD)); // offer is removed but not taken
-
608 }
-
609 else
-
610 {
-
611 // TODO: Offers are not removed when payments fail
-
612 // If that is addressed, the test should show that carol's
-
613 // offer is removed but not taken, as in the other branch of
-
614 // this if statement
-
615 }
-
616 }
-
617 else
-
618 {
-
619 if (partialPayment)
-
620 {
-
621 env.require(offers(carol, 0));
-
622 env.require(
-
623 balance(carol, USD(0))); // offer is removed and taken
-
624 }
-
625 else
-
626 {
-
627 // offer is not removed or taken
-
628 BEAST_EXPECT(isOffer(env, carol, EUR(1), USD(2)));
-
629 }
-
630 }
-
631 }
-
632 }
-
+
590 auto const gw1 = Account{"gw1"};
+
591 auto const USD1 = gw1["USD"];
+
592 auto const gw2 = Account{"gw2"};
+
593 auto const USD2 = gw2["USD"];
+
594
+
595 env.fund(XRP(10000), alice, noripple(bob), carol, dan, gw1, gw2);
+
596 env.close();
+
597 env.trust(USD1(1000), alice, carol, dan);
+
598 env(trust(bob, USD1(1000), tfSetNoRipple));
+
599 env.trust(USD2(1000), alice, carol, dan);
+
600 env(trust(bob, USD2(1000), tfSetNoRipple));
+
601
+
602 env(pay(gw1, dan, USD1(50)));
+
603 env(pay(gw1, bob, USD1(50)));
+
604 env(pay(gw2, bob, USD2(50)));
+
605
+
606 env(offer(dan, XRP(50), USD1(50)));
+
607
+
608 env(pay(alice, carol, USD2(50)),
+
609 path(~USD1, bob),
+
610 sendmax(XRP(50)),
+ + +
613 }
+
614 {
+
615 // Make sure payment works with default flags
+
616 Env env{*this, features};
+
617
+
618 auto const gw1 = Account{"gw1"};
+
619 auto const USD1 = gw1["USD"];
+
620 auto const gw2 = Account{"gw2"};
+
621 auto const USD2 = gw2["USD"];
+
622
+
623 env.fund(XRP(10000), alice, bob, carol, dan, gw1, gw2);
+
624 env.close();
+
625 env.trust(USD1(1000), alice, bob, carol, dan);
+
626 env.trust(USD2(1000), alice, bob, carol, dan);
+
627
+
628 env(pay(gw1, dan, USD1(50)));
+
629 env(pay(gw1, bob, USD1(50)));
+
630 env(pay(gw2, bob, USD2(50)));
+
631
+
632 env(offer(dan, XRP(50), USD1(50)));
633
-
634 void
-
- -
636 {
-
637 testcase("Enforce No Ripple");
+
634 env(pay(alice, carol, USD2(50)),
+
635 path(~USD1, bob),
+
636 sendmax(XRP(50)),
+
638
-
639 using namespace jtx;
-
640
-
641 auto const gw = Account{"gateway"};
-
642 auto const USD = gw["USD"];
-
643 auto const BTC = gw["BTC"];
-
644 auto const EUR = gw["EUR"];
-
645 Account const alice{"alice"};
-
646 Account const bob{"bob"};
-
647 Account const carol{"carol"};
-
648 Account const dan{"dan"};
-
649
-
650 {
-
651 // No ripple with an implied account step after an offer
-
652 Env env{*this, features};
-
653
-
654 auto const gw1 = Account{"gw1"};
-
655 auto const USD1 = gw1["USD"];
-
656 auto const gw2 = Account{"gw2"};
-
657 auto const USD2 = gw2["USD"];
-
658
-
659 env.fund(XRP(10000), alice, noripple(bob), carol, dan, gw1, gw2);
-
660 env.close();
-
661 env.trust(USD1(1000), alice, carol, dan);
-
662 env(trust(bob, USD1(1000), tfSetNoRipple));
-
663 env.trust(USD2(1000), alice, carol, dan);
-
664 env(trust(bob, USD2(1000), tfSetNoRipple));
-
665
-
666 env(pay(gw1, dan, USD1(50)));
-
667 env(pay(gw1, bob, USD1(50)));
-
668 env(pay(gw2, bob, USD2(50)));
-
669
-
670 env(offer(dan, XRP(50), USD1(50)));
-
671
-
672 env(pay(alice, carol, USD2(50)),
-
673 path(~USD1, bob),
-
674 sendmax(XRP(50)),
- - -
677 }
-
678 {
-
679 // Make sure payment works with default flags
-
680 Env env{*this, features};
-
681
-
682 auto const gw1 = Account{"gw1"};
-
683 auto const USD1 = gw1["USD"];
-
684 auto const gw2 = Account{"gw2"};
-
685 auto const USD2 = gw2["USD"];
-
686
-
687 env.fund(XRP(10000), alice, bob, carol, dan, gw1, gw2);
-
688 env.close();
-
689 env.trust(USD1(1000), alice, bob, carol, dan);
-
690 env.trust(USD2(1000), alice, bob, carol, dan);
-
691
-
692 env(pay(gw1, dan, USD1(50)));
-
693 env(pay(gw1, bob, USD1(50)));
-
694 env(pay(gw2, bob, USD2(50)));
-
695
-
696 env(offer(dan, XRP(50), USD1(50)));
-
697
-
698 env(pay(alice, carol, USD2(50)),
-
699 path(~USD1, bob),
-
700 sendmax(XRP(50)),
- -
702
-
703 env.require(balance(alice, xrpMinusFee(env, 10000 - 50)));
-
704 env.require(balance(bob, USD1(100)));
-
705 env.require(balance(bob, USD2(0)));
-
706 env.require(balance(carol, USD2(50)));
-
707 }
-
708 }
+
639 env.require(balance(alice, xrpMinusFee(env, 10000 - 50)));
+
640 env.require(balance(bob, USD1(100)));
+
641 env.require(balance(bob, USD2(0)));
+
642 env.require(balance(carol, USD2(50)));
+
643 }
+
644 }
-
709
-
710 void
-
- -
712 {
-
713 testcase("Insufficient Reserve");
-
714
-
715 // If an account places an offer and its balance
-
716 // *before* the transaction began isn't high enough
-
717 // to meet the reserve *after* the transaction runs,
-
718 // then no offer should go on the books but if the
-
719 // offer partially or fully crossed the tx succeeds.
-
720
-
721 using namespace jtx;
-
722
-
723 auto const gw = Account{"gateway"};
-
724 auto const alice = Account{"alice"};
-
725 auto const bob = Account{"bob"};
-
726 auto const carol = Account{"carol"};
-
727 auto const USD = gw["USD"];
-
728
-
729 auto const usdOffer = USD(1000);
-
730 auto const xrpOffer = XRP(1000);
+
645
+
646 void
+
+ +
648 {
+
649 testcase("Insufficient Reserve");
+
650
+
651 // If an account places an offer and its balance
+
652 // *before* the transaction began isn't high enough
+
653 // to meet the reserve *after* the transaction runs,
+
654 // then no offer should go on the books but if the
+
655 // offer partially or fully crossed the tx succeeds.
+
656
+
657 using namespace jtx;
+
658
+
659 auto const gw = Account{"gateway"};
+
660 auto const alice = Account{"alice"};
+
661 auto const bob = Account{"bob"};
+
662 auto const carol = Account{"carol"};
+
663 auto const USD = gw["USD"];
+
664
+
665 auto const usdOffer = USD(1000);
+
666 auto const xrpOffer = XRP(1000);
+
667
+
668 // No crossing:
+
669 {
+
670 Env env{*this, features};
+
671
+
672 env.fund(XRP(1000000), gw);
+
673
+
674 auto const f = env.current()->fees().base;
+
675 auto const r = reserve(env, 0);
+
676
+
677 env.fund(r + f, alice);
+
678
+
679 env(trust(alice, usdOffer), ter(tesSUCCESS));
+
680 env(pay(gw, alice, usdOffer), ter(tesSUCCESS));
+
681 env(offer(alice, xrpOffer, usdOffer), ter(tecINSUF_RESERVE_OFFER));
+
682
+
683 env.require(balance(alice, r - f), owners(alice, 1));
+
684 }
+
685
+
686 // Partial cross:
+
687 {
+
688 Env env{*this, features};
+
689
+
690 env.fund(XRP(1000000), gw);
+
691
+
692 auto const f = env.current()->fees().base;
+
693 auto const r = reserve(env, 0);
+
694
+
695 auto const usdOffer2 = USD(500);
+
696 auto const xrpOffer2 = XRP(500);
+
697
+
698 env.fund(r + f + xrpOffer, bob);
+
699
+
700 env(offer(bob, usdOffer2, xrpOffer2), ter(tesSUCCESS));
+
701 env.fund(r + f, alice);
+
702
+
703 env(trust(alice, usdOffer), ter(tesSUCCESS));
+
704 env(pay(gw, alice, usdOffer), ter(tesSUCCESS));
+
705 env(offer(alice, xrpOffer, usdOffer), ter(tesSUCCESS));
+
706
+
707 env.require(
+
708 balance(alice, r - f + xrpOffer2),
+
709 balance(alice, usdOffer2),
+
710 owners(alice, 1),
+
711 balance(bob, r + xrpOffer2),
+
712 balance(bob, usdOffer2),
+
713 owners(bob, 1));
+
714 }
+
715
+
716 // Account has enough reserve as is, but not enough
+
717 // if an offer were added. Attempt to sell IOUs to
+
718 // buy XRP. If it fully crosses, we succeed.
+
719 {
+
720 Env env{*this, features};
+
721
+
722 env.fund(XRP(1000000), gw);
+
723
+
724 auto const f = env.current()->fees().base;
+
725 auto const r = reserve(env, 0);
+
726
+
727 auto const usdOffer2 = USD(500);
+
728 auto const xrpOffer2 = XRP(500);
+
729
+
730 env.fund(r + f + xrpOffer, bob, carol);
731
-
732 // No crossing:
-
733 {
-
734 Env env{*this, features};
-
735
-
736 env.fund(XRP(1000000), gw);
-
737
-
738 auto const f = env.current()->fees().base;
-
739 auto const r = reserve(env, 0);
+
732 env(offer(bob, usdOffer2, xrpOffer2), ter(tesSUCCESS));
+
733 env(offer(carol, usdOffer, xrpOffer), ter(tesSUCCESS));
+
734
+
735 env.fund(r + f, alice);
+
736
+
737 env(trust(alice, usdOffer), ter(tesSUCCESS));
+
738 env(pay(gw, alice, usdOffer), ter(tesSUCCESS));
+
739 env(offer(alice, xrpOffer, usdOffer), ter(tesSUCCESS));
740
-
741 env.fund(r + f, alice);
-
742
-
743 env(trust(alice, usdOffer), ter(tesSUCCESS));
-
744 env(pay(gw, alice, usdOffer), ter(tesSUCCESS));
-
745 env(offer(alice, xrpOffer, usdOffer), ter(tecINSUF_RESERVE_OFFER));
-
746
-
747 env.require(balance(alice, r - f), owners(alice, 1));
-
748 }
-
749
-
750 // Partial cross:
-
751 {
-
752 Env env{*this, features};
+
741 env.require(
+
742 balance(alice, r - f + xrpOffer),
+
743 balance(alice, USD(0)),
+
744 owners(alice, 1),
+
745 balance(bob, r + xrpOffer2),
+
746 balance(bob, usdOffer2),
+
747 owners(bob, 1),
+
748 balance(carol, r + xrpOffer2),
+
749 balance(carol, usdOffer2),
+
750 owners(carol, 2));
+
751 }
+
752 }
+
753
-
754 env.fund(XRP(1000000), gw);
-
755
-
756 auto const f = env.current()->fees().base;
-
757 auto const r = reserve(env, 0);
-
758
-
759 auto const usdOffer2 = USD(500);
-
760 auto const xrpOffer2 = XRP(500);
-
761
-
762 env.fund(r + f + xrpOffer, bob);
-
763
-
764 env(offer(bob, usdOffer2, xrpOffer2), ter(tesSUCCESS));
-
765 env.fund(r + f, alice);
-
766
-
767 env(trust(alice, usdOffer), ter(tesSUCCESS));
-
768 env(pay(gw, alice, usdOffer), ter(tesSUCCESS));
-
769 env(offer(alice, xrpOffer, usdOffer), ter(tesSUCCESS));
-
770
-
771 env.require(
-
772 balance(alice, r - f + xrpOffer2),
-
773 balance(alice, usdOffer2),
-
774 owners(alice, 1),
-
775 balance(bob, r + xrpOffer2),
-
776 balance(bob, usdOffer2),
-
777 owners(bob, 1));
-
778 }
-
779
-
780 // Account has enough reserve as is, but not enough
-
781 // if an offer were added. Attempt to sell IOUs to
-
782 // buy XRP. If it fully crosses, we succeed.
-
783 {
-
784 Env env{*this, features};
-
785
-
786 env.fund(XRP(1000000), gw);
+
754 // Helper function that returns the Offers on an account.
+ +
+ +
757 {
+ + +
760 *env.current(),
+
761 account,
+
762 [&result](std::shared_ptr<SLE const> const& sle) {
+
763 if (sle->getType() == ltOFFER)
+
764 result.push_back(sle);
+
765 });
+
766 return result;
+
767 }
+
+
768
+
769 void
+
+ +
771 {
+
772 testcase("Fill Modes");
+
773
+
774 using namespace jtx;
+
775
+
776 auto const startBalance = XRP(1000000);
+
777 auto const gw = Account{"gateway"};
+
778 auto const alice = Account{"alice"};
+
779 auto const bob = Account{"bob"};
+
780 auto const USD = gw["USD"];
+
781
+
782 // Fill or Kill - unless we fully cross, just charge a fee and don't
+
783 // place the offer on the books. But also clean up expired offers
+
784 // that are discovered along the way.
+
785 {
+
786 Env env{*this, features};
787
788 auto const f = env.current()->fees().base;
-
789 auto const r = reserve(env, 0);
-
790
-
791 auto const usdOffer2 = USD(500);
-
792 auto const xrpOffer2 = XRP(500);
-
793
-
794 env.fund(r + f + xrpOffer, bob, carol);
-
795
-
796 env(offer(bob, usdOffer2, xrpOffer2), ter(tesSUCCESS));
-
797 env(offer(carol, usdOffer, xrpOffer), ter(tesSUCCESS));
-
798
-
799 env.fund(r + f, alice);
-
800
-
801 env(trust(alice, usdOffer), ter(tesSUCCESS));
-
802 env(pay(gw, alice, usdOffer), ter(tesSUCCESS));
-
803 env(offer(alice, xrpOffer, usdOffer), ter(tesSUCCESS));
-
804
-
805 env.require(
-
806 balance(alice, r - f + xrpOffer),
-
807 balance(alice, USD(0)),
-
808 owners(alice, 1),
-
809 balance(bob, r + xrpOffer2),
-
810 balance(bob, usdOffer2),
-
811 owners(bob, 1),
-
812 balance(carol, r + xrpOffer2),
-
813 balance(carol, usdOffer2),
-
814 owners(carol, 2));
-
815 }
-
816 }
-
-
817
-
818 // Helper function that returns the Offers on an account.
- -
- -
821 {
- - -
824 *env.current(),
-
825 account,
-
826 [&result](std::shared_ptr<SLE const> const& sle) {
-
827 if (sle->getType() == ltOFFER)
-
828 result.push_back(sle);
-
829 });
-
830 return result;
-
831 }
-
-
832
-
833 void
-
- -
835 {
-
836 testcase("Fill Modes");
-
837
-
838 using namespace jtx;
-
839
-
840 auto const startBalance = XRP(1000000);
-
841 auto const gw = Account{"gateway"};
-
842 auto const alice = Account{"alice"};
-
843 auto const bob = Account{"bob"};
-
844 auto const USD = gw["USD"];
-
845
-
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 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 // 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 // The offer expires (it's not removed yet).
-
863 env.close();
-
864 env.require(owners(bob, 1), offers(bob, 1));
+
789
+
790 env.fund(startBalance, gw, alice, bob);
+
791 env.close();
+
792
+
793 // bob creates an offer that expires before the next ledger close.
+
794 env(offer(bob, USD(500), XRP(500)),
+
795 json(sfExpiration.fieldName, lastClose(env) + 1),
+
796 ter(tesSUCCESS));
+
797
+
798 // The offer expires (it's not removed yet).
+
799 env.close();
+
800 env.require(owners(bob, 1), offers(bob, 1));
+
801
+
802 // bob creates the offer that will be crossed.
+
803 env(offer(bob, USD(500), XRP(500)), ter(tesSUCCESS));
+
804 env.close();
+
805 env.require(owners(bob, 2), offers(bob, 2));
+
806
+
807 env(trust(alice, USD(1000)), ter(tesSUCCESS));
+
808 env(pay(gw, alice, USD(1000)), ter(tesSUCCESS));
+
809
+
810 // Order that can't be filled but will remove bob's expired offer:
+
811 {
+
812 TER const killedCode{TER{tecKILLED}};
+
813 env(offer(alice, XRP(1000), USD(1000)),
+ +
815 ter(killedCode));
+
816 }
+
817 env.require(
+
818 balance(alice, startBalance - (f * 2)),
+
819 balance(alice, USD(1000)),
+
820 owners(alice, 1),
+
821 offers(alice, 0),
+
822 balance(bob, startBalance - (f * 2)),
+
823 balance(bob, USD(none)),
+
824 owners(bob, 1),
+
825 offers(bob, 1));
+
826
+
827 // Order that can be filled
+
828 env(offer(alice, XRP(500), USD(500)),
+ +
830 ter(tesSUCCESS));
+
831
+
832 env.require(
+
833 balance(alice, startBalance - (f * 3) + XRP(500)),
+
834 balance(alice, USD(500)),
+
835 owners(alice, 1),
+
836 offers(alice, 0),
+
837 balance(bob, startBalance - (f * 2) - XRP(500)),
+
838 balance(bob, USD(500)),
+
839 owners(bob, 1),
+
840 offers(bob, 0));
+
841 }
+
842
+
843 // Immediate or Cancel - cross as much as possible
+
844 // and add nothing on the books:
+
845 {
+
846 Env env{*this, features};
+
847
+
848 auto const f = env.current()->fees().base;
+
849
+
850 env.fund(startBalance, gw, alice, bob);
+
851 env.close();
+
852
+
853 env(trust(alice, USD(1000)), ter(tesSUCCESS));
+
854 env(pay(gw, alice, USD(1000)), ter(tesSUCCESS));
+
855
+
856 // No cross:
+
857 {
+
858 TER const expectedCode = features[featureImmediateOfferKilled]
+
859 ? static_cast<TER>(tecKILLED)
+
860 : static_cast<TER>(tesSUCCESS);
+
861 env(offer(alice, XRP(1000), USD(1000)),
+ +
863 ter(expectedCode));
+
864 }
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, 2), offers(bob, 2));
-
870
-
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};
+
866 env.require(
+
867 balance(alice, startBalance - f - f),
+
868 balance(alice, USD(1000)),
+
869 owners(alice, 1),
+
870 offers(alice, 0));
+
871
+
872 // Partially cross:
+
873 env(offer(bob, USD(50), XRP(50)), ter(tesSUCCESS));
+
874 env(offer(alice, XRP(1000), USD(1000)),
+ +
876 ter(tesSUCCESS));
+
877
+
878 env.require(
+
879 balance(alice, startBalance - f - f - f + XRP(50)),
+
880 balance(alice, USD(950)),
+
881 owners(alice, 1),
+
882 offers(alice, 0),
+
883 balance(bob, startBalance - f - XRP(50)),
+
884 balance(bob, USD(50)),
+
885 owners(bob, 1),
+
886 offers(bob, 0));
+
887
+
888 // Fully cross:
+
889 env(offer(bob, USD(50), XRP(50)), ter(tesSUCCESS));
+
890 env(offer(alice, XRP(50), USD(50)),
+ +
892 ter(tesSUCCESS));
+
893
+
894 env.require(
+
895 balance(alice, startBalance - f - f - f - f + XRP(100)),
+
896 balance(alice, USD(900)),
+
897 owners(alice, 1),
+
898 offers(alice, 0),
+
899 balance(bob, startBalance - f - f - XRP(100)),
+
900 balance(bob, USD(100)),
+
901 owners(bob, 1),
+
902 offers(bob, 0));
+
903 }
+
904
+
905 // tfPassive -- place the offer without crossing it.
+
906 {
+
907 Env env(*this, features);
+
908
+
909 env.fund(startBalance, gw, alice, bob);
+
910 env.close();
911
-
912 auto const f = env.current()->fees().base;
-
913
-
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));
+
912 env(trust(bob, USD(1000)));
+
913 env.close();
+
914
+
915 env(pay(gw, bob, USD(1000)));
+
916 env.close();
+
917
+
918 env(offer(alice, USD(1000), XRP(2000)));
+
919 env.close();
+
920
+
921 auto const aliceOffers = offersOnAccount(env, alice);
+
922 BEAST_EXPECT(aliceOffers.size() == 1);
+
923 for (auto offerPtr : aliceOffers)
+
924 {
+
925 auto const& offer = *offerPtr;
+
926 BEAST_EXPECT(offer[sfTakerGets] == XRP(2000));
+
927 BEAST_EXPECT(offer[sfTakerPays] == USD(1000));
928 }
929
-
930 env.require(
-
931 balance(alice, startBalance - f - f),
-
932 balance(alice, USD(1000)),
-
933 owners(alice, 1),
-
934 offers(alice, 0));
+
930 // bob creates a passive offer that could cross alice's.
+
931 // bob's offer should stay in the ledger.
+
932 env(offer(bob, XRP(2000), USD(1000), tfPassive));
+
933 env.close();
+
934 env.require(offers(alice, 1));
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));
+
936 auto const bobOffers = offersOnAccount(env, bob);
+
937 BEAST_EXPECT(bobOffers.size() == 1);
+
938 for (auto offerPtr : bobOffers)
+
939 {
+
940 auto const& offer = *offerPtr;
+
941 BEAST_EXPECT(offer[sfTakerGets] == USD(1000));
+
942 BEAST_EXPECT(offer[sfTakerPays] == XRP(2000));
+
943 }
+
944
+
945 // It should be possible for gw to cross both of those offers.
+
946 env(offer(gw, XRP(2000), USD(1000)));
+
947 env.close();
+
948 env.require(offers(alice, 0));
+
949 env.require(offers(gw, 0));
+
950 env.require(offers(bob, 1));
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));
+
952 env(offer(gw, USD(1000), XRP(2000)));
+
953 env.close();
+
954 env.require(offers(bob, 0));
+
955 env.require(offers(gw, 0));
+
956 }
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 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();
+
958 // tfPassive -- cross only offers of better quality.
+
959 {
+
960 Env env(*this, features);
+
961
+
962 env.fund(startBalance, gw, "alice", "bob");
+
963 env.close();
+
964
+
965 env(trust("bob", USD(1000)));
+
966 env.close();
+
967
+
968 env(pay(gw, "bob", USD(1000)));
+
969 env(offer("alice", USD(500), XRP(1001)));
+
970 env.close();
+
971
+
972 env(offer("alice", USD(500), XRP(1000)));
+
973 env.close();
+
974
+
975 auto const aliceOffers = offersOnAccount(env, "alice");
+
976 BEAST_EXPECT(aliceOffers.size() == 2);
+
977
+
978 // bob creates a passive offer. That offer should cross one
+
979 // of alice's (the one with better quality) and leave alice's
+
980 // other offer untouched.
+
981 env(offer("bob", XRP(2000), USD(1000), tfPassive));
+
982 env.close();
+
983 env.require(offers("alice", 1));
984
-
985 auto const aliceOffers = offersOnAccount(env, alice);
-
986 BEAST_EXPECT(aliceOffers.size() == 1);
-
987 for (auto offerPtr : aliceOffers)
+
985 auto const bobOffers = offersOnAccount(env, "bob");
+
986 BEAST_EXPECT(bobOffers.size() == 1);
+
987 for (auto offerPtr : bobOffers)
988 {
989 auto const& offer = *offerPtr;
-
990 BEAST_EXPECT(offer[sfTakerGets] == XRP(2000));
-
991 BEAST_EXPECT(offer[sfTakerPays] == USD(1000));
+
990 BEAST_EXPECT(offer[sfTakerGets] == USD(499.5));
+
991 BEAST_EXPECT(offer[sfTakerPays] == XRP(999));
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 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 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(offer("alice", USD(500), XRP(1000)));
-
1037 env.close();
-
1038
-
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));
+
993 }
+
994 }
+
+
995
+
996 void
+
+ +
998 {
+
999 testcase("Malformed Detection");
+
1000
+
1001 using namespace jtx;
+
1002
+
1003 auto const startBalance = XRP(1000000);
+
1004 auto const gw = Account{"gateway"};
+
1005 auto const alice = Account{"alice"};
+
1006 auto const USD = gw["USD"];
+
1007
+
1008 Env env{*this, features};
+
1009
+
1010 env.fund(startBalance, gw, alice);
+
1011 env.close();
+
1012
+
1013 // Order that has invalid flags
+
1014 env(offer(alice, USD(1000), XRP(1000)),
+ + +
1017 env.require(
+
1018 balance(alice, startBalance), owners(alice, 0), offers(alice, 0));
+
1019
+
1020 // Order with incompatible flags
+
1021 env(offer(alice, USD(1000), XRP(1000)),
+ + +
1024 env.require(
+
1025 balance(alice, startBalance), owners(alice, 0), offers(alice, 0));
+
1026
+
1027 // Sell and buy the same asset
+
1028 {
+
1029 // Alice tries an XRP to XRP order:
+
1030 env(offer(alice, XRP(1000), XRP(1000)), ter(temBAD_OFFER));
+
1031 env.require(owners(alice, 0), offers(alice, 0));
+
1032
+
1033 // Alice tries an IOU to IOU order:
+
1034 env(trust(alice, USD(1000)), ter(tesSUCCESS));
+
1035 env(pay(gw, alice, USD(1000)), ter(tesSUCCESS));
+
1036 env(offer(alice, USD(1000), USD(1000)), ter(temREDUNDANT));
+
1037 env.require(owners(alice, 1), offers(alice, 0));
+
1038 }
+
1039
+
1040 // Offers with negative amounts
+
1041 {
+
1042 env(offer(alice, -USD(1000), XRP(1000)), ter(temBAD_OFFER));
+
1043 env.require(owners(alice, 1), offers(alice, 0));
+
1044
+
1045 env(offer(alice, USD(1000), -XRP(1000)), ter(temBAD_OFFER));
+
1046 env.require(owners(alice, 1), offers(alice, 0));
+
1047 }
1048
-
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");
+
1049 // Offer with a bad expiration
+
1050 {
+
1051 env(offer(alice, USD(1000), XRP(1000)),
+
1052 json(sfExpiration.fieldName, std::uint32_t(0)),
+ +
1054 env.require(owners(alice, 1), offers(alice, 0));
+
1055 }
+
1056
+
1057 // Offer with a bad offer sequence
+
1058 {
+
1059 env(offer(alice, USD(1000), XRP(1000)),
+
1060 json(jss::OfferSequence, std::uint32_t(0)),
+ +
1062 env.require(owners(alice, 1), offers(alice, 0));
+
1063 }
1064
-
1065 using namespace jtx;
-
1066
-
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 Env env{*this, features};
+
1065 // Use XRP as a currency code
+
1066 {
+
1067 auto const BAD = IOU(gw, badCurrency());
+
1068
+
1069 env(offer(alice, XRP(1000), BAD(1000)), ter(temBAD_CURRENCY));
+
1070 env.require(owners(alice, 1), offers(alice, 0));
+
1071 }
+
1072 }
+
1073
-
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 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 // 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));
+
1074 void
+
+ +
1076 {
+
1077 testcase("Offer Expiration");
+
1078
+
1079 using namespace jtx;
+
1080
+
1081 auto const gw = Account{"gateway"};
+
1082 auto const alice = Account{"alice"};
+
1083 auto const bob = Account{"bob"};
+
1084 auto const USD = gw["USD"];
+
1085
+
1086 auto const startBalance = XRP(1000000);
+
1087 auto const usdOffer = USD(1000);
+
1088 auto const xrpOffer = XRP(1000);
+
1089
+
1090 Env env{*this, features};
+
1091
+
1092 env.fund(startBalance, gw, alice, bob);
+
1093 env.close();
+
1094
+
1095 auto const f = env.current()->fees().base;
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 // 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 }
+
1097 env(trust(alice, usdOffer), ter(tesSUCCESS));
+
1098 env(pay(gw, alice, usdOffer), ter(tesSUCCESS));
+
1099 env.close();
+
1100 env.require(
+
1101 balance(alice, startBalance - f),
+
1102 balance(alice, usdOffer),
+
1103 offers(alice, 0),
+
1104 owners(alice, 1));
+
1105
+
1106 // Place an offer that should have already expired.
+
1107 // The DepositPreauth amendment changes the return code; adapt to that.
+
1108 bool const featPreauth{features[featureDepositPreauth]};
+
1109
+
1110 env(offer(alice, xrpOffer, usdOffer),
+
1111 json(sfExpiration.fieldName, lastClose(env)),
+
1112 ter(featPreauth ? TER{tecEXPIRED} : TER{tesSUCCESS}));
+
1113
+
1114 env.require(
+
1115 balance(alice, startBalance - f - f),
+
1116 balance(alice, usdOffer),
+
1117 offers(alice, 0),
+
1118 owners(alice, 1));
+
1119 env.close();
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 }
+
1121 // Add an offer that expires before the next ledger close
+
1122 env(offer(alice, xrpOffer, usdOffer),
+
1123 json(sfExpiration.fieldName, lastClose(env) + 1),
+
1124 ter(tesSUCCESS));
+
1125 env.require(
+
1126 balance(alice, startBalance - f - f - f),
+
1127 balance(alice, usdOffer),
+
1128 offers(alice, 1),
+
1129 owners(alice, 2));
+
1130
+
1131 // The offer expires (it's not removed yet)
+
1132 env.close();
+
1133 env.require(
+
1134 balance(alice, startBalance - f - f - f),
+
1135 balance(alice, usdOffer),
+
1136 offers(alice, 1),
+
1137 owners(alice, 2));
+
1138
+
1139 // Add offer - the expired offer is removed
+
1140 env(offer(bob, usdOffer, xrpOffer), ter(tesSUCCESS));
+
1141 env.require(
+
1142 balance(alice, startBalance - f - f - f),
+
1143 balance(alice, usdOffer),
+
1144 offers(alice, 0),
+
1145 owners(alice, 1),
+
1146 balance(bob, startBalance - f),
+
1147 balance(bob, USD(none)),
+
1148 offers(bob, 1),
+
1149 owners(bob, 1));
+
1150 }
-
1137
-
1138 void
-
- -
1140 {
-
1141 testcase("Offer Expiration");
-
1142
-
1143 using namespace jtx;
-
1144
-
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 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();
+
1151
+
1152 void
+
+ +
1154 {
+
1155 testcase("Unfunded Crossing");
+
1156
+
1157 using namespace jtx;
1158
-
1159 auto const f = env.current()->fees().base;
-
1160
-
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));
+
1159 auto const gw = Account{"gateway"};
+
1160 auto const USD = gw["USD"];
+
1161
+
1162 auto const usdOffer = USD(1000);
+
1163 auto const xrpOffer = XRP(1000);
+
1164
+
1165 Env env{*this, features};
+
1166
+
1167 env.fund(XRP(1000000), gw);
+
1168 env.close();
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));
+
1170 // The fee that's charged for transactions
+
1171 auto const f = env.current()->fees().base;
+
1172
+
1173 // Account is at the reserve, and will dip below once
+
1174 // fees are subtracted.
+
1175 env.fund(reserve(env, 0), "alice");
+
1176 env.close();
+
1177 env(offer("alice", usdOffer, xrpOffer), ter(tecUNFUNDED_OFFER));
+
1178 env.require(balance("alice", reserve(env, 0) - f), owners("alice", 0));
+
1179
+
1180 // Account has just enough for the reserve and the
+
1181 // fee.
+
1182 env.fund(reserve(env, 0) + f, "bob");
1183 env.close();
-
1184
-
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));
+
1184 env(offer("bob", usdOffer, xrpOffer), ter(tecUNFUNDED_OFFER));
+
1185 env.require(balance("bob", reserve(env, 0)), owners("bob", 0));
+
1186
+
1187 // Account has enough for the reserve, the fee and
+
1188 // the offer, and a bit more, but not enough for the
+
1189 // reserve after the offer is placed.
+
1190 env.fund(reserve(env, 0) + f + XRP(1), "carol");
+
1191 env.close();
+
1192 env(offer("carol", usdOffer, xrpOffer), ter(tecINSUF_RESERVE_OFFER));
+
1193 env.require(
+
1194 balance("carol", reserve(env, 0) + XRP(1)), owners("carol", 0));
+
1195
+
1196 // Account has enough for the reserve plus one
+
1197 // offer, and the fee.
+
1198 env.fund(reserve(env, 1) + f, "dan");
+
1199 env.close();
+
1200 env(offer("dan", usdOffer, xrpOffer), ter(tesSUCCESS));
+
1201 env.require(balance("dan", reserve(env, 1)), owners("dan", 1));
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 }
+
1203 // Account has enough for the reserve plus one
+
1204 // offer, the fee and the entire offer amount.
+
1205 env.fund(reserve(env, 1) + f + xrpOffer, "eve");
+
1206 env.close();
+
1207 env(offer("eve", usdOffer, xrpOffer), ter(tesSUCCESS));
+
1208 env.require(
+
1209 balance("eve", reserve(env, 1) + xrpOffer), owners("eve", 1));
+
1210 }
-
1215
-
1216 void
-
- -
1218 {
-
1219 testcase("Unfunded Crossing");
+
1211
+
1212 void
+
+
1213 testSelfCross(bool use_partner, FeatureBitset features)
+
1214 {
+
1215 testcase(
+
1216 std::string("Self-crossing") +
+
1217 (use_partner ? ", with partner account" : ""));
+
1218
+
1219 using namespace jtx;
1220
-
1221 using namespace jtx;
-
1222
-
1223 auto const gw = Account{"gateway"};
-
1224 auto const USD = gw["USD"];
+
1221 auto const gw = Account{"gateway"};
+
1222 auto const partner = Account{"partner"};
+
1223 auto const USD = gw["USD"];
+
1224 auto const BTC = gw["BTC"];
1225
-
1226 auto const usdOffer = USD(1000);
-
1227 auto const xrpOffer = XRP(1000);
+
1226 Env env{*this, features};
+
1227 env.close();
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 has just enough for the reserve and the
-
1245 // fee.
-
1246 env.fund(reserve(env, 0) + f, "bob");
-
1247 env.close();
-
1248 env(offer("bob", usdOffer, xrpOffer), ter(tecUNFUNDED_OFFER));
-
1249 env.require(balance("bob", reserve(env, 0)), owners("bob", 0));
+
1229 env.fund(XRP(10000), gw);
+
1230 if (use_partner)
+
1231 {
+
1232 env.fund(XRP(10000), partner);
+
1233 env.close();
+
1234 env(trust(partner, USD(100)));
+
1235 env(trust(partner, BTC(500)));
+
1236 env.close();
+
1237 env(pay(gw, partner, USD(100)));
+
1238 env(pay(gw, partner, BTC(500)));
+
1239 }
+
1240 auto const& account_to_test = use_partner ? partner : gw;
+
1241
+
1242 env.close();
+
1243 env.require(offers(account_to_test, 0));
+
1244
+
1245 // PART 1:
+
1246 // we will make two offers that can be used to bridge BTC to USD
+
1247 // through XRP
+
1248 env(offer(account_to_test, BTC(250), XRP(1000)));
+
1249 env.require(offers(account_to_test, 1));
1250
-
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, the fee and the entire offer amount.
-
1269 env.fund(reserve(env, 1) + f + xrpOffer, "eve");
-
1270 env.close();
-
1271 env(offer("eve", usdOffer, xrpOffer), ter(tesSUCCESS));
-
1272 env.require(
-
1273 balance("eve", reserve(env, 1) + xrpOffer), owners("eve", 1));
-
1274 }
+
1251 // validate that the book now shows a BTC for XRP offer
+
1252 BEAST_EXPECT(isOffer(env, account_to_test, BTC(250), XRP(1000)));
+
1253
+
1254 auto const secondLegSeq = env.seq(account_to_test);
+
1255 env(offer(account_to_test, XRP(1000), USD(50)));
+
1256 env.require(offers(account_to_test, 2));
+
1257
+
1258 // validate that the book also shows a XRP for USD offer
+
1259 BEAST_EXPECT(isOffer(env, account_to_test, XRP(1000), USD(50)));
+
1260
+
1261 // now make an offer that will cross and auto-bridge, meaning
+
1262 // the outstanding offers will be taken leaving us with none
+
1263 env(offer(account_to_test, USD(50), BTC(250)));
+
1264
+
1265 auto jrr = getBookOffers(env, USD, BTC);
+
1266 BEAST_EXPECT(jrr[jss::offers].isArray());
+
1267 BEAST_EXPECT(jrr[jss::offers].size() == 0);
+
1268
+
1269 jrr = getBookOffers(env, BTC, XRP);
+
1270 BEAST_EXPECT(jrr[jss::offers].isArray());
+
1271 BEAST_EXPECT(jrr[jss::offers].size() == 0);
+
1272
+
1273 // NOTE :
+
1274 // At this point, all offers are expected to be consumed.
+
1275 {
+
1276 auto acctOffers = offersOnAccount(env, account_to_test);
+
1277
+
1278 BEAST_EXPECT(acctOffers.size() == 0);
+
1279 for (auto const& offerPtr : acctOffers)
+
1280 {
+
1281 auto const& offer = *offerPtr;
+
1282 BEAST_EXPECT(offer[sfLedgerEntryType] == ltOFFER);
+
1283 BEAST_EXPECT(offer[sfTakerGets] == USD(0));
+
1284 BEAST_EXPECT(offer[sfTakerPays] == XRP(0));
+
1285 }
+
1286 }
+
1287
+
1288 // cancel that lingering second offer so that it doesn't interfere
+
1289 // with the next set of offers we test. This will not be needed once
+
1290 // the bridging bug is fixed
+
1291 env(offer_cancel(account_to_test, secondLegSeq));
+
1292 env.require(offers(account_to_test, 0));
+
1293
+
1294 // PART 2:
+
1295 // simple direct crossing BTC to USD and then USD to BTC which causes
+
1296 // the first offer to be replaced
+
1297 env(offer(account_to_test, BTC(250), USD(50)));
+
1298 env.require(offers(account_to_test, 1));
+
1299
+
1300 // validate that the book shows one BTC for USD offer and no USD for
+
1301 // BTC offers
+
1302 BEAST_EXPECT(isOffer(env, account_to_test, BTC(250), USD(50)));
+
1303
+
1304 jrr = getBookOffers(env, USD, BTC);
+
1305 BEAST_EXPECT(jrr[jss::offers].isArray());
+
1306 BEAST_EXPECT(jrr[jss::offers].size() == 0);
+
1307
+
1308 // this second offer would self-cross directly, so it causes the first
+
1309 // offer by the same owner/taker to be removed
+
1310 env(offer(account_to_test, USD(50), BTC(250)));
+
1311 env.require(offers(account_to_test, 1));
+
1312
+
1313 // validate that we now have just the second offer...the first
+
1314 // was removed
+
1315 jrr = getBookOffers(env, BTC, USD);
+
1316 BEAST_EXPECT(jrr[jss::offers].isArray());
+
1317 BEAST_EXPECT(jrr[jss::offers].size() == 0);
+
1318
+
1319 BEAST_EXPECT(isOffer(env, account_to_test, USD(50), BTC(250)));
+
1320 }
-
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 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 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 also shows a XRP for USD offer
-
1323 BEAST_EXPECT(isOffer(env, account_to_test, XRP(1000), USD(50)));
-
1324
-
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)));
+
1322 void
+
+ +
1324 {
+
1325 // This test creates an offer test for negative balance
+
1326 // with transfer fees and miniscule funds.
+
1327 testcase("Negative Balance");
1328
-
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 }
+
1329 using namespace jtx;
+
1330
+
1331 // This is one of the few tests where fixReducedOffersV2 changes the
+
1332 // results. So test both with and without fixReducedOffersV2.
+
1333 for (FeatureBitset localFeatures :
+
1334 {features - fixReducedOffersV2, features | fixReducedOffersV2})
+
1335 {
+
1336 Env env{*this, localFeatures};
+
1337
+
1338 auto const gw = Account{"gateway"};
+
1339 auto const alice = Account{"alice"};
+
1340 auto const bob = Account{"bob"};
+
1341 auto const USD = gw["USD"];
+
1342 auto const BTC = gw["BTC"];
+
1343
+
1344 // these *interesting* amounts were taken
+
1345 // from the original JS test that was ported here
+
1346 auto const gw_initial_balance = drops(1149999730);
+
1347 auto const alice_initial_balance = drops(499946999680);
+
1348 auto const bob_initial_balance = drops(10199999920);
+
1349 auto const small_amount =
+
1350 STAmount{bob["USD"].issue(), UINT64_C(2710505431213761), -33};
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)));
+
1352 env.fund(gw_initial_balance, gw);
+
1353 env.fund(alice_initial_balance, alice);
+
1354 env.fund(bob_initial_balance, bob);
+
1355 env.close();
+
1356
+
1357 env(rate(gw, 1.005));
+
1358
+
1359 env(trust(alice, USD(500)));
+
1360 env(trust(bob, USD(50)));
+
1361 env(trust(gw, alice["USD"](100)));
+
1362
+
1363 env(pay(gw, alice, alice["USD"](50)));
+
1364 env(pay(gw, bob, small_amount));
+
1365
+
1366 env(offer(alice, USD(50), XRP(150000)));
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 }
+
1368 // unfund the offer
+
1369 env(pay(alice, gw, USD(100)));
+
1370
+
1371 // drop the trust line (set to 0)
+
1372 env(trust(gw, alice["USD"](0)));
+
1373
+
1374 // verify balances
+
1375 auto jrr = ledgerEntryState(env, alice, gw, "USD");
+
1376 BEAST_EXPECT(
+
1377 jrr[jss::node][sfBalance.fieldName][jss::value] == "50");
+
1378
+
1379 jrr = ledgerEntryState(env, bob, gw, "USD");
+
1380 BEAST_EXPECT(
+
1381 jrr[jss::node][sfBalance.fieldName][jss::value] ==
+
1382 "-2710505431213761e-33");
+
1383
+
1384 // create crossing offer
+
1385 std::uint32_t const bobOfferSeq = env.seq(bob);
+
1386 env(offer(bob, XRP(2000), USD(1)));
+
1387
+
1388 if (localFeatures[fixReducedOffersV2])
+
1389 {
+
1390 // With the rounding introduced by fixReducedOffersV2, bob's
+
1391 // offer does not cross alice's offer and goes straight into
+
1392 // the ledger.
+
1393 jrr = ledgerEntryState(env, bob, gw, "USD");
+
1394 BEAST_EXPECT(
+
1395 jrr[jss::node][sfBalance.fieldName][jss::value] ==
+
1396 "-2710505431213761e-33");
+
1397
+
1398 Json::Value const bobOffer =
+
1399 ledgerEntryOffer(env, bob, bobOfferSeq)[jss::node];
+
1400 BEAST_EXPECT(bobOffer[sfTakerGets.jsonName][jss::value] == "1");
+
1401 BEAST_EXPECT(bobOffer[sfTakerPays.jsonName] == "2000000000");
+
1402 return;
+
1403 }
+
1404
+
1405 // verify balances again.
+
1406 //
+
1407 // NOTE:
+
1408 // Here a difference in the rounding modes of our two offer
+
1409 // crossing algorithms becomes apparent. The old offer crossing
+
1410 // would consume small_amount and transfer no XRP. The new offer
+
1411 // crossing transfers a single drop, rather than no drops.
+
1412 auto const crossingDelta = drops(1);
+
1413
+
1414 jrr = ledgerEntryState(env, alice, gw, "USD");
+
1415 BEAST_EXPECT(
+
1416 jrr[jss::node][sfBalance.fieldName][jss::value] == "50");
+
1417 BEAST_EXPECT(
+
1418 env.balance(alice, xrpIssue()) ==
+
1419 alice_initial_balance - env.current()->fees().base * 3 -
+
1420 crossingDelta);
+
1421
+
1422 jrr = ledgerEntryState(env, bob, gw, "USD");
+
1423 BEAST_EXPECT(
+
1424 jrr[jss::node][sfBalance.fieldName][jss::value] == "0");
+
1425 BEAST_EXPECT(
+
1426 env.balance(bob, xrpIssue()) ==
+
1427 bob_initial_balance - env.current()->fees().base * 2 +
+
1428 crossingDelta);
+
1429 }
+
1430 }
-
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 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 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(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(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");
+
1432 void
+
+
1433 testOfferCrossWithXRP(bool reverse_order, FeatureBitset features)
+
1434 {
+
1435 testcase(
+
1436 std::string("Offer Crossing with XRP, ") +
+
1437 (reverse_order ? "Reverse" : "Normal") + " order");
+
1438
+
1439 using namespace jtx;
+
1440
+
1441 Env env{*this, features};
1442
-
1443 jrr = ledgerEntryState(env, bob, gw, "USD");
-
1444 BEAST_EXPECT(
-
1445 jrr[jss::node][sfBalance.fieldName][jss::value] ==
-
1446 "-2710505431213761e-33");
+
1443 auto const gw = Account{"gateway"};
+
1444 auto const alice = Account{"alice"};
+
1445 auto const bob = Account{"bob"};
+
1446 auto const USD = gw["USD"];
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 // 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 }
+
1448 env.fund(XRP(10000), gw, alice, bob);
+
1449 env.close();
+
1450
+
1451 env(trust(alice, USD(1000)));
+
1452 env(trust(bob, USD(1000)));
+
1453
+
1454 env(pay(gw, alice, alice["USD"](500)));
+
1455
+
1456 if (reverse_order)
+
1457 env(offer(bob, USD(1), XRP(4000)));
+
1458
+
1459 env(offer(alice, XRP(150000), USD(50)));
+
1460
+
1461 if (!reverse_order)
+
1462 env(offer(bob, USD(1), XRP(4000)));
+
1463
+
1464 // Existing offer pays better than this wants.
+
1465 // Fully consume existing offer.
+
1466 // Pay 1 USD, get 4000 XRP.
+
1467
+
1468 auto jrr = ledgerEntryState(env, bob, gw, "USD");
+
1469 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-1");
+
1470 jrr = ledgerEntryRoot(env, bob);
+
1471 BEAST_EXPECT(
+
1472 jrr[jss::node][sfBalance.fieldName] ==
+
1473 to_string((XRP(10000) - XRP(reverse_order ? 4000 : 3000) -
+
1474 env.current()->fees().base * 2)
+
1475 .xrp()));
+
1476
+
1477 jrr = ledgerEntryState(env, alice, gw, "USD");
+
1478 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-499");
+
1479 jrr = ledgerEntryRoot(env, alice);
+
1480 BEAST_EXPECT(
+
1481 jrr[jss::node][sfBalance.fieldName] ==
+
1482 to_string((XRP(10000) + XRP(reverse_order ? 4000 : 3000) -
+
1483 env.current()->fees().base * 2)
+
1484 .xrp()));
+
1485 }
+
1486
+
1487 void
+
+ +
1489 {
+
1490 testcase("Offer Crossing with Limit Override");
+
1491
+
1492 using namespace jtx;
+
1493
+
1494 Env env{*this, features};
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 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.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 if (!reverse_order)
-
1526 env(offer(bob, USD(1), XRP(4000)));
+
1496 auto const gw = Account{"gateway"};
+
1497 auto const alice = Account{"alice"};
+
1498 auto const bob = Account{"bob"};
+
1499 auto const USD = gw["USD"];
+
1500
+
1501 env.fund(XRP(100000), gw, alice, bob);
+
1502 env.close();
+
1503
+
1504 env(trust(alice, USD(1000)));
+
1505
+
1506 env(pay(gw, alice, alice["USD"](500)));
+
1507
+
1508 env(offer(alice, XRP(150000), USD(50)));
+
1509 env(offer(bob, USD(1), XRP(3000)));
+
1510
+
1511 auto jrr = ledgerEntryState(env, bob, gw, "USD");
+
1512 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-1");
+
1513 jrr = ledgerEntryRoot(env, bob);
+
1514 BEAST_EXPECT(
+
1515 jrr[jss::node][sfBalance.fieldName] ==
+
1516 to_string((XRP(100000) - XRP(3000) - env.current()->fees().base * 1)
+
1517 .xrp()));
+
1518
+
1519 jrr = ledgerEntryState(env, alice, gw, "USD");
+
1520 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-499");
+
1521 jrr = ledgerEntryRoot(env, alice);
+
1522 BEAST_EXPECT(
+
1523 jrr[jss::node][sfBalance.fieldName] ==
+
1524 to_string((XRP(100000) + XRP(3000) - env.current()->fees().base * 2)
+
1525 .xrp()));
+
1526 }
+
1527
-
1528 // Existing offer pays better than this wants.
-
1529 // Fully consume existing offer.
-
1530 // Pay 1 USD, get 4000 XRP.
-
1531
-
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 }
+
1528 void
+
+ +
1530 {
+
1531 testcase("Offer Accept then Cancel.");
+
1532
+
1533 using namespace jtx;
+
1534
+
1535 Env env{*this, features};
+
1536
+
1537 auto const USD = env.master["USD"];
+
1538
+
1539 auto const nextOfferSeq = env.seq(env.master);
+
1540 env(offer(env.master, XRP(500), USD(100)));
+
1541 env.close();
+
1542
+
1543 env(offer_cancel(env.master, nextOfferSeq));
+
1544 BEAST_EXPECT(env.seq(env.master) == nextOfferSeq + 2);
+
1545
+
1546 // ledger_accept, call twice and verify no odd behavior
+
1547 env.close();
+
1548 env.close();
+
1549 BEAST_EXPECT(env.seq(env.master) == nextOfferSeq + 2);
+
1550 }
-
1550
-
1551 void
-
- -
1553 {
-
1554 testcase("Offer Crossing with Limit Override");
-
1555
-
1556 using namespace jtx;
-
1557
-
1558 Env env{*this, features};
-
1559
-
1560 auto const gw = Account{"gateway"};
+
1551
+
1552 void
+
+ +
1554 {
+
1555 testcase("Offer Cancel Past and Future Sequence.");
+
1556
+
1557 using namespace jtx;
+
1558
+
1559 Env env{*this, features};
+
1560
1561 auto const alice = Account{"alice"};
-
1562 auto const bob = Account{"bob"};
-
1563 auto const USD = gw["USD"];
-
1564
-
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)));
+
1562
+
1563 auto const nextOfferSeq = env.seq(env.master);
+
1564 env.fund(XRP(10000), alice);
+
1565 env.close();
+
1566
+
1567 env(offer_cancel(env.master, nextOfferSeq));
+
1568
+
1569 env(offer_cancel(env.master, env.seq(env.master)),
+
1571
-
1572 env(offer(alice, XRP(150000), USD(50)));
-
1573 env(offer(bob, USD(1), XRP(3000)));
+
1572 env(offer_cancel(env.master, env.seq(env.master) + 1),
+
1574
-
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()));
+
1575 env.close();
+
1576 }
+
+
1577
+
1578 void
+
+ +
1580 {
+
1581 testcase("Currency Conversion: Entire Offer");
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 }
-
+
1583 using namespace jtx;
+
1584
+
1585 Env env{*this, features};
+
1586
+
1587 auto const gw = Account{"gateway"};
+
1588 auto const alice = Account{"alice"};
+
1589 auto const bob = Account{"bob"};
+
1590 auto const USD = gw["USD"];
1591
-
1592 void
-
- -
1594 {
-
1595 testcase("Offer Accept then Cancel.");
-
1596
-
1597 using namespace jtx;
+
1592 env.fund(XRP(10000), gw, alice, bob);
+
1593 env.close();
+
1594 env.require(owners(bob, 0));
+
1595
+
1596 env(trust(alice, USD(100)));
+
1597 env(trust(bob, USD(1000)));
1598
-
1599 Env env{*this, features};
+
1599 env.require(owners(alice, 1), owners(bob, 1));
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 // ledger_accept, call twice and verify no odd behavior
-
1611 env.close();
-
1612 env.close();
-
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;
+
1601 env(pay(gw, alice, alice["USD"](100)));
+
1602 auto const bobOfferSeq = env.seq(bob);
+
1603 env(offer(bob, USD(100), XRP(500)));
+
1604
+
1605 env.require(owners(alice, 1), owners(bob, 2));
+
1606 auto jro = ledgerEntryOffer(env, bob, bobOfferSeq);
+
1607 BEAST_EXPECT(
+
1608 jro[jss::node][jss::TakerGets] == XRP(500).value().getText());
+
1609 BEAST_EXPECT(
+
1610 jro[jss::node][jss::TakerPays] ==
+
1611 USD(100).value().getJson(JsonOptions::none));
+
1612
+
1613 env(pay(alice, alice, XRP(500)), sendmax(USD(100)));
+
1614
+
1615 auto jrr = ledgerEntryState(env, alice, gw, "USD");
+
1616 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "0");
+
1617 jrr = ledgerEntryRoot(env, alice);
+
1618 BEAST_EXPECT(
+
1619 jrr[jss::node][sfBalance.fieldName] ==
+
1620 to_string((XRP(10000) + XRP(500) - env.current()->fees().base * 2)
+
1621 .xrp()));
1622
-
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),
- +
1623 jrr = ledgerEntryState(env, bob, gw, "USD");
+
1624 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-100");
+
1625
+
1626 jro = ledgerEntryOffer(env, bob, bobOfferSeq);
+
1627 BEAST_EXPECT(jro[jss::error] == "entryNotFound");
+
1628
+
1629 env.require(owners(alice, 1), owners(bob, 1));
+
1630 }
+
+
1631
+
1632 void
+
+ +
1634 {
+
1635 testcase("Currency Conversion: Offerer Into Debt");
+
1636
+
1637 using namespace jtx;
1638
-
1639 env.close();
-
1640 }
-
-
1641
-
1642 void
-
- -
1644 {
-
1645 testcase("Currency Conversion: Entire Offer");
-
1646
-
1647 using namespace jtx;
-
1648
-
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"];
+
1639 Env env{*this, features};
+
1640
+
1641 auto const alice = Account{"alice"};
+
1642 auto const bob = Account{"bob"};
+
1643 auto const carol = Account{"carol"};
+
1644
+
1645 env.fund(XRP(10000), alice, bob, carol);
+
1646 env.close();
+
1647
+
1648 env(trust(alice, carol["EUR"](2000)));
+
1649 env(trust(bob, alice["USD"](100)));
+
1650 env(trust(carol, bob["EUR"](1000)));
+
1651
+
1652 auto const bobOfferSeq = env.seq(bob);
+
1653 env(offer(bob, alice["USD"](50), carol["EUR"](200)),
+
1655
-
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.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)));
+
1656 env(offer(alice, carol["EUR"](200), alice["USD"](50)));
+
1657
+
1658 auto jro = ledgerEntryOffer(env, bob, bobOfferSeq);
+
1659 BEAST_EXPECT(jro[jss::error] == "entryNotFound");
+
1660 }
+
+
1661
+
1662 void
+
+ +
1664 {
+
1665 testcase("Currency Conversion: In Parts");
+
1666
+
1667 using namespace jtx;
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)));
+
1669 Env env{*this, features};
+
1670
+
1671 auto const gw = Account{"gateway"};
+
1672 auto const alice = Account{"alice"};
+
1673 auto const bob = Account{"bob"};
+
1674 auto const USD = gw["USD"];
+
1675
+
1676 env.fund(XRP(10000), gw, alice, bob);
+
1677 env.close();
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()));
+
1679 env(trust(alice, USD(200)));
+
1680 env(trust(bob, USD(1000)));
+
1681
+
1682 env(pay(gw, alice, alice["USD"](200)));
+
1683
+
1684 auto const bobOfferSeq = env.seq(bob);
+
1685 env(offer(bob, USD(100), XRP(500)));
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 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();
+
1687 env(pay(alice, alice, XRP(200)), sendmax(USD(100)));
+
1688
+
1689 // The previous payment reduced the remaining offer amount by 200 XRP
+
1690 auto jro = ledgerEntryOffer(env, bob, bobOfferSeq);
+
1691 BEAST_EXPECT(
+
1692 jro[jss::node][jss::TakerGets] == XRP(300).value().getText());
+
1693 BEAST_EXPECT(
+
1694 jro[jss::node][jss::TakerPays] ==
+
1695 USD(60).value().getJson(JsonOptions::none));
+
1696
+
1697 // the balance between alice and gw is 160 USD..200 less the 40 taken
+
1698 // by the offer
+
1699 auto jrr = ledgerEntryState(env, alice, gw, "USD");
+
1700 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-160");
+
1701 // alice now has 200 more XRP from the payment
+
1702 jrr = ledgerEntryRoot(env, alice);
+
1703 BEAST_EXPECT(
+
1704 jrr[jss::node][sfBalance.fieldName] ==
+
1705 to_string((XRP(10000) + XRP(200) - env.current()->fees().base * 2)
+
1706 .xrp()));
+
1707
+
1708 // bob got 40 USD from partial consumption of the offer
+
1709 jrr = ledgerEntryState(env, bob, gw, "USD");
+
1710 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-40");
1711
-
1712 env(trust(alice, carol["EUR"](2000)));
-
1713 env(trust(bob, alice["USD"](100)));
-
1714 env(trust(carol, bob["EUR"](1000)));
-
1715
-
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 }
+
1712 // Alice converts USD to XRP which should fail
+
1713 // due to PartialPayment.
+
1714 env(pay(alice, alice, XRP(600)),
+
1715 sendmax(USD(100)),
+ +
1717
+
1718 // Alice converts USD to XRP, should succeed because
+
1719 // we permit partial payment
+
1720 env(pay(alice, alice, XRP(600)),
+
1721 sendmax(USD(100)),
+ +
1723
+
1724 // Verify the offer was consumed
+
1725 jro = ledgerEntryOffer(env, bob, bobOfferSeq);
+
1726 BEAST_EXPECT(jro[jss::error] == "entryNotFound");
+
1727
+
1728 // verify balances look right after the partial payment
+
1729 // only 300 XRP should be have been payed since that's all
+
1730 // that remained in the offer from bob. The alice balance is now
+
1731 // 100 USD because another 60 USD were transferred to bob in the second
+
1732 // payment
+
1733 jrr = ledgerEntryState(env, alice, gw, "USD");
+
1734 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-100");
+
1735 jrr = ledgerEntryRoot(env, alice);
+
1736 BEAST_EXPECT(
+
1737 jrr[jss::node][sfBalance.fieldName] ==
+
1738 to_string((XRP(10000) + XRP(200) + XRP(300) -
+
1739 env.current()->fees().base * 4)
+
1740 .xrp()));
+
1741
+
1742 // bob now has 100 USD - 40 from the first payment and 60 from the
+
1743 // second (partial) payment
+
1744 jrr = ledgerEntryState(env, bob, gw, "USD");
+
1745 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-100");
+
1746 }
-
1725
-
1726 void
-
- -
1728 {
-
1729 testcase("Currency Conversion: In Parts");
-
1730
-
1731 using namespace jtx;
-
1732
-
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.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)));
+
1748 void
+
+ +
1750 {
+
1751 testcase("Cross Currency Payment: Start with XRP");
1752
-
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");
+
1753 using namespace jtx;
+
1754
+
1755 Env env{*this, features};
+
1756
+
1757 auto const gw = Account{"gateway"};
+
1758 auto const alice = Account{"alice"};
+
1759 auto const bob = Account{"bob"};
+
1760 auto const carol = Account{"carol"};
+
1761 auto const USD = gw["USD"];
+
1762
+
1763 env.fund(XRP(10000), gw, alice, bob, carol);
+
1764 env.close();
+
1765
+
1766 env(trust(carol, USD(1000)));
+
1767 env(trust(bob, USD(2000)));
+
1768
+
1769 env(pay(gw, carol, carol["USD"](500)));
+
1770
+
1771 auto const carolOfferSeq = env.seq(carol);
+
1772 env(offer(carol, XRP(500), USD(50)));
+
1773
+
1774 env(pay(alice, bob, USD(25)), sendmax(XRP(333)));
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)),
- +
1776 auto jrr = ledgerEntryState(env, bob, gw, "USD");
+
1777 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-25");
+
1778
+
1779 jrr = ledgerEntryState(env, carol, gw, "USD");
+
1780 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-475");
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 }
+
1782 auto jro = ledgerEntryOffer(env, carol, carolOfferSeq);
+
1783 BEAST_EXPECT(
+
1784 jro[jss::node][jss::TakerGets] ==
+
1785 USD(25).value().getJson(JsonOptions::none));
+
1786 BEAST_EXPECT(
+
1787 jro[jss::node][jss::TakerPays] == XRP(250).value().getText());
+
1788 }
-
1811
-
1812 void
-
- -
1814 {
-
1815 testcase("Cross Currency Payment: Start with XRP");
-
1816
-
1817 using namespace jtx;
-
1818
-
1819 Env env{*this, features};
+
1789
+
1790 void
+
+ +
1792 {
+
1793 testcase("Cross Currency Payment: End with XRP");
+
1794
+
1795 using namespace jtx;
+
1796
+
1797 Env env{*this, features};
+
1798
+
1799 auto const gw = Account{"gateway"};
+
1800 auto const alice = Account{"alice"};
+
1801 auto const bob = Account{"bob"};
+
1802 auto const carol = Account{"carol"};
+
1803 auto const USD = gw["USD"];
+
1804
+
1805 env.fund(XRP(10000), gw, alice, bob, carol);
+
1806 env.close();
+
1807
+
1808 env(trust(alice, USD(1000)));
+
1809 env(trust(carol, USD(2000)));
+
1810
+
1811 env(pay(gw, alice, alice["USD"](500)));
+
1812
+
1813 auto const carolOfferSeq = env.seq(carol);
+
1814 env(offer(carol, USD(50), XRP(500)));
+
1815
+
1816 env(pay(alice, bob, XRP(250)), sendmax(USD(333)));
+
1817
+
1818 auto jrr = ledgerEntryState(env, alice, gw, "USD");
+
1819 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-475");
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();
+
1821 jrr = ledgerEntryState(env, carol, gw, "USD");
+
1822 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-25");
+
1823
+
1824 jrr = ledgerEntryRoot(env, bob);
+
1825 BEAST_EXPECT(
+
1826 jrr[jss::node][sfBalance.fieldName] ==
+ +
1828 XRP(10000).value().mantissa() + XRP(250).value().mantissa()));
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)));
+
1830 auto jro = ledgerEntryOffer(env, carol, carolOfferSeq);
+
1831 BEAST_EXPECT(
+
1832 jro[jss::node][jss::TakerGets] == XRP(250).value().getText());
+
1833 BEAST_EXPECT(
+
1834 jro[jss::node][jss::TakerPays] ==
+
1835 USD(25).value().getJson(JsonOptions::none));
+
1836 }
+
1837
-
1838 env(pay(alice, bob, USD(25)), sendmax(XRP(333)));
-
1839
-
1840 auto jrr = ledgerEntryState(env, bob, gw, "USD");
-
1841 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-25");
+
1838 void
+
+ +
1840 {
+
1841 testcase("Cross Currency Payment: Bridged");
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");
+
1843 using namespace jtx;
+
1844
+
1845 Env env{*this, features};
+
1846
+
1847 auto const gw1 = Account{"gateway_1"};
+
1848 auto const gw2 = Account{"gateway_2"};
+
1849 auto const alice = Account{"alice"};
+
1850 auto const bob = Account{"bob"};
+
1851 auto const carol = Account{"carol"};
+
1852 auto const dan = Account{"dan"};
+
1853 auto const USD = gw1["USD"];
+
1854 auto const EUR = gw2["EUR"];
+
1855
+
1856 env.fund(XRP(10000), gw1, gw2, alice, bob, carol, dan);
+
1857 env.close();
1858
-
1859 using namespace jtx;
-
1860
-
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)));
+
1859 env(trust(alice, USD(1000)));
+
1860 env(trust(bob, EUR(1000)));
+
1861 env(trust(carol, USD(1000)));
+
1862 env(trust(dan, EUR(1000)));
+
1863
+
1864 env(pay(gw1, alice, alice["USD"](500)));
+
1865 env(pay(gw2, dan, dan["EUR"](400)));
+
1866
+
1867 auto const carolOfferSeq = env.seq(carol);
+
1868 env(offer(carol, USD(50), XRP(500)));
+
1869
+
1870 auto const danOfferSeq = env.seq(dan);
+
1871 env(offer(dan, XRP(500), EUR(50)));
+
1872
+ +
1874 jtp[0u][0u][jss::currency] = "XRP";
+
1875 env(pay(alice, bob, EUR(30)), json(jss::Paths, jtp), sendmax(USD(333)));
1876
-
1877 auto const carolOfferSeq = env.seq(carol);
-
1878 env(offer(carol, USD(50), XRP(500)));
+
1877 auto jrr = ledgerEntryState(env, alice, gw1, "USD");
+
1878 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "470");
1879
-
1880 env(pay(alice, bob, XRP(250)), sendmax(USD(333)));
-
1881
-
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());
+
1880 jrr = ledgerEntryState(env, bob, gw2, "EUR");
+
1881 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-30");
+
1882
+
1883 jrr = ledgerEntryState(env, carol, gw1, "USD");
+
1884 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-30");
+
1885
+
1886 jrr = ledgerEntryState(env, dan, gw2, "EUR");
+
1887 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-370");
+
1888
+
1889 auto jro = ledgerEntryOffer(env, carol, carolOfferSeq);
+
1890 BEAST_EXPECT(
+
1891 jro[jss::node][jss::TakerGets] == XRP(200).value().getText());
+
1892 BEAST_EXPECT(
+
1893 jro[jss::node][jss::TakerPays] ==
+
1894 USD(20).value().getJson(JsonOptions::none));
+
1895
+
1896 jro = ledgerEntryOffer(env, dan, danOfferSeq);
1897 BEAST_EXPECT(
-
1898 jro[jss::node][jss::TakerPays] ==
-
1899 USD(25).value().getJson(JsonOptions::none));
-
1900 }
+
1898 jro[jss::node][jss::TakerGets] ==
+
1899 gw2["EUR"](20).value().getJson(JsonOptions::none));
+
1900 BEAST_EXPECT(
+
1901 jro[jss::node][jss::TakerPays] == XRP(200).value().getText());
+
1902 }
-
1901
-
1902 void
-
- -
1904 {
-
1905 testcase("Cross Currency Payment: Bridged");
-
1906
-
1907 using namespace jtx;
-
1908
-
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 jrr = ledgerEntryState(env, alice, gw1, "USD");
-
1942 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "470");
-
1943
-
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 jro = ledgerEntryOffer(env, dan, danOfferSeq);
-
1961 BEAST_EXPECT(
-
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 }
+
1903
+
1904 void
+
+ +
1906 {
+
1907 // At least with Taker bridging, a sensitivity was identified if the
+
1908 // second leg goes dry before the first one. This test exercises that
+
1909 // case.
+
1910 testcase("Auto Bridged Second Leg Dry");
+
1911
+
1912 using namespace jtx;
+
1913 Env env(*this, features);
+
1914
+
1915 Account const alice{"alice"};
+
1916 Account const bob{"bob"};
+
1917 Account const carol{"carol"};
+
1918 Account const gw{"gateway"};
+
1919 auto const USD = gw["USD"];
+
1920 auto const EUR = gw["EUR"];
+
1921
+
1922 env.fund(XRP(100000000), alice, bob, carol, gw);
+
1923 env.close();
+
1924
+
1925 env.trust(USD(10), alice);
+
1926 env.close();
+
1927 env(pay(gw, alice, USD(10)));
+
1928 env.trust(USD(10), carol);
+
1929 env.close();
+
1930 env(pay(gw, carol, USD(3)));
+
1931
+
1932 env(offer(alice, EUR(2), XRP(1)));
+
1933 env(offer(alice, EUR(2), XRP(1)));
+
1934
+
1935 env(offer(alice, XRP(1), USD(4)));
+
1936 env(offer(carol, XRP(1), USD(3)));
+
1937 env.close();
+
1938
+
1939 // Bob offers to buy 10 USD for 10 EUR.
+
1940 // 1. He spends 2 EUR taking Alice's auto-bridged offers and
+
1941 // gets 4 USD for that.
+
1942 // 2. He spends another 2 EUR taking Alice's last EUR->XRP offer and
+
1943 // Carol's XRP-USD offer. He gets 3 USD for that.
+
1944 // The key for this test is that Alice's XRP->USD leg goes dry before
+
1945 // Alice's EUR->XRP. The XRP->USD leg is the second leg which showed
+
1946 // some sensitivity.
+
1947 env.trust(EUR(10), bob);
+
1948 env.close();
+
1949 env(pay(gw, bob, EUR(10)));
+
1950 env.close();
+
1951 env(offer(bob, USD(10), EUR(10)));
+
1952 env.close();
+
1953
+
1954 env.require(balance(bob, USD(7)));
+
1955 env.require(balance(bob, EUR(6)));
+
1956 env.require(offers(bob, 1));
+
1957 env.require(owners(bob, 3));
+
1958
+
1959 env.require(balance(alice, USD(6)));
+
1960 env.require(balance(alice, EUR(4)));
+
1961 env.require(offers(alice, 0));
+
1962 env.require(owners(alice, 2));
+
1963
+
1964 env.require(balance(carol, USD(0)));
+
1965 env.require(balance(carol, EUR(none)));
+
1966
+
1967 env.require(offers(carol, 0));
+
1968 env.require(owners(carol, 1));
+
1969 }
-
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");
+
1970
+
1971 void
+
+ +
1973 {
+
1974 testcase("Offer Fees Consume Funds");
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 env.fund(XRP(100000000), alice, bob, carol, gw);
-
1987 env.close();
+
1977
+
1978 Env env{*this, features};
+
1979
+
1980 auto const gw1 = Account{"gateway_1"};
+
1981 auto const gw2 = Account{"gateway_2"};
+
1982 auto const gw3 = Account{"gateway_3"};
+
1983 auto const alice = Account{"alice"};
+
1984 auto const bob = Account{"bob"};
+
1985 auto const USD1 = gw1["USD"];
+
1986 auto const USD2 = gw2["USD"];
+
1987 auto const USD3 = gw3["USD"];
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(offer(alice, EUR(2), XRP(1)));
-
1997 env(offer(alice, EUR(2), XRP(1)));
+
1989 // Provide micro amounts to compensate for fees to make results round
+
1990 // nice.
+
1991 // reserve: Alice has 3 entries in the ledger, via trust lines
+
1992 // fees:
+
1993 // 1 for each trust limit == 3 (alice < mtgox/amazon/bitstamp) +
+
1994 // 1 for payment == 4
+
1995 auto const starting_xrp = XRP(100) +
+
1996 env.current()->fees().accountReserve(3) +
+
1997 env.current()->fees().base * 4;
1998
-
1999 env(offer(alice, XRP(1), USD(4)));
-
2000 env(offer(carol, XRP(1), USD(3)));
-
2001 env.close();
-
2002
-
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)));
+
1999 env.fund(starting_xrp, gw1, gw2, gw3, alice, bob);
+
2000 env.close();
+
2001
+
2002 env(trust(alice, USD1(1000)));
+
2003 env(trust(alice, USD2(1000)));
+
2004 env(trust(alice, USD3(1000)));
+
2005 env(trust(bob, USD1(1000)));
+
2006 env(trust(bob, USD2(1000)));
+
2007
+
2008 env(pay(gw1, bob, bob["USD"](500)));
+
2009
+
2010 env(offer(bob, XRP(200), USD1(200)));
+
2011 // Alice has 350 fees - a reserve of 50 = 250 reserve = 100 available.
+
2012 // Ask for more than available to prove reserve works.
+
2013 env(offer(alice, USD1(200), XRP(200)));
+
2014
+
2015 auto jrr = ledgerEntryState(env, alice, gw1, "USD");
+
2016 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "100");
+
2017 jrr = ledgerEntryRoot(env, alice);
+
2018 BEAST_EXPECT(
+
2019 jrr[jss::node][sfBalance.fieldName] ==
+
2020 STAmount(env.current()->fees().accountReserve(3)).getText());
+
2021
+
2022 jrr = ledgerEntryState(env, bob, gw1, "USD");
+
2023 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-400");
+
2024 }
+
+
2025
+
2026 void
+
+ +
2028 {
+
2029 testcase("Offer Create, then Cross");
2030
-
2031 env.require(offers(carol, 0));
-
2032 env.require(owners(carol, 1));
-
2033 }
-
-
2034
-
2035 void
-
- -
2037 {
-
2038 testcase("Offer Fees Consume Funds");
-
2039
-
2040 using namespace jtx;
-
2041
-
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;
+
2031 using namespace jtx;
+
2032
+
2033 for (auto NumberSwitchOver : {false, true})
+
2034 {
+
2035 Env env{*this, features};
+
2036 if (NumberSwitchOver)
+
2037 env.enableFeature(fixUniversalNumber);
+
2038 else
+
2039 env.disableFeature(fixUniversalNumber);
+
2040
+
2041 auto const gw = Account{"gateway"};
+
2042 auto const alice = Account{"alice"};
+
2043 auto const bob = Account{"bob"};
+
2044 auto const USD = gw["USD"];
+
2045
+
2046 env.fund(XRP(10000), gw, alice, bob);
+
2047 env.close();
+
2048
+
2049 env(rate(gw, 1.005));
+
2050
+
2051 env(trust(alice, USD(1000)));
+
2052 env(trust(bob, USD(1000)));
+
2053 env(trust(gw, alice["USD"](50)));
+
2054
+
2055 env(pay(gw, bob, bob["USD"](1)));
+
2056 env(pay(alice, gw, USD(50)));
+
2057
+
2058 env(trust(gw, alice["USD"](0)));
+
2059
+
2060 env(offer(alice, USD(50), XRP(150000)));
+
2061 env(offer(bob, XRP(100), USD(0.1)));
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 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 jrr = ledgerEntryState(env, bob, gw1, "USD");
-
2087 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-400");
-
2088 }
+
2063 auto jrr = ledgerEntryState(env, alice, gw, "USD");
+
2064 BEAST_EXPECT(
+
2065 jrr[jss::node][sfBalance.fieldName][jss::value] ==
+
2066 "49.96666666666667");
+
2067
+
2068 jrr = ledgerEntryState(env, bob, gw, "USD");
+
2069 Json::Value const bobsUSD =
+
2070 jrr[jss::node][sfBalance.fieldName][jss::value];
+
2071 if (!NumberSwitchOver)
+
2072 {
+
2073 BEAST_EXPECT(bobsUSD == "-0.966500000033334");
+
2074 }
+
2075 else
+
2076 {
+
2077 BEAST_EXPECT(bobsUSD == "-0.9665000000333333");
+
2078 }
+
2079 }
+
2080 }
-
2089
-
2090 void
-
- -
2092 {
-
2093 testcase("Offer Create, then Cross");
-
2094
-
2095 using namespace jtx;
-
2096
-
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(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");
+
2081
+
2082 void
+
+ +
2084 {
+
2085 testcase("Offer tfSell: Basic Sell");
+
2086
+
2087 using namespace jtx;
+
2088
+
2089 Env env{*this, features};
+
2090
+
2091 auto const gw = Account{"gateway"};
+
2092 auto const alice = Account{"alice"};
+
2093 auto const bob = Account{"bob"};
+
2094 auto const USD = gw["USD"];
+
2095
+
2096 auto const starting_xrp = XRP(100) +
+
2097 env.current()->fees().accountReserve(1) +
+
2098 env.current()->fees().base * 2;
+
2099
+
2100 env.fund(starting_xrp, gw, alice, bob);
+
2101 env.close();
+
2102
+
2103 env(trust(alice, USD(1000)));
+
2104 env(trust(bob, USD(1000)));
+
2105
+
2106 env(pay(gw, bob, bob["USD"](500)));
+
2107
+
2108 env(offer(bob, XRP(200), USD(200)), json(jss::Flags, tfSell));
+
2109 // Alice has 350 + fees - a reserve of 50 = 250 reserve = 100 available.
+
2110 // Alice has 350 + fees - a reserve of 50 = 250 reserve = 100 available.
+
2111 // Ask for more than available to prove reserve works.
+
2112 env(offer(alice, USD(200), XRP(200)), json(jss::Flags, tfSell));
+
2113
+
2114 auto jrr = ledgerEntryState(env, alice, gw, "USD");
+
2115 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-100");
+
2116 jrr = ledgerEntryRoot(env, alice);
+
2117 BEAST_EXPECT(
+
2118 jrr[jss::node][sfBalance.fieldName] ==
+
2119 STAmount(env.current()->fees().accountReserve(1)).getText());
+
2120
+
2121 jrr = ledgerEntryState(env, bob, gw, "USD");
+
2122 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-400");
+
2123 }
+
+
2124
+
2125 void
+
+ +
2127 {
+
2128 testcase("Offer tfSell: 2x Sell Exceed Limit");
+
2129
+
2130 using namespace jtx;
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 }
-
+
2132 Env env{*this, features};
+
2133
+
2134 auto const gw = Account{"gateway"};
+
2135 auto const alice = Account{"alice"};
+
2136 auto const bob = Account{"bob"};
+
2137 auto const USD = gw["USD"];
+
2138
+
2139 auto const starting_xrp = XRP(100) +
+
2140 env.current()->fees().accountReserve(1) +
+
2141 env.current()->fees().base * 2;
+
2142
+
2143 env.fund(starting_xrp, gw, alice, bob);
+
2144 env.close();
2145
-
2146 void
-
- -
2148 {
-
2149 testcase("Offer tfSell: Basic Sell");
+
2146 env(trust(alice, USD(150)));
+
2147 env(trust(bob, USD(1000)));
+
2148
+
2149 env(pay(gw, bob, bob["USD"](500)));
2150
-
2151 using namespace jtx;
-
2152
-
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 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 env(trust(alice, USD(1000)));
-
2168 env(trust(bob, USD(1000)));
+
2151 env(offer(bob, XRP(100), USD(200)));
+
2152 // Alice has 350 fees - a reserve of 50 = 250 reserve = 100 available.
+
2153 // Ask for more than available to prove reserve works.
+
2154 // Taker pays 100 USD for 100 XRP.
+
2155 // Selling XRP.
+
2156 // Will sell all 100 XRP and get more USD than asked for.
+
2157 env(offer(alice, USD(100), XRP(100)), json(jss::Flags, tfSell));
+
2158
+
2159 auto jrr = ledgerEntryState(env, alice, gw, "USD");
+
2160 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-200");
+
2161 jrr = ledgerEntryRoot(env, alice);
+
2162 BEAST_EXPECT(
+
2163 jrr[jss::node][sfBalance.fieldName] ==
+
2164 STAmount(env.current()->fees().accountReserve(1)).getText());
+
2165
+
2166 jrr = ledgerEntryState(env, bob, gw, "USD");
+
2167 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-300");
+
2168 }
+
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());
+
2170 void
+
+ +
2172 {
+
2173 testcase("Client Issue #535: Gateway Cross Currency");
+
2174
+
2175 using namespace jtx;
+
2176
+
2177 Env env{*this, features};
+
2178
+
2179 auto const gw = Account{"gateway"};
+
2180 auto const alice = Account{"alice"};
+
2181 auto const bob = Account{"bob"};
+
2182 auto const XTS = gw["XTS"];
+
2183 auto const XXX = gw["XXX"];
2184
-
2185 jrr = ledgerEntryState(env, bob, gw, "USD");
-
2186 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-400");
-
2187 }
-
+
2185 auto const starting_xrp = XRP(100.1) +
+
2186 env.current()->fees().accountReserve(1) +
+
2187 env.current()->fees().base * 2;
2188
-
2189 void
-
- -
2191 {
-
2192 testcase("Offer tfSell: 2x Sell Exceed Limit");
-
2193
-
2194 using namespace jtx;
-
2195
-
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 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 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 jrr = ledgerEntryState(env, bob, gw, "USD");
-
2231 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-300");
-
2232 }
+
2189 env.fund(starting_xrp, gw, alice, bob);
+
2190 env.close();
+
2191
+
2192 env(trust(alice, XTS(1000)));
+
2193 env(trust(alice, XXX(1000)));
+
2194 env(trust(bob, XTS(1000)));
+
2195 env(trust(bob, XXX(1000)));
+
2196
+
2197 env(pay(gw, alice, alice["XTS"](100)));
+
2198 env(pay(gw, alice, alice["XXX"](100)));
+
2199 env(pay(gw, bob, bob["XTS"](100)));
+
2200 env(pay(gw, bob, bob["XXX"](100)));
+
2201
+
2202 env(offer(alice, XTS(100), XXX(100)));
+
2203
+
2204 // WS client is used here because the RPC client could not
+
2205 // be convinced to pass the build_path argument
+
2206 auto wsc = makeWSClient(env.app().config());
+
2207 Json::Value payment;
+
2208 payment[jss::secret] = toBase58(generateSeed("bob"));
+
2209 payment[jss::id] = env.seq(bob);
+
2210 payment[jss::build_path] = true;
+
2211 payment[jss::tx_json] = pay(bob, bob, bob["XXX"](1));
+
2212 payment[jss::tx_json][jss::Sequence] =
+
2213 env.current()
+
2214 ->read(keylet::account(bob.id()))
+
2215 ->getFieldU32(sfSequence);
+
2216 payment[jss::tx_json][jss::Fee] = to_string(env.current()->fees().base);
+
2217 payment[jss::tx_json][jss::SendMax] =
+
2218 bob["XTS"](1.5).value().getJson(JsonOptions::none);
+
2219 auto jrr = wsc->invoke("submit", payment);
+
2220 BEAST_EXPECT(jrr[jss::status] == "success");
+
2221 BEAST_EXPECT(jrr[jss::result][jss::engine_result] == "tesSUCCESS");
+
2222 if (wsc->version() == 2)
+
2223 {
+
2224 BEAST_EXPECT(
+
2225 jrr.isMember(jss::jsonrpc) && jrr[jss::jsonrpc] == "2.0");
+
2226 BEAST_EXPECT(
+
2227 jrr.isMember(jss::ripplerpc) && jrr[jss::ripplerpc] == "2.0");
+
2228 BEAST_EXPECT(jrr.isMember(jss::id) && jrr[jss::id] == 5);
+
2229 }
+
2230
+
2231 jrr = ledgerEntryState(env, alice, gw, "XTS");
+
2232 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-101");
+
2233 jrr = ledgerEntryState(env, alice, gw, "XXX");
+
2234 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-99");
+
2235
+
2236 jrr = ledgerEntryState(env, bob, gw, "XTS");
+
2237 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-99");
+
2238 jrr = ledgerEntryState(env, bob, gw, "XXX");
+
2239 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "-101");
+
2240 }
-
2233
-
2234 void
-
- -
2236 {
-
2237 testcase("Client Issue #535: Gateway Cross Currency");
-
2238
-
2239 using namespace jtx;
-
2240
-
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 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)));
+
2241
+
2242 // Helper function that validates a *defaulted* trustline: one that has
+
2243 // no unusual flags set and doesn't have high or low limits set. Such a
+
2244 // trustline may have an actual balance (it can be created automatically
+
2245 // if a user places an offer to acquire an IOU for which they don't have
+
2246 // a trust line defined). If the trustline is not defaulted then the tests
+
2247 // will not pass.
+
2248 void
+
+ +
2250 jtx::Env& env,
+
2251 jtx::Account const& account,
+
2252 jtx::PrettyAmount const& expectBalance)
+
2253 {
+
2254 auto const sleTrust =
+
2255 env.le(keylet::line(account.id(), expectBalance.value().issue()));
+
2256 BEAST_EXPECT(sleTrust);
+
2257 if (sleTrust)
+
2258 {
+
2259 Issue const issue = expectBalance.value().issue();
+
2260 bool const accountLow = account.id() < issue.account;
+
2261
+
2262 STAmount low{issue};
+
2263 STAmount high{issue};
+
2264
+
2265 low.setIssuer(accountLow ? account.id() : issue.account);
+
2266 high.setIssuer(accountLow ? issue.account : account.id());
2267
-
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");
+
2268 BEAST_EXPECT(sleTrust->getFieldAmount(sfLowLimit) == low);
+
2269 BEAST_EXPECT(sleTrust->getFieldAmount(sfHighLimit) == high);
+
2270
+
2271 STAmount actualBalance{sleTrust->getFieldAmount(sfBalance)};
+
2272 if (!accountLow)
+
2273 actualBalance.negate();
+
2274
+
2275 BEAST_EXPECT(actualBalance == expectBalance);
+
2276 }
+
2277 }
+
+
2278
+
2279 void
+
+ +
2281 {
+
2282 // Test a number of different corner cases regarding adding a
+
2283 // possibly crossable offer to an account. The test is table
+
2284 // driven so it should be easy to add or remove tests.
+
2285 testcase("Partial Crossing");
+
2286
+
2287 using namespace jtx;
+
2288
+
2289 auto const gw = Account("gateway");
+
2290 auto const USD = gw["USD"];
+
2291
+
2292 Env env{*this, features};
+
2293
+
2294 env.fund(XRP(10000000), gw);
+
2295 env.close();
+
2296
+
2297 // The fee that's charged for transactions
+
2298 auto const f = env.current()->fees().base;
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 }
-
-
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(actualBalance == expectBalance);
-
2340 }
-
2341 }
-
-
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 env.fund(XRP(10000000), gw);
-
2359 env.close();
+
2300 // To keep things simple all offers are 1 : 1 for XRP : USD.
+
2301 enum preTrustType { noPreTrust, gwPreTrust, acctPreTrust };
+
2302 struct TestData
+
2303 {
+
2304 std::string account; // Account operated on
+
2305 STAmount fundXrp; // Account funded with
+
2306 int bookAmount; // USD -> XRP offer on the books
+
2307 preTrustType preTrust; // If true, pre-establish trust line
+
2308 int offerAmount; // Account offers this much XRP -> USD
+
2309 TER tec; // Returned tec code
+
2310 STAmount spentXrp; // Amount removed from fundXrp
+
2311 PrettyAmount balanceUsd; // Balance on account end
+
2312 int offers; // Offers on account
+
2313 int owners; // Owners on account
+
2314 };
+
2315
+
2316 // clang-format off
+
2317 TestData const tests[]{
+
2318 // acct fundXrp bookAmt preTrust offerAmt tec spentXrp balanceUSD offers owners
+
2319 {"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.
+
2320 {"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.
+
2321 {"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.
+
2322 {"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.
+
2323 {"eve", reserve(env, 1) + 0 * f, 0, noPreTrust, 1000, tesSUCCESS, f, USD( 0), 1, 1}, // No offer to cross
+
2324 {"flo", reserve(env, 1) + 0 * f, 1, noPreTrust, 1000, tesSUCCESS, XRP( 1) + f, USD( 1), 0, 1},
+
2325 {"gay", reserve(env, 1) + 1 * f, 1000, noPreTrust, 1000, tesSUCCESS, XRP( 50) + f, USD( 50), 0, 1},
+
2326 {"hye", XRP(1000) + 1 * f, 1000, noPreTrust, 1000, tesSUCCESS, XRP( 800) + f, USD( 800), 0, 1},
+
2327 {"ivy", XRP( 1) + reserve(env, 1) + 1 * f, 1, noPreTrust, 1000, tesSUCCESS, XRP( 1) + f, USD( 1), 0, 1},
+
2328 {"joy", XRP( 1) + reserve(env, 2) + 1 * f, 1, noPreTrust, 1000, tesSUCCESS, XRP( 1) + f, USD( 1), 1, 2},
+
2329 {"kim", XRP( 900) + reserve(env, 2) + 1 * f, 999, noPreTrust, 1000, tesSUCCESS, XRP( 999) + f, USD( 999), 0, 1},
+
2330 {"liz", XRP( 998) + reserve(env, 0) + 1 * f, 999, noPreTrust, 1000, tesSUCCESS, XRP( 998) + f, USD( 998), 0, 1},
+
2331 {"meg", XRP( 998) + reserve(env, 1) + 1 * f, 999, noPreTrust, 1000, tesSUCCESS, XRP( 999) + f, USD( 999), 0, 1},
+
2332 {"nia", XRP( 998) + reserve(env, 2) + 1 * f, 999, noPreTrust, 1000, tesSUCCESS, XRP( 999) + f, USD( 999), 1, 2},
+
2333 {"ova", XRP( 999) + reserve(env, 0) + 1 * f, 1000, noPreTrust, 1000, tesSUCCESS, XRP( 999) + f, USD( 999), 0, 1},
+
2334 {"pam", XRP( 999) + reserve(env, 1) + 1 * f, 1000, noPreTrust, 1000, tesSUCCESS, XRP(1000) + f, USD( 1000), 0, 1},
+
2335 {"rae", XRP( 999) + reserve(env, 2) + 1 * f, 1000, noPreTrust, 1000, tesSUCCESS, XRP(1000) + f, USD( 1000), 0, 1},
+
2336 {"sue", XRP(1000) + reserve(env, 2) + 1 * f, 0, noPreTrust, 1000, tesSUCCESS, f, USD( 0), 1, 1},
+
2337 //---------------- Pre-established trust lines ---------------------
+
2338 {"abe", reserve(env, 0) + 0 * f, 1, gwPreTrust, 1000, tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
+
2339 {"bud", reserve(env, 0) + 1 * f, 1, gwPreTrust, 1000, tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
+
2340 {"che", reserve(env, 0) + 2 * f, 0, gwPreTrust, 1000, tecINSUF_RESERVE_OFFER, f, USD( 0), 0, 0},
+
2341 {"dan", drops(10) + reserve(env, 0) + 1 * f, 1, gwPreTrust, 1000, tesSUCCESS, drops(10) + f, USD(0.00001), 0, 0},
+
2342 {"eli", XRP( 20) + reserve(env, 0) + 1 * f, 1000, gwPreTrust, 1000, tesSUCCESS, XRP(20) + 1 * f, USD( 20), 0, 0},
+
2343 {"fyn", reserve(env, 1) + 0 * f, 0, gwPreTrust, 1000, tesSUCCESS, f, USD( 0), 1, 1},
+
2344 {"gar", reserve(env, 1) + 0 * f, 1, gwPreTrust, 1000, tesSUCCESS, XRP( 1) + f, USD( 1), 1, 1},
+
2345 {"hal", reserve(env, 1) + 1 * f, 1, gwPreTrust, 1000, tesSUCCESS, XRP( 1) + f, USD( 1), 1, 1},
+
2346
+
2347 {"ned", reserve(env, 1) + 0 * f, 1, acctPreTrust, 1000, tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
+
2348 {"ole", reserve(env, 1) + 1 * f, 1, acctPreTrust, 1000, tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
+
2349 {"pat", reserve(env, 1) + 2 * f, 0, acctPreTrust, 1000, tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
+
2350 {"quy", reserve(env, 1) + 2 * f, 1, acctPreTrust, 1000, tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
+
2351 {"ron", reserve(env, 1) + 3 * f, 0, acctPreTrust, 1000, tecINSUF_RESERVE_OFFER, 2 * f, USD( 0), 0, 1},
+
2352 {"syd", drops(10) + reserve(env, 1) + 2 * f, 1, acctPreTrust, 1000, tesSUCCESS, drops(10) + 2 * f, USD(0.00001), 0, 1},
+
2353 {"ted", XRP( 20) + reserve(env, 1) + 2 * f, 1000, acctPreTrust, 1000, tesSUCCESS, XRP(20) + 2 * f, USD( 20), 0, 1},
+
2354 {"uli", reserve(env, 2) + 0 * f, 0, acctPreTrust, 1000, tecINSUF_RESERVE_OFFER, 2 * f, USD( 0), 0, 1},
+
2355 {"vic", reserve(env, 2) + 0 * f, 1, acctPreTrust, 1000, tesSUCCESS, XRP( 1) + 2 * f, USD( 1), 0, 1},
+
2356 {"wes", reserve(env, 2) + 1 * f, 0, acctPreTrust, 1000, tesSUCCESS, 2 * f, USD( 0), 1, 2},
+
2357 {"xan", reserve(env, 2) + 1 * f, 1, acctPreTrust, 1000, tesSUCCESS, XRP( 1) + 2 * f, USD( 1), 1, 2},
+
2358 };
+
2359 // clang-format on
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 // 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();
+
2361 for (auto const& t : tests)
+
2362 {
+
2363 auto const acct = Account(t.account);
+
2364 env.fund(t.fundXrp, acct);
+
2365 env.close();
+
2366
+
2367 // Make sure gateway has no current offers.
+
2368 env.require(offers(gw, 0));
+
2369
+
2370 // The gateway optionally creates an offer that would be crossed.
+
2371 auto const book = t.bookAmount;
+
2372 if (book)
+
2373 env(offer(gw, XRP(book), USD(book)));
+
2374 env.close();
+
2375 std::uint32_t const gwOfferSeq = env.seq(gw) - 1;
+
2376
+
2377 // Optionally pre-establish a trustline between gw and acct.
+
2378 if (t.preTrust == gwPreTrust)
+
2379 env(trust(gw, acct["USD"](1)));
+
2380 env.close();
+
2381
+
2382 // Optionally pre-establish a trustline between acct and gw.
+
2383 // Note this is not really part of the test, so we expect there
+
2384 // to be enough XRP reserve for acct to create the trust line.
+
2385 if (t.preTrust == acctPreTrust)
+
2386 env(trust(acct, USD(1)));
+
2387 env.close();
+
2388
+
2389 {
+
2390 // Acct creates an offer. This is the heart of the test.
+
2391 auto const acctOffer = t.offerAmount;
+
2392 env(offer(acct, USD(acctOffer), XRP(acctOffer)), ter(t.tec));
+
2393 env.close();
+
2394 }
+
2395 std::uint32_t const acctOfferSeq = env.seq(acct) - 1;
+
2396
+
2397 BEAST_EXPECT(env.balance(acct, USD.issue()) == t.balanceUsd);
+
2398 BEAST_EXPECT(
+
2399 env.balance(acct, xrpIssue()) == t.fundXrp - t.spentXrp);
+
2400 env.require(offers(acct, t.offers));
+
2401 env.require(owners(acct, t.owners));
+
2402
+
2403 auto acctOffers = offersOnAccount(env, acct);
+
2404 BEAST_EXPECT(acctOffers.size() == t.offers);
+
2405 if (acctOffers.size() && t.offers)
+
2406 {
+
2407 auto const& acctOffer = *(acctOffers.front());
+
2408
+
2409 auto const leftover = t.offerAmount - t.bookAmount;
+
2410 BEAST_EXPECT(acctOffer[sfTakerGets] == XRP(leftover));
+
2411 BEAST_EXPECT(acctOffer[sfTakerPays] == USD(leftover));
+
2412 }
+
2413
+
2414 if (t.preTrust == noPreTrust)
+
2415 {
+
2416 if (t.balanceUsd.value().signum())
+
2417 {
+
2418 // Verify the correct contents of the trustline
+
2419 verifyDefaultTrustline(env, acct, t.balanceUsd);
+
2420 }
+
2421 else
+
2422 {
+
2423 // Verify that no trustline was created.
+
2424 auto const sleTrust =
+
2425 env.le(keylet::line(acct, USD.issue()));
+
2426 BEAST_EXPECT(!sleTrust);
+
2427 }
+
2428 }
+
2429
+
2430 // Give the next loop a clean slate by canceling any left-overs
+
2431 // in the offers.
+
2432 env(offer_cancel(acct, acctOfferSeq));
+
2433 env(offer_cancel(gw, gwOfferSeq));
+
2434 env.close();
+
2435 }
+
2436 }
+
+
2437
+
2438 void
+
+ +
2440 {
+
2441 testcase("XRP Direct Crossing");
+
2442
+
2443 using namespace jtx;
+
2444
+
2445 auto const gw = Account("gateway");
+
2446 auto const alice = Account("alice");
+
2447 auto const bob = Account("bob");
+
2448 auto const USD = gw["USD"];
+
2449
+
2450 auto const usdOffer = USD(1000);
+
2451 auto const xrpOffer = XRP(1000);
2452
-
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;
+
2453 Env env{*this, features};
+
2454
+
2455 env.fund(XRP(1000000), gw, bob);
+
2456 env.close();
+
2457
+
2458 // The fee that's charged for transactions.
+
2459 auto const fee = env.current()->fees().base;
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 }
-
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;
+
2461 // alice's account has enough for the reserve, one trust line plus two
+
2462 // offers, and two fees.
+
2463 env.fund(reserve(env, 2) + fee * 2, alice);
+
2464 env.close();
+
2465
+
2466 env(trust(alice, usdOffer));
+
2467
+
2468 env.close();
+
2469
+
2470 env(pay(gw, alice, usdOffer));
+
2471 env.close();
+
2472 env.require(balance(alice, usdOffer), offers(alice, 0), offers(bob, 0));
+
2473
+
2474 // The scenario:
+
2475 // o alice has USD but wants XRP.
+
2476 // o bob has XRP but wants USD.
+
2477 auto const alicesXRP = env.balance(alice);
+
2478 auto const bobsXRP = env.balance(bob);
+
2479
+
2480 env(offer(alice, xrpOffer, usdOffer));
+
2481 env.close();
+
2482 env(offer(bob, usdOffer, xrpOffer));
+
2483
+
2484 env.close();
+
2485 env.require(
+
2486 balance(alice, USD(0)),
+
2487 balance(bob, usdOffer),
+
2488 balance(alice, alicesXRP + xrpOffer - fee),
+
2489 balance(bob, bobsXRP - xrpOffer - fee),
+
2490 offers(alice, 0),
+
2491 offers(bob, 0));
+
2492
+
2493 verifyDefaultTrustline(env, bob, usdOffer);
+
2494
+
2495 // Make two more offers that leave one of the offers non-dry.
+
2496 env(offer(alice, USD(999), XRP(999)));
+
2497 env(offer(bob, xrpOffer, usdOffer));
+
2498
+
2499 env.close();
+
2500 env.require(balance(alice, USD(999)));
+
2501 env.require(balance(bob, USD(1)));
+
2502 env.require(offers(alice, 0));
+
2503 verifyDefaultTrustline(env, bob, USD(1));
+
2504 {
+
2505 auto const bobsOffers = offersOnAccount(env, bob);
+
2506 BEAST_EXPECT(bobsOffers.size() == 1);
+
2507 auto const& bobsOffer = *(bobsOffers.front());
2508
-
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 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();
+
2509 BEAST_EXPECT(bobsOffer[sfLedgerEntryType] == ltOFFER);
+
2510 BEAST_EXPECT(bobsOffer[sfTakerGets] == USD(1));
+
2511 BEAST_EXPECT(bobsOffer[sfTakerPays] == XRP(1));
+
2512 }
+
2513 }
+
+
2514
+
2515 void
+
+ +
2517 {
+
2518 testcase("Direct Crossing");
+
2519
+
2520 using namespace jtx;
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 env.close();
-
2533
-
2534 env(pay(gw, alice, usdOffer));
-
2535 env.close();
-
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());
+
2522 auto const gw = Account("gateway");
+
2523 auto const alice = Account("alice");
+
2524 auto const bob = Account("bob");
+
2525 auto const USD = gw["USD"];
+
2526 auto const EUR = gw["EUR"];
+
2527
+
2528 auto const usdOffer = USD(1000);
+
2529 auto const eurOffer = EUR(1000);
+
2530
+
2531 Env env{*this, features};
+
2532
+
2533 env.fund(XRP(1000000), gw);
+
2534 env.close();
+
2535
+
2536 // The fee that's charged for transactions.
+
2537 auto const fee = env.current()->fees().base;
+
2538
+
2539 // Each account has enough for the reserve, two trust lines, one
+
2540 // offer, and two fees.
+
2541 env.fund(reserve(env, 3) + fee * 3, alice);
+
2542 env.fund(reserve(env, 3) + fee * 2, bob);
+
2543 env.close();
+
2544
+
2545 env(trust(alice, usdOffer));
+
2546 env(trust(bob, eurOffer));
+
2547 env.close();
+
2548
+
2549 env(pay(gw, alice, usdOffer));
+
2550 env(pay(gw, bob, eurOffer));
+
2551 env.close();
+
2552
+
2553 env.require(balance(alice, usdOffer), balance(bob, eurOffer));
+
2554
+
2555 // The scenario:
+
2556 // o alice has USD but wants EUR.
+
2557 // o bob has EUR but wants USD.
+
2558 env(offer(alice, eurOffer, usdOffer));
+
2559 env(offer(bob, usdOffer, eurOffer));
+
2560
+
2561 env.close();
+
2562 env.require(
+
2563 balance(alice, eurOffer),
+
2564 balance(bob, usdOffer),
+
2565 offers(alice, 0),
+
2566 offers(bob, 0));
+
2567
+
2568 // Alice's offer crossing created a default EUR trustline and
+
2569 // Bob's offer crossing created a default USD trustline:
+
2570 verifyDefaultTrustline(env, alice, eurOffer);
+
2571 verifyDefaultTrustline(env, bob, usdOffer);
2572
-
2573 BEAST_EXPECT(bobsOffer[sfLedgerEntryType] == ltOFFER);
-
2574 BEAST_EXPECT(bobsOffer[sfTakerGets] == USD(1));
-
2575 BEAST_EXPECT(bobsOffer[sfTakerPays] == XRP(1));
-
2576 }
-
2577 }
-
+
2573 // Make two more offers that leave one of the offers non-dry.
+
2574 // Guarantee the order of application by putting a close()
+
2575 // between them.
+
2576 env(offer(bob, eurOffer, usdOffer));
+
2577 env.close();
2578
-
2579 void
-
- -
2581 {
-
2582 testcase("Direct Crossing");
-
2583
-
2584 using namespace jtx;
-
2585
-
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 // 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 // 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 }
+
2579 env(offer(alice, USD(999), eurOffer));
+
2580 env.close();
+
2581
+
2582 env.require(offers(alice, 0));
+
2583 env.require(offers(bob, 1));
+
2584
+
2585 env.require(balance(alice, USD(999)));
+
2586 env.require(balance(alice, EUR(1)));
+
2587 env.require(balance(bob, USD(1)));
+
2588 env.require(balance(bob, EUR(999)));
+
2589
+
2590 {
+
2591 auto bobsOffers = offersOnAccount(env, bob);
+
2592 if (BEAST_EXPECT(bobsOffers.size() == 1))
+
2593 {
+
2594 auto const& bobsOffer = *(bobsOffers.front());
+
2595
+
2596 BEAST_EXPECT(bobsOffer[sfTakerGets] == USD(1));
+
2597 BEAST_EXPECT(bobsOffer[sfTakerPays] == EUR(1));
+
2598 }
+
2599 }
+
2600
+
2601 // alice makes one more offer that cleans out bob's offer.
+
2602 env(offer(alice, USD(1), EUR(1)));
+
2603 env.close();
+
2604
+
2605 env.require(balance(alice, USD(1000)));
+
2606 env.require(balance(alice, EUR(none)));
+
2607 env.require(balance(bob, USD(none)));
+
2608 env.require(balance(bob, EUR(1000)));
+
2609 env.require(offers(alice, 0));
+
2610 env.require(offers(bob, 0));
+
2611
+
2612 // The two trustlines that were generated by offers should be gone.
+
2613 BEAST_EXPECT(!env.le(keylet::line(alice.id(), EUR.issue())));
+
2614 BEAST_EXPECT(!env.le(keylet::line(bob.id(), USD.issue())));
+
2615
+
2616 // Make two more offers that leave one of the offers non-dry. We
+
2617 // need to properly sequence the transactions:
+
2618 env(offer(alice, EUR(999), usdOffer));
+
2619 env.close();
+
2620
+
2621 env(offer(bob, usdOffer, eurOffer));
+
2622 env.close();
+
2623
+
2624 env.require(offers(alice, 0));
+
2625 env.require(offers(bob, 0));
+
2626
+
2627 env.require(balance(alice, USD(0)));
+
2628 env.require(balance(alice, EUR(999)));
+
2629 env.require(balance(bob, USD(1000)));
+
2630 env.require(balance(bob, EUR(1)));
+
2631 }
-
2696
-
2697 void
-
- -
2699 {
-
2700 testcase("Bridged Crossing");
-
2701
-
2702 using namespace jtx;
+
2632
+
2633 void
+
+ +
2635 {
+
2636 testcase("Bridged Crossing");
+
2637
+
2638 using namespace jtx;
+
2639
+
2640 auto const gw = Account("gateway");
+
2641 auto const alice = Account("alice");
+
2642 auto const bob = Account("bob");
+
2643 auto const carol = Account("carol");
+
2644 auto const USD = gw["USD"];
+
2645 auto const EUR = gw["EUR"];
+
2646
+
2647 auto const usdOffer = USD(1000);
+
2648 auto const eurOffer = EUR(1000);
+
2649
+
2650 Env env{*this, features};
+
2651
+
2652 env.fund(XRP(1000000), gw, alice, bob, carol);
+
2653 env.close();
+
2654
+
2655 env(trust(alice, usdOffer));
+
2656 env(trust(carol, eurOffer));
+
2657 env.close();
+
2658 env(pay(gw, alice, usdOffer));
+
2659 env(pay(gw, carol, eurOffer));
+
2660 env.close();
+
2661
+
2662 // The scenario:
+
2663 // o alice has USD but wants XRP.
+
2664 // o bob has XRP but wants EUR.
+
2665 // o carol has EUR but wants USD.
+
2666 // Note that carol's offer must come last. If carol's offer is placed
+
2667 // before bob's or alice's, then autobridging will not occur.
+
2668 env(offer(alice, XRP(1000), usdOffer));
+
2669 env(offer(bob, eurOffer, XRP(1000)));
+
2670 auto const bobXrpBalance = env.balance(bob);
+
2671 env.close();
+
2672
+
2673 // carol makes an offer that partially consumes alice and bob's offers.
+
2674 env(offer(carol, USD(400), EUR(400)));
+
2675 env.close();
+
2676
+
2677 env.require(
+
2678 balance(alice, USD(600)),
+
2679 balance(bob, EUR(400)),
+
2680 balance(carol, USD(400)),
+
2681 balance(bob, bobXrpBalance - XRP(400)),
+
2682 offers(carol, 0));
+
2683 verifyDefaultTrustline(env, bob, EUR(400));
+
2684 verifyDefaultTrustline(env, carol, USD(400));
+
2685 {
+
2686 auto const alicesOffers = offersOnAccount(env, alice);
+
2687 BEAST_EXPECT(alicesOffers.size() == 1);
+
2688 auto const& alicesOffer = *(alicesOffers.front());
+
2689
+
2690 BEAST_EXPECT(alicesOffer[sfLedgerEntryType] == ltOFFER);
+
2691 BEAST_EXPECT(alicesOffer[sfTakerGets] == USD(600));
+
2692 BEAST_EXPECT(alicesOffer[sfTakerPays] == XRP(600));
+
2693 }
+
2694 {
+
2695 auto const bobsOffers = offersOnAccount(env, bob);
+
2696 BEAST_EXPECT(bobsOffers.size() == 1);
+
2697 auto const& bobsOffer = *(bobsOffers.front());
+
2698
+
2699 BEAST_EXPECT(bobsOffer[sfLedgerEntryType] == ltOFFER);
+
2700 BEAST_EXPECT(bobsOffer[sfTakerGets] == XRP(600));
+
2701 BEAST_EXPECT(bobsOffer[sfTakerPays] == EUR(600));
+
2702 }
2703
-
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 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 // 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();
+
2704 // carol makes an offer that exactly consumes alice and bob's offers.
+
2705 env(offer(carol, USD(600), EUR(600)));
+
2706 env.close();
+
2707
+
2708 env.require(
+
2709 balance(alice, USD(0)),
+
2710 balance(bob, eurOffer),
+
2711 balance(carol, usdOffer),
+
2712 balance(bob, bobXrpBalance - XRP(1000)),
+
2713 offers(bob, 0),
+
2714 offers(carol, 0));
+
2715 verifyDefaultTrustline(env, bob, EUR(1000));
+
2716 verifyDefaultTrustline(env, carol, USD(1000));
+
2717
+
2718 // In pre-flow code alice's offer is left empty in the ledger.
+
2719 auto const alicesOffers = offersOnAccount(env, alice);
+
2720 if (alicesOffers.size() != 0)
+
2721 {
+
2722 BEAST_EXPECT(alicesOffers.size() == 1);
+
2723 auto const& alicesOffer = *(alicesOffers.front());
+
2724
+
2725 BEAST_EXPECT(alicesOffer[sfLedgerEntryType] == ltOFFER);
+
2726 BEAST_EXPECT(alicesOffer[sfTakerGets] == USD(0));
+
2727 BEAST_EXPECT(alicesOffer[sfTakerPays] == XRP(0));
+
2728 }
+
2729 }
+
+
2730
+
2731 void
+
+ +
2733 {
+
2734 // Test a number of different corner cases regarding offer crossing
+
2735 // when the tfSell flag is set. The test is table driven so it
+
2736 // should be easy to add or remove tests.
+
2737 testcase("Sell Offer");
+
2738
+
2739 using namespace jtx;
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 BEAST_EXPECT(alicesOffer[sfLedgerEntryType] == ltOFFER);
-
2790 BEAST_EXPECT(alicesOffer[sfTakerGets] == USD(0));
-
2791 BEAST_EXPECT(alicesOffer[sfTakerPays] == XRP(0));
-
2792 }
-
2793 }
-
-
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 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 }
+
2741 auto const gw = Account("gateway");
+
2742 auto const USD = gw["USD"];
+
2743
+
2744 Env env{*this, features};
+
2745
+
2746 env.fund(XRP(10000000), gw);
+
2747 env.close();
+
2748
+
2749 // The fee that's charged for transactions
+
2750 auto const f = env.current()->fees().base;
+
2751
+
2752 // To keep things simple all offers are 1 : 1 for XRP : USD.
+
2753 enum preTrustType { noPreTrust, gwPreTrust, acctPreTrust };
+
2754 struct TestData
+
2755 {
+
2756 std::string account; // Account operated on
+
2757 STAmount fundXrp; // XRP acct funded with
+
2758 STAmount fundUSD; // USD acct funded with
+
2759 STAmount gwGets; // gw's offer
+
2760 STAmount gwPays; //
+
2761 STAmount acctGets; // acct's offer
+
2762 STAmount acctPays; //
+
2763 TER tec; // Returned tec code
+
2764 STAmount spentXrp; // Amount removed from fundXrp
+
2765 STAmount finalUsd; // Final USD balance on acct
+
2766 int offers; // Offers on acct
+
2767 int owners; // Owners on acct
+
2768 STAmount takerGets; // Remainder of acct's offer
+
2769 STAmount takerPays; //
+
2770
+
2771 // Constructor with takerGets/takerPays
+
2772 TestData(
+
2773 std::string&& account_, // Account operated on
+
2774 STAmount const& fundXrp_, // XRP acct funded with
+
2775 STAmount const& fundUSD_, // USD acct funded with
+
2776 STAmount const& gwGets_, // gw's offer
+
2777 STAmount const& gwPays_, //
+
2778 STAmount const& acctGets_, // acct's offer
+
2779 STAmount const& acctPays_, //
+
2780 TER tec_, // Returned tec code
+
2781 STAmount const& spentXrp_, // Amount removed from fundXrp
+
2782 STAmount const& finalUsd_, // Final USD balance on acct
+
2783 int offers_, // Offers on acct
+
2784 int owners_, // Owners on acct
+
2785 STAmount const& takerGets_, // Remainder of acct's offer
+
2786 STAmount const& takerPays_) //
+
2787 : account(std::move(account_))
+
2788 , fundXrp(fundXrp_)
+
2789 , fundUSD(fundUSD_)
+
2790 , gwGets(gwGets_)
+
2791 , gwPays(gwPays_)
+
2792 , acctGets(acctGets_)
+
2793 , acctPays(acctPays_)
+
2794 , tec(tec_)
+
2795 , spentXrp(spentXrp_)
+
2796 , finalUsd(finalUsd_)
+
2797 , offers(offers_)
+
2798 , owners(owners_)
+
2799 , takerGets(takerGets_)
+
2800 , takerPays(takerPays_)
+
2801 {
+
2802 }
+
2803
+
2804 // Constructor without takerGets/takerPays
+
2805 TestData(
+
2806 std::string&& account_, // Account operated on
+
2807 STAmount const& fundXrp_, // XRP acct funded with
+
2808 STAmount const& fundUSD_, // USD acct funded with
+
2809 STAmount const& gwGets_, // gw's offer
+
2810 STAmount const& gwPays_, //
+
2811 STAmount const& acctGets_, // acct's offer
+
2812 STAmount const& acctPays_, //
+
2813 TER tec_, // Returned tec code
+
2814 STAmount const& spentXrp_, // Amount removed from fundXrp
+
2815 STAmount const& finalUsd_, // Final USD balance on acct
+
2816 int offers_, // Offers on acct
+
2817 int owners_) // Owners on acct
+
2818 : TestData(
+
2819 std::move(account_),
+
2820 fundXrp_,
+
2821 fundUSD_,
+
2822 gwGets_,
+
2823 gwPays_,
+
2824 acctGets_,
+
2825 acctPays_,
+
2826 tec_,
+
2827 spentXrp_,
+
2828 finalUsd_,
+
2829 offers_,
+
2830 owners_,
+
2831 STAmount{0},
+
2832 STAmount{0})
+
2833 {
+
2834 }
+
2835 };
+
2836
+
2837 // clang-format off
+
2838 TestData const tests[]{
+
2839 // acct pays XRP
+
2840 // acct fundXrp fundUSD gwGets gwPays acctGets acctPays tec spentXrp finalUSD offers owners takerGets takerPays
+
2841 {"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},
+
2842 {"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)},
+
2843 {"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},
+
2844 {"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},
+
2845 {"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},
+
2846 {"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},
+
2847 {"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},
+
2848 {"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)},
+
2849 // acct pays USD
+
2850 {"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},
+
2851 {"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)},
+
2852 {"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},
+
2853 {"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},
+
2854 {"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},
+
2855 {"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)},
+
2856 {"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)},
+
2857 };
+
2858 // clang-format on
+
2859
+
2860 auto const zeroUsd = USD(0);
+
2861 for (auto const& t : tests)
+
2862 {
+
2863 // Make sure gateway has no current offers.
+
2864 env.require(offers(gw, 0));
+
2865
+
2866 auto const acct = Account(t.account);
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 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 }
+
2868 env.fund(t.fundXrp, acct);
+
2869 env.close();
+
2870
+
2871 // Optionally give acct some USD. This is not part of the test,
+
2872 // so we assume that acct has sufficient USD to cover the reserve
+
2873 // on the trust line.
+
2874 if (t.fundUSD != zeroUsd)
+
2875 {
+
2876 env(trust(acct, t.fundUSD));
+
2877 env.close();
+
2878 env(pay(gw, acct, t.fundUSD));
+
2879 env.close();
+
2880 }
+
2881
+
2882 env(offer(gw, t.gwGets, t.gwPays));
+
2883 env.close();
+
2884 std::uint32_t const gwOfferSeq = env.seq(gw) - 1;
+
2885
+
2886 // Acct creates a tfSell offer. This is the heart of the test.
+
2887 env(offer(acct, t.acctGets, t.acctPays, tfSell), ter(t.tec));
+
2888 env.close();
+
2889 std::uint32_t const acctOfferSeq = env.seq(acct) - 1;
+
2890
+
2891 // Check results
+
2892 BEAST_EXPECT(env.balance(acct, USD.issue()) == t.finalUsd);
+
2893 BEAST_EXPECT(
+
2894 env.balance(acct, xrpIssue()) == t.fundXrp - t.spentXrp);
+
2895 env.require(offers(acct, t.offers));
+
2896 env.require(owners(acct, t.owners));
+
2897
+
2898 if (t.offers)
+
2899 {
+
2900 auto const acctOffers = offersOnAccount(env, acct);
+
2901 if (acctOffers.size() > 0)
+
2902 {
+
2903 BEAST_EXPECT(acctOffers.size() == 1);
+
2904 auto const& acctOffer = *(acctOffers.front());
+
2905
+
2906 BEAST_EXPECT(acctOffer[sfLedgerEntryType] == ltOFFER);
+
2907 BEAST_EXPECT(acctOffer[sfTakerGets] == t.takerGets);
+
2908 BEAST_EXPECT(acctOffer[sfTakerPays] == t.takerPays);
+
2909 }
+
2910 }
+
2911
+
2912 // Give the next loop a clean slate by canceling any left-overs
+
2913 // in the offers.
+
2914 env(offer_cancel(acct, acctOfferSeq));
+
2915 env(offer_cancel(gw, gwOfferSeq));
+
2916 env.close();
+
2917 }
+
2918 }
+
2919
+
2920 void
+
+ +
2922 {
+
2923 // Test a number of different corner cases regarding offer crossing
+
2924 // when both the tfSell flag and tfFillOrKill flags are set.
+
2925 testcase("Combine tfSell with tfFillOrKill");
+
2926
+
2927 using namespace jtx;
+
2928
+
2929 auto const gw = Account("gateway");
+
2930 auto const alice = Account("alice");
+
2931 auto const bob = Account("bob");
+
2932 auto const USD = gw["USD"];
+
2933
+
2934 Env env{*this, features};
+
2935
+
2936 env.fund(XRP(10000000), gw, alice, bob);
+
2937 env.close();
+
2938
+
2939 // Code returned if an offer is killed.
+
2940 TER const killedCode{TER{tecKILLED}};
+
2941
+
2942 // bob offers XRP for USD.
+
2943 env(trust(bob, USD(200)));
+
2944 env.close();
+
2945 env(pay(gw, bob, USD(100)));
+
2946 env.close();
+
2947 env(offer(bob, XRP(2000), USD(20)));
+
2948 env.close();
+
2949 {
+
2950 // alice submits a tfSell | tfFillOrKill offer that does not cross.
+
2951 env(offer(alice, USD(21), XRP(2100), tfSell | tfFillOrKill),
+
2952 ter(killedCode));
+
2953 env.close();
+
2954 env.require(balance(alice, USD(none)));
+
2955 env.require(offers(alice, 0));
+
2956 env.require(balance(bob, USD(100)));
+
2957 }
+
2958 {
+
2959 // alice submits a tfSell | tfFillOrKill offer that crosses.
+
2960 // Even though tfSell is present it doesn't matter this time.
+
2961 env(offer(alice, USD(20), XRP(2000), tfSell | tfFillOrKill));
+
2962 env.close();
+
2963 env.require(balance(alice, USD(20)));
+
2964 env.require(offers(alice, 0));
+
2965 env.require(balance(bob, USD(80)));
+
2966 }
+
2967 {
+
2968 // alice submits a tfSell | tfFillOrKill offer that crosses and
+
2969 // returns more than was asked for (because of the tfSell flag).
+
2970 env(offer(bob, XRP(2000), USD(20)));
+
2971 env.close();
+
2972 env(offer(alice, USD(10), XRP(1500), tfSell | tfFillOrKill));
+
2973 env.close();
+
2974 env.require(balance(alice, USD(35)));
+
2975 env.require(offers(alice, 0));
+
2976 env.require(balance(bob, USD(65)));
+
2977 }
+
2978 {
+
2979 // alice submits a tfSell | tfFillOrKill offer that doesn't cross.
+
2980 // This would have succeeded with a regular tfSell, but the
+
2981 // fillOrKill prevents the transaction from crossing since not
+
2982 // all of the offer is consumed.
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 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 Env env{*this, features};
-
2999
-
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 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 }
+
2984 // We're using bob's left-over offer for XRP(500), USD(5)
+
2985 env(offer(alice, USD(1), XRP(501), tfSell | tfFillOrKill),
+
2986 ter(killedCode));
+
2987 env.close();
+
2988 env.require(balance(alice, USD(35)));
+
2989 env.require(offers(alice, 0));
+
2990 env.require(balance(bob, USD(65)));
+
2991 }
+
2992 {
+
2993 // Alice submits a tfSell | tfFillOrKill offer that finishes
+
2994 // off the remainder of bob's offer.
+
2995
+
2996 // We're using bob's left-over offer for XRP(500), USD(5)
+
2997 env(offer(alice, USD(1), XRP(500), tfSell | tfFillOrKill));
+
2998 env.close();
+
2999 env.require(balance(alice, USD(40)));
+
3000 env.require(offers(alice, 0));
+
3001 env.require(balance(bob, USD(60)));
+
3002 }
+
3003 }
+
3004
+
3005 void
+
+ +
3007 {
+
3008 testcase("Transfer Rate Offer");
+
3009
+
3010 using namespace jtx;
+
3011
+
3012 auto const gw1 = Account("gateway1");
+
3013 auto const USD = gw1["USD"];
+
3014
+
3015 Env env{*this, features};
+
3016
+
3017 // The fee that's charged for transactions.
+
3018 auto const fee = env.current()->fees().base;
+
3019
+
3020 env.fund(XRP(100000), gw1);
+
3021 env.close();
+
3022
+
3023 env(rate(gw1, 1.25));
+
3024 {
+
3025 auto const ann = Account("ann");
+
3026 auto const bob = Account("bob");
+
3027 env.fund(XRP(100) + reserve(env, 2) + (fee * 2), ann, bob);
+
3028 env.close();
+
3029
+
3030 env(trust(ann, USD(200)));
+
3031 env(trust(bob, USD(200)));
+
3032 env.close();
+
3033
+
3034 env(pay(gw1, bob, USD(125)));
+
3035 env.close();
+
3036
+
3037 // bob offers to sell USD(100) for XRP. alice takes bob's offer.
+
3038 // Notice that although bob only offered USD(100), USD(125) was
+
3039 // removed from his account due to the gateway fee.
+
3040 //
+
3041 // A comparable payment would look like this:
+
3042 // env (pay (bob, alice, USD(100)), sendmax(USD(125)))
+
3043 env(offer(bob, XRP(1), USD(100)));
+
3044 env.close();
+
3045
+
3046 env(offer(ann, USD(100), XRP(1)));
+
3047 env.close();
+
3048
+
3049 env.require(balance(ann, USD(100)));
+
3050 env.require(balance(ann, XRP(99) + reserve(env, 2)));
+
3051 env.require(offers(ann, 0));
+
3052
+
3053 env.require(balance(bob, USD(0)));
+
3054 env.require(balance(bob, XRP(101) + reserve(env, 2)));
+
3055 env.require(offers(bob, 0));
+
3056 }
+
3057 {
+
3058 // Reverse the order, so the offer in the books is to sell XRP
+
3059 // in return for USD. Gateway rate should still apply identically.
+
3060 auto const che = Account("che");
+
3061 auto const deb = Account("deb");
+
3062 env.fund(XRP(100) + reserve(env, 2) + (fee * 2), che, deb);
+
3063 env.close();
+
3064
+
3065 env(trust(che, USD(200)));
+
3066 env(trust(deb, USD(200)));
+
3067 env.close();
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 env.fund(XRP(100000), gw1);
-
3085 env.close();
-
3086
-
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)));
+
3069 env(pay(gw1, deb, USD(125)));
+
3070 env.close();
+
3071
+
3072 env(offer(che, USD(100), XRP(1)));
+
3073 env.close();
+
3074
+
3075 env(offer(deb, XRP(1), USD(100)));
+
3076 env.close();
+
3077
+
3078 env.require(balance(che, USD(100)));
+
3079 env.require(balance(che, XRP(99) + reserve(env, 2)));
+
3080 env.require(offers(che, 0));
+
3081
+
3082 env.require(balance(deb, USD(0)));
+
3083 env.require(balance(deb, XRP(101) + reserve(env, 2)));
+
3084 env.require(offers(deb, 0));
+
3085 }
+
3086 {
+
3087 auto const eve = Account("eve");
+
3088 auto const fyn = Account("fyn");
+
3089
+
3090 env.fund(XRP(20000) + (fee * 2), eve, fyn);
+
3091 env.close();
+
3092
+
3093 env(trust(eve, USD(1000)));
+
3094 env(trust(fyn, USD(1000)));
+
3095 env.close();
+
3096
+
3097 env(pay(gw1, eve, USD(100)));
+
3098 env(pay(gw1, fyn, USD(100)));
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.fund(XRP(20000) + (fee * 2), eve, fyn);
-
3155 env.close();
-
3156
-
3157 env(trust(eve, USD(1000)));
-
3158 env(trust(fyn, USD(1000)));
+
3101 // This test verifies that the amount removed from an offer
+
3102 // accounts for the transfer fee that is removed from the
+
3103 // account but not from the remaining offer.
+
3104 env(offer(eve, USD(10), XRP(4000)));
+
3105 env.close();
+
3106 std::uint32_t const eveOfferSeq = env.seq(eve) - 1;
+
3107
+
3108 env(offer(fyn, XRP(2000), USD(5)));
+
3109 env.close();
+
3110
+
3111 env.require(balance(eve, USD(105)));
+
3112 env.require(balance(eve, XRP(18000)));
+
3113 auto const evesOffers = offersOnAccount(env, eve);
+
3114 BEAST_EXPECT(evesOffers.size() == 1);
+
3115 if (evesOffers.size() != 0)
+
3116 {
+
3117 auto const& evesOffer = *(evesOffers.front());
+
3118 BEAST_EXPECT(evesOffer[sfLedgerEntryType] == ltOFFER);
+
3119 BEAST_EXPECT(evesOffer[sfTakerGets] == XRP(2000));
+
3120 BEAST_EXPECT(evesOffer[sfTakerPays] == USD(5));
+
3121 }
+
3122 env(offer_cancel(eve, eveOfferSeq)); // For later tests
+
3123
+
3124 env.require(balance(fyn, USD(93.75)));
+
3125 env.require(balance(fyn, XRP(22000)));
+
3126 env.require(offers(fyn, 0));
+
3127 }
+
3128 // Start messing with two non-native currencies.
+
3129 auto const gw2 = Account("gateway2");
+
3130 auto const EUR = gw2["EUR"];
+
3131
+
3132 env.fund(XRP(100000), gw2);
+
3133 env.close();
+
3134
+
3135 env(rate(gw2, 1.5));
+
3136 {
+
3137 // Remove XRP from the equation. Give the two currencies two
+
3138 // different transfer rates so we can see both transfer rates
+
3139 // apply in the same transaction.
+
3140 auto const gay = Account("gay");
+
3141 auto const hal = Account("hal");
+
3142 env.fund(reserve(env, 3) + (fee * 3), gay, hal);
+
3143 env.close();
+
3144
+
3145 env(trust(gay, USD(200)));
+
3146 env(trust(gay, EUR(200)));
+
3147 env(trust(hal, USD(200)));
+
3148 env(trust(hal, EUR(200)));
+
3149 env.close();
+
3150
+
3151 env(pay(gw1, gay, USD(125)));
+
3152 env(pay(gw2, hal, EUR(150)));
+
3153 env.close();
+
3154
+
3155 env(offer(gay, EUR(100), USD(100)));
+
3156 env.close();
+
3157
+
3158 env(offer(hal, USD(100), EUR(100)));
3159 env.close();
3160
-
3161 env(pay(gw1, eve, USD(100)));
-
3162 env(pay(gw1, fyn, USD(100)));
-
3163 env.close();
-
3164
-
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"];
+
3161 env.require(balance(gay, USD(0)));
+
3162 env.require(balance(gay, EUR(100)));
+
3163 env.require(balance(gay, reserve(env, 3)));
+
3164 env.require(offers(gay, 0));
+
3165
+
3166 env.require(balance(hal, USD(100)));
+
3167 env.require(balance(hal, EUR(0)));
+
3168 env.require(balance(hal, reserve(env, 3)));
+
3169 env.require(offers(hal, 0));
+
3170 }
+
3171 {
+
3172 // A trust line's QualityIn should not affect offer crossing.
+
3173 auto const ivy = Account("ivy");
+
3174 auto const joe = Account("joe");
+
3175 env.fund(reserve(env, 3) + (fee * 3), ivy, joe);
+
3176 env.close();
+
3177
+
3178 env(trust(ivy, USD(400)), qualityInPercent(90));
+
3179 env(trust(ivy, EUR(400)), qualityInPercent(80));
+
3180 env(trust(joe, USD(400)), qualityInPercent(70));
+
3181 env(trust(joe, EUR(400)), qualityInPercent(60));
+
3182 env.close();
+
3183
+
3184 env(pay(gw1, ivy, USD(270)), sendmax(USD(500)));
+
3185 env(pay(gw2, joe, EUR(150)), sendmax(EUR(300)));
+
3186 env.close();
+
3187 env.require(balance(ivy, USD(300)));
+
3188 env.require(balance(joe, EUR(250)));
+
3189
+
3190 env(offer(ivy, EUR(100), USD(200)));
+
3191 env.close();
+
3192
+
3193 env(offer(joe, USD(200), EUR(100)));
+
3194 env.close();
3195
-
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();
+
3196 env.require(balance(ivy, USD(50)));
+
3197 env.require(balance(ivy, EUR(100)));
+
3198 env.require(balance(ivy, reserve(env, 3)));
+
3199 env.require(offers(ivy, 0));
+
3200
+
3201 env.require(balance(joe, USD(200)));
+
3202 env.require(balance(joe, EUR(100)));
+
3203 env.require(balance(joe, reserve(env, 3)));
+
3204 env.require(offers(joe, 0));
+
3205 }
+
3206 {
+
3207 // A trust line's QualityOut should not affect offer crossing.
+
3208 auto const kim = Account("kim");
+
3209 auto const K_BUX = kim["BUX"];
+
3210 auto const lex = Account("lex");
+
3211 auto const meg = Account("meg");
+
3212 auto const ned = Account("ned");
+
3213 auto const N_BUX = ned["BUX"];
3214
-
3215 env(pay(gw1, gay, USD(125)));
-
3216 env(pay(gw2, hal, EUR(150)));
+
3215 // Verify trust line QualityOut affects payments.
+
3216 env.fund(reserve(env, 4) + (fee * 4), kim, lex, meg, ned);
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));
+
3219 env(trust(lex, K_BUX(400)));
+
3220 env(trust(lex, N_BUX(200)), qualityOutPercent(120));
+
3221 env(trust(meg, N_BUX(100)));
+
3222 env.close();
+
3223 env(pay(ned, lex, N_BUX(100)));
+
3224 env.close();
+
3225 env.require(balance(lex, N_BUX(100)));
+
3226
+
3227 env(pay(kim, meg, N_BUX(60)), path(lex, ned), sendmax(K_BUX(200)));
+
3228 env.close();
3229
-
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
-
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.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(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(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 }
+
3230 env.require(balance(kim, K_BUX(none)));
+
3231 env.require(balance(kim, N_BUX(none)));
+
3232 env.require(balance(lex, K_BUX(72)));
+
3233 env.require(balance(lex, N_BUX(40)));
+
3234 env.require(balance(meg, K_BUX(none)));
+
3235 env.require(balance(meg, N_BUX(60)));
+
3236 env.require(balance(ned, K_BUX(none)));
+
3237 env.require(balance(ned, N_BUX(none)));
+
3238
+
3239 // Now verify that offer crossing is unaffected by QualityOut.
+
3240 env(offer(lex, K_BUX(30), N_BUX(30)));
+
3241 env.close();
+
3242
+
3243 env(offer(kim, N_BUX(30), K_BUX(30)));
+
3244 env.close();
+
3245
+
3246 env.require(balance(kim, K_BUX(none)));
+
3247 env.require(balance(kim, N_BUX(30)));
+
3248 env.require(balance(lex, K_BUX(102)));
+
3249 env.require(balance(lex, N_BUX(10)));
+
3250 env.require(balance(meg, K_BUX(none)));
+
3251 env.require(balance(meg, N_BUX(60)));
+
3252 env.require(balance(ned, K_BUX(-30)));
+
3253 env.require(balance(ned, N_BUX(none)));
+
3254 }
+
3255 {
+
3256 // Make sure things work right when we're auto-bridging as well.
+
3257 auto const ova = Account("ova");
+
3258 auto const pat = Account("pat");
+
3259 auto const qae = Account("qae");
+
3260 env.fund(XRP(2) + reserve(env, 3) + (fee * 3), ova, pat, qae);
+
3261 env.close();
+
3262
+
3263 // o ova has USD but wants XRP.
+
3264 // o pat has XRP but wants EUR.
+
3265 // o qae has EUR but wants USD.
+
3266 env(trust(ova, USD(200)));
+
3267 env(trust(ova, EUR(200)));
+
3268 env(trust(pat, USD(200)));
+
3269 env(trust(pat, EUR(200)));
+
3270 env(trust(qae, USD(200)));
+
3271 env(trust(qae, EUR(200)));
+
3272 env.close();
+
3273
+
3274 env(pay(gw1, ova, USD(125)));
+
3275 env(pay(gw2, qae, EUR(150)));
+
3276 env.close();
+
3277
+
3278 env(offer(ova, XRP(2), USD(100)));
+
3279 env(offer(pat, EUR(100), XRP(2)));
+
3280 env.close();
+
3281
+
3282 env(offer(qae, USD(100), EUR(100)));
+
3283 env.close();
+
3284
+
3285 env.require(balance(ova, USD(0)));
+
3286 env.require(balance(ova, EUR(0)));
+
3287 env.require(balance(ova, XRP(4) + reserve(env, 3)));
+
3288
+
3289 // In pre-flow code ova's offer is left empty in the ledger.
+
3290 auto const ovasOffers = offersOnAccount(env, ova);
+
3291 if (ovasOffers.size() != 0)
+
3292 {
+
3293 BEAST_EXPECT(ovasOffers.size() == 1);
+
3294 auto const& ovasOffer = *(ovasOffers.front());
+
3295
+
3296 BEAST_EXPECT(ovasOffer[sfLedgerEntryType] == ltOFFER);
+
3297 BEAST_EXPECT(ovasOffer[sfTakerGets] == USD(0));
+
3298 BEAST_EXPECT(ovasOffer[sfTakerPays] == XRP(0));
+
3299 }
+
3300
+
3301 env.require(balance(pat, USD(0)));
+
3302 env.require(balance(pat, EUR(100)));
+
3303 env.require(balance(pat, XRP(0) + reserve(env, 3)));
+
3304 env.require(offers(pat, 0));
+
3305
+
3306 env.require(balance(qae, USD(100)));
+
3307 env.require(balance(qae, EUR(0)));
+
3308 env.require(balance(qae, XRP(2) + reserve(env, 3)));
+
3309 env.require(offers(qae, 0));
+
3310 }
+
3311 }
-
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 // 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;
+
3312
+
3313 void
+
+ +
3315 {
+
3316 // The following test verifies some correct but slightly surprising
+
3317 // behavior in offer crossing. The scenario:
+
3318 //
+
3319 // o An entity has created one or more offers.
+
3320 // o The entity creates another offer that can be directly crossed
+
3321 // (not autobridged) by the previously created offer(s).
+
3322 // o Rather than self crossing the offers, delete the old offer(s).
+
3323 //
+
3324 // See a more complete explanation in the comments for
+
3325 // BookOfferCrossingStep::limitSelfCrossQuality().
+
3326 //
+
3327 // Note that, in this particular example, one offer causes several
+
3328 // crossable offers (worth considerably more than the new offer)
+
3329 // to be removed from the book.
+
3330 using namespace jtx;
+
3331
+
3332 auto const gw = Account("gateway");
+
3333 auto const USD = gw["USD"];
+
3334
+
3335 Env env{*this, features};
+
3336
+
3337 // The fee that's charged for transactions.
+
3338 auto const fee = env.current()->fees().base;
+
3339 auto const startBalance = XRP(1000000);
+
3340
+
3341 env.fund(startBalance + (fee * 4), gw);
+
3342 env.close();
+
3343
+
3344 env(offer(gw, USD(60), XRP(600)));
+
3345 env.close();
+
3346 env(offer(gw, USD(60), XRP(600)));
+
3347 env.close();
+
3348 env(offer(gw, USD(60), XRP(600)));
+
3349 env.close();
+
3350
+
3351 env.require(owners(gw, 3));
+
3352 env.require(balance(gw, startBalance + fee));
+
3353
+
3354 auto gwOffers = offersOnAccount(env, gw);
+
3355 BEAST_EXPECT(gwOffers.size() == 3);
+
3356 for (auto const& offerPtr : gwOffers)
+
3357 {
+
3358 auto const& offer = *offerPtr;
+
3359 BEAST_EXPECT(offer[sfLedgerEntryType] == ltOFFER);
+
3360 BEAST_EXPECT(offer[sfTakerGets] == XRP(600));
+
3361 BEAST_EXPECT(offer[sfTakerPays] == USD(60));
+
3362 }
+
3363
+
3364 // Since this offer crosses the first offers, the previous offers
+
3365 // will be deleted and this offer will be put on the order book.
+
3366 env(offer(gw, XRP(1000), USD(100)));
+
3367 env.close();
+
3368 env.require(owners(gw, 1));
+
3369 env.require(offers(gw, 1));
+
3370 env.require(balance(gw, startBalance));
+
3371
+
3372 gwOffers = offersOnAccount(env, gw);
+
3373 BEAST_EXPECT(gwOffers.size() == 1);
+
3374 for (auto const& offerPtr : gwOffers)
+
3375 {
+
3376 auto const& offer = *offerPtr;
+
3377 BEAST_EXPECT(offer[sfLedgerEntryType] == ltOFFER);
+
3378 BEAST_EXPECT(offer[sfTakerGets] == USD(100));
+
3379 BEAST_EXPECT(offer[sfTakerPays] == XRP(1000));
+
3380 }
+
3381 }
+
+
3382
+
3383 void
+
+ +
3385 {
+
3386 using namespace jtx;
+
3387
+
3388 auto const gw1 = Account("gateway1");
+
3389 auto const gw2 = Account("gateway2");
+
3390 auto const alice = Account("alice");
+
3391 auto const USD = gw1["USD"];
+
3392 auto const EUR = gw2["EUR"];
+
3393
+
3394 Env env{*this, features};
3395
-
3396 auto const gw = Account("gateway");
-
3397 auto const USD = gw["USD"];
+
3396 env.fund(XRP(1000000), gw1, gw2);
+
3397 env.close();
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 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 }
-
-
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};
+
3399 // The fee that's charged for transactions.
+
3400 auto const f = env.current()->fees().base;
+
3401
+
3402 // Test cases
+
3403 struct TestData
+
3404 {
+
3405 std::string acct; // Account operated on
+
3406 STAmount fundXRP; // XRP acct funded with
+
3407 STAmount fundUSD; // USD acct funded with
+
3408 STAmount fundEUR; // EUR acct funded with
+
3409 TER firstOfferTec; // tec code on first offer
+
3410 TER secondOfferTec; // tec code on second offer
+
3411 };
+
3412
+
3413 // clang-format off
+
3414 TestData const tests[]{
+
3415 // acct fundXRP fundUSD fundEUR firstOfferTec secondOfferTec
+
3416 {"ann", reserve(env, 3) + f * 4, USD(1000), EUR(1000), tesSUCCESS, tesSUCCESS},
+
3417 {"bev", reserve(env, 3) + f * 4, USD( 1), EUR(1000), tesSUCCESS, tesSUCCESS},
+
3418 {"cam", reserve(env, 3) + f * 4, USD(1000), EUR( 1), tesSUCCESS, tesSUCCESS},
+
3419 {"deb", reserve(env, 3) + f * 4, USD( 0), EUR( 1), tesSUCCESS, tecUNFUNDED_OFFER},
+
3420 {"eve", reserve(env, 3) + f * 4, USD( 1), EUR( 0), tecUNFUNDED_OFFER, tesSUCCESS},
+
3421 {"flo", reserve(env, 3) + 0, USD(1000), EUR(1000), tecINSUF_RESERVE_OFFER, tecINSUF_RESERVE_OFFER},
+
3422 };
+
3423 //clang-format on
+
3424
+
3425 for (auto const& t : tests)
+
3426 {
+
3427 auto const acct = Account{t.acct};
+
3428 env.fund(t.fundXRP, acct);
+
3429 env.close();
+
3430
+
3431 env(trust(acct, USD(1000)));
+
3432 env(trust(acct, EUR(1000)));
+
3433 env.close();
+
3434
+
3435 if (t.fundUSD > USD(0))
+
3436 env(pay(gw1, acct, t.fundUSD));
+
3437 if (t.fundEUR > EUR(0))
+
3438 env(pay(gw2, acct, t.fundEUR));
+
3439 env.close();
+
3440
+
3441 env(offer(acct, USD(500), EUR(600)), ter(t.firstOfferTec));
+
3442 env.close();
+
3443 std::uint32_t const firstOfferSeq = env.seq(acct) - 1;
+
3444
+
3445 int offerCount = t.firstOfferTec == tesSUCCESS ? 1 : 0;
+
3446 env.require(owners(acct, 2 + offerCount));
+
3447 env.require(balance(acct, t.fundUSD));
+
3448 env.require(balance(acct, t.fundEUR));
+
3449
+
3450 auto acctOffers = offersOnAccount(env, acct);
+
3451 BEAST_EXPECT(acctOffers.size() == offerCount);
+
3452 for (auto const& offerPtr : acctOffers)
+
3453 {
+
3454 auto const& offer = *offerPtr;
+
3455 BEAST_EXPECT(offer[sfLedgerEntryType] == ltOFFER);
+
3456 BEAST_EXPECT(offer[sfTakerGets] == EUR(600));
+
3457 BEAST_EXPECT(offer[sfTakerPays] == USD(500));
+
3458 }
3459
-
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 // 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();
+
3460 env(offer(acct, EUR(600), USD(500)), ter(t.secondOfferTec));
+
3461 env.close();
+
3462 std::uint32_t const secondOfferSeq = env.seq(acct) - 1;
+
3463
+
3464 offerCount = t.secondOfferTec == tesSUCCESS ? 1 : offerCount;
+
3465 env.require(owners(acct, 2 + offerCount));
+
3466 env.require(balance(acct, t.fundUSD));
+
3467 env.require(balance(acct, t.fundEUR));
+
3468
+
3469 acctOffers = offersOnAccount(env, acct);
+
3470 BEAST_EXPECT(acctOffers.size() == offerCount);
+
3471 for (auto const& offerPtr : acctOffers)
+
3472 {
+
3473 auto const& offer = *offerPtr;
+
3474 BEAST_EXPECT(offer[sfLedgerEntryType] == ltOFFER);
+
3475 if (offer[sfSequence] == firstOfferSeq)
+
3476 {
+
3477 BEAST_EXPECT(offer[sfTakerGets] == EUR(600));
+
3478 BEAST_EXPECT(offer[sfTakerPays] == USD(500));
+
3479 }
+
3480 else
+
3481 {
+
3482 BEAST_EXPECT(offer[sfTakerGets] == USD(500));
+
3483 BEAST_EXPECT(offer[sfTakerPays] == EUR(600));
+
3484 }
+
3485 }
+
3486
+
3487 // Remove any offers from acct for the next pass.
+
3488 env(offer_cancel(acct, firstOfferSeq));
+
3489 env.close();
+
3490 env(offer_cancel(acct, secondOfferSeq));
+
3491 env.close();
+
3492 }
+
3493 }
+
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));
+
3495 void
+
+ +
3497 {
+
3498 testcase("Self Cross Offer");
+
3499 testSelfCrossOffer1(features);
+
3500 testSelfCrossOffer2(features);
+
3501 }
+
+
3502
+
3503 void
+
+ +
3505 {
+
3506 // Folks who issue their own currency have, in effect, as many
+
3507 // funds as they are trusted for. This test used to fail because
+
3508 // self-issuing was not properly checked. Verify that it works
+
3509 // correctly now.
+
3510 using namespace jtx;
+
3511
+
3512 Env env{*this, features};
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 }
+
3514 auto const alice = Account("alice");
+
3515 auto const bob = Account("bob");
+
3516 auto const USD = bob["USD"];
+
3517 auto const f = env.current()->fees().base;
+
3518
+
3519 env.fund(XRP(50000) + f, alice, bob);
+
3520 env.close();
+
3521
+
3522 env(offer(alice, USD(5000), XRP(50000)));
+
3523 env.close();
+
3524
+
3525 // This offer should take alice's offer up to Alice's reserve.
+
3526 env(offer(bob, XRP(50000), USD(5000)));
+
3527 env.close();
+
3528
+
3529 // alice's offer should have been removed, since she's down to her
+
3530 // XRP reserve.
+
3531 env.require(balance(alice, XRP(250)));
+
3532 env.require(owners(alice, 1));
+
3533 env.require(lines(alice, 1));
+
3534
+
3535 // However bob's offer should be in the ledger, since it was not
+
3536 // fully crossed.
+
3537 auto const bobOffers = offersOnAccount(env, bob);
+
3538 BEAST_EXPECT(bobOffers.size() == 1);
+
3539 for (auto const& offerPtr : bobOffers)
+
3540 {
+
3541 auto const& offer = *offerPtr;
+
3542 BEAST_EXPECT(offer[sfLedgerEntryType] == ltOFFER);
+
3543 BEAST_EXPECT(offer[sfTakerGets] == USD(25));
+
3544 BEAST_EXPECT(offer[sfTakerPays] == XRP(250));
+
3545 }
+
3546 }
-
3558
-
3559 void
-
- -
3561 {
-
3562 testcase("Self Cross Offer");
-
3563 testSelfCrossOffer1(features);
-
3564 testSelfCrossOffer2(features);
-
3565 }
-
-
3566
-
3567 void
-
- -
3569 {
-
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;
+
3547
+
3548 void
+
+ +
3550 {
+
3551 // At one point in the past this invalid path caused an assert. It
+
3552 // should not be possible for user-supplied data to cause an assert.
+
3553 // Make sure the assert is gone.
+
3554 testcase("Bad path assert");
+
3555
+
3556 using namespace jtx;
+
3557
+
3558 Env env{*this, features};
+
3559
+
3560 // The fee that's charged for transactions.
+
3561 auto const fee = env.current()->fees().base;
+
3562 {
+
3563 // A trust line's QualityOut should not affect offer crossing.
+
3564 auto const ann = Account("ann");
+
3565 auto const A_BUX = ann["BUX"];
+
3566 auto const bob = Account("bob");
+
3567 auto const cam = Account("cam");
+
3568 auto const dan = Account("dan");
+
3569 auto const D_BUX = dan["BUX"];
+
3570
+
3571 // Verify trust line QualityOut affects payments.
+
3572 env.fund(reserve(env, 4) + (fee * 4), ann, bob, cam, dan);
+
3573 env.close();
+
3574
+
3575 env(trust(bob, A_BUX(400)));
+
3576 env(trust(bob, D_BUX(200)), qualityOutPercent(120));
+
3577 env(trust(cam, D_BUX(100)));
+
3578 env.close();
+
3579 env(pay(dan, bob, D_BUX(100)));
+
3580 env.close();
+
3581 env.require(balance(bob, D_BUX(100)));
3582
-
3583 env.fund(XRP(50000) + f, alice, bob);
-
3584 env.close();
+
3583 env(pay(ann, cam, D_BUX(60)), path(bob, dan), sendmax(A_BUX(200)));
+
3584 env.close();
3585
-
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 }
+
3586 env.require(balance(ann, A_BUX(none)));
+
3587 env.require(balance(ann, D_BUX(none)));
+
3588 env.require(balance(bob, A_BUX(72)));
+
3589 env.require(balance(bob, D_BUX(40)));
+
3590 env.require(balance(cam, A_BUX(none)));
+
3591 env.require(balance(cam, D_BUX(60)));
+
3592 env.require(balance(dan, A_BUX(none)));
+
3593 env.require(balance(dan, D_BUX(none)));
+
3594
+
3595 env(offer(bob, A_BUX(30), D_BUX(30)));
+
3596 env.close();
+
3597
+
3598 env(trust(ann, D_BUX(100)));
+
3599 env.close();
+
3600
+
3601 // This payment caused the assert.
+
3602 env(pay(ann, ann, D_BUX(30)),
+
3603 path(A_BUX, D_BUX),
+
3604 sendmax(A_BUX(30)),
+
3605 ter(temBAD_PATH));
+
3606 env.close();
+
3607
+
3608 env.require(balance(ann, A_BUX(none)));
+
3609 env.require(balance(ann, D_BUX(0)));
+
3610 env.require(balance(bob, A_BUX(72)));
+
3611 env.require(balance(bob, D_BUX(40)));
+
3612 env.require(balance(cam, A_BUX(none)));
+
3613 env.require(balance(cam, D_BUX(60)));
+
3614 env.require(balance(dan, A_BUX(0)));
+
3615 env.require(balance(dan, D_BUX(none)));
+
3616 }
+
3617 }
-
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 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)));
+
3618
+
3619 void
+
+ +
3621 {
+
3622 // The offer crossing code expects that a DirectStep is always
+
3623 // preceded by a BookStep. In one instance the default path
+
3624 // was not matching that assumption. Here we recreate that case
+
3625 // so we can prove the bug stays fixed.
+
3626 testcase("Direct to Direct path");
+
3627
+
3628 using namespace jtx;
+
3629
+
3630 Env env{*this, features};
+
3631
+
3632 auto const ann = Account("ann");
+
3633 auto const bob = Account("bob");
+
3634 auto const cam = Account("cam");
+
3635 auto const A_BUX = ann["BUX"];
+
3636 auto const B_BUX = bob["BUX"];
+
3637
+
3638 auto const fee = env.current()->fees().base;
+
3639 env.fund(reserve(env, 4) + (fee * 5), ann, bob, cam);
+
3640 env.close();
+
3641
+
3642 env(trust(ann, B_BUX(40)));
+
3643 env(trust(cam, A_BUX(40)));
+
3644 env(trust(cam, B_BUX(40)));
+
3645 env.close();
3646
-
3647 env(pay(ann, cam, D_BUX(60)), path(bob, dan), sendmax(A_BUX(200)));
-
3648 env.close();
+
3647 env(pay(ann, cam, A_BUX(35)));
+
3648 env(pay(bob, cam, B_BUX(35)));
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();
+
3650 env(offer(bob, A_BUX(30), B_BUX(30)));
+
3651 env.close();
+
3652
+
3653 // cam puts an offer on the books that her upcoming offer could cross.
+
3654 // But this offer should be deleted, not crossed, by her upcoming
+
3655 // offer.
+
3656 env(offer(cam, A_BUX(29), B_BUX(30), tfPassive));
+
3657 env.close();
+
3658 env.require(balance(cam, A_BUX(35)));
+
3659 env.require(balance(cam, B_BUX(35)));
+
3660 env.require(offers(cam, 1));
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();
+
3662 // This offer caused the assert.
+
3663 env(offer(cam, B_BUX(30), A_BUX(30)));
+
3664 env.close();
+
3665
+
3666 env.require(balance(bob, A_BUX(30)));
+
3667 env.require(balance(cam, A_BUX(5)));
+
3668 env.require(balance(cam, B_BUX(65)));
+
3669 env.require(offers(cam, 0));
+
3670 }
+
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 }
+
3672 void
+
+ +
3674 {
+
3675 // The Flow offer crossing code used to assert if an offer was made
+
3676 // for more XRP than the offering account held. This unit test
+
3677 // reproduces that failing case.
+
3678 testcase("Self crossing low quality offer");
+
3679
+
3680 using namespace jtx;
+
3681
+
3682 Env env{*this, features};
+
3683
+
3684 auto const ann = Account("ann");
+
3685 auto const gw = Account("gateway");
+
3686 auto const BTC = gw["BTC"];
+
3687
+
3688 auto const fee = env.current()->fees().base;
+
3689 env.fund(reserve(env, 2) + drops(9999640) + (fee), ann);
+
3690 env.fund(reserve(env, 2) + (fee * 4), gw);
+
3691 env.close();
+
3692
+
3693 env(rate(gw, 1.002));
+
3694 env(trust(ann, BTC(10)));
+
3695 env.close();
+
3696
+
3697 env(pay(gw, ann, BTC(2.856)));
+
3698 env.close();
+
3699
+
3700 env(offer(ann, drops(365611702030), BTC(5.713)));
+
3701 env.close();
+
3702
+
3703 // This offer caused the assert.
+
3704 env(offer(ann, BTC(0.687), drops(20000000000)),
+ +
3706 }
-
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 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(offer(bob, A_BUX(30), B_BUX(30)));
-
3715 env.close();
+
3707
+
3708 void
+
+ +
3710 {
+
3711 // The Flow offer crossing code had a case where it was not rounding
+
3712 // the offer crossing correctly after a partial crossing. The
+
3713 // failing case was found on the network. Here we add the case to
+
3714 // the unit tests.
+
3715 testcase("Offer In Scaling");
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));
+
3717 using namespace jtx;
+
3718
+
3719 Env env{*this, features};
+
3720
+
3721 auto const gw = Account("gateway");
+
3722 auto const alice = Account("alice");
+
3723 auto const bob = Account("bob");
+
3724 auto const CNY = gw["CNY"];
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");
+
3726 auto const fee = env.current()->fees().base;
+
3727 env.fund(reserve(env, 2) + drops(400000000000) + (fee), alice, bob);
+
3728 env.fund(reserve(env, 2) + (fee * 4), gw);
+
3729 env.close();
+
3730
+
3731 env(trust(bob, CNY(500)));
+
3732 env.close();
+
3733
+
3734 env(pay(gw, bob, CNY(300)));
+
3735 env.close();
+
3736
+
3737 env(offer(bob, drops(5400000000), CNY(216.054)));
+
3738 env.close();
+
3739
+
3740 // This offer did not round result of partial crossing correctly.
+
3741 env(offer(alice, CNY(13562.0001), drops(339000000000)));
+
3742 env.close();
3743
-
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 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();
+
3744 auto const aliceOffers = offersOnAccount(env, alice);
+
3745 BEAST_EXPECT(aliceOffers.size() == 1);
+
3746 for (auto const& offerPtr : aliceOffers)
+
3747 {
+
3748 auto const& offer = *offerPtr;
+
3749 BEAST_EXPECT(offer[sfLedgerEntryType] == ltOFFER);
+
3750 BEAST_EXPECT(offer[sfTakerGets] == drops(333599446582));
+
3751 BEAST_EXPECT(offer[sfTakerPays] == CNY(13345.9461));
+
3752 }
+
3753 }
+
+
3754
+
3755 void
+
+ +
3757 {
+
3758 // After adding the previous case, there were still failing rounding
+
3759 // cases in Flow offer crossing. This one was because the gateway
+
3760 // transfer rate was not being correctly handled.
+
3761 testcase("Offer In Scaling With Xfer Rate");
+
3762
+
3763 using namespace jtx;
+
3764
+
3765 Env env{*this, features};
3766
-
3767 // This offer caused the assert.
-
3768 env(offer(ann, BTC(0.687), drops(20000000000)),
- -
3770 }
-
-
3771
-
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;
+
3767 auto const gw = Account("gateway");
+
3768 auto const alice = Account("alice");
+
3769 auto const bob = Account("bob");
+
3770 auto const BTC = gw["BTC"];
+
3771 auto const JPY = gw["JPY"];
+
3772
+
3773 auto const fee = env.current()->fees().base;
+
3774 env.fund(reserve(env, 2) + drops(400000000000) + (fee), alice, bob);
+
3775 env.fund(reserve(env, 2) + (fee * 4), gw);
+
3776 env.close();
+
3777
+
3778 env(rate(gw, 1.002));
+
3779 env(trust(alice, JPY(4000)));
+
3780 env(trust(bob, BTC(2)));
+
3781 env.close();
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"];
+
3783 env(pay(gw, alice, JPY(3699.034802280317)));
+
3784 env(pay(gw, bob, BTC(1.156722559140311)));
+
3785 env.close();
+
3786
+
3787 env(offer(bob, JPY(1241.913390770747), BTC(0.01969825690469254)));
+
3788 env.close();
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 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 }
+
3790 // This offer did not round result of partial crossing correctly.
+
3791 env(offer(alice, BTC(0.05507568706427876), JPY(3472.696773391072)));
+
3792 env.close();
+
3793
+
3794 auto const aliceOffers = offersOnAccount(env, alice);
+
3795 BEAST_EXPECT(aliceOffers.size() == 1);
+
3796 for (auto const& offerPtr : aliceOffers)
+
3797 {
+
3798 auto const& offer = *offerPtr;
+
3799 BEAST_EXPECT(offer[sfLedgerEntryType] == ltOFFER);
+
3800 BEAST_EXPECT(
+
3801 offer[sfTakerGets] ==
+
3802 STAmount(JPY.issue(), std::uint64_t(2230682446713524ul), -12));
+
3803 BEAST_EXPECT(offer[sfTakerPays] == BTC(0.035378));
+
3804 }
+
3805 }
+
3806
+
3807 void
+
+ +
3809 {
+
3810 // Another instance where Flow offer crossing was not always
+
3811 // working right was if the Taker had fewer funds than the Offer
+
3812 // was offering. The basis for this test came off the network.
+
3813 testcase("Offer Threshold With Reduced Funds");
+
3814
+
3815 using namespace jtx;
+
3816
+
3817 Env env{*this, features};
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 using namespace jtx;
-
3828
-
3829 Env env{*this, features};
+
3819 auto const gw1 = Account("gw1");
+
3820 auto const gw2 = Account("gw2");
+
3821 auto const alice = Account("alice");
+
3822 auto const bob = Account("bob");
+
3823 auto const USD = gw1["USD"];
+
3824 auto const JPY = gw2["JPY"];
+
3825
+
3826 auto const fee = env.current()->fees().base;
+
3827 env.fund(reserve(env, 2) + drops(400000000000) + (fee), alice, bob);
+
3828 env.fund(reserve(env, 2) + (fee * 4), gw1, gw2);
+
3829 env.close();
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 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 }
+
3831 env(rate(gw1, 1.002));
+
3832 env(trust(alice, USD(1000)));
+
3833 env(trust(bob, JPY(100000)));
+
3834 env.close();
+
3835
+
3836 env(
+
3837 pay(gw1,
+
3838 alice,
+
3839 STAmount{USD.issue(), std::uint64_t(2185410179555600), -14}));
+
3840 env(
+
3841 pay(gw2,
+
3842 bob,
+
3843 STAmount{JPY.issue(), std::uint64_t(6351823459548956), -12}));
+
3844 env.close();
+
3845
+
3846 env(offer(
+
3847 bob,
+
3848 STAmount{USD.issue(), std::uint64_t(4371257532306000), -17},
+
3849 STAmount{JPY.issue(), std::uint64_t(4573216636606000), -15}));
+
3850 env.close();
+
3851
+
3852 // This offer did not partially cross correctly.
+
3853 env(offer(
+
3854 alice,
+
3855 STAmount{JPY.issue(), std::uint64_t(2291181510070762), -12},
+
3856 STAmount{USD.issue(), std::uint64_t(2190218999914694), -14}));
+
3857 env.close();
+
3858
+
3859 auto const aliceOffers = offersOnAccount(env, alice);
+
3860 BEAST_EXPECT(aliceOffers.size() == 1);
+
3861 for (auto const& offerPtr : aliceOffers)
+
3862 {
+
3863 auto const& offer = *offerPtr;
+
3864 BEAST_EXPECT(offer[sfLedgerEntryType] == ltOFFER);
+
3865 BEAST_EXPECT(
+
3866 offer[sfTakerGets] ==
+
3867 STAmount(USD.issue(), std::uint64_t(2185847305256635), -14));
+
3868 BEAST_EXPECT(
+
3869 offer[sfTakerPays] ==
+
3870 STAmount(JPY.issue(), std::uint64_t(2286608293434156), -12));
+
3871 }
+
3872 }
-
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");
+
3873
+
3874 void
+
+ +
3876 {
+
3877 testcase("Tiny Offer");
3878
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"];
+
3883 auto const gw = Account("gw");
+
3884 auto const alice = Account("alice");
+
3885 auto const bob = Account("bob");
+
3886 auto const CNY = gw["CNY"];
+
3887 auto const fee = env.current()->fees().base;
+
3888 auto const startXrpBalance = drops(400000000000) + (fee * 2);
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}));
+
3890 env.fund(startXrpBalance, gw, alice, bob);
+
3891 env.close();
+
3892
+
3893 env(trust(bob, CNY(100000)));
+
3894 env.close();
+
3895
+
3896 // Place alice's tiny offer in the book first. Let's see what happens
+
3897 // when a reasonable offer crosses it.
+
3898 STAmount const alicesCnyOffer{
+
3899 CNY.issue(), std::uint64_t(4926000000000000), -23};
+
3900
+
3901 env(offer(alice, alicesCnyOffer, drops(1), tfPassive));
+
3902 env.close();
+
3903
+
3904 // bob places an ordinary offer
+
3905 STAmount const bobsCnyStartBalance{
+
3906 CNY.issue(), std::uint64_t(3767479960090235), -15};
+
3907 env(pay(gw, bob, bobsCnyStartBalance));
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}));
+
3912 drops(203),
+
3913 STAmount{CNY.issue(), std::uint64_t(1000000000000000), -20}));
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 }
+
3916 env.require(balance(alice, alicesCnyOffer));
+
3917 env.require(balance(alice, startXrpBalance - fee - drops(1)));
+
3918 env.require(balance(bob, bobsCnyStartBalance - alicesCnyOffer));
+
3919 env.require(balance(bob, startXrpBalance - (fee * 2) + drops(1)));
+
3920 }
-
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(offer(alice, alicesCnyOffer, drops(1), tfPassive));
-
3966 env.close();
-
3967
-
3968 // bob places an ordinary offer
-
3969 STAmount const bobsCnyStartBalance{
-
3970 CNY.issue(), std::uint64_t(3767479960090235), -15};
-
3971 env(pay(gw, bob, bobsCnyStartBalance));
+
3921
+
3922 void
+
+ +
3924 {
+
3925 testcase("Self Pay Xfer Fee");
+
3926 // The old offer crossing code does not charge a transfer fee
+
3927 // if alice pays alice. That's different from how payments work.
+
3928 // Payments always charge a transfer fee even if the money is staying
+
3929 // in the same hands.
+
3930 //
+
3931 // What's an example where alice pays alice? There are three actors:
+
3932 // gw, alice, and bob.
+
3933 //
+
3934 // 1. gw issues BTC and USD. qw charges a 0.2% transfer fee.
+
3935 //
+
3936 // 2. alice makes an offer to buy XRP and sell USD.
+
3937 // 3. bob makes an offer to buy BTC and sell XRP.
+
3938 //
+
3939 // 4. alice now makes an offer to sell BTC and buy USD.
+
3940 //
+
3941 // This last offer crosses using auto-bridging.
+
3942 // o alice's last offer sells BTC to...
+
3943 // o bob' offer which takes alice's BTC and sells XRP to...
+
3944 // o alice's first offer which takes bob's XRP and sells USD to...
+
3945 // o alice's last offer.
+
3946 //
+
3947 // So alice sells USD to herself.
+
3948 //
+
3949 // There are six cases that we need to test:
+
3950 // o alice crosses her own offer on the first leg (BTC).
+
3951 // o alice crosses her own offer on the second leg (USD).
+
3952 // o alice crosses her own offers on both legs.
+
3953 // All three cases need to be tested:
+
3954 // o In reverse (alice has enough BTC to cover her offer) and
+
3955 // o Forward (alice owns less BTC than is in her final offer.
+
3956 //
+
3957 // It turns out that two of the forward cases fail for a different
+
3958 // reason. They are therefore commented out here, But they are
+
3959 // revisited in the testSelfPayUnlimitedFunds() unit test.
+
3960
+
3961 using namespace jtx;
+
3962
+
3963 Env env{*this, features};
+
3964 auto const baseFee = env.current()->fees().base.drops();
+
3965
+
3966 auto const gw = Account("gw");
+
3967 auto const BTC = gw["BTC"];
+
3968 auto const USD = gw["USD"];
+
3969 auto const startXrpBalance = XRP(4000000);
+
3970
+
3971 env.fund(startXrpBalance, gw);
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 }
-
-
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 // 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 // So alice sells USD to herself.
-
4012 //
-
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 // 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.
+
3974 env(rate(gw, 1.25));
+
3975 env.close();
+
3976
+
3977 // Test cases
+
3978 struct Actor
+
3979 {
+
3980 Account acct;
+
3981 int offers; // offers on account after crossing
+
3982 PrettyAmount xrp; // final expected after crossing
+
3983 PrettyAmount btc; // final expected after crossing
+
3984 PrettyAmount usd; // final expected after crossing
+
3985 };
+
3986 struct TestData
+
3987 {
+
3988 // The first three three integers give the *index* in actors
+
3989 // to assign each of the three roles. By using indices it is
+
3990 // easy for alice to own the offer in the first leg, the second
+
3991 // leg, or both.
+
3992 std::size_t self;
+
3993 std::size_t leg0;
+
3994 std::size_t leg1;
+
3995 PrettyAmount btcStart;
+
3996 std::vector<Actor> actors;
+
3997 };
+
3998
+
3999 // clang-format off
+
4000 TestData const tests[]{
+
4001 // btcStart --------------------- actor[0] --------------------- -------------------- actor[1] -------------------
+
4002 {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
+
4003 {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
+
4004 {0, 0, 0, BTC(20), {{"cam", 0, drops(4000000'000000 - 5 * baseFee), BTC(20.0), USD(2000)} }}, // no xfer fee
+
4005 {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
+
4006 };
+
4007 // clang-format on
+
4008
+
4009 for (auto const& t : tests)
+
4010 {
+
4011 Account const& self = t.actors[t.self].acct;
+
4012 Account const& leg0 = t.actors[t.leg0].acct;
+
4013 Account const& leg1 = t.actors[t.leg1].acct;
+
4014
+
4015 for (auto const& actor : t.actors)
+
4016 {
+
4017 env.fund(XRP(4000000), actor.acct);
+
4018 env.close();
+
4019
+
4020 env(trust(actor.acct, BTC(40)));
+
4021 env(trust(actor.acct, USD(8000)));
+
4022 env.close();
+
4023 }
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.fund(startXrpBalance, gw);
-
4036 env.close();
-
4037
-
4038 env(rate(gw, 1.25));
-
4039 env.close();
+
4025 env(pay(gw, self, t.btcStart));
+
4026 env(pay(gw, self, USD(2000)));
+
4027 if (self.id() != leg1.id())
+
4028 env(pay(gw, leg1, USD(2000)));
+
4029 env.close();
+
4030
+
4031 // Get the initial offers in place. Remember their sequences
+
4032 // so we can delete them later.
+
4033 env(offer(leg0, BTC(10), XRP(100000), tfPassive));
+
4034 env.close();
+
4035 std::uint32_t const leg0OfferSeq = env.seq(leg0) - 1;
+
4036
+
4037 env(offer(leg1, XRP(100000), USD(1000), tfPassive));
+
4038 env.close();
+
4039 std::uint32_t const leg1OfferSeq = env.seq(leg1) - 1;
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 // 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 }
+
4041 // This is the offer that matters.
+
4042 env(offer(self, USD(1000), BTC(10)));
+
4043 env.close();
+
4044 std::uint32_t const selfOfferSeq = env.seq(self) - 1;
+
4045
+
4046 // Verify results.
+
4047 for (auto const& actor : t.actors)
+
4048 {
+
4049 // Sometimes Taker crossing gets lazy about deleting offers.
+
4050 // Treat an empty offer as though it is deleted.
+
4051 auto actorOffers = offersOnAccount(env, actor.acct);
+
4052 auto const offerCount = std::distance(
+
4053 actorOffers.begin(),
+ +
4055 actorOffers.begin(),
+
4056 actorOffers.end(),
+ +
4058 return (*offer)[sfTakerGets].signum() == 0;
+
4059 }));
+
4060 BEAST_EXPECT(offerCount == actor.offers);
+
4061
+
4062 env.require(balance(actor.acct, actor.xrp));
+
4063 env.require(balance(actor.acct, actor.btc));
+
4064 env.require(balance(actor.acct, actor.usd));
+
4065 }
+
4066 // Remove any offers that might be left hanging around. They
+
4067 // could bollix up later loops.
+
4068 env(offer_cancel(leg0, leg0OfferSeq));
+
4069 env.close();
+
4070 env(offer_cancel(leg1, leg1OfferSeq));
+
4071 env.close();
+
4072 env(offer_cancel(self, selfOfferSeq));
+
4073 env.close();
+
4074 }
+
4075 }
-
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 // 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);
+
4076
+
4077 void
+
+ +
4079 {
+
4080 testcase("Self Pay Unlimited Funds");
+
4081 // The Taker offer crossing code recognized when Alice was paying
+
4082 // Alice the same denomination. In this case, as long as Alice
+
4083 // has a little bit of that denomination, it treats Alice as though
+
4084 // she has unlimited funds in that denomination.
+
4085 //
+
4086 // Huh? What kind of sense does that make?
+
4087 //
+
4088 // One way to think about it is to break a single payment into a
+
4089 // series of very small payments executed sequentially but very
+
4090 // quickly. Alice needs to pay herself 1 USD, but she only has
+
4091 // 0.01 USD. Alice says, "Hey Alice, let me pay you a penny."
+
4092 // Alice does this, taking the penny out of her pocket and then
+
4093 // putting it back in her pocket. Then she says, "Hey Alice,
+
4094 // I found another penny. I can pay you another penny." Repeat
+
4095 // these steps 100 times and Alice has paid herself 1 USD even though
+
4096 // she only owns 0.01 USD.
+
4097 //
+
4098 // That's all very nice, but the payment code does not support this
+
4099 // optimization. In part that's because the payment code can
+
4100 // operate on a whole batch of offers. As a matter of fact, it can
+
4101 // deal in two consecutive batches of offers. It would take a great
+
4102 // deal of sorting out to figure out which offers in the two batches
+
4103 // had the same owner and give them special processing. And,
+
4104 // honestly, it's a weird little corner case.
+
4105 //
+
4106 // So, since Flow offer crossing uses the payments engine, Flow
+
4107 // offer crossing no longer supports this optimization.
+
4108 //
+
4109 // The following test shows the difference in the behaviors between
+
4110 // Taker offer crossing and Flow offer crossing.
+
4111
+
4112 using namespace jtx;
+
4113
+
4114 Env env{*this, features};
+
4115 auto const baseFee = env.current()->fees().base.drops();
+
4116
+
4117 auto const gw = Account("gw");
+
4118 auto const BTC = gw["BTC"];
+
4119 auto const USD = gw["USD"];
+
4120 auto const startXrpBalance = XRP(4000000);
+
4121
+
4122 env.fund(startXrpBalance, gw);
+
4123 env.close();
+
4124
+
4125 env(rate(gw, 1.25));
+
4126 env.close();
+
4127
+
4128 // Test cases
+
4129 struct Actor
+
4130 {
+
4131 Account acct;
+
4132 int offers; // offers on account after crossing
+
4133 PrettyAmount xrp; // final expected after crossing
+
4134 PrettyAmount btc; // final expected after crossing
+
4135 PrettyAmount usd; // final expected after crossing
+
4136 };
+
4137 struct TestData
+
4138 {
+
4139 // The first three three integers give the *index* in actors
+
4140 // to assign each of the three roles. By using indices it is
+
4141 // easy for alice to own the offer in the first leg, the second
+
4142 // leg, or both.
+
4143 std::size_t self;
+
4144 std::size_t leg0;
+
4145 std::size_t leg1;
+
4146 PrettyAmount btcStart;
+
4147 std::vector<Actor> actors;
+
4148 };
+
4149
+
4150 // clang-format off
+
4151 TestData const tests[]{
+
4152 // btcStart ------------------- actor[0] -------------------- ------------------- actor[1] --------------------
+
4153 {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
+
4154 {0, 0, 0, BTC(5), {{"hye", 2, drops(4000000'000000 - 5 * baseFee), BTC(5), USD(2000)} }} // no xfer fee
+
4155 };
+
4156 // clang-format on
+
4157
+
4158 for (auto const& t : tests)
+
4159 {
+
4160 Account const& self = t.actors[t.self].acct;
+
4161 Account const& leg0 = t.actors[t.leg0].acct;
+
4162 Account const& leg1 = t.actors[t.leg1].acct;
+
4163
+
4164 for (auto const& actor : t.actors)
+
4165 {
+
4166 env.fund(XRP(4000000), actor.acct);
+
4167 env.close();
+
4168
+
4169 env(trust(actor.acct, BTC(40)));
+
4170 env(trust(actor.acct, USD(8000)));
+
4171 env.close();
+
4172 }
+
4173
+
4174 env(pay(gw, self, t.btcStart));
+
4175 env(pay(gw, self, USD(2000)));
+
4176 if (self.id() != leg1.id())
+
4177 env(pay(gw, leg1, USD(2000)));
+
4178 env.close();
+
4179
+
4180 // Get the initial offers in place. Remember their sequences
+
4181 // so we can delete them later.
+
4182 env(offer(leg0, BTC(10), XRP(100000), tfPassive));
+
4183 env.close();
+
4184 std::uint32_t const leg0OfferSeq = env.seq(leg0) - 1;
4185
-
4186 env.fund(startXrpBalance, gw);
-
4187 env.close();
-
4188
-
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 // 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 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 }
+
4186 env(offer(leg1, XRP(100000), USD(1000), tfPassive));
+
4187 env.close();
+
4188 std::uint32_t const leg1OfferSeq = env.seq(leg1) - 1;
+
4189
+
4190 // This is the offer that matters.
+
4191 env(offer(self, USD(1000), BTC(10)));
+
4192 env.close();
+
4193 std::uint32_t const selfOfferSeq = env.seq(self) - 1;
+
4194
+
4195 // Verify results.
+
4196 for (auto const& actor : t.actors)
+
4197 {
+
4198 // Sometimes Taker offer crossing gets lazy about deleting
+
4199 // offers. Treat an empty offer as though it is deleted.
+
4200 auto actorOffers = offersOnAccount(env, actor.acct);
+
4201 auto const offerCount = std::distance(
+
4202 actorOffers.begin(),
+ +
4204 actorOffers.begin(),
+
4205 actorOffers.end(),
+ +
4207 return (*offer)[sfTakerGets].signum() == 0;
+
4208 }));
+
4209 BEAST_EXPECT(offerCount == actor.offers);
+
4210
+
4211 env.require(balance(actor.acct, actor.xrp));
+
4212 env.require(balance(actor.acct, actor.btc));
+
4213 env.require(balance(actor.acct, actor.usd));
+
4214 }
+
4215 // Remove any offers that might be left hanging around. They
+
4216 // could bollix up later loops.
+
4217 env(offer_cancel(leg0, leg0OfferSeq));
+
4218 env.close();
+
4219 env(offer_cancel(leg1, leg1OfferSeq));
+
4220 env.close();
+
4221 env(offer_cancel(self, selfOfferSeq));
+
4222 env.close();
+
4223 }
+
4224 }
-
4289
-
4290 void
-
- -
4292 {
-
4293 testcase("lsfRequireAuth");
-
4294
-
4295 using namespace jtx;
-
4296
-
4297 Env env{*this, features};
+
4225
+
4226 void
+
+ +
4228 {
+
4229 testcase("lsfRequireAuth");
+
4230
+
4231 using namespace jtx;
+
4232
+
4233 Env env{*this, features};
+
4234
+
4235 auto const gw = Account("gw");
+
4236 auto const alice = Account("alice");
+
4237 auto const bob = Account("bob");
+
4238 auto const gwUSD = gw["USD"];
+
4239 auto const aliceUSD = alice["USD"];
+
4240 auto const bobUSD = bob["USD"];
+
4241
+
4242 env.fund(XRP(400000), gw, alice, bob);
+
4243 env.close();
+
4244
+
4245 // GW requires authorization for holders of its IOUs
+
4246 env(fset(gw, asfRequireAuth));
+
4247 env.close();
+
4248
+
4249 // Properly set trust and have gw authorize bob and alice
+
4250 env(trust(gw, bobUSD(100)), txflags(tfSetfAuth));
+
4251 env(trust(bob, gwUSD(100)));
+
4252 env(trust(gw, aliceUSD(100)), txflags(tfSetfAuth));
+
4253 env(trust(alice, gwUSD(100)));
+
4254 // Alice is able to place the offer since the GW has authorized her
+
4255 env(offer(alice, gwUSD(40), XRP(4000)));
+
4256 env.close();
+
4257
+
4258 env.require(offers(alice, 1));
+
4259 env.require(balance(alice, gwUSD(0)));
+
4260
+
4261 env(pay(gw, bob, gwUSD(50)));
+
4262 env.close();
+
4263
+
4264 env.require(balance(bob, gwUSD(50)));
+
4265
+
4266 // Bob's offer should cross Alice's
+
4267 env(offer(bob, XRP(4000), gwUSD(40)));
+
4268 env.close();
+
4269
+
4270 env.require(offers(alice, 0));
+
4271 env.require(balance(alice, gwUSD(40)));
+
4272
+
4273 env.require(offers(bob, 0));
+
4274 env.require(balance(bob, gwUSD(10)));
+
4275 }
+
+
4276
+
4277 void
+
+ +
4279 {
+
4280 testcase("Missing Auth");
+
4281 // 1. alice creates an offer to acquire USD/gw, an asset for which
+
4282 // she does not have a trust line. At some point in the future,
+
4283 // gw adds lsfRequireAuth. Then, later, alice's offer is crossed.
+
4284 // Alice's offer is deleted, not consumed, since alice is not
+
4285 // authorized to hold USD/gw.
+
4286 //
+
4287 // 2. alice tries to create an offer for USD/gw, now that gw has
+
4288 // lsfRequireAuth set. This time the offer create fails because
+
4289 // alice is not authorized to hold USD/gw.
+
4290 //
+
4291 // 3. Next, gw creates a trust line to alice, but does not set
+
4292 // tfSetfAuth on that trust line. alice attempts to create an
+
4293 // offer and again fails.
+
4294 //
+
4295 // 4. Finally, gw sets tsfSetAuth on the trust line authorizing
+
4296 // alice to own USD/gw. At this point alice successfully
+
4297 // creates and crosses an offer for USD/gw.
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));
+
4299 using namespace jtx;
+
4300
+
4301 Env env{*this, features};
+
4302
+
4303 auto const gw = Account("gw");
+
4304 auto const alice = Account("alice");
+
4305 auto const bob = Account("bob");
+
4306 auto const gwUSD = gw["USD"];
+
4307 auto const aliceUSD = alice["USD"];
+
4308 auto const bobUSD = bob["USD"];
+
4309
+
4310 env.fund(XRP(400000), gw, alice, bob);
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
+
4313 env(offer(alice, gwUSD(40), XRP(4000)));
+
4314 env.close();
+
4315
+
4316 env.require(offers(alice, 1));
+
4317 env.require(balance(alice, gwUSD(none)));
+
4318 env(fset(gw, asfRequireAuth));
+
4319 env.close();
+
4320
+
4321 env(trust(gw, bobUSD(100)), txflags(tfSetfAuth));
+
4322 env.close();
+
4323 env(trust(bob, gwUSD(100)));
+
4324 env.close();
+
4325
+
4326 env(pay(gw, bob, gwUSD(50)));
+
4327 env.close();
4328 env.require(balance(bob, gwUSD(50)));
4329
-
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 }
-
-
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 // 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;
+
4330 // gw now requires authorization and bob has gwUSD(50). Let's see if
+
4331 // bob can cross alice's offer.
+
4332 //
+
4333 // Bob's offer shouldn't cross and alice's unauthorized offer should be
+
4334 // deleted.
+
4335 env(offer(bob, XRP(4000), gwUSD(40)));
+
4336 env.close();
+
4337 std::uint32_t const bobOfferSeq = env.seq(bob) - 1;
+
4338
+
4339 env.require(offers(alice, 0));
+
4340 // alice's unauthorized offer is deleted & bob's offer not crossed.
+
4341 env.require(balance(alice, gwUSD(none)));
+
4342 env.require(offers(bob, 1));
+
4343 env.require(balance(bob, gwUSD(50)));
+
4344
+
4345 // See if alice can create an offer without authorization. alice
+
4346 // should not be able to create the offer and bob's offer should be
+
4347 // untouched.
+
4348 env(offer(alice, gwUSD(40), XRP(4000)), ter(tecNO_LINE));
+
4349 env.close();
+
4350
+
4351 env.require(offers(alice, 0));
+
4352 env.require(balance(alice, gwUSD(none)));
+
4353
+
4354 env.require(offers(bob, 1));
+
4355 env.require(balance(bob, gwUSD(50)));
+
4356
+
4357 // Set up a trust line for alice, but don't authorize it. alice
+
4358 // should still not be able to create an offer for USD/gw.
+
4359 env(trust(gw, aliceUSD(100)));
+
4360 env.close();
+
4361
+
4362 env(offer(alice, gwUSD(40), XRP(4000)), ter(tecNO_AUTH));
+
4363 env.close();
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));
+
4365 env.require(offers(alice, 0));
+
4366 env.require(balance(alice, gwUSD(0)));
+
4367
+
4368 env.require(offers(bob, 1));
+
4369 env.require(balance(bob, gwUSD(50)));
+
4370
+
4371 // Delete bob's offer so alice can create an offer without crossing.
+
4372 env(offer_cancel(bob, bobOfferSeq));
+
4373 env.close();
+
4374 env.require(offers(bob, 0));
+
4375
+
4376 // Finally, set up an authorized trust line for alice. Now alice's
+
4377 // offer should succeed. Note that, since this is an offer rather
+
4378 // than a payment, alice does not need to set a trust line limit.
+
4379 env(trust(gw, aliceUSD(100)), txflags(tfSetfAuth));
+
4380 env.close();
+
4381
+
4382 env(offer(alice, gwUSD(40), XRP(4000)));
4383 env.close();
4384
-
4385 env(trust(gw, bobUSD(100)), txflags(tfSetfAuth));
-
4386 env.close();
-
4387 env(trust(bob, gwUSD(100)));
-
4388 env.close();
-
4389
-
4390 env(pay(gw, bob, gwUSD(50)));
-
4391 env.close();
-
4392 env.require(balance(bob, gwUSD(50)));
+
4385 env.require(offers(alice, 1));
+
4386
+
4387 // Now bob creates his offer again. alice's offer should cross.
+
4388 env(offer(bob, XRP(4000), gwUSD(40)));
+
4389 env.close();
+
4390
+
4391 env.require(offers(alice, 0));
+
4392 env.require(balance(alice, gwUSD(40)));
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)));
+
4394 env.require(offers(bob, 0));
+
4395 env.require(balance(bob, gwUSD(10)));
+
4396 }
+
+
4397
+
4398 void
+
+ +
4400 {
+
4401 testcase("RippleConnect Smoketest payment flow");
+
4402 using namespace jtx;
+
4403
+
4404 Env env{*this, features};
+
4405
+
4406 // This test mimics the payment flow used in the Ripple Connect
+
4407 // smoke test. The players:
+
4408 // A USD gateway with hot and cold wallets
+
4409 // A EUR gateway with hot and cold walllets
+
4410 // A MM gateway that will provide offers from USD->EUR and EUR->USD
+
4411 // A path from hot US to cold EUR is found and then used to send
+
4412 // USD for EUR that goes through the market maker
+
4413
+
4414 auto const hotUS = Account("hotUS");
+
4415 auto const coldUS = Account("coldUS");
+
4416 auto const hotEU = Account("hotEU");
+
4417 auto const coldEU = Account("coldEU");
+
4418 auto const mm = Account("mm");
+
4419
+
4420 auto const USD = coldUS["USD"];
+
4421 auto const EUR = coldEU["EUR"];
+
4422
+
4423 env.fund(XRP(100000), hotUS, coldUS, hotEU, coldEU, mm);
4424 env.close();
4425
-
4426 env(offer(alice, gwUSD(40), XRP(4000)), ter(tecNO_AUTH));
-
4427 env.close();
-
4428
-
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 // 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)));
+
4426 // Cold wallets require trust but will ripple by default
+
4427 for (auto const& cold : {coldUS, coldEU})
+
4428 {
+
4429 env(fset(cold, asfRequireAuth));
+
4430 env(fset(cold, asfDefaultRipple));
+
4431 }
+
4432 env.close();
+
4433
+
4434 // Each hot wallet trusts the related cold wallet for a large amount
+
4435 env(trust(hotUS, USD(10000000)), txflags(tfSetNoRipple));
+
4436 env(trust(hotEU, EUR(10000000)), txflags(tfSetNoRipple));
+
4437 // Market maker trusts both cold wallets for a large amount
+
4438 env(trust(mm, USD(10000000)), txflags(tfSetNoRipple));
+
4439 env(trust(mm, EUR(10000000)), txflags(tfSetNoRipple));
+
4440 env.close();
+
4441
+
4442 // Gateways authorize the trustlines of hot and market maker
+
4443 env(trust(coldUS, USD(0), hotUS, tfSetfAuth));
+
4444 env(trust(coldEU, EUR(0), hotEU, tfSetfAuth));
+
4445 env(trust(coldUS, USD(0), mm, tfSetfAuth));
+
4446 env(trust(coldEU, EUR(0), mm, tfSetfAuth));
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 // 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
+
4449 // Issue currency from cold wallets to hot and market maker
+
4450 env(pay(coldUS, hotUS, USD(5000000)));
+
4451 env(pay(coldEU, hotEU, EUR(5000000)));
+
4452 env(pay(coldUS, mm, USD(5000000)));
+
4453 env(pay(coldEU, mm, EUR(5000000)));
+
4454 env.close();
+
4455
+
4456 // MM places offers
+
4457 float const rate = 0.9f; // 0.9 USD = 1 EUR
+
4458 env(offer(mm, EUR(4000000 * rate), USD(4000000)),
+
4459 json(jss::Flags, tfSell));
+
4460
+
4461 float const reverseRate = 1.0f / rate * 1.00101f;
+
4462 env(offer(mm, USD(4000000 * reverseRate), EUR(4000000)),
+
4463 json(jss::Flags, tfSell));
+
4464 env.close();
+
4465
+
4466 // There should be a path available from hot US to cold EUR
+
4467 {
+
4468 Json::Value jvParams;
+
4469 jvParams[jss::destination_account] = coldEU.human();
+
4470 jvParams[jss::destination_amount][jss::issuer] = coldEU.human();
+
4471 jvParams[jss::destination_amount][jss::currency] = "EUR";
+
4472 jvParams[jss::destination_amount][jss::value] = 10;
+
4473 jvParams[jss::source_account] = hotUS.human();
+
4474
+
4475 Json::Value const jrr{env.rpc(
+
4476 "json", "ripple_path_find", to_string(jvParams))[jss::result]};
4477
-
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"];
+
4478 BEAST_EXPECT(jrr[jss::status] == "success");
+
4479 BEAST_EXPECT(
+
4480 jrr[jss::alternatives].isArray() &&
+
4481 jrr[jss::alternatives].size() > 0);
+
4482 }
+
4483 // Send the payment using the found path.
+
4484 env(pay(hotUS, coldEU, EUR(10)), sendmax(USD(11.1223326)));
+
4485 }
+
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 // 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 // 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();
+
4487 void
+
+ +
4489 {
+
4490 testcase("Self Auth");
+
4491
+
4492 using namespace jtx;
+
4493
+
4494 Env env{*this, features};
+
4495
+
4496 auto const gw = Account("gw");
+
4497 auto const alice = Account("alice");
+
4498 auto const gwUSD = gw["USD"];
+
4499 auto const aliceUSD = alice["USD"];
+
4500
+
4501 env.fund(XRP(400000), gw, alice);
+
4502 env.close();
+
4503
+
4504 // Test that gw can create an offer to buy gw's currency.
+
4505 env(offer(gw, gwUSD(40), XRP(4000)));
+
4506 env.close();
+
4507 std::uint32_t const gwOfferSeq = env.seq(gw) - 1;
+
4508 env.require(offers(gw, 1));
+
4509
+
4510 // Since gw has an offer out, gw should not be able to set RequireAuth.
+
4511 env(fset(gw, asfRequireAuth), ter(tecOWNERS));
+
4512 env.close();
+
4513
+
4514 // Cancel gw's offer so we can set RequireAuth.
+
4515 env(offer_cancel(gw, gwOfferSeq));
+
4516 env.close();
+
4517 env.require(offers(gw, 0));
+
4518
+
4519 // gw now requires authorization for holders of its IOUs
+
4520 env(fset(gw, asfRequireAuth));
+
4521 env.close();
+
4522
+
4523 // The test behaves differently with or without DepositPreauth.
+
4524 bool const preauth = features[featureDepositPreauth];
+
4525
+
4526 // Before DepositPreauth an account with lsfRequireAuth set could not
+
4527 // create an offer to buy their own currency. After DepositPreauth
+
4528 // they can.
+
4529 env(offer(gw, gwUSD(40), XRP(4000)),
+
4530 ter(preauth ? TER{tesSUCCESS} : TER{tecNO_LINE}));
+
4531 env.close();
+
4532
+
4533 env.require(offers(gw, preauth ? 1 : 0));
+
4534
+
4535 if (!preauth)
+
4536 // The rest of the test verifies DepositPreauth behavior.
+
4537 return;
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 }
-
-
4550
-
4551 void
-
- -
4553 {
-
4554 testcase("Self Auth");
+
4539 // Set up an authorized trust line and pay alice gwUSD 50.
+
4540 env(trust(gw, aliceUSD(100)), txflags(tfSetfAuth));
+
4541 env(trust(alice, gwUSD(100)));
+
4542 env.close();
+
4543
+
4544 env(pay(gw, alice, gwUSD(50)));
+
4545 env.close();
+
4546
+
4547 env.require(balance(alice, gwUSD(50)));
+
4548
+
4549 // alice's offer should cross gw's
+
4550 env(offer(alice, XRP(4000), gwUSD(40)));
+
4551 env.close();
+
4552
+
4553 env.require(offers(alice, 0));
+
4554 env.require(balance(alice, gwUSD(10)));
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"];
+
4556 env.require(offers(gw, 0));
+
4557 }
+
+
4558
+
4559 void
+
+ +
4561 {
+
4562 // Show that an offer who's issuer has been deleted cannot be crossed.
+
4563 using namespace jtx;
4564
-
4565 env.fund(XRP(400000), gw, alice);
-
4566 env.close();
-
4567
-
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));
+
4565 testcase("Deleted offer issuer");
+
4566
+
4567 auto trustLineExists = [](jtx::Env const& env,
+
4568 jtx::Account const& src,
+
4569 jtx::Account const& dst,
+
4570 Currency const& cur) -> bool {
+
4571 return bool(env.le(keylet::line(src, dst, cur)));
+
4572 };
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));
+
4574 Account const alice("alice");
+
4575 Account const becky("becky");
+
4576 Account const carol("carol");
+
4577 Account const gw("gateway");
+
4578 auto const USD = gw["USD"];
+
4579 auto const BUX = alice["BUX"];
+
4580
+
4581 Env env{*this, features};
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];
+
4583 env.fund(XRP(10000), alice, becky, carol, noripple(gw));
+
4584 env.close();
+
4585 env.trust(USD(1000), becky);
+
4586 env(pay(gw, becky, USD(5)));
+
4587 env.close();
+
4588 BEAST_EXPECT(trustLineExists(env, gw, becky, USD.currency));
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 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 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 };
+
4590 // Make offers that produce USD and can be crossed two ways:
+
4591 // direct XRP -> USD
+
4592 // direct BUX -> USD
+
4593 env(offer(becky, XRP(2), USD(2)), txflags(tfPassive));
+
4594 std::uint32_t const beckyBuxUsdSeq{env.seq(becky)};
+
4595 env(offer(becky, BUX(3), USD(3)), txflags(tfPassive));
+
4596 env.close();
+
4597
+
4598 // becky keeps the offers, but removes the trustline.
+
4599 env(pay(becky, gw, USD(5)));
+
4600 env.trust(USD(0), becky);
+
4601 env.close();
+
4602 BEAST_EXPECT(!trustLineExists(env, gw, becky, USD.currency));
+
4603 BEAST_EXPECT(isOffer(env, becky, XRP(2), USD(2)));
+
4604 BEAST_EXPECT(isOffer(env, becky, BUX(3), USD(3)));
+
4605
+
4606 // Delete gw's account.
+
4607 {
+
4608 // The ledger sequence needs to far enough ahead of the account
+
4609 // sequence before the account can be deleted.
+
4610 int const delta =
+
4611 [&env, &gw, openLedgerSeq = env.current()->seq()]() -> int {
+
4612 std::uint32_t const gwSeq{env.seq(gw)};
+
4613 if (gwSeq + 255 > openLedgerSeq)
+
4614 return gwSeq - openLedgerSeq + 255;
+
4615 return 0;
+
4616 }();
+
4617
+
4618 for (int i = 0; i < delta; ++i)
+
4619 env.close();
+
4620
+
4621 // Account deletion has a high fee. Account for that.
+
4622 env(acctdelete(gw, alice),
+
4623 fee(drops(env.current()->fees().increment)));
+
4624 env.close();
+
4625
+
4626 // Verify that gw's account root is gone from the ledger.
+
4627 BEAST_EXPECT(!env.closed()->exists(keylet::account(gw.id())));
+
4628 }
+
4629
+
4630 // alice crosses becky's first offer. The offer create fails because
+
4631 // the USD issuer is not in the ledger.
+
4632 env(offer(alice, USD(2), XRP(2)), ter(tecNO_ISSUER));
+
4633 env.close();
+
4634 env.require(offers(alice, 0));
+
4635 BEAST_EXPECT(isOffer(env, becky, XRP(2), USD(2)));
+
4636 BEAST_EXPECT(isOffer(env, becky, BUX(3), USD(3)));
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"];
+
4638 // alice crosses becky's second offer. Again, the offer create fails
+
4639 // because the USD issuer is not in the ledger.
+
4640 env(offer(alice, USD(3), BUX(3)), ter(tecNO_ISSUER));
+
4641 env.require(offers(alice, 0));
+
4642 BEAST_EXPECT(isOffer(env, becky, XRP(2), USD(2)));
+
4643 BEAST_EXPECT(isOffer(env, becky, BUX(3), USD(3)));
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 // 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 // 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 // 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)));
+
4645 // Cancel becky's BUX -> USD offer so we can try auto-bridging.
+
4646 env(offer_cancel(becky, beckyBuxUsdSeq));
+
4647 env.close();
+
4648 BEAST_EXPECT(!isOffer(env, becky, BUX(3), USD(3)));
+
4649
+
4650 // alice creates an offer that can be auto-bridged with becky's
+
4651 // remaining offer.
+
4652 env.trust(BUX(1000), carol);
+
4653 env(pay(alice, carol, BUX(2)));
+
4654
+
4655 env(offer(alice, BUX(2), XRP(2)));
+
4656 env.close();
+
4657
+
4658 // carol attempts the auto-bridge. Again, the offer create fails
+
4659 // because the USD issuer is not in the ledger.
+
4660 env(offer(carol, USD(2), BUX(2)), ter(tecNO_ISSUER));
+
4661 env.close();
+
4662 BEAST_EXPECT(isOffer(env, alice, BUX(2), XRP(2)));
+
4663 BEAST_EXPECT(isOffer(env, becky, XRP(2), USD(2)));
+
4664 }
+
+
4665
+
4666 void
+
+ +
4668 {
+
4669 testcase("Tick Size");
+
4670
+
4671 using namespace jtx;
+
4672
+
4673 // Try to set tick size out of range
+
4674 {
+
4675 Env env{*this, features};
+
4676 auto const gw = Account{"gateway"};
+
4677 env.fund(XRP(10000), gw);
+
4678 env.close();
+
4679
+
4680 auto txn = noop(gw);
+
4681 txn[sfTickSize.fieldName] = Quality::minTickSize - 1;
+
4682 env(txn, ter(temBAD_TICK_SIZE));
+
4683
+
4684 txn[sfTickSize.fieldName] = Quality::minTickSize;
+
4685 env(txn);
+
4686 BEAST_EXPECT((*env.le(gw))[sfTickSize] == Quality::minTickSize);
+
4687
+
4688 txn = noop(gw);
+
4689 txn[sfTickSize.fieldName] = Quality::maxTickSize;
+
4690 env(txn);
+
4691 BEAST_EXPECT(!env.le(gw)->isFieldPresent(sfTickSize));
+
4692
+
4693 txn = noop(gw);
+
4694 txn[sfTickSize.fieldName] = Quality::maxTickSize - 1;
+
4695 env(txn);
+
4696 BEAST_EXPECT((*env.le(gw))[sfTickSize] == Quality::maxTickSize - 1);
+
4697
+
4698 txn = noop(gw);
+
4699 txn[sfTickSize.fieldName] = Quality::maxTickSize + 1;
+
4700 env(txn, ter(temBAD_TICK_SIZE));
4701
-
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 // 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 }
-
+
4702 txn[sfTickSize.fieldName] = 0;
+
4703 env(txn);
+
4704 BEAST_EXPECT(!env.le(gw)->isFieldPresent(sfTickSize));
+
4705 }
+
4706
+
4707 Env env{*this, features};
+
4708 auto const gw = Account{"gateway"};
+
4709 auto const alice = Account{"alice"};
+
4710 auto const XTS = gw["XTS"];
+
4711 auto const XXX = gw["XXX"];
+
4712
+
4713 env.fund(XRP(10000), gw, alice);
+
4714 env.close();
+
4715
+
4716 {
+
4717 // Gateway sets its tick size to 5
+
4718 auto txn = noop(gw);
+
4719 txn[sfTickSize.fieldName] = 5;
+
4720 env(txn);
+
4721 BEAST_EXPECT((*env.le(gw))[sfTickSize] == 5);
+
4722 }
+
4723
+
4724 env(trust(alice, XTS(1000)));
+
4725 env(trust(alice, XXX(1000)));
+
4726
+
4727 env(pay(gw, alice, alice["XTS"](100)));
+
4728 env(pay(gw, alice, alice["XXX"](100)));
4729
-
4730 void
-
- -
4732 {
-
4733 testcase("Tick Size");
+
4730 env(offer(alice, XTS(10), XXX(30)));
+
4731 env(offer(alice, XTS(30), XXX(10)));
+
4732 env(offer(alice, XTS(10), XXX(30)), json(jss::Flags, tfSell));
+
4733 env(offer(alice, XTS(30), XXX(10)), json(jss::Flags, tfSell));
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);
+ + +
4737 *env.current(), alice, [&](std::shared_ptr<SLE const> const& sle) {
+
4738 if (sle->getType() == ltOFFER)
+
4739 offers.emplace(
+
4740 (*sle)[sfSequence],
+
4741 std::make_pair(
+
4742 (*sle)[sfTakerPays], (*sle)[sfTakerGets]));
+
4743 });
+
4744
+
4745 // first offer
+
4746 auto it = offers.begin();
+
4747 BEAST_EXPECT(it != offers.end());
+
4748 BEAST_EXPECT(
+
4749 it->second.first == XTS(10) && it->second.second < XXX(30) &&
+
4750 it->second.second > XXX(29.9994));
4751
-
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)->isFieldPresent(sfTickSize));
-
4769 }
+
4752 // second offer
+
4753 ++it;
+
4754 BEAST_EXPECT(it != offers.end());
+
4755 BEAST_EXPECT(
+
4756 it->second.first == XTS(30) && it->second.second == XXX(10));
+
4757
+
4758 // third offer
+
4759 ++it;
+
4760 BEAST_EXPECT(it != offers.end());
+
4761 BEAST_EXPECT(
+
4762 it->second.first == XTS(10.0002) && it->second.second == XXX(30));
+
4763
+
4764 // fourth offer
+
4765 // exact TakerPays is XTS(1/.033333)
+
4766 ++it;
+
4767 BEAST_EXPECT(it != offers.end());
+
4768 BEAST_EXPECT(
+
4769 it->second.first == XTS(30) && it->second.second == XXX(10));
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 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
- - -
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 });
+
4771 BEAST_EXPECT(++it == offers.end());
+
4772 }
+
+
4773
+
4774 // Helper function that returns offers on an account sorted by sequence.
+ +
+ +
4777 {
+ +
4779 offersOnAccount(env, acct)};
+
4780 std::sort(
+
4781 offers.begin(),
+
4782 offers.end(),
+
4783 [](std::shared_ptr<SLE const> const& rhs,
+
4784 std::shared_ptr<SLE const> const& lhs) {
+
4785 return (*rhs)[sfSequence] < (*lhs)[sfSequence];
+
4786 });
+
4787 return offers;
+
4788 }
+
+
4789
+
4790 void
+
+ +
4792 {
+
4793 testcase("Ticket Offers");
+
4794
+
4795 using namespace jtx;
+
4796
+
4797 // Two goals for this test.
+
4798 //
+
4799 // o Verify that offers can be created using tickets.
+
4800 //
+
4801 // o Show that offers in the _same_ order book remain in
+
4802 // chronological order regardless of sequence/ticket numbers.
+
4803 Env env{*this, features};
+
4804 auto const gw = Account{"gateway"};
+
4805 auto const alice = Account{"alice"};
+
4806 auto const bob = Account{"bob"};
+
4807 auto const USD = gw["USD"];
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));
+
4809 env.fund(XRP(10000), gw, alice, bob);
+
4810 env.close();
+
4811
+
4812 env(trust(alice, USD(1000)));
+
4813 env(trust(bob, USD(1000)));
+
4814 env.close();
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 }
-
-
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 }
-
-
4853
-
4854 void
-
- -
4856 {
-
4857 testcase("Ticket Offers");
+
4816 env(pay(gw, alice, USD(200)));
+
4817 env.close();
+
4818
+
4819 // Create four offers from the same account with identical quality
+
4820 // so they go in the same order book. Each offer goes in a different
+
4821 // ledger so the chronology is clear.
+
4822 std::uint32_t const offerId_0{env.seq(alice)};
+
4823 env(offer(alice, XRP(50), USD(50)));
+
4824 env.close();
+
4825
+
4826 // Create two tickets.
+
4827 std::uint32_t const ticketSeq{env.seq(alice) + 1};
+
4828 env(ticket::create(alice, 2));
+
4829 env.close();
+
4830
+
4831 // Create another sequence-based offer.
+
4832 std::uint32_t const offerId_1{env.seq(alice)};
+
4833 BEAST_EXPECT(offerId_1 == offerId_0 + 4);
+
4834 env(offer(alice, XRP(50), USD(50)));
+
4835 env.close();
+
4836
+
4837 // Create two ticket based offers in reverse order.
+
4838 std::uint32_t const offerId_2{ticketSeq + 1};
+
4839 env(offer(alice, XRP(50), USD(50)), ticket::use(offerId_2));
+
4840 env.close();
+
4841
+
4842 // Create the last offer.
+
4843 std::uint32_t const offerId_3{ticketSeq};
+
4844 env(offer(alice, XRP(50), USD(50)), ticket::use(offerId_3));
+
4845 env.close();
+
4846
+
4847 // Verify that all of alice's offers are present.
+
4848 {
+
4849 auto offers = sortedOffersOnAccount(env, alice);
+
4850 BEAST_EXPECT(offers.size() == 4);
+
4851 BEAST_EXPECT(offers[0]->getFieldU32(sfSequence) == offerId_0);
+
4852 BEAST_EXPECT(offers[1]->getFieldU32(sfSequence) == offerId_3);
+
4853 BEAST_EXPECT(offers[2]->getFieldU32(sfSequence) == offerId_2);
+
4854 BEAST_EXPECT(offers[3]->getFieldU32(sfSequence) == offerId_1);
+
4855 env.require(balance(alice, USD(200)));
+
4856 env.require(owners(alice, 5));
+
4857 }
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);
+
4859 // Cross alice's first offer.
+
4860 env(offer(bob, USD(50), XRP(50)));
+
4861 env.close();
+
4862
+
4863 // Verify that the first offer alice created was consumed.
+
4864 {
+
4865 auto offers = sortedOffersOnAccount(env, alice);
+
4866 BEAST_EXPECT(offers.size() == 3);
+
4867 BEAST_EXPECT(offers[0]->getFieldU32(sfSequence) == offerId_3);
+
4868 BEAST_EXPECT(offers[1]->getFieldU32(sfSequence) == offerId_2);
+
4869 BEAST_EXPECT(offers[2]->getFieldU32(sfSequence) == offerId_1);
+
4870 }
+
4871
+
4872 // Cross alice's second offer.
+
4873 env(offer(bob, USD(50), XRP(50)));
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();
+
4876 // Verify that the second offer alice created was consumed.
+
4877 {
+
4878 auto offers = sortedOffersOnAccount(env, alice);
+
4879 BEAST_EXPECT(offers.size() == 2);
+
4880 BEAST_EXPECT(offers[0]->getFieldU32(sfSequence) == offerId_3);
+
4881 BEAST_EXPECT(offers[1]->getFieldU32(sfSequence) == offerId_2);
+
4882 }
+
4883
+
4884 // Cross alice's third offer.
+
4885 env(offer(bob, USD(50), XRP(50)));
+
4886 env.close();
+
4887
+
4888 // Verify that the third offer alice created was consumed.
+
4889 {
+
4890 auto offers = sortedOffersOnAccount(env, alice);
+
4891 BEAST_EXPECT(offers.size() == 1);
+
4892 BEAST_EXPECT(offers[0]->getFieldU32(sfSequence) == offerId_3);
+
4893 }
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)));
+
4895 // Cross alice's last offer.
+
4896 env(offer(bob, USD(50), XRP(50)));
+
4897 env.close();
+
4898
+
4899 // Verify that the third offer alice created was consumed.
+
4900 {
+
4901 auto offers = sortedOffersOnAccount(env, alice);
+
4902 BEAST_EXPECT(offers.size() == 0);
+
4903 }
+
4904 env.require(balance(alice, USD(0)));
+
4905 env.require(owners(alice, 1));
+
4906 env.require(balance(bob, USD(200)));
+
4907 env.require(owners(bob, 1));
+
4908 }
+
+
4909
+
4910 void
+
+ +
4912 {
+
4913 testcase("Ticket Cancel Offers");
+
4914
+
4915 using namespace jtx;
+
4916
+
4917 // Verify that offers created with or without tickets can be canceled
+
4918 // by transactions with or without tickets.
+
4919 Env env{*this, features};
+
4920 auto const gw = Account{"gateway"};
+
4921 auto const alice = Account{"alice"};
+
4922 auto const USD = gw["USD"];
+
4923
+
4924 env.fund(XRP(10000), gw, alice);
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();
+
4927 env(trust(alice, USD(1000)));
+
4928 env.close();
+
4929 env.require(owners(alice, 1), tickets(alice, 0));
+
4930
+
4931 env(pay(gw, alice, USD(200)));
+
4932 env.close();
+
4933
+
4934 // Create the first of four offers using a sequence.
+
4935 std::uint32_t const offerSeqId_0{env.seq(alice)};
+
4936 env(offer(alice, XRP(50), USD(50)));
+
4937 env.close();
+
4938 env.require(owners(alice, 2), tickets(alice, 0));
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 // Cross alice's third offer.
-
4949 env(offer(bob, USD(50), XRP(50)));
+
4940 // Create four tickets.
+
4941 std::uint32_t const ticketSeq{env.seq(alice) + 1};
+
4942 env(ticket::create(alice, 4));
+
4943 env.close();
+
4944 env.require(owners(alice, 6), tickets(alice, 4));
+
4945
+
4946 // Create the second (also sequence-based) offer.
+
4947 std::uint32_t const offerSeqId_1{env.seq(alice)};
+
4948 BEAST_EXPECT(offerSeqId_1 == offerSeqId_0 + 6);
+
4949 env(offer(alice, XRP(50), USD(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 }
-
+
4952 // Create the third (ticket-based) offer.
+
4953 std::uint32_t const offerTixId_0{ticketSeq + 1};
+
4954 env(offer(alice, XRP(50), USD(50)), ticket::use(offerTixId_0));
+
4955 env.close();
+
4956
+
4957 // Create the last offer.
+
4958 std::uint32_t const offerTixId_1{ticketSeq};
+
4959 env(offer(alice, XRP(50), USD(50)), ticket::use(offerTixId_1));
+
4960 env.close();
+
4961
+
4962 // Verify that all of alice's offers are present.
+
4963 {
+
4964 auto offers = sortedOffersOnAccount(env, alice);
+
4965 BEAST_EXPECT(offers.size() == 4);
+
4966 BEAST_EXPECT(offers[0]->getFieldU32(sfSequence) == offerSeqId_0);
+
4967 BEAST_EXPECT(offers[1]->getFieldU32(sfSequence) == offerTixId_1);
+
4968 BEAST_EXPECT(offers[2]->getFieldU32(sfSequence) == offerTixId_0);
+
4969 BEAST_EXPECT(offers[3]->getFieldU32(sfSequence) == offerSeqId_1);
+
4970 env.require(balance(alice, USD(200)));
+
4971 env.require(owners(alice, 7));
+
4972 }
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);
+
4974 // Use a ticket to cancel an offer created with a sequence.
+
4975 env(offer_cancel(alice, offerSeqId_0), ticket::use(ticketSeq + 2));
+
4976 env.close();
+
4977
+
4978 // Verify that offerSeqId_0 was canceled.
+
4979 {
+
4980 auto offers = sortedOffersOnAccount(env, alice);
+
4981 BEAST_EXPECT(offers.size() == 3);
+
4982 BEAST_EXPECT(offers[0]->getFieldU32(sfSequence) == offerTixId_1);
+
4983 BEAST_EXPECT(offers[1]->getFieldU32(sfSequence) == offerTixId_0);
+
4984 BEAST_EXPECT(offers[2]->getFieldU32(sfSequence) == offerSeqId_1);
+
4985 }
+
4986
+
4987 // Use a ticket to cancel an offer created with a ticket.
+
4988 env(offer_cancel(alice, offerTixId_0), ticket::use(ticketSeq + 3));
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 // 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 }
+
4991 // Verify that offerTixId_0 was canceled.
+
4992 {
+
4993 auto offers = sortedOffersOnAccount(env, alice);
+
4994 BEAST_EXPECT(offers.size() == 2);
+
4995 BEAST_EXPECT(offers[0]->getFieldU32(sfSequence) == offerTixId_1);
+
4996 BEAST_EXPECT(offers[1]->getFieldU32(sfSequence) == offerSeqId_1);
+
4997 }
+
4998
+
4999 // All of alice's tickets should now be used up.
+
5000 env.require(owners(alice, 3), tickets(alice, 0));
+
5001
+
5002 // Use a sequence to cancel an offer created with a ticket.
+
5003 env(offer_cancel(alice, offerTixId_1));
+
5004 env.close();
+
5005
+
5006 // Verify that offerTixId_1 was canceled.
+
5007 {
+
5008 auto offers = sortedOffersOnAccount(env, alice);
+
5009 BEAST_EXPECT(offers.size() == 1);
+
5010 BEAST_EXPECT(offers[0]->getFieldU32(sfSequence) == offerSeqId_1);
+
5011 }
+
5012
+
5013 // Use a sequence to cancel an offer created with a sequence.
+
5014 env(offer_cancel(alice, offerSeqId_1));
+
5015 env.close();
+
5016
+
5017 // Verify that offerSeqId_1 was canceled.
+
5018 // All of alice's tickets should now be used up.
+
5019 env.require(owners(alice, 1), tickets(alice, 0), offers(alice, 0));
+
5020 }
+
+
5021
+
5022 void
+
+ +
5024 {
+
5025 // An assert was falsely triggering when computing rates for offers.
+
5026 // This unit test would trigger that assert (which has been removed).
+
5027 testcase("incorrect assert fixed");
+
5028 using namespace jtx;
+
5029
+
5030 Env env{*this};
+
5031 auto const alice = Account("alice");
+
5032 auto const USD = alice["USD"];
+
5033
+
5034 env.fund(XRP(10000), alice);
+
5035 env.close();
+
5036 env(offer(alice, XRP(100000000000), USD(100000000)));
+
5037 pass();
+
5038 }
+
+
5039
+
5040 void
+
+ +
5042 {
+
5043 testcase("fixFillOrKill");
+
5044 using namespace jtx;
+
5045 Env env(*this, features);
+
5046 Account const issuer("issuer");
+
5047 Account const maker("maker");
+
5048 Account const taker("taker");
+
5049 auto const USD = issuer["USD"];
+
5050 auto const EUR = issuer["EUR"];
+
5051
+
5052 env.fund(XRP(1'000), issuer);
+
5053 env.fund(XRP(1'000), maker, taker);
+
5054 env.close();
+
5055
+
5056 env.trust(USD(1'000), maker, taker);
+
5057 env.trust(EUR(1'000), maker, taker);
+
5058 env.close();
+
5059
+
5060 env(pay(issuer, maker, USD(1'000)));
+
5061 env(pay(issuer, taker, USD(1'000)));
+
5062 env(pay(issuer, maker, EUR(1'000)));
+
5063 env.close();
+
5064
+
5065 auto makerUSDBalance = env.balance(maker, USD).value();
+
5066 auto takerUSDBalance = env.balance(taker, USD).value();
+
5067 auto makerEURBalance = env.balance(maker, EUR).value();
+
5068 auto takerEURBalance = env.balance(taker, EUR).value();
+
5069 auto makerXRPBalance = env.balance(maker, XRP).value();
+
5070 auto takerXRPBalance = env.balance(taker, XRP).value();
+
5071
+
5072 // tfFillOrKill, TakerPays must be filled
+
5073 {
+
5074 TER const err =
+
5075 features[fixFillOrKill] ? TER(tesSUCCESS) : tecKILLED;
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 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 }
-
+
5077 env(offer(maker, XRP(100), USD(100)));
+
5078 env.close();
+
5079
+
5080 env(offer(taker, USD(100), XRP(101)),
+ +
5082 ter(err));
+
5083 env.close();
+
5084
+
5085 makerXRPBalance -= txfee(env, 1);
+
5086 takerXRPBalance -= txfee(env, 1);
+
5087 if (err == tesSUCCESS)
+
5088 {
+
5089 makerUSDBalance -= USD(100);
+
5090 takerUSDBalance += USD(100);
+
5091 makerXRPBalance += XRP(100).value();
+
5092 takerXRPBalance -= XRP(100).value();
+
5093 }
+
5094 BEAST_EXPECT(expectOffers(env, taker, 0));
+
5095
+
5096 env(offer(maker, USD(100), XRP(100)));
+
5097 env.close();
+
5098
+
5099 env(offer(taker, XRP(100), USD(101)),
+ +
5101 ter(err));
+
5102 env.close();
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(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)));
+
5104 makerXRPBalance -= txfee(env, 1);
+
5105 takerXRPBalance -= txfee(env, 1);
+
5106 if (err == tesSUCCESS)
+
5107 {
+
5108 makerUSDBalance += USD(100);
+
5109 takerUSDBalance -= USD(100);
+
5110 makerXRPBalance -= XRP(100).value();
+
5111 takerXRPBalance += XRP(100).value();
+
5112 }
+
5113 BEAST_EXPECT(expectOffers(env, taker, 0));
+
5114
+
5115 env(offer(maker, USD(100), EUR(100)));
+
5116 env.close();
+
5117
+
5118 env(offer(taker, EUR(100), USD(101)),
+ +
5120 ter(err));
+
5121 env.close();
+
5122
+
5123 makerXRPBalance -= txfee(env, 1);
+
5124 takerXRPBalance -= txfee(env, 1);
+
5125 if (err == tesSUCCESS)
+
5126 {
+
5127 makerUSDBalance += USD(100);
+
5128 takerUSDBalance -= USD(100);
+
5129 makerEURBalance -= EUR(100);
+
5130 takerEURBalance += EUR(100);
+
5131 }
+
5132 BEAST_EXPECT(expectOffers(env, taker, 0));
+
5133 }
+
5134
+
5135 // tfFillOrKill + tfSell, TakerGets must be filled
+
5136 {
+
5137 env(offer(maker, XRP(101), USD(101)));
+
5138 env.close();
+
5139
+
5140 env(offer(taker, USD(100), XRP(101)),
+
5142 env.close();
5143
-
5144 env(offer(taker, USD(100), XRP(101)),
- -
5146 ter(err));
-
5147 env.close();
-
5148
-
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();
+
5144 makerUSDBalance -= USD(101);
+
5145 takerUSDBalance += USD(101);
+
5146 makerXRPBalance += XRP(101).value() - txfee(env, 1);
+
5147 takerXRPBalance -= XRP(101).value() + txfee(env, 1);
+
5148 BEAST_EXPECT(expectOffers(env, taker, 0));
+
5149
+
5150 env(offer(maker, USD(101), XRP(101)));
+
5151 env.close();
+
5152
+
5153 env(offer(taker, XRP(100), USD(101)),
+ +
5155 env.close();
+
5156
+
5157 makerUSDBalance += USD(101);
+
5158 takerUSDBalance -= USD(101);
+
5159 makerXRPBalance -= XRP(101).value() + txfee(env, 1);
+
5160 takerXRPBalance += XRP(101).value() - txfee(env, 1);
+
5161 BEAST_EXPECT(expectOffers(env, taker, 0));
5162
-
5163 env(offer(taker, XRP(100), USD(101)),
- -
5165 ter(err));
-
5166 env.close();
-
5167
-
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));
+
5163 env(offer(maker, USD(101), EUR(101)));
+
5164 env.close();
+
5165
+
5166 env(offer(taker, EUR(100), USD(101)),
+ +
5168 env.close();
+
5169
+
5170 makerUSDBalance += USD(101);
+
5171 takerUSDBalance -= USD(101);
+
5172 makerEURBalance -= EUR(101);
+
5173 takerEURBalance += EUR(101);
+
5174 makerXRPBalance -= txfee(env, 1);
+
5175 takerXRPBalance -= txfee(env, 1);
+
5176 BEAST_EXPECT(expectOffers(env, taker, 0));
+
5177 }
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 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));
+
5179 // Fail regardless of fixFillOrKill amendment
+
5180 for (auto const flags : {tfFillOrKill, tfFillOrKill + tfSell})
+
5181 {
+
5182 env(offer(maker, XRP(100), USD(100)));
+
5183 env.close();
+
5184
+
5185 env(offer(taker, USD(100), XRP(99)),
+
5186 txflags(flags),
+
5187 ter(tecKILLED));
+
5188 env.close();
+
5189
+
5190 makerXRPBalance -= txfee(env, 1);
+
5191 takerXRPBalance -= txfee(env, 1);
+
5192 BEAST_EXPECT(expectOffers(env, taker, 0));
+
5193
+
5194 env(offer(maker, USD(100), XRP(100)));
+
5195 env.close();
+
5196
+
5197 env(offer(taker, XRP(100), USD(99)),
+
5198 txflags(flags),
+
5199 ter(tecKILLED));
+
5200 env.close();
+
5201
+
5202 makerXRPBalance -= txfee(env, 1);
+
5203 takerXRPBalance -= txfee(env, 1);
+
5204 BEAST_EXPECT(expectOffers(env, taker, 0));
+
5205
+
5206 env(offer(maker, USD(100), EUR(100)));
+
5207 env.close();
+
5208
+
5209 env(offer(taker, EUR(100), USD(99)),
+
5210 txflags(flags),
+
5211 ter(tecKILLED));
+
5212 env.close();
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 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 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);
+
5214 makerXRPBalance -= txfee(env, 1);
+
5215 takerXRPBalance -= txfee(env, 1);
+
5216 BEAST_EXPECT(expectOffers(env, taker, 0));
+
5217 }
+
5218
+
5219 BEAST_EXPECT(
+
5220 env.balance(maker, USD) == makerUSDBalance &&
+
5221 env.balance(taker, USD) == takerUSDBalance &&
+
5222 env.balance(maker, EUR) == makerEURBalance &&
+
5223 env.balance(taker, EUR) == takerEURBalance &&
+
5224 env.balance(maker, XRP) == makerXRPBalance &&
+
5225 env.balance(taker, XRP) == takerXRPBalance);
+
5226 }
+
+
5227
+
5228 void
+
+ +
5230 {
+
5231 testCanceledOffer(features);
+
5232 testRmFundedOffer(features);
+
5233 testTinyPayment(features);
+
5234 testXRPTinyPayment(features);
+
5235 testEnforceNoRipple(features);
+
5236 testInsufficientReserve(features);
+
5237 testFillModes(features);
+
5238 testMalformed(features);
+
5239 testExpiration(features);
+
5240 testUnfundedCross(features);
+
5241 testSelfCross(false, features);
+
5242 testSelfCross(true, features);
+
5243 testNegativeBalance(features);
+
5244 testOfferCrossWithXRP(true, features);
+
5245 testOfferCrossWithXRP(false, features);
+ +
5247 testOfferAcceptThenCancel(features);
+ + + + +
5252 testCrossCurrencyStartXRP(features);
+
5253 testCrossCurrencyEndXRP(features);
+
5254 testCrossCurrencyBridged(features);
+
5255 testBridgedSecondLegDry(features);
+
5256 testOfferFeesConsumeFunds(features);
+
5257 testOfferCreateThenCross(features);
+
5258 testSellFlagBasic(features);
+
5259 testSellFlagExceedLimit(features);
+
5260 testGatewayCrossCurrency(features);
+
5261 testPartialCross(features);
+
5262 testXRPDirectCross(features);
+
5263 testDirectCross(features);
+
5264 testBridgedCross(features);
+
5265 testSellOffer(features);
+
5266 testSellWithFillOrKill(features);
+
5267 testTransferRateOffer(features);
+
5268 testSelfCrossOffer(features);
+
5269 testSelfIssueOffer(features);
+
5270 testBadPathAssert(features);
+
5271 testDirectToDirectPath(features);
+ +
5273 testOfferInScaling(features);
+ + +
5276 testTinyOffer(features);
+
5277 testSelfPayXferFeeOffer(features);
+
5278 testSelfPayUnlimitedFunds(features);
+
5279 testRequireAuth(features);
+
5280 testMissingAuth(features);
+
5281 testRCSmoketest(features);
+
5282 testSelfAuth(features);
+
5283 testDeletedOfferIssuer(features);
+
5284 testTickSize(features);
+
5285 testTicketOffer(features);
+
5286 testTicketCancelOffer(features);
+ + +
5289 testFillOrKill(features);
5290 }
5291
5292 void
- +
5293 run(std::uint32_t instance, bool last = false)
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 }
+
5295 using namespace jtx;
+
5296 static FeatureBitset const all{testable_amendments()};
+
5297 static FeatureBitset const takerDryOffer{fixTakerDryOfferRemoval};
+
5298 static FeatureBitset const immediateOfferKilled{
+
5299 featureImmediateOfferKilled};
+
5300 FeatureBitset const fillOrKill{fixFillOrKill};
+
5301 FeatureBitset const permDEX{featurePermissionedDEX};
+
5302
+
5303 static std::array<FeatureBitset, 6> const feats{
+
5304 all - takerDryOffer - immediateOfferKilled - permDEX,
+
5305 all - immediateOfferKilled - permDEX,
+
5306 all - immediateOfferKilled - fillOrKill - permDEX,
+
5307 all - fillOrKill - permDEX,
+
5308 all - permDEX,
+
5309 all};
+
5310
+
5311 if (BEAST_EXPECT(instance < feats.size()))
+
5312 {
+
5313 testAll(feats[instance]);
+
5314 }
+
5315 BEAST_EXPECT(!last || instance == feats.size() - 1);
+
5316 }
-
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 }
+
5317
+
5318 void
+
+
5319 run() override
+
5320 {
+
5321 run(0);
+ +
5323 }
-
5384
-
5385 void
-
-
5386 run() override
-
5387 {
-
5388 run(0);
- +
5324};
+
+
5325
+
+ +
5327{
+
5328 void
+
+
5329 run() override
+
5330 {
+ +
5332 }
+
+
5333};
+
+
5334
+
+ +
5336{
+
5337 void
+
+
5338 run() override
+
5339 {
+ +
5341 }
+
+
5342};
+
+
5343
+
+ +
5345{
+
5346 void
+
+
5347 run() override
+
5348 {
+ +
5350 }
+
+
5351};
+
+
5352
+
+ +
5354{
+
5355 void
+
+
5356 run() override
+
5357 {
+ +
5359 }
+
+
5360};
+
+
5361
+
+ +
5363{
+
5364 void
+
+
5365 run() override
+
5366 {
+
5367 OfferBaseUtil_test::run(5, true);
+
5368 }
+
+
5369};
+
+
5370
+
+ +
5372{
+
5373 void
+
+
5374 run() override
+
5375 {
+
5376 using namespace jtx;
+ +
5378 FeatureBitset const immediateOfferKilled{featureImmediateOfferKilled};
+
5379 FeatureBitset const takerDryOffer{fixTakerDryOfferRemoval};
+
5380 FeatureBitset const fillOrKill{fixFillOrKill};
+
5381 FeatureBitset const permDEX{featurePermissionedDEX};
+
5382
+
5383 testAll(all - immediateOfferKilled - permDEX);
+
5384 testAll(all - immediateOfferKilled - fillOrKill - permDEX);
+
5385 testAll(all - fillOrKill - permDEX);
+
5386 testAll(all - permDEX);
+
5387 testAll(all);
+
5388
+
5389 testAll(all - takerDryOffer - permDEX);
5390 }
5391};
5392
-
- -
5394{
-
5395 void
-
-
5396 run() override
-
5397 {
- -
5399 }
-
-
5400};
-
-
5401
-
- -
5403{
-
5404 void
-
-
5405 run() override
-
5406 {
- -
5408 }
-
-
5409};
-
-
5410
-
- -
5412{
-
5413 void
-
-
5414 run() override
-
5415 {
- -
5417 }
-
-
5418};
-
-
5419
-
- -
5421{
-
5422 void
-
-
5423 run() override
-
5424 {
- -
5426 }
-
-
5427};
-
-
5428
-
- -
5430{
-
5431 void
-
-
5432 run() override
-
5433 {
-
5434 OfferBaseUtil_test::run(5, true);
-
5435 }
-
-
5436};
-
-
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 }
-
-
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
-
5468} // namespace test
-
5469} // namespace ripple
+
5393BEAST_DEFINE_TESTSUITE_PRIO(OfferBaseUtil, app, ripple, 2);
+
5394BEAST_DEFINE_TESTSUITE_PRIO(OfferWTakerDryOffer, app, ripple, 2);
+
5395BEAST_DEFINE_TESTSUITE_PRIO(OfferWOSmallQOffers, app, ripple, 2);
+
5396BEAST_DEFINE_TESTSUITE_PRIO(OfferWOFillOrKill, app, ripple, 2);
+
5397BEAST_DEFINE_TESTSUITE_PRIO(OfferWOPermDEX, app, ripple, 2);
+
5398BEAST_DEFINE_TESTSUITE_PRIO(OfferAllFeatures, app, ripple, 2);
+
5399BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(Offer_manual, app, ripple, 20);
+
5400
+
5401} // namespace test
+
5402} // namespace ripple
Represents a JSON value.
Definition json_value.h:149
@@ -5733,89 +5666,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)
-
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 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 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 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 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 testFillModes(FeatureBitset features)
-
void testOfferInScaling(FeatureBitset features)
-
void testOfferInScalingWithXferRate(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)
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 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.
Immutable cryptographic account descriptor.
Definition Account.h:39
diff --git a/classripple_1_1FlowOfferStream.html b/classripple_1_1FlowOfferStream.html index efc2fa87d9..c98d7aa88b 100644 --- a/classripple_1_1FlowOfferStream.html +++ b/classripple_1_1FlowOfferStream.html @@ -307,7 +307,7 @@ template<class TIn , class TOut >

Implements ripple::TOfferStreamBase< TIn, TOut >.

-

Definition at line 422 of file OfferStream.cpp.

+

Definition at line 419 of file OfferStream.cpp.

@@ -458,7 +458,7 @@ template<class TIn , class TOut >
-

Definition at line 226 of file OfferStream.cpp.

+

Definition at line 223 of file OfferStream.cpp.

diff --git a/classripple_1_1OfferStream.html b/classripple_1_1OfferStream.html index 27768a0c98..3c401f5f57 100644 --- a/classripple_1_1OfferStream.html +++ b/classripple_1_1OfferStream.html @@ -296,7 +296,7 @@ Protected Attributes

Implements ripple::TOfferStreamBase< STAmount, STAmount >.

-

Definition at line 415 of file OfferStream.cpp.

+

Definition at line 412 of file OfferStream.cpp.

diff --git a/classripple_1_1TOfferStreamBase.html b/classripple_1_1TOfferStreamBase.html index 10e23ecadd..4e79f6546e 100644 --- a/classripple_1_1TOfferStreamBase.html +++ b/classripple_1_1TOfferStreamBase.html @@ -493,7 +493,7 @@ template<class TIn , class TOut >
-

Definition at line 226 of file OfferStream.cpp.

+

Definition at line 223 of file OfferStream.cpp.

diff --git a/classripple_1_1test_1_1OfferAllFeatures__test.html b/classripple_1_1test_1_1OfferAllFeatures__test.html index b22730669f..f1cf648426 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 5429 of file Offer_test.cpp.

+

Definition at line 5362 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 5432 of file Offer_test.cpp.

+

Definition at line 5365 of file Offer_test.cpp.

@@ -733,7 +733,7 @@ Private Attributes
-

Definition at line 472 of file Offer_test.cpp.

+

Definition at line 440 of file Offer_test.cpp.

@@ -761,7 +761,7 @@ Private Attributes
-

Definition at line 635 of file Offer_test.cpp.

+

Definition at line 571 of file Offer_test.cpp.

@@ -789,7 +789,7 @@ Private Attributes
-

Definition at line 711 of file Offer_test.cpp.

+

Definition at line 647 of file Offer_test.cpp.

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

Definition at line 820 of file Offer_test.cpp.

+

Definition at line 756 of file Offer_test.cpp.

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

Definition at line 834 of file Offer_test.cpp.

+

Definition at line 770 of file Offer_test.cpp.

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

Definition at line 1061 of file Offer_test.cpp.

+

Definition at line 997 of file Offer_test.cpp.

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

Definition at line 1139 of file Offer_test.cpp.

+

Definition at line 1075 of file Offer_test.cpp.

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

Definition at line 1217 of file Offer_test.cpp.

+

Definition at line 1153 of file Offer_test.cpp.

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

Definition at line 1277 of file Offer_test.cpp.

+

Definition at line 1213 of file Offer_test.cpp.

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

Definition at line 1387 of file Offer_test.cpp.

+

Definition at line 1323 of file Offer_test.cpp.

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

Definition at line 1497 of file Offer_test.cpp.

+

Definition at line 1433 of file Offer_test.cpp.

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

Definition at line 1552 of file Offer_test.cpp.

+

Definition at line 1488 of file Offer_test.cpp.

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

Definition at line 1593 of file Offer_test.cpp.

+

Definition at line 1529 of file Offer_test.cpp.

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

Definition at line 1617 of file Offer_test.cpp.

+

Definition at line 1553 of file Offer_test.cpp.

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

Definition at line 1643 of file Offer_test.cpp.

+

Definition at line 1579 of file Offer_test.cpp.

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

Definition at line 1697 of file Offer_test.cpp.

+

Definition at line 1633 of file Offer_test.cpp.

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

Definition at line 1727 of file Offer_test.cpp.

+

Definition at line 1663 of file Offer_test.cpp.

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

Definition at line 1813 of file Offer_test.cpp.

+

Definition at line 1749 of file Offer_test.cpp.

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

Definition at line 1855 of file Offer_test.cpp.

+

Definition at line 1791 of file Offer_test.cpp.

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

Definition at line 1903 of file Offer_test.cpp.

+

Definition at line 1839 of file Offer_test.cpp.

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

Definition at line 1969 of file Offer_test.cpp.

+

Definition at line 1905 of file Offer_test.cpp.

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

Definition at line 2036 of file Offer_test.cpp.

+

Definition at line 1972 of file Offer_test.cpp.

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

Definition at line 2091 of file Offer_test.cpp.

+

Definition at line 2027 of file Offer_test.cpp.

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

Definition at line 2147 of file Offer_test.cpp.

+

Definition at line 2083 of file Offer_test.cpp.

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

Definition at line 2190 of file Offer_test.cpp.

+

Definition at line 2126 of file Offer_test.cpp.

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

Definition at line 2235 of file Offer_test.cpp.

+

Definition at line 2171 of file Offer_test.cpp.

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

Definition at line 2313 of file Offer_test.cpp.

+

Definition at line 2249 of file Offer_test.cpp.

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

Definition at line 2344 of file Offer_test.cpp.

+

Definition at line 2280 of file Offer_test.cpp.

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

Definition at line 2503 of file Offer_test.cpp.

+

Definition at line 2439 of file Offer_test.cpp.

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

Definition at line 2580 of file Offer_test.cpp.

+

Definition at line 2516 of file Offer_test.cpp.

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

Definition at line 2698 of file Offer_test.cpp.

+

Definition at line 2634 of file Offer_test.cpp.

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

Definition at line 2796 of file Offer_test.cpp.

+

Definition at line 2732 of file Offer_test.cpp.

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

Definition at line 2985 of file Offer_test.cpp.

+

Definition at line 2921 of file Offer_test.cpp.

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

Definition at line 3070 of file Offer_test.cpp.

+

Definition at line 3006 of file Offer_test.cpp.

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

Definition at line 3378 of file Offer_test.cpp.

+

Definition at line 3314 of file Offer_test.cpp.

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

Definition at line 3448 of file Offer_test.cpp.

+

Definition at line 3384 of file Offer_test.cpp.

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

Definition at line 3560 of file Offer_test.cpp.

+

Definition at line 3496 of file Offer_test.cpp.

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

Definition at line 3568 of file Offer_test.cpp.

+

Definition at line 3504 of file Offer_test.cpp.

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

Definition at line 3613 of file Offer_test.cpp.

+

Definition at line 3549 of file Offer_test.cpp.

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

Definition at line 3684 of file Offer_test.cpp.

+

Definition at line 3620 of file Offer_test.cpp.

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

Definition at line 3737 of file Offer_test.cpp.

+

Definition at line 3673 of file Offer_test.cpp.

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

Definition at line 3773 of file Offer_test.cpp.

+

Definition at line 3709 of file Offer_test.cpp.

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

Definition at line 3820 of file Offer_test.cpp.

+

Definition at line 3756 of file Offer_test.cpp.

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

Definition at line 3872 of file Offer_test.cpp.

+

Definition at line 3808 of file Offer_test.cpp.

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

Definition at line 3939 of file Offer_test.cpp.

+

Definition at line 3875 of file Offer_test.cpp.

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

Definition at line 3987 of file Offer_test.cpp.

+

Definition at line 3923 of file Offer_test.cpp.

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

Definition at line 4142 of file Offer_test.cpp.

+

Definition at line 4078 of file Offer_test.cpp.

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

Definition at line 4291 of file Offer_test.cpp.

+

Definition at line 4227 of file Offer_test.cpp.

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

Definition at line 4342 of file Offer_test.cpp.

+

Definition at line 4278 of file Offer_test.cpp.

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

Definition at line 4463 of file Offer_test.cpp.

+

Definition at line 4399 of file Offer_test.cpp.

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

Definition at line 4552 of file Offer_test.cpp.

+

Definition at line 4488 of file Offer_test.cpp.

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

Definition at line 4624 of file Offer_test.cpp.

+

Definition at line 4560 of file Offer_test.cpp.

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

Definition at line 4731 of file Offer_test.cpp.

+

Definition at line 4667 of file Offer_test.cpp.

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

Definition at line 4840 of file Offer_test.cpp.

+

Definition at line 4776 of file Offer_test.cpp.

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

Definition at line 4855 of file Offer_test.cpp.

+

Definition at line 4791 of file Offer_test.cpp.

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

Definition at line 4975 of file Offer_test.cpp.

+

Definition at line 4911 of file Offer_test.cpp.

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

Definition at line 5087 of file Offer_test.cpp.

+

Definition at line 5023 of file Offer_test.cpp.

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

Definition at line 5105 of file Offer_test.cpp.

+

Definition at line 5041 of file Offer_test.cpp.

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

Definition at line 5293 of file Offer_test.cpp.

+

Definition at line 5229 of file Offer_test.cpp.

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

Definition at line 5357 of file Offer_test.cpp.

+

Definition at line 5293 of file Offer_test.cpp.

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

Definition at line 472 of file Offer_test.cpp.

+

Definition at line 440 of file Offer_test.cpp.

@@ -682,7 +682,7 @@ Private Attributes
-

Definition at line 635 of file Offer_test.cpp.

+

Definition at line 571 of file Offer_test.cpp.

@@ -702,7 +702,7 @@ Private Attributes
-

Definition at line 711 of file Offer_test.cpp.

+

Definition at line 647 of file Offer_test.cpp.

@@ -740,7 +740,7 @@ Private Attributes
-

Definition at line 820 of file Offer_test.cpp.

+

Definition at line 756 of file Offer_test.cpp.

@@ -760,7 +760,7 @@ Private Attributes
-

Definition at line 834 of file Offer_test.cpp.

+

Definition at line 770 of file Offer_test.cpp.

@@ -780,7 +780,7 @@ Private Attributes
-

Definition at line 1061 of file Offer_test.cpp.

+

Definition at line 997 of file Offer_test.cpp.

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

Definition at line 1139 of file Offer_test.cpp.

+

Definition at line 1075 of file Offer_test.cpp.

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

Definition at line 1217 of file Offer_test.cpp.

+

Definition at line 1153 of file Offer_test.cpp.

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

Definition at line 1277 of file Offer_test.cpp.

+

Definition at line 1213 of file Offer_test.cpp.

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

Definition at line 1387 of file Offer_test.cpp.

+

Definition at line 1323 of file Offer_test.cpp.

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

Definition at line 1497 of file Offer_test.cpp.

+

Definition at line 1433 of file Offer_test.cpp.

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

Definition at line 1552 of file Offer_test.cpp.

+

Definition at line 1488 of file Offer_test.cpp.

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

Definition at line 1593 of file Offer_test.cpp.

+

Definition at line 1529 of file Offer_test.cpp.

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

Definition at line 1617 of file Offer_test.cpp.

+

Definition at line 1553 of file Offer_test.cpp.

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

Definition at line 1643 of file Offer_test.cpp.

+

Definition at line 1579 of file Offer_test.cpp.

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

Definition at line 1697 of file Offer_test.cpp.

+

Definition at line 1633 of file Offer_test.cpp.

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

Definition at line 1727 of file Offer_test.cpp.

+

Definition at line 1663 of file Offer_test.cpp.

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

Definition at line 1813 of file Offer_test.cpp.

+

Definition at line 1749 of file Offer_test.cpp.

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

Definition at line 1855 of file Offer_test.cpp.

+

Definition at line 1791 of file Offer_test.cpp.

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

Definition at line 1903 of file Offer_test.cpp.

+

Definition at line 1839 of file Offer_test.cpp.

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

Definition at line 1969 of file Offer_test.cpp.

+

Definition at line 1905 of file Offer_test.cpp.

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

Definition at line 2036 of file Offer_test.cpp.

+

Definition at line 1972 of file Offer_test.cpp.

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

Definition at line 2091 of file Offer_test.cpp.

+

Definition at line 2027 of file Offer_test.cpp.

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

Definition at line 2147 of file Offer_test.cpp.

+

Definition at line 2083 of file Offer_test.cpp.

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

Definition at line 2190 of file Offer_test.cpp.

+

Definition at line 2126 of file Offer_test.cpp.

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

Definition at line 2235 of file Offer_test.cpp.

+

Definition at line 2171 of file Offer_test.cpp.

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

Definition at line 2313 of file Offer_test.cpp.

+

Definition at line 2249 of file Offer_test.cpp.

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

Definition at line 2344 of file Offer_test.cpp.

+

Definition at line 2280 of file Offer_test.cpp.

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

Definition at line 2503 of file Offer_test.cpp.

+

Definition at line 2439 of file Offer_test.cpp.

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

Definition at line 2580 of file Offer_test.cpp.

+

Definition at line 2516 of file Offer_test.cpp.

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

Definition at line 2698 of file Offer_test.cpp.

+

Definition at line 2634 of file Offer_test.cpp.

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

Definition at line 2796 of file Offer_test.cpp.

+

Definition at line 2732 of file Offer_test.cpp.

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

Definition at line 2985 of file Offer_test.cpp.

+

Definition at line 2921 of file Offer_test.cpp.

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

Definition at line 3070 of file Offer_test.cpp.

+

Definition at line 3006 of file Offer_test.cpp.

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

Definition at line 3378 of file Offer_test.cpp.

+

Definition at line 3314 of file Offer_test.cpp.

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

Definition at line 3448 of file Offer_test.cpp.

+

Definition at line 3384 of file Offer_test.cpp.

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

Definition at line 3560 of file Offer_test.cpp.

+

Definition at line 3496 of file Offer_test.cpp.

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

Definition at line 3568 of file Offer_test.cpp.

+

Definition at line 3504 of file Offer_test.cpp.

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

Definition at line 3613 of file Offer_test.cpp.

+

Definition at line 3549 of file Offer_test.cpp.

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

Definition at line 3684 of file Offer_test.cpp.

+

Definition at line 3620 of file Offer_test.cpp.

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

Definition at line 3737 of file Offer_test.cpp.

+

Definition at line 3673 of file Offer_test.cpp.

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

Definition at line 3773 of file Offer_test.cpp.

+

Definition at line 3709 of file Offer_test.cpp.

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

Definition at line 3820 of file Offer_test.cpp.

+

Definition at line 3756 of file Offer_test.cpp.

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

Definition at line 3872 of file Offer_test.cpp.

+

Definition at line 3808 of file Offer_test.cpp.

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

Definition at line 3939 of file Offer_test.cpp.

+

Definition at line 3875 of file Offer_test.cpp.

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

Definition at line 3987 of file Offer_test.cpp.

+

Definition at line 3923 of file Offer_test.cpp.

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

Definition at line 4142 of file Offer_test.cpp.

+

Definition at line 4078 of file Offer_test.cpp.

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

Definition at line 4291 of file Offer_test.cpp.

+

Definition at line 4227 of file Offer_test.cpp.

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

Definition at line 4342 of file Offer_test.cpp.

+

Definition at line 4278 of file Offer_test.cpp.

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

Definition at line 4463 of file Offer_test.cpp.

+

Definition at line 4399 of file Offer_test.cpp.

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

Definition at line 4552 of file Offer_test.cpp.

+

Definition at line 4488 of file Offer_test.cpp.

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

Definition at line 4624 of file Offer_test.cpp.

+

Definition at line 4560 of file Offer_test.cpp.

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

Definition at line 4731 of file Offer_test.cpp.

+

Definition at line 4667 of file Offer_test.cpp.

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

Definition at line 4840 of file Offer_test.cpp.

+

Definition at line 4776 of file Offer_test.cpp.

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

Definition at line 4855 of file Offer_test.cpp.

+

Definition at line 4791 of file Offer_test.cpp.

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

Definition at line 4975 of file Offer_test.cpp.

+

Definition at line 4911 of file Offer_test.cpp.

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

Definition at line 5087 of file Offer_test.cpp.

+

Definition at line 5023 of file Offer_test.cpp.

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

Definition at line 5105 of file Offer_test.cpp.

+

Definition at line 5041 of file Offer_test.cpp.

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

Definition at line 5293 of file Offer_test.cpp.

+

Definition at line 5229 of file Offer_test.cpp.

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

Definition at line 5357 of file Offer_test.cpp.

+

Definition at line 5293 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 5386 of file Offer_test.cpp.

+

Definition at line 5319 of file Offer_test.cpp.

diff --git a/classripple_1_1test_1_1OfferWOFillOrKill__test.html b/classripple_1_1test_1_1OfferWOFillOrKill__test.html index f5f0c92f3c..dddfb22f6b 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 5411 of file Offer_test.cpp.

+

Definition at line 5344 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 5414 of file Offer_test.cpp.

+

Definition at line 5347 of file Offer_test.cpp.

@@ -733,7 +733,7 @@ Private Attributes
-

Definition at line 472 of file Offer_test.cpp.

+

Definition at line 440 of file Offer_test.cpp.

@@ -761,7 +761,7 @@ Private Attributes
-

Definition at line 635 of file Offer_test.cpp.

+

Definition at line 571 of file Offer_test.cpp.

@@ -789,7 +789,7 @@ Private Attributes
-

Definition at line 711 of file Offer_test.cpp.

+

Definition at line 647 of file Offer_test.cpp.

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

Definition at line 820 of file Offer_test.cpp.

+

Definition at line 756 of file Offer_test.cpp.

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

Definition at line 834 of file Offer_test.cpp.

+

Definition at line 770 of file Offer_test.cpp.

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

Definition at line 1061 of file Offer_test.cpp.

+

Definition at line 997 of file Offer_test.cpp.

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

Definition at line 1139 of file Offer_test.cpp.

+

Definition at line 1075 of file Offer_test.cpp.

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

Definition at line 1217 of file Offer_test.cpp.

+

Definition at line 1153 of file Offer_test.cpp.

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

Definition at line 1277 of file Offer_test.cpp.

+

Definition at line 1213 of file Offer_test.cpp.

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

Definition at line 1387 of file Offer_test.cpp.

+

Definition at line 1323 of file Offer_test.cpp.

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

Definition at line 1497 of file Offer_test.cpp.

+

Definition at line 1433 of file Offer_test.cpp.

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

Definition at line 1552 of file Offer_test.cpp.

+

Definition at line 1488 of file Offer_test.cpp.

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

Definition at line 1593 of file Offer_test.cpp.

+

Definition at line 1529 of file Offer_test.cpp.

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

Definition at line 1617 of file Offer_test.cpp.

+

Definition at line 1553 of file Offer_test.cpp.

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

Definition at line 1643 of file Offer_test.cpp.

+

Definition at line 1579 of file Offer_test.cpp.

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

Definition at line 1697 of file Offer_test.cpp.

+

Definition at line 1633 of file Offer_test.cpp.

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

Definition at line 1727 of file Offer_test.cpp.

+

Definition at line 1663 of file Offer_test.cpp.

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

Definition at line 1813 of file Offer_test.cpp.

+

Definition at line 1749 of file Offer_test.cpp.

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

Definition at line 1855 of file Offer_test.cpp.

+

Definition at line 1791 of file Offer_test.cpp.

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

Definition at line 1903 of file Offer_test.cpp.

+

Definition at line 1839 of file Offer_test.cpp.

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

Definition at line 1969 of file Offer_test.cpp.

+

Definition at line 1905 of file Offer_test.cpp.

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

Definition at line 2036 of file Offer_test.cpp.

+

Definition at line 1972 of file Offer_test.cpp.

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

Definition at line 2091 of file Offer_test.cpp.

+

Definition at line 2027 of file Offer_test.cpp.

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

Definition at line 2147 of file Offer_test.cpp.

+

Definition at line 2083 of file Offer_test.cpp.

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

Definition at line 2190 of file Offer_test.cpp.

+

Definition at line 2126 of file Offer_test.cpp.

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

Definition at line 2235 of file Offer_test.cpp.

+

Definition at line 2171 of file Offer_test.cpp.

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

Definition at line 2313 of file Offer_test.cpp.

+

Definition at line 2249 of file Offer_test.cpp.

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

Definition at line 2344 of file Offer_test.cpp.

+

Definition at line 2280 of file Offer_test.cpp.

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

Definition at line 2503 of file Offer_test.cpp.

+

Definition at line 2439 of file Offer_test.cpp.

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

Definition at line 2580 of file Offer_test.cpp.

+

Definition at line 2516 of file Offer_test.cpp.

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

Definition at line 2698 of file Offer_test.cpp.

+

Definition at line 2634 of file Offer_test.cpp.

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

Definition at line 2796 of file Offer_test.cpp.

+

Definition at line 2732 of file Offer_test.cpp.

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

Definition at line 2985 of file Offer_test.cpp.

+

Definition at line 2921 of file Offer_test.cpp.

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

Definition at line 3070 of file Offer_test.cpp.

+

Definition at line 3006 of file Offer_test.cpp.

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

Definition at line 3378 of file Offer_test.cpp.

+

Definition at line 3314 of file Offer_test.cpp.

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

Definition at line 3448 of file Offer_test.cpp.

+

Definition at line 3384 of file Offer_test.cpp.

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

Definition at line 3560 of file Offer_test.cpp.

+

Definition at line 3496 of file Offer_test.cpp.

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

Definition at line 3568 of file Offer_test.cpp.

+

Definition at line 3504 of file Offer_test.cpp.

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

Definition at line 3613 of file Offer_test.cpp.

+

Definition at line 3549 of file Offer_test.cpp.

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

Definition at line 3684 of file Offer_test.cpp.

+

Definition at line 3620 of file Offer_test.cpp.

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

Definition at line 3737 of file Offer_test.cpp.

+

Definition at line 3673 of file Offer_test.cpp.

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

Definition at line 3773 of file Offer_test.cpp.

+

Definition at line 3709 of file Offer_test.cpp.

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

Definition at line 3820 of file Offer_test.cpp.

+

Definition at line 3756 of file Offer_test.cpp.

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

Definition at line 3872 of file Offer_test.cpp.

+

Definition at line 3808 of file Offer_test.cpp.

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

Definition at line 3939 of file Offer_test.cpp.

+

Definition at line 3875 of file Offer_test.cpp.

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

Definition at line 3987 of file Offer_test.cpp.

+

Definition at line 3923 of file Offer_test.cpp.

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

Definition at line 4142 of file Offer_test.cpp.

+

Definition at line 4078 of file Offer_test.cpp.

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

Definition at line 4291 of file Offer_test.cpp.

+

Definition at line 4227 of file Offer_test.cpp.

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

Definition at line 4342 of file Offer_test.cpp.

+

Definition at line 4278 of file Offer_test.cpp.

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

Definition at line 4463 of file Offer_test.cpp.

+

Definition at line 4399 of file Offer_test.cpp.

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

Definition at line 4552 of file Offer_test.cpp.

+

Definition at line 4488 of file Offer_test.cpp.

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

Definition at line 4624 of file Offer_test.cpp.

+

Definition at line 4560 of file Offer_test.cpp.

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

Definition at line 4731 of file Offer_test.cpp.

+

Definition at line 4667 of file Offer_test.cpp.

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

Definition at line 4840 of file Offer_test.cpp.

+

Definition at line 4776 of file Offer_test.cpp.

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

Definition at line 4855 of file Offer_test.cpp.

+

Definition at line 4791 of file Offer_test.cpp.

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

Definition at line 4975 of file Offer_test.cpp.

+

Definition at line 4911 of file Offer_test.cpp.

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

Definition at line 5087 of file Offer_test.cpp.

+

Definition at line 5023 of file Offer_test.cpp.

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

Definition at line 5105 of file Offer_test.cpp.

+

Definition at line 5041 of file Offer_test.cpp.

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

Definition at line 5293 of file Offer_test.cpp.

+

Definition at line 5229 of file Offer_test.cpp.

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

Definition at line 5357 of file Offer_test.cpp.

+

Definition at line 5293 of file Offer_test.cpp.

diff --git a/classripple_1_1test_1_1OfferWOPermDEX__test.html b/classripple_1_1test_1_1OfferWOPermDEX__test.html index 6a15f826ba..c74d00313f 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 5420 of file Offer_test.cpp.

+

Definition at line 5353 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 5423 of file Offer_test.cpp.

+

Definition at line 5356 of file Offer_test.cpp.

@@ -733,7 +733,7 @@ Private Attributes
-

Definition at line 472 of file Offer_test.cpp.

+

Definition at line 440 of file Offer_test.cpp.

@@ -761,7 +761,7 @@ Private Attributes
-

Definition at line 635 of file Offer_test.cpp.

+

Definition at line 571 of file Offer_test.cpp.

@@ -789,7 +789,7 @@ Private Attributes
-

Definition at line 711 of file Offer_test.cpp.

+

Definition at line 647 of file Offer_test.cpp.

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

Definition at line 820 of file Offer_test.cpp.

+

Definition at line 756 of file Offer_test.cpp.

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

Definition at line 834 of file Offer_test.cpp.

+

Definition at line 770 of file Offer_test.cpp.

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

Definition at line 1061 of file Offer_test.cpp.

+

Definition at line 997 of file Offer_test.cpp.

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

Definition at line 1139 of file Offer_test.cpp.

+

Definition at line 1075 of file Offer_test.cpp.

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

Definition at line 1217 of file Offer_test.cpp.

+

Definition at line 1153 of file Offer_test.cpp.

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

Definition at line 1277 of file Offer_test.cpp.

+

Definition at line 1213 of file Offer_test.cpp.

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

Definition at line 1387 of file Offer_test.cpp.

+

Definition at line 1323 of file Offer_test.cpp.

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

Definition at line 1497 of file Offer_test.cpp.

+

Definition at line 1433 of file Offer_test.cpp.

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

Definition at line 1552 of file Offer_test.cpp.

+

Definition at line 1488 of file Offer_test.cpp.

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

Definition at line 1593 of file Offer_test.cpp.

+

Definition at line 1529 of file Offer_test.cpp.

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

Definition at line 1617 of file Offer_test.cpp.

+

Definition at line 1553 of file Offer_test.cpp.

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

Definition at line 1643 of file Offer_test.cpp.

+

Definition at line 1579 of file Offer_test.cpp.

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

Definition at line 1697 of file Offer_test.cpp.

+

Definition at line 1633 of file Offer_test.cpp.

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

Definition at line 1727 of file Offer_test.cpp.

+

Definition at line 1663 of file Offer_test.cpp.

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

Definition at line 1813 of file Offer_test.cpp.

+

Definition at line 1749 of file Offer_test.cpp.

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

Definition at line 1855 of file Offer_test.cpp.

+

Definition at line 1791 of file Offer_test.cpp.

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

Definition at line 1903 of file Offer_test.cpp.

+

Definition at line 1839 of file Offer_test.cpp.

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

Definition at line 1969 of file Offer_test.cpp.

+

Definition at line 1905 of file Offer_test.cpp.

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

Definition at line 2036 of file Offer_test.cpp.

+

Definition at line 1972 of file Offer_test.cpp.

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

Definition at line 2091 of file Offer_test.cpp.

+

Definition at line 2027 of file Offer_test.cpp.

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

Definition at line 2147 of file Offer_test.cpp.

+

Definition at line 2083 of file Offer_test.cpp.

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

Definition at line 2190 of file Offer_test.cpp.

+

Definition at line 2126 of file Offer_test.cpp.

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

Definition at line 2235 of file Offer_test.cpp.

+

Definition at line 2171 of file Offer_test.cpp.

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

Definition at line 2313 of file Offer_test.cpp.

+

Definition at line 2249 of file Offer_test.cpp.

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

Definition at line 2344 of file Offer_test.cpp.

+

Definition at line 2280 of file Offer_test.cpp.

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

Definition at line 2503 of file Offer_test.cpp.

+

Definition at line 2439 of file Offer_test.cpp.

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

Definition at line 2580 of file Offer_test.cpp.

+

Definition at line 2516 of file Offer_test.cpp.

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

Definition at line 2698 of file Offer_test.cpp.

+

Definition at line 2634 of file Offer_test.cpp.

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

Definition at line 2796 of file Offer_test.cpp.

+

Definition at line 2732 of file Offer_test.cpp.

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

Definition at line 2985 of file Offer_test.cpp.

+

Definition at line 2921 of file Offer_test.cpp.

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

Definition at line 3070 of file Offer_test.cpp.

+

Definition at line 3006 of file Offer_test.cpp.

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

Definition at line 3378 of file Offer_test.cpp.

+

Definition at line 3314 of file Offer_test.cpp.

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

Definition at line 3448 of file Offer_test.cpp.

+

Definition at line 3384 of file Offer_test.cpp.

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

Definition at line 3560 of file Offer_test.cpp.

+

Definition at line 3496 of file Offer_test.cpp.

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

Definition at line 3568 of file Offer_test.cpp.

+

Definition at line 3504 of file Offer_test.cpp.

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

Definition at line 3613 of file Offer_test.cpp.

+

Definition at line 3549 of file Offer_test.cpp.

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

Definition at line 3684 of file Offer_test.cpp.

+

Definition at line 3620 of file Offer_test.cpp.

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

Definition at line 3737 of file Offer_test.cpp.

+

Definition at line 3673 of file Offer_test.cpp.

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

Definition at line 3773 of file Offer_test.cpp.

+

Definition at line 3709 of file Offer_test.cpp.

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

Definition at line 3820 of file Offer_test.cpp.

+

Definition at line 3756 of file Offer_test.cpp.

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

Definition at line 3872 of file Offer_test.cpp.

+

Definition at line 3808 of file Offer_test.cpp.

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

Definition at line 3939 of file Offer_test.cpp.

+

Definition at line 3875 of file Offer_test.cpp.

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

Definition at line 3987 of file Offer_test.cpp.

+

Definition at line 3923 of file Offer_test.cpp.

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

Definition at line 4142 of file Offer_test.cpp.

+

Definition at line 4078 of file Offer_test.cpp.

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

Definition at line 4291 of file Offer_test.cpp.

+

Definition at line 4227 of file Offer_test.cpp.

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

Definition at line 4342 of file Offer_test.cpp.

+

Definition at line 4278 of file Offer_test.cpp.

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

Definition at line 4463 of file Offer_test.cpp.

+

Definition at line 4399 of file Offer_test.cpp.

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

Definition at line 4552 of file Offer_test.cpp.

+

Definition at line 4488 of file Offer_test.cpp.

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

Definition at line 4624 of file Offer_test.cpp.

+

Definition at line 4560 of file Offer_test.cpp.

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

Definition at line 4731 of file Offer_test.cpp.

+

Definition at line 4667 of file Offer_test.cpp.

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

Definition at line 4840 of file Offer_test.cpp.

+

Definition at line 4776 of file Offer_test.cpp.

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

Definition at line 4855 of file Offer_test.cpp.

+

Definition at line 4791 of file Offer_test.cpp.

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

Definition at line 4975 of file Offer_test.cpp.

+

Definition at line 4911 of file Offer_test.cpp.

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

Definition at line 5087 of file Offer_test.cpp.

+

Definition at line 5023 of file Offer_test.cpp.

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

Definition at line 5105 of file Offer_test.cpp.

+

Definition at line 5041 of file Offer_test.cpp.

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

Definition at line 5293 of file Offer_test.cpp.

+

Definition at line 5229 of file Offer_test.cpp.

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

Definition at line 5357 of file Offer_test.cpp.

+

Definition at line 5293 of file Offer_test.cpp.

diff --git a/classripple_1_1test_1_1OfferWOSmallQOffers__test.html b/classripple_1_1test_1_1OfferWOSmallQOffers__test.html index 66a7fc1445..dbd3967851 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 5402 of file Offer_test.cpp.

+

Definition at line 5335 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 5405 of file Offer_test.cpp.

+

Definition at line 5338 of file Offer_test.cpp.

@@ -733,7 +733,7 @@ Private Attributes
-

Definition at line 472 of file Offer_test.cpp.

+

Definition at line 440 of file Offer_test.cpp.

@@ -761,7 +761,7 @@ Private Attributes
-

Definition at line 635 of file Offer_test.cpp.

+

Definition at line 571 of file Offer_test.cpp.

@@ -789,7 +789,7 @@ Private Attributes
-

Definition at line 711 of file Offer_test.cpp.

+

Definition at line 647 of file Offer_test.cpp.

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

Definition at line 820 of file Offer_test.cpp.

+

Definition at line 756 of file Offer_test.cpp.

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

Definition at line 834 of file Offer_test.cpp.

+

Definition at line 770 of file Offer_test.cpp.

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

Definition at line 1061 of file Offer_test.cpp.

+

Definition at line 997 of file Offer_test.cpp.

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

Definition at line 1139 of file Offer_test.cpp.

+

Definition at line 1075 of file Offer_test.cpp.

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

Definition at line 1217 of file Offer_test.cpp.

+

Definition at line 1153 of file Offer_test.cpp.

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

Definition at line 1277 of file Offer_test.cpp.

+

Definition at line 1213 of file Offer_test.cpp.

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

Definition at line 1387 of file Offer_test.cpp.

+

Definition at line 1323 of file Offer_test.cpp.

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

Definition at line 1497 of file Offer_test.cpp.

+

Definition at line 1433 of file Offer_test.cpp.

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

Definition at line 1552 of file Offer_test.cpp.

+

Definition at line 1488 of file Offer_test.cpp.

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

Definition at line 1593 of file Offer_test.cpp.

+

Definition at line 1529 of file Offer_test.cpp.

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

Definition at line 1617 of file Offer_test.cpp.

+

Definition at line 1553 of file Offer_test.cpp.

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

Definition at line 1643 of file Offer_test.cpp.

+

Definition at line 1579 of file Offer_test.cpp.

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

Definition at line 1697 of file Offer_test.cpp.

+

Definition at line 1633 of file Offer_test.cpp.

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

Definition at line 1727 of file Offer_test.cpp.

+

Definition at line 1663 of file Offer_test.cpp.

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

Definition at line 1813 of file Offer_test.cpp.

+

Definition at line 1749 of file Offer_test.cpp.

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

Definition at line 1855 of file Offer_test.cpp.

+

Definition at line 1791 of file Offer_test.cpp.

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

Definition at line 1903 of file Offer_test.cpp.

+

Definition at line 1839 of file Offer_test.cpp.

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

Definition at line 1969 of file Offer_test.cpp.

+

Definition at line 1905 of file Offer_test.cpp.

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

Definition at line 2036 of file Offer_test.cpp.

+

Definition at line 1972 of file Offer_test.cpp.

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

Definition at line 2091 of file Offer_test.cpp.

+

Definition at line 2027 of file Offer_test.cpp.

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

Definition at line 2147 of file Offer_test.cpp.

+

Definition at line 2083 of file Offer_test.cpp.

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

Definition at line 2190 of file Offer_test.cpp.

+

Definition at line 2126 of file Offer_test.cpp.

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

Definition at line 2235 of file Offer_test.cpp.

+

Definition at line 2171 of file Offer_test.cpp.

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

Definition at line 2313 of file Offer_test.cpp.

+

Definition at line 2249 of file Offer_test.cpp.

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

Definition at line 2344 of file Offer_test.cpp.

+

Definition at line 2280 of file Offer_test.cpp.

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

Definition at line 2503 of file Offer_test.cpp.

+

Definition at line 2439 of file Offer_test.cpp.

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

Definition at line 2580 of file Offer_test.cpp.

+

Definition at line 2516 of file Offer_test.cpp.

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

Definition at line 2698 of file Offer_test.cpp.

+

Definition at line 2634 of file Offer_test.cpp.

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

Definition at line 2796 of file Offer_test.cpp.

+

Definition at line 2732 of file Offer_test.cpp.

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

Definition at line 2985 of file Offer_test.cpp.

+

Definition at line 2921 of file Offer_test.cpp.

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

Definition at line 3070 of file Offer_test.cpp.

+

Definition at line 3006 of file Offer_test.cpp.

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

Definition at line 3378 of file Offer_test.cpp.

+

Definition at line 3314 of file Offer_test.cpp.

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

Definition at line 3448 of file Offer_test.cpp.

+

Definition at line 3384 of file Offer_test.cpp.

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

Definition at line 3560 of file Offer_test.cpp.

+

Definition at line 3496 of file Offer_test.cpp.

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

Definition at line 3568 of file Offer_test.cpp.

+

Definition at line 3504 of file Offer_test.cpp.

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

Definition at line 3613 of file Offer_test.cpp.

+

Definition at line 3549 of file Offer_test.cpp.

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

Definition at line 3684 of file Offer_test.cpp.

+

Definition at line 3620 of file Offer_test.cpp.

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

Definition at line 3737 of file Offer_test.cpp.

+

Definition at line 3673 of file Offer_test.cpp.

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

Definition at line 3773 of file Offer_test.cpp.

+

Definition at line 3709 of file Offer_test.cpp.

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

Definition at line 3820 of file Offer_test.cpp.

+

Definition at line 3756 of file Offer_test.cpp.

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

Definition at line 3872 of file Offer_test.cpp.

+

Definition at line 3808 of file Offer_test.cpp.

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

Definition at line 3939 of file Offer_test.cpp.

+

Definition at line 3875 of file Offer_test.cpp.

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

Definition at line 3987 of file Offer_test.cpp.

+

Definition at line 3923 of file Offer_test.cpp.

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

Definition at line 4142 of file Offer_test.cpp.

+

Definition at line 4078 of file Offer_test.cpp.

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

Definition at line 4291 of file Offer_test.cpp.

+

Definition at line 4227 of file Offer_test.cpp.

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

Definition at line 4342 of file Offer_test.cpp.

+

Definition at line 4278 of file Offer_test.cpp.

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

Definition at line 4463 of file Offer_test.cpp.

+

Definition at line 4399 of file Offer_test.cpp.

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

Definition at line 4552 of file Offer_test.cpp.

+

Definition at line 4488 of file Offer_test.cpp.

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

Definition at line 4624 of file Offer_test.cpp.

+

Definition at line 4560 of file Offer_test.cpp.

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

Definition at line 4731 of file Offer_test.cpp.

+

Definition at line 4667 of file Offer_test.cpp.

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

Definition at line 4840 of file Offer_test.cpp.

+

Definition at line 4776 of file Offer_test.cpp.

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

Definition at line 4855 of file Offer_test.cpp.

+

Definition at line 4791 of file Offer_test.cpp.

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

Definition at line 4975 of file Offer_test.cpp.

+

Definition at line 4911 of file Offer_test.cpp.

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

Definition at line 5087 of file Offer_test.cpp.

+

Definition at line 5023 of file Offer_test.cpp.

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

Definition at line 5105 of file Offer_test.cpp.

+

Definition at line 5041 of file Offer_test.cpp.

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

Definition at line 5293 of file Offer_test.cpp.

+

Definition at line 5229 of file Offer_test.cpp.

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

Definition at line 5357 of file Offer_test.cpp.

+

Definition at line 5293 of file Offer_test.cpp.

diff --git a/classripple_1_1test_1_1OfferWTakerDryOffer__test.html b/classripple_1_1test_1_1OfferWTakerDryOffer__test.html index 9eecbada40..2b035623d2 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 5393 of file Offer_test.cpp.

+

Definition at line 5326 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 5396 of file Offer_test.cpp.

+

Definition at line 5329 of file Offer_test.cpp.

@@ -733,7 +733,7 @@ Private Attributes
-

Definition at line 472 of file Offer_test.cpp.

+

Definition at line 440 of file Offer_test.cpp.

@@ -761,7 +761,7 @@ Private Attributes
-

Definition at line 635 of file Offer_test.cpp.

+

Definition at line 571 of file Offer_test.cpp.

@@ -789,7 +789,7 @@ Private Attributes
-

Definition at line 711 of file Offer_test.cpp.

+

Definition at line 647 of file Offer_test.cpp.

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

Definition at line 820 of file Offer_test.cpp.

+

Definition at line 756 of file Offer_test.cpp.

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

Definition at line 834 of file Offer_test.cpp.

+

Definition at line 770 of file Offer_test.cpp.

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

Definition at line 1061 of file Offer_test.cpp.

+

Definition at line 997 of file Offer_test.cpp.

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

Definition at line 1139 of file Offer_test.cpp.

+

Definition at line 1075 of file Offer_test.cpp.

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

Definition at line 1217 of file Offer_test.cpp.

+

Definition at line 1153 of file Offer_test.cpp.

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

Definition at line 1277 of file Offer_test.cpp.

+

Definition at line 1213 of file Offer_test.cpp.

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

Definition at line 1387 of file Offer_test.cpp.

+

Definition at line 1323 of file Offer_test.cpp.

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

Definition at line 1497 of file Offer_test.cpp.

+

Definition at line 1433 of file Offer_test.cpp.

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

Definition at line 1552 of file Offer_test.cpp.

+

Definition at line 1488 of file Offer_test.cpp.

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

Definition at line 1593 of file Offer_test.cpp.

+

Definition at line 1529 of file Offer_test.cpp.

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

Definition at line 1617 of file Offer_test.cpp.

+

Definition at line 1553 of file Offer_test.cpp.

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

Definition at line 1643 of file Offer_test.cpp.

+

Definition at line 1579 of file Offer_test.cpp.

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

Definition at line 1697 of file Offer_test.cpp.

+

Definition at line 1633 of file Offer_test.cpp.

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

Definition at line 1727 of file Offer_test.cpp.

+

Definition at line 1663 of file Offer_test.cpp.

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

Definition at line 1813 of file Offer_test.cpp.

+

Definition at line 1749 of file Offer_test.cpp.

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

Definition at line 1855 of file Offer_test.cpp.

+

Definition at line 1791 of file Offer_test.cpp.

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

Definition at line 1903 of file Offer_test.cpp.

+

Definition at line 1839 of file Offer_test.cpp.

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

Definition at line 1969 of file Offer_test.cpp.

+

Definition at line 1905 of file Offer_test.cpp.

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

Definition at line 2036 of file Offer_test.cpp.

+

Definition at line 1972 of file Offer_test.cpp.

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

Definition at line 2091 of file Offer_test.cpp.

+

Definition at line 2027 of file Offer_test.cpp.

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

Definition at line 2147 of file Offer_test.cpp.

+

Definition at line 2083 of file Offer_test.cpp.

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

Definition at line 2190 of file Offer_test.cpp.

+

Definition at line 2126 of file Offer_test.cpp.

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

Definition at line 2235 of file Offer_test.cpp.

+

Definition at line 2171 of file Offer_test.cpp.

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

Definition at line 2313 of file Offer_test.cpp.

+

Definition at line 2249 of file Offer_test.cpp.

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

Definition at line 2344 of file Offer_test.cpp.

+

Definition at line 2280 of file Offer_test.cpp.

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

Definition at line 2503 of file Offer_test.cpp.

+

Definition at line 2439 of file Offer_test.cpp.

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

Definition at line 2580 of file Offer_test.cpp.

+

Definition at line 2516 of file Offer_test.cpp.

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

Definition at line 2698 of file Offer_test.cpp.

+

Definition at line 2634 of file Offer_test.cpp.

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

Definition at line 2796 of file Offer_test.cpp.

+

Definition at line 2732 of file Offer_test.cpp.

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

Definition at line 2985 of file Offer_test.cpp.

+

Definition at line 2921 of file Offer_test.cpp.

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

Definition at line 3070 of file Offer_test.cpp.

+

Definition at line 3006 of file Offer_test.cpp.

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

Definition at line 3378 of file Offer_test.cpp.

+

Definition at line 3314 of file Offer_test.cpp.

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

Definition at line 3448 of file Offer_test.cpp.

+

Definition at line 3384 of file Offer_test.cpp.

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

Definition at line 3560 of file Offer_test.cpp.

+

Definition at line 3496 of file Offer_test.cpp.

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

Definition at line 3568 of file Offer_test.cpp.

+

Definition at line 3504 of file Offer_test.cpp.

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

Definition at line 3613 of file Offer_test.cpp.

+

Definition at line 3549 of file Offer_test.cpp.

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

Definition at line 3684 of file Offer_test.cpp.

+

Definition at line 3620 of file Offer_test.cpp.

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

Definition at line 3737 of file Offer_test.cpp.

+

Definition at line 3673 of file Offer_test.cpp.

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

Definition at line 3773 of file Offer_test.cpp.

+

Definition at line 3709 of file Offer_test.cpp.

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

Definition at line 3820 of file Offer_test.cpp.

+

Definition at line 3756 of file Offer_test.cpp.

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

Definition at line 3872 of file Offer_test.cpp.

+

Definition at line 3808 of file Offer_test.cpp.

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

Definition at line 3939 of file Offer_test.cpp.

+

Definition at line 3875 of file Offer_test.cpp.

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

Definition at line 3987 of file Offer_test.cpp.

+

Definition at line 3923 of file Offer_test.cpp.

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

Definition at line 4142 of file Offer_test.cpp.

+

Definition at line 4078 of file Offer_test.cpp.

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

Definition at line 4291 of file Offer_test.cpp.

+

Definition at line 4227 of file Offer_test.cpp.

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

Definition at line 4342 of file Offer_test.cpp.

+

Definition at line 4278 of file Offer_test.cpp.

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

Definition at line 4463 of file Offer_test.cpp.

+

Definition at line 4399 of file Offer_test.cpp.

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

Definition at line 4552 of file Offer_test.cpp.

+

Definition at line 4488 of file Offer_test.cpp.

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

Definition at line 4624 of file Offer_test.cpp.

+

Definition at line 4560 of file Offer_test.cpp.

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

Definition at line 4731 of file Offer_test.cpp.

+

Definition at line 4667 of file Offer_test.cpp.

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

Definition at line 4840 of file Offer_test.cpp.

+

Definition at line 4776 of file Offer_test.cpp.

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

Definition at line 4855 of file Offer_test.cpp.

+

Definition at line 4791 of file Offer_test.cpp.

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

Definition at line 4975 of file Offer_test.cpp.

+

Definition at line 4911 of file Offer_test.cpp.

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

Definition at line 5087 of file Offer_test.cpp.

+

Definition at line 5023 of file Offer_test.cpp.

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

Definition at line 5105 of file Offer_test.cpp.

+

Definition at line 5041 of file Offer_test.cpp.

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

Definition at line 5293 of file Offer_test.cpp.

+

Definition at line 5229 of file Offer_test.cpp.

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

Definition at line 5357 of file Offer_test.cpp.

+

Definition at line 5293 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 a062a4913f..db4a5b7a2c 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 5438 of file Offer_test.cpp.

+

Definition at line 5371 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 5441 of file Offer_test.cpp.

+

Definition at line 5374 of file Offer_test.cpp.

@@ -733,7 +733,7 @@ Private Attributes
-

Definition at line 472 of file Offer_test.cpp.

+

Definition at line 440 of file Offer_test.cpp.

@@ -761,7 +761,7 @@ Private Attributes
-

Definition at line 635 of file Offer_test.cpp.

+

Definition at line 571 of file Offer_test.cpp.

@@ -789,7 +789,7 @@ Private Attributes
-

Definition at line 711 of file Offer_test.cpp.

+

Definition at line 647 of file Offer_test.cpp.

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

Definition at line 820 of file Offer_test.cpp.

+

Definition at line 756 of file Offer_test.cpp.

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

Definition at line 834 of file Offer_test.cpp.

+

Definition at line 770 of file Offer_test.cpp.

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

Definition at line 1061 of file Offer_test.cpp.

+

Definition at line 997 of file Offer_test.cpp.

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

Definition at line 1139 of file Offer_test.cpp.

+

Definition at line 1075 of file Offer_test.cpp.

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

Definition at line 1217 of file Offer_test.cpp.

+

Definition at line 1153 of file Offer_test.cpp.

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

Definition at line 1277 of file Offer_test.cpp.

+

Definition at line 1213 of file Offer_test.cpp.

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

Definition at line 1387 of file Offer_test.cpp.

+

Definition at line 1323 of file Offer_test.cpp.

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

Definition at line 1497 of file Offer_test.cpp.

+

Definition at line 1433 of file Offer_test.cpp.

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

Definition at line 1552 of file Offer_test.cpp.

+

Definition at line 1488 of file Offer_test.cpp.

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

Definition at line 1593 of file Offer_test.cpp.

+

Definition at line 1529 of file Offer_test.cpp.

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

Definition at line 1617 of file Offer_test.cpp.

+

Definition at line 1553 of file Offer_test.cpp.

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

Definition at line 1643 of file Offer_test.cpp.

+

Definition at line 1579 of file Offer_test.cpp.

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

Definition at line 1697 of file Offer_test.cpp.

+

Definition at line 1633 of file Offer_test.cpp.

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

Definition at line 1727 of file Offer_test.cpp.

+

Definition at line 1663 of file Offer_test.cpp.

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

Definition at line 1813 of file Offer_test.cpp.

+

Definition at line 1749 of file Offer_test.cpp.

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

Definition at line 1855 of file Offer_test.cpp.

+

Definition at line 1791 of file Offer_test.cpp.

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

Definition at line 1903 of file Offer_test.cpp.

+

Definition at line 1839 of file Offer_test.cpp.

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

Definition at line 1969 of file Offer_test.cpp.

+

Definition at line 1905 of file Offer_test.cpp.

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

Definition at line 2036 of file Offer_test.cpp.

+

Definition at line 1972 of file Offer_test.cpp.

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

Definition at line 2091 of file Offer_test.cpp.

+

Definition at line 2027 of file Offer_test.cpp.

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

Definition at line 2147 of file Offer_test.cpp.

+

Definition at line 2083 of file Offer_test.cpp.

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

Definition at line 2190 of file Offer_test.cpp.

+

Definition at line 2126 of file Offer_test.cpp.

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

Definition at line 2235 of file Offer_test.cpp.

+

Definition at line 2171 of file Offer_test.cpp.

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

Definition at line 2313 of file Offer_test.cpp.

+

Definition at line 2249 of file Offer_test.cpp.

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

Definition at line 2344 of file Offer_test.cpp.

+

Definition at line 2280 of file Offer_test.cpp.

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

Definition at line 2503 of file Offer_test.cpp.

+

Definition at line 2439 of file Offer_test.cpp.

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

Definition at line 2580 of file Offer_test.cpp.

+

Definition at line 2516 of file Offer_test.cpp.

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

Definition at line 2698 of file Offer_test.cpp.

+

Definition at line 2634 of file Offer_test.cpp.

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

Definition at line 2796 of file Offer_test.cpp.

+

Definition at line 2732 of file Offer_test.cpp.

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

Definition at line 2985 of file Offer_test.cpp.

+

Definition at line 2921 of file Offer_test.cpp.

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

Definition at line 3070 of file Offer_test.cpp.

+

Definition at line 3006 of file Offer_test.cpp.

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

Definition at line 3378 of file Offer_test.cpp.

+

Definition at line 3314 of file Offer_test.cpp.

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

Definition at line 3448 of file Offer_test.cpp.

+

Definition at line 3384 of file Offer_test.cpp.

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

Definition at line 3560 of file Offer_test.cpp.

+

Definition at line 3496 of file Offer_test.cpp.

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

Definition at line 3568 of file Offer_test.cpp.

+

Definition at line 3504 of file Offer_test.cpp.

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

Definition at line 3613 of file Offer_test.cpp.

+

Definition at line 3549 of file Offer_test.cpp.

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

Definition at line 3684 of file Offer_test.cpp.

+

Definition at line 3620 of file Offer_test.cpp.

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

Definition at line 3737 of file Offer_test.cpp.

+

Definition at line 3673 of file Offer_test.cpp.

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

Definition at line 3773 of file Offer_test.cpp.

+

Definition at line 3709 of file Offer_test.cpp.

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

Definition at line 3820 of file Offer_test.cpp.

+

Definition at line 3756 of file Offer_test.cpp.

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

Definition at line 3872 of file Offer_test.cpp.

+

Definition at line 3808 of file Offer_test.cpp.

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

Definition at line 3939 of file Offer_test.cpp.

+

Definition at line 3875 of file Offer_test.cpp.

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

Definition at line 3987 of file Offer_test.cpp.

+

Definition at line 3923 of file Offer_test.cpp.

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

Definition at line 4142 of file Offer_test.cpp.

+

Definition at line 4078 of file Offer_test.cpp.

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

Definition at line 4291 of file Offer_test.cpp.

+

Definition at line 4227 of file Offer_test.cpp.

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

Definition at line 4342 of file Offer_test.cpp.

+

Definition at line 4278 of file Offer_test.cpp.

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

Definition at line 4463 of file Offer_test.cpp.

+

Definition at line 4399 of file Offer_test.cpp.

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

Definition at line 4552 of file Offer_test.cpp.

+

Definition at line 4488 of file Offer_test.cpp.

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

Definition at line 4624 of file Offer_test.cpp.

+

Definition at line 4560 of file Offer_test.cpp.

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

Definition at line 4731 of file Offer_test.cpp.

+

Definition at line 4667 of file Offer_test.cpp.

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

Definition at line 4840 of file Offer_test.cpp.

+

Definition at line 4776 of file Offer_test.cpp.

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

Definition at line 4855 of file Offer_test.cpp.

+

Definition at line 4791 of file Offer_test.cpp.

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

Definition at line 4975 of file Offer_test.cpp.

+

Definition at line 4911 of file Offer_test.cpp.

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

Definition at line 5087 of file Offer_test.cpp.

+

Definition at line 5023 of file Offer_test.cpp.

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

Definition at line 5105 of file Offer_test.cpp.

+

Definition at line 5041 of file Offer_test.cpp.

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

Definition at line 5293 of file Offer_test.cpp.

+

Definition at line 5229 of file Offer_test.cpp.

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

Definition at line 5357 of file Offer_test.cpp.

+

Definition at line 5293 of file Offer_test.cpp.