From 3fcc2e4cf0f77fd95c5729421f48a2b015cae788 Mon Sep 17 00:00:00 2001 From: bthomee Date: Mon, 10 Nov 2025 08:06:08 -0800 Subject: [PATCH] deploy: 12c629a1d2e676848ae185306ab2d28660cfc74f --- CashCheck_8cpp_source.html | 659 +++--- CashCheck_8h_source.html | 2 +- Check__test_8cpp_source.html | 3895 +++++++++++++++---------------- classripple_1_1CashCheck.html | 2 +- classripple_1_1Check__test.html | 20 +- 5 files changed, 2250 insertions(+), 2328 deletions(-) diff --git a/CashCheck_8cpp_source.html b/CashCheck_8cpp_source.html index e4caf8b963..e1fcf42c74 100644 --- a/CashCheck_8cpp_source.html +++ b/CashCheck_8cpp_source.html @@ -242,347 +242,329 @@ $(document).ready(function() { init_codefold(0); });
156 // An issuer can always accept their own currency.
157 if (!value.native() && (value.getIssuer() != dstId))
158 {
-
159 auto const sleTrustLine =
-
160 ctx.view.read(keylet::line(dstId, issuerId, currency));
-
161
-
162 if (!sleTrustLine &&
-
163 !ctx.view.rules().enabled(featureCheckCashMakesTrustLine))
-
164 {
-
165 JLOG(ctx.j.warn())
-
166 << "Cannot cash check for IOU without trustline.";
-
167 return tecNO_LINE;
-
168 }
-
169
-
170 auto const sleIssuer = ctx.view.read(keylet::account(issuerId));
-
171 if (!sleIssuer)
-
172 {
-
173 JLOG(ctx.j.warn())
-
174 << "Can't receive IOUs from non-existent issuer: "
-
175 << to_string(issuerId);
-
176 return tecNO_ISSUER;
-
177 }
-
178
-
179 if (sleIssuer->at(sfFlags) & lsfRequireAuth)
-
180 {
-
181 if (!sleTrustLine)
-
182 {
-
183 // We can only create a trust line if the issuer does not
-
184 // have lsfRequireAuth set.
-
185 return tecNO_AUTH;
-
186 }
-
187
-
188 // Entries have a canonical representation, determined by a
-
189 // lexicographical "greater than" comparison employing strict
-
190 // weak ordering. Determine which entry we need to access.
-
191 bool const canonical_gt(dstId > issuerId);
-
192
-
193 bool const is_authorized(
-
194 sleTrustLine->at(sfFlags) &
-
195 (canonical_gt ? lsfLowAuth : lsfHighAuth));
+
159 auto const sleIssuer = ctx.view.read(keylet::account(issuerId));
+
160 if (!sleIssuer)
+
161 {
+
162 JLOG(ctx.j.warn())
+
163 << "Can't receive IOUs from non-existent issuer: "
+
164 << to_string(issuerId);
+
165 return tecNO_ISSUER;
+
166 }
+
167
+
168 if (sleIssuer->at(sfFlags) & lsfRequireAuth)
+
169 {
+
170 auto const sleTrustLine =
+
171 ctx.view.read(keylet::line(dstId, issuerId, currency));
+
172
+
173 if (!sleTrustLine)
+
174 {
+
175 // We can only create a trust line if the issuer does not
+
176 // have lsfRequireAuth set.
+
177 return tecNO_AUTH;
+
178 }
+
179
+
180 // Entries have a canonical representation, determined by a
+
181 // lexicographical "greater than" comparison employing strict
+
182 // weak ordering. Determine which entry we need to access.
+
183 bool const canonical_gt(dstId > issuerId);
+
184
+
185 bool const is_authorized(
+
186 sleTrustLine->at(sfFlags) &
+
187 (canonical_gt ? lsfLowAuth : lsfHighAuth));
+
188
+
189 if (!is_authorized)
+
190 {
+
191 JLOG(ctx.j.warn())
+
192 << "Can't receive IOUs from issuer without auth.";
+
193 return tecNO_AUTH;
+
194 }
+
195 }
196
-
197 if (!is_authorized)
-
198 {
-
199 JLOG(ctx.j.warn())
-
200 << "Can't receive IOUs from issuer without auth.";
-
201 return tecNO_AUTH;
-
202 }
-
203 }
-
204
-
205 // The trustline from source to issuer does not need to
-
206 // be checked for freezing, since we already verified that the
-
207 // source has sufficient non-frozen funds available.
-
208
-
209 // However, the trustline from destination to issuer may not
-
210 // be frozen.
-
211 if (isFrozen(ctx.view, dstId, currency, issuerId))
-
212 {
-
213 JLOG(ctx.j.warn()) << "Cashing a check to a frozen trustline.";
-
214 return tecFROZEN;
-
215 }
-
216 }
-
217 }
-
218 return tesSUCCESS;
-
219}
+
197 // The trustline from source to issuer does not need to
+
198 // be checked for freezing, since we already verified that the
+
199 // source has sufficient non-frozen funds available.
+
200
+
201 // However, the trustline from destination to issuer may not
+
202 // be frozen.
+
203 if (isFrozen(ctx.view, dstId, currency, issuerId))
+
204 {
+
205 JLOG(ctx.j.warn()) << "Cashing a check to a frozen trustline.";
+
206 return tecFROZEN;
+
207 }
+
208 }
+
209 }
+
210 return tesSUCCESS;
+
211}
-
220
-
221TER
-
- -
223{
-
224 // Flow requires that we operate on a PaymentSandbox, rather than
-
225 // directly on a View.
-
226 PaymentSandbox psb(&ctx_.view());
-
227
-
228 auto sleCheck = psb.peek(keylet::check(ctx_.tx[sfCheckID]));
-
229 if (!sleCheck)
-
230 {
-
231 // LCOV_EXCL_START
-
232 JLOG(j_.fatal()) << "Precheck did not verify check's existence.";
- -
234 // LCOV_EXCL_STOP
-
235 }
-
236
-
237 AccountID const srcId{sleCheck->getAccountID(sfAccount)};
-
238 if (!psb.exists(keylet::account(srcId)) ||
- -
240 {
-
241 // LCOV_EXCL_START
-
242 JLOG(ctx_.journal.fatal())
-
243 << "Precheck did not verify source or destination's existence.";
- -
245 // LCOV_EXCL_STOP
-
246 }
-
247
-
248 // Preclaim already checked that source has at least the requested
-
249 // funds.
-
250 //
-
251 // Therefore, if this is a check written to self, (and it shouldn't be)
-
252 // we know they have sufficient funds to pay the check. Since they are
-
253 // taking the funds from their own pocket and putting it back in their
-
254 // pocket no balance will change.
-
255 //
-
256 // If it is not a check to self (as should be the case), then there's
-
257 // work to do...
-
258 auto viewJ = ctx_.app.journal("View");
-
259 auto const optDeliverMin = ctx_.tx[~sfDeliverMin];
-
260
-
261 if (srcId != account_)
-
262 {
-
263 STAmount const sendMax = sleCheck->at(sfSendMax);
-
264
-
265 // Flow() doesn't do XRP to XRP transfers.
-
266 if (sendMax.native())
-
267 {
-
268 // Here we need to calculate the amount of XRP src can send.
-
269 // The amount they have available is their balance minus their
-
270 // reserve.
-
271 //
-
272 // Since (if we're successful) we're about to remove an entry
-
273 // from src's directory, we allow them to send that additional
-
274 // incremental reserve amount in the transfer. Hence the -1
-
275 // argument.
-
276 STAmount const srcLiquid{xrpLiquid(psb, srcId, -1, viewJ)};
-
277
-
278 // Now, how much do they need in order to be successful?
-
279 STAmount const xrpDeliver{
-
280 optDeliverMin
-
281 ? std::max(*optDeliverMin, std::min(sendMax, srcLiquid))
-
282 : ctx_.tx.getFieldAmount(sfAmount)};
-
283
-
284 if (srcLiquid < xrpDeliver)
-
285 {
-
286 // Vote no. However the transaction might succeed if applied
-
287 // in a different order.
-
288 JLOG(j_.trace()) << "Cash Check: Insufficient XRP: "
-
289 << srcLiquid.getFullText() << " < "
-
290 << xrpDeliver.getFullText();
-
291 return tecUNFUNDED_PAYMENT;
-
292 }
-
293
-
294 if (optDeliverMin)
-
295 // Set the DeliveredAmount metadata.
-
296 ctx_.deliver(xrpDeliver);
-
297
-
298 // The source account has enough XRP so make the ledger change.
-
299 if (TER const ter{
-
300 transferXRP(psb, srcId, account_, xrpDeliver, viewJ)};
-
301 ter != tesSUCCESS)
-
302 {
-
303 // The transfer failed. Return the error code.
-
304 return ter;
-
305 }
-
306 }
-
307 else
-
308 {
-
309 // Note that for DeliverMin we don't know exactly how much
-
310 // currency we want flow to deliver. We can't ask for the
-
311 // maximum possible currency because there might be a gateway
-
312 // transfer rate to account for. Since the transfer rate cannot
-
313 // exceed 200%, we use 1/2 maxValue as our limit.
-
314 STAmount const flowDeliver{
-
315 optDeliverMin ? STAmount(
-
316 optDeliverMin->issue(),
- - -
319 : ctx_.tx.getFieldAmount(sfAmount)};
-
320
-
321 // If a trust line does not exist yet create one.
-
322 Issue const& trustLineIssue = flowDeliver.issue();
-
323 AccountID const issuer = flowDeliver.getIssuer();
-
324 AccountID const truster = issuer == account_ ? srcId : account_;
-
325 Keylet const trustLineKey = keylet::line(truster, trustLineIssue);
-
326 bool const destLow = issuer > account_;
-
327
-
328 bool const checkCashMakesTrustLine =
-
329 psb.rules().enabled(featureCheckCashMakesTrustLine);
+
212
+
213TER
+
+ +
215{
+
216 // Flow requires that we operate on a PaymentSandbox, rather than
+
217 // directly on a View.
+
218 PaymentSandbox psb(&ctx_.view());
+
219
+
220 auto sleCheck = psb.peek(keylet::check(ctx_.tx[sfCheckID]));
+
221 if (!sleCheck)
+
222 {
+
223 // LCOV_EXCL_START
+
224 JLOG(j_.fatal()) << "Precheck did not verify check's existence.";
+ +
226 // LCOV_EXCL_STOP
+
227 }
+
228
+
229 AccountID const srcId{sleCheck->getAccountID(sfAccount)};
+
230 if (!psb.exists(keylet::account(srcId)) ||
+ +
232 {
+
233 // LCOV_EXCL_START
+
234 JLOG(ctx_.journal.fatal())
+
235 << "Precheck did not verify source or destination's existence.";
+ +
237 // LCOV_EXCL_STOP
+
238 }
+
239
+
240 // Preclaim already checked that source has at least the requested
+
241 // funds.
+
242 //
+
243 // Therefore, if this is a check written to self, (and it shouldn't be)
+
244 // we know they have sufficient funds to pay the check. Since they are
+
245 // taking the funds from their own pocket and putting it back in their
+
246 // pocket no balance will change.
+
247 //
+
248 // If it is not a check to self (as should be the case), then there's
+
249 // work to do...
+
250 auto viewJ = ctx_.app.journal("View");
+
251 auto const optDeliverMin = ctx_.tx[~sfDeliverMin];
+
252
+
253 if (srcId != account_)
+
254 {
+
255 STAmount const sendMax = sleCheck->at(sfSendMax);
+
256
+
257 // Flow() doesn't do XRP to XRP transfers.
+
258 if (sendMax.native())
+
259 {
+
260 // Here we need to calculate the amount of XRP src can send.
+
261 // The amount they have available is their balance minus their
+
262 // reserve.
+
263 //
+
264 // Since (if we're successful) we're about to remove an entry
+
265 // from src's directory, we allow them to send that additional
+
266 // incremental reserve amount in the transfer. Hence the -1
+
267 // argument.
+
268 STAmount const srcLiquid{xrpLiquid(psb, srcId, -1, viewJ)};
+
269
+
270 // Now, how much do they need in order to be successful?
+
271 STAmount const xrpDeliver{
+
272 optDeliverMin
+
273 ? std::max(*optDeliverMin, std::min(sendMax, srcLiquid))
+
274 : ctx_.tx.getFieldAmount(sfAmount)};
+
275
+
276 if (srcLiquid < xrpDeliver)
+
277 {
+
278 // Vote no. However the transaction might succeed if applied
+
279 // in a different order.
+
280 JLOG(j_.trace()) << "Cash Check: Insufficient XRP: "
+
281 << srcLiquid.getFullText() << " < "
+
282 << xrpDeliver.getFullText();
+
283 return tecUNFUNDED_PAYMENT;
+
284 }
+
285
+
286 if (optDeliverMin)
+
287 // Set the DeliveredAmount metadata.
+
288 ctx_.deliver(xrpDeliver);
+
289
+
290 // The source account has enough XRP so make the ledger change.
+
291 if (TER const ter{
+
292 transferXRP(psb, srcId, account_, xrpDeliver, viewJ)};
+
293 ter != tesSUCCESS)
+
294 {
+
295 // The transfer failed. Return the error code.
+
296 return ter;
+
297 }
+
298 }
+
299 else
+
300 {
+
301 // Note that for DeliverMin we don't know exactly how much
+
302 // currency we want flow to deliver. We can't ask for the
+
303 // maximum possible currency because there might be a gateway
+
304 // transfer rate to account for. Since the transfer rate cannot
+
305 // exceed 200%, we use 1/2 maxValue as our limit.
+
306 STAmount const flowDeliver{
+
307 optDeliverMin ? STAmount(
+
308 optDeliverMin->issue(),
+ + +
311 : ctx_.tx.getFieldAmount(sfAmount)};
+
312
+
313 // If a trust line does not exist yet create one.
+
314 Issue const& trustLineIssue = flowDeliver.issue();
+
315 AccountID const issuer = flowDeliver.getIssuer();
+
316 AccountID const truster = issuer == account_ ? srcId : account_;
+
317 Keylet const trustLineKey = keylet::line(truster, trustLineIssue);
+
318 bool const destLow = issuer > account_;
+
319
+
320 if (!psb.exists(trustLineKey))
+
321 {
+
322 // 1. Can the check casher meet the reserve for the trust line?
+
323 // 2. Create trust line between destination (this) account
+
324 // and the issuer.
+
325 // 3. Apply correct noRipple settings on trust line. Use...
+
326 // a. this (destination) account and
+
327 // b. issuing account (not sending account).
+
328
+
329 auto const sleDst = psb.peek(keylet::account(account_));
330
-
331 if (checkCashMakesTrustLine && !psb.exists(trustLineKey))
-
332 {
-
333 // 1. Can the check casher meet the reserve for the trust line?
-
334 // 2. Create trust line between destination (this) account
-
335 // and the issuer.
-
336 // 3. Apply correct noRipple settings on trust line. Use...
-
337 // a. this (destination) account and
-
338 // b. issuing account (not sending account).
-
339
-
340 auto const sleDst = psb.peek(keylet::account(account_));
-
341
-
342 // Can the account cover the trust line's reserve?
-
343 if (std::uint32_t const ownerCount = {sleDst->at(sfOwnerCount)};
-
344 mPriorBalance < psb.fees().accountReserve(ownerCount + 1))
-
345 {
-
346 JLOG(j_.trace()) << "Trust line does not exist. "
-
347 "Insufficent reserve to create line.";
-
348
- -
350 }
-
351
-
352 Currency const currency = flowDeliver.getCurrency();
-
353 STAmount initialBalance(flowDeliver.issue());
-
354 initialBalance.setIssuer(noAccount());
-
355
-
356 // clang-format off
-
357 if (TER const ter = trustCreate(
-
358 psb, // payment sandbox
-
359 destLow, // is dest low?
-
360 issuer, // source
-
361 account_, // destination
-
362 trustLineKey.key, // ledger index
-
363 sleDst, // Account to add to
-
364 false, // authorize account
-
365 (sleDst->getFlags() & lsfDefaultRipple) == 0,
-
366 false, // freeze trust line
-
367 false, // deep freeze trust line
-
368 initialBalance, // zero initial balance
-
369 Issue(currency, account_), // limit of zero
-
370 0, // quality in
-
371 0, // quality out
-
372 viewJ); // journal
-
373 !isTesSuccess(ter))
-
374 {
-
375 return ter;
-
376 }
-
377 // clang-format on
-
378
-
379 psb.update(sleDst);
-
380
-
381 // Note that we _don't_ need to be careful about destroying
-
382 // the trust line if the check cashing fails. The transaction
-
383 // machinery will automatically clean it up.
-
384 }
+
331 // Can the account cover the trust line's reserve?
+
332 if (std::uint32_t const ownerCount = {sleDst->at(sfOwnerCount)};
+
333 mPriorBalance < psb.fees().accountReserve(ownerCount + 1))
+
334 {
+
335 JLOG(j_.trace()) << "Trust line does not exist. "
+
336 "Insufficent reserve to create line.";
+
337
+ +
339 }
+
340
+
341 Currency const currency = flowDeliver.getCurrency();
+
342 STAmount initialBalance(flowDeliver.issue());
+
343 initialBalance.setIssuer(noAccount());
+
344
+
345 // clang-format off
+
346 if (TER const ter = trustCreate(
+
347 psb, // payment sandbox
+
348 destLow, // is dest low?
+
349 issuer, // source
+
350 account_, // destination
+
351 trustLineKey.key, // ledger index
+
352 sleDst, // Account to add to
+
353 false, // authorize account
+
354 (sleDst->getFlags() & lsfDefaultRipple) == 0,
+
355 false, // freeze trust line
+
356 false, // deep freeze trust line
+
357 initialBalance, // zero initial balance
+
358 Issue(currency, account_), // limit of zero
+
359 0, // quality in
+
360 0, // quality out
+
361 viewJ); // journal
+
362 !isTesSuccess(ter))
+
363 {
+
364 return ter;
+
365 }
+
366 // clang-format on
+
367
+
368 psb.update(sleDst);
+
369
+
370 // Note that we _don't_ need to be careful about destroying
+
371 // the trust line if the check cashing fails. The transaction
+
372 // machinery will automatically clean it up.
+
373 }
+
374
+
375 // Since the destination is signing the check, they clearly want
+
376 // the funds even if their new total funds would exceed the limit
+
377 // on their trust line. So we tweak the trust line limits before
+
378 // calling flow and then restore the trust line limits afterwards.
+
379 auto const sleTrustLine = psb.peek(trustLineKey);
+
380 if (!sleTrustLine)
+
381 return tecNO_LINE;
+
382
+
383 SF_AMOUNT const& tweakedLimit = destLow ? sfLowLimit : sfHighLimit;
+
384 STAmount const savedLimit = sleTrustLine->at(tweakedLimit);
385
-
386 // Since the destination is signing the check, they clearly want
-
387 // the funds even if their new total funds would exceed the limit
-
388 // on their trust line. So we tweak the trust line limits before
-
389 // calling flow and then restore the trust line limits afterwards.
-
390 auto const sleTrustLine = psb.peek(trustLineKey);
-
391 if (!sleTrustLine)
-
392 return tecNO_LINE;
-
393
-
394 SF_AMOUNT const& tweakedLimit = destLow ? sfLowLimit : sfHighLimit;
-
395 STAmount const savedLimit = sleTrustLine->at(tweakedLimit);
-
396
-
397 // Make sure the tweaked limits are restored when we leave scope.
-
398 scope_exit fixup(
-
399 [&psb, &trustLineKey, &tweakedLimit, &savedLimit]() {
-
400 if (auto const sleTrustLine = psb.peek(trustLineKey))
-
401 sleTrustLine->at(tweakedLimit) = savedLimit;
-
402 });
-
403
-
404 if (checkCashMakesTrustLine)
-
405 {
-
406 // Set the trust line limit to the highest possible value
-
407 // while flow runs.
-
408 STAmount const bigAmount(
- -
410 sleTrustLine->at(tweakedLimit) = bigAmount;
-
411 }
-
412
-
413 // Let flow() do the heavy lifting on a check for an IOU.
-
414 auto const result = flow(
-
415 psb,
-
416 flowDeliver,
-
417 srcId,
-
418 account_,
-
419 STPathSet{},
-
420 true, // default path
-
421 static_cast<bool>(optDeliverMin), // partial payment
-
422 true, // owner pays transfer fee
- - -
425 sleCheck->getFieldAmount(sfSendMax),
-
426 std::nullopt, // check does not support domain
-
427 viewJ);
-
428
-
429 if (result.result() != tesSUCCESS)
-
430 {
-
431 JLOG(ctx_.journal.warn()) << "flow failed when cashing check.";
-
432 return result.result();
-
433 }
-
434
-
435 // Make sure that deliverMin was satisfied.
-
436 if (optDeliverMin)
-
437 {
-
438 if (result.actualAmountOut < *optDeliverMin)
-
439 {
-
440 JLOG(ctx_.journal.warn())
-
441 << "flow did not produce DeliverMin.";
-
442 return tecPATH_PARTIAL;
-
443 }
-
444 if (!checkCashMakesTrustLine)
-
445 // Set the delivered_amount metadata.
-
446 ctx_.deliver(result.actualAmountOut);
-
447 }
-
448
-
449 // Set the delivered amount metadata in all cases, not just
-
450 // for DeliverMin.
-
451 if (checkCashMakesTrustLine)
-
452 ctx_.deliver(result.actualAmountOut);
-
453
-
454 sleCheck = psb.peek(keylet::check(ctx_.tx[sfCheckID]));
-
455 }
-
456 }
-
457
-
458 // Check was cashed. If not a self send (and it shouldn't be), remove
-
459 // check link from destination directory.
-
460 if (srcId != account_ &&
-
461 !psb.dirRemove(
- -
463 sleCheck->at(sfDestinationNode),
-
464 sleCheck->key(),
-
465 true))
-
466 {
-
467 // LCOV_EXCL_START
-
468 JLOG(j_.fatal()) << "Unable to delete check from destination.";
-
469 return tefBAD_LEDGER;
-
470 // LCOV_EXCL_STOP
-
471 }
-
472
-
473 // Remove check from check owner's directory.
-
474 if (!psb.dirRemove(
-
475 keylet::ownerDir(srcId),
-
476 sleCheck->at(sfOwnerNode),
-
477 sleCheck->key(),
-
478 true))
-
479 {
-
480 // LCOV_EXCL_START
-
481 JLOG(j_.fatal()) << "Unable to delete check from owner.";
-
482 return tefBAD_LEDGER;
-
483 // LCOV_EXCL_STOP
-
484 }
-
485
-
486 // If we succeeded, update the check owner's reserve.
-
487 adjustOwnerCount(psb, psb.peek(keylet::account(srcId)), -1, viewJ);
-
488
-
489 // Remove check from ledger.
-
490 psb.erase(sleCheck);
-
491
-
492 psb.apply(ctx_.rawView());
-
493 return tesSUCCESS;
-
494}
+
386 // Make sure the tweaked limits are restored when we leave scope.
+
387 scope_exit fixup(
+
388 [&psb, &trustLineKey, &tweakedLimit, &savedLimit]() {
+
389 if (auto const sleTrustLine = psb.peek(trustLineKey))
+
390 sleTrustLine->at(tweakedLimit) = savedLimit;
+
391 });
+
392
+
393 // Set the trust line limit to the highest possible value
+
394 // while flow runs.
+
395 STAmount const bigAmount(
+ +
397 sleTrustLine->at(tweakedLimit) = bigAmount;
+
398
+
399 // Let flow() do the heavy lifting on a check for an IOU.
+
400 auto const result = flow(
+
401 psb,
+
402 flowDeliver,
+
403 srcId,
+
404 account_,
+
405 STPathSet{},
+
406 true, // default path
+
407 static_cast<bool>(optDeliverMin), // partial payment
+
408 true, // owner pays transfer fee
+ + +
411 sleCheck->getFieldAmount(sfSendMax),
+
412 std::nullopt, // check does not support domain
+
413 viewJ);
+
414
+
415 if (result.result() != tesSUCCESS)
+
416 {
+
417 JLOG(ctx_.journal.warn()) << "flow failed when cashing check.";
+
418 return result.result();
+
419 }
+
420
+
421 // Make sure that deliverMin was satisfied.
+
422 if (optDeliverMin)
+
423 {
+
424 if (result.actualAmountOut < *optDeliverMin)
+
425 {
+
426 JLOG(ctx_.journal.warn())
+
427 << "flow did not produce DeliverMin.";
+
428 return tecPATH_PARTIAL;
+
429 }
+
430 }
+
431
+
432 // Set the delivered amount metadata in all cases, not just
+
433 // for DeliverMin.
+
434 ctx_.deliver(result.actualAmountOut);
+
435
+
436 sleCheck = psb.peek(keylet::check(ctx_.tx[sfCheckID]));
+
437 }
+
438 }
+
439
+
440 // Check was cashed. If not a self send (and it shouldn't be), remove
+
441 // check link from destination directory.
+
442 if (srcId != account_ &&
+
443 !psb.dirRemove(
+ +
445 sleCheck->at(sfDestinationNode),
+
446 sleCheck->key(),
+
447 true))
+
448 {
+
449 // LCOV_EXCL_START
+
450 JLOG(j_.fatal()) << "Unable to delete check from destination.";
+
451 return tefBAD_LEDGER;
+
452 // LCOV_EXCL_STOP
+
453 }
+
454
+
455 // Remove check from check owner's directory.
+
456 if (!psb.dirRemove(
+
457 keylet::ownerDir(srcId),
+
458 sleCheck->at(sfOwnerNode),
+
459 sleCheck->key(),
+
460 true))
+
461 {
+
462 // LCOV_EXCL_START
+
463 JLOG(j_.fatal()) << "Unable to delete check from owner.";
+
464 return tefBAD_LEDGER;
+
465 // LCOV_EXCL_STOP
+
466 }
+
467
+
468 // If we succeeded, update the check owner's reserve.
+
469 adjustOwnerCount(psb, psb.peek(keylet::account(srcId)), -1, viewJ);
+
470
+
471 // Remove check from ledger.
+
472 psb.erase(sleCheck);
+
473
+
474 psb.apply(ctx_.rawView());
+
475 return tesSUCCESS;
+
476}
-
495
-
496} // namespace ripple
+
477
+
478} // namespace ripple
Stream fatal() const
Definition Journal.h:333
Stream error() const
Definition Journal.h:327
@@ -597,15 +579,13 @@ $(document).ready(function() { init_codefold(0); });
void deliver(STAmount const &amount)
Sets the DeliveredAmount field in the metadata.
bool dirRemove(Keylet const &directory, std::uint64_t page, uint256 const &key, bool keepRoot)
Remove an entry from a directory.
static TER preclaim(PreclaimContext const &ctx)
Definition CashCheck.cpp:50
-
TER doApply() override
+
TER doApply() override
static NotTEC preflight(PreflightContext const &ctx)
Definition CashCheck.cpp:17
A currency issued by an account.
Definition Issue.h:14
A wrapper which makes credits unavailable to balances.
void apply(RawView &to)
Apply changes to base view.
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
virtual Fees const & fees() const =0
Returns the fees for the base ledger.
-
virtual Rules const & rules() const =0
Returns the tx processing rules.
-
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
Definition Rules.cpp:111
void setIssuer(AccountID const &uIssuer)
Definition STAmount.h:569
static int const cMaxOffset
Definition STAmount.h:47
@@ -627,7 +607,6 @@ $(document).ready(function() { init_codefold(0); });
void erase(std::shared_ptr< SLE > const &sle) override
Remove a peeked SLE.
void update(std::shared_ptr< SLE > const &sle) override
Indicate changes to a peeked SLE.
bool exists(Keylet const &k) const override
Determine if a state item exists.
-
Rules const & rules() const override
Returns the tx processing rules.
std::shared_ptr< SLE > peek(Keylet const &k) override
Prepare to modify the SLE associated with key.
diff --git a/CashCheck_8h_source.html b/CashCheck_8h_source.html index cc59f8ffa3..256aa93eaf 100644 --- a/CashCheck_8h_source.html +++ b/CashCheck_8h_source.html @@ -120,7 +120,7 @@ $(document).ready(function() { init_codefold(0); });
static TER preclaim(PreclaimContext const &ctx)
Definition CashCheck.cpp:50
CashCheck(ApplyContext &ctx)
Definition CashCheck.h:13
-
TER doApply() override
+
TER doApply() override
static constexpr ConsequencesFactoryType ConsequencesFactory
Definition CashCheck.h:11
static NotTEC preflight(PreflightContext const &ctx)
Definition CashCheck.cpp:17
diff --git a/Check__test_8cpp_source.html b/Check__test_8cpp_source.html index 70fac8b032..daf2576ba2 100644 --- a/Check__test_8cpp_source.html +++ b/Check__test_8cpp_source.html @@ -797,2048 +797,1991 @@ $(document).ready(function() { init_codefold(0); });
679
680 using namespace test::jtx;
681
-
682 bool const cashCheckMakesTrustLine =
-
683 features[featureCheckCashMakesTrustLine];
-
684
-
685 Account const gw{"gateway"};
-
686 Account const alice{"alice"};
-
687 Account const bob{"bob"};
-
688 IOU const USD{gw["USD"]};
-
689 {
-
690 // Simple IOU check cashed with Amount (with failures).
-
691 Env env{*this, features};
+
682 Account const gw{"gateway"};
+
683 Account const alice{"alice"};
+
684 Account const bob{"bob"};
+
685 IOU const USD{gw["USD"]};
+
686 {
+
687 // Simple IOU check cashed with Amount (with failures).
+
688 Env env{*this, features};
+
689
+
690 env.fund(XRP(1000), gw, alice, bob);
+
691 env.close();
692
-
693 env.fund(XRP(1000), gw, alice, bob);
-
694 env.close();
-
695
-
696 // alice writes the check before she gets the funds.
-
697 uint256 const chkId1{getCheckIndex(alice, env.seq(alice))};
-
698 env(check::create(alice, bob, USD(10)));
-
699 env.close();
-
700
-
701 // bob attempts to cash the check. Should fail.
-
702 env(check::cash(bob, chkId1, USD(10)), ter(tecPATH_PARTIAL));
-
703 env.close();
-
704
-
705 // alice gets almost enough funds. bob tries and fails again.
-
706 env(trust(alice, USD(20)));
-
707 env.close();
-
708 env(pay(gw, alice, USD(9.5)));
-
709 env.close();
-
710 env(check::cash(bob, chkId1, USD(10)), ter(tecPATH_PARTIAL));
-
711 env.close();
-
712
-
713 // alice gets the last of the necessary funds. bob tries again
-
714 // and fails because he hasn't got a trust line for USD.
-
715 env(pay(gw, alice, USD(0.5)));
-
716 env.close();
-
717 if (!cashCheckMakesTrustLine)
-
718 {
-
719 // If cashing a check automatically creates a trustline then
-
720 // this returns tesSUCCESS and the check is removed from the
-
721 // ledger which would mess up later tests.
-
722 env(check::cash(bob, chkId1, USD(10)), ter(tecNO_LINE));
-
723 env.close();
-
724 }
+
693 // alice writes the check before she gets the funds.
+
694 uint256 const chkId1{getCheckIndex(alice, env.seq(alice))};
+
695 env(check::create(alice, bob, USD(10)));
+
696 env.close();
+
697
+
698 // bob attempts to cash the check. Should fail.
+
699 env(check::cash(bob, chkId1, USD(10)), ter(tecPATH_PARTIAL));
+
700 env.close();
+
701
+
702 // alice gets almost enough funds. bob tries and fails again.
+
703 env(trust(alice, USD(20)));
+
704 env.close();
+
705 env(pay(gw, alice, USD(9.5)));
+
706 env.close();
+
707 env(check::cash(bob, chkId1, USD(10)), ter(tecPATH_PARTIAL));
+
708 env.close();
+
709
+
710 // alice gets the last of the necessary funds. bob tries again
+
711 // and fails because he hasn't got a trust line for USD.
+
712 env(pay(gw, alice, USD(0.5)));
+
713 env.close();
+
714
+
715 // bob sets up the trust line, but not at a high enough limit.
+
716 env(trust(bob, USD(9.5)));
+
717 env.close();
+
718
+
719 // bob sets the trust line limit high enough but asks for more
+
720 // than the check's SendMax.
+
721 env(trust(bob, USD(10.5)));
+
722 env.close();
+
723 env(check::cash(bob, chkId1, USD(10.5)), ter(tecPATH_PARTIAL));
+
724 env.close();
725
-
726 // bob sets up the trust line, but not at a high enough limit.
-
727 env(trust(bob, USD(9.5)));
+
726 // bob asks for exactly the check amount and the check clears.
+
727 env(check::cash(bob, chkId1, USD(10)));
728 env.close();
-
729 if (!cashCheckMakesTrustLine)
-
730 {
-
731 // If cashing a check is allowed to exceed the trust line
-
732 // limit then this returns tesSUCCESS and the check is
-
733 // removed from the ledger which would mess up later tests.
-
734 env(check::cash(bob, chkId1, USD(10)), ter(tecPATH_PARTIAL));
-
735 env.close();
-
736 }
-
737
-
738 // bob sets the trust line limit high enough but asks for more
-
739 // than the check's SendMax.
-
740 env(trust(bob, USD(10.5)));
-
741 env.close();
-
742 env(check::cash(bob, chkId1, USD(10.5)), ter(tecPATH_PARTIAL));
-
743 env.close();
-
744
-
745 // bob asks for exactly the check amount and the check clears.
-
746 env(check::cash(bob, chkId1, USD(10)));
-
747 env.close();
-
748 env.require(balance(alice, USD(0)));
-
749 env.require(balance(bob, USD(10)));
-
750 BEAST_EXPECT(checksOnAccount(env, alice).size() == 0);
-
751 BEAST_EXPECT(checksOnAccount(env, bob).size() == 0);
-
752 BEAST_EXPECT(ownerCount(env, alice) == 1);
-
753 BEAST_EXPECT(ownerCount(env, bob) == 1);
-
754
-
755 // bob tries to cash the same check again, which fails.
-
756 env(check::cash(bob, chkId1, USD(10)), ter(tecNO_ENTRY));
-
757 env.close();
-
758
-
759 // bob pays alice USD(7) so he can try another case.
-
760 env(pay(bob, alice, USD(7)));
-
761 env.close();
-
762
-
763 uint256 const chkId2{getCheckIndex(alice, env.seq(alice))};
-
764 env(check::create(alice, bob, USD(7)));
-
765 env.close();
-
766 BEAST_EXPECT(checksOnAccount(env, alice).size() == 1);
-
767 BEAST_EXPECT(checksOnAccount(env, bob).size() == 1);
-
768
-
769 // bob cashes the check for less than the face amount. That works,
-
770 // consumes the check, and bob receives as much as he asked for.
-
771 env(check::cash(bob, chkId2, USD(5)));
-
772 env.close();
-
773 env.require(balance(alice, USD(2)));
-
774 env.require(balance(bob, USD(8)));
-
775 BEAST_EXPECT(checksOnAccount(env, alice).size() == 0);
-
776 BEAST_EXPECT(checksOnAccount(env, bob).size() == 0);
-
777 BEAST_EXPECT(ownerCount(env, alice) == 1);
-
778 BEAST_EXPECT(ownerCount(env, bob) == 1);
-
779
-
780 // alice writes two checks for USD(2), although she only has USD(2).
-
781 uint256 const chkId3{getCheckIndex(alice, env.seq(alice))};
-
782 env(check::create(alice, bob, USD(2)));
-
783 env.close();
-
784 uint256 const chkId4{getCheckIndex(alice, env.seq(alice))};
-
785 env(check::create(alice, bob, USD(2)));
-
786 env.close();
-
787 BEAST_EXPECT(checksOnAccount(env, alice).size() == 2);
-
788 BEAST_EXPECT(checksOnAccount(env, bob).size() == 2);
-
789
-
790 // bob cashes the second check for the face amount.
-
791 env(check::cash(bob, chkId4, USD(2)));
-
792 env.close();
-
793 env.require(balance(alice, USD(0)));
-
794 env.require(balance(bob, USD(10)));
-
795 BEAST_EXPECT(checksOnAccount(env, alice).size() == 1);
-
796 BEAST_EXPECT(checksOnAccount(env, bob).size() == 1);
-
797 BEAST_EXPECT(ownerCount(env, alice) == 2);
-
798 BEAST_EXPECT(ownerCount(env, bob) == 1);
-
799
-
800 // bob is not allowed to cash the last check for USD(0), he must
-
801 // use check::cancel instead.
-
802 env(check::cash(bob, chkId3, USD(0)), ter(temBAD_AMOUNT));
+
729 env.require(balance(alice, USD(0)));
+
730 env.require(balance(bob, USD(10)));
+
731 BEAST_EXPECT(checksOnAccount(env, alice).size() == 0);
+
732 BEAST_EXPECT(checksOnAccount(env, bob).size() == 0);
+
733 BEAST_EXPECT(ownerCount(env, alice) == 1);
+
734 BEAST_EXPECT(ownerCount(env, bob) == 1);
+
735
+
736 // bob tries to cash the same check again, which fails.
+
737 env(check::cash(bob, chkId1, USD(10)), ter(tecNO_ENTRY));
+
738 env.close();
+
739
+
740 // bob pays alice USD(7) so he can try another case.
+
741 env(pay(bob, alice, USD(7)));
+
742 env.close();
+
743
+
744 uint256 const chkId2{getCheckIndex(alice, env.seq(alice))};
+
745 env(check::create(alice, bob, USD(7)));
+
746 env.close();
+
747 BEAST_EXPECT(checksOnAccount(env, alice).size() == 1);
+
748 BEAST_EXPECT(checksOnAccount(env, bob).size() == 1);
+
749
+
750 // bob cashes the check for less than the face amount. That works,
+
751 // consumes the check, and bob receives as much as he asked for.
+
752 env(check::cash(bob, chkId2, USD(5)));
+
753 env.close();
+
754 env.require(balance(alice, USD(2)));
+
755 env.require(balance(bob, USD(8)));
+
756 BEAST_EXPECT(checksOnAccount(env, alice).size() == 0);
+
757 BEAST_EXPECT(checksOnAccount(env, bob).size() == 0);
+
758 BEAST_EXPECT(ownerCount(env, alice) == 1);
+
759 BEAST_EXPECT(ownerCount(env, bob) == 1);
+
760
+
761 // alice writes two checks for USD(2), although she only has USD(2).
+
762 uint256 const chkId3{getCheckIndex(alice, env.seq(alice))};
+
763 env(check::create(alice, bob, USD(2)));
+
764 env.close();
+
765 uint256 const chkId4{getCheckIndex(alice, env.seq(alice))};
+
766 env(check::create(alice, bob, USD(2)));
+
767 env.close();
+
768 BEAST_EXPECT(checksOnAccount(env, alice).size() == 2);
+
769 BEAST_EXPECT(checksOnAccount(env, bob).size() == 2);
+
770
+
771 // bob cashes the second check for the face amount.
+
772 env(check::cash(bob, chkId4, USD(2)));
+
773 env.close();
+
774 env.require(balance(alice, USD(0)));
+
775 env.require(balance(bob, USD(10)));
+
776 BEAST_EXPECT(checksOnAccount(env, alice).size() == 1);
+
777 BEAST_EXPECT(checksOnAccount(env, bob).size() == 1);
+
778 BEAST_EXPECT(ownerCount(env, alice) == 2);
+
779 BEAST_EXPECT(ownerCount(env, bob) == 1);
+
780
+
781 // bob is not allowed to cash the last check for USD(0), he must
+
782 // use check::cancel instead.
+
783 env(check::cash(bob, chkId3, USD(0)), ter(temBAD_AMOUNT));
+
784 env.close();
+
785 env.require(balance(alice, USD(0)));
+
786 env.require(balance(bob, USD(10)));
+
787 BEAST_EXPECT(checksOnAccount(env, alice).size() == 1);
+
788 BEAST_EXPECT(checksOnAccount(env, bob).size() == 1);
+
789 BEAST_EXPECT(ownerCount(env, alice) == 2);
+
790 BEAST_EXPECT(ownerCount(env, bob) == 1);
+
791
+
792 // Automatic trust lines are enabled. But one aspect of
+
793 // automatic trust lines is that they allow the account
+
794 // cashing a check to exceed their trust line limit. Show
+
795 // that at work.
+
796 //
+
797 // bob's trust line limit is currently USD(10.5). Show that
+
798 // a payment to bob cannot exceed that trust line, but cashing
+
799 // a check can.
+
800
+
801 // Payment of 20 USD fails.
+
802 env(pay(gw, bob, USD(20)), ter(tecPATH_PARTIAL));
803 env.close();
-
804 env.require(balance(alice, USD(0)));
-
805 env.require(balance(bob, USD(10)));
-
806 BEAST_EXPECT(checksOnAccount(env, alice).size() == 1);
-
807 BEAST_EXPECT(checksOnAccount(env, bob).size() == 1);
-
808 BEAST_EXPECT(ownerCount(env, alice) == 2);
-
809 BEAST_EXPECT(ownerCount(env, bob) == 1);
-
810
-
811 if (cashCheckMakesTrustLine)
-
812 {
-
813 // Automatic trust lines are enabled. But one aspect of
-
814 // automatic trust lines is that they allow the account
-
815 // cashing a check to exceed their trust line limit. Show
-
816 // that at work.
-
817 //
-
818 // bob's trust line limit is currently USD(10.5). Show that
-
819 // a payment to bob cannot exceed that trust line, but cashing
-
820 // a check can.
-
821
-
822 // Payment of 20 USD fails.
-
823 env(pay(gw, bob, USD(20)), ter(tecPATH_PARTIAL));
-
824 env.close();
-
825
-
826 uint256 const chkId20{getCheckIndex(gw, env.seq(gw))};
-
827 env(check::create(gw, bob, USD(20)));
-
828 env.close();
-
829
-
830 // However cashing a check for 20 USD succeeds.
-
831 env(check::cash(bob, chkId20, USD(20)));
-
832 env.close();
-
833 env.require(balance(bob, USD(30)));
+
804
+
805 uint256 const chkId20{getCheckIndex(gw, env.seq(gw))};
+
806 env(check::create(gw, bob, USD(20)));
+
807 env.close();
+
808
+
809 // However cashing a check for 20 USD succeeds.
+
810 env(check::cash(bob, chkId20, USD(20)));
+
811 env.close();
+
812 env.require(balance(bob, USD(30)));
+
813
+
814 // Clean up this most recent experiment so the rest of the
+
815 // tests work.
+
816 env(pay(bob, gw, USD(20)));
+
817
+
818 // ... so bob cancels alice's remaining check.
+
819 env(check::cancel(bob, chkId3));
+
820 env.close();
+
821 env.require(balance(alice, USD(0)));
+
822 env.require(balance(bob, USD(10)));
+
823 BEAST_EXPECT(checksOnAccount(env, alice).size() == 0);
+
824 BEAST_EXPECT(checksOnAccount(env, bob).size() == 0);
+
825 BEAST_EXPECT(ownerCount(env, alice) == 1);
+
826 BEAST_EXPECT(ownerCount(env, bob) == 1);
+
827 }
+
828 {
+
829 // Simple IOU check cashed with DeliverMin (with failures).
+
830 Env env{*this, features};
+
831
+
832 env.fund(XRP(1000), gw, alice, bob);
+
833 env.close();
834
-
835 // Clean up this most recent experiment so the rest of the
-
836 // tests work.
-
837 env(pay(bob, gw, USD(20)));
-
838 }
-
839
-
840 // ... so bob cancels alice's remaining check.
-
841 env(check::cancel(bob, chkId3));
-
842 env.close();
-
843 env.require(balance(alice, USD(0)));
-
844 env.require(balance(bob, USD(10)));
-
845 BEAST_EXPECT(checksOnAccount(env, alice).size() == 0);
-
846 BEAST_EXPECT(checksOnAccount(env, bob).size() == 0);
-
847 BEAST_EXPECT(ownerCount(env, alice) == 1);
-
848 BEAST_EXPECT(ownerCount(env, bob) == 1);
-
849 }
-
850 {
-
851 // Simple IOU check cashed with DeliverMin (with failures).
-
852 Env env{*this, features};
-
853
-
854 env.fund(XRP(1000), gw, alice, bob);
-
855 env.close();
-
856
-
857 env(trust(alice, USD(20)));
-
858 env(trust(bob, USD(20)));
+
835 env(trust(alice, USD(20)));
+
836 env(trust(bob, USD(20)));
+
837 env.close();
+
838 env(pay(gw, alice, USD(8)));
+
839 env.close();
+
840
+
841 // alice creates several checks ahead of time.
+
842 uint256 const chkId9{getCheckIndex(alice, env.seq(alice))};
+
843 env(check::create(alice, bob, USD(9)));
+
844 env.close();
+
845 uint256 const chkId8{getCheckIndex(alice, env.seq(alice))};
+
846 env(check::create(alice, bob, USD(8)));
+
847 env.close();
+
848 uint256 const chkId7{getCheckIndex(alice, env.seq(alice))};
+
849 env(check::create(alice, bob, USD(7)));
+
850 env.close();
+
851 uint256 const chkId6{getCheckIndex(alice, env.seq(alice))};
+
852 env(check::create(alice, bob, USD(6)));
+
853 env.close();
+
854
+
855 // bob attempts to cash a check for the amount on the check.
+
856 // Should fail, since alice doesn't have the funds.
+
857 env(check::cash(bob, chkId9, check::DeliverMin(USD(9))),
+
858 ter(tecPATH_PARTIAL));
859 env.close();
-
860 env(pay(gw, alice, USD(8)));
-
861 env.close();
-
862
-
863 // alice creates several checks ahead of time.
-
864 uint256 const chkId9{getCheckIndex(alice, env.seq(alice))};
-
865 env(check::create(alice, bob, USD(9)));
-
866 env.close();
-
867 uint256 const chkId8{getCheckIndex(alice, env.seq(alice))};
-
868 env(check::create(alice, bob, USD(8)));
-
869 env.close();
-
870 uint256 const chkId7{getCheckIndex(alice, env.seq(alice))};
-
871 env(check::create(alice, bob, USD(7)));
-
872 env.close();
-
873 uint256 const chkId6{getCheckIndex(alice, env.seq(alice))};
-
874 env(check::create(alice, bob, USD(6)));
-
875 env.close();
-
876
-
877 // bob attempts to cash a check for the amount on the check.
-
878 // Should fail, since alice doesn't have the funds.
-
879 env(check::cash(bob, chkId9, check::DeliverMin(USD(9))),
-
880 ter(tecPATH_PARTIAL));
-
881 env.close();
-
882
-
883 // bob sets a DeliverMin of 7 and gets all that alice has.
-
884 env(check::cash(bob, chkId9, check::DeliverMin(USD(7))));
-
885 verifyDeliveredAmount(env, USD(8));
-
886 env.require(balance(alice, USD(0)));
-
887 env.require(balance(bob, USD(8)));
-
888 BEAST_EXPECT(checksOnAccount(env, alice).size() == 3);
-
889 BEAST_EXPECT(checksOnAccount(env, bob).size() == 3);
-
890 BEAST_EXPECT(ownerCount(env, alice) == 4);
-
891 BEAST_EXPECT(ownerCount(env, bob) == 1);
-
892
-
893 // bob pays alice USD(7) so he can use another check.
-
894 env(pay(bob, alice, USD(7)));
-
895 env.close();
-
896
-
897 // Using DeliverMin for the SendMax value of the check (and no
-
898 // transfer fees) should work just like setting Amount.
-
899 env(check::cash(bob, chkId7, check::DeliverMin(USD(7))));
-
900 verifyDeliveredAmount(env, USD(7));
-
901 env.require(balance(alice, USD(0)));
-
902 env.require(balance(bob, USD(8)));
-
903 BEAST_EXPECT(checksOnAccount(env, alice).size() == 2);
-
904 BEAST_EXPECT(checksOnAccount(env, bob).size() == 2);
-
905 BEAST_EXPECT(ownerCount(env, alice) == 3);
-
906 BEAST_EXPECT(ownerCount(env, bob) == 1);
-
907
-
908 // bob pays alice USD(8) so he can use the last two checks.
-
909 env(pay(bob, alice, USD(8)));
-
910 env.close();
-
911
-
912 // alice has USD(8). If bob uses the check for USD(6) and uses a
-
913 // DeliverMin of 4, he should get the SendMax value of the check.
-
914 env(check::cash(bob, chkId6, check::DeliverMin(USD(4))));
-
915 verifyDeliveredAmount(env, USD(6));
-
916 env.require(balance(alice, USD(2)));
-
917 env.require(balance(bob, USD(6)));
-
918 BEAST_EXPECT(checksOnAccount(env, alice).size() == 1);
-
919 BEAST_EXPECT(checksOnAccount(env, bob).size() == 1);
-
920 BEAST_EXPECT(ownerCount(env, alice) == 2);
-
921 BEAST_EXPECT(ownerCount(env, bob) == 1);
-
922
-
923 // bob cashes the last remaining check setting a DeliverMin.
-
924 // of exactly alice's remaining USD.
-
925 env(check::cash(bob, chkId8, check::DeliverMin(USD(2))));
-
926 verifyDeliveredAmount(env, USD(2));
-
927 env.require(balance(alice, USD(0)));
-
928 env.require(balance(bob, USD(8)));
-
929 BEAST_EXPECT(checksOnAccount(env, alice).size() == 0);
-
930 BEAST_EXPECT(checksOnAccount(env, bob).size() == 0);
-
931 BEAST_EXPECT(ownerCount(env, alice) == 1);
-
932 BEAST_EXPECT(ownerCount(env, bob) == 1);
-
933 }
-
934 {
-
935 // Examine the effects of the asfRequireAuth flag.
-
936 Env env(*this, features);
-
937
-
938 env.fund(XRP(1000), gw, alice, bob);
-
939 env(fset(gw, asfRequireAuth));
+
860
+
861 // bob sets a DeliverMin of 7 and gets all that alice has.
+
862 env(check::cash(bob, chkId9, check::DeliverMin(USD(7))));
+
863 verifyDeliveredAmount(env, USD(8));
+
864 env.require(balance(alice, USD(0)));
+
865 env.require(balance(bob, USD(8)));
+
866 BEAST_EXPECT(checksOnAccount(env, alice).size() == 3);
+
867 BEAST_EXPECT(checksOnAccount(env, bob).size() == 3);
+
868 BEAST_EXPECT(ownerCount(env, alice) == 4);
+
869 BEAST_EXPECT(ownerCount(env, bob) == 1);
+
870
+
871 // bob pays alice USD(7) so he can use another check.
+
872 env(pay(bob, alice, USD(7)));
+
873 env.close();
+
874
+
875 // Using DeliverMin for the SendMax value of the check (and no
+
876 // transfer fees) should work just like setting Amount.
+
877 env(check::cash(bob, chkId7, check::DeliverMin(USD(7))));
+
878 verifyDeliveredAmount(env, USD(7));
+
879 env.require(balance(alice, USD(0)));
+
880 env.require(balance(bob, USD(8)));
+
881 BEAST_EXPECT(checksOnAccount(env, alice).size() == 2);
+
882 BEAST_EXPECT(checksOnAccount(env, bob).size() == 2);
+
883 BEAST_EXPECT(ownerCount(env, alice) == 3);
+
884 BEAST_EXPECT(ownerCount(env, bob) == 1);
+
885
+
886 // bob pays alice USD(8) so he can use the last two checks.
+
887 env(pay(bob, alice, USD(8)));
+
888 env.close();
+
889
+
890 // alice has USD(8). If bob uses the check for USD(6) and uses a
+
891 // DeliverMin of 4, he should get the SendMax value of the check.
+
892 env(check::cash(bob, chkId6, check::DeliverMin(USD(4))));
+
893 verifyDeliveredAmount(env, USD(6));
+
894 env.require(balance(alice, USD(2)));
+
895 env.require(balance(bob, USD(6)));
+
896 BEAST_EXPECT(checksOnAccount(env, alice).size() == 1);
+
897 BEAST_EXPECT(checksOnAccount(env, bob).size() == 1);
+
898 BEAST_EXPECT(ownerCount(env, alice) == 2);
+
899 BEAST_EXPECT(ownerCount(env, bob) == 1);
+
900
+
901 // bob cashes the last remaining check setting a DeliverMin.
+
902 // of exactly alice's remaining USD.
+
903 env(check::cash(bob, chkId8, check::DeliverMin(USD(2))));
+
904 verifyDeliveredAmount(env, USD(2));
+
905 env.require(balance(alice, USD(0)));
+
906 env.require(balance(bob, USD(8)));
+
907 BEAST_EXPECT(checksOnAccount(env, alice).size() == 0);
+
908 BEAST_EXPECT(checksOnAccount(env, bob).size() == 0);
+
909 BEAST_EXPECT(ownerCount(env, alice) == 1);
+
910 BEAST_EXPECT(ownerCount(env, bob) == 1);
+
911 }
+
912 {
+
913 // Examine the effects of the asfRequireAuth flag.
+
914 Env env(*this, features);
+
915
+
916 env.fund(XRP(1000), gw, alice, bob);
+
917 env(fset(gw, asfRequireAuth));
+
918 env.close();
+
919 env(trust(gw, alice["USD"](100)), txflags(tfSetfAuth));
+
920 env(trust(alice, USD(20)));
+
921 env.close();
+
922 env(pay(gw, alice, USD(8)));
+
923 env.close();
+
924
+
925 // alice writes a check to bob for USD. bob can't cash it
+
926 // because he is not authorized to hold gw["USD"].
+
927 uint256 const chkId{getCheckIndex(alice, env.seq(alice))};
+
928 env(check::create(alice, bob, USD(7)));
+
929 env.close();
+
930
+
931 env(check::cash(bob, chkId, USD(7)), ter(tecNO_AUTH));
+
932 env.close();
+
933
+
934 // Now give bob a trustline for USD. bob still can't cash the
+
935 // check because he is not authorized.
+
936 env(trust(bob, USD(5)));
+
937 env.close();
+
938
+
939 env(check::cash(bob, chkId, USD(7)), ter(tecNO_AUTH));
940 env.close();
-
941 env(trust(gw, alice["USD"](100)), txflags(tfSetfAuth));
-
942 env(trust(alice, USD(20)));
-
943 env.close();
-
944 env(pay(gw, alice, USD(8)));
-
945 env.close();
-
946
-
947 // alice writes a check to bob for USD. bob can't cash it
-
948 // because he is not authorized to hold gw["USD"].
-
949 uint256 const chkId{getCheckIndex(alice, env.seq(alice))};
-
950 env(check::create(alice, bob, USD(7)));
-
951 env.close();
-
952
-
953 env(check::cash(bob, chkId, USD(7)),
-
954 ter(cashCheckMakesTrustLine ? tecNO_AUTH : tecNO_LINE));
-
955 env.close();
-
956
-
957 // Now give bob a trustline for USD. bob still can't cash the
-
958 // check because he is not authorized.
-
959 env(trust(bob, USD(5)));
-
960 env.close();
-
961
-
962 env(check::cash(bob, chkId, USD(7)), ter(tecNO_AUTH));
-
963 env.close();
+
941
+
942 // bob gets authorization to hold gw["USD"].
+
943 env(trust(gw, bob["USD"](1)), txflags(tfSetfAuth));
+
944 env.close();
+
945
+
946 // Two possible outcomes here depending on whether cashing a
+
947 // check can build a trust line:
+
948 // o If it can't build a trust line, then since bob set his
+
949 // limit low, he cashes the check with a DeliverMin and hits
+
950 // his trust limit.
+
951 // o If it can build a trust line, then the check is allowed to
+
952 // exceed the trust limit and bob gets the full transfer.
+
953 env(check::cash(bob, chkId, check::DeliverMin(USD(4))));
+
954 STAmount const bobGot = USD(7);
+
955 verifyDeliveredAmount(env, bobGot);
+
956 env.require(balance(alice, USD(8) - bobGot));
+
957 env.require(balance(bob, bobGot));
+
958
+
959 BEAST_EXPECT(checksOnAccount(env, alice).size() == 0);
+
960 BEAST_EXPECT(checksOnAccount(env, bob).size() == 0);
+
961 BEAST_EXPECT(ownerCount(env, alice) == 1);
+
962 BEAST_EXPECT(ownerCount(env, bob) == 1);
+
963 }
964
-
965 // bob gets authorization to hold gw["USD"].
-
966 env(trust(gw, bob["USD"](1)), txflags(tfSetfAuth));
-
967 env.close();
-
968
-
969 // bob tries to cash the check again but fails because his trust
-
970 // limit is too low.
-
971 if (!cashCheckMakesTrustLine)
-
972 {
-
973 // If cashing a check is allowed to exceed the trust line
-
974 // limit then this returns tesSUCCESS and the check is
-
975 // removed from the ledger which would mess up later tests.
-
976 env(check::cash(bob, chkId, USD(7)), ter(tecPATH_PARTIAL));
-
977 env.close();
-
978 }
-
979
-
980 // Two possible outcomes here depending on whether cashing a
-
981 // check can build a trust line:
-
982 // o If it can't build a trust line, then since bob set his
-
983 // limit low, he cashes the check with a DeliverMin and hits
-
984 // his trust limit.
-
985 // o If it can build a trust line, then the check is allowed to
-
986 // exceed the trust limit and bob gets the full transfer.
-
987 env(check::cash(bob, chkId, check::DeliverMin(USD(4))));
-
988 STAmount const bobGot = cashCheckMakesTrustLine ? USD(7) : USD(5);
-
989 verifyDeliveredAmount(env, bobGot);
-
990 env.require(balance(alice, USD(8) - bobGot));
-
991 env.require(balance(bob, bobGot));
-
992
-
993 BEAST_EXPECT(checksOnAccount(env, alice).size() == 0);
-
994 BEAST_EXPECT(checksOnAccount(env, bob).size() == 0);
-
995 BEAST_EXPECT(ownerCount(env, alice) == 1);
-
996 BEAST_EXPECT(ownerCount(env, bob) == 1);
-
997 }
-
998
-
999 // Use a regular key and also multisign to cash a check.
-
1000 // featureMultiSignReserve changes the reserve on a SignerList, so
-
1001 // check both before and after.
-
1002 for (auto const& testFeatures :
-
1003 {features - featureMultiSignReserve,
-
1004 features | featureMultiSignReserve})
-
1005 {
-
1006 Env env{*this, testFeatures};
+
965 // Use a regular key and also multisign to cash a check.
+
966 // featureMultiSignReserve changes the reserve on a SignerList, so
+
967 // check both before and after.
+
968 for (auto const& testFeatures :
+
969 {features - featureMultiSignReserve,
+
970 features | featureMultiSignReserve})
+
971 {
+
972 Env env{*this, testFeatures};
+
973
+
974 env.fund(XRP(1000), gw, alice, bob);
+
975 env.close();
+
976
+
977 // alice creates her checks ahead of time.
+
978 uint256 const chkId1{getCheckIndex(alice, env.seq(alice))};
+
979 env(check::create(alice, bob, USD(1)));
+
980 env.close();
+
981
+
982 uint256 const chkId2{getCheckIndex(alice, env.seq(alice))};
+
983 env(check::create(alice, bob, USD(2)));
+
984 env.close();
+
985
+
986 env(trust(alice, USD(20)));
+
987 env(trust(bob, USD(20)));
+
988 env.close();
+
989 env(pay(gw, alice, USD(8)));
+
990 env.close();
+
991
+
992 // Give bob a regular key and signers
+
993 Account const bobby{"bobby", KeyType::secp256k1};
+
994 env(regkey(bob, bobby));
+
995 env.close();
+
996
+
997 Account const bogie{"bogie", KeyType::secp256k1};
+
998 Account const demon{"demon", KeyType::ed25519};
+
999 env(signers(bob, 2, {{bogie, 1}, {demon, 1}}), sig(bobby));
+
1000 env.close();
+
1001
+
1002 // If featureMultiSignReserve is enabled then bob's signer list
+
1003 // has an owner count of 1, otherwise it's 4.
+
1004 int const signersCount = {
+
1005 testFeatures[featureMultiSignReserve] ? 1 : 4};
+
1006 BEAST_EXPECT(ownerCount(env, bob) == signersCount + 1);
1007
-
1008 env.fund(XRP(1000), gw, alice, bob);
-
1009 env.close();
-
1010
-
1011 // alice creates her checks ahead of time.
-
1012 uint256 const chkId1{getCheckIndex(alice, env.seq(alice))};
-
1013 env(check::create(alice, bob, USD(1)));
-
1014 env.close();
-
1015
-
1016 uint256 const chkId2{getCheckIndex(alice, env.seq(alice))};
-
1017 env(check::create(alice, bob, USD(2)));
-
1018 env.close();
-
1019
-
1020 env(trust(alice, USD(20)));
-
1021 env(trust(bob, USD(20)));
-
1022 env.close();
-
1023 env(pay(gw, alice, USD(8)));
-
1024 env.close();
-
1025
-
1026 // Give bob a regular key and signers
-
1027 Account const bobby{"bobby", KeyType::secp256k1};
-
1028 env(regkey(bob, bobby));
-
1029 env.close();
-
1030
-
1031 Account const bogie{"bogie", KeyType::secp256k1};
-
1032 Account const demon{"demon", KeyType::ed25519};
-
1033 env(signers(bob, 2, {{bogie, 1}, {demon, 1}}), sig(bobby));
-
1034 env.close();
-
1035
-
1036 // If featureMultiSignReserve is enabled then bob's signer list
-
1037 // has an owner count of 1, otherwise it's 4.
-
1038 int const signersCount = {
-
1039 testFeatures[featureMultiSignReserve] ? 1 : 4};
-
1040 BEAST_EXPECT(ownerCount(env, bob) == signersCount + 1);
-
1041
-
1042 // bob uses his regular key to cash a check.
-
1043 env(check::cash(bob, chkId1, (USD(1))), sig(bobby));
-
1044 env.close();
-
1045 env.require(balance(alice, USD(7)));
-
1046 env.require(balance(bob, USD(1)));
-
1047 BEAST_EXPECT(checksOnAccount(env, alice).size() == 1);
-
1048 BEAST_EXPECT(checksOnAccount(env, bob).size() == 1);
-
1049 BEAST_EXPECT(ownerCount(env, alice) == 2);
-
1050 BEAST_EXPECT(ownerCount(env, bob) == signersCount + 1);
-
1051
-
1052 // bob uses multisigning to cash a check.
-
1053 XRPAmount const baseFeeDrops{env.current()->fees().base};
-
1054 env(check::cash(bob, chkId2, (USD(2))),
-
1055 msig(bogie, demon),
-
1056 fee(3 * baseFeeDrops));
-
1057 env.close();
-
1058 env.require(balance(alice, USD(5)));
-
1059 env.require(balance(bob, USD(3)));
-
1060 BEAST_EXPECT(checksOnAccount(env, alice).size() == 0);
-
1061 BEAST_EXPECT(checksOnAccount(env, bob).size() == 0);
-
1062 BEAST_EXPECT(ownerCount(env, alice) == 1);
-
1063 BEAST_EXPECT(ownerCount(env, bob) == signersCount + 1);
-
1064 }
-
1065 }
+
1008 // bob uses his regular key to cash a check.
+
1009 env(check::cash(bob, chkId1, (USD(1))), sig(bobby));
+
1010 env.close();
+
1011 env.require(balance(alice, USD(7)));
+
1012 env.require(balance(bob, USD(1)));
+
1013 BEAST_EXPECT(checksOnAccount(env, alice).size() == 1);
+
1014 BEAST_EXPECT(checksOnAccount(env, bob).size() == 1);
+
1015 BEAST_EXPECT(ownerCount(env, alice) == 2);
+
1016 BEAST_EXPECT(ownerCount(env, bob) == signersCount + 1);
+
1017
+
1018 // bob uses multisigning to cash a check.
+
1019 XRPAmount const baseFeeDrops{env.current()->fees().base};
+
1020 env(check::cash(bob, chkId2, (USD(2))),
+
1021 msig(bogie, demon),
+
1022 fee(3 * baseFeeDrops));
+
1023 env.close();
+
1024 env.require(balance(alice, USD(5)));
+
1025 env.require(balance(bob, USD(3)));
+
1026 BEAST_EXPECT(checksOnAccount(env, alice).size() == 0);
+
1027 BEAST_EXPECT(checksOnAccount(env, bob).size() == 0);
+
1028 BEAST_EXPECT(ownerCount(env, alice) == 1);
+
1029 BEAST_EXPECT(ownerCount(env, bob) == signersCount + 1);
+
1030 }
+
1031 }
+
1032
+
1033 void
+
+ +
1035 {
+
1036 // Look at behavior when the issuer charges a transfer fee.
+
1037 testcase("Cash with transfer fee");
+
1038
+
1039 using namespace test::jtx;
+
1040
+
1041 Account const gw{"gateway"};
+
1042 Account const alice{"alice"};
+
1043 Account const bob{"bob"};
+
1044 IOU const USD{gw["USD"]};
+
1045
+
1046 Env env{*this, features};
+
1047
+
1048 env.fund(XRP(1000), gw, alice, bob);
+
1049 env.close();
+
1050
+
1051 env(trust(alice, USD(1000)));
+
1052 env(trust(bob, USD(1000)));
+
1053 env.close();
+
1054 env(pay(gw, alice, USD(1000)));
+
1055 env.close();
+
1056
+
1057 // Set gw's transfer rate and see the consequences when cashing a check.
+
1058 env(rate(gw, 1.25));
+
1059 env.close();
+
1060
+
1061 // alice writes a check with a SendMax of USD(125). The most bob
+
1062 // can get is USD(100) because of the transfer rate.
+
1063 uint256 const chkId125{getCheckIndex(alice, env.seq(alice))};
+
1064 env(check::create(alice, bob, USD(125)));
+
1065 env.close();
1066
-
1067 void
-
- -
1069 {
-
1070 // Look at behavior when the issuer charges a transfer fee.
-
1071 testcase("Cash with transfer fee");
-
1072
-
1073 using namespace test::jtx;
-
1074
-
1075 Account const gw{"gateway"};
-
1076 Account const alice{"alice"};
-
1077 Account const bob{"bob"};
-
1078 IOU const USD{gw["USD"]};
-
1079
-
1080 Env env{*this, features};
-
1081
-
1082 env.fund(XRP(1000), gw, alice, bob);
-
1083 env.close();
-
1084
-
1085 env(trust(alice, USD(1000)));
-
1086 env(trust(bob, USD(1000)));
-
1087 env.close();
-
1088 env(pay(gw, alice, USD(1000)));
-
1089 env.close();
-
1090
-
1091 // Set gw's transfer rate and see the consequences when cashing a check.
-
1092 env(rate(gw, 1.25));
-
1093 env.close();
-
1094
-
1095 // alice writes a check with a SendMax of USD(125). The most bob
-
1096 // can get is USD(100) because of the transfer rate.
-
1097 uint256 const chkId125{getCheckIndex(alice, env.seq(alice))};
-
1098 env(check::create(alice, bob, USD(125)));
-
1099 env.close();
-
1100
-
1101 // alice writes another check that won't get cashed until the transfer
-
1102 // rate changes so we can see the rate applies when the check is
-
1103 // cashed, not when it is created.
-
1104 uint256 const chkId120{getCheckIndex(alice, env.seq(alice))};
-
1105 env(check::create(alice, bob, USD(120)));
-
1106 env.close();
-
1107
-
1108 // bob attempts to cash the check for face value. Should fail.
-
1109 env(check::cash(bob, chkId125, USD(125)), ter(tecPATH_PARTIAL));
-
1110 env.close();
-
1111 env(check::cash(bob, chkId125, check::DeliverMin(USD(101))),
-
1112 ter(tecPATH_PARTIAL));
-
1113 env.close();
-
1114
-
1115 // bob decides that he'll accept anything USD(75) or up.
-
1116 // He gets USD(100).
-
1117 env(check::cash(bob, chkId125, check::DeliverMin(USD(75))));
-
1118 verifyDeliveredAmount(env, USD(100));
-
1119 env.require(balance(alice, USD(1000 - 125)));
-
1120 env.require(balance(bob, USD(0 + 100)));
-
1121 BEAST_EXPECT(checksOnAccount(env, alice).size() == 1);
-
1122 BEAST_EXPECT(checksOnAccount(env, bob).size() == 1);
-
1123
-
1124 // Adjust gw's rate...
-
1125 env(rate(gw, 1.2));
+
1067 // alice writes another check that won't get cashed until the transfer
+
1068 // rate changes so we can see the rate applies when the check is
+
1069 // cashed, not when it is created.
+
1070 uint256 const chkId120{getCheckIndex(alice, env.seq(alice))};
+
1071 env(check::create(alice, bob, USD(120)));
+
1072 env.close();
+
1073
+
1074 // bob attempts to cash the check for face value. Should fail.
+
1075 env(check::cash(bob, chkId125, USD(125)), ter(tecPATH_PARTIAL));
+
1076 env.close();
+
1077 env(check::cash(bob, chkId125, check::DeliverMin(USD(101))),
+
1078 ter(tecPATH_PARTIAL));
+
1079 env.close();
+
1080
+
1081 // bob decides that he'll accept anything USD(75) or up.
+
1082 // He gets USD(100).
+
1083 env(check::cash(bob, chkId125, check::DeliverMin(USD(75))));
+
1084 verifyDeliveredAmount(env, USD(100));
+
1085 env.require(balance(alice, USD(1000 - 125)));
+
1086 env.require(balance(bob, USD(0 + 100)));
+
1087 BEAST_EXPECT(checksOnAccount(env, alice).size() == 1);
+
1088 BEAST_EXPECT(checksOnAccount(env, bob).size() == 1);
+
1089
+
1090 // Adjust gw's rate...
+
1091 env(rate(gw, 1.2));
+
1092 env.close();
+
1093
+
1094 // bob cashes the second check for less than the face value. The new
+
1095 // rate applies to the actual value transferred.
+
1096 env(check::cash(bob, chkId120, USD(50)));
+
1097 env.close();
+
1098 env.require(balance(alice, USD(1000 - 125 - 60)));
+
1099 env.require(balance(bob, USD(0 + 100 + 50)));
+
1100 BEAST_EXPECT(checksOnAccount(env, alice).size() == 0);
+
1101 BEAST_EXPECT(checksOnAccount(env, bob).size() == 0);
+
1102 }
+
+
1103
+
1104 void
+
+ +
1106 {
+
1107 // Look at the eight possible cases for Quality In/Out.
+
1108 testcase("Cash quality");
+
1109
+
1110 using namespace test::jtx;
+
1111
+
1112 Account const gw{"gateway"};
+
1113 Account const alice{"alice"};
+
1114 Account const bob{"bob"};
+
1115 IOU const USD{gw["USD"]};
+
1116
+
1117 Env env{*this, features};
+
1118
+
1119 env.fund(XRP(1000), gw, alice, bob);
+
1120 env.close();
+
1121
+
1122 env(trust(alice, USD(1000)));
+
1123 env(trust(bob, USD(1000)));
+
1124 env.close();
+
1125 env(pay(gw, alice, USD(1000)));
1126 env.close();
1127
-
1128 // bob cashes the second check for less than the face value. The new
-
1129 // rate applies to the actual value transferred.
-
1130 env(check::cash(bob, chkId120, USD(50)));
-
1131 env.close();
-
1132 env.require(balance(alice, USD(1000 - 125 - 60)));
-
1133 env.require(balance(bob, USD(0 + 100 + 50)));
-
1134 BEAST_EXPECT(checksOnAccount(env, alice).size() == 0);
-
1135 BEAST_EXPECT(checksOnAccount(env, bob).size() == 0);
-
1136 }
-
-
1137
-
1138 void
-
- -
1140 {
-
1141 // Look at the eight possible cases for Quality In/Out.
-
1142 testcase("Cash quality");
-
1143
-
1144 using namespace test::jtx;
-
1145
-
1146 Account const gw{"gateway"};
-
1147 Account const alice{"alice"};
-
1148 Account const bob{"bob"};
-
1149 IOU const USD{gw["USD"]};
-
1150
-
1151 Env env{*this, features};
-
1152
-
1153 env.fund(XRP(1000), gw, alice, bob);
-
1154 env.close();
-
1155
-
1156 env(trust(alice, USD(1000)));
-
1157 env(trust(bob, USD(1000)));
-
1158 env.close();
-
1159 env(pay(gw, alice, USD(1000)));
-
1160 env.close();
-
1161
-
1162 //
-
1163 // Quality effects on transfers between two non-issuers.
-
1164 //
-
1165
-
1166 // Provide lambdas that return a qualityInPercent and qualityOutPercent.
-
1167 auto qIn = [](double percent) { return qualityInPercent(percent); };
-
1168 auto qOut = [](double percent) { return qualityOutPercent(percent); };
-
1169
-
1170 // There are two test lambdas: one for a Payment and one for a Check.
-
1171 // This shows whether a Payment and a Check behave the same.
-
1172 auto testNonIssuerQPay = [&env, &alice, &bob, &USD](
-
1173 Account const& truster,
-
1174 IOU const& iou,
-
1175 auto const& inOrOut,
-
1176 double pct,
-
1177 double amount) {
-
1178 // Capture bob's and alice's balances so we can test at the end.
-
1179 STAmount const aliceStart{env.balance(alice, USD.issue()).value()};
-
1180 STAmount const bobStart{env.balance(bob, USD.issue()).value()};
-
1181
-
1182 // Set the modified quality.
-
1183 env(trust(truster, iou(1000)), inOrOut(pct));
-
1184 env.close();
+
1128 //
+
1129 // Quality effects on transfers between two non-issuers.
+
1130 //
+
1131
+
1132 // Provide lambdas that return a qualityInPercent and qualityOutPercent.
+
1133 auto qIn = [](double percent) { return qualityInPercent(percent); };
+
1134 auto qOut = [](double percent) { return qualityOutPercent(percent); };
+
1135
+
1136 // There are two test lambdas: one for a Payment and one for a Check.
+
1137 // This shows whether a Payment and a Check behave the same.
+
1138 auto testNonIssuerQPay = [&env, &alice, &bob, &USD](
+
1139 Account const& truster,
+
1140 IOU const& iou,
+
1141 auto const& inOrOut,
+
1142 double pct,
+
1143 double amount) {
+
1144 // Capture bob's and alice's balances so we can test at the end.
+
1145 STAmount const aliceStart{env.balance(alice, USD.issue()).value()};
+
1146 STAmount const bobStart{env.balance(bob, USD.issue()).value()};
+
1147
+
1148 // Set the modified quality.
+
1149 env(trust(truster, iou(1000)), inOrOut(pct));
+
1150 env.close();
+
1151
+
1152 env(pay(alice, bob, USD(amount)), sendmax(USD(10)));
+
1153 env.close();
+
1154 env.require(balance(alice, aliceStart - USD(10)));
+
1155 env.require(balance(bob, bobStart + USD(10)));
+
1156
+
1157 // Return the quality to the unmodified state so it doesn't
+
1158 // interfere with upcoming tests.
+
1159 env(trust(truster, iou(1000)), inOrOut(0));
+
1160 env.close();
+
1161 };
+
1162
+
1163 auto testNonIssuerQCheck = [&env, &alice, &bob, &USD](
+
1164 Account const& truster,
+
1165 IOU const& iou,
+
1166 auto const& inOrOut,
+
1167 double pct,
+
1168 double amount) {
+
1169 // Capture bob's and alice's balances so we can test at the end.
+
1170 STAmount const aliceStart{env.balance(alice, USD.issue()).value()};
+
1171 STAmount const bobStart{env.balance(bob, USD.issue()).value()};
+
1172
+
1173 // Set the modified quality.
+
1174 env(trust(truster, iou(1000)), inOrOut(pct));
+
1175 env.close();
+
1176
+
1177 uint256 const chkId = getCheckIndex(alice, env.seq(alice));
+
1178 env(check::create(alice, bob, USD(10)));
+
1179 env.close();
+
1180
+
1181 env(check::cash(bob, chkId, USD(amount)));
+
1182 env.close();
+
1183 env.require(balance(alice, aliceStart - USD(10)));
+
1184 env.require(balance(bob, bobStart + USD(10)));
1185
-
1186 env(pay(alice, bob, USD(amount)), sendmax(USD(10)));
-
1187 env.close();
-
1188 env.require(balance(alice, aliceStart - USD(10)));
-
1189 env.require(balance(bob, bobStart + USD(10)));
-
1190
-
1191 // Return the quality to the unmodified state so it doesn't
-
1192 // interfere with upcoming tests.
-
1193 env(trust(truster, iou(1000)), inOrOut(0));
-
1194 env.close();
-
1195 };
-
1196
-
1197 auto testNonIssuerQCheck = [&env, &alice, &bob, &USD](
-
1198 Account const& truster,
-
1199 IOU const& iou,
-
1200 auto const& inOrOut,
-
1201 double pct,
-
1202 double amount) {
-
1203 // Capture bob's and alice's balances so we can test at the end.
-
1204 STAmount const aliceStart{env.balance(alice, USD.issue()).value()};
-
1205 STAmount const bobStart{env.balance(bob, USD.issue()).value()};
-
1206
-
1207 // Set the modified quality.
-
1208 env(trust(truster, iou(1000)), inOrOut(pct));
-
1209 env.close();
-
1210
-
1211 uint256 const chkId = getCheckIndex(alice, env.seq(alice));
-
1212 env(check::create(alice, bob, USD(10)));
-
1213 env.close();
+
1186 // Return the quality to the unmodified state so it doesn't
+
1187 // interfere with upcoming tests.
+
1188 env(trust(truster, iou(1000)), inOrOut(0));
+
1189 env.close();
+
1190 };
+
1191
+
1192 // pct amount
+
1193 testNonIssuerQPay(alice, gw["USD"], qIn, 50, 10);
+
1194 testNonIssuerQCheck(alice, gw["USD"], qIn, 50, 10);
+
1195
+
1196 // This is the only case where the Quality affects the outcome.
+
1197 testNonIssuerQPay(bob, gw["USD"], qIn, 50, 5);
+
1198 testNonIssuerQCheck(bob, gw["USD"], qIn, 50, 5);
+
1199
+
1200 testNonIssuerQPay(gw, alice["USD"], qIn, 50, 10);
+
1201 testNonIssuerQCheck(gw, alice["USD"], qIn, 50, 10);
+
1202
+
1203 testNonIssuerQPay(gw, bob["USD"], qIn, 50, 10);
+
1204 testNonIssuerQCheck(gw, bob["USD"], qIn, 50, 10);
+
1205
+
1206 testNonIssuerQPay(alice, gw["USD"], qOut, 200, 10);
+
1207 testNonIssuerQCheck(alice, gw["USD"], qOut, 200, 10);
+
1208
+
1209 testNonIssuerQPay(bob, gw["USD"], qOut, 200, 10);
+
1210 testNonIssuerQCheck(bob, gw["USD"], qOut, 200, 10);
+
1211
+
1212 testNonIssuerQPay(gw, alice["USD"], qOut, 200, 10);
+
1213 testNonIssuerQCheck(gw, alice["USD"], qOut, 200, 10);
1214
-
1215 env(check::cash(bob, chkId, USD(amount)));
-
1216 env.close();
-
1217 env.require(balance(alice, aliceStart - USD(10)));
-
1218 env.require(balance(bob, bobStart + USD(10)));
-
1219
-
1220 // Return the quality to the unmodified state so it doesn't
-
1221 // interfere with upcoming tests.
-
1222 env(trust(truster, iou(1000)), inOrOut(0));
-
1223 env.close();
-
1224 };
-
1225
-
1226 // pct amount
-
1227 testNonIssuerQPay(alice, gw["USD"], qIn, 50, 10);
-
1228 testNonIssuerQCheck(alice, gw["USD"], qIn, 50, 10);
-
1229
-
1230 // This is the only case where the Quality affects the outcome.
-
1231 testNonIssuerQPay(bob, gw["USD"], qIn, 50, 5);
-
1232 testNonIssuerQCheck(bob, gw["USD"], qIn, 50, 5);
-
1233
-
1234 testNonIssuerQPay(gw, alice["USD"], qIn, 50, 10);
-
1235 testNonIssuerQCheck(gw, alice["USD"], qIn, 50, 10);
-
1236
-
1237 testNonIssuerQPay(gw, bob["USD"], qIn, 50, 10);
-
1238 testNonIssuerQCheck(gw, bob["USD"], qIn, 50, 10);
+
1215 testNonIssuerQPay(gw, bob["USD"], qOut, 200, 10);
+
1216 testNonIssuerQCheck(gw, bob["USD"], qOut, 200, 10);
+
1217
+
1218 //
+
1219 // Quality effects on transfers between an issuer and a non-issuer.
+
1220 //
+
1221
+
1222 // There are two test lambdas for the same reason as before.
+
1223 auto testIssuerQPay = [&env, &gw, &alice, &USD](
+
1224 Account const& truster,
+
1225 IOU const& iou,
+
1226 auto const& inOrOut,
+
1227 double pct,
+
1228 double amt1,
+
1229 double max1,
+
1230 double amt2,
+
1231 double max2) {
+
1232 // Capture alice's balance so we can test at the end. It doesn't
+
1233 // make any sense to look at the balance of a gateway.
+
1234 STAmount const aliceStart{env.balance(alice, USD.issue()).value()};
+
1235
+
1236 // Set the modified quality.
+
1237 env(trust(truster, iou(1000)), inOrOut(pct));
+
1238 env.close();
1239
-
1240 testNonIssuerQPay(alice, gw["USD"], qOut, 200, 10);
-
1241 testNonIssuerQCheck(alice, gw["USD"], qOut, 200, 10);
-
1242
-
1243 testNonIssuerQPay(bob, gw["USD"], qOut, 200, 10);
-
1244 testNonIssuerQCheck(bob, gw["USD"], qOut, 200, 10);
-
1245
-
1246 testNonIssuerQPay(gw, alice["USD"], qOut, 200, 10);
-
1247 testNonIssuerQCheck(gw, alice["USD"], qOut, 200, 10);
-
1248
-
1249 testNonIssuerQPay(gw, bob["USD"], qOut, 200, 10);
-
1250 testNonIssuerQCheck(gw, bob["USD"], qOut, 200, 10);
-
1251
-
1252 //
-
1253 // Quality effects on transfers between an issuer and a non-issuer.
-
1254 //
+
1240 // alice pays gw.
+
1241 env(pay(alice, gw, USD(amt1)), sendmax(USD(max1)));
+
1242 env.close();
+
1243 env.require(balance(alice, aliceStart - USD(10)));
+
1244
+
1245 // gw pays alice.
+
1246 env(pay(gw, alice, USD(amt2)), sendmax(USD(max2)));
+
1247 env.close();
+
1248 env.require(balance(alice, aliceStart));
+
1249
+
1250 // Return the quality to the unmodified state so it doesn't
+
1251 // interfere with upcoming tests.
+
1252 env(trust(truster, iou(1000)), inOrOut(0));
+
1253 env.close();
+
1254 };
1255
-
1256 // There are two test lambdas for the same reason as before.
-
1257 auto testIssuerQPay = [&env, &gw, &alice, &USD](
-
1258 Account const& truster,
-
1259 IOU const& iou,
-
1260 auto const& inOrOut,
-
1261 double pct,
-
1262 double amt1,
-
1263 double max1,
-
1264 double amt2,
-
1265 double max2) {
-
1266 // Capture alice's balance so we can test at the end. It doesn't
-
1267 // make any sense to look at the balance of a gateway.
-
1268 STAmount const aliceStart{env.balance(alice, USD.issue()).value()};
-
1269
-
1270 // Set the modified quality.
-
1271 env(trust(truster, iou(1000)), inOrOut(pct));
-
1272 env.close();
-
1273
-
1274 // alice pays gw.
-
1275 env(pay(alice, gw, USD(amt1)), sendmax(USD(max1)));
+
1256 auto testIssuerQCheck = [&env, &gw, &alice, &USD](
+
1257 Account const& truster,
+
1258 IOU const& iou,
+
1259 auto const& inOrOut,
+
1260 double pct,
+
1261 double amt1,
+
1262 double max1,
+
1263 double amt2,
+
1264 double max2) {
+
1265 // Capture alice's balance so we can test at the end. It doesn't
+
1266 // make any sense to look at the balance of the issuer.
+
1267 STAmount const aliceStart{env.balance(alice, USD.issue()).value()};
+
1268
+
1269 // Set the modified quality.
+
1270 env(trust(truster, iou(1000)), inOrOut(pct));
+
1271 env.close();
+
1272
+
1273 // alice writes check to gw. gw cashes.
+
1274 uint256 const chkAliceId{getCheckIndex(alice, env.seq(alice))};
+
1275 env(check::create(alice, gw, USD(max1)));
1276 env.close();
-
1277 env.require(balance(alice, aliceStart - USD(10)));
-
1278
-
1279 // gw pays alice.
-
1280 env(pay(gw, alice, USD(amt2)), sendmax(USD(max2)));
-
1281 env.close();
-
1282 env.require(balance(alice, aliceStart));
-
1283
-
1284 // Return the quality to the unmodified state so it doesn't
-
1285 // interfere with upcoming tests.
-
1286 env(trust(truster, iou(1000)), inOrOut(0));
-
1287 env.close();
-
1288 };
-
1289
-
1290 auto testIssuerQCheck = [&env, &gw, &alice, &USD](
-
1291 Account const& truster,
-
1292 IOU const& iou,
-
1293 auto const& inOrOut,
-
1294 double pct,
-
1295 double amt1,
-
1296 double max1,
-
1297 double amt2,
-
1298 double max2) {
-
1299 // Capture alice's balance so we can test at the end. It doesn't
-
1300 // make any sense to look at the balance of the issuer.
-
1301 STAmount const aliceStart{env.balance(alice, USD.issue()).value()};
-
1302
-
1303 // Set the modified quality.
-
1304 env(trust(truster, iou(1000)), inOrOut(pct));
-
1305 env.close();
-
1306
-
1307 // alice writes check to gw. gw cashes.
-
1308 uint256 const chkAliceId{getCheckIndex(alice, env.seq(alice))};
-
1309 env(check::create(alice, gw, USD(max1)));
-
1310 env.close();
+
1277
+
1278 env(check::cash(gw, chkAliceId, USD(amt1)));
+
1279 env.close();
+
1280 env.require(balance(alice, aliceStart - USD(10)));
+
1281
+
1282 // gw writes check to alice. alice cashes.
+
1283 uint256 const chkGwId{getCheckIndex(gw, env.seq(gw))};
+
1284 env(check::create(gw, alice, USD(max2)));
+
1285 env.close();
+
1286
+
1287 env(check::cash(alice, chkGwId, USD(amt2)));
+
1288 env.close();
+
1289 env.require(balance(alice, aliceStart));
+
1290
+
1291 // Return the quality to the unmodified state so it doesn't
+
1292 // interfere with upcoming tests.
+
1293 env(trust(truster, iou(1000)), inOrOut(0));
+
1294 env.close();
+
1295 };
+
1296
+
1297 // The first case is the only one where the quality affects the outcome.
+
1298 // pct amt1 max1 amt2 max2
+
1299 testIssuerQPay(alice, gw["USD"], qIn, 50, 10, 10, 5, 10);
+
1300 testIssuerQCheck(alice, gw["USD"], qIn, 50, 10, 10, 5, 10);
+
1301
+
1302 testIssuerQPay(gw, alice["USD"], qIn, 50, 10, 10, 10, 10);
+
1303 testIssuerQCheck(gw, alice["USD"], qIn, 50, 10, 10, 10, 10);
+
1304
+
1305 testIssuerQPay(alice, gw["USD"], qOut, 200, 10, 10, 10, 10);
+
1306 testIssuerQCheck(alice, gw["USD"], qOut, 200, 10, 10, 10, 10);
+
1307
+
1308 testIssuerQPay(gw, alice["USD"], qOut, 200, 10, 10, 10, 10);
+
1309 testIssuerQCheck(gw, alice["USD"], qOut, 200, 10, 10, 10, 10);
+
1310 }
+
1311
-
1312 env(check::cash(gw, chkAliceId, USD(amt1)));
-
1313 env.close();
-
1314 env.require(balance(alice, aliceStart - USD(10)));
-
1315
-
1316 // gw writes check to alice. alice cashes.
-
1317 uint256 const chkGwId{getCheckIndex(gw, env.seq(gw))};
-
1318 env(check::create(gw, alice, USD(max2)));
-
1319 env.close();
-
1320
-
1321 env(check::cash(alice, chkGwId, USD(amt2)));
-
1322 env.close();
-
1323 env.require(balance(alice, aliceStart));
-
1324
-
1325 // Return the quality to the unmodified state so it doesn't
-
1326 // interfere with upcoming tests.
-
1327 env(trust(truster, iou(1000)), inOrOut(0));
-
1328 env.close();
-
1329 };
+
1312 void
+
+ +
1314 {
+
1315 // Explore many of the ways to fail at cashing a check.
+
1316 testcase("Cash invalid");
+
1317
+
1318 using namespace test::jtx;
+
1319
+
1320 Account const gw{"gateway"};
+
1321 Account const alice{"alice"};
+
1322 Account const bob{"bob"};
+
1323 Account const zoe{"zoe"};
+
1324 IOU const USD{gw["USD"]};
+
1325
+
1326 Env env(*this, features);
+
1327
+
1328 env.fund(XRP(1000), gw, alice, bob, zoe);
+
1329 env.close();
1330
-
1331 // The first case is the only one where the quality affects the outcome.
-
1332 // pct amt1 max1 amt2 max2
-
1333 testIssuerQPay(alice, gw["USD"], qIn, 50, 10, 10, 5, 10);
-
1334 testIssuerQCheck(alice, gw["USD"], qIn, 50, 10, 10, 5, 10);
-
1335
-
1336 testIssuerQPay(gw, alice["USD"], qIn, 50, 10, 10, 10, 10);
-
1337 testIssuerQCheck(gw, alice["USD"], qIn, 50, 10, 10, 10, 10);
-
1338
-
1339 testIssuerQPay(alice, gw["USD"], qOut, 200, 10, 10, 10, 10);
-
1340 testIssuerQCheck(alice, gw["USD"], qOut, 200, 10, 10, 10, 10);
-
1341
-
1342 testIssuerQPay(gw, alice["USD"], qOut, 200, 10, 10, 10, 10);
-
1343 testIssuerQCheck(gw, alice["USD"], qOut, 200, 10, 10, 10, 10);
-
1344 }
-
-
1345
-
1346 void
-
- -
1348 {
-
1349 // Explore many of the ways to fail at cashing a check.
-
1350 testcase("Cash invalid");
-
1351
-
1352 using namespace test::jtx;
-
1353
-
1354 Account const gw{"gateway"};
-
1355 Account const alice{"alice"};
-
1356 Account const bob{"bob"};
-
1357 Account const zoe{"zoe"};
-
1358 IOU const USD{gw["USD"]};
-
1359
-
1360 Env env(*this, features);
+
1331 // Now set up alice's trustline.
+
1332 env(trust(alice, USD(20)));
+
1333 env.close();
+
1334 env(pay(gw, alice, USD(20)));
+
1335 env.close();
+
1336
+
1337 // Now set up bob's trustline.
+
1338 env(trust(bob, USD(20)));
+
1339 env.close();
+
1340
+
1341 // bob tries to cash a non-existent check from alice.
+
1342 {
+
1343 uint256 const chkId{getCheckIndex(alice, env.seq(alice))};
+
1344 env(check::cash(bob, chkId, USD(20)), ter(tecNO_ENTRY));
+
1345 env.close();
+
1346 }
+
1347
+
1348 // alice creates her checks ahead of time.
+
1349 uint256 const chkIdU{getCheckIndex(alice, env.seq(alice))};
+
1350 env(check::create(alice, bob, USD(20)));
+
1351 env.close();
+
1352
+
1353 uint256 const chkIdX{getCheckIndex(alice, env.seq(alice))};
+
1354 env(check::create(alice, bob, XRP(10)));
+
1355 env.close();
+
1356
+
1357 using namespace std::chrono_literals;
+
1358 uint256 const chkIdExp{getCheckIndex(alice, env.seq(alice))};
+
1359 env(check::create(alice, bob, XRP(10)), expiration(env.now() + 1s));
+
1360 env.close();
1361
-
1362 env.fund(XRP(1000), gw, alice, bob, zoe);
-
1363 env.close();
-
1364
-
1365 // Now set up alice's trustline.
-
1366 env(trust(alice, USD(20)));
-
1367 env.close();
-
1368 env(pay(gw, alice, USD(20)));
-
1369 env.close();
-
1370
-
1371 // Before bob gets a trustline, have him try to cash a check.
-
1372 // Should fail.
-
1373 {
-
1374 uint256 const chkId{getCheckIndex(alice, env.seq(alice))};
-
1375 env(check::create(alice, bob, USD(20)));
-
1376 env.close();
+
1362 uint256 const chkIdFroz1{getCheckIndex(alice, env.seq(alice))};
+
1363 env(check::create(alice, bob, USD(1)));
+
1364 env.close();
+
1365
+
1366 uint256 const chkIdFroz2{getCheckIndex(alice, env.seq(alice))};
+
1367 env(check::create(alice, bob, USD(2)));
+
1368 env.close();
+
1369
+
1370 uint256 const chkIdFroz3{getCheckIndex(alice, env.seq(alice))};
+
1371 env(check::create(alice, bob, USD(3)));
+
1372 env.close();
+
1373
+
1374 uint256 const chkIdFroz4{getCheckIndex(alice, env.seq(alice))};
+
1375 env(check::create(alice, bob, USD(4)));
+
1376 env.close();
1377
-
1378 if (!features[featureCheckCashMakesTrustLine])
-
1379 {
-
1380 // If cashing a check automatically creates a trustline then
-
1381 // this returns tesSUCCESS and the check is removed from the
-
1382 // ledger which would mess up later tests.
-
1383 env(check::cash(bob, chkId, USD(20)), ter(tecNO_LINE));
-
1384 env.close();
-
1385 }
-
1386 }
-
1387
-
1388 // Now set up bob's trustline.
-
1389 env(trust(bob, USD(20)));
-
1390 env.close();
-
1391
-
1392 // bob tries to cash a non-existent check from alice.
-
1393 {
-
1394 uint256 const chkId{getCheckIndex(alice, env.seq(alice))};
-
1395 env(check::cash(bob, chkId, USD(20)), ter(tecNO_ENTRY));
-
1396 env.close();
-
1397 }
-
1398
-
1399 // alice creates her checks ahead of time.
-
1400 uint256 const chkIdU{getCheckIndex(alice, env.seq(alice))};
-
1401 env(check::create(alice, bob, USD(20)));
-
1402 env.close();
-
1403
-
1404 uint256 const chkIdX{getCheckIndex(alice, env.seq(alice))};
-
1405 env(check::create(alice, bob, XRP(10)));
-
1406 env.close();
-
1407
-
1408 using namespace std::chrono_literals;
-
1409 uint256 const chkIdExp{getCheckIndex(alice, env.seq(alice))};
-
1410 env(check::create(alice, bob, XRP(10)), expiration(env.now() + 1s));
-
1411 env.close();
-
1412
-
1413 uint256 const chkIdFroz1{getCheckIndex(alice, env.seq(alice))};
-
1414 env(check::create(alice, bob, USD(1)));
-
1415 env.close();
-
1416
-
1417 uint256 const chkIdFroz2{getCheckIndex(alice, env.seq(alice))};
-
1418 env(check::create(alice, bob, USD(2)));
-
1419 env.close();
-
1420
-
1421 uint256 const chkIdFroz3{getCheckIndex(alice, env.seq(alice))};
-
1422 env(check::create(alice, bob, USD(3)));
-
1423 env.close();
-
1424
-
1425 uint256 const chkIdFroz4{getCheckIndex(alice, env.seq(alice))};
-
1426 env(check::create(alice, bob, USD(4)));
-
1427 env.close();
-
1428
-
1429 uint256 const chkIdNoDest1{getCheckIndex(alice, env.seq(alice))};
-
1430 env(check::create(alice, bob, USD(1)));
-
1431 env.close();
-
1432
-
1433 uint256 const chkIdHasDest2{getCheckIndex(alice, env.seq(alice))};
-
1434 env(check::create(alice, bob, USD(2)), dest_tag(7));
-
1435 env.close();
+
1378 uint256 const chkIdNoDest1{getCheckIndex(alice, env.seq(alice))};
+
1379 env(check::create(alice, bob, USD(1)));
+
1380 env.close();
+
1381
+
1382 uint256 const chkIdHasDest2{getCheckIndex(alice, env.seq(alice))};
+
1383 env(check::create(alice, bob, USD(2)), dest_tag(7));
+
1384 env.close();
+
1385
+
1386 // Same set of failing cases for both IOU and XRP check cashing.
+
1387 auto failingCases = [&env, &gw, &alice, &bob](
+
1388 uint256 const& chkId, STAmount const& amount) {
+
1389 // Bad fee.
+
1390 env(check::cash(bob, chkId, amount),
+
1391 fee(drops(-10)),
+
1392 ter(temBAD_FEE));
+
1393 env.close();
+
1394
+
1395 // Bad flags.
+
1396 env(check::cash(bob, chkId, amount),
+
1397 txflags(tfImmediateOrCancel),
+
1398 ter(temINVALID_FLAG));
+
1399 env.close();
+
1400
+
1401 // Missing both Amount and DeliverMin.
+
1402 {
+
1403 Json::Value tx{check::cash(bob, chkId, amount)};
+
1404 tx.removeMember(sfAmount.jsonName);
+
1405 env(tx, ter(temMALFORMED));
+
1406 env.close();
+
1407 }
+
1408 // Both Amount and DeliverMin present.
+
1409 {
+
1410 Json::Value tx{check::cash(bob, chkId, amount)};
+
1411 tx[sfDeliverMin.jsonName] = amount.getJson(JsonOptions::none);
+
1412 env(tx, ter(temMALFORMED));
+
1413 env.close();
+
1414 }
+
1415
+
1416 // Negative or zero amount.
+
1417 {
+
1418 STAmount neg{amount};
+
1419 neg.negate();
+
1420 env(check::cash(bob, chkId, neg), ter(temBAD_AMOUNT));
+
1421 env.close();
+
1422 env(check::cash(bob, chkId, amount.zeroed()),
+
1423 ter(temBAD_AMOUNT));
+
1424 env.close();
+
1425 }
+
1426
+
1427 // Bad currency.
+
1428 if (!amount.native())
+
1429 {
+
1430 Issue const badIssue{badCurrency(), amount.getIssuer()};
+
1431 STAmount badAmount{amount};
+
1432 badAmount.setIssue(Issue{badCurrency(), amount.getIssuer()});
+
1433 env(check::cash(bob, chkId, badAmount), ter(temBAD_CURRENCY));
+
1434 env.close();
+
1435 }
1436
-
1437 // Same set of failing cases for both IOU and XRP check cashing.
-
1438 auto failingCases = [&env, &gw, &alice, &bob](
-
1439 uint256 const& chkId, STAmount const& amount) {
-
1440 // Bad fee.
-
1441 env(check::cash(bob, chkId, amount),
-
1442 fee(drops(-10)),
-
1443 ter(temBAD_FEE));
-
1444 env.close();
-
1445
-
1446 // Bad flags.
-
1447 env(check::cash(bob, chkId, amount),
-
1448 txflags(tfImmediateOrCancel),
-
1449 ter(temINVALID_FLAG));
-
1450 env.close();
+
1437 // Not destination cashing check.
+
1438 env(check::cash(alice, chkId, amount), ter(tecNO_PERMISSION));
+
1439 env.close();
+
1440 env(check::cash(gw, chkId, amount), ter(tecNO_PERMISSION));
+
1441 env.close();
+
1442
+
1443 // Currency mismatch.
+
1444 {
+
1445 IOU const wrongCurrency{gw["EUR"]};
+
1446 STAmount badAmount{amount};
+
1447 badAmount.setIssue(wrongCurrency.issue());
+
1448 env(check::cash(bob, chkId, badAmount), ter(temMALFORMED));
+
1449 env.close();
+
1450 }
1451
-
1452 // Missing both Amount and DeliverMin.
+
1452 // Issuer mismatch.
1453 {
-
1454 Json::Value tx{check::cash(bob, chkId, amount)};
-
1455 tx.removeMember(sfAmount.jsonName);
-
1456 env(tx, ter(temMALFORMED));
-
1457 env.close();
-
1458 }
-
1459 // Both Amount and DeliverMin present.
-
1460 {
-
1461 Json::Value tx{check::cash(bob, chkId, amount)};
-
1462 tx[sfDeliverMin.jsonName] = amount.getJson(JsonOptions::none);
-
1463 env(tx, ter(temMALFORMED));
-
1464 env.close();
-
1465 }
-
1466
-
1467 // Negative or zero amount.
-
1468 {
-
1469 STAmount neg{amount};
-
1470 neg.negate();
-
1471 env(check::cash(bob, chkId, neg), ter(temBAD_AMOUNT));
-
1472 env.close();
-
1473 env(check::cash(bob, chkId, amount.zeroed()),
-
1474 ter(temBAD_AMOUNT));
-
1475 env.close();
-
1476 }
-
1477
-
1478 // Bad currency.
-
1479 if (!amount.native())
-
1480 {
-
1481 Issue const badIssue{badCurrency(), amount.getIssuer()};
-
1482 STAmount badAmount{amount};
-
1483 badAmount.setIssue(Issue{badCurrency(), amount.getIssuer()});
-
1484 env(check::cash(bob, chkId, badAmount), ter(temBAD_CURRENCY));
-
1485 env.close();
-
1486 }
+
1454 IOU const wrongIssuer{alice["USD"]};
+
1455 STAmount badAmount{amount};
+
1456 badAmount.setIssue(wrongIssuer.issue());
+
1457 env(check::cash(bob, chkId, badAmount), ter(temMALFORMED));
+
1458 env.close();
+
1459 }
+
1460
+
1461 // Amount bigger than SendMax.
+
1462 env(check::cash(bob, chkId, amount + amount), ter(tecPATH_PARTIAL));
+
1463 env.close();
+
1464
+
1465 // DeliverMin bigger than SendMax.
+
1466 env(check::cash(bob, chkId, check::DeliverMin(amount + amount)),
+
1467 ter(tecPATH_PARTIAL));
+
1468 env.close();
+
1469 };
+
1470
+
1471 failingCases(chkIdX, XRP(10));
+
1472 failingCases(chkIdU, USD(20));
+
1473
+
1474 // Verify that those two checks really were cashable.
+
1475 env(check::cash(bob, chkIdU, USD(20)));
+
1476 env.close();
+
1477 env(check::cash(bob, chkIdX, check::DeliverMin(XRP(10))));
+
1478 verifyDeliveredAmount(env, XRP(10));
+
1479
+
1480 // Try to cash an expired check.
+
1481 env(check::cash(bob, chkIdExp, XRP(10)), ter(tecEXPIRED));
+
1482 env.close();
+
1483
+
1484 // Cancel the expired check. Anyone can cancel an expired check.
+
1485 env(check::cancel(zoe, chkIdExp));
+
1486 env.close();
1487
-
1488 // Not destination cashing check.
-
1489 env(check::cash(alice, chkId, amount), ter(tecNO_PERMISSION));
-
1490 env.close();
-
1491 env(check::cash(gw, chkId, amount), ter(tecNO_PERMISSION));
-
1492 env.close();
-
1493
-
1494 // Currency mismatch.
-
1495 {
-
1496 IOU const wrongCurrency{gw["EUR"]};
-
1497 STAmount badAmount{amount};
-
1498 badAmount.setIssue(wrongCurrency.issue());
-
1499 env(check::cash(bob, chkId, badAmount), ter(temMALFORMED));
-
1500 env.close();
-
1501 }
-
1502
-
1503 // Issuer mismatch.
-
1504 {
-
1505 IOU const wrongIssuer{alice["USD"]};
-
1506 STAmount badAmount{amount};
-
1507 badAmount.setIssue(wrongIssuer.issue());
-
1508 env(check::cash(bob, chkId, badAmount), ter(temMALFORMED));
-
1509 env.close();
-
1510 }
-
1511
-
1512 // Amount bigger than SendMax.
-
1513 env(check::cash(bob, chkId, amount + amount), ter(tecPATH_PARTIAL));
-
1514 env.close();
-
1515
-
1516 // DeliverMin bigger than SendMax.
-
1517 env(check::cash(bob, chkId, check::DeliverMin(amount + amount)),
-
1518 ter(tecPATH_PARTIAL));
-
1519 env.close();
-
1520 };
-
1521
-
1522 failingCases(chkIdX, XRP(10));
-
1523 failingCases(chkIdU, USD(20));
-
1524
-
1525 // Verify that those two checks really were cashable.
-
1526 env(check::cash(bob, chkIdU, USD(20)));
-
1527 env.close();
-
1528 env(check::cash(bob, chkIdX, check::DeliverMin(XRP(10))));
-
1529 verifyDeliveredAmount(env, XRP(10));
+
1488 // Can we cash a check with frozen currency?
+
1489 {
+
1490 env(pay(bob, alice, USD(20)));
+
1491 env.close();
+
1492 env.require(balance(alice, USD(20)));
+
1493 env.require(balance(bob, USD(0)));
+
1494
+
1495 // Global freeze
+
1496 env(fset(gw, asfGlobalFreeze));
+
1497 env.close();
+
1498
+
1499 env(check::cash(bob, chkIdFroz1, USD(1)), ter(tecPATH_PARTIAL));
+
1500 env.close();
+
1501 env(check::cash(bob, chkIdFroz1, check::DeliverMin(USD(0.5))),
+
1502 ter(tecPATH_PARTIAL));
+
1503 env.close();
+
1504
+
1505 env(fclear(gw, asfGlobalFreeze));
+
1506 env.close();
+
1507
+
1508 // No longer frozen. Success.
+
1509 env(check::cash(bob, chkIdFroz1, USD(1)));
+
1510 env.close();
+
1511 env.require(balance(alice, USD(19)));
+
1512 env.require(balance(bob, USD(1)));
+
1513
+
1514 // Freeze individual trustlines.
+
1515 env(trust(gw, alice["USD"](0), tfSetFreeze));
+
1516 env.close();
+
1517 env(check::cash(bob, chkIdFroz2, USD(2)), ter(tecPATH_PARTIAL));
+
1518 env.close();
+
1519 env(check::cash(bob, chkIdFroz2, check::DeliverMin(USD(1))),
+
1520 ter(tecPATH_PARTIAL));
+
1521 env.close();
+
1522
+
1523 // Clear that freeze. Now check cashing works.
+
1524 env(trust(gw, alice["USD"](0), tfClearFreeze));
+
1525 env.close();
+
1526 env(check::cash(bob, chkIdFroz2, USD(2)));
+
1527 env.close();
+
1528 env.require(balance(alice, USD(17)));
+
1529 env.require(balance(bob, USD(3)));
1530
-
1531 // Try to cash an expired check.
-
1532 env(check::cash(bob, chkIdExp, XRP(10)), ter(tecEXPIRED));
-
1533 env.close();
-
1534
-
1535 // Cancel the expired check. Anyone can cancel an expired check.
-
1536 env(check::cancel(zoe, chkIdExp));
-
1537 env.close();
-
1538
-
1539 // Can we cash a check with frozen currency?
-
1540 {
-
1541 env(pay(bob, alice, USD(20)));
+
1531 // Freeze bob's trustline. bob can't cash the check.
+
1532 env(trust(gw, bob["USD"](0), tfSetFreeze));
+
1533 env.close();
+
1534 env(check::cash(bob, chkIdFroz3, USD(3)), ter(tecFROZEN));
+
1535 env.close();
+
1536 env(check::cash(bob, chkIdFroz3, check::DeliverMin(USD(1))),
+
1537 ter(tecFROZEN));
+
1538 env.close();
+
1539
+
1540 // Clear that freeze. Now check cashing works again.
+
1541 env(trust(gw, bob["USD"](0), tfClearFreeze));
1542 env.close();
-
1543 env.require(balance(alice, USD(20)));
-
1544 env.require(balance(bob, USD(0)));
-
1545
-
1546 // Global freeze
-
1547 env(fset(gw, asfGlobalFreeze));
-
1548 env.close();
-
1549
-
1550 env(check::cash(bob, chkIdFroz1, USD(1)), ter(tecPATH_PARTIAL));
+
1543 env(check::cash(bob, chkIdFroz3, check::DeliverMin(USD(1))));
+
1544 verifyDeliveredAmount(env, USD(3));
+
1545 env.require(balance(alice, USD(14)));
+
1546 env.require(balance(bob, USD(6)));
+
1547
+
1548 // Set bob's freeze bit in the other direction. Check
+
1549 // cashing fails.
+
1550 env(trust(bob, USD(20), tfSetFreeze));
1551 env.close();
-
1552 env(check::cash(bob, chkIdFroz1, check::DeliverMin(USD(0.5))),
-
1553 ter(tecPATH_PARTIAL));
-
1554 env.close();
-
1555
-
1556 env(fclear(gw, asfGlobalFreeze));
-
1557 env.close();
-
1558
-
1559 // No longer frozen. Success.
-
1560 env(check::cash(bob, chkIdFroz1, USD(1)));
-
1561 env.close();
-
1562 env.require(balance(alice, USD(19)));
-
1563 env.require(balance(bob, USD(1)));
-
1564
-
1565 // Freeze individual trustlines.
-
1566 env(trust(gw, alice["USD"](0), tfSetFreeze));
-
1567 env.close();
-
1568 env(check::cash(bob, chkIdFroz2, USD(2)), ter(tecPATH_PARTIAL));
-
1569 env.close();
-
1570 env(check::cash(bob, chkIdFroz2, check::DeliverMin(USD(1))),
-
1571 ter(tecPATH_PARTIAL));
+
1552 env(check::cash(bob, chkIdFroz4, USD(4)), ter(terNO_LINE));
+
1553 env.close();
+
1554 env(check::cash(bob, chkIdFroz4, check::DeliverMin(USD(1))),
+
1555 ter(terNO_LINE));
+
1556 env.close();
+
1557
+
1558 // Clear bob's freeze bit and the check should be cashable.
+
1559 env(trust(bob, USD(20), tfClearFreeze));
+
1560 env.close();
+
1561 env(check::cash(bob, chkIdFroz4, USD(4)));
+
1562 env.close();
+
1563 env.require(balance(alice, USD(10)));
+
1564 env.require(balance(bob, USD(10)));
+
1565 }
+
1566 {
+
1567 // Set the RequireDest flag on bob's account (after the check
+
1568 // was created) then cash a check without a destination tag.
+
1569 env(fset(bob, asfRequireDest));
+
1570 env.close();
+
1571 env(check::cash(bob, chkIdNoDest1, USD(1)), ter(tecDST_TAG_NEEDED));
1572 env.close();
-
1573
-
1574 // Clear that freeze. Now check cashing works.
-
1575 env(trust(gw, alice["USD"](0), tfClearFreeze));
-
1576 env.close();
-
1577 env(check::cash(bob, chkIdFroz2, USD(2)));
-
1578 env.close();
-
1579 env.require(balance(alice, USD(17)));
-
1580 env.require(balance(bob, USD(3)));
-
1581
-
1582 // Freeze bob's trustline. bob can't cash the check.
-
1583 env(trust(gw, bob["USD"](0), tfSetFreeze));
-
1584 env.close();
-
1585 env(check::cash(bob, chkIdFroz3, USD(3)), ter(tecFROZEN));
+
1573 env(check::cash(bob, chkIdNoDest1, check::DeliverMin(USD(0.5))),
+
1574 ter(tecDST_TAG_NEEDED));
+
1575 env.close();
+
1576
+
1577 // bob can cash a check with a destination tag.
+
1578 env(check::cash(bob, chkIdHasDest2, USD(2)));
+
1579 env.close();
+
1580 env.require(balance(alice, USD(8)));
+
1581 env.require(balance(bob, USD(12)));
+
1582
+
1583 // Clear the RequireDest flag on bob's account so he can
+
1584 // cash the check with no DestinationTag.
+
1585 env(fclear(bob, asfRequireDest));
1586 env.close();
-
1587 env(check::cash(bob, chkIdFroz3, check::DeliverMin(USD(1))),
-
1588 ter(tecFROZEN));
-
1589 env.close();
-
1590
-
1591 // Clear that freeze. Now check cashing works again.
-
1592 env(trust(gw, bob["USD"](0), tfClearFreeze));
-
1593 env.close();
-
1594 env(check::cash(bob, chkIdFroz3, check::DeliverMin(USD(1))));
-
1595 verifyDeliveredAmount(env, USD(3));
-
1596 env.require(balance(alice, USD(14)));
-
1597 env.require(balance(bob, USD(6)));
-
1598
-
1599 // Set bob's freeze bit in the other direction. Check
-
1600 // cashing fails.
-
1601 env(trust(bob, USD(20), tfSetFreeze));
-
1602 env.close();
-
1603 env(check::cash(bob, chkIdFroz4, USD(4)), ter(terNO_LINE));
-
1604 env.close();
-
1605 env(check::cash(bob, chkIdFroz4, check::DeliverMin(USD(1))),
-
1606 ter(terNO_LINE));
-
1607 env.close();
-
1608
-
1609 // Clear bob's freeze bit and the check should be cashable.
-
1610 env(trust(bob, USD(20), tfClearFreeze));
-
1611 env.close();
-
1612 env(check::cash(bob, chkIdFroz4, USD(4)));
-
1613 env.close();
-
1614 env.require(balance(alice, USD(10)));
-
1615 env.require(balance(bob, USD(10)));
-
1616 }
-
1617 {
-
1618 // Set the RequireDest flag on bob's account (after the check
-
1619 // was created) then cash a check without a destination tag.
-
1620 env(fset(bob, asfRequireDest));
-
1621 env.close();
-
1622 env(check::cash(bob, chkIdNoDest1, USD(1)), ter(tecDST_TAG_NEEDED));
+
1587 env(check::cash(bob, chkIdNoDest1, USD(1)));
+
1588 env.close();
+
1589 env.require(balance(alice, USD(7)));
+
1590 env.require(balance(bob, USD(13)));
+
1591 }
+
1592 }
+
+
1593
+
1594 void
+
+ +
1596 {
+
1597 // Explore many of the ways to cancel a check.
+
1598 testcase("Cancel valid");
+
1599
+
1600 using namespace test::jtx;
+
1601
+
1602 Account const gw{"gateway"};
+
1603 Account const alice{"alice"};
+
1604 Account const bob{"bob"};
+
1605 Account const zoe{"zoe"};
+
1606 IOU const USD{gw["USD"]};
+
1607
+
1608 // featureMultiSignReserve changes the reserve on a SignerList, so
+
1609 // check both before and after.
+
1610 for (auto const& testFeatures :
+
1611 {features - featureMultiSignReserve,
+
1612 features | featureMultiSignReserve})
+
1613 {
+
1614 Env env{*this, testFeatures};
+
1615
+
1616 env.fund(XRP(1000), gw, alice, bob, zoe);
+
1617 env.close();
+
1618
+
1619 // alice creates her checks ahead of time.
+
1620 // Three ordinary checks with no expiration.
+
1621 uint256 const chkId1{getCheckIndex(alice, env.seq(alice))};
+
1622 env(check::create(alice, bob, USD(10)));
1623 env.close();
-
1624 env(check::cash(bob, chkIdNoDest1, check::DeliverMin(USD(0.5))),
-
1625 ter(tecDST_TAG_NEEDED));
-
1626 env.close();
-
1627
-
1628 // bob can cash a check with a destination tag.
-
1629 env(check::cash(bob, chkIdHasDest2, USD(2)));
-
1630 env.close();
-
1631 env.require(balance(alice, USD(8)));
-
1632 env.require(balance(bob, USD(12)));
-
1633
-
1634 // Clear the RequireDest flag on bob's account so he can
-
1635 // cash the check with no DestinationTag.
-
1636 env(fclear(bob, asfRequireDest));
-
1637 env.close();
-
1638 env(check::cash(bob, chkIdNoDest1, USD(1)));
-
1639 env.close();
-
1640 env.require(balance(alice, USD(7)));
-
1641 env.require(balance(bob, USD(13)));
-
1642 }
-
1643 }
-
+
1624
+
1625 uint256 const chkId2{getCheckIndex(alice, env.seq(alice))};
+
1626 env(check::create(alice, bob, XRP(10)));
+
1627 env.close();
+
1628
+
1629 uint256 const chkId3{getCheckIndex(alice, env.seq(alice))};
+
1630 env(check::create(alice, bob, USD(10)));
+
1631 env.close();
+
1632
+
1633 // Three checks that expire in 10 minutes.
+
1634 using namespace std::chrono_literals;
+
1635 uint256 const chkIdNotExp1{getCheckIndex(alice, env.seq(alice))};
+
1636 env(check::create(alice, bob, XRP(10)),
+
1637 expiration(env.now() + 600s));
+
1638 env.close();
+
1639
+
1640 uint256 const chkIdNotExp2{getCheckIndex(alice, env.seq(alice))};
+
1641 env(check::create(alice, bob, USD(10)),
+
1642 expiration(env.now() + 600s));
+
1643 env.close();
1644
-
1645 void
-
- -
1647 {
-
1648 // Explore many of the ways to cancel a check.
-
1649 testcase("Cancel valid");
-
1650
-
1651 using namespace test::jtx;
-
1652
-
1653 Account const gw{"gateway"};
-
1654 Account const alice{"alice"};
-
1655 Account const bob{"bob"};
-
1656 Account const zoe{"zoe"};
-
1657 IOU const USD{gw["USD"]};
+
1645 uint256 const chkIdNotExp3{getCheckIndex(alice, env.seq(alice))};
+
1646 env(check::create(alice, bob, XRP(10)),
+
1647 expiration(env.now() + 600s));
+
1648 env.close();
+
1649
+
1650 // Three checks that expire in one second.
+
1651 uint256 const chkIdExp1{getCheckIndex(alice, env.seq(alice))};
+
1652 env(check::create(alice, bob, USD(10)), expiration(env.now() + 1s));
+
1653 env.close();
+
1654
+
1655 uint256 const chkIdExp2{getCheckIndex(alice, env.seq(alice))};
+
1656 env(check::create(alice, bob, XRP(10)), expiration(env.now() + 1s));
+
1657 env.close();
1658
-
1659 // featureMultiSignReserve changes the reserve on a SignerList, so
-
1660 // check both before and after.
-
1661 for (auto const& testFeatures :
-
1662 {features - featureMultiSignReserve,
-
1663 features | featureMultiSignReserve})
-
1664 {
-
1665 Env env{*this, testFeatures};
-
1666
-
1667 env.fund(XRP(1000), gw, alice, bob, zoe);
-
1668 env.close();
-
1669
-
1670 // alice creates her checks ahead of time.
-
1671 // Three ordinary checks with no expiration.
-
1672 uint256 const chkId1{getCheckIndex(alice, env.seq(alice))};
-
1673 env(check::create(alice, bob, USD(10)));
-
1674 env.close();
-
1675
-
1676 uint256 const chkId2{getCheckIndex(alice, env.seq(alice))};
-
1677 env(check::create(alice, bob, XRP(10)));
-
1678 env.close();
+
1659 uint256 const chkIdExp3{getCheckIndex(alice, env.seq(alice))};
+
1660 env(check::create(alice, bob, USD(10)), expiration(env.now() + 1s));
+
1661 env.close();
+
1662
+
1663 // Two checks to cancel using a regular key and using multisigning.
+
1664 uint256 const chkIdReg{getCheckIndex(alice, env.seq(alice))};
+
1665 env(check::create(alice, bob, USD(10)));
+
1666 env.close();
+
1667
+
1668 uint256 const chkIdMSig{getCheckIndex(alice, env.seq(alice))};
+
1669 env(check::create(alice, bob, XRP(10)));
+
1670 env.close();
+
1671 BEAST_EXPECT(checksOnAccount(env, alice).size() == 11);
+
1672 BEAST_EXPECT(ownerCount(env, alice) == 11);
+
1673
+
1674 // Creator, destination, and an outsider cancel the checks.
+
1675 env(check::cancel(alice, chkId1));
+
1676 env.close();
+
1677 BEAST_EXPECT(checksOnAccount(env, alice).size() == 10);
+
1678 BEAST_EXPECT(ownerCount(env, alice) == 10);
1679
-
1680 uint256 const chkId3{getCheckIndex(alice, env.seq(alice))};
-
1681 env(check::create(alice, bob, USD(10)));
-
1682 env.close();
-
1683
-
1684 // Three checks that expire in 10 minutes.
-
1685 using namespace std::chrono_literals;
-
1686 uint256 const chkIdNotExp1{getCheckIndex(alice, env.seq(alice))};
-
1687 env(check::create(alice, bob, XRP(10)),
-
1688 expiration(env.now() + 600s));
-
1689 env.close();
-
1690
-
1691 uint256 const chkIdNotExp2{getCheckIndex(alice, env.seq(alice))};
-
1692 env(check::create(alice, bob, USD(10)),
-
1693 expiration(env.now() + 600s));
-
1694 env.close();
+
1680 env(check::cancel(bob, chkId2));
+
1681 env.close();
+
1682 BEAST_EXPECT(checksOnAccount(env, alice).size() == 9);
+
1683 BEAST_EXPECT(ownerCount(env, alice) == 9);
+
1684
+
1685 env(check::cancel(zoe, chkId3), ter(tecNO_PERMISSION));
+
1686 env.close();
+
1687 BEAST_EXPECT(checksOnAccount(env, alice).size() == 9);
+
1688 BEAST_EXPECT(ownerCount(env, alice) == 9);
+
1689
+
1690 // Creator, destination, and an outsider cancel unexpired checks.
+
1691 env(check::cancel(alice, chkIdNotExp1));
+
1692 env.close();
+
1693 BEAST_EXPECT(checksOnAccount(env, alice).size() == 8);
+
1694 BEAST_EXPECT(ownerCount(env, alice) == 8);
1695
-
1696 uint256 const chkIdNotExp3{getCheckIndex(alice, env.seq(alice))};
-
1697 env(check::create(alice, bob, XRP(10)),
-
1698 expiration(env.now() + 600s));
-
1699 env.close();
+
1696 env(check::cancel(bob, chkIdNotExp2));
+
1697 env.close();
+
1698 BEAST_EXPECT(checksOnAccount(env, alice).size() == 7);
+
1699 BEAST_EXPECT(ownerCount(env, alice) == 7);
1700
-
1701 // Three checks that expire in one second.
-
1702 uint256 const chkIdExp1{getCheckIndex(alice, env.seq(alice))};
-
1703 env(check::create(alice, bob, USD(10)), expiration(env.now() + 1s));
-
1704 env.close();
+
1701 env(check::cancel(zoe, chkIdNotExp3), ter(tecNO_PERMISSION));
+
1702 env.close();
+
1703 BEAST_EXPECT(checksOnAccount(env, alice).size() == 7);
+
1704 BEAST_EXPECT(ownerCount(env, alice) == 7);
1705
-
1706 uint256 const chkIdExp2{getCheckIndex(alice, env.seq(alice))};
-
1707 env(check::create(alice, bob, XRP(10)), expiration(env.now() + 1s));
+
1706 // Creator, destination, and an outsider cancel expired checks.
+
1707 env(check::cancel(alice, chkIdExp1));
1708 env.close();
-
1709
-
1710 uint256 const chkIdExp3{getCheckIndex(alice, env.seq(alice))};
-
1711 env(check::create(alice, bob, USD(10)), expiration(env.now() + 1s));
-
1712 env.close();
-
1713
-
1714 // Two checks to cancel using a regular key and using multisigning.
-
1715 uint256 const chkIdReg{getCheckIndex(alice, env.seq(alice))};
-
1716 env(check::create(alice, bob, USD(10)));
-
1717 env.close();
-
1718
-
1719 uint256 const chkIdMSig{getCheckIndex(alice, env.seq(alice))};
-
1720 env(check::create(alice, bob, XRP(10)));
-
1721 env.close();
-
1722 BEAST_EXPECT(checksOnAccount(env, alice).size() == 11);
-
1723 BEAST_EXPECT(ownerCount(env, alice) == 11);
-
1724
-
1725 // Creator, destination, and an outsider cancel the checks.
-
1726 env(check::cancel(alice, chkId1));
-
1727 env.close();
-
1728 BEAST_EXPECT(checksOnAccount(env, alice).size() == 10);
-
1729 BEAST_EXPECT(ownerCount(env, alice) == 10);
-
1730
-
1731 env(check::cancel(bob, chkId2));
-
1732 env.close();
-
1733 BEAST_EXPECT(checksOnAccount(env, alice).size() == 9);
-
1734 BEAST_EXPECT(ownerCount(env, alice) == 9);
-
1735
-
1736 env(check::cancel(zoe, chkId3), ter(tecNO_PERMISSION));
-
1737 env.close();
-
1738 BEAST_EXPECT(checksOnAccount(env, alice).size() == 9);
-
1739 BEAST_EXPECT(ownerCount(env, alice) == 9);
-
1740
-
1741 // Creator, destination, and an outsider cancel unexpired checks.
-
1742 env(check::cancel(alice, chkIdNotExp1));
-
1743 env.close();
-
1744 BEAST_EXPECT(checksOnAccount(env, alice).size() == 8);
-
1745 BEAST_EXPECT(ownerCount(env, alice) == 8);
-
1746
-
1747 env(check::cancel(bob, chkIdNotExp2));
+
1709 BEAST_EXPECT(checksOnAccount(env, alice).size() == 6);
+
1710 BEAST_EXPECT(ownerCount(env, alice) == 6);
+
1711
+
1712 env(check::cancel(bob, chkIdExp2));
+
1713 env.close();
+
1714 BEAST_EXPECT(checksOnAccount(env, alice).size() == 5);
+
1715 BEAST_EXPECT(ownerCount(env, alice) == 5);
+
1716
+
1717 env(check::cancel(zoe, chkIdExp3));
+
1718 env.close();
+
1719 BEAST_EXPECT(checksOnAccount(env, alice).size() == 4);
+
1720 BEAST_EXPECT(ownerCount(env, alice) == 4);
+
1721
+
1722 // Use a regular key and also multisign to cancel checks.
+
1723 Account const alie{"alie", KeyType::ed25519};
+
1724 env(regkey(alice, alie));
+
1725 env.close();
+
1726
+
1727 Account const bogie{"bogie", KeyType::secp256k1};
+
1728 Account const demon{"demon", KeyType::ed25519};
+
1729 env(signers(alice, 2, {{bogie, 1}, {demon, 1}}), sig(alie));
+
1730 env.close();
+
1731
+
1732 // If featureMultiSignReserve is enabled then alices's signer list
+
1733 // has an owner count of 1, otherwise it's 4.
+
1734 int const signersCount{
+
1735 testFeatures[featureMultiSignReserve] ? 1 : 4};
+
1736
+
1737 // alice uses her regular key to cancel a check.
+
1738 env(check::cancel(alice, chkIdReg), sig(alie));
+
1739 env.close();
+
1740 BEAST_EXPECT(checksOnAccount(env, alice).size() == 3);
+
1741 BEAST_EXPECT(ownerCount(env, alice) == signersCount + 3);
+
1742
+
1743 // alice uses multisigning to cancel a check.
+
1744 XRPAmount const baseFeeDrops{env.current()->fees().base};
+
1745 env(check::cancel(alice, chkIdMSig),
+
1746 msig(bogie, demon),
+
1747 fee(3 * baseFeeDrops));
1748 env.close();
-
1749 BEAST_EXPECT(checksOnAccount(env, alice).size() == 7);
-
1750 BEAST_EXPECT(ownerCount(env, alice) == 7);
+
1749 BEAST_EXPECT(checksOnAccount(env, alice).size() == 2);
+
1750 BEAST_EXPECT(ownerCount(env, alice) == signersCount + 2);
1751
-
1752 env(check::cancel(zoe, chkIdNotExp3), ter(tecNO_PERMISSION));
-
1753 env.close();
-
1754 BEAST_EXPECT(checksOnAccount(env, alice).size() == 7);
-
1755 BEAST_EXPECT(ownerCount(env, alice) == 7);
-
1756
-
1757 // Creator, destination, and an outsider cancel expired checks.
-
1758 env(check::cancel(alice, chkIdExp1));
+
1752 // Creator and destination cancel the remaining unexpired checks.
+
1753 env(check::cancel(alice, chkId3), sig(alice));
+
1754 env.close();
+
1755 BEAST_EXPECT(checksOnAccount(env, alice).size() == 1);
+
1756 BEAST_EXPECT(ownerCount(env, alice) == signersCount + 1);
+
1757
+
1758 env(check::cancel(bob, chkIdNotExp3));
1759 env.close();
-
1760 BEAST_EXPECT(checksOnAccount(env, alice).size() == 6);
-
1761 BEAST_EXPECT(ownerCount(env, alice) == 6);
-
1762
-
1763 env(check::cancel(bob, chkIdExp2));
-
1764 env.close();
-
1765 BEAST_EXPECT(checksOnAccount(env, alice).size() == 5);
-
1766 BEAST_EXPECT(ownerCount(env, alice) == 5);
-
1767
-
1768 env(check::cancel(zoe, chkIdExp3));
-
1769 env.close();
-
1770 BEAST_EXPECT(checksOnAccount(env, alice).size() == 4);
-
1771 BEAST_EXPECT(ownerCount(env, alice) == 4);
+
1760 BEAST_EXPECT(checksOnAccount(env, alice).size() == 0);
+
1761 BEAST_EXPECT(ownerCount(env, alice) == signersCount + 0);
+
1762 }
+
1763 }
+
+
1764
+
1765 void
+
+ +
1767 {
+
1768 // Explore many of the ways to fail at canceling a check.
+
1769 testcase("Cancel invalid");
+
1770
+
1771 using namespace test::jtx;
1772
-
1773 // Use a regular key and also multisign to cancel checks.
-
1774 Account const alie{"alie", KeyType::ed25519};
-
1775 env(regkey(alice, alie));
-
1776 env.close();
+
1773 Account const alice{"alice"};
+
1774 Account const bob{"bob"};
+
1775
+
1776 Env env{*this, features};
1777
-
1778 Account const bogie{"bogie", KeyType::secp256k1};
-
1779 Account const demon{"demon", KeyType::ed25519};
-
1780 env(signers(alice, 2, {{bogie, 1}, {demon, 1}}), sig(alie));
-
1781 env.close();
-
1782
-
1783 // If featureMultiSignReserve is enabled then alices's signer list
-
1784 // has an owner count of 1, otherwise it's 4.
-
1785 int const signersCount{
-
1786 testFeatures[featureMultiSignReserve] ? 1 : 4};
-
1787
-
1788 // alice uses her regular key to cancel a check.
-
1789 env(check::cancel(alice, chkIdReg), sig(alie));
-
1790 env.close();
-
1791 BEAST_EXPECT(checksOnAccount(env, alice).size() == 3);
-
1792 BEAST_EXPECT(ownerCount(env, alice) == signersCount + 3);
-
1793
-
1794 // alice uses multisigning to cancel a check.
-
1795 XRPAmount const baseFeeDrops{env.current()->fees().base};
-
1796 env(check::cancel(alice, chkIdMSig),
-
1797 msig(bogie, demon),
-
1798 fee(3 * baseFeeDrops));
-
1799 env.close();
-
1800 BEAST_EXPECT(checksOnAccount(env, alice).size() == 2);
-
1801 BEAST_EXPECT(ownerCount(env, alice) == signersCount + 2);
-
1802
-
1803 // Creator and destination cancel the remaining unexpired checks.
-
1804 env(check::cancel(alice, chkId3), sig(alice));
-
1805 env.close();
-
1806 BEAST_EXPECT(checksOnAccount(env, alice).size() == 1);
-
1807 BEAST_EXPECT(ownerCount(env, alice) == signersCount + 1);
-
1808
-
1809 env(check::cancel(bob, chkIdNotExp3));
-
1810 env.close();
-
1811 BEAST_EXPECT(checksOnAccount(env, alice).size() == 0);
-
1812 BEAST_EXPECT(ownerCount(env, alice) == signersCount + 0);
-
1813 }
-
1814 }
+
1778 env.fund(XRP(1000), alice, bob);
+
1779 env.close();
+
1780
+
1781 // Bad fee.
+
1782 env(check::cancel(bob, getCheckIndex(alice, env.seq(alice))),
+
1783 fee(drops(-10)),
+
1784 ter(temBAD_FEE));
+
1785 env.close();
+
1786
+
1787 // Bad flags.
+
1788 env(check::cancel(bob, getCheckIndex(alice, env.seq(alice))),
+
1789 txflags(tfImmediateOrCancel),
+
1790 ter(temINVALID_FLAG));
+
1791 env.close();
+
1792
+
1793 // Non-existent check.
+
1794 env(check::cancel(bob, getCheckIndex(alice, env.seq(alice))),
+
1795 ter(tecNO_ENTRY));
+
1796 env.close();
+
1797 }
-
1815
-
1816 void
-
- -
1818 {
-
1819 // Explore many of the ways to fail at canceling a check.
-
1820 testcase("Cancel invalid");
-
1821
-
1822 using namespace test::jtx;
-
1823
-
1824 Account const alice{"alice"};
-
1825 Account const bob{"bob"};
-
1826
-
1827 Env env{*this, features};
-
1828
-
1829 env.fund(XRP(1000), alice, bob);
-
1830 env.close();
-
1831
-
1832 // Bad fee.
-
1833 env(check::cancel(bob, getCheckIndex(alice, env.seq(alice))),
-
1834 fee(drops(-10)),
-
1835 ter(temBAD_FEE));
-
1836 env.close();
+
1798
+
1799 void
+
+ +
1801 {
+
1802 testcase("DeliveredAmount For CheckCash Txn");
+
1803
+
1804 using namespace test::jtx;
+
1805 Account const alice{"alice"};
+
1806 Account const bob{"bob"};
+
1807
+
1808 Env env{*this, features};
+
1809
+
1810 env.fund(XRP(1000), alice, bob);
+
1811 env.close();
+
1812
+
1813 uint256 const chkId{getCheckIndex(alice, env.seq(alice))};
+
1814 env(check::create(alice, bob, XRP(200)));
+
1815 env.close();
+
1816
+
1817 env(check::cash(bob, chkId, check::DeliverMin(XRP(100))));
+
1818
+
1819 // Get the hash for the most recent transaction.
+
1820 std::string const txHash{
+
1821 env.tx()->getJson(JsonOptions::none)[jss::hash].asString()};
+
1822
+
1823 env.close();
+
1824 Json::Value const meta = env.rpc("tx", txHash)[jss::result][jss::meta];
+
1825
+
1826 // DeliveredAmount and delivered_amount are present.
+
1827 BEAST_EXPECT(meta.isMember(sfDeliveredAmount.jsonName));
+
1828 BEAST_EXPECT(meta.isMember(jss::delivered_amount));
+
1829 }
+
+
1830
+
1831 void
+
+ +
1833 {
+
1834 testcase("With Tickets");
+
1835
+
1836 using namespace test::jtx;
1837
-
1838 // Bad flags.
-
1839 env(check::cancel(bob, getCheckIndex(alice, env.seq(alice))),
-
1840 txflags(tfImmediateOrCancel),
-
1841 ter(temINVALID_FLAG));
-
1842 env.close();
-
1843
-
1844 // Non-existent check.
-
1845 env(check::cancel(bob, getCheckIndex(alice, env.seq(alice))),
-
1846 ter(tecNO_ENTRY));
-
1847 env.close();
-
1848 }
-
-
1849
-
1850 void
-
- -
1852 {
-
1853 testcase("DeliveredAmount For CheckCash Txn");
-
1854
-
1855 using namespace test::jtx;
-
1856 Account const alice{"alice"};
-
1857 Account const bob{"bob"};
-
1858
-
1859 Env env{*this, features};
-
1860
-
1861 env.fund(XRP(1000), alice, bob);
-
1862 env.close();
-
1863
-
1864 uint256 const chkId{getCheckIndex(alice, env.seq(alice))};
-
1865 env(check::create(alice, bob, XRP(200)));
-
1866 env.close();
-
1867
-
1868 env(check::cash(bob, chkId, check::DeliverMin(XRP(100))));
-
1869
-
1870 // Get the hash for the most recent transaction.
-
1871 std::string const txHash{
-
1872 env.tx()->getJson(JsonOptions::none)[jss::hash].asString()};
-
1873
-
1874 env.close();
-
1875 Json::Value const meta = env.rpc("tx", txHash)[jss::result][jss::meta];
-
1876
-
1877 // DeliveredAmount and delivered_amount are present.
-
1878 BEAST_EXPECT(meta.isMember(sfDeliveredAmount.jsonName));
-
1879 BEAST_EXPECT(meta.isMember(jss::delivered_amount));
-
1880 }
-
-
1881
-
1882 void
-
- -
1884 {
-
1885 testcase("With Tickets");
-
1886
-
1887 using namespace test::jtx;
+
1838 Account const gw{"gw"};
+
1839 Account const alice{"alice"};
+
1840 Account const bob{"bob"};
+
1841 IOU const USD{gw["USD"]};
+
1842
+
1843 Env env{*this, features};
+
1844 env.fund(XRP(1000), gw, alice, bob);
+
1845 env.close();
+
1846
+
1847 // alice and bob grab enough tickets for all of the following
+
1848 // transactions. Note that once the tickets are acquired alice's
+
1849 // and bob's account sequence numbers should not advance.
+
1850 std::uint32_t aliceTicketSeq{env.seq(alice) + 1};
+
1851 env(ticket::create(alice, 10));
+
1852 std::uint32_t const aliceSeq{env.seq(alice)};
+
1853
+
1854 std::uint32_t bobTicketSeq{env.seq(bob) + 1};
+
1855 env(ticket::create(bob, 10));
+
1856 std::uint32_t const bobSeq{env.seq(bob)};
+
1857
+
1858 env.close();
+
1859 env.require(owners(alice, 10));
+
1860 env.require(owners(bob, 10));
+
1861
+
1862 // alice gets enough USD to write a few checks.
+
1863 env(trust(alice, USD(1000)), ticket::use(aliceTicketSeq++));
+
1864 env(trust(bob, USD(1000)), ticket::use(bobTicketSeq++));
+
1865 env.close();
+
1866 env.require(owners(alice, 10));
+
1867 env.require(owners(bob, 10));
+
1868
+
1869 env.require(tickets(alice, env.seq(alice) - aliceTicketSeq));
+
1870 BEAST_EXPECT(env.seq(alice) == aliceSeq);
+
1871
+
1872 env.require(tickets(bob, env.seq(bob) - bobTicketSeq));
+
1873 BEAST_EXPECT(env.seq(bob) == bobSeq);
+
1874
+
1875 env(pay(gw, alice, USD(900)));
+
1876 env.close();
+
1877
+
1878 // alice creates four checks; two XRP, two IOU. Bob will cash
+
1879 // one of each and cancel one of each.
+
1880 uint256 const chkIdXrp1{getCheckIndex(alice, aliceTicketSeq)};
+
1881 env(check::create(alice, bob, XRP(200)), ticket::use(aliceTicketSeq++));
+
1882
+
1883 uint256 const chkIdXrp2{getCheckIndex(alice, aliceTicketSeq)};
+
1884 env(check::create(alice, bob, XRP(300)), ticket::use(aliceTicketSeq++));
+
1885
+
1886 uint256 const chkIdUsd1{getCheckIndex(alice, aliceTicketSeq)};
+
1887 env(check::create(alice, bob, USD(200)), ticket::use(aliceTicketSeq++));
1888
-
1889 Account const gw{"gw"};
-
1890 Account const alice{"alice"};
-
1891 Account const bob{"bob"};
-
1892 IOU const USD{gw["USD"]};
-
1893
-
1894 Env env{*this, features};
-
1895 env.fund(XRP(1000), gw, alice, bob);
-
1896 env.close();
-
1897
-
1898 // alice and bob grab enough tickets for all of the following
-
1899 // transactions. Note that once the tickets are acquired alice's
-
1900 // and bob's account sequence numbers should not advance.
-
1901 std::uint32_t aliceTicketSeq{env.seq(alice) + 1};
-
1902 env(ticket::create(alice, 10));
-
1903 std::uint32_t const aliceSeq{env.seq(alice)};
-
1904
-
1905 std::uint32_t bobTicketSeq{env.seq(bob) + 1};
-
1906 env(ticket::create(bob, 10));
-
1907 std::uint32_t const bobSeq{env.seq(bob)};
-
1908
-
1909 env.close();
-
1910 env.require(owners(alice, 10));
-
1911 env.require(owners(bob, 10));
-
1912
-
1913 // alice gets enough USD to write a few checks.
-
1914 env(trust(alice, USD(1000)), ticket::use(aliceTicketSeq++));
-
1915 env(trust(bob, USD(1000)), ticket::use(bobTicketSeq++));
-
1916 env.close();
-
1917 env.require(owners(alice, 10));
-
1918 env.require(owners(bob, 10));
+
1889 uint256 const chkIdUsd2{getCheckIndex(alice, aliceTicketSeq)};
+
1890 env(check::create(alice, bob, USD(300)), ticket::use(aliceTicketSeq++));
+
1891
+
1892 env.close();
+
1893 // Alice used four tickets but created four checks.
+
1894 env.require(owners(alice, 10));
+
1895 env.require(tickets(alice, env.seq(alice) - aliceTicketSeq));
+
1896 BEAST_EXPECT(checksOnAccount(env, alice).size() == 4);
+
1897 BEAST_EXPECT(env.seq(alice) == aliceSeq);
+
1898
+
1899 env.require(owners(bob, 10));
+
1900 BEAST_EXPECT(env.seq(bob) == bobSeq);
+
1901
+
1902 // Bob cancels two of alice's checks.
+
1903 env(check::cancel(bob, chkIdXrp1), ticket::use(bobTicketSeq++));
+
1904 env(check::cancel(bob, chkIdUsd2), ticket::use(bobTicketSeq++));
+
1905 env.close();
+
1906
+
1907 env.require(owners(alice, 8));
+
1908 env.require(tickets(alice, env.seq(alice) - aliceTicketSeq));
+
1909 BEAST_EXPECT(checksOnAccount(env, alice).size() == 2);
+
1910 BEAST_EXPECT(env.seq(alice) == aliceSeq);
+
1911
+
1912 env.require(owners(bob, 8));
+
1913 BEAST_EXPECT(env.seq(bob) == bobSeq);
+
1914
+
1915 // Bob cashes alice's two remaining checks.
+
1916 env(check::cash(bob, chkIdXrp2, XRP(300)), ticket::use(bobTicketSeq++));
+
1917 env(check::cash(bob, chkIdUsd1, USD(200)), ticket::use(bobTicketSeq++));
+
1918 env.close();
1919
-
1920 env.require(tickets(alice, env.seq(alice) - aliceTicketSeq));
-
1921 BEAST_EXPECT(env.seq(alice) == aliceSeq);
-
1922
-
1923 env.require(tickets(bob, env.seq(bob) - bobTicketSeq));
-
1924 BEAST_EXPECT(env.seq(bob) == bobSeq);
+
1920 env.require(owners(alice, 6));
+
1921 env.require(tickets(alice, env.seq(alice) - aliceTicketSeq));
+
1922 BEAST_EXPECT(checksOnAccount(env, alice).size() == 0);
+
1923 BEAST_EXPECT(env.seq(alice) == aliceSeq);
+
1924 env.require(balance(alice, USD(700)));
1925
-
1926 env(pay(gw, alice, USD(900)));
-
1927 env.close();
-
1928
-
1929 // alice creates four checks; two XRP, two IOU. Bob will cash
-
1930 // one of each and cancel one of each.
-
1931 uint256 const chkIdXrp1{getCheckIndex(alice, aliceTicketSeq)};
-
1932 env(check::create(alice, bob, XRP(200)), ticket::use(aliceTicketSeq++));
-
1933
-
1934 uint256 const chkIdXrp2{getCheckIndex(alice, aliceTicketSeq)};
-
1935 env(check::create(alice, bob, XRP(300)), ticket::use(aliceTicketSeq++));
-
1936
-
1937 uint256 const chkIdUsd1{getCheckIndex(alice, aliceTicketSeq)};
-
1938 env(check::create(alice, bob, USD(200)), ticket::use(aliceTicketSeq++));
-
1939
-
1940 uint256 const chkIdUsd2{getCheckIndex(alice, aliceTicketSeq)};
-
1941 env(check::create(alice, bob, USD(300)), ticket::use(aliceTicketSeq++));
-
1942
-
1943 env.close();
-
1944 // Alice used four tickets but created four checks.
-
1945 env.require(owners(alice, 10));
-
1946 env.require(tickets(alice, env.seq(alice) - aliceTicketSeq));
-
1947 BEAST_EXPECT(checksOnAccount(env, alice).size() == 4);
-
1948 BEAST_EXPECT(env.seq(alice) == aliceSeq);
-
1949
-
1950 env.require(owners(bob, 10));
-
1951 BEAST_EXPECT(env.seq(bob) == bobSeq);
-
1952
-
1953 // Bob cancels two of alice's checks.
-
1954 env(check::cancel(bob, chkIdXrp1), ticket::use(bobTicketSeq++));
-
1955 env(check::cancel(bob, chkIdUsd2), ticket::use(bobTicketSeq++));
-
1956 env.close();
-
1957
-
1958 env.require(owners(alice, 8));
-
1959 env.require(tickets(alice, env.seq(alice) - aliceTicketSeq));
-
1960 BEAST_EXPECT(checksOnAccount(env, alice).size() == 2);
-
1961 BEAST_EXPECT(env.seq(alice) == aliceSeq);
-
1962
-
1963 env.require(owners(bob, 8));
-
1964 BEAST_EXPECT(env.seq(bob) == bobSeq);
-
1965
-
1966 // Bob cashes alice's two remaining checks.
-
1967 env(check::cash(bob, chkIdXrp2, XRP(300)), ticket::use(bobTicketSeq++));
-
1968 env(check::cash(bob, chkIdUsd1, USD(200)), ticket::use(bobTicketSeq++));
-
1969 env.close();
-
1970
-
1971 env.require(owners(alice, 6));
-
1972 env.require(tickets(alice, env.seq(alice) - aliceTicketSeq));
-
1973 BEAST_EXPECT(checksOnAccount(env, alice).size() == 0);
-
1974 BEAST_EXPECT(env.seq(alice) == aliceSeq);
-
1975 env.require(balance(alice, USD(700)));
-
1976
-
1977 env.require(owners(bob, 6));
-
1978 BEAST_EXPECT(env.seq(bob) == bobSeq);
-
1979 env.require(balance(bob, USD(200)));
-
1980 }
+
1926 env.require(owners(bob, 6));
+
1927 BEAST_EXPECT(env.seq(bob) == bobSeq);
+
1928 env.require(balance(bob, USD(200)));
+
1929 }
+
1930
+
1931 void
+
+ +
1933 {
+
1934 // Explore automatic trust line creation when a check is cashed.
+
1935 //
+
1936
+
1937 testcase("Trust Line Creation");
+
1938
+
1939 using namespace test::jtx;
+
1940
+
1941 Env env{*this, features};
+
1942
+
1943 // An account that independently tracks its owner count.
+
1944 struct AccountOwns
+
1945 {
+ +
1947 Env const& env;
+
1948 Account const acct;
+
1949 std::size_t owners;
+
1950
+
1951 void
+
1952 verifyOwners(std::uint32_t line) const
+
1953 {
+
1954 suite.expect(
+
1955 ownerCount(env, acct) == owners,
+
1956 "Owner count mismatch",
+
1957 __FILE__,
+
1958 line);
+
1959 }
+
1960
+
1961 // Operators to make using the class more convenient.
+
1962 operator Account const() const
+
1963 {
+
1964 return acct;
+
1965 }
+
1966
+
1967 operator ripple::AccountID() const
+
1968 {
+
1969 return acct.id();
+
1970 }
+
1971
+
1972 IOU
+
1973 operator[](std::string const& s) const
+
1974 {
+
1975 return acct[s];
+
1976 }
+
1977 };
+
1978
+
1979 AccountOwns alice{*this, env, "alice", 0};
+
1980 AccountOwns bob{*this, env, "bob", 0};
1981
-
1982 void
-
- -
1984 {
-
1985 // Explore automatic trust line creation when a check is cashed.
-
1986 //
-
1987 // This capability is enabled by the featureCheckCashMakesTrustLine
-
1988 // amendment. So this test executes only when that amendment is
-
1989 // active.
-
1990 assert(features[featureCheckCashMakesTrustLine]);
-
1991
-
1992 testcase("Trust Line Creation");
-
1993
-
1994 using namespace test::jtx;
-
1995
-
1996 Env env{*this, features};
-
1997
-
1998 // An account that independently tracks its owner count.
-
1999 struct AccountOwns
-
2000 {
- -
2002 Env const& env;
-
2003 Account const acct;
-
2004 std::size_t owners;
-
2005
-
2006 void
-
2007 verifyOwners(std::uint32_t line) const
-
2008 {
-
2009 suite.expect(
-
2010 ownerCount(env, acct) == owners,
-
2011 "Owner count mismatch",
-
2012 __FILE__,
-
2013 line);
-
2014 }
-
2015
-
2016 // Operators to make using the class more convenient.
-
2017 operator Account const() const
-
2018 {
-
2019 return acct;
-
2020 }
-
2021
-
2022 operator ripple::AccountID() const
-
2023 {
-
2024 return acct.id();
-
2025 }
-
2026
-
2027 IOU
-
2028 operator[](std::string const& s) const
-
2029 {
-
2030 return acct[s];
-
2031 }
-
2032 };
-
2033
-
2034 AccountOwns alice{*this, env, "alice", 0};
-
2035 AccountOwns bob{*this, env, "bob", 0};
-
2036
-
2037 // Fund with noripple so the accounts do not have any flags set.
-
2038 env.fund(XRP(5000), noripple(alice, bob));
-
2039 env.close();
-
2040
-
2041 // Automatic trust line creation should fail if the check destination
-
2042 // can't afford the reserve for the trust line.
-
2043 {
-
2044 AccountOwns gw1{*this, env, "gw1", 0};
-
2045
-
2046 // Fund gw1 with noripple (even though that's atypical for a
-
2047 // gateway) so it does not have any flags set. We'll set flags
-
2048 // on gw1 later.
-
2049 env.fund(XRP(5000), noripple(gw1));
-
2050 env.close();
-
2051
-
2052 IOU const CK8 = gw1["CK8"];
-
2053 gw1.verifyOwners(__LINE__);
-
2054
-
2055 Account const yui{"yui"};
-
2056
-
2057 // Note the reserve in unit tests is 200 XRP, not 20. So here
-
2058 // we're just barely giving yui enough XRP to meet the
-
2059 // account reserve.
-
2060 env.fund(XRP(200), yui);
-
2061 env.close();
-
2062
-
2063 uint256 const chkId{getCheckIndex(gw1, env.seq(gw1))};
-
2064 env(check::create(gw1, yui, CK8(99)));
-
2065 env.close();
-
2066
-
2067 env(check::cash(yui, chkId, CK8(99)),
- -
2069 env.close();
-
2070 alice.verifyOwners(__LINE__);
-
2071
-
2072 // Give yui enough XRP to meet the trust line's reserve. Cashing
-
2073 // the check succeeds and creates the trust line.
-
2074 env(pay(env.master, yui, XRP(51)));
-
2075 env.close();
-
2076 env(check::cash(yui, chkId, CK8(99)));
-
2077 verifyDeliveredAmount(env, CK8(99));
-
2078 env.close();
-
2079 BEAST_EXPECT(ownerCount(env, yui) == 1);
-
2080
-
2081 // The automatic trust line does not take a reserve from gw1.
-
2082 // Since gw1's check was consumed it has no owners.
-
2083 gw1.verifyOwners(__LINE__);
-
2084 }
-
2085
-
2086 // We'll be looking at the effects of various account root flags.
-
2087
-
2088 // Automatically create trust lines using
-
2089 // o Offers and
-
2090 // o Check cashing
-
2091 // Compare the resulting trust lines and expect them to be very similar.
-
2092
-
2093 // Lambda that compares two trust lines created by
-
2094 // o Offer crossing and
-
2095 // o Check cashing
-
2096 // between the same two accounts but with two different currencies.
-
2097 // The lambda expects the two trust lines to be largely similar.
-
2098 auto cmpTrustLines = [this, &env](
-
2099 Account const& acct1,
-
2100 Account const& acct2,
-
2101 IOU const& offerIou,
-
2102 IOU const& checkIou) {
-
2103 auto const offerLine =
-
2104 env.le(keylet::line(acct1, acct2, offerIou.currency));
-
2105 auto const checkLine =
-
2106 env.le(keylet::line(acct1, acct2, checkIou.currency));
-
2107 if (offerLine == nullptr || checkLine == nullptr)
-
2108 {
-
2109 BEAST_EXPECT(offerLine == nullptr && checkLine == nullptr);
-
2110 return;
-
2111 }
-
2112
-
2113 {
-
2114 // Compare the contents of required fields.
-
2115 BEAST_EXPECT(offerLine->at(sfFlags) == checkLine->at(sfFlags));
-
2116
-
2117 // Lambda that compares the contents of required STAmounts
-
2118 // without comparing the currency.
-
2119 auto cmpReqAmount =
-
2120 [this, offerLine, checkLine](SF_AMOUNT const& sfield) {
-
2121 STAmount const offerAmount = offerLine->at(sfield);
-
2122 STAmount const checkAmount = checkLine->at(sfield);
+
1982 // Fund with noripple so the accounts do not have any flags set.
+
1983 env.fund(XRP(5000), noripple(alice, bob));
+
1984 env.close();
+
1985
+
1986 // Automatic trust line creation should fail if the check destination
+
1987 // can't afford the reserve for the trust line.
+
1988 {
+
1989 AccountOwns gw1{*this, env, "gw1", 0};
+
1990
+
1991 // Fund gw1 with noripple (even though that's atypical for a
+
1992 // gateway) so it does not have any flags set. We'll set flags
+
1993 // on gw1 later.
+
1994 env.fund(XRP(5000), noripple(gw1));
+
1995 env.close();
+
1996
+
1997 IOU const CK8 = gw1["CK8"];
+
1998 gw1.verifyOwners(__LINE__);
+
1999
+
2000 Account const yui{"yui"};
+
2001
+
2002 // Note the reserve in unit tests is 200 XRP, not 20. So here
+
2003 // we're just barely giving yui enough XRP to meet the
+
2004 // account reserve.
+
2005 env.fund(XRP(200), yui);
+
2006 env.close();
+
2007
+
2008 uint256 const chkId{getCheckIndex(gw1, env.seq(gw1))};
+
2009 env(check::create(gw1, yui, CK8(99)));
+
2010 env.close();
+
2011
+
2012 env(check::cash(yui, chkId, CK8(99)),
+ +
2014 env.close();
+
2015 alice.verifyOwners(__LINE__);
+
2016
+
2017 // Give yui enough XRP to meet the trust line's reserve. Cashing
+
2018 // the check succeeds and creates the trust line.
+
2019 env(pay(env.master, yui, XRP(51)));
+
2020 env.close();
+
2021 env(check::cash(yui, chkId, CK8(99)));
+
2022 verifyDeliveredAmount(env, CK8(99));
+
2023 env.close();
+
2024 BEAST_EXPECT(ownerCount(env, yui) == 1);
+
2025
+
2026 // The automatic trust line does not take a reserve from gw1.
+
2027 // Since gw1's check was consumed it has no owners.
+
2028 gw1.verifyOwners(__LINE__);
+
2029 }
+
2030
+
2031 // We'll be looking at the effects of various account root flags.
+
2032
+
2033 // Automatically create trust lines using
+
2034 // o Offers and
+
2035 // o Check cashing
+
2036 // Compare the resulting trust lines and expect them to be very similar.
+
2037
+
2038 // Lambda that compares two trust lines created by
+
2039 // o Offer crossing and
+
2040 // o Check cashing
+
2041 // between the same two accounts but with two different currencies.
+
2042 // The lambda expects the two trust lines to be largely similar.
+
2043 auto cmpTrustLines = [this, &env](
+
2044 Account const& acct1,
+
2045 Account const& acct2,
+
2046 IOU const& offerIou,
+
2047 IOU const& checkIou) {
+
2048 auto const offerLine =
+
2049 env.le(keylet::line(acct1, acct2, offerIou.currency));
+
2050 auto const checkLine =
+
2051 env.le(keylet::line(acct1, acct2, checkIou.currency));
+
2052 if (offerLine == nullptr || checkLine == nullptr)
+
2053 {
+
2054 BEAST_EXPECT(offerLine == nullptr && checkLine == nullptr);
+
2055 return;
+
2056 }
+
2057
+
2058 {
+
2059 // Compare the contents of required fields.
+
2060 BEAST_EXPECT(offerLine->at(sfFlags) == checkLine->at(sfFlags));
+
2061
+
2062 // Lambda that compares the contents of required STAmounts
+
2063 // without comparing the currency.
+
2064 auto cmpReqAmount =
+
2065 [this, offerLine, checkLine](SF_AMOUNT const& sfield) {
+
2066 STAmount const offerAmount = offerLine->at(sfield);
+
2067 STAmount const checkAmount = checkLine->at(sfield);
+
2068
+
2069 // Neither STAmount should be native.
+
2070 if (!BEAST_EXPECT(
+
2071 !offerAmount.native() && !checkAmount.native()))
+
2072 return;
+
2073
+
2074 BEAST_EXPECT(
+
2075 offerAmount.issue().account ==
+
2076 checkAmount.issue().account);
+
2077 BEAST_EXPECT(
+
2078 offerAmount.negative() == checkAmount.negative());
+
2079 BEAST_EXPECT(
+
2080 offerAmount.mantissa() == checkAmount.mantissa());
+
2081 BEAST_EXPECT(
+
2082 offerAmount.exponent() == checkAmount.exponent());
+
2083 };
+
2084 cmpReqAmount(sfBalance);
+
2085 cmpReqAmount(sfLowLimit);
+
2086 cmpReqAmount(sfHighLimit);
+
2087 }
+
2088 {
+
2089 // Lambda that compares the contents of optional fields.
+
2090 auto cmpOptField =
+
2091 [this, offerLine, checkLine](auto const& sfield) {
+
2092 // Expect both fields to either be present or absent.
+
2093 if (!BEAST_EXPECT(
+
2094 offerLine->isFieldPresent(sfield) ==
+
2095 checkLine->isFieldPresent(sfield)))
+
2096 return;
+
2097
+
2098 // If both fields are absent then there's nothing
+
2099 // further to check.
+
2100 if (!offerLine->isFieldPresent(sfield))
+
2101 return;
+
2102
+
2103 // Both optional fields are present so we can compare
+
2104 // them.
+
2105 BEAST_EXPECT(
+
2106 offerLine->at(sfield) == checkLine->at(sfield));
+
2107 };
+
2108 cmpOptField(sfLowNode);
+
2109 cmpOptField(sfLowQualityIn);
+
2110 cmpOptField(sfLowQualityOut);
+
2111
+
2112 cmpOptField(sfHighNode);
+
2113 cmpOptField(sfHighQualityIn);
+
2114 cmpOptField(sfHighQualityOut);
+
2115 }
+
2116 };
+
2117
+
2118 //----------- No account root flags, check written by issuer -----------
+
2119 {
+
2120 // No account root flags on any participant.
+
2121 // Automatic trust line from issuer to destination.
+
2122 AccountOwns gw1{*this, env, "gw1", 0};
2123
-
2124 // Neither STAmount should be native.
-
2125 if (!BEAST_EXPECT(
-
2126 !offerAmount.native() && !checkAmount.native()))
-
2127 return;
-
2128
-
2129 BEAST_EXPECT(
-
2130 offerAmount.issue().account ==
-
2131 checkAmount.issue().account);
-
2132 BEAST_EXPECT(
-
2133 offerAmount.negative() == checkAmount.negative());
-
2134 BEAST_EXPECT(
-
2135 offerAmount.mantissa() == checkAmount.mantissa());
-
2136 BEAST_EXPECT(
-
2137 offerAmount.exponent() == checkAmount.exponent());
-
2138 };
-
2139 cmpReqAmount(sfBalance);
-
2140 cmpReqAmount(sfLowLimit);
-
2141 cmpReqAmount(sfHighLimit);
-
2142 }
-
2143 {
-
2144 // Lambda that compares the contents of optional fields.
-
2145 auto cmpOptField =
-
2146 [this, offerLine, checkLine](auto const& sfield) {
-
2147 // Expect both fields to either be present or absent.
-
2148 if (!BEAST_EXPECT(
-
2149 offerLine->isFieldPresent(sfield) ==
-
2150 checkLine->isFieldPresent(sfield)))
-
2151 return;
-
2152
-
2153 // If both fields are absent then there's nothing
-
2154 // further to check.
-
2155 if (!offerLine->isFieldPresent(sfield))
-
2156 return;
+
2124 BEAST_EXPECT((*env.le(gw1))[sfFlags] == 0);
+
2125 BEAST_EXPECT((*env.le(alice))[sfFlags] == 0);
+
2126 BEAST_EXPECT((*env.le(bob))[sfFlags] == 0);
+
2127
+
2128 // Use offers to automatically create the trust line.
+
2129 IOU const OF1 = gw1["OF1"];
+
2130 env(offer(gw1, XRP(98), OF1(98)));
+
2131 env.close();
+
2132 BEAST_EXPECT(
+
2133 env.le(keylet::line(gw1, alice, OF1.currency)) == nullptr);
+
2134 env(offer(alice, OF1(98), XRP(98)));
+
2135 ++alice.owners;
+
2136 env.close();
+
2137
+
2138 // Both offers should be consumed.
+
2139 // Since gw1's offer was consumed and the trust line was not
+
2140 // created by gw1, gw1's owner count should be 0.
+
2141 gw1.verifyOwners(__LINE__);
+
2142
+
2143 // alice's automatically created trust line bumps her owner count.
+
2144 alice.verifyOwners(__LINE__);
+
2145
+
2146 // Use check cashing to automatically create the trust line.
+
2147 IOU const CK1 = gw1["CK1"];
+
2148 uint256 const chkId{getCheckIndex(gw1, env.seq(gw1))};
+
2149 env(check::create(gw1, alice, CK1(98)));
+
2150 env.close();
+
2151 BEAST_EXPECT(
+
2152 env.le(keylet::line(gw1, alice, CK1.currency)) == nullptr);
+
2153 env(check::cash(alice, chkId, CK1(98)));
+
2154 ++alice.owners;
+
2155 verifyDeliveredAmount(env, CK1(98));
+
2156 env.close();
2157
-
2158 // Both optional fields are present so we can compare
-
2159 // them.
-
2160 BEAST_EXPECT(
-
2161 offerLine->at(sfield) == checkLine->at(sfield));
-
2162 };
-
2163 cmpOptField(sfLowNode);
-
2164 cmpOptField(sfLowQualityIn);
-
2165 cmpOptField(sfLowQualityOut);
-
2166
-
2167 cmpOptField(sfHighNode);
-
2168 cmpOptField(sfHighQualityIn);
-
2169 cmpOptField(sfHighQualityOut);
-
2170 }
-
2171 };
+
2158 // gw1's check should be consumed.
+
2159 // Since gw1's check was consumed and the trust line was not
+
2160 // created by gw1, gw1's owner count should be 0.
+
2161 gw1.verifyOwners(__LINE__);
+
2162
+
2163 // alice's automatically created trust line bumps her owner count.
+
2164 alice.verifyOwners(__LINE__);
+
2165
+
2166 cmpTrustLines(gw1, alice, OF1, CK1);
+
2167 }
+
2168 //--------- No account root flags, check written by non-issuer ---------
+
2169 {
+
2170 // No account root flags on any participant.
+
2171 // Automatic trust line from non-issuer to non-issuer.
2172
-
2173 //----------- No account root flags, check written by issuer -----------
-
2174 {
-
2175 // No account root flags on any participant.
-
2176 // Automatic trust line from issuer to destination.
+
2173 // Use offers to automatically create the trust line.
+
2174 // Transfer of assets using offers does not require rippling.
+
2175 // So bob's offer is successfully crossed which creates the
+
2176 // trust line.
2177 AccountOwns gw1{*this, env, "gw1", 0};
-
2178
-
2179 BEAST_EXPECT((*env.le(gw1))[sfFlags] == 0);
-
2180 BEAST_EXPECT((*env.le(alice))[sfFlags] == 0);
-
2181 BEAST_EXPECT((*env.le(bob))[sfFlags] == 0);
-
2182
-
2183 // Use offers to automatically create the trust line.
-
2184 IOU const OF1 = gw1["OF1"];
-
2185 env(offer(gw1, XRP(98), OF1(98)));
-
2186 env.close();
-
2187 BEAST_EXPECT(
-
2188 env.le(keylet::line(gw1, alice, OF1.currency)) == nullptr);
-
2189 env(offer(alice, OF1(98), XRP(98)));
-
2190 ++alice.owners;
-
2191 env.close();
-
2192
-
2193 // Both offers should be consumed.
-
2194 // Since gw1's offer was consumed and the trust line was not
-
2195 // created by gw1, gw1's owner count should be 0.
-
2196 gw1.verifyOwners(__LINE__);
-
2197
-
2198 // alice's automatically created trust line bumps her owner count.
-
2199 alice.verifyOwners(__LINE__);
-
2200
-
2201 // Use check cashing to automatically create the trust line.
+
2178 IOU const OF1 = gw1["OF1"];
+
2179 env(offer(alice, XRP(97), OF1(97)));
+
2180 env.close();
+
2181 BEAST_EXPECT(
+
2182 env.le(keylet::line(alice, bob, OF1.currency)) == nullptr);
+
2183 env(offer(bob, OF1(97), XRP(97)));
+
2184 ++bob.owners;
+
2185 env.close();
+
2186
+
2187 // Both offers should be consumed.
+
2188 env.require(balance(alice, OF1(1)));
+
2189 env.require(balance(bob, OF1(97)));
+
2190
+
2191 // bob now has an owner count of 1 due to the new trust line.
+
2192 gw1.verifyOwners(__LINE__);
+
2193 alice.verifyOwners(__LINE__);
+
2194 bob.verifyOwners(__LINE__);
+
2195
+
2196 // Use check cashing to automatically create the trust line.
+
2197 //
+
2198 // However cashing a check (unlike crossing offers) requires
+
2199 // rippling through the currency's issuer. Since gw1 does not
+
2200 // have rippling enabled the check cash fails and bob does not
+
2201 // have a trust line created.
2202 IOU const CK1 = gw1["CK1"];
-
2203 uint256 const chkId{getCheckIndex(gw1, env.seq(gw1))};
-
2204 env(check::create(gw1, alice, CK1(98)));
+
2203 uint256 const chkId{getCheckIndex(alice, env.seq(alice))};
+
2204 env(check::create(alice, bob, CK1(97)));
2205 env.close();
2206 BEAST_EXPECT(
-
2207 env.le(keylet::line(gw1, alice, CK1.currency)) == nullptr);
-
2208 env(check::cash(alice, chkId, CK1(98)));
-
2209 ++alice.owners;
-
2210 verifyDeliveredAmount(env, CK1(98));
-
2211 env.close();
-
2212
-
2213 // gw1's check should be consumed.
-
2214 // Since gw1's check was consumed and the trust line was not
-
2215 // created by gw1, gw1's owner count should be 0.
-
2216 gw1.verifyOwners(__LINE__);
-
2217
-
2218 // alice's automatically created trust line bumps her owner count.
-
2219 alice.verifyOwners(__LINE__);
-
2220
-
2221 cmpTrustLines(gw1, alice, OF1, CK1);
-
2222 }
-
2223 //--------- No account root flags, check written by non-issuer ---------
-
2224 {
-
2225 // No account root flags on any participant.
-
2226 // Automatic trust line from non-issuer to non-issuer.
-
2227
-
2228 // Use offers to automatically create the trust line.
-
2229 // Transfer of assets using offers does not require rippling.
-
2230 // So bob's offer is successfully crossed which creates the
-
2231 // trust line.
-
2232 AccountOwns gw1{*this, env, "gw1", 0};
-
2233 IOU const OF1 = gw1["OF1"];
-
2234 env(offer(alice, XRP(97), OF1(97)));
-
2235 env.close();
-
2236 BEAST_EXPECT(
-
2237 env.le(keylet::line(alice, bob, OF1.currency)) == nullptr);
-
2238 env(offer(bob, OF1(97), XRP(97)));
-
2239 ++bob.owners;
-
2240 env.close();
-
2241
-
2242 // Both offers should be consumed.
-
2243 env.require(balance(alice, OF1(1)));
-
2244 env.require(balance(bob, OF1(97)));
-
2245
-
2246 // bob now has an owner count of 1 due to the new trust line.
+
2207 env.le(keylet::line(alice, bob, CK1.currency)) == nullptr);
+
2208 env(check::cash(bob, chkId, CK1(97)), ter(terNO_RIPPLE));
+
2209 env.close();
+
2210
+
2211 BEAST_EXPECT(
+
2212 env.le(keylet::line(gw1, bob, OF1.currency)) != nullptr);
+
2213 BEAST_EXPECT(
+
2214 env.le(keylet::line(gw1, bob, CK1.currency)) == nullptr);
+
2215
+
2216 // Delete alice's check since it is no longer needed.
+
2217 env(check::cancel(alice, chkId));
+
2218 env.close();
+
2219
+
2220 // No one's owner count should have changed.
+
2221 gw1.verifyOwners(__LINE__);
+
2222 alice.verifyOwners(__LINE__);
+
2223 bob.verifyOwners(__LINE__);
+
2224 }
+
2225
+
2226 //------------- lsfDefaultRipple, check written by issuer --------------
+
2227 {
+
2228 // gw1 enables rippling.
+
2229 // Automatic trust line from issuer to non-issuer should still work.
+
2230 AccountOwns gw1{*this, env, "gw1", 0};
+
2231 env(fset(gw1, asfDefaultRipple));
+
2232 env.close();
+
2233
+
2234 // Use offers to automatically create the trust line.
+
2235 IOU const OF2 = gw1["OF2"];
+
2236 env(offer(gw1, XRP(96), OF2(96)));
+
2237 env.close();
+
2238 BEAST_EXPECT(
+
2239 env.le(keylet::line(gw1, alice, OF2.currency)) == nullptr);
+
2240 env(offer(alice, OF2(96), XRP(96)));
+
2241 ++alice.owners;
+
2242 env.close();
+
2243
+
2244 // Both offers should be consumed.
+
2245 // Since gw1's offer was consumed and the trust line was not
+
2246 // created by gw1, gw1's owner count should still be 0.
2247 gw1.verifyOwners(__LINE__);
-
2248 alice.verifyOwners(__LINE__);
-
2249 bob.verifyOwners(__LINE__);
-
2250
-
2251 // Use check cashing to automatically create the trust line.
-
2252 //
-
2253 // However cashing a check (unlike crossing offers) requires
-
2254 // rippling through the currency's issuer. Since gw1 does not
-
2255 // have rippling enabled the check cash fails and bob does not
-
2256 // have a trust line created.
-
2257 IOU const CK1 = gw1["CK1"];
-
2258 uint256 const chkId{getCheckIndex(alice, env.seq(alice))};
-
2259 env(check::create(alice, bob, CK1(97)));
-
2260 env.close();
-
2261 BEAST_EXPECT(
-
2262 env.le(keylet::line(alice, bob, CK1.currency)) == nullptr);
-
2263 env(check::cash(bob, chkId, CK1(97)), ter(terNO_RIPPLE));
-
2264 env.close();
-
2265
-
2266 BEAST_EXPECT(
-
2267 env.le(keylet::line(gw1, bob, OF1.currency)) != nullptr);
-
2268 BEAST_EXPECT(
-
2269 env.le(keylet::line(gw1, bob, CK1.currency)) == nullptr);
-
2270
-
2271 // Delete alice's check since it is no longer needed.
-
2272 env(check::cancel(alice, chkId));
-
2273 env.close();
-
2274
-
2275 // No one's owner count should have changed.
-
2276 gw1.verifyOwners(__LINE__);
-
2277 alice.verifyOwners(__LINE__);
-
2278 bob.verifyOwners(__LINE__);
-
2279 }
-
2280
-
2281 //------------- lsfDefaultRipple, check written by issuer --------------
-
2282 {
-
2283 // gw1 enables rippling.
-
2284 // Automatic trust line from issuer to non-issuer should still work.
-
2285 AccountOwns gw1{*this, env, "gw1", 0};
-
2286 env(fset(gw1, asfDefaultRipple));
-
2287 env.close();
-
2288
-
2289 // Use offers to automatically create the trust line.
-
2290 IOU const OF2 = gw1["OF2"];
-
2291 env(offer(gw1, XRP(96), OF2(96)));
-
2292 env.close();
-
2293 BEAST_EXPECT(
-
2294 env.le(keylet::line(gw1, alice, OF2.currency)) == nullptr);
-
2295 env(offer(alice, OF2(96), XRP(96)));
-
2296 ++alice.owners;
-
2297 env.close();
-
2298
-
2299 // Both offers should be consumed.
-
2300 // Since gw1's offer was consumed and the trust line was not
-
2301 // created by gw1, gw1's owner count should still be 0.
-
2302 gw1.verifyOwners(__LINE__);
-
2303
-
2304 // alice's automatically created trust line bumps her owner count.
-
2305 alice.verifyOwners(__LINE__);
+
2248
+
2249 // alice's automatically created trust line bumps her owner count.
+
2250 alice.verifyOwners(__LINE__);
+
2251
+
2252 // Use check cashing to automatically create the trust line.
+
2253 IOU const CK2 = gw1["CK2"];
+
2254 uint256 const chkId{getCheckIndex(gw1, env.seq(gw1))};
+
2255 env(check::create(gw1, alice, CK2(96)));
+
2256 env.close();
+
2257 BEAST_EXPECT(
+
2258 env.le(keylet::line(gw1, alice, CK2.currency)) == nullptr);
+
2259 env(check::cash(alice, chkId, CK2(96)));
+
2260 ++alice.owners;
+
2261 verifyDeliveredAmount(env, CK2(96));
+
2262 env.close();
+
2263
+
2264 // gw1's check should be consumed.
+
2265 // Since gw1's check was consumed and the trust line was not
+
2266 // created by gw1, gw1's owner count should still be 0.
+
2267 gw1.verifyOwners(__LINE__);
+
2268
+
2269 // alice's automatically created trust line bumps her owner count.
+
2270 alice.verifyOwners(__LINE__);
+
2271
+
2272 cmpTrustLines(gw1, alice, OF2, CK2);
+
2273 }
+
2274 //----------- lsfDefaultRipple, check written by non-issuer ------------
+
2275 {
+
2276 // gw1 enabled rippling, so automatic trust line from non-issuer
+
2277 // to non-issuer should work.
+
2278
+
2279 // Use offers to automatically create the trust line.
+
2280 AccountOwns gw1{*this, env, "gw1", 0};
+
2281 IOU const OF2 = gw1["OF2"];
+
2282 env(offer(alice, XRP(95), OF2(95)));
+
2283 env.close();
+
2284 BEAST_EXPECT(
+
2285 env.le(keylet::line(alice, bob, OF2.currency)) == nullptr);
+
2286 env(offer(bob, OF2(95), XRP(95)));
+
2287 ++bob.owners;
+
2288 env.close();
+
2289
+
2290 // bob's owner count should increase due to the new trust line.
+
2291 gw1.verifyOwners(__LINE__);
+
2292 alice.verifyOwners(__LINE__);
+
2293 bob.verifyOwners(__LINE__);
+
2294
+
2295 // Use check cashing to automatically create the trust line.
+
2296 IOU const CK2 = gw1["CK2"];
+
2297 uint256 const chkId{getCheckIndex(alice, env.seq(alice))};
+
2298 env(check::create(alice, bob, CK2(95)));
+
2299 env.close();
+
2300 BEAST_EXPECT(
+
2301 env.le(keylet::line(alice, bob, CK2.currency)) == nullptr);
+
2302 env(check::cash(bob, chkId, CK2(95)));
+
2303 ++bob.owners;
+
2304 verifyDeliveredAmount(env, CK2(95));
+
2305 env.close();
2306
-
2307 // Use check cashing to automatically create the trust line.
-
2308 IOU const CK2 = gw1["CK2"];
-
2309 uint256 const chkId{getCheckIndex(gw1, env.seq(gw1))};
-
2310 env(check::create(gw1, alice, CK2(96)));
-
2311 env.close();
-
2312 BEAST_EXPECT(
-
2313 env.le(keylet::line(gw1, alice, CK2.currency)) == nullptr);
-
2314 env(check::cash(alice, chkId, CK2(96)));
-
2315 ++alice.owners;
-
2316 verifyDeliveredAmount(env, CK2(96));
-
2317 env.close();
-
2318
-
2319 // gw1's check should be consumed.
-
2320 // Since gw1's check was consumed and the trust line was not
-
2321 // created by gw1, gw1's owner count should still be 0.
-
2322 gw1.verifyOwners(__LINE__);
-
2323
-
2324 // alice's automatically created trust line bumps her owner count.
-
2325 alice.verifyOwners(__LINE__);
-
2326
-
2327 cmpTrustLines(gw1, alice, OF2, CK2);
-
2328 }
-
2329 //----------- lsfDefaultRipple, check written by non-issuer ------------
-
2330 {
-
2331 // gw1 enabled rippling, so automatic trust line from non-issuer
-
2332 // to non-issuer should work.
-
2333
-
2334 // Use offers to automatically create the trust line.
-
2335 AccountOwns gw1{*this, env, "gw1", 0};
-
2336 IOU const OF2 = gw1["OF2"];
-
2337 env(offer(alice, XRP(95), OF2(95)));
-
2338 env.close();
-
2339 BEAST_EXPECT(
-
2340 env.le(keylet::line(alice, bob, OF2.currency)) == nullptr);
-
2341 env(offer(bob, OF2(95), XRP(95)));
-
2342 ++bob.owners;
-
2343 env.close();
-
2344
-
2345 // bob's owner count should increase due to the new trust line.
-
2346 gw1.verifyOwners(__LINE__);
-
2347 alice.verifyOwners(__LINE__);
-
2348 bob.verifyOwners(__LINE__);
-
2349
-
2350 // Use check cashing to automatically create the trust line.
-
2351 IOU const CK2 = gw1["CK2"];
-
2352 uint256 const chkId{getCheckIndex(alice, env.seq(alice))};
-
2353 env(check::create(alice, bob, CK2(95)));
-
2354 env.close();
-
2355 BEAST_EXPECT(
-
2356 env.le(keylet::line(alice, bob, CK2.currency)) == nullptr);
-
2357 env(check::cash(bob, chkId, CK2(95)));
-
2358 ++bob.owners;
-
2359 verifyDeliveredAmount(env, CK2(95));
-
2360 env.close();
-
2361
-
2362 // bob's owner count should increase due to the new trust line.
-
2363 gw1.verifyOwners(__LINE__);
-
2364 alice.verifyOwners(__LINE__);
-
2365 bob.verifyOwners(__LINE__);
+
2307 // bob's owner count should increase due to the new trust line.
+
2308 gw1.verifyOwners(__LINE__);
+
2309 alice.verifyOwners(__LINE__);
+
2310 bob.verifyOwners(__LINE__);
+
2311
+
2312 cmpTrustLines(alice, bob, OF2, CK2);
+
2313 }
+
2314
+
2315 //-------------- lsfDepositAuth, check written by issuer ---------------
+
2316 {
+
2317 // Both offers and checks ignore the lsfDepositAuth flag, since
+
2318 // the destination signs the transaction that delivers their funds.
+
2319 // So setting lsfDepositAuth on all the participants should not
+
2320 // change any outcomes.
+
2321 //
+
2322 // Automatic trust line from issuer to non-issuer should still work.
+
2323 AccountOwns gw1{*this, env, "gw1", 0};
+
2324 env(fset(gw1, asfDepositAuth));
+
2325 env(fset(alice, asfDepositAuth));
+
2326 env(fset(bob, asfDepositAuth));
+
2327 env.close();
+
2328
+
2329 // Use offers to automatically create the trust line.
+
2330 IOU const OF3 = gw1["OF3"];
+
2331 env(offer(gw1, XRP(94), OF3(94)));
+
2332 env.close();
+
2333 BEAST_EXPECT(
+
2334 env.le(keylet::line(gw1, alice, OF3.currency)) == nullptr);
+
2335 env(offer(alice, OF3(94), XRP(94)));
+
2336 ++alice.owners;
+
2337 env.close();
+
2338
+
2339 // Both offers should be consumed.
+
2340 // Since gw1's offer was consumed and the trust line was not
+
2341 // created by gw1, gw1's owner count should still be 0.
+
2342 gw1.verifyOwners(__LINE__);
+
2343
+
2344 // alice's automatically created trust line bumps her owner count.
+
2345 alice.verifyOwners(__LINE__);
+
2346
+
2347 // Use check cashing to automatically create the trust line.
+
2348 IOU const CK3 = gw1["CK3"];
+
2349 uint256 const chkId{getCheckIndex(gw1, env.seq(gw1))};
+
2350 env(check::create(gw1, alice, CK3(94)));
+
2351 env.close();
+
2352 BEAST_EXPECT(
+
2353 env.le(keylet::line(gw1, alice, CK3.currency)) == nullptr);
+
2354 env(check::cash(alice, chkId, CK3(94)));
+
2355 ++alice.owners;
+
2356 verifyDeliveredAmount(env, CK3(94));
+
2357 env.close();
+
2358
+
2359 // gw1's check should be consumed.
+
2360 // Since gw1's check was consumed and the trust line was not
+
2361 // created by gw1, gw1's owner count should still be 0.
+
2362 gw1.verifyOwners(__LINE__);
+
2363
+
2364 // alice's automatically created trust line bumps her owner count.
+
2365 alice.verifyOwners(__LINE__);
2366
-
2367 cmpTrustLines(alice, bob, OF2, CK2);
+
2367 cmpTrustLines(gw1, alice, OF3, CK3);
2368 }
-
2369
-
2370 //-------------- lsfDepositAuth, check written by issuer ---------------
-
2371 {
-
2372 // Both offers and checks ignore the lsfDepositAuth flag, since
-
2373 // the destination signs the transaction that delivers their funds.
-
2374 // So setting lsfDepositAuth on all the participants should not
-
2375 // change any outcomes.
-
2376 //
-
2377 // Automatic trust line from issuer to non-issuer should still work.
-
2378 AccountOwns gw1{*this, env, "gw1", 0};
-
2379 env(fset(gw1, asfDepositAuth));
-
2380 env(fset(alice, asfDepositAuth));
-
2381 env(fset(bob, asfDepositAuth));
-
2382 env.close();
-
2383
-
2384 // Use offers to automatically create the trust line.
-
2385 IOU const OF3 = gw1["OF3"];
-
2386 env(offer(gw1, XRP(94), OF3(94)));
-
2387 env.close();
-
2388 BEAST_EXPECT(
-
2389 env.le(keylet::line(gw1, alice, OF3.currency)) == nullptr);
-
2390 env(offer(alice, OF3(94), XRP(94)));
-
2391 ++alice.owners;
-
2392 env.close();
-
2393
-
2394 // Both offers should be consumed.
-
2395 // Since gw1's offer was consumed and the trust line was not
-
2396 // created by gw1, gw1's owner count should still be 0.
-
2397 gw1.verifyOwners(__LINE__);
-
2398
-
2399 // alice's automatically created trust line bumps her owner count.
-
2400 alice.verifyOwners(__LINE__);
+
2369 //------------ lsfDepositAuth, check written by non-issuer -------------
+
2370 {
+
2371 // The presence of the lsfDepositAuth flag should not affect
+
2372 // automatic trust line creation.
+
2373
+
2374 // Use offers to automatically create the trust line.
+
2375 AccountOwns gw1{*this, env, "gw1", 0};
+
2376 IOU const OF3 = gw1["OF3"];
+
2377 env(offer(alice, XRP(93), OF3(93)));
+
2378 env.close();
+
2379 BEAST_EXPECT(
+
2380 env.le(keylet::line(alice, bob, OF3.currency)) == nullptr);
+
2381 env(offer(bob, OF3(93), XRP(93)));
+
2382 ++bob.owners;
+
2383 env.close();
+
2384
+
2385 // bob's owner count should increase due to the new trust line.
+
2386 gw1.verifyOwners(__LINE__);
+
2387 alice.verifyOwners(__LINE__);
+
2388 bob.verifyOwners(__LINE__);
+
2389
+
2390 // Use check cashing to automatically create the trust line.
+
2391 IOU const CK3 = gw1["CK3"];
+
2392 uint256 const chkId{getCheckIndex(alice, env.seq(alice))};
+
2393 env(check::create(alice, bob, CK3(93)));
+
2394 env.close();
+
2395 BEAST_EXPECT(
+
2396 env.le(keylet::line(alice, bob, CK3.currency)) == nullptr);
+
2397 env(check::cash(bob, chkId, CK3(93)));
+
2398 ++bob.owners;
+
2399 verifyDeliveredAmount(env, CK3(93));
+
2400 env.close();
2401
-
2402 // Use check cashing to automatically create the trust line.
-
2403 IOU const CK3 = gw1["CK3"];
-
2404 uint256 const chkId{getCheckIndex(gw1, env.seq(gw1))};
-
2405 env(check::create(gw1, alice, CK3(94)));
-
2406 env.close();
-
2407 BEAST_EXPECT(
-
2408 env.le(keylet::line(gw1, alice, CK3.currency)) == nullptr);
-
2409 env(check::cash(alice, chkId, CK3(94)));
-
2410 ++alice.owners;
-
2411 verifyDeliveredAmount(env, CK3(94));
-
2412 env.close();
-
2413
-
2414 // gw1's check should be consumed.
-
2415 // Since gw1's check was consumed and the trust line was not
-
2416 // created by gw1, gw1's owner count should still be 0.
-
2417 gw1.verifyOwners(__LINE__);
-
2418
-
2419 // alice's automatically created trust line bumps her owner count.
-
2420 alice.verifyOwners(__LINE__);
-
2421
-
2422 cmpTrustLines(gw1, alice, OF3, CK3);
-
2423 }
-
2424 //------------ lsfDepositAuth, check written by non-issuer -------------
-
2425 {
-
2426 // The presence of the lsfDepositAuth flag should not affect
-
2427 // automatic trust line creation.
-
2428
-
2429 // Use offers to automatically create the trust line.
-
2430 AccountOwns gw1{*this, env, "gw1", 0};
-
2431 IOU const OF3 = gw1["OF3"];
-
2432 env(offer(alice, XRP(93), OF3(93)));
-
2433 env.close();
-
2434 BEAST_EXPECT(
-
2435 env.le(keylet::line(alice, bob, OF3.currency)) == nullptr);
-
2436 env(offer(bob, OF3(93), XRP(93)));
-
2437 ++bob.owners;
-
2438 env.close();
-
2439
-
2440 // bob's owner count should increase due to the new trust line.
-
2441 gw1.verifyOwners(__LINE__);
-
2442 alice.verifyOwners(__LINE__);
-
2443 bob.verifyOwners(__LINE__);
-
2444
-
2445 // Use check cashing to automatically create the trust line.
-
2446 IOU const CK3 = gw1["CK3"];
-
2447 uint256 const chkId{getCheckIndex(alice, env.seq(alice))};
-
2448 env(check::create(alice, bob, CK3(93)));
-
2449 env.close();
-
2450 BEAST_EXPECT(
-
2451 env.le(keylet::line(alice, bob, CK3.currency)) == nullptr);
-
2452 env(check::cash(bob, chkId, CK3(93)));
-
2453 ++bob.owners;
-
2454 verifyDeliveredAmount(env, CK3(93));
-
2455 env.close();
-
2456
-
2457 // bob's owner count should increase due to the new trust line.
-
2458 gw1.verifyOwners(__LINE__);
-
2459 alice.verifyOwners(__LINE__);
-
2460 bob.verifyOwners(__LINE__);
-
2461
-
2462 cmpTrustLines(alice, bob, OF3, CK3);
-
2463 }
-
2464
-
2465 //-------------- lsfGlobalFreeze, check written by issuer --------------
-
2466 {
-
2467 // Set lsfGlobalFreeze on gw1. That should stop any automatic
-
2468 // trust lines from being created.
-
2469 AccountOwns gw1{*this, env, "gw1", 0};
-
2470 env(fset(gw1, asfGlobalFreeze));
-
2471 env.close();
-
2472
-
2473 // Use offers to automatically create the trust line.
-
2474 IOU const OF4 = gw1["OF4"];
-
2475 env(offer(gw1, XRP(92), OF4(92)), ter(tecFROZEN));
-
2476 env.close();
-
2477 BEAST_EXPECT(
-
2478 env.le(keylet::line(gw1, alice, OF4.currency)) == nullptr);
-
2479 env(offer(alice, OF4(92), XRP(92)), ter(tecFROZEN));
-
2480 env.close();
-
2481
-
2482 // No one's owner count should have changed.
-
2483 gw1.verifyOwners(__LINE__);
-
2484 alice.verifyOwners(__LINE__);
-
2485 bob.verifyOwners(__LINE__);
-
2486
-
2487 // Use check cashing to automatically create the trust line.
-
2488 IOU const CK4 = gw1["CK4"];
-
2489 uint256 const chkId{getCheckIndex(gw1, env.seq(gw1))};
-
2490 env(check::create(gw1, alice, CK4(92)), ter(tecFROZEN));
-
2491 env.close();
-
2492 BEAST_EXPECT(
-
2493 env.le(keylet::line(gw1, alice, CK4.currency)) == nullptr);
-
2494 env(check::cash(alice, chkId, CK4(92)), ter(tecNO_ENTRY));
-
2495 env.close();
+
2402 // bob's owner count should increase due to the new trust line.
+
2403 gw1.verifyOwners(__LINE__);
+
2404 alice.verifyOwners(__LINE__);
+
2405 bob.verifyOwners(__LINE__);
+
2406
+
2407 cmpTrustLines(alice, bob, OF3, CK3);
+
2408 }
+
2409
+
2410 //-------------- lsfGlobalFreeze, check written by issuer --------------
+
2411 {
+
2412 // Set lsfGlobalFreeze on gw1. That should stop any automatic
+
2413 // trust lines from being created.
+
2414 AccountOwns gw1{*this, env, "gw1", 0};
+
2415 env(fset(gw1, asfGlobalFreeze));
+
2416 env.close();
+
2417
+
2418 // Use offers to automatically create the trust line.
+
2419 IOU const OF4 = gw1["OF4"];
+
2420 env(offer(gw1, XRP(92), OF4(92)), ter(tecFROZEN));
+
2421 env.close();
+
2422 BEAST_EXPECT(
+
2423 env.le(keylet::line(gw1, alice, OF4.currency)) == nullptr);
+
2424 env(offer(alice, OF4(92), XRP(92)), ter(tecFROZEN));
+
2425 env.close();
+
2426
+
2427 // No one's owner count should have changed.
+
2428 gw1.verifyOwners(__LINE__);
+
2429 alice.verifyOwners(__LINE__);
+
2430 bob.verifyOwners(__LINE__);
+
2431
+
2432 // Use check cashing to automatically create the trust line.
+
2433 IOU const CK4 = gw1["CK4"];
+
2434 uint256 const chkId{getCheckIndex(gw1, env.seq(gw1))};
+
2435 env(check::create(gw1, alice, CK4(92)), ter(tecFROZEN));
+
2436 env.close();
+
2437 BEAST_EXPECT(
+
2438 env.le(keylet::line(gw1, alice, CK4.currency)) == nullptr);
+
2439 env(check::cash(alice, chkId, CK4(92)), ter(tecNO_ENTRY));
+
2440 env.close();
+
2441
+
2442 // No one's owner count should have changed.
+
2443 gw1.verifyOwners(__LINE__);
+
2444 alice.verifyOwners(__LINE__);
+
2445 bob.verifyOwners(__LINE__);
+
2446
+
2447 // Because gw1 has set lsfGlobalFreeze, neither trust line
+
2448 // is created.
+
2449 BEAST_EXPECT(
+
2450 env.le(keylet::line(gw1, alice, OF4.currency)) == nullptr);
+
2451 BEAST_EXPECT(
+
2452 env.le(keylet::line(gw1, alice, CK4.currency)) == nullptr);
+
2453 }
+
2454 //------------ lsfGlobalFreeze, check written by non-issuer ------------
+
2455 {
+
2456 // Since gw1 has the lsfGlobalFreeze flag set, there should be
+
2457 // no automatic trust line creation between non-issuers.
+
2458
+
2459 // Use offers to automatically create the trust line.
+
2460 AccountOwns gw1{*this, env, "gw1", 0};
+
2461 IOU const OF4 = gw1["OF4"];
+
2462 env(offer(alice, XRP(91), OF4(91)), ter(tecFROZEN));
+
2463 env.close();
+
2464 BEAST_EXPECT(
+
2465 env.le(keylet::line(alice, bob, OF4.currency)) == nullptr);
+
2466 env(offer(bob, OF4(91), XRP(91)), ter(tecFROZEN));
+
2467 env.close();
+
2468
+
2469 // No one's owner count should have changed.
+
2470 gw1.verifyOwners(__LINE__);
+
2471 alice.verifyOwners(__LINE__);
+
2472 bob.verifyOwners(__LINE__);
+
2473
+
2474 // Use check cashing to automatically create the trust line.
+
2475 IOU const CK4 = gw1["CK4"];
+
2476 uint256 const chkId{getCheckIndex(alice, env.seq(alice))};
+
2477 env(check::create(alice, bob, CK4(91)), ter(tecFROZEN));
+
2478 env.close();
+
2479 BEAST_EXPECT(
+
2480 env.le(keylet::line(alice, bob, CK4.currency)) == nullptr);
+
2481 env(check::cash(bob, chkId, CK4(91)), ter(tecNO_ENTRY));
+
2482 env.close();
+
2483
+
2484 // No one's owner count should have changed.
+
2485 gw1.verifyOwners(__LINE__);
+
2486 alice.verifyOwners(__LINE__);
+
2487 bob.verifyOwners(__LINE__);
+
2488
+
2489 // Because gw1 has set lsfGlobalFreeze, neither trust line
+
2490 // is created.
+
2491 BEAST_EXPECT(
+
2492 env.le(keylet::line(gw1, bob, OF4.currency)) == nullptr);
+
2493 BEAST_EXPECT(
+
2494 env.le(keylet::line(gw1, bob, CK4.currency)) == nullptr);
+
2495 }
2496
-
2497 // No one's owner count should have changed.
-
2498 gw1.verifyOwners(__LINE__);
-
2499 alice.verifyOwners(__LINE__);
-
2500 bob.verifyOwners(__LINE__);
-
2501
-
2502 // Because gw1 has set lsfGlobalFreeze, neither trust line
-
2503 // is created.
-
2504 BEAST_EXPECT(
-
2505 env.le(keylet::line(gw1, alice, OF4.currency)) == nullptr);
-
2506 BEAST_EXPECT(
-
2507 env.le(keylet::line(gw1, alice, CK4.currency)) == nullptr);
-
2508 }
-
2509 //------------ lsfGlobalFreeze, check written by non-issuer ------------
-
2510 {
-
2511 // Since gw1 has the lsfGlobalFreeze flag set, there should be
-
2512 // no automatic trust line creation between non-issuers.
-
2513
-
2514 // Use offers to automatically create the trust line.
-
2515 AccountOwns gw1{*this, env, "gw1", 0};
-
2516 IOU const OF4 = gw1["OF4"];
-
2517 env(offer(alice, XRP(91), OF4(91)), ter(tecFROZEN));
-
2518 env.close();
-
2519 BEAST_EXPECT(
-
2520 env.le(keylet::line(alice, bob, OF4.currency)) == nullptr);
-
2521 env(offer(bob, OF4(91), XRP(91)), ter(tecFROZEN));
-
2522 env.close();
-
2523
-
2524 // No one's owner count should have changed.
-
2525 gw1.verifyOwners(__LINE__);
+
2497 //-------------- lsfRequireAuth, check written by issuer ---------------
+
2498
+
2499 // We want to test the lsfRequireAuth flag, but we can't set that
+
2500 // flag on an account that already has trust lines. So we'll fund
+
2501 // a new gateway and use that.
+
2502 {
+
2503 AccountOwns gw2{*this, env, "gw2", 0};
+
2504 env.fund(XRP(5000), gw2);
+
2505 env.close();
+
2506
+
2507 // Set lsfRequireAuth on gw2. That should stop any automatic
+
2508 // trust lines from being created.
+
2509 env(fset(gw2, asfRequireAuth));
+
2510 env.close();
+
2511
+
2512 // Use offers to automatically create the trust line.
+
2513 IOU const OF5 = gw2["OF5"];
+
2514 std::uint32_t gw2OfferSeq = {env.seq(gw2)};
+
2515 env(offer(gw2, XRP(92), OF5(92)));
+
2516 ++gw2.owners;
+
2517 env.close();
+
2518 BEAST_EXPECT(
+
2519 env.le(keylet::line(gw2, alice, OF5.currency)) == nullptr);
+
2520 env(offer(alice, OF5(92), XRP(92)), ter(tecNO_LINE));
+
2521 env.close();
+
2522
+
2523 // gw2 should still own the offer, but no one else's owner
+
2524 // count should have changed.
+
2525 gw2.verifyOwners(__LINE__);
2526 alice.verifyOwners(__LINE__);
2527 bob.verifyOwners(__LINE__);
2528
-
2529 // Use check cashing to automatically create the trust line.
-
2530 IOU const CK4 = gw1["CK4"];
-
2531 uint256 const chkId{getCheckIndex(alice, env.seq(alice))};
-
2532 env(check::create(alice, bob, CK4(91)), ter(tecFROZEN));
-
2533 env.close();
-
2534 BEAST_EXPECT(
-
2535 env.le(keylet::line(alice, bob, CK4.currency)) == nullptr);
-
2536 env(check::cash(bob, chkId, CK4(91)), ter(tecNO_ENTRY));
-
2537 env.close();
-
2538
-
2539 // No one's owner count should have changed.
-
2540 gw1.verifyOwners(__LINE__);
-
2541 alice.verifyOwners(__LINE__);
-
2542 bob.verifyOwners(__LINE__);
-
2543
-
2544 // Because gw1 has set lsfGlobalFreeze, neither trust line
-
2545 // is created.
-
2546 BEAST_EXPECT(
-
2547 env.le(keylet::line(gw1, bob, OF4.currency)) == nullptr);
-
2548 BEAST_EXPECT(
-
2549 env.le(keylet::line(gw1, bob, CK4.currency)) == nullptr);
-
2550 }
+
2529 // Since we don't need it any more, remove gw2's offer.
+
2530 env(offer_cancel(gw2, gw2OfferSeq));
+
2531 --gw2.owners;
+
2532 env.close();
+
2533 gw2.verifyOwners(__LINE__);
+
2534
+
2535 // Use check cashing to automatically create the trust line.
+
2536 IOU const CK5 = gw2["CK5"];
+
2537 uint256 const chkId{getCheckIndex(gw2, env.seq(gw2))};
+
2538 env(check::create(gw2, alice, CK5(92)));
+
2539 ++gw2.owners;
+
2540 env.close();
+
2541 BEAST_EXPECT(
+
2542 env.le(keylet::line(gw2, alice, CK5.currency)) == nullptr);
+
2543 env(check::cash(alice, chkId, CK5(92)), ter(tecNO_AUTH));
+
2544 env.close();
+
2545
+
2546 // gw2 should still own the check, but no one else's owner
+
2547 // count should have changed.
+
2548 gw2.verifyOwners(__LINE__);
+
2549 alice.verifyOwners(__LINE__);
+
2550 bob.verifyOwners(__LINE__);
2551
-
2552 //-------------- lsfRequireAuth, check written by issuer ---------------
-
2553
-
2554 // We want to test the lsfRequireAuth flag, but we can't set that
-
2555 // flag on an account that already has trust lines. So we'll fund
-
2556 // a new gateway and use that.
-
2557 {
-
2558 AccountOwns gw2{*this, env, "gw2", 0};
-
2559 env.fund(XRP(5000), gw2);
-
2560 env.close();
-
2561
-
2562 // Set lsfRequireAuth on gw2. That should stop any automatic
-
2563 // trust lines from being created.
-
2564 env(fset(gw2, asfRequireAuth));
-
2565 env.close();
-
2566
-
2567 // Use offers to automatically create the trust line.
-
2568 IOU const OF5 = gw2["OF5"];
-
2569 std::uint32_t gw2OfferSeq = {env.seq(gw2)};
-
2570 env(offer(gw2, XRP(92), OF5(92)));
-
2571 ++gw2.owners;
-
2572 env.close();
-
2573 BEAST_EXPECT(
-
2574 env.le(keylet::line(gw2, alice, OF5.currency)) == nullptr);
-
2575 env(offer(alice, OF5(92), XRP(92)), ter(tecNO_LINE));
-
2576 env.close();
-
2577
-
2578 // gw2 should still own the offer, but no one else's owner
-
2579 // count should have changed.
+
2552 // Because gw2 has set lsfRequireAuth, neither trust line
+
2553 // is created.
+
2554 BEAST_EXPECT(
+
2555 env.le(keylet::line(gw2, alice, OF5.currency)) == nullptr);
+
2556 BEAST_EXPECT(
+
2557 env.le(keylet::line(gw2, alice, CK5.currency)) == nullptr);
+
2558
+
2559 // Since we don't need it any more, remove gw2's check.
+
2560 env(check::cancel(gw2, chkId));
+
2561 --gw2.owners;
+
2562 env.close();
+
2563 gw2.verifyOwners(__LINE__);
+
2564 }
+
2565 //------------ lsfRequireAuth, check written by non-issuer -------------
+
2566 {
+
2567 // Since gw2 has the lsfRequireAuth flag set, there should be
+
2568 // no automatic trust line creation between non-issuers.
+
2569
+
2570 // Use offers to automatically create the trust line.
+
2571 AccountOwns gw2{*this, env, "gw2", 0};
+
2572 IOU const OF5 = gw2["OF5"];
+
2573 env(offer(alice, XRP(91), OF5(91)), ter(tecUNFUNDED_OFFER));
+
2574 env.close();
+
2575 env(offer(bob, OF5(91), XRP(91)), ter(tecNO_LINE));
+
2576 BEAST_EXPECT(
+
2577 env.le(keylet::line(gw2, bob, OF5.currency)) == nullptr);
+
2578 env.close();
+
2579
2580 gw2.verifyOwners(__LINE__);
2581 alice.verifyOwners(__LINE__);
2582 bob.verifyOwners(__LINE__);
2583
-
2584 // Since we don't need it any more, remove gw2's offer.
-
2585 env(offer_cancel(gw2, gw2OfferSeq));
-
2586 --gw2.owners;
-
2587 env.close();
-
2588 gw2.verifyOwners(__LINE__);
-
2589
-
2590 // Use check cashing to automatically create the trust line.
-
2591 IOU const CK5 = gw2["CK5"];
-
2592 uint256 const chkId{getCheckIndex(gw2, env.seq(gw2))};
-
2593 env(check::create(gw2, alice, CK5(92)));
-
2594 ++gw2.owners;
-
2595 env.close();
-
2596 BEAST_EXPECT(
-
2597 env.le(keylet::line(gw2, alice, CK5.currency)) == nullptr);
-
2598 env(check::cash(alice, chkId, CK5(92)), ter(tecNO_AUTH));
-
2599 env.close();
-
2600
-
2601 // gw2 should still own the check, but no one else's owner
-
2602 // count should have changed.
-
2603 gw2.verifyOwners(__LINE__);
-
2604 alice.verifyOwners(__LINE__);
-
2605 bob.verifyOwners(__LINE__);
-
2606
-
2607 // Because gw2 has set lsfRequireAuth, neither trust line
-
2608 // is created.
-
2609 BEAST_EXPECT(
-
2610 env.le(keylet::line(gw2, alice, OF5.currency)) == nullptr);
-
2611 BEAST_EXPECT(
-
2612 env.le(keylet::line(gw2, alice, CK5.currency)) == nullptr);
-
2613
-
2614 // Since we don't need it any more, remove gw2's check.
-
2615 env(check::cancel(gw2, chkId));
-
2616 --gw2.owners;
-
2617 env.close();
-
2618 gw2.verifyOwners(__LINE__);
-
2619 }
-
2620 //------------ lsfRequireAuth, check written by non-issuer -------------
-
2621 {
-
2622 // Since gw2 has the lsfRequireAuth flag set, there should be
-
2623 // no automatic trust line creation between non-issuers.
-
2624
-
2625 // Use offers to automatically create the trust line.
-
2626 AccountOwns gw2{*this, env, "gw2", 0};
-
2627 IOU const OF5 = gw2["OF5"];
-
2628 env(offer(alice, XRP(91), OF5(91)), ter(tecUNFUNDED_OFFER));
-
2629 env.close();
-
2630 env(offer(bob, OF5(91), XRP(91)), ter(tecNO_LINE));
-
2631 BEAST_EXPECT(
-
2632 env.le(keylet::line(gw2, bob, OF5.currency)) == nullptr);
-
2633 env.close();
-
2634
-
2635 gw2.verifyOwners(__LINE__);
-
2636 alice.verifyOwners(__LINE__);
-
2637 bob.verifyOwners(__LINE__);
-
2638
-
2639 // Use check cashing to automatically create the trust line.
-
2640 IOU const CK5 = gw2["CK5"];
-
2641 uint256 const chkId{getCheckIndex(alice, env.seq(alice))};
-
2642 env(check::create(alice, bob, CK5(91)));
-
2643 env.close();
-
2644 BEAST_EXPECT(
-
2645 env.le(keylet::line(alice, bob, CK5.currency)) == nullptr);
-
2646 env(check::cash(bob, chkId, CK5(91)), ter(tecPATH_PARTIAL));
-
2647 env.close();
-
2648
-
2649 // Delete alice's check since it is no longer needed.
-
2650 env(check::cancel(alice, chkId));
-
2651 env.close();
-
2652
-
2653 // No one's owner count should have changed.
-
2654 gw2.verifyOwners(__LINE__);
-
2655 alice.verifyOwners(__LINE__);
-
2656 bob.verifyOwners(__LINE__);
-
2657
-
2658 // Because gw2 has set lsfRequireAuth, neither trust line
-
2659 // is created.
-
2660 BEAST_EXPECT(
-
2661 env.le(keylet::line(gw2, bob, OF5.currency)) == nullptr);
-
2662 BEAST_EXPECT(
-
2663 env.le(keylet::line(gw2, bob, CK5.currency)) == nullptr);
-
2664 }
-
2665 }
+
2584 // Use check cashing to automatically create the trust line.
+
2585 IOU const CK5 = gw2["CK5"];
+
2586 uint256 const chkId{getCheckIndex(alice, env.seq(alice))};
+
2587 env(check::create(alice, bob, CK5(91)));
+
2588 env.close();
+
2589 BEAST_EXPECT(
+
2590 env.le(keylet::line(alice, bob, CK5.currency)) == nullptr);
+
2591 env(check::cash(bob, chkId, CK5(91)), ter(tecPATH_PARTIAL));
+
2592 env.close();
+
2593
+
2594 // Delete alice's check since it is no longer needed.
+
2595 env(check::cancel(alice, chkId));
+
2596 env.close();
+
2597
+
2598 // No one's owner count should have changed.
+
2599 gw2.verifyOwners(__LINE__);
+
2600 alice.verifyOwners(__LINE__);
+
2601 bob.verifyOwners(__LINE__);
+
2602
+
2603 // Because gw2 has set lsfRequireAuth, neither trust line
+
2604 // is created.
+
2605 BEAST_EXPECT(
+
2606 env.le(keylet::line(gw2, bob, OF5.currency)) == nullptr);
+
2607 BEAST_EXPECT(
+
2608 env.le(keylet::line(gw2, bob, CK5.currency)) == nullptr);
+
2609 }
+
2610 }
-
2666
-
2667 void
-
- -
2669 {
-
2670 testEnabled(features);
-
2671 testCreateValid(features);
- -
2673 testCreateInvalid(features);
-
2674 testCashXRP(features);
-
2675 testCashIOU(features);
-
2676 testCashXferFee(features);
-
2677 testCashQuality(features);
-
2678 testCashInvalid(features);
-
2679 testCancelValid(features);
-
2680 testCancelInvalid(features);
- -
2682 testWithTickets(features);
-
2683 }
+
2611
+
2612 void
+
+ +
2614 {
+
2615 testEnabled(features);
+
2616 testCreateValid(features);
+ +
2618 testCreateInvalid(features);
+
2619 testCashXRP(features);
+
2620 testCashIOU(features);
+
2621 testCashXferFee(features);
+
2622 testCashQuality(features);
+
2623 testCashInvalid(features);
+
2624 testCancelValid(features);
+
2625 testCancelInvalid(features);
+ +
2627 testWithTickets(features);
+
2628 }
-
2684
-
2685public:
-
2686 void
-
-
2687 run() override
-
2688 {
-
2689 using namespace test::jtx;
-
2690 auto const sa = testable_amendments();
-
2691 testWithFeats(sa - featureCheckCashMakesTrustLine);
- -
2693 testWithFeats(sa);
-
2694
-
2695 testTrustLineCreation(sa); // Test with featureCheckCashMakesTrustLine
-
2696 }
+
2629
+
2630public:
+
2631 void
+
+
2632 run() override
+
2633 {
+
2634 using namespace test::jtx;
+
2635 auto const sa = testable_amendments();
+ +
2637 testWithFeats(sa);
+ +
2639 }
-
2697};
+
2640};
-
2698
-
2699BEAST_DEFINE_TESTSUITE(Check, app, ripple);
-
2700
-
2701} // namespace ripple
+
2641
+
2642BEAST_DEFINE_TESTSUITE(Check, app, ripple);
+
2643
+
2644} // namespace ripple
Represents a JSON value.
Definition json_value.h:130
Value removeMember(char const *key)
Remove and return the named member.
@@ -2847,26 +2790,26 @@ $(document).ready(function() { init_codefold(0); });
testcase_t testcase
Memberspace for declaring test cases.
Definition suite.h:152
bool expect(Condition const &shouldBeTrue)
Evaluate a test condition.
Definition suite.h:226
-
void testCancelInvalid(FeatureBitset features)
-
void testCashXferFee(FeatureBitset features)
+
void testCancelInvalid(FeatureBitset features)
+
void testCashXferFee(FeatureBitset features)
void testCashIOU(FeatureBitset features)
-
void testWithTickets(FeatureBitset features)
-
void testDeliveredAmountForCheckCashTxn(FeatureBitset features)
+
void testWithTickets(FeatureBitset features)
+
void testDeliveredAmountForCheckCashTxn(FeatureBitset features)
static std::vector< std::shared_ptr< SLE const > > checksOnAccount(test::jtx::Env &env, test::jtx::Account account)
void testCashXRP(FeatureBitset features)
void verifyDeliveredAmount(test::jtx::Env &env, STAmount const &amount)
void testEnabled(FeatureBitset features)
-
void testCashQuality(FeatureBitset features)
+
void testCashQuality(FeatureBitset features)
static uint256 getCheckIndex(AccountID const &account, std::uint32_t uSequence)
-
void testTrustLineCreation(FeatureBitset features)
+
void testTrustLineCreation(FeatureBitset features)
FeatureBitset const disallowIncoming
void testCreateDisallowIncoming(FeatureBitset features)
void testCreateInvalid(FeatureBitset features)
-
void testCancelValid(FeatureBitset features)
+
void testCancelValid(FeatureBitset features)
void testCreateValid(FeatureBitset features)
-
void run() override
Runs the suite.
-
void testCashInvalid(FeatureBitset features)
-
void testWithFeats(FeatureBitset features)
+
void run() override
Runs the suite.
+
void testCashInvalid(FeatureBitset features)
+
void testWithFeats(FeatureBitset features)
A currency issued by an account.
Definition Issue.h:14
AccountID account
Definition Issue.h:17
diff --git a/classripple_1_1CashCheck.html b/classripple_1_1CashCheck.html index 8c6d034e66..be9e85108c 100644 --- a/classripple_1_1CashCheck.html +++ b/classripple_1_1CashCheck.html @@ -499,7 +499,7 @@ Static Private Member Functions

Implements ripple::Transactor.

-

Definition at line 222 of file CashCheck.cpp.

+

Definition at line 214 of file CashCheck.cpp.

diff --git a/classripple_1_1Check__test.html b/classripple_1_1Check__test.html index c40e6bb8f3..62321cafc9 100644 --- a/classripple_1_1Check__test.html +++ b/classripple_1_1Check__test.html @@ -590,7 +590,7 @@ Private Attributes
-

Definition at line 1068 of file Check_test.cpp.

+

Definition at line 1034 of file Check_test.cpp.

@@ -618,7 +618,7 @@ Private Attributes
-

Definition at line 1139 of file Check_test.cpp.

+

Definition at line 1105 of file Check_test.cpp.

@@ -646,7 +646,7 @@ Private Attributes
-

Definition at line 1347 of file Check_test.cpp.

+

Definition at line 1313 of file Check_test.cpp.

@@ -674,7 +674,7 @@ Private Attributes
-

Definition at line 1646 of file Check_test.cpp.

+

Definition at line 1595 of file Check_test.cpp.

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

Definition at line 1817 of file Check_test.cpp.

+

Definition at line 1766 of file Check_test.cpp.

@@ -730,7 +730,7 @@ Private Attributes
-

Definition at line 1851 of file Check_test.cpp.

+

Definition at line 1800 of file Check_test.cpp.

@@ -758,7 +758,7 @@ Private Attributes
-

Definition at line 1883 of file Check_test.cpp.

+

Definition at line 1832 of file Check_test.cpp.

@@ -786,7 +786,7 @@ Private Attributes
-

Definition at line 1983 of file Check_test.cpp.

+

Definition at line 1932 of file Check_test.cpp.

@@ -814,7 +814,7 @@ Private Attributes
-

Definition at line 2668 of file Check_test.cpp.

+

Definition at line 2613 of file Check_test.cpp.

@@ -845,7 +845,7 @@ Private Attributes

Implements beast::unit_test::suite.

-

Definition at line 2687 of file Check_test.cpp.

+

Definition at line 2632 of file Check_test.cpp.