From ce57c882ce2f6770c0f2fc5281a0aca75f37f12a Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Wed, 15 Jul 2026 12:26:06 -0400 Subject: [PATCH] refactor: Introduce preflight helper functions --- src/libxrpl/tx/PreflightHelpers.h | 68 +++++++++++++++++++ .../tx/transactors/escrow/EscrowCreate.cpp | 11 +-- .../lending/LoanBrokerCoverClawback.cpp | 4 +- .../lending/LoanBrokerCoverDeposit.cpp | 6 +- .../lending/LoanBrokerCoverWithdraw.cpp | 8 ++- .../transactors/lending/LoanBrokerDelete.cpp | 4 +- .../tx/transactors/lending/LoanBrokerSet.cpp | 6 +- .../tx/transactors/lending/LoanDelete.cpp | 4 +- .../tx/transactors/lending/LoanManage.cpp | 4 +- .../tx/transactors/lending/LoanPay.cpp | 6 +- .../tx/transactors/lending/LoanSet.cpp | 4 +- .../tx/transactors/payment/Payment.cpp | 8 ++- .../payment_channel/PaymentChannelClaim.cpp | 8 ++- .../payment_channel/PaymentChannelCreate.cpp | 4 +- .../payment_channel/PaymentChannelFund.cpp | 6 +- .../PermissionedDomainDelete.cpp | 4 +- .../PermissionedDomainSet.cpp | 4 +- src/libxrpl/tx/transactors/token/Clawback.cpp | 6 +- .../token/MPTokenIssuanceCreate.cpp | 4 +- src/libxrpl/tx/transactors/token/TrustSet.cpp | 4 +- .../tx/transactors/vault/VaultDelete.cpp | 4 +- .../tx/transactors/vault/VaultWithdraw.cpp | 8 ++- 22 files changed, 148 insertions(+), 37 deletions(-) create mode 100644 src/libxrpl/tx/PreflightHelpers.h diff --git a/src/libxrpl/tx/PreflightHelpers.h b/src/libxrpl/tx/PreflightHelpers.h new file mode 100644 index 0000000000..bf71187559 --- /dev/null +++ b/src/libxrpl/tx/PreflightHelpers.h @@ -0,0 +1,68 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include + +template +inline bool +checkBounds(T const& value, T const& min, T const& max) +{ + return value >= min && value <= max; +} + +template +inline bool +checkMax(T const& value, T const& max) +{ + return value <= max; +} + +template +inline bool +checkSize(T const& value, std::size_t const max) +{ + return value.size() <= max; +} + +template +inline bool +checkSizeNonEmpty(T const& value, std::size_t const max) +{ + return value.size() <= max && !value.empty(); +} + +// Checks whether a hash-like identifier field (e.g. a uint256 object ID) is +// unset/zero. +template +inline bool +isZeroId(T const& id) +{ + return id == beast::kZero; +} + +// Checks whether an amount is a strictly positive XRP amount. +inline bool +checkPositiveXRPAmount(xrpl::STAmount const& amount) +{ + return xrpl::isXRP(amount) && amount > beast::kZero; +} + +// Checks whether an amount (of any asset type) is strictly positive. +inline bool +checkPositiveAmount(xrpl::STAmount const& amount) +{ + return amount > beast::kZero; +} + +// Checks whether a currency code is the reserved "bad"/XRP currency code, +// i.e. not a valid IOU currency. +inline bool +isBadCurrency(xrpl::Currency const& currency) +{ + return xrpl::badCurrency() == currency; +} diff --git a/src/libxrpl/tx/transactors/escrow/EscrowCreate.cpp b/src/libxrpl/tx/transactors/escrow/EscrowCreate.cpp index 50f2e8b859..47a3e79329 100644 --- a/src/libxrpl/tx/transactors/escrow/EscrowCreate.cpp +++ b/src/libxrpl/tx/transactors/escrow/EscrowCreate.cpp @@ -33,6 +33,8 @@ #include #include +#include + #include #include #include @@ -101,10 +103,10 @@ NotTEC escrowCreatePreflightHelper(PreflightContext const& ctx) { STAmount const amount = ctx.tx[sfAmount]; - if (amount.native() || amount <= beast::kZero) + if (amount.native() || !checkPositiveAmount(amount)) return temBAD_AMOUNT; - if (badCurrency() == amount.get().currency) + if (isBadCurrency(amount.get().currency)) return temBAD_CURRENCY; return tesSUCCESS; @@ -118,7 +120,8 @@ escrowCreatePreflightHelper(PreflightContext const& ctx) return temDISABLED; auto const amount = ctx.tx[sfAmount]; - if (amount.native() || amount.mpt() > MPTAmount{kMaxMpTokenAmount} || amount <= beast::kZero) + if (amount.native() || amount.mpt() > MPTAmount{kMaxMpTokenAmount} || + !checkPositiveAmount(amount)) return temBAD_AMOUNT; return tesSUCCESS; @@ -141,7 +144,7 @@ EscrowCreate::preflight(PreflightContext const& ctx) } else { - if (amount <= beast::kZero) + if (!checkPositiveXRPAmount(amount)) return temBAD_AMOUNT; } diff --git a/src/libxrpl/tx/transactors/lending/LoanBrokerCoverClawback.cpp b/src/libxrpl/tx/transactors/lending/LoanBrokerCoverClawback.cpp index b914f3cf24..b06f761911 100644 --- a/src/libxrpl/tx/transactors/lending/LoanBrokerCoverClawback.cpp +++ b/src/libxrpl/tx/transactors/lending/LoanBrokerCoverClawback.cpp @@ -27,6 +27,8 @@ #include #include +#include + #include #include #include @@ -48,7 +50,7 @@ LoanBrokerCoverClawback::preflight(PreflightContext const& ctx) if (!brokerID && !amount) return temINVALID; - if (brokerID && *brokerID == beast::kZero) + if (brokerID && isZeroId(*brokerID)) return temINVALID; if (amount) diff --git a/src/libxrpl/tx/transactors/lending/LoanBrokerCoverDeposit.cpp b/src/libxrpl/tx/transactors/lending/LoanBrokerCoverDeposit.cpp index 09ab03347a..a605734d5c 100644 --- a/src/libxrpl/tx/transactors/lending/LoanBrokerCoverDeposit.cpp +++ b/src/libxrpl/tx/transactors/lending/LoanBrokerCoverDeposit.cpp @@ -16,6 +16,8 @@ #include #include +#include + namespace xrpl { bool @@ -27,11 +29,11 @@ LoanBrokerCoverDeposit::checkExtraFeatures(PreflightContext const& ctx) NotTEC LoanBrokerCoverDeposit::preflight(PreflightContext const& ctx) { - if (ctx.tx[sfLoanBrokerID] == beast::kZero) + if (isZeroId(ctx.tx[sfLoanBrokerID])) return temINVALID; auto const dstAmount = ctx.tx[sfAmount]; - if (dstAmount <= beast::kZero) + if (!checkPositiveAmount(dstAmount)) return temBAD_AMOUNT; if (!isLegalNet(dstAmount)) diff --git a/src/libxrpl/tx/transactors/lending/LoanBrokerCoverWithdraw.cpp b/src/libxrpl/tx/transactors/lending/LoanBrokerCoverWithdraw.cpp index 498f3c99eb..1ba55dc42e 100644 --- a/src/libxrpl/tx/transactors/lending/LoanBrokerCoverWithdraw.cpp +++ b/src/libxrpl/tx/transactors/lending/LoanBrokerCoverWithdraw.cpp @@ -20,6 +20,8 @@ #include #include +#include + namespace xrpl { bool @@ -31,11 +33,11 @@ LoanBrokerCoverWithdraw::checkExtraFeatures(PreflightContext const& ctx) NotTEC LoanBrokerCoverWithdraw::preflight(PreflightContext const& ctx) { - if (ctx.tx[sfLoanBrokerID] == beast::kZero) + if (isZeroId(ctx.tx[sfLoanBrokerID])) return temINVALID; auto const dstAmount = ctx.tx[sfAmount]; - if (dstAmount <= beast::kZero) + if (!checkPositiveAmount(dstAmount)) return temBAD_AMOUNT; if (!isLegalNet(dstAmount)) @@ -43,7 +45,7 @@ LoanBrokerCoverWithdraw::preflight(PreflightContext const& ctx) if (auto const destination = ctx.tx[~sfDestination]) { - if (*destination == beast::kZero) + if (isZeroId(*destination)) { return temMALFORMED; } diff --git a/src/libxrpl/tx/transactors/lending/LoanBrokerDelete.cpp b/src/libxrpl/tx/transactors/lending/LoanBrokerDelete.cpp index b36977d225..f80c778be3 100644 --- a/src/libxrpl/tx/transactors/lending/LoanBrokerDelete.cpp +++ b/src/libxrpl/tx/transactors/lending/LoanBrokerDelete.cpp @@ -18,6 +18,8 @@ #include #include +#include + namespace xrpl { bool @@ -29,7 +31,7 @@ LoanBrokerDelete::checkExtraFeatures(PreflightContext const& ctx) NotTEC LoanBrokerDelete::preflight(PreflightContext const& ctx) { - if (ctx.tx[sfLoanBrokerID] == beast::kZero) + if (isZeroId(ctx.tx[sfLoanBrokerID])) return temINVALID; return tesSUCCESS; diff --git a/src/libxrpl/tx/transactors/lending/LoanBrokerSet.cpp b/src/libxrpl/tx/transactors/lending/LoanBrokerSet.cpp index e9c153404c..1539510008 100644 --- a/src/libxrpl/tx/transactors/lending/LoanBrokerSet.cpp +++ b/src/libxrpl/tx/transactors/lending/LoanBrokerSet.cpp @@ -20,6 +20,8 @@ #include #include +#include + #include #include @@ -57,13 +59,13 @@ LoanBrokerSet::preflight(PreflightContext const& ctx) tx.isFieldPresent(sfCoverRateLiquidation)) return temINVALID; - if (tx[sfLoanBrokerID] == beast::kZero) + if (isZeroId(tx[sfLoanBrokerID])) return temINVALID; } if (auto const vaultID = tx.at(~sfVaultID)) { - if (*vaultID == beast::kZero) + if (isZeroId(*vaultID)) return temINVALID; } diff --git a/src/libxrpl/tx/transactors/lending/LoanDelete.cpp b/src/libxrpl/tx/transactors/lending/LoanDelete.cpp index 1a77489b4b..6a63ccb47f 100644 --- a/src/libxrpl/tx/transactors/lending/LoanDelete.cpp +++ b/src/libxrpl/tx/transactors/lending/LoanDelete.cpp @@ -16,6 +16,8 @@ #include #include +#include + namespace xrpl { bool @@ -27,7 +29,7 @@ LoanDelete::checkExtraFeatures(PreflightContext const& ctx) NotTEC LoanDelete::preflight(PreflightContext const& ctx) { - if (ctx.tx[sfLoanID] == beast::kZero) + if (isZeroId(ctx.tx[sfLoanID])) return temINVALID; return tesSUCCESS; diff --git a/src/libxrpl/tx/transactors/lending/LoanManage.cpp b/src/libxrpl/tx/transactors/lending/LoanManage.cpp index a0aa948876..5653e10b36 100644 --- a/src/libxrpl/tx/transactors/lending/LoanManage.cpp +++ b/src/libxrpl/tx/transactors/lending/LoanManage.cpp @@ -24,6 +24,8 @@ #include #include +#include + #include #include namespace xrpl { @@ -43,7 +45,7 @@ LoanManage::getFlagsMask(PreflightContext const& ctx) NotTEC LoanManage::preflight(PreflightContext const& ctx) { - if (ctx.tx[sfLoanID] == beast::kZero) + if (isZeroId(ctx.tx[sfLoanID])) return temINVALID; // Flags are mutually exclusive diff --git a/src/libxrpl/tx/transactors/lending/LoanPay.cpp b/src/libxrpl/tx/transactors/lending/LoanPay.cpp index 54ee85b186..0062ef6092 100644 --- a/src/libxrpl/tx/transactors/lending/LoanPay.cpp +++ b/src/libxrpl/tx/transactors/lending/LoanPay.cpp @@ -25,6 +25,8 @@ #include #include +#include + #include #include #include @@ -48,10 +50,10 @@ LoanPay::getFlagsMask(PreflightContext const& ctx) NotTEC LoanPay::preflight(PreflightContext const& ctx) { - if (ctx.tx[sfLoanID] == beast::kZero) + if (isZeroId(ctx.tx[sfLoanID])) return temINVALID; - if (ctx.tx[sfAmount] <= beast::kZero) + if (!checkPositiveAmount(ctx.tx[sfAmount])) return temBAD_AMOUNT; // The loan payment flags are all mutually exclusive. If more than one is diff --git a/src/libxrpl/tx/transactors/lending/LoanSet.cpp b/src/libxrpl/tx/transactors/lending/LoanSet.cpp index 694d01c69f..3a46d70a6e 100644 --- a/src/libxrpl/tx/transactors/lending/LoanSet.cpp +++ b/src/libxrpl/tx/transactors/lending/LoanSet.cpp @@ -28,6 +28,8 @@ #include #include +#include + #include #include #include @@ -138,7 +140,7 @@ LoanSet::preflight(PreflightContext const& ctx) return *ret; } - if (auto const brokerID = ctx.tx[~sfLoanBrokerID]; brokerID && *brokerID == beast::kZero) + if (auto const brokerID = ctx.tx[~sfLoanBrokerID]; brokerID && isZeroId(*brokerID)) return temINVALID; return tesSUCCESS; diff --git a/src/libxrpl/tx/transactors/payment/Payment.cpp b/src/libxrpl/tx/transactors/payment/Payment.cpp index 17c96a1919..b67742490e 100644 --- a/src/libxrpl/tx/transactors/payment/Payment.cpp +++ b/src/libxrpl/tx/transactors/payment/Payment.cpp @@ -36,6 +36,8 @@ #include #include +#include + #include #include #include @@ -143,7 +145,7 @@ Payment::preflight(PreflightContext const& ctx) // A zero DomainID is invalid for a PermissionedDomain ledger entry because // keylet::permissionedDomain(uint256) uses the DomainID as the ledger key. if (auto const domainID = tx[~sfDomainID]; - ctx.rules.enabled(fixCleanup3_2_0) && domainID && *domainID == beast::kZero) + ctx.rules.enabled(fixCleanup3_2_0) && domainID && isZeroId(*domainID)) return temMALFORMED; bool const partialPaymentAllowed = tx.isFlag(tfPartialPayment); @@ -183,13 +185,13 @@ Payment::preflight(PreflightContext const& ctx) << "Payment destination account not specified."; return temDST_NEEDED; } - if (hasMax && maxSourceAmount <= beast::kZero) + if (hasMax && !checkPositiveAmount(maxSourceAmount)) { JLOG(j.trace()) << "Malformed transaction: bad max amount: " << maxSourceAmount.getFullText(); return temBAD_AMOUNT; } - if (dstAmount <= beast::kZero) + if (!checkPositiveAmount(dstAmount)) { JLOG(j.trace()) << "Malformed transaction: bad dst amount: " << dstAmount.getFullText(); return temBAD_AMOUNT; diff --git a/src/libxrpl/tx/transactors/payment_channel/PaymentChannelClaim.cpp b/src/libxrpl/tx/transactors/payment_channel/PaymentChannelClaim.cpp index b8118bc49f..0e9042a51c 100644 --- a/src/libxrpl/tx/transactors/payment_channel/PaymentChannelClaim.cpp +++ b/src/libxrpl/tx/transactors/payment_channel/PaymentChannelClaim.cpp @@ -22,6 +22,8 @@ #include #include +#include + #include #include @@ -42,15 +44,15 @@ PaymentChannelClaim::getFlagsMask(PreflightContext const&) NotTEC PaymentChannelClaim::preflight(PreflightContext const& ctx) { - if (ctx.rules.enabled(fixCleanup3_2_0) && ctx.tx[sfChannel] == beast::kZero) + if (ctx.rules.enabled(fixCleanup3_2_0) && isZeroId(ctx.tx[sfChannel])) return temMALFORMED; auto const bal = ctx.tx[~sfBalance]; - if (bal && (!isXRP(*bal) || *bal <= beast::kZero)) + if (bal && !checkPositiveXRPAmount(*bal)) return temBAD_AMOUNT; auto const amt = ctx.tx[~sfAmount]; - if (amt && (!isXRP(*amt) || *amt <= beast::kZero)) + if (amt && !checkPositiveXRPAmount(*amt)) return temBAD_AMOUNT; if (bal && amt && *bal > *amt) diff --git a/src/libxrpl/tx/transactors/payment_channel/PaymentChannelCreate.cpp b/src/libxrpl/tx/transactors/payment_channel/PaymentChannelCreate.cpp index b17430948a..6e0432dafb 100644 --- a/src/libxrpl/tx/transactors/payment_channel/PaymentChannelCreate.cpp +++ b/src/libxrpl/tx/transactors/payment_channel/PaymentChannelCreate.cpp @@ -22,6 +22,8 @@ #include #include +#include + #include namespace xrpl { @@ -57,7 +59,7 @@ PaymentChannelCreate::makeTxConsequences(PreflightContext const& ctx) NotTEC PaymentChannelCreate::preflight(PreflightContext const& ctx) { - if (!isXRP(ctx.tx[sfAmount]) || (ctx.tx[sfAmount] <= beast::kZero)) + if (!checkPositiveXRPAmount(ctx.tx[sfAmount])) return temBAD_AMOUNT; if (ctx.tx[sfAccount] == ctx.tx[sfDestination]) diff --git a/src/libxrpl/tx/transactors/payment_channel/PaymentChannelFund.cpp b/src/libxrpl/tx/transactors/payment_channel/PaymentChannelFund.cpp index 1d1cf07e25..f328c97a06 100644 --- a/src/libxrpl/tx/transactors/payment_channel/PaymentChannelFund.cpp +++ b/src/libxrpl/tx/transactors/payment_channel/PaymentChannelFund.cpp @@ -20,6 +20,8 @@ #include #include +#include + namespace xrpl { TxConsequences @@ -31,10 +33,10 @@ PaymentChannelFund::makeTxConsequences(PreflightContext const& ctx) NotTEC PaymentChannelFund::preflight(PreflightContext const& ctx) { - if (ctx.rules.enabled(fixCleanup3_2_0) && ctx.tx[sfChannel] == beast::kZero) + if (ctx.rules.enabled(fixCleanup3_2_0) && isZeroId(ctx.tx[sfChannel])) return temMALFORMED; - if (!isXRP(ctx.tx[sfAmount]) || (ctx.tx[sfAmount] <= beast::kZero)) + if (!checkPositiveXRPAmount(ctx.tx[sfAmount])) return temBAD_AMOUNT; return tesSUCCESS; diff --git a/src/libxrpl/tx/transactors/permissioned_domain/PermissionedDomainDelete.cpp b/src/libxrpl/tx/transactors/permissioned_domain/PermissionedDomainDelete.cpp index dc1b323482..660d5a4c39 100644 --- a/src/libxrpl/tx/transactors/permissioned_domain/PermissionedDomainDelete.cpp +++ b/src/libxrpl/tx/transactors/permissioned_domain/PermissionedDomainDelete.cpp @@ -12,13 +12,15 @@ #include #include +#include + namespace xrpl { NotTEC PermissionedDomainDelete::preflight(PreflightContext const& ctx) { auto const domain = ctx.tx.getFieldH256(sfDomainID); - if (domain == beast::kZero) + if (isZeroId(domain)) return temMALFORMED; return tesSUCCESS; diff --git a/src/libxrpl/tx/transactors/permissioned_domain/PermissionedDomainSet.cpp b/src/libxrpl/tx/transactors/permissioned_domain/PermissionedDomainSet.cpp index 61ebdcf9c7..a5de6b7d49 100644 --- a/src/libxrpl/tx/transactors/permissioned_domain/PermissionedDomainSet.cpp +++ b/src/libxrpl/tx/transactors/permissioned_domain/PermissionedDomainSet.cpp @@ -17,6 +17,8 @@ #include #include +#include + #include #include @@ -39,7 +41,7 @@ PermissionedDomainSet::preflight(PreflightContext const& ctx) return err; auto const domain = ctx.tx.at(~sfDomainID); - if (domain && *domain == beast::kZero) + if (domain && isZeroId(*domain)) return temMALFORMED; return tesSUCCESS; diff --git a/src/libxrpl/tx/transactors/token/Clawback.cpp b/src/libxrpl/tx/transactors/token/Clawback.cpp index 64457a3b5f..82e5e60509 100644 --- a/src/libxrpl/tx/transactors/token/Clawback.cpp +++ b/src/libxrpl/tx/transactors/token/Clawback.cpp @@ -22,6 +22,8 @@ #include #include +#include + #include #include @@ -44,7 +46,7 @@ preflightHelper(PreflightContext const& ctx) // The issuer field is used for the token holder instead AccountID const& holder = clawAmount.getIssuer(); - if (issuer == holder || isXRP(clawAmount) || clawAmount <= beast::kZero) + if (issuer == holder || isXRP(clawAmount) || !checkPositiveAmount(clawAmount)) return temBAD_AMOUNT; return tesSUCCESS; @@ -67,7 +69,7 @@ preflightHelper(PreflightContext const& ctx) if (ctx.tx[sfAccount] == *mptHolder) return temMALFORMED; - if (clawAmount.mpt() > MPTAmount{kMaxMpTokenAmount} || clawAmount <= beast::kZero) + if (clawAmount.mpt() > MPTAmount{kMaxMpTokenAmount} || !checkPositiveAmount(clawAmount)) return temBAD_AMOUNT; return tesSUCCESS; diff --git a/src/libxrpl/tx/transactors/token/MPTokenIssuanceCreate.cpp b/src/libxrpl/tx/transactors/token/MPTokenIssuanceCreate.cpp index aad1642f68..43861ae9e5 100644 --- a/src/libxrpl/tx/transactors/token/MPTokenIssuanceCreate.cpp +++ b/src/libxrpl/tx/transactors/token/MPTokenIssuanceCreate.cpp @@ -21,6 +21,8 @@ #include #include +#include + #include #include #include @@ -87,7 +89,7 @@ MPTokenIssuanceCreate::preflight(PreflightContext const& ctx) if (auto const domain = ctx.tx[~sfDomainID]) { - if (*domain == beast::kZero) + if (isZeroId(*domain)) return temMALFORMED; // Domain present implies that MPTokenIssuance is not public diff --git a/src/libxrpl/tx/transactors/token/TrustSet.cpp b/src/libxrpl/tx/transactors/token/TrustSet.cpp index 3d078ce825..4158034076 100644 --- a/src/libxrpl/tx/transactors/token/TrustSet.cpp +++ b/src/libxrpl/tx/transactors/token/TrustSet.cpp @@ -25,6 +25,8 @@ #include #include +#include + #include #include @@ -98,7 +100,7 @@ TrustSet::preflight(PreflightContext const& ctx) return temBAD_LIMIT; } - if (badCurrency() == saLimitAmount.get().currency) + if (isBadCurrency(saLimitAmount.get().currency)) { JLOG(j.trace()) << "Malformed transaction: specifies XRP as IOU"; return temBAD_CURRENCY; diff --git a/src/libxrpl/tx/transactors/vault/VaultDelete.cpp b/src/libxrpl/tx/transactors/vault/VaultDelete.cpp index 497a2f2465..f5cc262186 100644 --- a/src/libxrpl/tx/transactors/vault/VaultDelete.cpp +++ b/src/libxrpl/tx/transactors/vault/VaultDelete.cpp @@ -19,12 +19,14 @@ #include #include +#include + namespace xrpl { NotTEC VaultDelete::preflight(PreflightContext const& ctx) { - if (ctx.tx[sfVaultID] == beast::kZero) + if (isZeroId(ctx.tx[sfVaultID])) { JLOG(ctx.j.debug()) << "VaultDelete: zero/empty vault ID."; return temMALFORMED; diff --git a/src/libxrpl/tx/transactors/vault/VaultWithdraw.cpp b/src/libxrpl/tx/transactors/vault/VaultWithdraw.cpp index 353b72c30d..b2935b6693 100644 --- a/src/libxrpl/tx/transactors/vault/VaultWithdraw.cpp +++ b/src/libxrpl/tx/transactors/vault/VaultWithdraw.cpp @@ -23,6 +23,8 @@ #include #include +#include + #include namespace xrpl { @@ -42,18 +44,18 @@ shouldWaiveWithdrawal(ReadView const& view, AccountID const& account, SLE::const NotTEC VaultWithdraw::preflight(PreflightContext const& ctx) { - if (ctx.tx[sfVaultID] == beast::kZero) + if (isZeroId(ctx.tx[sfVaultID])) { JLOG(ctx.j.debug()) << "VaultWithdraw: zero/empty vault ID."; return temMALFORMED; } - if (ctx.tx[sfAmount] <= beast::kZero) + if (!checkPositiveAmount(ctx.tx[sfAmount])) return temBAD_AMOUNT; if (auto const destination = ctx.tx[~sfDestination]) { - if (*destination == beast::kZero) + if (isZeroId(*destination)) { return temMALFORMED; }