1#include <xrpld/app/paths/Flow.h> 
    2#include <xrpld/app/tx/detail/SignerEntries.h> 
    3#include <xrpld/app/tx/detail/Transactor.h> 
    4#include <xrpld/app/tx/detail/XChainBridge.h> 
    6#include <xrpl/basics/Log.h> 
    7#include <xrpl/basics/Number.h> 
    8#include <xrpl/basics/chrono.h> 
    9#include <xrpl/beast/utility/Journal.h> 
   10#include <xrpl/beast/utility/instrumentation.h> 
   11#include <xrpl/ledger/ApplyView.h> 
   12#include <xrpl/ledger/PaymentSandbox.h> 
   13#include <xrpl/ledger/View.h> 
   14#include <xrpl/protocol/AccountID.h> 
   15#include <xrpl/protocol/Feature.h> 
   16#include <xrpl/protocol/Indexes.h> 
   17#include <xrpl/protocol/PublicKey.h> 
   18#include <xrpl/protocol/SField.h> 
   19#include <xrpl/protocol/STAmount.h> 
   20#include <xrpl/protocol/STObject.h> 
   21#include <xrpl/protocol/STXChainBridge.h> 
   22#include <xrpl/protocol/TER.h> 
   23#include <xrpl/protocol/TxFlags.h> 
   24#include <xrpl/protocol/XChainAttestations.h> 
   25#include <xrpl/protocol/XRPAmount.h> 
   92checkAttestationPublicKey(
 
   95    AccountID const& attestationSignerAccount,
 
   99    if (!signersList.
contains(attestationSignerAccount))
 
  106    if (
auto const sleAttestationSigningAccount =
 
  109        if (accountFromPK == attestationSignerAccount)
 
  112            if (sleAttestationSigningAccount->getFieldU32(sfFlags) &
 
  115                JLOG(j.
trace()) << 
"Attempt to add an attestation with " 
  116                                   "disabled master key.";
 
  124                    (*sleAttestationSigningAccount)[~sfRegularKey];
 
  125                regularKey != accountFromPK)
 
  130                        << 
"Attempt to add an attestation with " 
  131                           "account present and non-present regular key.";
 
  135                    JLOG(j.
trace()) << 
"Attempt to add an attestation with " 
  136                                       "account present and mismatched " 
  137                                       "regular key/public key.";
 
  149                << 
"Attempt to add an attestation with non-existant account " 
  150                   "and mismatched pk/account pair.";
 
  169enum class CheckDst { 
check, ignore };
 
  170template <
class TAttestation>
 
  171Expected<std::vector<AccountID>, 
TER>
 
  173    XChainAttestationsBase<TAttestation>& attestations,
 
  174    ReadView 
const& view,
 
  175    typename TAttestation::MatchFields 
const& toMatch,
 
  184    attestations.erase_if([&](
auto const& a) {
 
  185        return checkAttestationPublicKey(
 
  186                   view, signersList, a.keyAccount, a.publicKey, j) !=
 
  192    rewardAccounts.reserve(attestations.size());
 
  194    for (
auto const& a : attestations)
 
  196        auto const matchR = a.match(toMatch);
 
  202            (checkDst == CheckDst::check && matchR != 
match))
 
  204        auto i = signersList.
find(a.keyAccount);
 
  205        if (i == signersList.
end())
 
  209                "ripple::claimHelper : invalid inputs");  
 
  215        rewardAccounts.push_back(a.rewardAccount);
 
  218    if (weight >= quorum)
 
  219        return rewardAccounts;
 
  255struct OnNewAttestationResult
 
  263template <
class TAttestation>
 
  264[[nodiscard]] OnNewAttestationResult
 
  266    XChainAttestationsBase<TAttestation>& attestations,
 
  267    ReadView 
const& view,
 
  268    typename TAttestation::TSignedAttestation 
const* attBegin,
 
  269    typename TAttestation::TSignedAttestation 
const* attEnd,
 
  274    bool changed = 
false;
 
  275    for (
auto att = attBegin; att != attEnd; ++att)
 
  277        if (checkAttestationPublicKey(
 
  280                att->attestationSignerAccount,
 
  291        auto const& claimSigningAccount = att->attestationSignerAccount;
 
  293                attestations.begin(),
 
  296                    return a.keyAccount == claimSigningAccount;
 
  298            i != attestations.end())
 
  302            *i = TAttestation{*att};
 
  307            attestations.emplace_back(*att);
 
  312    auto r = claimHelper(
 
  315        typename TAttestation::MatchFields{*attBegin},
 
  324    return {std::move(r.value()), changed};
 
  330Expected<std::vector<AccountID>, 
TER>
 
  332    XChainClaimAttestations& attestations,
 
  333    ReadView 
const& view,
 
  334    STAmount 
const& sendingAmount,
 
  335    bool wasLockingChainSend,
 
  340    XChainClaimAttestation::MatchFields toMatch{
 
  343        attestations, view, toMatch, CheckDst::ignore, quorum, signersList, j);
 
  346enum class CanCreateDstPolicy { 
no, 
yes };
 
  348enum class DepositAuthPolicy { normal, dstCanBypass };
 
  352struct TransferHelperSubmittingAccountInfo
 
  355    STAmount preFeeBalance;
 
  356    STAmount postFeeBalance;
 
  389    CanCreateDstPolicy canCreate,
 
  390    DepositAuthPolicy depositAuthPolicy,
 
  392        submittingAccountInfo,
 
  399    if (
auto sleDst = psb.read(dstK))
 
  409        bool const canBypassDepositAuth = dst == claimOwner &&
 
  410            depositAuthPolicy == DepositAuthPolicy::dstCanBypass;
 
  412        if (!canBypassDepositAuth && (sleDst->getFlags() & 
lsfDepositAuth) &&
 
  418    else if (!amt.native() || canCreate == CanCreateDstPolicy::no)
 
  426        XRPL_ASSERT(sleSrc, 
"ripple::transferHelper : non-null source account");
 
  431            auto const ownerCount = sleSrc->getFieldU32(sfOwnerCount);
 
  432            auto const reserve = psb.fees().accountReserve(ownerCount);
 
  434            auto const availableBalance = [&]() -> STAmount {
 
  435                STAmount 
const curBal = (*sleSrc)[sfBalance];
 
  439                if (!submittingAccountInfo ||
 
  440                    submittingAccountInfo->account != src ||
 
  441                    submittingAccountInfo->postFeeBalance != curBal)
 
  443                return submittingAccountInfo->preFeeBalance;
 
  446            if (availableBalance < amt + reserve)
 
  452        auto sleDst = psb.peek(dstK);
 
  455            if (canCreate == CanCreateDstPolicy::no)
 
  460            if (amt < psb.fees().reserve)
 
  462                JLOG(j.
trace()) << 
"Insufficient payment to create account.";
 
  468                psb.rules().enabled(featureDeletableAccounts) ? psb.seq() : 1};
 
  471            sleDst->setAccountID(sfAccount, dst);
 
  472            sleDst->setFieldU32(sfSequence, seqno);
 
  477        (*sleSrc)[sfBalance] = (*sleSrc)[sfBalance] - amt;
 
  478        (*sleDst)[sfBalance] = (*sleDst)[sfBalance] + amt;
 
  485    auto const result = 
flow(
 
  500    if (
auto const r = result.result();
 
  511enum class OnTransferFail {
 
  518struct FinalizeClaimHelperResult
 
  539        if ((!mainFundsTer || *mainFundsTer == 
tesSUCCESS) &&
 
  548            return *mainFundsTer;
 
  557        if (mainFundsTer && mainFundsTer != 
tesSUCCESS)
 
  558            return *mainFundsTer;
 
  595FinalizeClaimHelperResult
 
  597    PaymentSandbox& outerSb,
 
  598    STXChainBridge 
const& bridgeSpec,
 
  602    STAmount 
const& sendingAmount,
 
  604    STAmount 
const& rewardPool,
 
  607    Keylet 
const& claimIDKeylet,
 
  608    OnTransferFail onTransferFail,
 
  609    DepositAuthPolicy depositAuthPolicy,
 
  612    FinalizeClaimHelperResult result;
 
  616    STAmount 
const thisChainAmount = [&] {
 
  617        STAmount r = sendingAmount;
 
  618        r.setIssue(bridgeSpec.issue(dstChain));
 
  621    auto const& thisDoor = bridgeSpec.door(dstChain);
 
  624        PaymentSandbox innerSb{&outerSb};
 
  635        result.mainFundsTer = transferHelper(
 
  642            CanCreateDstPolicy::yes,
 
  648            onTransferFail == OnTransferFail::keepClaim)
 
  654        result.rewardTer = [&]() -> 
TER {
 
  655            if (rewardAccounts.empty())
 
  661            STAmount 
const share = [&] {
 
  662                auto const round_mode =
 
  663                    innerSb.rules().enabled(fixXChainRewardRounding)
 
  668                STAmount 
const den{rewardAccounts.size()};
 
  669                return divide(rewardPool, den, rewardPool.issue());
 
  671            STAmount distributed = rewardPool.zeroed();
 
  672            for (
auto const& rewardAccount : rewardAccounts)
 
  674                auto const thTer = transferHelper(
 
  682                    CanCreateDstPolicy::no,
 
  683                    DepositAuthPolicy::normal,
 
  691                    distributed += share;
 
  697            if (distributed > rewardPool)
 
  704            (onTransferFail == OnTransferFail::keepClaim ||
 
  716            innerSb.apply(outerSb);
 
  720    if (
auto const sleClaimID = outerSb.peek(claimIDKeylet))
 
  722        auto const cidOwner = (*sleClaimID)[sfAccount];
 
  726            auto const page = (*sleClaimID)[sfOwnerNode];
 
  727            if (!outerSb.dirRemove(
 
  731                    << 
"Unable to delete xchain seq number from owner.";
 
  737            outerSb.erase(sleClaimID);
 
  756getSignersListAndQuorum(
 
  757    ReadView 
const& view,
 
  758    SLE const& sleBridge,
 
  764    AccountID const thisDoor = sleBridge[sfAccount];
 
  765    auto const sleDoor = [&] { 
return view.read(
keylet::account(thisDoor)); }();
 
  777    q = (*sleS)[sfSignerQuorum];
 
  786    for (
auto const& as : *accountSigners)
 
  788        r[as.account] = as.weight;
 
  794template <
class R, 
class F>
 
  796readOrpeekBridge(F&& getter, STXChainBridge 
const& bridgeSpec)
 
  799        if (
auto r = getter(bridgeSpec, ct))
 
  801            if ((*r)[sfXChainBridge] == bridgeSpec)
 
  812peekBridge(ApplyView& v, STXChainBridge 
const& bridgeSpec)
 
  814    return readOrpeekBridge<SLE>(
 
  821readBridge(ReadView 
const& v, STXChainBridge 
const& bridgeSpec)
 
  823    return readOrpeekBridge<SLE const>(
 
  833template <
class TIter>
 
  835applyClaimAttestations(
 
  840    STXChainBridge 
const& bridgeSpec,
 
  846    if (attBegin == attEnd)
 
  849    PaymentSandbox psb(&view);
 
  851    auto const claimIDKeylet =
 
  856        OnNewAttestationResult newAttResult;
 
  857        STAmount rewardAmount;
 
  861    auto const scopeResult = [&]() -> Expected<ScopeResult, TER> {
 
  866        auto const sleClaimID = psb.peek(claimIDKeylet);
 
  873        for (
auto att = attBegin; att != attEnd; ++att)
 
  875            if (!signersList.
contains(att->attestationSignerAccount))
 
  885        AccountID const otherChainSource = (*sleClaimID)[sfOtherChainSource];
 
  886        if (attBegin->sendingAccount != otherChainSource)
 
  898            if (attDstChain != dstChain)
 
  904        XChainClaimAttestations curAtts{
 
  905            sleClaimID->getFieldArray(sfXChainClaimAttestations)};
 
  907        auto const newAttResult = onNewAttestations(
 
  911            &atts[0] + atts.
size(),
 
  917        sleClaimID->setFieldArray(
 
  918            sfXChainClaimAttestations, curAtts.toSTArray());
 
  919        psb.update(sleClaimID);
 
  923            (*sleClaimID)[sfSignatureReward],
 
  924            (*sleClaimID)[sfAccount]};
 
  927    if (!scopeResult.has_value())
 
  928        return scopeResult.error();
 
  930    auto const& [newAttResult, rewardAmount, cidOwner] = scopeResult.value();
 
  931    auto const& [rewardAccounts, attListChanged] = newAttResult;
 
  932    if (rewardAccounts && attBegin->dst)
 
  934        auto const r = finalizeClaimHelper(
 
  940            attBegin->sendingAmount,
 
  946            OnTransferFail::keepClaim,
 
  947            DepositAuthPolicy::normal,
 
  950        auto const rTer = r.ter();
 
  962template <
class TIter>
 
  964applyCreateAccountAttestations(
 
  971    STXChainBridge 
const& bridgeSpec,
 
  972    Keylet 
const& bridgeK,
 
  978    if (attBegin == attEnd)
 
  981    PaymentSandbox psb(&view);
 
  983    auto const claimCountResult = [&]() -> Expected<std::uint64_t, TER> {
 
  984        auto const sleBridge = psb.peek(bridgeK);
 
  988        return (*sleBridge)[sfXChainAccountClaimCount];
 
  991    if (!claimCountResult.has_value())
 
  992        return claimCountResult.error();
 
  996    if (attBegin->createCount <= claimCount)
 
 1013        if (attDstChain != dstChain)
 
 1019    auto const claimIDKeylet =
 
 1024        OnNewAttestationResult newAttResult;
 
 1026        XChainCreateAccountAttestations curAtts;
 
 1029    auto const scopeResult = [&]() -> Expected<ScopeResult, TER> {
 
 1037        auto const sleClaimID = psb.peek(claimIDKeylet);
 
 1038        bool createCID = 
false;
 
 1043            auto const sleDoor = psb.peek(doorK);
 
 1048            auto const balance = (*sleDoor)[sfBalance];
 
 1049            auto const reserve =
 
 1050                psb.fees().accountReserve((*sleDoor)[sfOwnerCount] + 1);
 
 1052            if (balance < reserve)
 
 1058        for (
auto att = attBegin; att != attEnd; ++att)
 
 1060            if (!signersList.
contains(att->attestationSignerAccount))
 
 1069        XChainCreateAccountAttestations curAtts = [&] {
 
 1071                return XChainCreateAccountAttestations{
 
 1072                    sleClaimID->getFieldArray(
 
 1073                        sfXChainCreateAccountAttestations)};
 
 1074            return XChainCreateAccountAttestations{};
 
 1077        auto const newAttResult = onNewAttestations(
 
 1081            &atts[0] + atts.
size(),
 
 1092            sleClaimID->setFieldArray(
 
 1093                sfXChainCreateAccountAttestations, curAtts.toSTArray());
 
 1094            psb.update(sleClaimID);
 
 1096        return ScopeResult{newAttResult, createCID, curAtts};
 
 1099    if (!scopeResult.has_value())
 
 1100        return scopeResult.error();
 
 1102    auto const& [attResult, createCID, curAtts] = scopeResult.value();
 
 1103    auto const& [rewardAccounts, attListChanged] = attResult;
 
 1106    if (rewardAccounts && claimCount + 1 == attBegin->createCount)
 
 1108        auto const r = finalizeClaimHelper(
 
 1114            attBegin->sendingAmount,
 
 1116            attBegin->rewardAmount,
 
 1120            OnTransferFail::removeClaim,
 
 1121            DepositAuthPolicy::normal,
 
 1124        auto const rTer = r.ter();
 
 1134        auto const sleBridge = psb.peek(bridgeK);
 
 1137        (*sleBridge)[sfXChainAccountClaimCount] = attBegin->createCount;
 
 1138        psb.update(sleBridge);
 
 1143        (*createdSleClaimID)[sfAccount] = doorAccount;
 
 1144        (*createdSleClaimID)[sfXChainBridge] = bridgeSpec;
 
 1145        (*createdSleClaimID)[sfXChainAccountCreateCount] =
 
 1146            attBegin->createCount;
 
 1147        createdSleClaimID->setFieldArray(
 
 1148            sfXChainCreateAccountAttestations, curAtts.toSTArray());
 
 1151        auto const page = psb.dirInsert(
 
 1157        (*createdSleClaimID)[sfOwnerNode] = *
page;
 
 1159        auto const sleDoor = psb.peek(doorK);
 
 1165        psb.insert(createdSleClaimID);
 
 1166        psb.update(sleDoor);
 
 1174template <
class TAttestation>
 
 1176toClaim(STTx 
const& tx)
 
 1185        o.setAccountID(sfAccount, o[sfOtherChainSource]);
 
 1186        return TAttestation(o);
 
 1194template <
class TAttestation>
 
 1196attestationpreflight(PreflightContext 
const& ctx)
 
 1201    auto const att = toClaim<TAttestation>(ctx.tx);
 
 1205    STXChainBridge 
const bridgeSpec = ctx.tx[sfXChainBridge];
 
 1206    if (!att->verify(bridgeSpec))
 
 1208    if (!att->validAmounts())
 
 1211    if (att->sendingAmount.signum() <= 0)
 
 1213    auto const expectedIssue =
 
 1215    if (att->sendingAmount.issue() != expectedIssue)
 
 1221template <
class TAttestation>
 
 1223attestationPreclaim(PreclaimContext 
const& ctx)
 
 1225    auto const att = toClaim<TAttestation>(ctx.tx);
 
 1230    STXChainBridge 
const bridgeSpec = ctx.tx[sfXChainBridge];
 
 1231    auto const sleBridge = readBridge(ctx.view, bridgeSpec);
 
 1237    AccountID const attestationSignerAccount{
 
 1238        ctx.tx[sfAttestationSignerAccount]};
 
 1239    PublicKey 
const pk{ctx.tx[sfPublicKey]};
 
 1242    auto const [signersList, quorum, slTer] =
 
 1243        getSignersListAndQuorum(ctx.view, *sleBridge, ctx.j);
 
 1248    return checkAttestationPublicKey(
 
 1249        ctx.view, signersList, attestationSignerAccount, pk, ctx.j);
 
 1252template <
class TAttestation>
 
 1254attestationDoApply(ApplyContext& ctx)
 
 1256    auto const att = toClaim<TAttestation>(ctx.tx);
 
 1261    STXChainBridge 
const bridgeSpec = ctx.tx[sfXChainBridge];
 
 1265        STXChainBridge::ChainType srcChain;
 
 1272    auto const scopeResult = [&]() -> Expected<ScopeResult, TER> {
 
 1277        auto sleBridge = readBridge(ctx.view(), bridgeSpec);
 
 1282        Keylet 
const bridgeK{ltBRIDGE, sleBridge->key()};
 
 1283        AccountID const thisDoor = (*sleBridge)[sfAccount];
 
 1287            if (thisDoor == bridgeSpec.lockingChainDoor())
 
 1289            else if (thisDoor == bridgeSpec.issuingChainDoor())
 
 1298        auto [signersList, quorum, slTer] =
 
 1299            getSignersListAndQuorum(ctx.view(), *sleBridge, ctx.journal);
 
 1305            srcChain, std::move(signersList), quorum, thisDoor, bridgeK};
 
 1308    if (!scopeResult.has_value())
 
 1309        return scopeResult.error();
 
 1311    auto const& [srcChain, signersList, quorum, thisDoor, bridgeK] =
 
 1312        scopeResult.value();
 
 1320        return applyClaimAttestations(
 
 1333                           Attestations::AttestationCreateAccount>)
 
 1335        return applyCreateAccountAttestations(
 
 1357    auto const account = ctx.
tx[sfAccount];
 
 1358    auto const reward = ctx.
tx[sfSignatureReward];
 
 1359    auto const minAccountCreate = ctx.
tx[~sfMinAccountCreateAmount];
 
 1360    auto const bridgeSpec = ctx.
tx[sfXChainBridge];
 
 1362    if (bridgeSpec.lockingChainDoor() == bridgeSpec.issuingChainDoor())
 
 1367    if (bridgeSpec.lockingChainDoor() != account &&
 
 1368        bridgeSpec.issuingChainDoor() != account)
 
 1373    if (
isXRP(bridgeSpec.lockingChainIssue()) !=
 
 1374        isXRP(bridgeSpec.issuingChainIssue()))
 
 1381    if (!
isXRP(reward) || reward.signum() < 0)
 
 1386    if (minAccountCreate &&
 
 1387        ((!
isXRP(*minAccountCreate) || minAccountCreate->signum() <= 0) ||
 
 1388         !
isXRP(bridgeSpec.lockingChainIssue()) ||
 
 1389         !
isXRP(bridgeSpec.issuingChainIssue())))
 
 1394    if (
isXRP(bridgeSpec.issuingChainIssue()))
 
 1403        if (bridgeSpec.issuingChainDoor() != rootAccount)
 
 1412        if (bridgeSpec.issuingChainDoor() !=
 
 1413            bridgeSpec.issuingChainIssue().account)
 
 1419    if (bridgeSpec.lockingChainDoor() == bridgeSpec.lockingChainIssue().account)
 
 
 1432    auto const account = ctx.
tx[sfAccount];
 
 1433    auto const bridgeSpec = ctx.
tx[sfXChainBridge];
 
 1449    if (!
isXRP(bridgeSpec.issue(chainType)))
 
 1451        auto const sleIssuer =
 
 1469        auto const balance = (*sleAcc)[sfBalance];
 
 1470        auto const reserve =
 
 1473        if (balance < reserve)
 
 
 1483    auto const account = 
ctx_.
tx[sfAccount];
 
 1484    auto const bridgeSpec = 
ctx_.
tx[sfXChainBridge];
 
 1485    auto const reward = 
ctx_.
tx[sfSignatureReward];
 
 1486    auto const minAccountCreate = 
ctx_.
tx[~sfMinAccountCreateAmount];
 
 1498    (*sleBridge)[sfAccount] = account;
 
 1499    (*sleBridge)[sfSignatureReward] = reward;
 
 1500    if (minAccountCreate)
 
 1501        (*sleBridge)[sfMinAccountCreateAmount] = *minAccountCreate;
 
 1502    (*sleBridge)[sfXChainBridge] = bridgeSpec;
 
 1503    (*sleBridge)[sfXChainClaimID] = 0;
 
 1504    (*sleBridge)[sfXChainAccountCreateCount] = 0;
 
 1505    (*sleBridge)[sfXChainAccountClaimCount] = 0;
 
 1513        (*sleBridge)[sfOwnerNode] = *page;
 
 
 1535    auto const account = ctx.
tx[sfAccount];
 
 1536    auto const reward = ctx.
tx[~sfSignatureReward];
 
 1537    auto const minAccountCreate = ctx.
tx[~sfMinAccountCreateAmount];
 
 1538    auto const bridgeSpec = ctx.
tx[sfXChainBridge];
 
 1539    bool const clearAccountCreate =
 
 1542    if (!reward && !minAccountCreate && !clearAccountCreate)
 
 1548    if (minAccountCreate && clearAccountCreate)
 
 1554    if (bridgeSpec.lockingChainDoor() != account &&
 
 1555        bridgeSpec.issuingChainDoor() != account)
 
 1560    if (reward && (!
isXRP(*reward) || reward->signum() < 0))
 
 1565    if (minAccountCreate &&
 
 1566        ((!
isXRP(*minAccountCreate) || minAccountCreate->signum() <= 0) ||
 
 1567         !
isXRP(bridgeSpec.lockingChainIssue()) ||
 
 1568         !
isXRP(bridgeSpec.issuingChainIssue())))
 
 
 1579    auto const account = ctx.
tx[sfAccount];
 
 1580    auto const bridgeSpec = ctx.
tx[sfXChainBridge];
 
 
 1596    auto const account = 
ctx_.
tx[sfAccount];
 
 1597    auto const bridgeSpec = 
ctx_.
tx[sfXChainBridge];
 
 1598    auto const reward = 
ctx_.
tx[~sfSignatureReward];
 
 1599    auto const minAccountCreate = 
ctx_.
tx[~sfMinAccountCreateAmount];
 
 1600    bool const clearAccountCreate =
 
 1610    auto const sleBridge =
 
 1616        (*sleBridge)[sfSignatureReward] = *reward;
 
 1617    if (minAccountCreate)
 
 1619        (*sleBridge)[sfMinAccountCreateAmount] = *minAccountCreate;
 
 1621    if (clearAccountCreate &&
 
 1622        sleBridge->isFieldPresent(sfMinAccountCreateAmount))
 
 1624        sleBridge->makeFieldAbsent(sfMinAccountCreateAmount);
 
 
 1637    auto const amount = ctx.
tx[sfAmount];
 
 1639    if (amount.signum() <= 0 ||
 
 
 1654    STAmount const& thisChainAmount = ctx.
tx[sfAmount];
 
 1655    auto const claimID = ctx.
tx[sfXChainClaimID];
 
 1657    auto const sleBridge = readBridge(ctx.
view, bridgeSpec);
 
 1668    auto const thisDoor = (*sleBridge)[sfAccount];
 
 1669    bool isLockingChain = 
false;
 
 1672            isLockingChain = 
true;
 
 1674            isLockingChain = 
false;
 
 1703    auto const otherChainAmount = [&]() -> 
STAmount {
 
 1712    auto const sleClaimID =
 
 1722        if ((*sleClaimID)[sfAccount] != account)
 
 
 1739    auto const dst = 
ctx_.
tx[sfDestination];
 
 1742    auto const claimID = 
ctx_.
tx[sfXChainClaimID];
 
 1761        auto const sleBridge = peekBridge(psb, bridgeSpec);
 
 1762        auto const sleClaimID = psb.
peek(claimIDKeylet);
 
 1764        if (!(sleBridge && sleClaimID && sleAcct))
 
 1767        AccountID const thisDoor = (*sleBridge)[sfAccount];
 
 1781        auto const sendingAmount = [&]() -> 
STAmount {
 
 1787        auto const [signersList, quorum, slTer] =
 
 1794            sleClaimID->getFieldArray(sfXChainClaimAttestations)};
 
 1796        auto const claimR = onClaim(
 
 1805        if (!claimR.has_value())
 
 1810            (*sleClaimID)[sfAccount],
 
 1813            (*sleClaimID)[sfSignatureReward],
 
 1817    if (!scopeResult.has_value())
 
 1818        return scopeResult.error();
 
 1820    auto const& [rewardAccounts, rewardPoolSrc, sendingAmount, srcChain, signatureReward] =
 
 1821        scopeResult.value();
 
 1824    auto const r = finalizeClaimHelper(
 
 1836        OnTransferFail::keepClaim,
 
 1837        DepositAuthPolicy::dstCanBypass,
 
 1839    if (!r.isTesSuccess())
 
 
 1852    auto const maxSpend = [&] {
 
 1853        auto const amount = ctx.
tx[sfAmount];
 
 1854        if (amount.native() && amount.signum() > 0)
 
 1855            return amount.xrp();
 
 
 1865    auto const amount = ctx.
tx[sfAmount];
 
 1866    auto const bridgeSpec = ctx.
tx[sfXChainBridge];
 
 1868    if (amount.signum() <= 0 || !
isLegalNet(amount))
 
 1871    if (amount.issue() != bridgeSpec.lockingChainIssue() &&
 
 1872        amount.issue() != bridgeSpec.issuingChainIssue())
 
 
 1881    auto const bridgeSpec = ctx.
tx[sfXChainBridge];
 
 1882    auto const amount = ctx.
tx[sfAmount];
 
 1884    auto const sleBridge = readBridge(ctx.
view, bridgeSpec);
 
 1890    AccountID const thisDoor = (*sleBridge)[sfAccount];
 
 1893    if (thisDoor == account)
 
 1899    bool isLockingChain = 
false;
 
 1901        if (thisDoor == bridgeSpec.lockingChainDoor())
 
 1902            isLockingChain = 
true;
 
 1903        else if (thisDoor == bridgeSpec.issuingChainDoor())
 
 1904            isLockingChain = 
false;
 
 1911        if (bridgeSpec.lockingChainIssue() != ctx.
tx[sfAmount].issue())
 
 1916        if (bridgeSpec.issuingChainIssue() != ctx.
tx[sfAmount].issue())
 
 
 1928    auto const account = 
ctx_.
tx[sfAccount];
 
 1929    auto const amount = 
ctx_.
tx[sfAmount];
 
 1930    auto const bridgeSpec = 
ctx_.
tx[sfXChainBridge];
 
 1935    auto const sleBridge = readBridge(psb, bridgeSpec);
 
 1939    auto const dst = (*sleBridge)[sfAccount];
 
 1942    TransferHelperSubmittingAccountInfo submittingAccountInfo{
 
 1945    auto const thTer = transferHelper(
 
 1952        CanCreateDstPolicy::no,
 
 1953        DepositAuthPolicy::normal,
 
 1954        submittingAccountInfo,
 
 
 1970    auto const reward = ctx.
tx[sfSignatureReward];
 
 
 1981    auto const account = ctx.
tx[sfAccount];
 
 1982    auto const bridgeSpec = ctx.
tx[sfXChainBridge];
 
 1983    auto const sleBridge = readBridge(ctx.
view, bridgeSpec);
 
 1991    auto const reward = ctx.
tx[sfSignatureReward];
 
 1993    if (reward != (*sleBridge)[sfSignatureReward])
 
 2004        auto const balance = (*sleAcc)[sfBalance];
 
 2005        auto const reserve =
 
 2008        if (balance < reserve)
 
 
 2018    auto const account = 
ctx_.
tx[sfAccount];
 
 2019    auto const bridgeSpec = 
ctx_.
tx[sfXChainBridge];
 
 2020    auto const reward = 
ctx_.
tx[sfSignatureReward];
 
 2021    auto const otherChainSrc = 
ctx_.
tx[sfOtherChainSource];
 
 2027    auto const sleBridge = peekBridge(
ctx_.
view(), bridgeSpec);
 
 2031    std::uint32_t const claimID = (*sleBridge)[sfXChainClaimID] + 1;
 
 2038    (*sleBridge)[sfXChainClaimID] = claimID;
 
 2049    (*sleClaimID)[sfAccount] = account;
 
 2050    (*sleClaimID)[sfXChainBridge] = bridgeSpec;
 
 2051    (*sleClaimID)[sfXChainClaimID] = claimID;
 
 2052    (*sleClaimID)[sfOtherChainSource] = otherChainSrc;
 
 2053    (*sleClaimID)[sfSignatureReward] = reward;
 
 2054    sleClaimID->setFieldArray(
 
 2055        sfXChainClaimAttestations, 
STArray{sfXChainClaimAttestations});
 
 2065        (*sleClaimID)[sfOwnerNode] = *page;
 
 
 2082    return attestationpreflight<Attestations::AttestationClaim>(ctx);
 
 
 2088    return attestationPreclaim<Attestations::AttestationClaim>(ctx);
 
 
 2094    return attestationDoApply<Attestations::AttestationClaim>(
ctx_);
 
 
 2102    return attestationpreflight<Attestations::AttestationCreateAccount>(ctx);
 
 
 2108    return attestationPreclaim<Attestations::AttestationCreateAccount>(ctx);
 
 
 2114    return attestationDoApply<Attestations::AttestationCreateAccount>(
ctx_);
 
 
 2122    auto const amount = ctx.
tx[sfAmount];
 
 2124    if (amount.signum() <= 0 || !amount.native())
 
 2127    auto const reward = ctx.
tx[sfSignatureReward];
 
 2128    if (reward.signum() < 0 || !reward.native())
 
 2131    if (reward.issue() != amount.issue())
 
 
 2142    STAmount const reward = ctx.
tx[sfSignatureReward];
 
 2144    auto const sleBridge = readBridge(ctx.
view, bridgeSpec);
 
 2150    if (reward != (*sleBridge)[sfSignatureReward])
 
 2156        (*sleBridge)[~sfMinAccountCreateAmount];
 
 2158    if (!minCreateAmount)
 
 2161    if (amount < *minCreateAmount)
 
 2164    if (minCreateAmount->issue() != amount.
issue())
 
 2167    AccountID const thisDoor = (*sleBridge)[sfAccount];
 
 2169    if (thisDoor == account)
 
 2187    if (bridgeSpec.
issue(srcChain) != ctx.
tx[sfAmount].issue())
 
 
 2210    auto const sleBridge = peekBridge(psb, bridge);
 
 2214    auto const dst = (*sleBridge)[sfAccount];
 
 2217    TransferHelperSubmittingAccountInfo submittingAccountInfo{
 
 2219    STAmount const toTransfer = amount + reward;
 
 2220    auto const thTer = transferHelper(
 
 2227        CanCreateDstPolicy::yes,
 
 2228        DepositAuthPolicy::normal,
 
 2229        submittingAccountInfo,
 
 2235    (*sleBridge)[sfXChainAccountCreateCount] =
 
 2236        (*sleBridge)[sfXChainAccountCreateCount] + 1;
 
 
A generic endpoint for log messages.
 
Stream trace() const
Severity stream access functions.
 
beast::Journal const journal
 
virtual void update(std::shared_ptr< SLE > const &sle)=0
Indicate changes to a peeked SLE.
 
virtual void insert(std::shared_ptr< SLE > const &sle)=0
Insert a new state SLE.
 
std::optional< std::uint64_t > dirInsert(Keylet const &directory, uint256 const &key, std::function< void(std::shared_ptr< SLE > const &)> const &describe)
Insert an entry to a directory.
 
virtual std::shared_ptr< SLE > peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
 
static TER preclaim(PreclaimContext const &ctx)
 
static NotTEC preflight(PreflightContext const &ctx)
 
static std::uint32_t getFlagsMask(PreflightContext const &ctx)
 
static rounding_mode getround()
 
static rounding_mode setround(rounding_mode mode)
 
A wrapper which makes credits unavailable to balances.
 
void apply(RawView &to)
Apply changes to base view.
 
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
 
virtual Fees const & fees() const =0
Returns the fees for the base ledger.
 
virtual bool exists(Keylet const &k) const =0
Determine if a state item exists.
 
void setIssue(Asset const &asset)
Set the Issue for this amount.
 
Issue const & issue() const
 
std::uint32_t getFlags() const
 
static ChainType dstChain(bool wasLockingChainSend)
 
static ChainType srcChain(bool wasLockingChainSend)
 
AccountID const & issuingChainDoor() const
 
Issue const & issuingChainIssue() const
 
Issue const & lockingChainIssue() const
 
static ChainType otherChain(ChainType ct)
 
AccountID const & lockingChainDoor() const
 
Issue const & issue(ChainType ct) const
 
static Expected< std::vector< SignerEntry >, NotTEC > deserialize(STObject const &obj, beast::Journal journal, std::string_view annotation)
 
Class describing the consequences to the account of applying a transaction if the transaction consume...
 
static TER preclaim(PreclaimContext const &ctx)
 
static NotTEC preflight(PreflightContext const &ctx)
 
static TER preclaim(PreclaimContext const &ctx)
 
static NotTEC preflight(PreflightContext const &ctx)
 
static TER preclaim(PreclaimContext const &ctx)
 
static NotTEC preflight(PreflightContext const &ctx)
 
static TxConsequences makeTxConsequences(PreflightContext const &ctx)
 
static TER preclaim(PreclaimContext const &ctx)
 
static NotTEC preflight(PreflightContext const &ctx)
 
static TER preclaim(PreclaimContext const &ctx)
 
static NotTEC preflight(PreflightContext const &ctx)
 
static TER preclaim(PreclaimContext const &ctx)
 
static NotTEC preflight(PreflightContext const &ctx)
 
static TER preclaim(PreclaimContext const &ctx)
 
static NotTEC preflight(PreflightContext const &ctx)
 
void update(std::shared_ptr< SLE > const &sle) override
Indicate changes to a peeked SLE.
 
std::shared_ptr< SLE const > read(Keylet const &k) const override
Return the state item associated with a key.
 
std::shared_ptr< SLE > peek(Keylet const &k) override
Prepare to modify the SLE associated with key.
 
void check(bool condition, std::string const &message)
 
Keylet xChainClaimID(STXChainBridge const &bridge, std::uint64_t seq)
 
Keylet account(AccountID const &id) noexcept
AccountID root.
 
Keylet page(uint256 const &root, std::uint64_t index=0) noexcept
A page in a directory.
 
Keylet bridge(STXChainBridge const &bridge, STXChainBridge::ChainType chainType)
 
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
 
Keylet signers(AccountID const &account) noexcept
A SignerList.
 
Keylet xChainCreateAccountClaimID(STXChainBridge const &bridge, std::uint64_t seq)
 
Keylet depositPreauth(AccountID const &owner, AccountID const &preauthorized) noexcept
A DepositPreauth.
 
std::uint32_t ownerCount(Env const &env, Account const &account)
 
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
 
base_uint< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
 
STAmount divide(STAmount const &amount, Rate const &rate)
 
constexpr std::uint32_t tfBridgeModifyMask
 
bool isXRP(AccountID const &c)
 
constexpr size_t xbridgeMaxAccountCreateClaims
 
std::pair< PublicKey, SecretKey > generateKeyPair(KeyType type, Seed const &seed)
Generate a key pair deterministically.
 
bool isLegalNet(STAmount const &value)
 
@ lsfAllowTrustLineClawback
 
void adjustOwnerCount(ApplyView &view, std::shared_ptr< SLE > const &sle, std::int32_t amount, beast::Journal j)
Adjust the owner count up or down.
 
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
 
StrandResult< TInAmt, TOutAmt > flow(PaymentSandbox const &baseView, Strand const &strand, std::optional< TInAmt > const &maxIn, TOutAmt const &out, beast::Journal j)
Request out amount from a strand.
 
AccountID calcAccountID(PublicKey const &pk)
 
bool isTefFailure(TER x) noexcept
 
std::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
 
constexpr std::uint32_t tfClearAccountCreateAmount
 
@ tecXCHAIN_INSUFF_CREATE_AMOUNT
 
@ tecXCHAIN_CREATE_ACCOUNT_DISABLED
 
@ tecXCHAIN_CREATE_ACCOUNT_NONXRP_ISSUE
 
@ tecXCHAIN_PAYMENT_FAILED
 
@ tecXCHAIN_CLAIM_NO_QUORUM
 
@ tecXCHAIN_PROOF_UNKNOWN_KEY
 
@ tecXCHAIN_ACCOUNT_CREATE_PAST
 
@ tecXCHAIN_BAD_TRANSFER_ISSUE
 
@ tecXCHAIN_REWARD_MISMATCH
 
@ tecXCHAIN_SENDING_ACCOUNT_MISMATCH
 
@ tecXCHAIN_BAD_PUBLIC_KEY_ACCOUNT_PAIR
 
@ tecXCHAIN_NO_SIGNERS_LIST
 
@ tecINSUFFICIENT_RESERVE
 
@ tecXCHAIN_ACCOUNT_CREATE_TOO_MANY
 
bool isTerRetry(TER x) noexcept
 
bool isTesSuccess(TER x) noexcept
 
Unexpected(E(&)[N]) -> Unexpected< E const * >
 
Seed generateSeed(std::string const &passPhrase)
Generate a seed deterministically.
 
TERSubset< CanCvtToTER > TER
 
bool isTecClaim(TER x) noexcept
 
TERSubset< CanCvtToNotTEC > NotTEC
 
@ temXCHAIN_BRIDGE_BAD_MIN_ACCOUNT_CREATE_AMOUNT
 
@ temXCHAIN_BRIDGE_BAD_REWARD_AMOUNT
 
@ temXCHAIN_EQUAL_DOOR_ACCOUNTS
 
@ temXCHAIN_BRIDGE_NONDOOR_OWNER
 
@ temXCHAIN_BRIDGE_BAD_ISSUES
 
XRPAmount accountReserve(std::size_t ownerCount) const
Returns the account reserve given the owner count, in drops.
 
A pair of SHAMap key and LedgerEntryType.
 
State information when determining if a tx is likely to claim a fee.
 
State information when preflighting a tx.