mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-04 17:27:00 +00:00
2808 lines
99 KiB
C++
2808 lines
99 KiB
C++
//------------------------------------------------------------------------------
|
|
/*
|
|
This file is part of rippled: https://github.com/ripple/rippled
|
|
Copyright (c) 2025 Ripple Labs Inc.
|
|
|
|
Permission to use, copy, modify, and/or distribute this software for any
|
|
purpose with or without fee is hereby granted, provided that the above
|
|
copyright notice and this permission notice appear in all copies.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
//==============================================================================
|
|
|
|
#include <test/jtx.h>
|
|
|
|
#include <xrpl/basics/strHex.h>
|
|
#include <xrpl/protocol/Feature.h>
|
|
|
|
namespace ripple {
|
|
namespace test {
|
|
|
|
static STAmount
|
|
reserve(jtx::Env& env, std::uint32_t count)
|
|
{
|
|
return env.current()->fees().accountReserve(count);
|
|
}
|
|
|
|
static void
|
|
adjustAccountXRPBalance(
|
|
jtx::Env& env,
|
|
jtx::Account const& account,
|
|
STAmount const& balanceTo)
|
|
{
|
|
using namespace test::jtx;
|
|
XRPL_ASSERT(
|
|
isXRP(balanceTo), "adjustAccountXRPBalance: balanceTo must be XRP");
|
|
auto const currentBalance = env.balance(account);
|
|
if (currentBalance == balanceTo)
|
|
return;
|
|
|
|
if (currentBalance > balanceTo)
|
|
env(pay(account, env.master, currentBalance - balanceTo + XRP(1)),
|
|
fee(XRP(1)));
|
|
else
|
|
env(pay(env.master, account, balanceTo - currentBalance), fee(XRP(1)));
|
|
|
|
env.close();
|
|
}
|
|
|
|
class Sponsor_test : public beast::unit_test::suite
|
|
{
|
|
public:
|
|
void
|
|
testDisabled()
|
|
{
|
|
testcase("Disabled");
|
|
using namespace test::jtx;
|
|
Env env{*this, testable_amendments() - featureSponsor};
|
|
Account const alice("alice");
|
|
Account const sponsor("sponsor");
|
|
env.fund(XRP(10000), alice, sponsor);
|
|
|
|
env(noop(alice),
|
|
fee(XRP(1)),
|
|
sponsor::as(sponsor),
|
|
sponsor::sig(sponsor),
|
|
ter(temDISABLED));
|
|
|
|
env(sponsor::transfer(alice), ter(temDISABLED));
|
|
env(sponsor::set(sponsor, 0), ter(temDISABLED));
|
|
}
|
|
|
|
void
|
|
testInvalidSponsorshipSet()
|
|
{
|
|
testcase("Invalid SponsorshipSet");
|
|
using namespace test::jtx;
|
|
Env env{*this, testable_amendments()};
|
|
Account const alice("alice");
|
|
Account const bob("bob");
|
|
Account const sponsor("sponsor");
|
|
Account const noFunded("noFunded");
|
|
Account const gw("gw");
|
|
|
|
auto const USD = gw["USD"];
|
|
env.fund(XRP(10000), alice, sponsor, gw);
|
|
env.close();
|
|
|
|
//
|
|
// preflight
|
|
//
|
|
|
|
// Invalid flags
|
|
{
|
|
env(sponsor::set(sponsor, ~tfSponsorshipSetMask - tfInnerBatchTxn),
|
|
sponsor::sponseeAcc(alice),
|
|
ter(temINVALID_FLAG));
|
|
|
|
env(sponsor::set(
|
|
sponsor,
|
|
tfSponsorshipSetRequireSignForFee |
|
|
tfSponsorshipClearRequireSignForFee),
|
|
sponsor::sponseeAcc(alice),
|
|
ter(temINVALID_FLAG));
|
|
|
|
env(sponsor::set(
|
|
sponsor,
|
|
tfSponsorshipSetRequireSignForReserve |
|
|
tfSponsorshipClearRequireSignForReserve),
|
|
sponsor::sponseeAcc(alice),
|
|
ter(temINVALID_FLAG));
|
|
|
|
for (auto flag :
|
|
{tfSponsorshipSetRequireSignForFee,
|
|
tfSponsorshipClearRequireSignForFee,
|
|
tfSponsorshipSetRequireSignForReserve,
|
|
tfSponsorshipClearRequireSignForReserve})
|
|
{
|
|
env(sponsor::set(sponsor, tfDeleteObject | flag),
|
|
sponsor::sponseeAcc(alice),
|
|
ter(temINVALID_FLAG));
|
|
}
|
|
}
|
|
|
|
// invalid SponsorAccount / Sponsee
|
|
// Account = Sponsor
|
|
env(sponsor::set(alice, tfDeleteObject),
|
|
sponsor::sponsorAcc(alice),
|
|
ter(temMALFORMED));
|
|
// Account = Sponsee
|
|
env(sponsor::set(alice, tfDeleteObject),
|
|
sponsor::sponseeAcc(alice),
|
|
ter(temMALFORMED));
|
|
// Both Sponsor and Sponsee are specified
|
|
env(sponsor::set(alice, 0),
|
|
sponsor::sponsorAcc(sponsor),
|
|
sponsor::sponseeAcc(alice),
|
|
ter(temMALFORMED));
|
|
|
|
// Invalid feeAmount
|
|
for (auto amt : {XRP(-1), XRP(0), USD(1)})
|
|
{
|
|
env(sponsor::set_fee(sponsor, 0, amt),
|
|
sponsor::sponseeAcc(alice),
|
|
ter(temBAD_AMOUNT));
|
|
}
|
|
|
|
// Invalid reserveCount
|
|
env(sponsor::set_reserve(sponsor, 0, 0),
|
|
sponsor::sponseeAcc(alice),
|
|
ter(temMALFORMED));
|
|
|
|
// Invalid Delete operation
|
|
env(sponsor::set_reserve(sponsor, tfDeleteObject, 1),
|
|
sponsor::sponseeAcc(alice),
|
|
ter(temMALFORMED));
|
|
env(sponsor::set_fee(sponsor, tfDeleteObject, XRP(1)),
|
|
sponsor::sponseeAcc(alice),
|
|
ter(temMALFORMED));
|
|
// TODO: test MaxFee with tfDeleteObject
|
|
|
|
//
|
|
// preclaim
|
|
//
|
|
|
|
// Invalid Sponsee
|
|
env(sponsor::set(sponsor, 0),
|
|
sponsor::sponseeAcc(noFunded),
|
|
ter(tecNO_DST));
|
|
|
|
// Invalid Delete operation (not found)
|
|
env(sponsor::set(sponsor, tfDeleteObject),
|
|
sponsor::sponseeAcc(alice),
|
|
ter(tecNO_ENTRY));
|
|
|
|
// DisallowIncomingSponsor: tested in other testcase
|
|
|
|
// create sponsor to use above tests
|
|
env(sponsor::set(sponsor, 0, 100, XRP(100)),
|
|
sponsor::sponseeAcc(alice),
|
|
ter(tesSUCCESS));
|
|
env.close();
|
|
}
|
|
|
|
void
|
|
testSingleSigning()
|
|
{
|
|
testcase("Single signing");
|
|
using namespace test::jtx;
|
|
Env env{*this, testable_amendments()};
|
|
Account const alice("alice");
|
|
Account const sponsor("sponsor");
|
|
Account const invalid("invalid");
|
|
|
|
env.fund(XRP(10000), alice, sponsor);
|
|
env.close();
|
|
|
|
// Signature doesn't exist
|
|
auto tx = noop(alice);
|
|
tx[sfSponsor.jsonName][sfAccount.jsonName] = sponsor.human();
|
|
tx[sfSponsor.jsonName][sfSigningPubKey.jsonName] =
|
|
strHex(sponsor.pk().slice());
|
|
|
|
env(tx,
|
|
fee(XRP(1)),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
ter(telENV_RPC_FAILED));
|
|
|
|
// Invalid signature
|
|
tx[sfSponsor.jsonName][sfTxnSignature.jsonName] = "DEADBEEF";
|
|
env(tx,
|
|
fee(XRP(1)),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
ter(telENV_RPC_FAILED));
|
|
|
|
// Signer account doesn't exist
|
|
env(noop(alice),
|
|
fee(XRP(1)),
|
|
sponsor::as(invalid, tfSponsorReserve),
|
|
sponsor::sig(invalid),
|
|
ter(tefBAD_AUTH));
|
|
|
|
// Success
|
|
env(noop(alice),
|
|
fee(XRP(1)),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
sponsor::sig(sponsor),
|
|
ter(tesSUCCESS));
|
|
}
|
|
|
|
void
|
|
testMultiSigning()
|
|
{
|
|
testcase("Multi signing");
|
|
using namespace test::jtx;
|
|
Env env{*this, testable_amendments()};
|
|
Account const alice("alice");
|
|
Account const sponsor("sponsor");
|
|
Account const invalid("invalid");
|
|
|
|
Account const signer1("signer1");
|
|
Account const signer2("signer2");
|
|
|
|
env.fund(XRP(10000), alice, sponsor);
|
|
env.close();
|
|
|
|
env(signers(sponsor, 1, {{signer1, 1}, {signer2, 1}}));
|
|
env.close();
|
|
|
|
// Invalid signature
|
|
auto tx = noop(alice);
|
|
auto& signers1 =
|
|
tx[sfSponsor.jsonName][sfSigners.jsonName][0U][sfSigner.jsonName];
|
|
signers1[sfAccount.jsonName] = signer1.human();
|
|
signers1[sfSigningPubKey.jsonName] = strHex(signer1.pk().slice());
|
|
signers1[sfTxnSignature.jsonName] = "DEADBEEF";
|
|
env(tx,
|
|
fee(XRP(1)),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
ter(telENV_RPC_FAILED));
|
|
|
|
// Signer account doesn't exist
|
|
env(noop(alice),
|
|
fee(XRP(1)),
|
|
sponsor::as(invalid, tfSponsorReserve),
|
|
sponsor::msig({signer1}),
|
|
ter(tefBAD_AUTH));
|
|
|
|
env(noop(alice),
|
|
fee(XRP(1)),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
sponsor::msig({signer1}),
|
|
ter(tesSUCCESS));
|
|
|
|
env(signers(sponsor, 2, {{signer1, 1}, {signer2, 1}}));
|
|
env.close();
|
|
|
|
env(noop(alice),
|
|
fee(XRP(1)),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
sponsor::msig({signer1, signer2}),
|
|
ter(tesSUCCESS));
|
|
}
|
|
|
|
void
|
|
testSimpleSponsorshipSet()
|
|
{
|
|
testcase("Simple SponsorshipSet");
|
|
using namespace test::jtx;
|
|
Env env{*this, testable_amendments()};
|
|
Account const alice("alice");
|
|
Account const sponsor("sponsor");
|
|
env.fund(XRP(10000), alice, sponsor);
|
|
env.close();
|
|
|
|
//
|
|
env(sponsor::set(
|
|
sponsor,
|
|
tfSponsorshipSetRequireSignForFee |
|
|
tfSponsorshipSetRequireSignForReserve,
|
|
100,
|
|
XRP(100),
|
|
XRP(1)),
|
|
sponsor::sponseeAcc(alice),
|
|
ter(tesSUCCESS));
|
|
env.close();
|
|
|
|
// delete from sponsor
|
|
env(sponsor::del(sponsor), sponsor::sponseeAcc(alice), ter(tesSUCCESS));
|
|
env.close();
|
|
|
|
env(sponsor::set(
|
|
sponsor,
|
|
tfSponsorshipSetRequireSignForFee |
|
|
tfSponsorshipSetRequireSignForReserve,
|
|
100,
|
|
XRP(100),
|
|
XRP(1)),
|
|
sponsor::sponseeAcc(alice),
|
|
ter(tesSUCCESS));
|
|
env.close();
|
|
|
|
// delete from sponsee
|
|
env(sponsor::del(alice), sponsor::sponsorAcc(sponsor), ter(tesSUCCESS));
|
|
env.close();
|
|
}
|
|
|
|
void
|
|
testTransferSponsor()
|
|
{
|
|
testcase("Transfer Sponsor");
|
|
using namespace test::jtx;
|
|
|
|
{
|
|
// sponsor account
|
|
Env env{*this, testable_amendments()};
|
|
Account const alice("alice");
|
|
Account const sponsor1("sponsor1");
|
|
Account const sponsor2("sponsor2");
|
|
env.fund(XRP(10000), alice);
|
|
env.fund(env.current()->fees().reserve * 2 - 1, sponsor1, sponsor2);
|
|
env.close();
|
|
|
|
env(sponsor::transfer(alice),
|
|
sponsor::as(sponsor1, tfSponsorReserve),
|
|
sponsor::sig(sponsor1),
|
|
ter(tecINSUFFICIENT_RESERVE));
|
|
|
|
env(pay(alice, sponsor1, drops(1)));
|
|
env.close();
|
|
|
|
env(sponsor::transfer(alice),
|
|
sponsor::as(sponsor1, tfSponsorReserve),
|
|
sponsor::sig(sponsor1));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, sponsor1) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor1) == 0);
|
|
BEAST_EXPECT(sponsoringAccountCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringAccountCount(env, sponsor1) == 1);
|
|
auto const sle1 = env.le(keylet::account(alice));
|
|
BEAST_EXPECT(sle1->isFieldPresent(sfSponsorAccount));
|
|
BEAST_EXPECT(sle1->getAccountID(sfSponsorAccount) == sponsor1.id());
|
|
|
|
// transfer sponsor
|
|
env(sponsor::transfer(alice),
|
|
sponsor::as(sponsor2, tfSponsorReserve),
|
|
sponsor::sig(sponsor2),
|
|
ter(tecINSUFFICIENT_RESERVE));
|
|
|
|
env(pay(alice, sponsor2, drops(1)));
|
|
env.close();
|
|
|
|
env(sponsor::transfer(alice),
|
|
sponsor::as(sponsor2, tfSponsorReserve),
|
|
sponsor::sig(sponsor2));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, sponsor1) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, sponsor2) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor1) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 0);
|
|
BEAST_EXPECT(sponsoringAccountCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringAccountCount(env, sponsor1) == 0);
|
|
BEAST_EXPECT(sponsoringAccountCount(env, sponsor2) == 1);
|
|
auto const sle2 = env.le(keylet::account(alice));
|
|
BEAST_EXPECT(sle2->isFieldPresent(sfSponsorAccount));
|
|
BEAST_EXPECT(sle2->getAccountID(sfSponsorAccount) == sponsor2.id());
|
|
|
|
// dissolve sponsor
|
|
env(pay(alice,
|
|
sponsor2,
|
|
(env.balance(alice).value() -
|
|
env.current()->fees().reserve - XRP(1) + drops(1))),
|
|
fee(XRP(1)));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(
|
|
env.balance(alice) == env.current()->fees().reserve - drops(1));
|
|
env(sponsor::transfer(alice), ter(tecINSUFFICIENT_RESERVE));
|
|
env.close();
|
|
|
|
env(pay(sponsor2, alice, XRP(1)));
|
|
env.close();
|
|
|
|
env(sponsor::transfer(alice));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, sponsor1) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, sponsor2) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor1) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 0);
|
|
BEAST_EXPECT(sponsoringAccountCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringAccountCount(env, sponsor1) == 0);
|
|
BEAST_EXPECT(sponsoringAccountCount(env, sponsor2) == 0);
|
|
auto const sle3 = env.le(keylet::account(alice));
|
|
BEAST_EXPECT(!sle3->isFieldPresent(sfSponsorAccount));
|
|
}
|
|
{
|
|
// sponsor object
|
|
Env env{*this, testable_amendments()};
|
|
Account const alice("alice");
|
|
Account const bob("bob");
|
|
Account const sponsor1("sponsor1");
|
|
Account const sponsor2("sponsor2");
|
|
env.fund(XRP(10000), alice, bob);
|
|
env.fund(
|
|
env.current()->fees().reserve +
|
|
env.current()->fees().increment - drops(1),
|
|
sponsor1,
|
|
sponsor2);
|
|
env.close();
|
|
|
|
auto const seq = env.seq(alice);
|
|
env(check::create(alice, bob, XRP(1)));
|
|
env.close();
|
|
|
|
auto const checkId = keylet::check(alice, seq).key;
|
|
BEAST_EXPECT(env.le(keylet::unchecked(checkId)) != nullptr);
|
|
|
|
env(sponsor::transfer(alice, checkId),
|
|
sponsor::as(sponsor1, tfSponsorReserve),
|
|
sponsor::sig(sponsor1),
|
|
ter(tecINSUFFICIENT_RESERVE));
|
|
env.close();
|
|
|
|
env(pay(alice, sponsor1, drops(1)));
|
|
env.close();
|
|
|
|
// Invalid Owner
|
|
env(sponsor::transfer(bob, checkId),
|
|
sponsor::as(sponsor1, tfSponsorReserve),
|
|
sponsor::sig(sponsor1),
|
|
ter(tecNO_PERMISSION));
|
|
env.close();
|
|
|
|
// Valid Owner
|
|
env(sponsor::transfer(alice, checkId),
|
|
sponsor::as(sponsor1, tfSponsorReserve),
|
|
sponsor::sig(sponsor1));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, sponsor1) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor1) == 1);
|
|
BEAST_EXPECT(sponsoringAccountCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringAccountCount(env, sponsor1) == 0);
|
|
auto const sle1 = env.le(keylet::unchecked(checkId));
|
|
BEAST_EXPECT(sle1->isFieldPresent(sfSponsorAccount));
|
|
BEAST_EXPECT(sle1->getAccountID(sfSponsorAccount) == sponsor1.id());
|
|
|
|
// transfer sponsor
|
|
env(sponsor::transfer(alice, checkId),
|
|
sponsor::as(sponsor2, tfSponsorReserve),
|
|
sponsor::sig(sponsor2),
|
|
ter(tecINSUFFICIENT_RESERVE));
|
|
|
|
env(pay(alice, sponsor2, drops(1)));
|
|
env.close();
|
|
|
|
env(sponsor::transfer(alice, checkId),
|
|
sponsor::as(sponsor2, tfSponsorReserve),
|
|
sponsor::sig(sponsor2));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, sponsor1) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, sponsor2) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor1) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1);
|
|
BEAST_EXPECT(sponsoringAccountCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringAccountCount(env, sponsor1) == 0);
|
|
BEAST_EXPECT(sponsoringAccountCount(env, sponsor2) == 0);
|
|
auto const sle2 = env.le(keylet::unchecked(checkId));
|
|
BEAST_EXPECT(sle2->isFieldPresent(sfSponsorAccount));
|
|
BEAST_EXPECT(sle2->getAccountID(sfSponsorAccount) == sponsor2.id());
|
|
|
|
// dissolve sponsor
|
|
env(pay(alice,
|
|
sponsor2,
|
|
(env.balance(alice).value() -
|
|
env.current()->fees().reserve -
|
|
env.current()->fees().increment - XRP(1) + drops(1))),
|
|
fee(XRP(1)));
|
|
env.close();
|
|
|
|
env(sponsor::transfer(alice, checkId),
|
|
ter(tecINSUFFICIENT_RESERVE));
|
|
env.close();
|
|
|
|
env(pay(sponsor2, alice, XRP(1)));
|
|
env.close();
|
|
|
|
env(sponsor::transfer(alice, checkId));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, sponsor1) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, sponsor2) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor1) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 0);
|
|
BEAST_EXPECT(sponsoringAccountCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringAccountCount(env, sponsor1) == 0);
|
|
BEAST_EXPECT(sponsoringAccountCount(env, sponsor2) == 0);
|
|
auto const sle3 = env.le(keylet::unchecked(checkId));
|
|
BEAST_EXPECT(!sle3->isFieldPresent(sfSponsorAccount));
|
|
}
|
|
}
|
|
|
|
void
|
|
testSponsorFee()
|
|
{
|
|
using namespace test::jtx;
|
|
|
|
testcase("Sponsor Fee");
|
|
|
|
{
|
|
// co-signing
|
|
Env env{*this, testable_amendments()};
|
|
Account const alice("alice");
|
|
Account const bob("bob");
|
|
Account const sponsor("sponsor");
|
|
env.fund(XRP(10000), alice, bob);
|
|
env.close();
|
|
|
|
{
|
|
// Fee should be checked before permission check,
|
|
// otherwise tecNO_SPONSOR_PERMISSION returned when permission
|
|
// check fails could cause context reset to pay fee because it
|
|
// is tec error
|
|
auto aliceBalance = env.balance(alice);
|
|
auto bobBalance = env.balance(bob);
|
|
auto sponsorBalance = env.balance(sponsor);
|
|
|
|
env(pay(alice, bob, XRP(100)),
|
|
fee(XRP(2000)),
|
|
sponsor::as(sponsor, tfSponsorFee),
|
|
sponsor::sig(sponsor),
|
|
ter(terNO_ACCOUNT));
|
|
env.close();
|
|
BEAST_EXPECT(env.balance(alice) == aliceBalance);
|
|
BEAST_EXPECT(env.balance(bob) == bobBalance);
|
|
BEAST_EXPECT(env.balance(sponsor) == sponsorBalance);
|
|
}
|
|
|
|
env.fund(XRP(1000), sponsor);
|
|
env.close();
|
|
|
|
{
|
|
// Sponsor pays the fee
|
|
auto aliceBalance = env.balance(alice);
|
|
auto bobBalance = env.balance(bob);
|
|
auto sponsorBalance = env.balance(sponsor);
|
|
|
|
auto const sendAmt = XRP(100);
|
|
auto const feeAmt = XRP(10);
|
|
env(pay(alice, bob, sendAmt),
|
|
fee(feeAmt),
|
|
sponsor::as(sponsor, tfSponsorFee),
|
|
sponsor::sig(sponsor));
|
|
env.close();
|
|
BEAST_EXPECT(env.balance(alice) == aliceBalance - sendAmt);
|
|
BEAST_EXPECT(env.balance(bob) == bobBalance + sendAmt);
|
|
BEAST_EXPECT(env.balance(sponsor) == sponsorBalance - feeAmt);
|
|
}
|
|
|
|
{
|
|
// insufficient balance to pay fee
|
|
auto aliceBalance = env.balance(alice);
|
|
auto bobBalance = env.balance(bob);
|
|
auto sponsorBalance = env.balance(sponsor);
|
|
|
|
env(pay(alice, bob, XRP(100)),
|
|
fee(XRP(2000)),
|
|
sponsor::as(sponsor, tfSponsorFee),
|
|
sponsor::sig(sponsor),
|
|
ter(terINSUF_FEE_B));
|
|
env.close();
|
|
BEAST_EXPECT(env.balance(alice) == aliceBalance);
|
|
BEAST_EXPECT(env.balance(bob) == bobBalance);
|
|
BEAST_EXPECT(env.balance(sponsor) == sponsorBalance);
|
|
}
|
|
|
|
{
|
|
// fee is paid by Sponsor
|
|
// on context reset (tec error)
|
|
auto aliceBalance = env.balance(alice);
|
|
auto bobBalance = env.balance(bob);
|
|
auto sponsorBalance = env.balance(sponsor);
|
|
auto const feeAmt = XRP(10);
|
|
|
|
env(pay(alice, bob, XRP(20000)),
|
|
fee(feeAmt),
|
|
sponsor::as(sponsor, tfSponsorFee),
|
|
sponsor::sig(sponsor),
|
|
ter(tecUNFUNDED_PAYMENT));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(env.balance(alice) == aliceBalance);
|
|
BEAST_EXPECT(env.balance(bob) == bobBalance);
|
|
BEAST_EXPECT(env.balance(sponsor) == sponsorBalance - feeAmt);
|
|
}
|
|
}
|
|
|
|
{
|
|
// pre funded
|
|
Env env{*this, testable_amendments()};
|
|
Account const alice("alice");
|
|
Account const bob("bob");
|
|
Account const sponsor("sponsor");
|
|
env.fund(XRP(10000), alice, bob, sponsor);
|
|
env.close();
|
|
|
|
auto const sponsorFeeBalance = [&](Account const& sponsor,
|
|
Account const& alice) {
|
|
return env.le(keylet::sponsor(sponsor, alice))
|
|
->getFieldAmount(sfFeeAmount)
|
|
.xrp();
|
|
};
|
|
|
|
{
|
|
// Fee should be checked before permission check,
|
|
// otherwise tecNO_SPONSOR_PERMISSION returned when permission
|
|
// check fails could cause context reset to pay fee because it
|
|
// is tec error
|
|
auto aliceBalance = env.balance(alice);
|
|
auto bobBalance = env.balance(bob);
|
|
auto sponsorBalance = env.balance(sponsor);
|
|
|
|
env(pay(alice, bob, XRP(100)),
|
|
fee(XRP(2000)),
|
|
sponsor::as(sponsor, tfSponsorFee),
|
|
ter(terNO_SPONSORSHIP));
|
|
env.close();
|
|
BEAST_EXPECT(env.balance(alice) == aliceBalance);
|
|
BEAST_EXPECT(env.balance(bob) == bobBalance);
|
|
BEAST_EXPECT(env.balance(sponsor) == sponsorBalance);
|
|
}
|
|
|
|
env(sponsor::set_fee(sponsor, 0, XRP(100)),
|
|
sponsor::sponseeAcc(alice));
|
|
env.close();
|
|
|
|
{
|
|
// Sponsor pays the fee
|
|
auto aliceBalance = env.balance(alice);
|
|
auto bobBalance = env.balance(bob);
|
|
auto sponsorBalance = env.balance(sponsor);
|
|
auto sponsorFee = sponsorFeeBalance(sponsor, alice);
|
|
|
|
auto const sendAmt = XRP(100);
|
|
auto const feeAmt = XRP(10);
|
|
env(pay(alice, bob, sendAmt),
|
|
fee(feeAmt),
|
|
sponsor::as(sponsor, tfSponsorFee));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(env.balance(alice) == aliceBalance - sendAmt);
|
|
BEAST_EXPECT(env.balance(bob) == bobBalance + sendAmt);
|
|
BEAST_EXPECT(env.balance(sponsor) == sponsorBalance);
|
|
BEAST_EXPECT(
|
|
sponsorFeeBalance(sponsor, alice) == sponsorFee - feeAmt);
|
|
}
|
|
|
|
{
|
|
// insufficient balance to pay fee
|
|
{
|
|
// > FeeAmount
|
|
auto aliceBalance = env.balance(alice);
|
|
auto bobBalance = env.balance(bob);
|
|
auto sponsorBalance = env.balance(sponsor);
|
|
auto sponsorFee = sponsorFeeBalance(sponsor, alice);
|
|
|
|
env(pay(alice, bob, XRP(100)),
|
|
fee(XRP(100) + drops(1)),
|
|
sponsor::as(sponsor, tfSponsorFee),
|
|
ter(terINSUF_FEE_B));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(env.balance(alice) == aliceBalance);
|
|
BEAST_EXPECT(env.balance(bob) == bobBalance);
|
|
BEAST_EXPECT(env.balance(sponsor) == sponsorBalance);
|
|
BEAST_EXPECT(
|
|
sponsorFeeBalance(sponsor, alice) == sponsorFee);
|
|
}
|
|
|
|
// reset FeeAmount and MaxFee
|
|
env(sponsor::del(sponsor), sponsor::sponseeAcc(alice));
|
|
env.close();
|
|
env(sponsor::set_fee(sponsor, 0, XRP(10), XRP(1)),
|
|
sponsor::sponseeAcc(alice));
|
|
env.close();
|
|
|
|
{
|
|
// > MaxFee
|
|
auto aliceBalance = env.balance(alice);
|
|
auto bobBalance = env.balance(bob);
|
|
auto sponsorBalance = env.balance(sponsor);
|
|
auto sponsorFee = sponsorFeeBalance(sponsor, alice);
|
|
|
|
env(pay(alice, bob, XRP(100)),
|
|
fee(XRP(1) + drops(1)),
|
|
sponsor::as(sponsor, tfSponsorFee),
|
|
ter(terINSUF_FEE_B));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(env.balance(alice) == aliceBalance);
|
|
BEAST_EXPECT(env.balance(bob) == bobBalance);
|
|
BEAST_EXPECT(env.balance(sponsor) == sponsorBalance);
|
|
BEAST_EXPECT(
|
|
sponsorFeeBalance(sponsor, alice) == sponsorFee);
|
|
}
|
|
}
|
|
|
|
{
|
|
// fee is paid by Sponsor
|
|
// on context reset (tec error)
|
|
auto aliceBalance = env.balance(alice);
|
|
auto bobBalance = env.balance(bob);
|
|
auto sponsorBalance = env.balance(sponsor);
|
|
auto sponsorFee = sponsorFeeBalance(sponsor, alice);
|
|
auto const feeAmt = XRP(1);
|
|
|
|
env(pay(alice, bob, XRP(20000)),
|
|
fee(feeAmt),
|
|
sponsor::as(sponsor, tfSponsorFee),
|
|
ter(tecUNFUNDED_PAYMENT));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(env.balance(alice) == aliceBalance);
|
|
BEAST_EXPECT(env.balance(bob) == bobBalance);
|
|
BEAST_EXPECT(env.balance(sponsor) == sponsorBalance);
|
|
BEAST_EXPECT(
|
|
sponsorFeeBalance(sponsor, alice) == sponsorFee - feeAmt);
|
|
}
|
|
}
|
|
|
|
// test lsfSponsorshipRequireSignForFee
|
|
{
|
|
Env env{*this, testable_amendments()};
|
|
Account const alice("alice");
|
|
Account const bob("bob");
|
|
Account const sponsor("sponsor");
|
|
env.fund(XRP(10000), alice, bob, sponsor);
|
|
env.close();
|
|
|
|
// set flag
|
|
env(sponsor::set_fee(
|
|
sponsor, tfSponsorshipSetRequireSignForFee, XRP(10)),
|
|
sponsor::sponseeAcc(alice));
|
|
env.close();
|
|
|
|
env(pay(alice, bob, XRP(100)),
|
|
fee(XRP(10)),
|
|
sponsor::as(sponsor, tfSponsorFee),
|
|
ter(terNO_SPONSORSHIP));
|
|
env.close();
|
|
|
|
// clear flag
|
|
env(sponsor::set_fee(
|
|
sponsor, tfSponsorshipClearRequireSignForFee, XRP(10)),
|
|
sponsor::sponseeAcc(alice));
|
|
env.close();
|
|
|
|
env(pay(alice, bob, XRP(100)),
|
|
fee(XRP(10)),
|
|
sponsor::as(sponsor, tfSponsorFee),
|
|
ter(tesSUCCESS));
|
|
env.close();
|
|
}
|
|
}
|
|
|
|
void
|
|
testSponsorAccount()
|
|
{
|
|
testcase("Sponsor Account");
|
|
using namespace test::jtx;
|
|
Env env{*this, testable_amendments()};
|
|
|
|
Account const alice("alice");
|
|
Account const sponsor("sponsor");
|
|
Account const bob("bob");
|
|
Account const charlie("charlie");
|
|
env.fund(XRP(10000), alice, sponsor);
|
|
|
|
// Account is not sponsored by normal Sponsor specification
|
|
{
|
|
env(pay(alice,
|
|
bob,
|
|
STAmount(env.current()->fees().accountReserve(0))),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
sponsor::sig(sponsor));
|
|
env.close();
|
|
|
|
auto const bobSle = env.le(keylet::account(bob));
|
|
BEAST_EXPECT(!bobSle->isFieldPresent(sfSponsorAccount));
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringAccountCount(env, sponsor) == 0);
|
|
}
|
|
|
|
// Use tfSponsorCreatedAccount to sponsor an account
|
|
{
|
|
// to funded accoutn
|
|
env(pay(sponsor,
|
|
bob,
|
|
STAmount(env.current()->fees().accountReserve(0))),
|
|
txflags(tfSponsorCreatedAccount),
|
|
ter(tecNO_SPONSOR_PERMISSION));
|
|
|
|
// to non-funded account
|
|
env(pay(sponsor,
|
|
charlie,
|
|
STAmount(env.current()->fees().accountReserve(0))),
|
|
txflags(tfSponsorCreatedAccount));
|
|
env.close();
|
|
|
|
auto const charlieSle = env.le(keylet::account(charlie));
|
|
BEAST_EXPECT(charlieSle->isFieldPresent(sfSponsorAccount));
|
|
BEAST_EXPECT(
|
|
charlieSle->getAccountID(sfSponsorAccount) == sponsor.id());
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, charlie) == 0);
|
|
BEAST_EXPECT(sponsoringAccountCount(env, sponsor) == 1);
|
|
}
|
|
}
|
|
|
|
void
|
|
testRequireFlag()
|
|
{
|
|
testcase("SponsorshipRequireSignForReserve");
|
|
using namespace test::jtx;
|
|
|
|
Env env{*this, testable_amendments()};
|
|
Account const alice("alice");
|
|
Account const bob("bob");
|
|
Account const sponsor("sponsor");
|
|
env.fund(XRP(10000), alice, bob, sponsor);
|
|
env.close();
|
|
|
|
// set flag
|
|
env(sponsor::set_reserve(
|
|
sponsor, tfSponsorshipSetRequireSignForReserve, 10),
|
|
sponsor::sponseeAcc(alice));
|
|
env.close();
|
|
|
|
env(check::create(alice, bob, XRP(100)),
|
|
fee(XRP(10)),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
ter(terNO_SPONSORSHIP));
|
|
env.close();
|
|
|
|
// clear flag
|
|
env(sponsor::set_reserve(
|
|
sponsor, tfSponsorshipClearRequireSignForReserve, 1),
|
|
sponsor::sponseeAcc(alice));
|
|
env.close();
|
|
|
|
env(check::create(alice, bob, XRP(100)),
|
|
fee(XRP(10)),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
ter(tesSUCCESS));
|
|
env.close();
|
|
}
|
|
|
|
void
|
|
testCheck()
|
|
{
|
|
testcase("Check");
|
|
using namespace test::jtx;
|
|
Account const alice("alice");
|
|
Account const bob("bob");
|
|
Account const gw("gw");
|
|
Account const sponsor("sponsor");
|
|
Account const sponsor2("sponsor2");
|
|
|
|
auto const USD = gw["USD"];
|
|
|
|
{
|
|
Env env{*this, testable_amendments()};
|
|
env.fund(XRP(10000), alice, bob, sponsor, sponsor2);
|
|
env.close();
|
|
|
|
// CheckCreate -> CheckCancel
|
|
auto const seq = env.seq(alice);
|
|
env(check::create(alice, bob, XRP(1)),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
sponsor::sig(sponsor));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1); // Check
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
|
|
|
|
auto const keylet = keylet::check(alice, seq);
|
|
BEAST_EXPECT(
|
|
env.le(keylet)->getAccountID(sfSponsorAccount) == sponsor.id());
|
|
|
|
// transfer sponsor
|
|
env(sponsor::transfer(alice, keylet.key),
|
|
sponsor::as(sponsor2, tfSponsorReserve),
|
|
sponsor::sig(sponsor2));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1); // Check
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1);
|
|
|
|
BEAST_EXPECT(
|
|
env.le(keylet)->getAccountID(sfSponsorAccount) ==
|
|
sponsor2.id());
|
|
|
|
// CheckCancel
|
|
env(check::cancel(alice, keylet.key));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 0);
|
|
}
|
|
|
|
{
|
|
Env env{*this, testable_amendments()};
|
|
env.fund(XRP(10000), alice, bob, sponsor);
|
|
env.close();
|
|
|
|
// CheckCreate -> CheckCash
|
|
auto const seq2 = env.seq(alice);
|
|
env(check::create(alice, bob, XRP(1)),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
sponsor::sig(sponsor));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1); // Check
|
|
BEAST_EXPECT(ownerCount(env, bob) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, bob) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
|
|
|
|
// CheckCash
|
|
auto const checkId2 = keylet::check(alice, seq2).key;
|
|
env(check::cash(bob, checkId2, XRP(1)),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
sponsor::sig(sponsor));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 0);
|
|
BEAST_EXPECT(ownerCount(env, bob) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, bob) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
}
|
|
|
|
// RippleState sponsor (CheckCashMakesTrustLine)
|
|
{
|
|
Env env{*this, testable_amendments()};
|
|
env.fund(XRP(10000), alice, bob, gw, sponsor, sponsor2);
|
|
env.close();
|
|
|
|
env.trust(USD(100), alice);
|
|
env.close();
|
|
env(pay(gw, alice, USD(100)));
|
|
env.close();
|
|
|
|
// CheckCreate -> CheckCash
|
|
auto const seq2 = env.seq(alice);
|
|
env(check::create(alice, bob, USD(1)),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
sponsor::sig(sponsor));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 2); // RippleState + Check
|
|
BEAST_EXPECT(ownerCount(env, bob) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, bob) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
|
|
|
|
auto const keylet = keylet::check(alice, seq2);
|
|
BEAST_EXPECT(
|
|
env.le(keylet)->getAccountID(sfSponsorAccount) == sponsor.id());
|
|
|
|
// CheckCash
|
|
env(check::cash(bob, keylet.key, USD(1)),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
sponsor::sig(sponsor));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1); // RippleState
|
|
BEAST_EXPECT(ownerCount(env, bob) == 1); // RippleState
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, bob) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
|
|
}
|
|
|
|
{
|
|
// check INSUFFICIENT_RESERVE
|
|
|
|
{
|
|
// CheckCreate
|
|
Env env{*this, testable_amendments()};
|
|
env.fund(XRP(10000), alice, bob, sponsor);
|
|
env.close();
|
|
|
|
adjustAccountXRPBalance(
|
|
env, sponsor, reserve(env, 1) - drops(1));
|
|
|
|
env(check::create(alice, bob, XRP(1)),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
sponsor::sig(sponsor),
|
|
ter(tecINSUFFICIENT_RESERVE));
|
|
env.close();
|
|
|
|
adjustAccountXRPBalance(env, sponsor, reserve(env, 1));
|
|
|
|
env(check::create(alice, bob, XRP(1)),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
sponsor::sig(sponsor),
|
|
ter(tesSUCCESS));
|
|
env.close();
|
|
}
|
|
|
|
{
|
|
// CheckCash (CheckCashMakesTrustLine)
|
|
Env env{*this, testable_amendments()};
|
|
env.fund(XRP(10000), alice, bob, gw, sponsor);
|
|
env.close();
|
|
|
|
env.trust(USD(100), alice);
|
|
env.close();
|
|
env(pay(gw, alice, USD(100)));
|
|
env.close();
|
|
|
|
auto const seq = env.seq(alice);
|
|
env(check::create(alice, bob, USD(1)));
|
|
env.close();
|
|
|
|
adjustAccountXRPBalance(
|
|
env, sponsor, reserve(env, 1) - drops(1));
|
|
|
|
auto const keylet = keylet::check(alice, seq);
|
|
env(check::cash(bob, keylet.key, USD(1)),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
sponsor::sig(sponsor),
|
|
ter(tecNO_LINE_INSUF_RESERVE));
|
|
env.close();
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
testOffer()
|
|
{
|
|
testcase("Offer");
|
|
using namespace test::jtx;
|
|
Account const alice("alice");
|
|
Account const bob("bob");
|
|
Account const gw("gw");
|
|
Account const sponsor1("sponsor1");
|
|
Account const sponsor2("sponsor2");
|
|
|
|
auto USD = gw["USD"];
|
|
auto EUR = gw["EUR"];
|
|
|
|
{
|
|
Env env{*this, testable_amendments()};
|
|
|
|
env.fund(XRP(10000), alice, gw, sponsor1, sponsor2);
|
|
env.close();
|
|
|
|
// OfferCreate
|
|
auto const seq = env.seq(alice);
|
|
env(offer(alice, USD(1), XRP(1)),
|
|
sponsor::as(sponsor1, tfSponsorReserve),
|
|
sponsor::sig(sponsor1));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor1) == 1);
|
|
|
|
// transfer sponsor
|
|
auto const keylet = keylet::offer(alice, seq);
|
|
env(sponsor::transfer(alice, keylet.key),
|
|
sponsor::as(sponsor2, tfSponsorReserve),
|
|
sponsor::sig(sponsor2));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor1) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1);
|
|
|
|
BEAST_EXPECT(
|
|
env.le(keylet)->getAccountID(sfSponsorAccount) ==
|
|
sponsor2.id());
|
|
|
|
// OfferCancel
|
|
env(offer_cancel(alice, seq));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor1) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 0);
|
|
}
|
|
|
|
{
|
|
Env env{*this, testable_amendments()};
|
|
|
|
env.fund(XRP(10000), alice, gw, sponsor1, sponsor2);
|
|
env.close();
|
|
|
|
// OfferCreate
|
|
auto const seq = env.seq(alice);
|
|
env(offer(alice, USD(1), XRP(1)),
|
|
sponsor::as(sponsor1, tfSponsorReserve),
|
|
sponsor::sig(sponsor1));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor1) == 1);
|
|
|
|
// OfferCreate with Cancel (new sponsor)
|
|
auto const seq2 = env.seq(alice);
|
|
env(offer(alice, USD(1), XRP(1)),
|
|
json(jss::OfferSequence, seq),
|
|
sponsor::as(sponsor2, tfSponsorReserve),
|
|
sponsor::sig(sponsor2));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor1) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1);
|
|
|
|
// OfferCreate with Cancel (no sponsor)
|
|
env(offer(alice, USD(1), XRP(1)), json(jss::OfferSequence, seq2));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor1) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 0);
|
|
}
|
|
|
|
// test Offer Execution doesn't sponsor new trustline
|
|
{
|
|
Env env{*this, testable_amendments()};
|
|
env.fund(XRP(10000), alice, bob, gw, sponsor1, sponsor2);
|
|
env.close();
|
|
|
|
env(trust(alice, USD(100)));
|
|
env(trust(bob, EUR(100)));
|
|
env.close();
|
|
|
|
env(pay(gw, alice, USD(100)));
|
|
env(pay(gw, bob, EUR(100)));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
|
BEAST_EXPECT(ownerCount(env, bob) == 1);
|
|
|
|
// OfferCreate
|
|
env(offer(alice, EUR(1), USD(1)),
|
|
sponsor::as(sponsor1, tfSponsorReserve),
|
|
sponsor::sig(sponsor1));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 2);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor1) == 1);
|
|
|
|
BEAST_EXPECT(ownerCount(env, bob) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, bob) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, bob) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 0);
|
|
|
|
// OfferCreate (cross offer)
|
|
env(offer(bob, USD(1), EUR(1)),
|
|
sponsor::as(sponsor2, tfSponsorReserve),
|
|
sponsor::sig(sponsor2));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 2);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor1) == 0);
|
|
|
|
// does not sponsor new trustline by cross offer
|
|
BEAST_EXPECT(ownerCount(env, bob) == 2);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, bob) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, bob) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 0);
|
|
}
|
|
|
|
{
|
|
// check INSUFFICIENT_RESERVE for OfferCreate
|
|
Env env{*this, testable_amendments()};
|
|
env.fund(XRP(10000), alice, bob, gw, sponsor1, sponsor2);
|
|
env.close();
|
|
|
|
env.trust(USD(100), alice);
|
|
env.close();
|
|
env(pay(gw, alice, USD(100)));
|
|
env.close();
|
|
|
|
adjustAccountXRPBalance(env, sponsor1, reserve(env, 1) - drops(1));
|
|
|
|
// fullly not crossed
|
|
env(offer(alice, USD(1), XRP(1)),
|
|
sponsor::as(sponsor1, tfSponsorReserve),
|
|
sponsor::sig(sponsor1),
|
|
ter(tecINSUF_RESERVE_OFFER));
|
|
|
|
// partially crossed
|
|
env(offer(gw, XRP(1), USD(1)));
|
|
env.close();
|
|
|
|
env(offer(alice, USD(5), XRP(5)),
|
|
sponsor::as(sponsor1, tfSponsorReserve),
|
|
sponsor::sig(sponsor1),
|
|
ter(tecINSUF_RESERVE_OFFER));
|
|
}
|
|
}
|
|
|
|
void
|
|
testTicket()
|
|
{
|
|
testcase("Ticket");
|
|
using namespace test::jtx;
|
|
Env env{*this, testable_amendments()};
|
|
Account const alice("alice");
|
|
Account const sponsor("master");
|
|
Account const sponsor2("sponsor2");
|
|
|
|
env.fund(XRP(1000000), alice, sponsor, sponsor2);
|
|
env.close();
|
|
|
|
// TicketCreate
|
|
std::uint32_t const ticketSeq{env.seq(alice) + 1};
|
|
env(ticket::create(alice, 250),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
sponsor::sig(sponsor));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 250);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 250);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 250);
|
|
|
|
auto const keylet = keylet::ticket(alice, ticketSeq);
|
|
BEAST_EXPECT(
|
|
env.le(keylet)->getAccountID(sfSponsorAccount) == sponsor.id());
|
|
|
|
// transfer sponsor
|
|
env(sponsor::transfer(alice, keylet.key),
|
|
sponsor::as(sponsor2, tfSponsorReserve),
|
|
sponsor::sig(sponsor2));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 250);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 250);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 249);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1);
|
|
|
|
BEAST_EXPECT(
|
|
env.le(keylet)->getAccountID(sfSponsorAccount) == sponsor2.id());
|
|
|
|
// use a Ticket
|
|
env(noop(alice), ticket::use(ticketSeq));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 249);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 249);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 249);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 0);
|
|
}
|
|
|
|
void
|
|
testCredentials()
|
|
{
|
|
testcase("Credentials");
|
|
using namespace test::jtx;
|
|
Env env{*this, testable_amendments()};
|
|
Account const issuer("issuer");
|
|
Account const subject("subject");
|
|
Account const sponsor("sponsor");
|
|
Account const sponsor2("sponsor2");
|
|
|
|
env.fund(XRP(1000000), issuer, subject, sponsor, sponsor2);
|
|
env.close();
|
|
|
|
auto const credType = std::string("credType");
|
|
auto const credTypeSlice = Slice(credType.data(), credType.size());
|
|
|
|
// CredentialsCreate
|
|
{
|
|
env(credentials::create(subject, issuer, credType),
|
|
credentials::uri("uri"),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
sponsor::sig(sponsor));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, issuer) == 1);
|
|
BEAST_EXPECT(ownerCount(env, subject) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, issuer) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, subject) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
|
|
|
|
// transfer sponsor
|
|
auto const keylet =
|
|
keylet::credential(subject, issuer, credTypeSlice);
|
|
env(sponsor::transfer(issuer, keylet.key),
|
|
sponsor::as(sponsor2, tfSponsorReserve),
|
|
sponsor::sig(sponsor2));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, issuer) == 1);
|
|
BEAST_EXPECT(ownerCount(env, subject) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, issuer) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, subject) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1);
|
|
|
|
// CredentialsAccept
|
|
env(credentials::accept(subject, issuer, credType),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
sponsor::sig(sponsor));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, issuer) == 0);
|
|
BEAST_EXPECT(ownerCount(env, subject) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, issuer) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, subject) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 0);
|
|
|
|
// CredentialsDelete
|
|
env(credentials::deleteCred(subject, subject, issuer, credType));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, issuer) == 0);
|
|
BEAST_EXPECT(ownerCount(env, subject) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, issuer) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, subject) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 0);
|
|
}
|
|
|
|
{
|
|
// Accept Sponsored Credentials without sponsoring
|
|
env(credentials::create(subject, issuer, credType),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
sponsor::sig(sponsor));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, issuer) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, issuer) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
|
|
|
|
env(credentials::accept(subject, issuer, credType));
|
|
env.close();
|
|
|
|
// sponsorship is removed
|
|
BEAST_EXPECT(ownerCount(env, issuer) == 0);
|
|
BEAST_EXPECT(ownerCount(env, subject) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, issuer) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, subject) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
BEAST_EXPECT(
|
|
!env.le(keylet::credential(subject, issuer, credTypeSlice))
|
|
->isFieldPresent(sfSponsorAccount));
|
|
|
|
env(credentials::deleteCred(subject, subject, issuer, credType));
|
|
env.close();
|
|
}
|
|
}
|
|
|
|
void
|
|
testDelegate()
|
|
{
|
|
testcase("Delegate");
|
|
using namespace test::jtx;
|
|
Env env{*this, testable_amendments()};
|
|
Account const alice("alice");
|
|
Account const bob("bob");
|
|
Account const sponsor("sponsor");
|
|
Account const sponsor2("sponsor2");
|
|
|
|
env.fund(XRP(1000000), alice, bob, sponsor, sponsor2);
|
|
env.close();
|
|
|
|
// DelegateSet
|
|
env(delegate::set(alice, bob, {"Payment"}),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
sponsor::sig(sponsor));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
|
|
|
|
// transfer sponsor
|
|
auto const keylet = keylet::delegate(alice, bob);
|
|
env(sponsor::transfer(alice, keylet.key),
|
|
sponsor::as(sponsor2, tfSponsorReserve),
|
|
sponsor::sig(sponsor2));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1);
|
|
|
|
// delete
|
|
env(delegate::set(alice, bob, {}));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
}
|
|
|
|
void
|
|
testDepositPreauth()
|
|
{
|
|
testcase("DepositPreauth");
|
|
using namespace test::jtx;
|
|
Env env{*this, testable_amendments()};
|
|
Account const alice("alice");
|
|
Account const sponsor("sponsor");
|
|
Account const sponsor2("sponsor2");
|
|
|
|
env.fund(XRP(1000000), alice, sponsor, sponsor2);
|
|
env.close();
|
|
|
|
// DepositPreauthSet
|
|
env(deposit::auth(alice, sponsor),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
sponsor::sig(sponsor));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
|
|
|
|
// transfer sponsor
|
|
auto const keylet = keylet::depositPreauth(alice, sponsor);
|
|
env(sponsor::transfer(alice, keylet.key),
|
|
sponsor::as(sponsor2, tfSponsorReserve),
|
|
sponsor::sig(sponsor2));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1);
|
|
|
|
// DepositPreauthDelete
|
|
env(deposit::unauth(alice, sponsor));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 0);
|
|
}
|
|
|
|
void
|
|
testDID()
|
|
{
|
|
testcase("DID");
|
|
using namespace test::jtx;
|
|
Env env{*this, testable_amendments()};
|
|
Account const alice("alice");
|
|
Account const sponsor("sponsor");
|
|
Account const sponsor2("sponsor2");
|
|
|
|
env.fund(XRP(1000000), alice, sponsor, sponsor2);
|
|
env.close();
|
|
|
|
// DIDSet
|
|
env(did::set(alice),
|
|
did::uri("uri"),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
sponsor::sig(sponsor));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
|
|
|
|
// transfer sponsor
|
|
auto const keylet = keylet::did(alice);
|
|
env(sponsor::transfer(alice, keylet.key),
|
|
sponsor::as(sponsor2, tfSponsorReserve),
|
|
sponsor::sig(sponsor2));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1);
|
|
|
|
// DIDDelete
|
|
env(did::del(alice));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 0);
|
|
}
|
|
|
|
void
|
|
testEscrow()
|
|
{
|
|
testcase("Escrow");
|
|
using namespace test::jtx;
|
|
using namespace std::chrono_literals;
|
|
|
|
Account const alice("alice");
|
|
Account const bob("bob");
|
|
Account const gw("gw");
|
|
Account const sponsor("sponsor");
|
|
Account const sponsor2("sponsor2");
|
|
auto const USD = gw["USD"];
|
|
{
|
|
// Native Escrow
|
|
Env env{*this, testable_amendments()};
|
|
auto const baseFee = env.current()->fees().base;
|
|
|
|
env.fund(XRP(1000000), alice, bob, sponsor, sponsor2);
|
|
env.close();
|
|
|
|
// EscrowCreate
|
|
auto const seq = env.seq(alice);
|
|
env(escrow::create(alice, bob, XRP(100)),
|
|
escrow::condition(escrow::cb1),
|
|
escrow::cancel_time(env.now() + 100s),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
sponsor::sig(sponsor));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
|
|
|
|
BEAST_EXPECT(
|
|
env.le(keylet::escrow(alice, seq))
|
|
->getAccountID(sfSponsorAccount) == sponsor.id());
|
|
|
|
// transfer sponsor
|
|
env(sponsor::transfer(alice, keylet::escrow(alice, seq).key),
|
|
sponsor::as(sponsor2, tfSponsorReserve),
|
|
sponsor::sig(sponsor2));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1);
|
|
|
|
BEAST_EXPECT(
|
|
env.le(keylet::escrow(alice, seq))
|
|
->getAccountID(sfSponsorAccount) == sponsor2.id());
|
|
|
|
// EscrowFinish
|
|
env(escrow::finish(bob, alice, seq),
|
|
escrow::condition(escrow::cb1),
|
|
escrow::fulfillment(escrow::fb1),
|
|
fee(baseFee * 150));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 0);
|
|
}
|
|
|
|
{
|
|
// IOU Escrow
|
|
Env env{*this, testable_amendments()};
|
|
auto const baseFee = env.current()->fees().base;
|
|
|
|
env.fund(XRP(1000000), alice, bob, gw, sponsor, sponsor2);
|
|
env.close();
|
|
|
|
env(fset(gw, asfAllowTrustLineLocking));
|
|
env.close();
|
|
|
|
env.trust(USD(1000000), alice);
|
|
env.close();
|
|
env(pay(gw, alice, USD(10000)));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
|
|
|
// EscrowCreate
|
|
auto const seq = env.seq(alice);
|
|
env(escrow::create(alice, bob, USD(100)),
|
|
escrow::condition(escrow::cb1),
|
|
escrow::cancel_time(env.now() + 10s),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
sponsor::sig(sponsor));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 2);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
|
|
|
|
BEAST_EXPECT(
|
|
env.le(keylet::escrow(alice, seq))
|
|
->getAccountID(sfSponsorAccount) == sponsor.id());
|
|
|
|
// EscrowFinish
|
|
env(escrow::finish(bob, alice, seq),
|
|
escrow::condition(escrow::cb1),
|
|
escrow::fulfillment(escrow::fb1),
|
|
sponsor::as(sponsor2, tfSponsorReserve),
|
|
sponsor::sig(sponsor2),
|
|
fee(baseFee * 150));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
|
|
BEAST_EXPECT(ownerCount(env, bob) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, bob) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1);
|
|
|
|
BEAST_EXPECT(
|
|
env.le(keylet::line(bob, gw, USD.currency))
|
|
->getAccountID(sfHighSponsorAccount) == sponsor2.id());
|
|
}
|
|
}
|
|
|
|
void
|
|
testMPToken()
|
|
{
|
|
testcase("MPToken");
|
|
using namespace test::jtx;
|
|
Env env{*this, testable_amendments()};
|
|
Account const alice("alice");
|
|
Account const bob("bob");
|
|
Account const sponsor("sponsor");
|
|
Account const sponsor2("sponsor2");
|
|
|
|
env.fund(XRP(1000000), alice, bob, sponsor, sponsor2);
|
|
env.close();
|
|
|
|
// MPTokenIssuanceCreate
|
|
Json::Value jv = {};
|
|
jv[sfAccount] = alice.human();
|
|
jv[sfTransactionType] = jss::MPTokenIssuanceCreate;
|
|
auto const mptid = makeMptID(env.seq(alice), alice.id());
|
|
env(jv, sponsor::as(sponsor, tfSponsorReserve), sponsor::sig(sponsor));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
|
|
|
|
// transfer sponsor
|
|
auto const mptIssuanceKeylet = keylet::mptIssuance(mptid);
|
|
env(sponsor::transfer(alice, mptIssuanceKeylet.key),
|
|
sponsor::as(sponsor2, tfSponsorReserve),
|
|
sponsor::sig(sponsor2));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1);
|
|
|
|
// MPTokenAuthorize
|
|
jv = {};
|
|
jv[sfTransactionType] = jss::MPTokenAuthorize;
|
|
jv[sfAccount] = bob.human();
|
|
jv[sfMPTokenIssuanceID] = to_string(mptid);
|
|
env(jv, sponsor::as(sponsor, tfSponsorReserve), sponsor::sig(sponsor));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
|
BEAST_EXPECT(ownerCount(env, bob) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, bob) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
|
|
|
|
// transfer sponsor
|
|
auto const mptTokenKeylet = keylet::mptoken(mptid, bob);
|
|
env(sponsor::transfer(bob, mptTokenKeylet.key),
|
|
sponsor::as(sponsor2, tfSponsorReserve),
|
|
sponsor::sig(sponsor2));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
|
BEAST_EXPECT(ownerCount(env, bob) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, bob) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 2);
|
|
|
|
// MPTokenAuthorize Unauthorize
|
|
jv = {};
|
|
jv[sfTransactionType] = jss::MPTokenAuthorize;
|
|
jv[sfAccount] = bob.human();
|
|
jv[sfMPTokenIssuanceID] = to_string(mptid);
|
|
jv[sfFlags] = tfMPTUnauthorize;
|
|
env(jv);
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
|
BEAST_EXPECT(ownerCount(env, bob) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, bob) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1);
|
|
|
|
// MPTokenIssuanceDestroy
|
|
jv = {};
|
|
jv[sfTransactionType] = jss::MPTokenIssuanceDestroy;
|
|
jv[sfAccount] = alice.human();
|
|
jv[sfMPTokenIssuanceID] = to_string(mptid);
|
|
env(jv);
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 0);
|
|
}
|
|
|
|
void
|
|
testNFToken()
|
|
{
|
|
testcase("NFToken");
|
|
using namespace test::jtx;
|
|
Account const alice("alice");
|
|
Account const bob("bob");
|
|
Account const sponsor("sponsor");
|
|
Account const sponsor2("sponsor2");
|
|
|
|
{
|
|
Env env{*this, testable_amendments()};
|
|
|
|
env.fund(XRP(1000000), alice, bob, sponsor);
|
|
env.close();
|
|
|
|
// NFTokenMint
|
|
uint256 const nftId{token::getNextID(env, alice, 0)};
|
|
env(token::mint(alice),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
sponsor::sig(sponsor));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
|
|
|
|
// NFTokenBurn
|
|
env(token::burn(alice, nftId));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
}
|
|
|
|
{
|
|
// multiple nft page process
|
|
Env env{*this, testable_amendments()};
|
|
|
|
env.fund(XRP(1000000), alice, bob, sponsor);
|
|
env.close();
|
|
|
|
auto const nftCount = 200;
|
|
|
|
// NFTokenMint
|
|
for (auto i = 0; i < nftCount; i++)
|
|
{
|
|
env(token::mint(alice),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
sponsor::sig(sponsor));
|
|
}
|
|
env.close();
|
|
|
|
BEAST_EXPECT(
|
|
ownerCount(env, alice) == sponsoredOwnerCount(env, alice));
|
|
BEAST_EXPECT(
|
|
sponsoredOwnerCount(env, alice) ==
|
|
sponsoringOwnerCount(env, sponsor));
|
|
|
|
// NFTokenBurn
|
|
for (auto i = 0; i < nftCount; i++)
|
|
{
|
|
auto const nftId = token::getID(env, alice, 0, i, 0, 0);
|
|
env(token::burn(alice, nftId));
|
|
}
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
}
|
|
}
|
|
|
|
void
|
|
testNFTokenOffer()
|
|
{
|
|
testcase("NFTokenOffer");
|
|
using namespace test::jtx;
|
|
Account const alice("alice");
|
|
Account const bob("bob");
|
|
Account const broker("broker");
|
|
Account const sponsor("sponsor");
|
|
Account const sponsor2("sponsor2");
|
|
|
|
auto const taxon = 0u;
|
|
|
|
{
|
|
// Mint + CreateOffer + CancelOffer
|
|
Env env{*this, testable_amendments()};
|
|
env.fund(XRP(1000000), alice, bob, sponsor, sponsor2);
|
|
env.close();
|
|
|
|
// Mint
|
|
uint256 const nftId{
|
|
token::getNextID(env, alice, taxon, tfTransferable)};
|
|
env(token::mint(alice, taxon), txflags(tfTransferable));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
|
|
|
// NFTokenOfferCreate
|
|
uint256 const offerIndex1 =
|
|
keylet::nftoffer(alice, env.seq(alice)).key;
|
|
env(token::createOffer(alice, nftId, XRP(1)),
|
|
token::destination(bob),
|
|
txflags(tfSellNFToken),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
sponsor::sig(sponsor));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 2);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
|
|
|
|
uint256 const offerIndex2 =
|
|
keylet::nftoffer(alice, env.seq(alice)).key;
|
|
env(token::createOffer(alice, nftId, XRP(1)),
|
|
token::destination(bob),
|
|
txflags(tfSellNFToken),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
sponsor::sig(sponsor));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 3);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 2);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 2);
|
|
|
|
// transfer sponsor
|
|
env(sponsor::transfer(alice, offerIndex1),
|
|
sponsor::as(sponsor2, tfSponsorReserve),
|
|
sponsor::sig(sponsor2));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 3);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 2);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1);
|
|
|
|
// NFTokenOfferCancel
|
|
env(token::cancelOffer(alice, {offerIndex1, offerIndex2}));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 0);
|
|
}
|
|
|
|
{
|
|
// Mint + CreateSellOffer + AcceptSellOffer
|
|
Env env{*this, testable_amendments()};
|
|
env.fund(XRP(1000000), alice, bob, sponsor);
|
|
env.close();
|
|
|
|
// Mint
|
|
uint256 const nftId{
|
|
token::getNextID(env, alice, taxon, tfTransferable)};
|
|
env(token::mint(alice, taxon), txflags(tfTransferable));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
|
|
|
// NFTokenOfferCreate
|
|
uint256 const offerIndex =
|
|
keylet::nftoffer(alice, env.seq(alice)).key;
|
|
env(token::createOffer(alice, nftId, XRP(1)),
|
|
token::destination(bob),
|
|
txflags(tfSellNFToken),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
sponsor::sig(sponsor));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 2);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
|
|
|
|
// NFTokenOfferAccept
|
|
env(token::acceptSellOffer(bob, offerIndex));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 0);
|
|
BEAST_EXPECT(ownerCount(env, bob) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, bob) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
}
|
|
|
|
{
|
|
// Mint + CreateBuyOffer + AcceptBuyOffer
|
|
Env env{*this, testable_amendments()};
|
|
env.fund(XRP(1000000), alice, bob, sponsor);
|
|
env.close();
|
|
|
|
// Mint
|
|
uint256 const nftId{
|
|
token::getNextID(env, alice, taxon, tfTransferable)};
|
|
env(token::mint(alice, taxon), txflags(tfTransferable));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
|
|
|
// NFTokenOfferCreate
|
|
uint256 const offerIndex = keylet::nftoffer(bob, env.seq(bob)).key;
|
|
env(token::createOffer(bob, nftId, XRP(1)),
|
|
token::owner(alice),
|
|
token::destination(alice),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
sponsor::sig(sponsor));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, bob) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, bob) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
|
|
|
|
// NFTokenOfferAccept
|
|
env(token::acceptBuyOffer(alice, offerIndex));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 0);
|
|
BEAST_EXPECT(ownerCount(env, bob) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, bob) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
}
|
|
{
|
|
// Broker
|
|
Env env{*this, testable_amendments()};
|
|
env.fund(XRP(1000000), alice, bob, broker, sponsor, sponsor2);
|
|
env.close();
|
|
|
|
// Mint
|
|
uint256 const nftId{
|
|
token::getNextID(env, alice, taxon, tfTransferable)};
|
|
env(token::mint(alice, taxon), txflags(tfTransferable));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
|
|
|
// NFTokenOfferCreate (BuyOffer)
|
|
uint256 const buyOfferIndex =
|
|
keylet::nftoffer(bob, env.seq(bob)).key;
|
|
env(token::createOffer(bob, nftId, XRP(1)),
|
|
token::owner(alice),
|
|
token::destination(broker),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
sponsor::sig(sponsor));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, bob) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, bob) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
|
|
|
|
// NFTokenOfferCreate (SellOffer)
|
|
uint256 const sellOfferIndex =
|
|
keylet::nftoffer(alice, env.seq(alice)).key;
|
|
env(token::createOffer(alice, nftId, XRP(1)),
|
|
txflags(tfSellNFToken),
|
|
token::destination(broker),
|
|
sponsor::as(sponsor2, tfSponsorReserve),
|
|
sponsor::sig(sponsor2));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 2);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1);
|
|
|
|
// NFTokenOfferAccept
|
|
env(token::brokerOffers(broker, buyOfferIndex, sellOfferIndex));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 0);
|
|
BEAST_EXPECT(ownerCount(env, bob) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, bob) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 0);
|
|
}
|
|
}
|
|
|
|
void
|
|
testPayChan()
|
|
{
|
|
testcase("PayChan");
|
|
using namespace test::jtx;
|
|
using namespace std::literals::chrono_literals;
|
|
Env env{*this, testable_amendments()};
|
|
Account const alice("alice");
|
|
Account const bob("bob");
|
|
Account const sponsor("sponsor");
|
|
Account const sponsor2("sponsor2");
|
|
|
|
env.fund(XRP(1000000), alice, bob, sponsor, sponsor2);
|
|
env.close();
|
|
|
|
// PayChanCreate
|
|
auto const pk = alice.pk();
|
|
auto const settleDelay = 10s;
|
|
auto const chan = paychan::channel(alice, bob, env.seq(alice));
|
|
env(paychan::create(alice, bob, XRP(100), settleDelay, pk),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
sponsor::sig(sponsor));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
|
|
|
|
// transfer sponsor
|
|
env(sponsor::transfer(alice, chan),
|
|
sponsor::as(sponsor2, tfSponsorReserve),
|
|
sponsor::sig(sponsor2));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1);
|
|
|
|
env.close(env.now() + settleDelay);
|
|
// PayChanClaim (delete PayChan)
|
|
env(paychan::claim(bob, chan), txflags(tfClose));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 0);
|
|
}
|
|
|
|
void
|
|
testPermissionedDomain()
|
|
{
|
|
testcase("PermissionedDomain");
|
|
using namespace test::jtx;
|
|
Env env{*this, testable_amendments()};
|
|
Account const alice("alice");
|
|
Account const sponsor("sponsor");
|
|
Account const sponsor2("sponsor2");
|
|
|
|
env.fund(XRP(1000000), alice, sponsor, sponsor2);
|
|
env.close();
|
|
|
|
// PermissionedDomainSet
|
|
auto const seq = env.seq(alice);
|
|
pdomain::Credentials credentials{{alice, "first credential"}};
|
|
env(pdomain::setTx(alice, credentials),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
sponsor::sig(sponsor));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
|
|
|
|
// transfer sponsor
|
|
env(sponsor::transfer(
|
|
alice, keylet::permissionedDomain(alice, seq).key),
|
|
sponsor::as(sponsor2, tfSponsorReserve),
|
|
sponsor::sig(sponsor2));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1);
|
|
|
|
// PermissionedDomainDelete
|
|
auto objects = pdomain::getObjects(alice, env);
|
|
auto const domain = objects.begin()->first;
|
|
env(pdomain::deleteTx(alice, domain));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 0);
|
|
}
|
|
|
|
void
|
|
testOracle()
|
|
{
|
|
testcase("Oracle");
|
|
using namespace test::jtx;
|
|
using namespace std::chrono;
|
|
using DataSeries = std::vector<
|
|
std::tuple<std::string, std::string, std::uint32_t, std::uint8_t>>;
|
|
|
|
Env env{*this, testable_amendments()};
|
|
Account const alice("alice");
|
|
Account const sponsor("sponsor");
|
|
Account const sponsor2("sponsor2");
|
|
|
|
env.fund(XRP(1000000), alice, sponsor, sponsor2);
|
|
env.close();
|
|
|
|
auto const oracleSet =
|
|
[&env](Account const& account, uint8_t dataSeriesSize) {
|
|
auto const now = env.timeKeeper().now();
|
|
env.close(now + oracle::testStartTime - epoch_offset);
|
|
Json::Value jv;
|
|
jv[jss::TransactionType] = jss::OracleSet;
|
|
jv[jss::Account] = to_string(account);
|
|
jv[jss::OracleDocumentID] = 1;
|
|
jv[jss::LastUpdateTime] = to_string(
|
|
duration_cast<seconds>(
|
|
env.current()->info().closeTime.time_since_epoch())
|
|
.count() +
|
|
epoch_offset.count() + 100);
|
|
jv[jss::PriceDataSeries] = Json::arrayValue;
|
|
jv[jss::Provider] = strHex(std::string{"provider"});
|
|
jv[jss::AssetClass] = strHex(std::string{"currency"});
|
|
|
|
DataSeries const series = {
|
|
{"XRP", "US1", 740, 1},
|
|
{"XRP", "US2", 750, 1},
|
|
{"XRP", "US3", 740, 1},
|
|
{"XRP", "US4", 750, 1},
|
|
{"XRP", "US5", 740, 1},
|
|
{"XRP", "US6", 750, 1},
|
|
{"XRP", "US7", 740, 1},
|
|
{"XRP", "US8", 750, 1},
|
|
{"XRP", "US9", 740, 1},
|
|
{"XRP", "U10", 750, 1},
|
|
};
|
|
|
|
DataSeries actualSeries(
|
|
series.begin(), series.begin() + dataSeriesSize);
|
|
|
|
Json::Value dataSeries(Json::arrayValue);
|
|
for (auto const& data : actualSeries)
|
|
{
|
|
Json::Value priceData;
|
|
Json::Value price;
|
|
price[jss::BaseAsset] = std::get<0>(data);
|
|
price[jss::QuoteAsset] = std::get<1>(data);
|
|
price[jss::AssetPrice] = std::get<2>(data);
|
|
price[jss::Scale] = std::get<3>(data);
|
|
priceData[jss::PriceData] = price;
|
|
dataSeries.append(priceData);
|
|
}
|
|
jv[jss::PriceDataSeries] = dataSeries;
|
|
return jv;
|
|
};
|
|
|
|
auto const oracleDelete = [&](Account const& account) {
|
|
Json::Value jv;
|
|
jv[jss::TransactionType] = jss::OracleDelete;
|
|
jv[jss::Account] = to_string(account);
|
|
jv[jss::OracleDocumentID] = 1;
|
|
return jv;
|
|
};
|
|
|
|
{
|
|
// OracleSet (reserve 1)
|
|
env(oracleSet(alice, 5),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
sponsor::sig(sponsor));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
|
|
|
|
// transfer sponsor
|
|
env(sponsor::transfer(alice, keylet::oracle(alice, 1).key),
|
|
sponsor::as(sponsor2, tfSponsorReserve),
|
|
sponsor::sig(sponsor2));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1);
|
|
|
|
// OracleDelete
|
|
env(oracleDelete(alice));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 0);
|
|
}
|
|
{
|
|
// OracleSet (reserve 2)
|
|
env(oracleSet(alice, 6),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
sponsor::sig(sponsor));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 2);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 2);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 2);
|
|
|
|
// transfer sponsor
|
|
env(sponsor::transfer(alice, keylet::oracle(alice, 1).key),
|
|
sponsor::as(sponsor2, tfSponsorReserve),
|
|
sponsor::sig(sponsor2));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 2);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 2);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 2);
|
|
|
|
// OracleDelete
|
|
env(oracleDelete(alice));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 0);
|
|
}
|
|
{
|
|
// OracleSet (reserve 1->2, sponsor1 -> no-sponsor)
|
|
env(oracleSet(alice, 5),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
sponsor::sig(sponsor));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
|
|
|
|
// reserve 1->2
|
|
env(oracleSet(alice, 6));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 2);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
|
|
// OracleDelete
|
|
env(oracleDelete(alice));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
}
|
|
{
|
|
// OracleSet (reserve 1->2, sponsor1 -> sponsor2)
|
|
env(oracleSet(alice, 5),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
sponsor::sig(sponsor));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
|
|
|
|
// reserve 1->2
|
|
env(oracleSet(alice, 6),
|
|
sponsor::as(sponsor2, tfSponsorReserve),
|
|
sponsor::sig(sponsor2));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 2);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 2);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 2);
|
|
|
|
// OracleDelete
|
|
env(oracleDelete(alice));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 0);
|
|
}
|
|
{
|
|
// OracleSet (reserve 1->2, non-sponsor -> sponsor1)
|
|
env(oracleSet(alice, 5));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
|
|
|
// reserve 1->2
|
|
env(oracleSet(alice, 6),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
sponsor::sig(sponsor));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 2);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 2);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 2);
|
|
|
|
// OracleDelete
|
|
env(oracleDelete(alice));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
}
|
|
for (bool isTwoOwnerCount : {false, true})
|
|
{
|
|
// test sponsor transfer
|
|
auto const dataSeriesSize = isTwoOwnerCount ? 6 : 5;
|
|
auto const ocount = isTwoOwnerCount ? 2 : 1;
|
|
env(oracleSet(alice, dataSeriesSize),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
sponsor::sig(sponsor));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == ocount);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == ocount);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == ocount);
|
|
|
|
// transfer sponsor
|
|
env(sponsor::transfer(alice, keylet::oracle(alice, 1).key),
|
|
sponsor::as(sponsor2, tfSponsorReserve),
|
|
sponsor::sig(sponsor2));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == ocount);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == ocount);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == ocount);
|
|
|
|
// disolve sponsor
|
|
env(sponsor::transfer(alice, keylet::oracle(alice, 1).key));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == ocount);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 0);
|
|
}
|
|
}
|
|
|
|
void
|
|
testSignerList()
|
|
{
|
|
testcase("SignerList");
|
|
using namespace test::jtx;
|
|
Env env{*this, testable_amendments()};
|
|
Account const alice("alice");
|
|
Account const sponsor("sponsor");
|
|
Account const sponsor2("sponsor2");
|
|
|
|
env.fund(XRP(1000000), alice, sponsor, sponsor2);
|
|
env.close();
|
|
|
|
Account const bob("bob");
|
|
|
|
// SignerListSet
|
|
env(signers(alice, 1, {{bob, 1}}),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
sponsor::sig(sponsor));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
|
|
|
|
// transfer sponsor
|
|
env(sponsor::transfer(alice, keylet::signers(alice).key),
|
|
sponsor::as(sponsor2, tfSponsorReserve),
|
|
sponsor::sig(sponsor2));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1);
|
|
|
|
// Delete
|
|
env(signers(alice, none));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 0);
|
|
}
|
|
|
|
void
|
|
testTrustSet()
|
|
{
|
|
testcase("TrustSet");
|
|
using namespace test::jtx;
|
|
Env env{*this, testable_amendments()};
|
|
Account const alice("alice");
|
|
Account const bob("bob");
|
|
Account const sponsor("sponsor");
|
|
Account const sponsor2("sponsor2");
|
|
|
|
env.fund(XRP(1000000), alice, bob, sponsor, sponsor2);
|
|
env.close();
|
|
|
|
auto const& highAcc = alice > bob ? alice : bob;
|
|
auto const& lowAcc = alice > bob ? bob : alice;
|
|
for (bool isIssuerHigh : {false, true})
|
|
{
|
|
auto const& issuer = isIssuerHigh ? highAcc : lowAcc;
|
|
auto const& user = isIssuerHigh ? lowAcc : highAcc;
|
|
|
|
auto const USD = issuer["USD"];
|
|
|
|
// create TrustLine
|
|
env(trust(user, USD(100)),
|
|
sponsor::as(sponsor, tfSponsorReserve),
|
|
sponsor::sig(sponsor));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, user) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, user) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
|
|
|
|
auto const line = env.le(keylet::line(user, issuer, USD.currency));
|
|
BEAST_EXPECT(
|
|
line->getAccountID(
|
|
isIssuerHigh ? sfLowSponsorAccount
|
|
: sfHighSponsorAccount) == sponsor.id());
|
|
BEAST_EXPECT(!line->isFieldPresent(
|
|
isIssuerHigh ? sfHighSponsorAccount : sfLowSponsorAccount));
|
|
|
|
// transfer sponsor
|
|
env(sponsor::transfer(
|
|
user, keylet::line(user, issuer, USD.currency).key),
|
|
sponsor::as(sponsor2, tfSponsorReserve),
|
|
sponsor::sig(sponsor2));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, user) == 1);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, user) == 1);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1);
|
|
|
|
auto const line2 = env.le(keylet::line(user, issuer, USD.currency));
|
|
BEAST_EXPECT(
|
|
line2->getAccountID(
|
|
isIssuerHigh ? sfLowSponsorAccount
|
|
: sfHighSponsorAccount) == sponsor2.id());
|
|
BEAST_EXPECT(!line2->isFieldPresent(
|
|
isIssuerHigh ? sfHighSponsorAccount : sfLowSponsorAccount));
|
|
|
|
// delete TrustLine
|
|
env(trust(user, USD(0)));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(ownerCount(env, user) == 0);
|
|
BEAST_EXPECT(sponsoredOwnerCount(env, user) == 0);
|
|
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
|
|
|
BEAST_EXPECT(!env.le(keylet::line(user, issuer, USD.currency)));
|
|
}
|
|
}
|
|
|
|
void
|
|
testVault()
|
|
{
|
|
}
|
|
|
|
void
|
|
testXChain()
|
|
{
|
|
}
|
|
|
|
void
|
|
testDisallowIncoming()
|
|
{
|
|
testcase("DisallowIncoming");
|
|
using namespace test::jtx;
|
|
Env env{*this, testable_amendments()};
|
|
Account const alice("alice");
|
|
Account const sponsor("sponsor");
|
|
|
|
env.fund(XRP(1000000), alice, sponsor);
|
|
env.close();
|
|
|
|
// set DisallowIncomingSponsor
|
|
env(fset(alice, asfDisallowIncomingSponsor));
|
|
env.close();
|
|
|
|
// Create sponsor should fail
|
|
env(sponsor::set(sponsor, 0, 100, XRP(100)),
|
|
sponsor::sponseeAcc(alice),
|
|
ter(tecNO_PERMISSION));
|
|
env.close();
|
|
|
|
// clear flag
|
|
env(fclear(alice, asfDisallowIncomingSponsor));
|
|
env.close();
|
|
|
|
// Create sponsor
|
|
env(sponsor::set(sponsor, 0, 100, XRP(100)),
|
|
sponsor::sponseeAcc(alice),
|
|
ter(tesSUCCESS));
|
|
env.close();
|
|
|
|
// set flag
|
|
env(fset(alice, asfDisallowIncomingSponsor));
|
|
env.close();
|
|
|
|
// Update sponsor should success
|
|
env(sponsor::set(sponsor, 0, 100, XRP(100)),
|
|
sponsor::sponseeAcc(alice),
|
|
ter(tesSUCCESS));
|
|
env.close();
|
|
|
|
// Delete sponsor should success
|
|
env(sponsor::set(sponsor, tfDeleteObject),
|
|
sponsor::sponseeAcc(alice),
|
|
ter(tesSUCCESS));
|
|
env.close();
|
|
}
|
|
void
|
|
testAccountDelete()
|
|
{
|
|
testcase("AccountDelete");
|
|
using namespace test::jtx;
|
|
Account const alice("alice");
|
|
Account const bob("bob");
|
|
Account const sponsor("sponsor");
|
|
|
|
{
|
|
// Delete Account with ltSponsorship
|
|
Env env{*this, testable_amendments()};
|
|
env.fund(XRP(1000000), alice, bob, sponsor);
|
|
env.close();
|
|
|
|
// set sponsor
|
|
env(sponsor::set(sponsor, 0, 100, XRP(100)),
|
|
sponsor::sponseeAcc(alice),
|
|
ter(tesSUCCESS));
|
|
env.close();
|
|
|
|
incLgrSeqForAccDel(env, alice);
|
|
|
|
auto const keylet = keylet::sponsor(sponsor, alice);
|
|
auto const sponsorObj = env.le(keylet);
|
|
BEAST_EXPECT(sponsorObj);
|
|
|
|
// AccountDelete
|
|
auto const requiredFee = drops(env.current()->fees().increment);
|
|
env(acctdelete(alice, bob), fee(requiredFee), ter(tesSUCCESS));
|
|
env.close();
|
|
|
|
BEAST_EXPECT(!env.le(keylet));
|
|
auto const jv = sponsor::ledgerEntry(env, sponsor, alice);
|
|
BEAST_EXPECT(
|
|
jv.isObject() && jv.isMember(jss::result) &&
|
|
jv[jss::result].isMember(jss::error) &&
|
|
jv[jss::result][jss::error] == "entryNotFound");
|
|
}
|
|
|
|
{
|
|
// Delete SponsoredAccount
|
|
Env env{*this, testable_amendments()};
|
|
env.memoize(alice);
|
|
env.fund(XRP(1000000), bob, sponsor);
|
|
env.close();
|
|
|
|
// create SponsoredAccount
|
|
env(pay(sponsor, alice, XRP(10000)),
|
|
txflags(tfSponsorCreatedAccount));
|
|
env.close();
|
|
|
|
incLgrSeqForAccDel(env, alice);
|
|
|
|
// AccountDelete: destination = non-sponsor
|
|
auto const requiredFee = drops(env.current()->fees().increment);
|
|
env(acctdelete(alice, bob),
|
|
fee(requiredFee),
|
|
ter(tecNO_SPONSOR_PERMISSION));
|
|
|
|
auto const sponsorSle = env.le(keylet::account(sponsor));
|
|
BEAST_EXPECT(
|
|
sponsorSle->getFieldU32(sfSponsoringAccountCount) == 1);
|
|
|
|
incLgrSeqForAccDel(env, alice);
|
|
|
|
// AccountDelete: destination = sponsor
|
|
env(acctdelete(alice, sponsor), fee(requiredFee), ter(tesSUCCESS));
|
|
|
|
auto const sponsorSle2 = env.le(keylet::account(sponsor));
|
|
BEAST_EXPECT(
|
|
!sponsorSle2->isFieldPresent(sfSponsoringAccountCount));
|
|
}
|
|
}
|
|
|
|
void
|
|
testDelegatePermission()
|
|
{
|
|
testcase("DelegatePermission");
|
|
using namespace test::jtx;
|
|
Account const alice("alice");
|
|
Account const bob("bob");
|
|
Account const carol("carol");
|
|
|
|
//
|
|
// Permission SponsorFee
|
|
//
|
|
{
|
|
Env env{*this, testable_amendments()};
|
|
env.fund(XRP(1000000), alice, bob, carol);
|
|
env.close();
|
|
auto const testFeePermission = [&](TER result) {
|
|
// FeeAmount
|
|
env(sponsor::set(alice, 0, std::nullopt, XRP(100)),
|
|
sponsor::sponseeAcc(bob),
|
|
delegate::as(carol),
|
|
ter(result));
|
|
// MaxFee
|
|
env(sponsor::set(
|
|
alice, 0, std::nullopt, std::nullopt, XRP(100)),
|
|
sponsor::sponseeAcc(bob),
|
|
delegate::as(carol),
|
|
ter(result));
|
|
// SetRequireSignForFee flag
|
|
env(sponsor::set(alice, tfSponsorshipSetRequireSignForFee),
|
|
sponsor::sponseeAcc(bob),
|
|
delegate::as(carol),
|
|
ter(result));
|
|
env.close();
|
|
};
|
|
|
|
// no delegated
|
|
testFeePermission(tecNO_DELEGATE_PERMISSION);
|
|
|
|
// set non-SponsorFee Permission
|
|
env(delegate::set(alice, carol, {"SponsorReserve"}));
|
|
env.close();
|
|
|
|
testFeePermission(tecNO_DELEGATE_PERMISSION);
|
|
|
|
// set SponsorFee Permission
|
|
env(delegate::set(alice, carol, {"SponsorFee"}));
|
|
env.close();
|
|
|
|
testFeePermission(tesSUCCESS);
|
|
}
|
|
|
|
//
|
|
// Permission SponsorReserve
|
|
//
|
|
{
|
|
Env env{*this, testable_amendments()};
|
|
env.fund(XRP(1000000), alice, bob, carol);
|
|
env.close();
|
|
|
|
auto const testReservePermission = [&](TER result) {
|
|
// ReserveCount
|
|
env(sponsor::set(alice, 0, 100),
|
|
sponsor::sponseeAcc(bob),
|
|
delegate::as(carol),
|
|
ter(result));
|
|
// SetRequireSignForReserve flag
|
|
env(sponsor::set(alice, tfSponsorshipSetRequireSignForReserve),
|
|
sponsor::sponseeAcc(bob),
|
|
delegate::as(carol),
|
|
ter(result));
|
|
env.close();
|
|
};
|
|
|
|
// no delegated
|
|
testReservePermission(tecNO_DELEGATE_PERMISSION);
|
|
|
|
// set non-SponsorReserve Permission
|
|
env(delegate::set(alice, carol, {"SponsorFee"}));
|
|
env.close();
|
|
|
|
testReservePermission(tecNO_DELEGATE_PERMISSION);
|
|
|
|
// set SponsorReserve Permission
|
|
env(delegate::set(alice, carol, {"SponsorReserve"}));
|
|
env.close();
|
|
|
|
testReservePermission(tesSUCCESS);
|
|
}
|
|
}
|
|
|
|
void
|
|
testSponsorReserve()
|
|
{
|
|
// TODO: add checks fo InsufficientReserve for Sponsoring ledger entry
|
|
testRequireFlag();
|
|
testCheck();
|
|
testOffer();
|
|
testTicket();
|
|
testCredentials();
|
|
testDelegate();
|
|
testDepositPreauth();
|
|
testDID();
|
|
testEscrow();
|
|
testMPToken();
|
|
testNFToken();
|
|
testNFTokenOffer();
|
|
testPayChan();
|
|
testPermissionedDomain();
|
|
testOracle();
|
|
testSignerList();
|
|
testTrustSet();
|
|
// testVault();
|
|
// testXChain();
|
|
}
|
|
|
|
void
|
|
run() override
|
|
{
|
|
testDisabled();
|
|
testInvalidSponsorshipSet();
|
|
|
|
testSingleSigning();
|
|
testMultiSigning();
|
|
// testInvalidSigninig(); // borh TxnSignature and Signers are present
|
|
// -> error
|
|
testSimpleSponsorshipSet();
|
|
|
|
testTransferSponsor();
|
|
testSponsorFee();
|
|
testSponsorAccount();
|
|
testSponsorReserve();
|
|
testDisallowIncoming();
|
|
|
|
testAccountDelete();
|
|
|
|
testDelegatePermission();
|
|
}
|
|
};
|
|
|
|
BEAST_DEFINE_TESTSUITE(Sponsor, app, ripple);
|
|
|
|
} // namespace test
|
|
} // namespace ripple
|