Compare commits

..

4 Commits

Author SHA1 Message Date
Richard Holland
99b70c58b5 add overflow check to dropsAdded accumulator 2023-12-28 09:53:11 +00:00
RichardAH
4ad697069f Fix xahau v1audit (#250) 2023-12-27 14:53:38 +01:00
Denis Angell
97acfe9f97 Fix: URIToken Test (#247) 2023-12-22 11:54:54 +01:00
Denis Angell
475b6f7347 Amendment: Fix Xahau v1 (#231)
* FXV1: Meta Amount (#225)

* FXV1: Optional Offer Sequence (#224)

* FXV1: Patch Hooks OwnerDir (#236)

* FXV1:  Fix `Import` Quorum (#235)

* FXV1: Namespace Limit (#220)

* FXV1: allow duplicate entries in genesis mint transactor (#239)

* FXV1: Fix URIToken (#243)

* lite fixes for tsh issues (#244)

Co-authored-by: RichardAH <richard.holland@starstone.co.nz>
2023-12-21 16:21:17 +01:00
20 changed files with 2167 additions and 2143 deletions

View File

@@ -2030,19 +2030,20 @@ TxQ::doRPC(Application& app, std::optional<XRPAmount> hookFeeUnits) const
levels[jss::median_level] = to_string(metrics.medFeeLevel);
levels[jss::open_ledger_level] = to_string(metrics.openLedgerFeeLevel);
auto const txFee = XRPAmount{hookFeeUnits->drops()};
auto const baseFee = view->fees().base;
auto const baseFee =
hookFeeUnits ? XRPAmount{hookFeeUnits->drops()} : view->fees().base;
// If the base fee is 0 drops, but escalation has kicked in, treat the
// base fee as if it is 1 drop, which makes the rest of the math
// work.
auto const effectiveBaseFee = [&txFee, &metrics]() {
if (!txFee && metrics.openLedgerFeeLevel != metrics.referenceFeeLevel)
auto const effectiveBaseFee = [&baseFee, &metrics]() {
if (!baseFee && metrics.openLedgerFeeLevel != metrics.referenceFeeLevel)
return XRPAmount{1};
return txFee;
return baseFee;
}();
auto& drops = ret[jss::drops] = Json::Value();
drops[jss::base_fee_no_hooks] = to_string(view->fees().base);
drops[jss::base_fee] = to_string(baseFee);
drops[jss::median_fee] = to_string(toDrops(metrics.medFeeLevel, baseFee));
drops[jss::minimum_fee] = to_string(toDrops(

View File

@@ -111,6 +111,14 @@ CancelOffer::doApply()
JLOG(j_.debug()) << "Trying to cancel offer :" << *offerID;
else
JLOG(j_.debug()) << "Trying to cancel offer #" << *offerSequence;
bool const fixV1 = view().rules().enabled(fixXahauV1);
if (fixV1 && sleOffer->getFieldU16(sfLedgerEntryType) != ltOFFER)
{
JLOG(j_.debug()) << "OfferCancel specified non-offer ledger object";
return tecINTERNAL;
}
return offerDelete(view(), sleOffer, ctx_.app.journal("View"));
}

View File

@@ -431,9 +431,25 @@ EscrowFinish::preflight(PreflightContext const& ctx)
}
}
if (!ctx.tx.isFieldPresent(sfEscrowID) &&
!ctx.tx.isFieldPresent(sfOfferSequence))
return temMALFORMED;
// sfOfferSequence was changed to optional, so ensure the behaviour is the
// same until amendment passes
if (!ctx.rules.enabled(fixXahauV1))
{
if (!ctx.tx.isFieldPresent(sfOfferSequence))
return temMALFORMED;
if (ctx.tx.isFieldPresent(sfEscrowID) &&
ctx.tx.getFieldU32(sfOfferSequence) != 0)
return temMALFORMED;
}
else
{
if ((!ctx.tx.isFieldPresent(sfEscrowID) &&
!ctx.tx.isFieldPresent(sfOfferSequence)) ||
ctx.tx.isFieldPresent(sfEscrowID) &&
ctx.tx.isFieldPresent(sfOfferSequence))
return temMALFORMED;
}
return tesSUCCESS;
}
@@ -462,16 +478,7 @@ EscrowFinish::doApply()
std::optional<uint256> escrowID = ctx_.tx[~sfEscrowID];
std::optional<std::uint32_t> offerSequence = ctx_.tx[~sfOfferSequence];
if (!view().rules().enabled(fixXahauV1))
{
if (escrowID && ctx_.tx[sfOfferSequence] != 0)
return temMALFORMED;
}
else
{
if (escrowID && offerSequence)
return temMALFORMED;
}
bool const fixV1 = view().rules().enabled(fixXahauV1);
Keylet k = escrowID ? Keylet(ltESCROW, *escrowID)
: keylet::escrow(ctx_.tx[sfOwner], *offerSequence);
@@ -480,6 +487,9 @@ EscrowFinish::doApply()
if (!slep)
return tecNO_TARGET;
if (fixV1 && slep->getFieldU16(sfLedgerEntryType) != ltESCROW)
return tecINTERNAL;
AccountID const account = (*slep)[sfAccount];
auto const sle = ctx_.view().peek(keylet::account(account));
auto const amount = slep->getFieldAmount(sfAmount);
@@ -704,9 +714,25 @@ EscrowCancel::preflight(PreflightContext const& ctx)
if (auto const ret = preflight1(ctx); !isTesSuccess(ret))
return ret;
if (!ctx.tx.isFieldPresent(sfEscrowID) &&
!ctx.tx.isFieldPresent(sfOfferSequence))
return temMALFORMED;
// sfOfferSequence was changed to optional, so ensure the behaviour is the
// same until amendment passes
if (!ctx.rules.enabled(fixXahauV1))
{
if (!ctx.tx.isFieldPresent(sfOfferSequence))
return temMALFORMED;
if (ctx.tx.isFieldPresent(sfEscrowID) &&
ctx.tx.getFieldU32(sfOfferSequence) != 0)
return temMALFORMED;
}
else
{
if ((!ctx.tx.isFieldPresent(sfEscrowID) &&
!ctx.tx.isFieldPresent(sfOfferSequence)) ||
ctx.tx.isFieldPresent(sfEscrowID) &&
ctx.tx.isFieldPresent(sfOfferSequence))
return temMALFORMED;
}
return preflight2(ctx);
}
@@ -722,16 +748,7 @@ EscrowCancel::doApply()
std::optional<uint256> escrowID = ctx_.tx[~sfEscrowID];
std::optional<std::uint32_t> offerSequence = ctx_.tx[~sfOfferSequence];
if (!view().rules().enabled(fixXahauV1))
{
if (escrowID && ctx_.tx[sfOfferSequence] != 0)
return temMALFORMED;
}
else
{
if (escrowID && offerSequence)
return temMALFORMED;
}
bool const fixV1 = view().rules().enabled(fixXahauV1);
Keylet k = escrowID ? Keylet(ltESCROW, *escrowID)
: keylet::escrow(ctx_.tx[sfOwner], *offerSequence);
@@ -740,6 +757,9 @@ EscrowCancel::doApply()
if (!slep)
return tecNO_TARGET;
if (fixV1 && slep->getFieldU16(sfLedgerEntryType) != ltESCROW)
return tecINTERNAL;
if (ctx_.view().rules().enabled(fix1571))
{
auto const now = ctx_.view().info().parentCloseTime;

View File

@@ -299,10 +299,16 @@ GenesisMint::doApply()
auto const flags = dest[~sfGovernanceFlags];
auto const marks = dest[~sfGovernanceMarks];
auto const id = dest.getAccountID(sfDestination);
auto const k = keylet::account(id);
bool const firstOccurance = mints.find(id) == mints.end();
if (dropsAdded + toCredit < dropsAdded)
{
JLOG(ctx_.journal.warn()) << "GenesisMint: cannot credit " << id
<< " due to dropsAdded overflow";
return tecINTERNAL;
}
dropsAdded += toCredit;
// if flags / marks appear more than once we just take the first

View File

@@ -817,16 +817,17 @@ Import::preflight(PreflightContext const& ctx)
<< " validation count: " << validationCount;
// check if the validation count is adequate
auto hasInsufficientQuorum = [&ctx](int quorum, int validationCount) {
if (ctx.rules.enabled(fixXahauV1))
{
return quorum > validationCount;
}
else
{
return quorum >= validationCount;
}
};
auto hasInsufficientQuorum =
[&ctx](uint64_t quorum, uint64_t validationCount) {
if (ctx.rules.enabled(fixXahauV1))
{
return quorum > validationCount;
}
else
{
return quorum >= validationCount;
}
};
if (hasInsufficientQuorum(quorum, validationCount))
{
JLOG(ctx.j.warn()) << "Import: xpop did not contain an 80% quorum for "

View File

@@ -86,6 +86,27 @@ Invoke::calculateBaseFee(ReadView const& view, STTx const& tx)
extraFee +=
XRPAmount{static_cast<XRPAmount>(tx.getFieldVL(sfBlob).size())};
// old code (prior to fixXahauV1)
if (!view.rules().enabled(fixXahauV1))
{
if (tx.isFieldPresent(sfHookParameters))
{
uint64_t paramBytes = 0;
auto const& params = tx.getFieldArray(sfHookParameters);
for (auto const& param : params)
{
paramBytes +=
(param.isFieldPresent(sfHookParameterName)
? param.getFieldVL(sfHookParameterName).size()
: 0) +
(param.isFieldPresent(sfHookParameterValue)
? param.getFieldVL(sfHookParameterValue).size()
: 0);
}
extraFee += XRPAmount{static_cast<XRPAmount>(paramBytes)};
}
}
return Transactor::calculateBaseFee(view, tx) + extraFee;
}

View File

@@ -351,7 +351,7 @@ Transactor::calculateBaseFee(ReadView const& view, STTx const& tx)
XRPAmount accumulator = baseFee;
if (view.rules().enabled(featureHooks) &&
tx.isFieldPresent(sfHookParameters))
view.rules().enabled(fixXahauV1) && tx.isFieldPresent(sfHookParameters))
{
uint64_t paramBytes = 0;
auto const& params = tx.getFieldArray(sfHookParameters);

File diff suppressed because it is too large Load Diff

View File

@@ -27,6 +27,7 @@
#include <ripple/ledger/OpenView.h>
#include <ripple/ledger/RawView.h>
#include <ripple/ledger/ReadView.h>
#include <ripple/ledger/Sandbox.h>
#include <ripple/protocol/Feature.h>
#include <ripple/protocol/Protocol.h>
#include <ripple/protocol/Rate.h>
@@ -394,7 +395,8 @@ accountSend(
AccountID const& from,
AccountID const& to,
const STAmount& saAmount,
beast::Journal j);
beast::Journal j,
bool const senderPaysXferFees = true);
[[nodiscard]] TER
issueIOU(
@@ -627,7 +629,7 @@ trustTransferAllowed(
{
static_assert(
std::is_same<V, ReadView const>::value ||
std::is_same<V, ApplyView>::value);
std::is_same<V, ApplyView>::value || std::is_same<V, Sandbox>::value);
typedef typename std::conditional<
std::is_same<V, ApplyView>::value,

View File

@@ -1157,7 +1157,8 @@ rippleSend(
AccountID const& uReceiverID,
STAmount const& saAmount,
STAmount& saActual,
beast::Journal j)
beast::Journal j,
bool const senderPaysXferFees)
{
auto const issuer = saAmount.getIssuer();
@@ -1179,17 +1180,30 @@ rippleSend(
// Calculate the amount to transfer accounting
// for any transfer fees:
saActual = multiply(saAmount, transferRate(view, issuer));
STAmount senderPays = saAmount;
STAmount destReceives = saAmount;
if (senderPaysXferFees)
{
senderPays = multiply(saAmount, transferRate(view, issuer));
saActual = senderPays;
}
else
{
destReceives = divide(saAmount, transferRate(view, issuer));
saActual = destReceives;
}
JLOG(j.debug()) << "rippleSend> " << to_string(uSenderID) << " - > "
<< to_string(uReceiverID)
<< " : deliver=" << saAmount.getFullText()
<< " cost=" << saActual.getFullText();
TER terResult = rippleCredit(view, issuer, uReceiverID, saAmount, true, j);
TER terResult =
rippleCredit(view, issuer, uReceiverID, destReceives, true, j);
if (tesSUCCESS == terResult)
terResult = rippleCredit(view, uSenderID, issuer, saActual, true, j);
terResult = rippleCredit(view, uSenderID, issuer, senderPays, true, j);
return terResult;
}
@@ -1200,7 +1214,8 @@ accountSend(
AccountID const& uSenderID,
AccountID const& uReceiverID,
STAmount const& saAmount,
beast::Journal j)
beast::Journal j,
bool const senderPaysXferFees)
{
assert(saAmount >= beast::zero);
@@ -1218,7 +1233,14 @@ accountSend(
<< to_string(uReceiverID) << " : "
<< saAmount.getFullText();
return rippleSend(view, uSenderID, uReceiverID, saAmount, saActual, j);
return rippleSend(
view,
uSenderID,
uReceiverID,
saAmount,
saActual,
j,
senderPaysXferFees);
}
/* XRP send which does not check reserve and can do pure adjustment.
@@ -1227,7 +1249,6 @@ accountSend(
* ensure that transfers are balanced.
*/
TER terResult(tesSUCCESS);
SLE::pointer sender = uSenderID != beast::zero
? view.peek(keylet::account(uSenderID))
: SLE::pointer();

View File

@@ -74,7 +74,7 @@ namespace detail {
// Feature.cpp. Because it's only used to reserve storage, and determine how
// large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than
// the actual number of amendments. A LogicError on startup will verify this.
static constexpr std::size_t numFeatures = 67;
static constexpr std::size_t numFeatures = 66;
/** Amendments that this server supports and the default voting behavior.
Whether they are enabled depends on the Rules defined in the validated
@@ -353,7 +353,6 @@ extern uint256 const fixNFTokenRemint;
extern uint256 const featureImport;
extern uint256 const featureXahauGenesis;
extern uint256 const featureHooksUpdate1;
extern uint256 const fixURITokenV1;
extern uint256 const fixXahauV1;
} // namespace ripple

View File

@@ -337,6 +337,7 @@ enum TECcodes : TERUnderlyingType {
tecXCHAIN_PAYMENT_FAILED = 184, // RESERVED - XCHAIN
tecXCHAIN_SELF_COMMIT = 185, // RESERVED - XCHAIN
tecXCHAIN_BAD_PUBLIC_KEY_ACCOUNT_PAIR = 186, // RESERVED - XCHAIN
tecINSUF_RESERVE_SELLER = 187,
tecLAST_POSSIBLE_ENTRY = 255,
};

View File

@@ -459,7 +459,6 @@ REGISTER_FEATURE(URIToken, Supported::yes, VoteBehavior::De
REGISTER_FEATURE(Import, Supported::yes, VoteBehavior::DefaultYes);
REGISTER_FEATURE(XahauGenesis, Supported::yes, VoteBehavior::DefaultYes);
REGISTER_FEATURE(HooksUpdate1, Supported::yes, VoteBehavior::DefaultYes);
REGISTER_FIX (fixURITokenV1, Supported::yes, VoteBehavior::DefaultNo);
REGISTER_FIX (fixXahauV1, Supported::yes, VoteBehavior::DefaultNo);

View File

@@ -91,6 +91,7 @@ transResults()
MAKE_ERROR(tecHOOK_REJECTED, "Rejected by hook on sending or receiving account."),
MAKE_ERROR(tecREQUIRES_FLAG, "The transaction or part-thereof requires a flag that wasn't set."),
MAKE_ERROR(tecPRECISION_LOSS, "The amounts used by the transaction cannot interact."),
MAKE_ERROR(tecINSUF_RESERVE_SELLER, "The seller of an object has insufficient reserves, and thus cannot complete the sale."),
MAKE_ERROR(tefALREADY, "The exact transaction was already in this ledger."),
MAKE_ERROR(tefBAD_ADD_AUTH, "Not authorized to add account."),
MAKE_ERROR(tefBAD_AUTH, "Transaction's public key is not authorized."),

View File

@@ -173,29 +173,30 @@ JSS(accounts); // in: LedgerEntry, Subscribe,
JSS(accounts_proposed); // in: Subscribe, Unsubscribe
JSS(acroot);
JSS(action);
JSS(acquiring); // out: LedgerRequest
JSS(address); // out: PeerImp
JSS(affected); // out: AcceptedLedgerTx
JSS(age); // out: NetworkOPs, Peers
JSS(alternatives); // out: PathRequest, RipplePathFind
JSS(amendment_blocked); // out: NetworkOPs
JSS(amendments); // in: AccountObjects, out: NetworkOPs
JSS(amount); // out: AccountChannels
JSS(api_version); // in: many, out: Version
JSS(api_version_low); // out: Version
JSS(applied); // out: SubmitTransaction
JSS(asks); // out: Subscribe
JSS(assets); // out: GatewayBalances
JSS(authorized); // out: AccountLines
JSS(auth_change); // out: AccountInfo
JSS(auth_change_queued); // out: AccountInfo
JSS(available); // out: ValidatorList
JSS(avg_bps_recv); // out: Peers
JSS(avg_bps_sent); // out: Peers
JSS(balance); // out: AccountLines
JSS(balances); // out: GatewayBalances
JSS(base); // out: LogLevel
JSS(base_fee); // out: NetworkOPs
JSS(acquiring); // out: LedgerRequest
JSS(address); // out: PeerImp
JSS(affected); // out: AcceptedLedgerTx
JSS(age); // out: NetworkOPs, Peers
JSS(alternatives); // out: PathRequest, RipplePathFind
JSS(amendment_blocked); // out: NetworkOPs
JSS(amendments); // in: AccountObjects, out: NetworkOPs
JSS(amount); // out: AccountChannels
JSS(api_version); // in: many, out: Version
JSS(api_version_low); // out: Version
JSS(applied); // out: SubmitTransaction
JSS(asks); // out: Subscribe
JSS(assets); // out: GatewayBalances
JSS(authorized); // out: AccountLines
JSS(auth_change); // out: AccountInfo
JSS(auth_change_queued); // out: AccountInfo
JSS(available); // out: ValidatorList
JSS(avg_bps_recv); // out: Peers
JSS(avg_bps_sent); // out: Peers
JSS(balance); // out: AccountLines
JSS(balances); // out: GatewayBalances
JSS(base); // out: LogLevel
JSS(base_fee); // out: NetworkOPs
JSS(base_fee_no_hooks);
JSS(base_fee_xrp); // out: NetworkOPs
JSS(base_fee_native); // out: NetworkOPs
JSS(bids); // out: Subscribe

View File

@@ -59,7 +59,7 @@ class BaseFee_test : public beast::unit_test::suite
// verify base fee & open ledger fee
auto const drops = jrr[jss::result][jss::drops];
auto const baseFee = drops[jss::base_fee];
auto const baseFee = drops[jss::base_fee_no_hooks];
BEAST_EXPECT(baseFee == to_string(feeDrops));
auto const openLedgerFee = drops[jss::open_ledger_fee];
BEAST_EXPECT(openLedgerFee == expected);
@@ -77,7 +77,7 @@ class BaseFee_test : public beast::unit_test::suite
using namespace test::jtx;
using namespace std::literals;
Env env{*this, network::makeNetworkConfig(21337)};
Env env{*this, network::makeNetworkConfig(21337), features};
auto const account = Account("alice");
env.fund(XRP(1000), account);
@@ -87,7 +87,9 @@ class BaseFee_test : public beast::unit_test::suite
auto tx = fset(account, asfTshCollect);
// verify hooks fee
testRPCCall(env, tx, "16");
std::string const feeResult =
env.current()->rules().enabled(fixXahauV1) ? "16" : "10";
testRPCCall(env, tx, feeResult);
}
void
@@ -98,7 +100,7 @@ class BaseFee_test : public beast::unit_test::suite
using namespace test::jtx;
using namespace std::literals;
Env env{*this, network::makeNetworkConfig(21337)};
Env env{*this, network::makeNetworkConfig(21337), features};
auto const account = Account("alice");
auto const bene = Account("bob");
@@ -109,7 +111,9 @@ class BaseFee_test : public beast::unit_test::suite
auto tx = acctdelete(account, bene);
// verify hooks fee
testRPCCall(env, tx, "200000");
std::string const feeResult =
env.current()->rules().enabled(fixXahauV1) ? "200000" : "200000";
testRPCCall(env, tx, feeResult);
}
static uint256
@@ -126,7 +130,7 @@ class BaseFee_test : public beast::unit_test::suite
using namespace test::jtx;
using namespace std::literals;
Env env{*this, network::makeNetworkConfig(21337)};
Env env{*this, network::makeNetworkConfig(21337), features};
auto const account = Account("alice");
env.fund(XRP(1000), account);
@@ -137,7 +141,9 @@ class BaseFee_test : public beast::unit_test::suite
auto tx = check::cancel(account, checkId);
// verify hooks fee
testRPCCall(env, tx, "16");
std::string const feeResult =
env.current()->rules().enabled(fixXahauV1) ? "16" : "10";
testRPCCall(env, tx, feeResult);
}
void
@@ -148,7 +154,7 @@ class BaseFee_test : public beast::unit_test::suite
using namespace test::jtx;
using namespace std::literals;
Env env{*this, network::makeNetworkConfig(21337)};
Env env{*this, network::makeNetworkConfig(21337), features};
auto const account = Account("alice");
auto const dest = Account("bob");
@@ -160,7 +166,9 @@ class BaseFee_test : public beast::unit_test::suite
auto tx = check::cash(dest, checkId, XRP(100));
// verify hooks fee
testRPCCall(env, tx, "16");
std::string const feeResult =
env.current()->rules().enabled(fixXahauV1) ? "16" : "10";
testRPCCall(env, tx, feeResult);
}
void
@@ -171,7 +179,7 @@ class BaseFee_test : public beast::unit_test::suite
using namespace test::jtx;
using namespace std::literals;
Env env{*this, network::makeNetworkConfig(21337)};
Env env{*this, network::makeNetworkConfig(21337), features};
auto const account = Account("alice");
auto const dest = Account("bob");
@@ -182,7 +190,9 @@ class BaseFee_test : public beast::unit_test::suite
auto tx = check::create(account, dest, XRP(100));
// verify hooks fee
testRPCCall(env, tx, "16");
std::string const feeResult =
env.current()->rules().enabled(fixXahauV1) ? "16" : "10";
testRPCCall(env, tx, feeResult);
}
void
@@ -193,7 +203,7 @@ class BaseFee_test : public beast::unit_test::suite
using namespace test::jtx;
using namespace std::literals;
Env env{*this, network::makeNetworkConfig(21337)};
Env env{*this, network::makeNetworkConfig(21337), features};
auto const account = Account("alice");
env.fund(XRP(1000), account);
@@ -203,7 +213,9 @@ class BaseFee_test : public beast::unit_test::suite
auto tx = reward::claim(account);
// verify hooks fee
testRPCCall(env, tx, "16");
std::string const feeResult =
env.current()->rules().enabled(fixXahauV1) ? "16" : "10";
testRPCCall(env, tx, feeResult);
}
void
@@ -214,7 +226,7 @@ class BaseFee_test : public beast::unit_test::suite
using namespace test::jtx;
using namespace std::literals;
Env env{*this, network::makeNetworkConfig(21337)};
Env env{*this, network::makeNetworkConfig(21337), features};
auto const account = Account("alice");
auto const authed = Account("bob");
@@ -225,7 +237,9 @@ class BaseFee_test : public beast::unit_test::suite
auto tx = deposit::auth(account, authed);
// verify hooks fee
testRPCCall(env, tx, "16");
std::string const feeResult =
env.current()->rules().enabled(fixXahauV1) ? "16" : "10";
testRPCCall(env, tx, feeResult);
}
void
@@ -236,7 +250,7 @@ class BaseFee_test : public beast::unit_test::suite
using namespace test::jtx;
using namespace std::literals;
Env env{*this, network::makeNetworkConfig(21337)};
Env env{*this, network::makeNetworkConfig(21337), features};
auto const account = Account("alice");
env.fund(XRP(1000), account);
@@ -247,7 +261,9 @@ class BaseFee_test : public beast::unit_test::suite
auto tx = escrow::cancel(account, account, seq1);
// verify hooks fee
testRPCCall(env, tx, "16");
std::string const feeResult =
env.current()->rules().enabled(fixXahauV1) ? "16" : "10";
testRPCCall(env, tx, feeResult);
}
void
@@ -258,7 +274,7 @@ class BaseFee_test : public beast::unit_test::suite
using namespace test::jtx;
using namespace std::literals;
Env env{*this, network::makeNetworkConfig(21337)};
Env env{*this, network::makeNetworkConfig(21337), features};
auto const account = Account("alice");
auto const dest = Account("bob");
@@ -269,7 +285,9 @@ class BaseFee_test : public beast::unit_test::suite
auto tx = escrow::create(account, dest, XRP(10));
// verify hooks fee
testRPCCall(env, tx, "16");
std::string const feeResult =
env.current()->rules().enabled(fixXahauV1) ? "16" : "10";
testRPCCall(env, tx, feeResult);
}
void
@@ -280,7 +298,7 @@ class BaseFee_test : public beast::unit_test::suite
using namespace test::jtx;
using namespace std::literals;
Env env{*this, network::makeNetworkConfig(21337)};
Env env{*this, network::makeNetworkConfig(21337), features};
auto const account = Account("alice");
env.fund(XRP(1000), account);
@@ -291,7 +309,9 @@ class BaseFee_test : public beast::unit_test::suite
auto tx = escrow::finish(account, account, seq1);
// verify hooks fee
testRPCCall(env, tx, "16");
std::string const feeResult =
env.current()->rules().enabled(fixXahauV1) ? "16" : "10";
testRPCCall(env, tx, feeResult);
}
void
@@ -302,7 +322,7 @@ class BaseFee_test : public beast::unit_test::suite
using namespace test::jtx;
using namespace std::literals;
Env env{*this, network::makeNetworkConfig(21337)};
Env env{*this, network::makeNetworkConfig(21337), features};
auto const account = Account("alice");
env.fund(XRP(1000), account);
@@ -313,7 +333,9 @@ class BaseFee_test : public beast::unit_test::suite
account, import::loadXpop(ImportTCAccountSet::w_seed));
// verify hooks fee
testRPCCall(env, tx, "106");
std::string const feeResult =
env.current()->rules().enabled(fixXahauV1) ? "106" : "100";
testRPCCall(env, tx, feeResult);
}
void
@@ -324,7 +346,7 @@ class BaseFee_test : public beast::unit_test::suite
using namespace test::jtx;
using namespace std::literals;
Env env{*this, network::makeNetworkConfig(21337)};
Env env{*this, network::makeNetworkConfig(21337), features};
auto const account = Account("alice");
env.fund(XRP(1000), account);
@@ -334,7 +356,9 @@ class BaseFee_test : public beast::unit_test::suite
auto tx = invoke::invoke(account);
// verify hooks fee
testRPCCall(env, tx, "16");
std::string const feeResult =
env.current()->rules().enabled(fixXahauV1) ? "16" : "16";
testRPCCall(env, tx, feeResult);
}
void
@@ -345,7 +369,7 @@ class BaseFee_test : public beast::unit_test::suite
using namespace test::jtx;
using namespace std::literals;
Env env{*this, network::makeNetworkConfig(21337)};
Env env{*this, network::makeNetworkConfig(21337), features};
auto const account = Account("alice");
env.fund(XRP(1000), account);
@@ -356,7 +380,9 @@ class BaseFee_test : public beast::unit_test::suite
auto tx = offer_cancel(account, offerSeq);
// verify hooks fee
testRPCCall(env, tx, "16");
std::string const feeResult =
env.current()->rules().enabled(fixXahauV1) ? "16" : "10";
testRPCCall(env, tx, feeResult);
}
void
@@ -367,7 +393,7 @@ class BaseFee_test : public beast::unit_test::suite
using namespace test::jtx;
using namespace std::literals;
Env env{*this, network::makeNetworkConfig(21337)};
Env env{*this, network::makeNetworkConfig(21337), features};
auto const account = Account("alice");
auto const gw = Account("gw");
@@ -379,7 +405,9 @@ class BaseFee_test : public beast::unit_test::suite
auto tx = offer(account, USD(1000), XRP(1000));
// verify hooks fee
testRPCCall(env, tx, "16");
std::string const feeResult =
env.current()->rules().enabled(fixXahauV1) ? "16" : "10";
testRPCCall(env, tx, feeResult);
}
void
@@ -390,7 +418,7 @@ class BaseFee_test : public beast::unit_test::suite
using namespace test::jtx;
using namespace std::literals;
Env env{*this, network::makeNetworkConfig(21337)};
Env env{*this, network::makeNetworkConfig(21337), features};
auto const account = Account("alice");
auto const dest = Account("bob");
@@ -401,7 +429,9 @@ class BaseFee_test : public beast::unit_test::suite
auto tx = pay(account, dest, XRP(1));
// verify hooks fee
testRPCCall(env, tx, "16");
std::string const feeResult =
env.current()->rules().enabled(fixXahauV1) ? "16" : "10";
testRPCCall(env, tx, feeResult);
}
static uint256
@@ -422,7 +452,7 @@ class BaseFee_test : public beast::unit_test::suite
using namespace test::jtx;
using namespace std::literals;
Env env{*this, network::makeNetworkConfig(21337)};
Env env{*this, network::makeNetworkConfig(21337), features};
auto const account = Account("alice");
auto const dest = Account("bob");
@@ -437,7 +467,9 @@ class BaseFee_test : public beast::unit_test::suite
auto tx = paychan::claim(account, chan, reqBal, authAmt);
// verify hooks fee
testRPCCall(env, tx, "16");
std::string const feeResult =
env.current()->rules().enabled(fixXahauV1) ? "16" : "10";
testRPCCall(env, tx, feeResult);
}
void
@@ -448,7 +480,7 @@ class BaseFee_test : public beast::unit_test::suite
using namespace test::jtx;
using namespace std::literals;
Env env{*this, network::makeNetworkConfig(21337)};
Env env{*this, network::makeNetworkConfig(21337), features};
auto const account = Account("alice");
auto const dest = Account("bob");
@@ -461,7 +493,9 @@ class BaseFee_test : public beast::unit_test::suite
auto tx = paychan::create(account, dest, XRP(10), settleDelay, pk);
// verify hooks fee
testRPCCall(env, tx, "16");
std::string const feeResult =
env.current()->rules().enabled(fixXahauV1) ? "16" : "10";
testRPCCall(env, tx, feeResult);
}
void
@@ -472,7 +506,7 @@ class BaseFee_test : public beast::unit_test::suite
using namespace test::jtx;
using namespace std::literals;
Env env{*this, network::makeNetworkConfig(21337)};
Env env{*this, network::makeNetworkConfig(21337), features};
auto const account = Account("alice");
auto const dest = Account("bob");
@@ -484,7 +518,9 @@ class BaseFee_test : public beast::unit_test::suite
auto tx = paychan::fund(account, chan, XRP(1));
// verify hooks fee
testRPCCall(env, tx, "16");
std::string const feeResult =
env.current()->rules().enabled(fixXahauV1) ? "16" : "10";
testRPCCall(env, tx, feeResult);
}
void
@@ -495,7 +531,7 @@ class BaseFee_test : public beast::unit_test::suite
using namespace test::jtx;
using namespace std::literals;
Env env{*this, network::makeNetworkConfig(21337)};
Env env{*this, network::makeNetworkConfig(21337), features};
auto const account = Account("alice");
env.fund(XRP(1000), account);
@@ -515,7 +551,9 @@ class BaseFee_test : public beast::unit_test::suite
hookParams[jss::HookParameter][jss::HookParameterValue] = "DEADBEEF";
// verify hooks fee
testRPCCall(env, tx, "73022");
std::string const feeResult =
env.current()->rules().enabled(fixXahauV1) ? "73022" : "73016";
testRPCCall(env, tx, feeResult);
}
void
@@ -526,7 +564,7 @@ class BaseFee_test : public beast::unit_test::suite
using namespace test::jtx;
using namespace std::literals;
Env env{*this, network::makeNetworkConfig(21337)};
Env env{*this, network::makeNetworkConfig(21337), features};
auto const account = Account("alice");
auto const dest = Account("bob");
@@ -537,7 +575,9 @@ class BaseFee_test : public beast::unit_test::suite
auto tx = regkey(account, dest);
// verify hooks fee
testRPCCall(env, tx, "0");
std::string const feeResult =
env.current()->rules().enabled(fixXahauV1) ? "0" : "0";
testRPCCall(env, tx, feeResult);
}
void
@@ -548,7 +588,7 @@ class BaseFee_test : public beast::unit_test::suite
using namespace test::jtx;
using namespace std::literals;
Env env{*this, network::makeNetworkConfig(21337)};
Env env{*this, network::makeNetworkConfig(21337), features};
auto const account = Account("alice");
auto const signer1 = Account("bob");
@@ -560,7 +600,9 @@ class BaseFee_test : public beast::unit_test::suite
auto tx = signers(account, 2, {{signer1, 1}, {signer2, 1}});
// verify hooks fee
testRPCCall(env, tx, "16");
std::string const feeResult =
env.current()->rules().enabled(fixXahauV1) ? "16" : "10";
testRPCCall(env, tx, feeResult);
}
void
@@ -571,7 +613,7 @@ class BaseFee_test : public beast::unit_test::suite
using namespace test::jtx;
using namespace std::literals;
Env env{*this, network::makeNetworkConfig(21337)};
Env env{*this, network::makeNetworkConfig(21337), features};
auto const account = Account("alice");
env.fund(XRP(1000), account);
@@ -581,7 +623,9 @@ class BaseFee_test : public beast::unit_test::suite
auto tx = ticket::create(account, 2);
// verify hooks fee
testRPCCall(env, tx, "16");
std::string const feeResult =
env.current()->rules().enabled(fixXahauV1) ? "16" : "10";
testRPCCall(env, tx, feeResult);
}
void
@@ -592,7 +636,7 @@ class BaseFee_test : public beast::unit_test::suite
using namespace test::jtx;
using namespace std::literals;
Env env{*this, network::makeNetworkConfig(21337)};
Env env{*this, network::makeNetworkConfig(21337), features};
auto const account = Account("alice");
auto const gw = Account("gw");
@@ -604,7 +648,9 @@ class BaseFee_test : public beast::unit_test::suite
auto tx = trust(account, USD(1000));
// verify hooks fee
testRPCCall(env, tx, "16");
std::string const feeResult =
env.current()->rules().enabled(fixXahauV1) ? "16" : "10";
testRPCCall(env, tx, feeResult);
}
void
@@ -615,7 +661,7 @@ class BaseFee_test : public beast::unit_test::suite
using namespace test::jtx;
using namespace std::literals;
Env env{*this, network::makeNetworkConfig(21337)};
Env env{*this, network::makeNetworkConfig(21337), features};
auto const issuer = Account("alice");
env.fund(XRP(1000), issuer);
@@ -628,7 +674,9 @@ class BaseFee_test : public beast::unit_test::suite
auto tx = uritoken::burn(issuer, hexid);
// verify hooks fee
testRPCCall(env, tx, "16");
std::string const feeResult =
env.current()->rules().enabled(fixXahauV1) ? "16" : "10";
testRPCCall(env, tx, feeResult);
}
void
@@ -639,7 +687,7 @@ class BaseFee_test : public beast::unit_test::suite
using namespace test::jtx;
using namespace std::literals;
Env env{*this, network::makeNetworkConfig(21337)};
Env env{*this, network::makeNetworkConfig(21337), features};
auto const issuer = Account("alice");
env.fund(XRP(1000), issuer);
@@ -653,7 +701,9 @@ class BaseFee_test : public beast::unit_test::suite
tx[jss::Amount] = "1000000";
// verify hooks fee
testRPCCall(env, tx, "16");
std::string const feeResult =
env.current()->rules().enabled(fixXahauV1) ? "16" : "10";
testRPCCall(env, tx, feeResult);
}
void
@@ -664,7 +714,7 @@ class BaseFee_test : public beast::unit_test::suite
using namespace test::jtx;
using namespace std::literals;
Env env{*this, network::makeNetworkConfig(21337)};
Env env{*this, network::makeNetworkConfig(21337), features};
auto const issuer = Account("alice");
env.fund(XRP(1000), issuer);
@@ -677,7 +727,9 @@ class BaseFee_test : public beast::unit_test::suite
auto tx = uritoken::cancel(issuer, hexid);
// verify hooks fee
testRPCCall(env, tx, "16");
std::string const feeResult =
env.current()->rules().enabled(fixXahauV1) ? "16" : "10";
testRPCCall(env, tx, feeResult);
}
void
@@ -688,7 +740,7 @@ class BaseFee_test : public beast::unit_test::suite
using namespace test::jtx;
using namespace std::literals;
Env env{*this, network::makeNetworkConfig(21337)};
Env env{*this, network::makeNetworkConfig(21337), features};
auto const issuer = Account("alice");
auto const buyer = Account("bob");
@@ -704,7 +756,9 @@ class BaseFee_test : public beast::unit_test::suite
tx[jss::Amount] = "1000000";
// verify hooks fee
testRPCCall(env, tx, "16");
std::string const feeResult =
env.current()->rules().enabled(fixXahauV1) ? "16" : "10";
testRPCCall(env, tx, feeResult);
}
void
@@ -715,7 +769,7 @@ class BaseFee_test : public beast::unit_test::suite
using namespace test::jtx;
using namespace std::literals;
Env env{*this, network::makeNetworkConfig(21337)};
Env env{*this, network::makeNetworkConfig(21337), features};
auto const account = Account("alice");
env.fund(XRP(1000), account);
@@ -726,7 +780,9 @@ class BaseFee_test : public beast::unit_test::suite
auto tx = uritoken::mint(account, uri);
// verify hooks fee
testRPCCall(env, tx, "16");
std::string const feeResult =
env.current()->rules().enabled(fixXahauV1) ? "16" : "10";
testRPCCall(env, tx, feeResult);
}
void
@@ -770,6 +826,7 @@ public:
using namespace test::jtx;
auto const sa = supported_amendments();
testWithFeats(sa);
testWithFeats(sa - fixXahauV1);
}
};

View File

@@ -5298,7 +5298,6 @@ public:
// both offer id and offer sequence 0
{
uint256 const offerId{getOfferIndex(alice, env.seq(alice))};
std::uint32_t const offerSeqId{env.seq(alice)};
env(offer(alice, XRP(50), USD(50)));
env.close();
@@ -5404,12 +5403,12 @@ public:
FeatureBitset const rmSmallIncreasedQOffers{fixRmSmallIncreasedQOffers};
FeatureBitset const immediateOfferKilled{featureImmediateOfferKilled};
// testAll(all - takerDryOffer - immediateOfferKilled);
// testAll(all - flowCross - takerDryOffer - immediateOfferKilled);
// testAll(all - flowCross - immediateOfferKilled);
// testAll(all - rmSmallIncreasedQOffers - immediateOfferKilled);
// testAll(all);
// testFalseAssert();
testAll(all - takerDryOffer - immediateOfferKilled);
testAll(all - flowCross - takerDryOffer - immediateOfferKilled);
testAll(all - flowCross - immediateOfferKilled);
testAll(all - rmSmallIncreasedQOffers - immediateOfferKilled);
testAll(all);
testFalseAssert();
testOfferID(all);
}
};

File diff suppressed because it is too large Load Diff

View File

@@ -191,30 +191,25 @@ struct URIToken_test : public beast::unit_test::suite
using namespace jtx;
using namespace std::literals::chrono_literals;
// fixURITokenV1
// fixXahauV1
{
for (bool const withFixURITokenV1 : {true, false})
{
auto const amend =
withFixURITokenV1 ? features : features - fixURITokenV1;
Env env{*this, features};
auto const alice = Account("alice");
auto const bob = Account("bob");
env.fund(XRP(1000), alice, bob);
env.close();
auto const txResult =
withFixURITokenV1 ? ter(temMALFORMED) : ter(tefINTERNAL);
std::string const uri(2, '?');
auto const tid = uritoken::tokenid(alice, uri);
std::string const hexid{strHex(tid)};
Env env{*this, amend};
auto const alice = Account("alice");
auto const bob = Account("bob");
env.fund(XRP(1000), alice, bob);
env.close();
std::string const uri(2, '?');
auto const tid = uritoken::tokenid(alice, uri);
std::string const hexid{strHex(tid)};
// temMALFORMED - cannot include sfDestination without sfAmount
env(uritoken::mint(alice, uri), uritoken::dest(bob), txResult);
env.close();
}
// temMALFORMED - cannot include sfDestination without sfAmount
bool const withFixXahauV1 =
env.current()->rules().enabled(fixXahauV1);
auto const txResult =
withFixXahauV1 ? ter(temMALFORMED) : ter(tefINTERNAL);
env(uritoken::mint(alice, uri), uritoken::dest(bob), txResult);
env.close();
}
// setup env
@@ -459,7 +454,10 @@ struct URIToken_test : public beast::unit_test::suite
using namespace std::literals::chrono_literals;
// setup env
Env env{*this, features};
Env env{
*this, envconfig(), features, nullptr, beast::severities::kWarning
// beast::severities::kTrace
};
auto const alice = Account("alice");
auto const bob = Account("bob");
auto const carol = Account("carol");
@@ -602,7 +600,7 @@ struct URIToken_test : public beast::unit_test::suite
env.close();
// tecNO_LINE_INSUF_RESERVE - insuficient xrp to create line
{
// fund dave 251 xrp (not enough for line reserve)
// fund echo 251 xrp (not enough for line reserve)
env.fund(XRP(251), echo);
env.fund(XRP(301), dave);
env.close();
@@ -620,9 +618,12 @@ struct URIToken_test : public beast::unit_test::suite
env.close();
// tecNO_LINE_INSUF_RESERVE - insuficient xrp to create line
env(uritoken::buy(dave, hexid),
uritoken::amt(USD(1)),
ter(tecNO_LINE_INSUF_RESERVE));
auto const txResult = env.current()->rules().enabled(fixXahauV1)
? ter(tecINSUF_RESERVE_SELLER)
: ter(tecNO_LINE_INSUF_RESERVE);
env(noop(echo), fee(XRP(50)), ter(tesSUCCESS));
env(uritoken::buy(dave, hexid), uritoken::amt(USD(1)), txResult);
env.close();
}
@@ -711,12 +712,14 @@ struct URIToken_test : public beast::unit_test::suite
json(sfDigest.fieldName, digestval));
env.close();
BEAST_EXPECT(inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1);
BEAST_EXPECT(
to_string(tokenDigest(*env.current(), tid)) == digestval);
// cleanup
env(uritoken::burn(alice, hexid));
env.close();
BEAST_EXPECT(!inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 0);
}
// has digest - has uri - burnable flag
{
@@ -726,12 +729,14 @@ struct URIToken_test : public beast::unit_test::suite
json(sfDigest.fieldName, digestval));
env.close();
BEAST_EXPECT(inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1);
BEAST_EXPECT(
to_string(tokenDigest(*env.current(), tid)) == digestval);
// cleanup
env(uritoken::burn(alice, hexid));
env.close();
BEAST_EXPECT(!inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 0);
}
// has uri - no flags
{
@@ -739,10 +744,12 @@ struct URIToken_test : public beast::unit_test::suite
env(uritoken::mint(alice, uri));
env.close();
BEAST_EXPECT(inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1);
// cleanup
env(uritoken::burn(alice, hexid));
env.close();
BEAST_EXPECT(!inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 0);
}
// has uri - burnable flag
{
@@ -750,10 +757,12 @@ struct URIToken_test : public beast::unit_test::suite
env(uritoken::mint(alice, uri), txflags(tfBurnable));
env.close();
BEAST_EXPECT(inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1);
// cleanup
env(uritoken::burn(alice, hexid));
env.close();
BEAST_EXPECT(!inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 0);
}
// 0 amount and destination
@@ -766,14 +775,23 @@ struct URIToken_test : public beast::unit_test::suite
ter(tesSUCCESS));
env.close();
BEAST_EXPECT(inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 0);
// buy
env(uritoken::buy(bob, hexid), uritoken::amt(XRP(0)));
env.close();
BEAST_EXPECT(inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(!inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 0);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 1);
// cleanup
env(uritoken::burn(bob, hexid));
env.close();
BEAST_EXPECT(!inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 0);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 0);
}
// has amount and destination
@@ -786,14 +804,23 @@ struct URIToken_test : public beast::unit_test::suite
ter(tesSUCCESS));
env.close();
BEAST_EXPECT(inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 0);
// buy
env(uritoken::buy(bob, hexid), uritoken::amt(XRP(10)));
env.close();
BEAST_EXPECT(!inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 0);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 1);
// cleanup
env(uritoken::burn(bob, hexid));
env.close();
BEAST_EXPECT(!inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 0);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 0);
}
// has amount and no destination
@@ -805,14 +832,23 @@ struct URIToken_test : public beast::unit_test::suite
ter(tesSUCCESS));
env.close();
BEAST_EXPECT(inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 0);
// buy
env(uritoken::buy(bob, hexid), uritoken::amt(XRP(10)));
env.close();
BEAST_EXPECT(!inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 0);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 1);
// cleanup
env(uritoken::burn(bob, hexid));
env.close();
BEAST_EXPECT(!inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 0);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 0);
}
}
@@ -840,16 +876,30 @@ struct URIToken_test : public beast::unit_test::suite
env(uritoken::mint(alice, uri), txflags(tfBurnable));
env.close();
BEAST_EXPECT(inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 0);
// alice sells
env(uritoken::sell(alice, hexid), uritoken::amt(XRP(1)));
env.close();
BEAST_EXPECT(inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 0);
// bob buys
env(uritoken::buy(bob, hexid), uritoken::amt(XRP(1)));
env.close();
BEAST_EXPECT(!inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 0);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 1);
// alice burns
env(uritoken::burn(alice, hexid));
env.close();
BEAST_EXPECT(!inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 0);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 0);
}
// issuer cannot burn
{
@@ -857,21 +907,33 @@ struct URIToken_test : public beast::unit_test::suite
env(uritoken::mint(alice, uri));
env.close();
BEAST_EXPECT(inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 0);
// alice sells
env(uritoken::sell(alice, hexid), uritoken::amt(XRP(1)));
env.close();
// bob buys
env(uritoken::buy(bob, hexid), uritoken::amt(XRP(1)));
env.close();
BEAST_EXPECT(!inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 0);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 1);
// alice tries to burn
env(uritoken::burn(alice, hexid), ter(tecNO_PERMISSION));
env.close();
BEAST_EXPECT(!inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 0);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 1);
// burn for test reset
env(uritoken::burn(bob, hexid));
env.close();
BEAST_EXPECT(!inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 0);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 0);
}
// owner can burn
{
@@ -879,18 +941,30 @@ struct URIToken_test : public beast::unit_test::suite
env(uritoken::mint(alice, uri));
env.close();
BEAST_EXPECT(inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 0);
// alice sells
env(uritoken::sell(alice, hexid), uritoken::amt(XRP(1)));
BEAST_EXPECT(inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 0);
env.close();
// bob buys
env(uritoken::buy(bob, hexid), uritoken::amt(XRP(1)));
env.close();
BEAST_EXPECT(!inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 0);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 1);
// bob burns
env(uritoken::burn(bob, hexid));
env.close();
BEAST_EXPECT(!inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 0);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 0);
}
}
@@ -930,6 +1004,9 @@ struct URIToken_test : public beast::unit_test::suite
env(uritoken::mint(alice, uri));
env.close();
BEAST_EXPECT(inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 2);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 1);
BEAST_EXPECT(env.balance(alice) == preAlice - (1 * feeDrops));
// alice sells
env(uritoken::sell(alice, hexid), uritoken::amt(delta));
@@ -939,7 +1016,10 @@ struct URIToken_test : public beast::unit_test::suite
env(uritoken::buy(bob, hexid), uritoken::amt(delta));
env.close();
BEAST_EXPECT(!inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 2);
BEAST_EXPECT(
env.balance(alice) == preAlice + delta - (2 * feeDrops));
BEAST_EXPECT(env.balance(bob) == preBob - delta - feeDrops);
@@ -950,6 +1030,8 @@ struct URIToken_test : public beast::unit_test::suite
env.close();
BEAST_EXPECT(!inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 1);
}
// bob can buy with USD
{
@@ -962,6 +1044,9 @@ struct URIToken_test : public beast::unit_test::suite
env(uritoken::mint(alice, uri));
env.close();
BEAST_EXPECT(inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 2);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 1);
BEAST_EXPECT(env.balance(alice) == preAliceXrp - (1 * feeDrops));
// alice sells
env(uritoken::sell(alice, hexid), uritoken::amt(delta));
@@ -971,7 +1056,10 @@ struct URIToken_test : public beast::unit_test::suite
// bob buys
env(uritoken::buy(bob, hexid), uritoken::amt(delta));
env.close();
BEAST_EXPECT(!inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 2);
BEAST_EXPECT(env.balance(alice, USD.issue()) == preAlice + delta);
BEAST_EXPECT(env.balance(alice) == preAliceXrp - (2 * feeDrops));
BEAST_EXPECT(env.balance(bob, USD.issue()) == preBob - delta);
@@ -983,6 +1071,8 @@ struct URIToken_test : public beast::unit_test::suite
env.close();
BEAST_EXPECT(!inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 1);
}
}
@@ -1024,6 +1114,9 @@ struct URIToken_test : public beast::unit_test::suite
env(uritoken::mint(alice, uri));
env.close();
BEAST_EXPECT(inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 2);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 1);
// alice sells
env(uritoken::sell(alice, hexid), uritoken::amt(delta));
env.close();
@@ -1041,7 +1134,10 @@ struct URIToken_test : public beast::unit_test::suite
// bob buys at higher price
env(uritoken::buy(bob, hexid), uritoken::amt(XRP(11)));
env.close();
BEAST_EXPECT(!inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 2);
BEAST_EXPECT(
env.balance(alice) == preAlice + XRP(11) - (4 * feeDrops));
BEAST_EXPECT(env.balance(bob) == preBob - XRP(11) - (2 * feeDrops));
@@ -1052,6 +1148,8 @@ struct URIToken_test : public beast::unit_test::suite
env.close();
BEAST_EXPECT(!inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 1);
}
// alice can sell with XRP and dest
{
@@ -1062,6 +1160,9 @@ struct URIToken_test : public beast::unit_test::suite
env(uritoken::mint(alice, uri));
env.close();
BEAST_EXPECT(inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 2);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 1);
// alice sells
env(uritoken::sell(alice, hexid),
uritoken::amt(delta),
@@ -1076,7 +1177,10 @@ struct URIToken_test : public beast::unit_test::suite
// bob buys
env(uritoken::buy(bob, hexid), uritoken::amt(delta));
env.close();
BEAST_EXPECT(!inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 2);
BEAST_EXPECT(
env.balance(alice) == preAlice + delta - (2 * feeDrops));
BEAST_EXPECT(env.balance(bob) == preBob - delta - (1 * feeDrops));
@@ -1087,6 +1191,8 @@ struct URIToken_test : public beast::unit_test::suite
env.close();
BEAST_EXPECT(!inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 1);
}
// alice can sell with USD
@@ -1100,6 +1206,9 @@ struct URIToken_test : public beast::unit_test::suite
env(uritoken::mint(alice, uri));
env.close();
BEAST_EXPECT(inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 2);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 1);
// alice sells
env(uritoken::sell(alice, hexid), uritoken::amt(delta));
env.close();
@@ -1118,7 +1227,10 @@ struct URIToken_test : public beast::unit_test::suite
env(uritoken::buy(bob, hexid), uritoken::amt(USD(11)));
env.close();
BEAST_EXPECT(!inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 2);
BEAST_EXPECT(env.balance(alice, USD.issue()) == preAlice + USD(11));
BEAST_EXPECT(env.balance(alice) == preAliceXrp - (4 * feeDrops));
BEAST_EXPECT(env.balance(bob, USD.issue()) == preBob - USD(11));
@@ -1130,6 +1242,8 @@ struct URIToken_test : public beast::unit_test::suite
env.close();
BEAST_EXPECT(!inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 1);
}
// alice can sell with USD and dest
{
@@ -1142,6 +1256,9 @@ struct URIToken_test : public beast::unit_test::suite
env(uritoken::mint(alice, uri));
env.close();
BEAST_EXPECT(inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 2);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 1);
// alice sells
env(uritoken::sell(alice, hexid),
uritoken::amt(delta),
@@ -1157,7 +1274,10 @@ struct URIToken_test : public beast::unit_test::suite
env(uritoken::buy(bob, hexid), uritoken::amt(delta));
env.close();
BEAST_EXPECT(!inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 2);
BEAST_EXPECT(env.balance(alice, USD.issue()) == preAlice + delta);
BEAST_EXPECT(env.balance(alice) == preAliceXrp - (2 * feeDrops));
BEAST_EXPECT(env.balance(bob, USD.issue()) == preBob - delta);
@@ -1169,6 +1289,8 @@ struct URIToken_test : public beast::unit_test::suite
env.close();
BEAST_EXPECT(!inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 1);
}
}
@@ -1209,6 +1331,9 @@ struct URIToken_test : public beast::unit_test::suite
env(uritoken::mint(alice, uri));
env.close();
BEAST_EXPECT(inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 2);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 1);
// alice sells
env(uritoken::sell(alice, hexid), uritoken::amt(delta));
env.close();
@@ -1228,6 +1353,9 @@ struct URIToken_test : public beast::unit_test::suite
env(uritoken::burn(alice, hexid));
env.close();
BEAST_EXPECT(!inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 1);
}
// alice can clear / reset USD amount
{
@@ -1236,6 +1364,9 @@ struct URIToken_test : public beast::unit_test::suite
env(uritoken::mint(alice, uri));
env.close();
BEAST_EXPECT(inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 2);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 1);
// alice sells
env(uritoken::sell(alice, hexid), uritoken::amt(delta));
env.close();
@@ -1255,6 +1386,9 @@ struct URIToken_test : public beast::unit_test::suite
env(uritoken::burn(alice, hexid));
env.close();
BEAST_EXPECT(!inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1);
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 1);
}
}
@@ -1294,8 +1428,8 @@ struct URIToken_test : public beast::unit_test::suite
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 2);
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 1);
// // alice sets the sell offer
// // bob sets the buy offer
// alice sets the sell offer
// bob sets the buy offer
env(uritoken::buy(bob, hexid), uritoken::amt(USD(10)));
BEAST_EXPECT(!inOwnerDir(*env.current(), alice, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 1);
@@ -1321,8 +1455,8 @@ struct URIToken_test : public beast::unit_test::suite
BEAST_EXPECT(ownerDirCount(*env.current(), alice) == 2);
BEAST_EXPECT(!inOwnerDir(*env.current(), bob, tid));
BEAST_EXPECT(ownerDirCount(*env.current(), bob) == 1);
// // alice sets the sell offer
// // bob sets the buy offer
// alice sets the sell offer
// bob sets the buy offer
env(uritoken::buy(bob, hexid), uritoken::amt(USD(10)));
env.close();
BEAST_EXPECT(!inOwnerDir(*env.current(), alice, tid));
@@ -1833,11 +1967,27 @@ struct URIToken_test : public beast::unit_test::suite
auto const gw = Account{"gateway"};
auto const USD = gw["USD"];
// test transfer rate
struct TestRateData
{
double rate;
STAmount delta;
std::string multiply;
std::string divide;
};
std::array<TestRateData, 6> testCases = {{
{1, USD(100), "1100", "1100"},
{1.1, USD(100), "1110", "1090.909090909091"},
{1.0005, USD(100), "1100.05", "1099.950024987506"},
{1.005, USD(100), "1100.4999999", "1099.502487661197"},
{1.25, USD(100), "1125", "1080"},
{2, USD(100), "1200", "1050"},
}};
for (auto const& tc : testCases)
{
Env env{*this, features};
env.fund(XRP(10000), alice, bob, gw);
env(rate(gw, 1.25));
env(rate(gw, tc.rate));
env.close();
env.trust(USD(100000), alice, bob);
env.close();
@@ -1845,6 +1995,7 @@ struct URIToken_test : public beast::unit_test::suite
env(pay(gw, bob, USD(1000)));
env.close();
auto const preAlice = env.balance(alice, USD.issue());
auto const preBob = env.balance(bob, USD.issue());
// setup mint
@@ -1857,9 +2008,19 @@ struct URIToken_test : public beast::unit_test::suite
env(uritoken::buy(bob, id), uritoken::amt(delta));
env.close();
BEAST_EXPECT(env.balance(alice, USD.issue()) == USD(1125));
auto xferRate = transferRate(*env.current(), gw);
auto const postAlice = env.balance(alice, USD.issue());
if (!env.current()->rules().enabled(fixXahauV1))
{
BEAST_EXPECT(to_string(postAlice.value()) == tc.multiply);
}
else
{
BEAST_EXPECT(to_string(postAlice.value()) == tc.divide);
}
BEAST_EXPECT(env.balance(bob, USD.issue()) == preBob - delta);
}
// test rate change
{
Env env{*this, features};
@@ -1882,29 +2043,16 @@ struct URIToken_test : public beast::unit_test::suite
env(uritoken::sell(alice, id), uritoken::amt(delta));
env.close();
// bob buys at higher rate and burns
env(uritoken::buy(bob, id), uritoken::amt(delta));
env.close();
BEAST_EXPECT(env.balance(alice, USD.issue()) == USD(10125));
BEAST_EXPECT(env.balance(bob, USD.issue()) == preBob - delta);
env(uritoken::burn(bob, id));
// issuer changes rate lower
env(rate(gw, 1.00));
env.close();
preBob = env.balance(bob, USD.issue());
// alice mints and sells
env(uritoken::mint(alice, uri));
env(uritoken::sell(alice, id), uritoken::amt(delta));
env.close();
// bob buys at lower rate
// bob buys at higher rate and burns
env(uritoken::buy(bob, id), uritoken::amt(delta));
env.close();
BEAST_EXPECT(env.balance(alice, USD.issue()) == USD(10225));
BEAST_EXPECT(env.balance(alice, USD.issue()) == USD(10100));
BEAST_EXPECT(env.balance(bob, USD.issue()) == preBob - delta);
env(uritoken::burn(bob, id));
}
// test issuer doesnt pay own rate
{
@@ -2377,6 +2525,7 @@ public:
using namespace test::jtx;
auto const sa = supported_amendments();
testWithFeats(sa);
testWithFeats(sa - fixXahauV1);
}
};

View File

@@ -1750,13 +1750,10 @@ public:
env.fund(XRP(10000), "alice");
env.close();
std::cout << to_string(env.closed()->info().hash) << "\n";
env.fund(XRP(10000), "bob");
env.close();
std::cout << to_string(env.closed()->info().hash) << "\n";
env.fund(XRP(10000), "jim");
env.close();
std::cout << to_string(env.closed()->info().hash) << "\n";
env.fund(XRP(10000), "jill");
{