Bring back addEmptyHolding and removeEmptyHolding to View

This commit is contained in:
Bronek Kozicki
2025-04-01 13:49:58 +01:00
parent 2b86a1a557
commit ad6e048ab2
4 changed files with 176 additions and 126 deletions

View File

@@ -130,70 +130,6 @@ VaultCreate::preclaim(PreclaimContext const& ctx)
return tesSUCCESS;
}
[[nodiscard]] static TER
addEmptyHolding(
ApplyView& view,
AccountID const& accountID,
XRPAmount priorBalance,
Issue const& issue,
beast::Journal journal)
{
// Every account can hold XRP.
if (issue.native())
return tesSUCCESS;
auto const& issuerId = issue.getIssuer();
auto const& currency = issue.currency;
if (isGlobalFrozen(view, issuerId))
return tecFROZEN;
auto const& srcId = issuerId;
auto const& dstId = accountID;
auto const high = srcId > dstId;
auto const index = keylet::line(srcId, dstId, currency);
auto const sle = view.peek(keylet::account(accountID));
if (!sle)
return tefINTERNAL;
return trustCreate(
view,
high,
srcId,
dstId,
index.key,
sle,
/*auth=*/false,
/*noRipple=*/true,
/*freeze=*/false,
/*deepFreeze*/ false,
/*balance=*/STAmount{Issue{currency, noAccount()}},
/*limit=*/STAmount{Issue{currency, dstId}},
/*qualityIn=*/0,
/*qualityOut=*/0,
journal);
}
[[nodiscard]] static TER
addEmptyHolding(
ApplyView& view,
AccountID const& accountID,
XRPAmount priorBalance,
MPTIssue const& mptIssue,
beast::Journal journal)
{
auto const& mptID = mptIssue.getMptID();
auto const mpt = view.peek(keylet::mptIssuance(mptID));
if (!mpt)
return tefINTERNAL;
if (mpt->getFlags() & lsfMPTLocked)
return tecLOCKED;
return MPTokenAuthorize::authorize(
view,
journal,
{.priorBalance = priorBalance,
.mptIssuanceID = mptID,
.accountID = accountID});
}
TER
VaultCreate::doApply()
{
@@ -224,12 +160,7 @@ VaultCreate::doApply()
auto pseudoId = pseudo->at(sfAccount);
auto asset = tx[sfAsset];
if (auto ter = std::visit(
[&]<ValidIssueType TIss>(TIss const& issue) -> TER {
return addEmptyHolding(
view(), pseudoId, mPriorBalance, issue, j_);
},
asset.value());
if (auto ter = addEmptyHolding(view(), pseudoId, mPriorBalance, asset, j_);
!isTesSuccess(ter))
return ter;

View File

@@ -66,56 +66,6 @@ VaultDelete::preclaim(PreclaimContext const& ctx)
return tesSUCCESS;
}
[[nodiscard]] static TER
removeEmptyHolding(
ApplyView& view,
AccountID const& accountID,
Issue const& issue,
beast::Journal journal)
{
if (issue.native())
{
auto const sle = view.read(keylet::account(accountID));
if (!sle)
return tecINTERNAL;
auto const balance = sle->getFieldAmount(sfBalance);
if (balance.xrp() != 0)
return tecHAS_OBLIGATIONS;
return tesSUCCESS;
}
// `asset` is an IOU.
auto const line = view.peek(keylet::line(accountID, issue));
if (!line)
return tecOBJECT_NOT_FOUND;
if (line->at(sfBalance)->iou() != beast::zero)
return tecHAS_OBLIGATIONS;
return trustDelete(
view,
line,
line->at(sfLowLimit)->getIssuer(),
line->at(sfHighLimit)->getIssuer(),
journal);
}
[[nodiscard]] static TER
removeEmptyHolding(
ApplyView& view,
AccountID const& accountID,
MPTIssue const& mptIssue,
beast::Journal journal)
{
auto const& mptID = mptIssue.getMptID();
// `MPTokenAuthorize::authorize` asserts that the balance is 0.
return MPTokenAuthorize::authorize(
view,
journal,
{.priorBalance = {},
.mptIssuanceID = mptID,
.accountID = accountID,
.flags = tfMPTUnauthorize});
}
TER
VaultDelete::doApply()
{
@@ -125,12 +75,7 @@ VaultDelete::doApply()
// Destroy the asset holding.
auto asset = vault->at(sfAsset);
if (auto ter = std::visit(
[&]<ValidIssueType TIss>(TIss const& issue) -> TER {
return removeEmptyHolding(
view(), vault->at(sfAccount), issue, j_);
},
(*asset).value());
if (auto ter = removeEmptyHolding(view(), vault->at(sfAccount), asset, j_);
!isTesSuccess(ter))
return ter;

View File

@@ -500,6 +500,38 @@ createPseudoAccount(
uint256 const& pseudoOwnerKey,
PseudoAccountOwnerType type);
[[nodiscard]] TER
addEmptyHolding(
ApplyView& view,
AccountID const& accountID,
XRPAmount priorBalance,
Issue const& issue,
beast::Journal journal);
[[nodiscard]] TER
addEmptyHolding(
ApplyView& view,
AccountID const& accountID,
XRPAmount priorBalance,
MPTIssue const& mptIssue,
beast::Journal journal);
[[nodiscard]] inline TER
addEmptyHolding(
ApplyView& view,
AccountID const& accountID,
XRPAmount priorBalance,
Asset const& asset,
beast::Journal journal)
{
return std::visit(
[&]<ValidIssueType TIss>(TIss const& issue) -> TER {
return addEmptyHolding(
view, accountID, priorBalance, issue, journal);
},
asset.value());
}
// VFALCO NOTE Both STAmount parameters should just
// be "Amount", a unit-less number.
//
@@ -527,6 +559,34 @@ trustCreate(
std::uint32_t uSrcQualityOut,
beast::Journal j);
[[nodiscard]] TER
removeEmptyHolding(
ApplyView& view,
AccountID const& accountID,
Issue const& issue,
beast::Journal journal);
[[nodiscard]] TER
removeEmptyHolding(
ApplyView& view,
AccountID const& accountID,
MPTIssue const& mptIssue,
beast::Journal journal);
[[nodiscard]] inline TER
removeEmptyHolding(
ApplyView& view,
AccountID const& accountID,
Asset const& asset,
beast::Journal journal)
{
return std::visit(
[&]<ValidIssueType TIss>(TIss const& issue) -> TER {
return removeEmptyHolding(view, accountID, issue, journal);
},
asset.value());
}
[[nodiscard]] TER
trustDelete(
ApplyView& view,

View File

@@ -1104,6 +1104,70 @@ createPseudoAccount(
return account;
}
[[nodiscard]] TER
addEmptyHolding(
ApplyView& view,
AccountID const& accountID,
XRPAmount priorBalance,
Issue const& issue,
beast::Journal journal)
{
// Every account can hold XRP.
if (issue.native())
return tesSUCCESS;
auto const& issuerId = issue.getIssuer();
auto const& currency = issue.currency;
if (isGlobalFrozen(view, issuerId))
return tecFROZEN;
auto const& srcId = issuerId;
auto const& dstId = accountID;
auto const high = srcId > dstId;
auto const index = keylet::line(srcId, dstId, currency);
auto const sle = view.peek(keylet::account(accountID));
if (!sle)
return tefINTERNAL;
return trustCreate(
view,
high,
srcId,
dstId,
index.key,
sle,
/*auth=*/false,
/*noRipple=*/true,
/*freeze=*/false,
/*deepFreeze*/ false,
/*balance=*/STAmount{Issue{currency, noAccount()}},
/*limit=*/STAmount{Issue{currency, dstId}},
/*qualityIn=*/0,
/*qualityOut=*/0,
journal);
}
[[nodiscard]] TER
addEmptyHolding(
ApplyView& view,
AccountID const& accountID,
XRPAmount priorBalance,
MPTIssue const& mptIssue,
beast::Journal journal)
{
auto const& mptID = mptIssue.getMptID();
auto const mpt = view.peek(keylet::mptIssuance(mptID));
if (!mpt)
return tefINTERNAL;
if (mpt->getFlags() & lsfMPTLocked)
return tecLOCKED;
return MPTokenAuthorize::authorize(
view,
journal,
{.priorBalance = priorBalance,
.mptIssuanceID = mptID,
.accountID = accountID});
}
TER
trustCreate(
ApplyView& view,
@@ -1223,6 +1287,56 @@ trustCreate(
return tesSUCCESS;
}
[[nodiscard]] TER
removeEmptyHolding(
ApplyView& view,
AccountID const& accountID,
Issue const& issue,
beast::Journal journal)
{
if (issue.native())
{
auto const sle = view.read(keylet::account(accountID));
if (!sle)
return tecINTERNAL;
auto const balance = sle->getFieldAmount(sfBalance);
if (balance.xrp() != 0)
return tecHAS_OBLIGATIONS;
return tesSUCCESS;
}
// `asset` is an IOU.
auto const line = view.peek(keylet::line(accountID, issue));
if (!line)
return tecOBJECT_NOT_FOUND;
if (line->at(sfBalance)->iou() != beast::zero)
return tecHAS_OBLIGATIONS;
return trustDelete(
view,
line,
line->at(sfLowLimit)->getIssuer(),
line->at(sfHighLimit)->getIssuer(),
journal);
}
[[nodiscard]] TER
removeEmptyHolding(
ApplyView& view,
AccountID const& accountID,
MPTIssue const& mptIssue,
beast::Journal journal)
{
auto const& mptID = mptIssue.getMptID();
// `MPTokenAuthorize::authorize` asserts that the balance is 0.
return MPTokenAuthorize::authorize(
view,
journal,
{.priorBalance = {},
.mptIssuanceID = mptID,
.accountID = accountID,
.flags = tfMPTUnauthorize});
}
TER
trustDelete(
ApplyView& view,