20#include <xrpld/app/paths/Flow.h>
21#include <xrpld/app/tx/detail/SignerEntries.h>
22#include <xrpld/app/tx/detail/Transactor.h>
23#include <xrpld/app/tx/detail/XChainBridge.h>
25#include <xrpl/basics/Log.h>
26#include <xrpl/basics/Number.h>
27#include <xrpl/basics/chrono.h>
28#include <xrpl/beast/utility/Journal.h>
29#include <xrpl/beast/utility/instrumentation.h>
30#include <xrpl/ledger/ApplyView.h>
31#include <xrpl/ledger/PaymentSandbox.h>
32#include <xrpl/ledger/View.h>
33#include <xrpl/protocol/AccountID.h>
34#include <xrpl/protocol/Feature.h>
35#include <xrpl/protocol/Indexes.h>
36#include <xrpl/protocol/PublicKey.h>
37#include <xrpl/protocol/SField.h>
38#include <xrpl/protocol/STAmount.h>
39#include <xrpl/protocol/STObject.h>
40#include <xrpl/protocol/STXChainBridge.h>
41#include <xrpl/protocol/TER.h>
42#include <xrpl/protocol/TxFlags.h>
43#include <xrpl/protocol/XChainAttestations.h>
44#include <xrpl/protocol/XRPAmount.h>
111checkAttestationPublicKey(
112 ReadView
const& view,
114 AccountID const& attestationSignerAccount,
118 if (!signersList.
contains(attestationSignerAccount))
125 if (
auto const sleAttestationSigningAccount =
128 if (accountFromPK == attestationSignerAccount)
131 if (sleAttestationSigningAccount->getFieldU32(sfFlags) &
134 JLOG(j.
trace()) <<
"Attempt to add an attestation with "
135 "disabled master key.";
143 (*sleAttestationSigningAccount)[~sfRegularKey];
144 regularKey != accountFromPK)
149 <<
"Attempt to add an attestation with "
150 "account present and non-present regular key.";
154 JLOG(j.
trace()) <<
"Attempt to add an attestation with "
155 "account present and mismatched "
156 "regular key/public key.";
168 <<
"Attempt to add an attestation with non-existant account "
169 "and mismatched pk/account pair.";
188enum class CheckDst {
check, ignore };
189template <
class TAttestation>
190Expected<std::vector<AccountID>,
TER>
192 XChainAttestationsBase<TAttestation>& attestations,
193 ReadView
const& view,
194 typename TAttestation::MatchFields
const& toMatch,
203 attestations.erase_if([&](
auto const& a) {
204 return checkAttestationPublicKey(
205 view, signersList, a.keyAccount, a.publicKey, j) !=
211 rewardAccounts.reserve(attestations.size());
213 for (
auto const& a : attestations)
215 auto const matchR = a.match(toMatch);
221 (checkDst == CheckDst::check && matchR !=
match))
223 auto i = signersList.
find(a.keyAccount);
224 if (i == signersList.
end())
228 "ripple::claimHelper : invalid inputs");
234 rewardAccounts.push_back(a.rewardAccount);
237 if (weight >= quorum)
238 return rewardAccounts;
274struct OnNewAttestationResult
282template <
class TAttestation>
283[[nodiscard]] OnNewAttestationResult
285 XChainAttestationsBase<TAttestation>& attestations,
286 ReadView
const& view,
287 typename TAttestation::TSignedAttestation
const* attBegin,
288 typename TAttestation::TSignedAttestation
const* attEnd,
293 bool changed =
false;
294 for (
auto att = attBegin; att != attEnd; ++att)
296 if (checkAttestationPublicKey(
299 att->attestationSignerAccount,
310 auto const& claimSigningAccount = att->attestationSignerAccount;
312 attestations.begin(),
315 return a.keyAccount == claimSigningAccount;
317 i != attestations.end())
321 *i = TAttestation{*att};
326 attestations.emplace_back(*att);
331 auto r = claimHelper(
334 typename TAttestation::MatchFields{*attBegin},
343 return {std::move(r.value()), changed};
349Expected<std::vector<AccountID>,
TER>
351 XChainClaimAttestations& attestations,
352 ReadView
const& view,
353 STAmount
const& sendingAmount,
354 bool wasLockingChainSend,
359 XChainClaimAttestation::MatchFields toMatch{
362 attestations, view, toMatch, CheckDst::ignore, quorum, signersList, j);
365enum class CanCreateDstPolicy {
no,
yes };
367enum class DepositAuthPolicy { normal, dstCanBypass };
371struct TransferHelperSubmittingAccountInfo
374 STAmount preFeeBalance;
375 STAmount postFeeBalance;
408 CanCreateDstPolicy canCreate,
409 DepositAuthPolicy depositAuthPolicy,
411 submittingAccountInfo,
418 if (
auto sleDst = psb.read(dstK))
428 bool const canBypassDepositAuth = dst == claimOwner &&
429 depositAuthPolicy == DepositAuthPolicy::dstCanBypass;
431 if (!canBypassDepositAuth && (sleDst->getFlags() &
lsfDepositAuth) &&
437 else if (!amt.native() || canCreate == CanCreateDstPolicy::no)
445 XRPL_ASSERT(sleSrc,
"ripple::transferHelper : non-null source account");
450 auto const ownerCount = sleSrc->getFieldU32(sfOwnerCount);
451 auto const reserve = psb.fees().accountReserve(ownerCount);
453 auto const availableBalance = [&]() -> STAmount {
454 STAmount
const curBal = (*sleSrc)[sfBalance];
458 if (!submittingAccountInfo ||
459 submittingAccountInfo->account != src ||
460 submittingAccountInfo->postFeeBalance != curBal)
462 return submittingAccountInfo->preFeeBalance;
465 if (availableBalance < amt + reserve)
471 auto sleDst = psb.peek(dstK);
474 if (canCreate == CanCreateDstPolicy::no)
479 if (amt < psb.fees().accountReserve(0))
481 JLOG(j.
trace()) <<
"Insufficient payment to create account.";
487 psb.rules().enabled(featureDeletableAccounts) ? psb.seq() : 1};
490 sleDst->setAccountID(sfAccount, dst);
491 sleDst->setFieldU32(sfSequence, seqno);
496 (*sleSrc)[sfBalance] = (*sleSrc)[sfBalance] - amt;
497 (*sleDst)[sfBalance] = (*sleDst)[sfBalance] + amt;
504 auto const result =
flow(
519 if (
auto const r = result.result();
530enum class OnTransferFail {
537struct FinalizeClaimHelperResult
558 if ((!mainFundsTer || *mainFundsTer ==
tesSUCCESS) &&
567 return *mainFundsTer;
576 if (mainFundsTer && mainFundsTer !=
tesSUCCESS)
577 return *mainFundsTer;
614FinalizeClaimHelperResult
616 PaymentSandbox& outerSb,
617 STXChainBridge
const& bridgeSpec,
621 STAmount
const& sendingAmount,
623 STAmount
const& rewardPool,
626 Keylet
const& claimIDKeylet,
627 OnTransferFail onTransferFail,
628 DepositAuthPolicy depositAuthPolicy,
631 FinalizeClaimHelperResult result;
635 STAmount
const thisChainAmount = [&] {
636 STAmount r = sendingAmount;
637 r.setIssue(bridgeSpec.issue(dstChain));
640 auto const& thisDoor = bridgeSpec.door(dstChain);
643 PaymentSandbox innerSb{&outerSb};
654 result.mainFundsTer = transferHelper(
661 CanCreateDstPolicy::yes,
667 onTransferFail == OnTransferFail::keepClaim)
673 result.rewardTer = [&]() ->
TER {
674 if (rewardAccounts.empty())
680 STAmount
const share = [&] {
681 auto const round_mode =
682 innerSb.rules().enabled(fixXChainRewardRounding)
687 STAmount
const den{rewardAccounts.size()};
688 return divide(rewardPool, den, rewardPool.issue());
690 STAmount distributed = rewardPool.zeroed();
691 for (
auto const& rewardAccount : rewardAccounts)
693 auto const thTer = transferHelper(
701 CanCreateDstPolicy::no,
702 DepositAuthPolicy::normal,
710 distributed += share;
716 if (distributed > rewardPool)
723 (onTransferFail == OnTransferFail::keepClaim ||
735 innerSb.apply(outerSb);
739 if (
auto const sleClaimID = outerSb.peek(claimIDKeylet))
741 auto const cidOwner = (*sleClaimID)[sfAccount];
745 auto const page = (*sleClaimID)[sfOwnerNode];
746 if (!outerSb.dirRemove(
750 <<
"Unable to delete xchain seq number from owner.";
756 outerSb.erase(sleClaimID);
775getSignersListAndQuorum(
776 ReadView
const& view,
777 SLE const& sleBridge,
783 AccountID const thisDoor = sleBridge[sfAccount];
784 auto const sleDoor = [&] {
return view.read(
keylet::account(thisDoor)); }();
796 q = (*sleS)[sfSignerQuorum];
805 for (
auto const& as : *accountSigners)
807 r[as.account] = as.weight;
813template <
class R,
class F>
815readOrpeekBridge(F&& getter, STXChainBridge
const& bridgeSpec)
818 if (
auto r = getter(bridgeSpec, ct))
820 if ((*r)[sfXChainBridge] == bridgeSpec)
831peekBridge(ApplyView& v, STXChainBridge
const& bridgeSpec)
833 return readOrpeekBridge<SLE>(
840readBridge(ReadView
const& v, STXChainBridge
const& bridgeSpec)
842 return readOrpeekBridge<SLE const>(
852template <
class TIter>
854applyClaimAttestations(
859 STXChainBridge
const& bridgeSpec,
865 if (attBegin == attEnd)
868 PaymentSandbox psb(&view);
870 auto const claimIDKeylet =
875 OnNewAttestationResult newAttResult;
876 STAmount rewardAmount;
880 auto const scopeResult = [&]() -> Expected<ScopeResult, TER> {
885 auto const sleClaimID = psb.peek(claimIDKeylet);
892 for (
auto att = attBegin; att != attEnd; ++att)
894 if (!signersList.
contains(att->attestationSignerAccount))
904 AccountID const otherChainSource = (*sleClaimID)[sfOtherChainSource];
905 if (attBegin->sendingAccount != otherChainSource)
917 if (attDstChain != dstChain)
923 XChainClaimAttestations curAtts{
924 sleClaimID->getFieldArray(sfXChainClaimAttestations)};
926 auto const newAttResult = onNewAttestations(
930 &atts[0] + atts.
size(),
936 sleClaimID->setFieldArray(
937 sfXChainClaimAttestations, curAtts.toSTArray());
938 psb.update(sleClaimID);
942 (*sleClaimID)[sfSignatureReward],
943 (*sleClaimID)[sfAccount]};
946 if (!scopeResult.has_value())
947 return scopeResult.error();
949 auto const& [newAttResult, rewardAmount, cidOwner] = scopeResult.value();
950 auto const& [rewardAccounts, attListChanged] = newAttResult;
951 if (rewardAccounts && attBegin->dst)
953 auto const r = finalizeClaimHelper(
959 attBegin->sendingAmount,
965 OnTransferFail::keepClaim,
966 DepositAuthPolicy::normal,
969 auto const rTer = r.ter();
981template <
class TIter>
983applyCreateAccountAttestations(
990 STXChainBridge
const& bridgeSpec,
991 Keylet
const& bridgeK,
997 if (attBegin == attEnd)
1000 PaymentSandbox psb(&view);
1002 auto const claimCountResult = [&]() -> Expected<std::uint64_t, TER> {
1003 auto const sleBridge = psb.peek(bridgeK);
1007 return (*sleBridge)[sfXChainAccountClaimCount];
1010 if (!claimCountResult.has_value())
1011 return claimCountResult.error();
1015 if (attBegin->createCount <= claimCount)
1032 if (attDstChain != dstChain)
1038 auto const claimIDKeylet =
1043 OnNewAttestationResult newAttResult;
1045 XChainCreateAccountAttestations curAtts;
1048 auto const scopeResult = [&]() -> Expected<ScopeResult, TER> {
1056 auto const sleClaimID = psb.peek(claimIDKeylet);
1057 bool createCID =
false;
1062 auto const sleDoor = psb.peek(doorK);
1067 auto const balance = (*sleDoor)[sfBalance];
1068 auto const reserve =
1069 psb.fees().accountReserve((*sleDoor)[sfOwnerCount] + 1);
1071 if (balance < reserve)
1077 for (
auto att = attBegin; att != attEnd; ++att)
1079 if (!signersList.
contains(att->attestationSignerAccount))
1088 XChainCreateAccountAttestations curAtts = [&] {
1090 return XChainCreateAccountAttestations{
1091 sleClaimID->getFieldArray(
1092 sfXChainCreateAccountAttestations)};
1093 return XChainCreateAccountAttestations{};
1096 auto const newAttResult = onNewAttestations(
1100 &atts[0] + atts.
size(),
1111 sleClaimID->setFieldArray(
1112 sfXChainCreateAccountAttestations, curAtts.toSTArray());
1113 psb.update(sleClaimID);
1115 return ScopeResult{newAttResult, createCID, curAtts};
1118 if (!scopeResult.has_value())
1119 return scopeResult.error();
1121 auto const& [attResult, createCID, curAtts] = scopeResult.value();
1122 auto const& [rewardAccounts, attListChanged] = attResult;
1125 if (rewardAccounts && claimCount + 1 == attBegin->createCount)
1127 auto const r = finalizeClaimHelper(
1133 attBegin->sendingAmount,
1135 attBegin->rewardAmount,
1139 OnTransferFail::removeClaim,
1140 DepositAuthPolicy::normal,
1143 auto const rTer = r.ter();
1153 auto const sleBridge = psb.peek(bridgeK);
1156 (*sleBridge)[sfXChainAccountClaimCount] = attBegin->createCount;
1157 psb.update(sleBridge);
1162 (*createdSleClaimID)[sfAccount] = doorAccount;
1163 (*createdSleClaimID)[sfXChainBridge] = bridgeSpec;
1164 (*createdSleClaimID)[sfXChainAccountCreateCount] =
1165 attBegin->createCount;
1166 createdSleClaimID->setFieldArray(
1167 sfXChainCreateAccountAttestations, curAtts.toSTArray());
1170 auto const page = psb.dirInsert(
1176 (*createdSleClaimID)[sfOwnerNode] = *
page;
1178 auto const sleDoor = psb.peek(doorK);
1184 psb.insert(createdSleClaimID);
1185 psb.update(sleDoor);
1193template <
class TAttestation>
1195toClaim(STTx
const& tx)
1204 o.setAccountID(sfAccount, o[sfOtherChainSource]);
1205 return TAttestation(o);
1213template <
class TAttestation>
1215attestationpreflight(PreflightContext
const& ctx)
1220 auto const att = toClaim<TAttestation>(ctx.tx);
1224 STXChainBridge
const bridgeSpec = ctx.tx[sfXChainBridge];
1225 if (!att->verify(bridgeSpec))
1227 if (!att->validAmounts())
1230 if (att->sendingAmount.signum() <= 0)
1232 auto const expectedIssue =
1234 if (att->sendingAmount.issue() != expectedIssue)
1240template <
class TAttestation>
1242attestationPreclaim(PreclaimContext
const& ctx)
1244 auto const att = toClaim<TAttestation>(ctx.tx);
1248 STXChainBridge
const bridgeSpec = ctx.tx[sfXChainBridge];
1249 auto const sleBridge = readBridge(ctx.view, bridgeSpec);
1255 AccountID const attestationSignerAccount{
1256 ctx.tx[sfAttestationSignerAccount]};
1257 PublicKey
const pk{ctx.tx[sfPublicKey]};
1260 auto const [signersList, quorum, slTer] =
1261 getSignersListAndQuorum(ctx.view, *sleBridge, ctx.j);
1266 return checkAttestationPublicKey(
1267 ctx.view, signersList, attestationSignerAccount, pk, ctx.j);
1270template <
class TAttestation>
1272attestationDoApply(ApplyContext& ctx)
1274 auto const att = toClaim<TAttestation>(ctx.tx);
1279 STXChainBridge
const bridgeSpec = ctx.tx[sfXChainBridge];
1283 STXChainBridge::ChainType srcChain;
1290 auto const scopeResult = [&]() -> Expected<ScopeResult, TER> {
1295 auto sleBridge = readBridge(ctx.view(), bridgeSpec);
1300 Keylet
const bridgeK{ltBRIDGE, sleBridge->key()};
1301 AccountID const thisDoor = (*sleBridge)[sfAccount];
1305 if (thisDoor == bridgeSpec.lockingChainDoor())
1307 else if (thisDoor == bridgeSpec.issuingChainDoor())
1316 auto [signersList, quorum, slTer] =
1317 getSignersListAndQuorum(ctx.view(), *sleBridge, ctx.journal);
1323 srcChain, std::move(signersList), quorum, thisDoor, bridgeK};
1326 if (!scopeResult.has_value())
1327 return scopeResult.error();
1329 auto const& [srcChain, signersList, quorum, thisDoor, bridgeK] =
1330 scopeResult.value();
1338 return applyClaimAttestations(
1351 Attestations::AttestationCreateAccount>)
1353 return applyCreateAccountAttestations(
1375 auto const account = ctx.
tx[sfAccount];
1376 auto const reward = ctx.
tx[sfSignatureReward];
1377 auto const minAccountCreate = ctx.
tx[~sfMinAccountCreateAmount];
1378 auto const bridgeSpec = ctx.
tx[sfXChainBridge];
1380 if (bridgeSpec.lockingChainDoor() == bridgeSpec.issuingChainDoor())
1385 if (bridgeSpec.lockingChainDoor() != account &&
1386 bridgeSpec.issuingChainDoor() != account)
1391 if (
isXRP(bridgeSpec.lockingChainIssue()) !=
1392 isXRP(bridgeSpec.issuingChainIssue()))
1399 if (!
isXRP(reward) || reward.signum() < 0)
1404 if (minAccountCreate &&
1405 ((!
isXRP(*minAccountCreate) || minAccountCreate->signum() <= 0) ||
1406 !
isXRP(bridgeSpec.lockingChainIssue()) ||
1407 !
isXRP(bridgeSpec.issuingChainIssue())))
1412 if (
isXRP(bridgeSpec.issuingChainIssue()))
1421 if (bridgeSpec.issuingChainDoor() != rootAccount)
1430 if (bridgeSpec.issuingChainDoor() !=
1431 bridgeSpec.issuingChainIssue().account)
1437 if (bridgeSpec.lockingChainDoor() == bridgeSpec.lockingChainIssue().account)
1450 auto const account = ctx.
tx[sfAccount];
1451 auto const bridgeSpec = ctx.
tx[sfXChainBridge];
1467 if (!
isXRP(bridgeSpec.issue(chainType)))
1469 auto const sleIssuer =
1487 auto const balance = (*sleAcc)[sfBalance];
1488 auto const reserve =
1491 if (balance < reserve)
1501 auto const account =
ctx_.
tx[sfAccount];
1502 auto const bridgeSpec =
ctx_.
tx[sfXChainBridge];
1503 auto const reward =
ctx_.
tx[sfSignatureReward];
1504 auto const minAccountCreate =
ctx_.
tx[~sfMinAccountCreateAmount];
1516 (*sleBridge)[sfAccount] = account;
1517 (*sleBridge)[sfSignatureReward] = reward;
1518 if (minAccountCreate)
1519 (*sleBridge)[sfMinAccountCreateAmount] = *minAccountCreate;
1520 (*sleBridge)[sfXChainBridge] = bridgeSpec;
1521 (*sleBridge)[sfXChainClaimID] = 0;
1522 (*sleBridge)[sfXChainAccountCreateCount] = 0;
1523 (*sleBridge)[sfXChainAccountClaimCount] = 0;
1531 (*sleBridge)[sfOwnerNode] = *page;
1553 auto const account = ctx.
tx[sfAccount];
1554 auto const reward = ctx.
tx[~sfSignatureReward];
1555 auto const minAccountCreate = ctx.
tx[~sfMinAccountCreateAmount];
1556 auto const bridgeSpec = ctx.
tx[sfXChainBridge];
1557 bool const clearAccountCreate =
1560 if (!reward && !minAccountCreate && !clearAccountCreate)
1566 if (minAccountCreate && clearAccountCreate)
1572 if (bridgeSpec.lockingChainDoor() != account &&
1573 bridgeSpec.issuingChainDoor() != account)
1578 if (reward && (!
isXRP(*reward) || reward->signum() < 0))
1583 if (minAccountCreate &&
1584 ((!
isXRP(*minAccountCreate) || minAccountCreate->signum() <= 0) ||
1585 !
isXRP(bridgeSpec.lockingChainIssue()) ||
1586 !
isXRP(bridgeSpec.issuingChainIssue())))
1597 auto const account = ctx.
tx[sfAccount];
1598 auto const bridgeSpec = ctx.
tx[sfXChainBridge];
1614 auto const account =
ctx_.
tx[sfAccount];
1615 auto const bridgeSpec =
ctx_.
tx[sfXChainBridge];
1616 auto const reward =
ctx_.
tx[~sfSignatureReward];
1617 auto const minAccountCreate =
ctx_.
tx[~sfMinAccountCreateAmount];
1618 bool const clearAccountCreate =
1628 auto const sleBridge =
1634 (*sleBridge)[sfSignatureReward] = *reward;
1635 if (minAccountCreate)
1637 (*sleBridge)[sfMinAccountCreateAmount] = *minAccountCreate;
1639 if (clearAccountCreate &&
1640 sleBridge->isFieldPresent(sfMinAccountCreateAmount))
1642 sleBridge->makeFieldAbsent(sfMinAccountCreateAmount);
1655 auto const amount = ctx.
tx[sfAmount];
1657 if (amount.signum() <= 0 ||
1672 STAmount const& thisChainAmount = ctx.
tx[sfAmount];
1673 auto const claimID = ctx.
tx[sfXChainClaimID];
1675 auto const sleBridge = readBridge(ctx.
view, bridgeSpec);
1686 auto const thisDoor = (*sleBridge)[sfAccount];
1687 bool isLockingChain =
false;
1690 isLockingChain =
true;
1692 isLockingChain =
false;
1721 auto const otherChainAmount = [&]() ->
STAmount {
1730 auto const sleClaimID =
1740 if ((*sleClaimID)[sfAccount] != account)
1757 auto const dst =
ctx_.
tx[sfDestination];
1760 auto const claimID =
ctx_.
tx[sfXChainClaimID];
1779 auto const sleBridge = peekBridge(psb, bridgeSpec);
1780 auto const sleClaimID = psb.
peek(claimIDKeylet);
1782 if (!(sleBridge && sleClaimID && sleAcct))
1785 AccountID const thisDoor = (*sleBridge)[sfAccount];
1799 auto const sendingAmount = [&]() ->
STAmount {
1805 auto const [signersList, quorum, slTer] =
1812 sleClaimID->getFieldArray(sfXChainClaimAttestations)};
1814 auto const claimR = onClaim(
1823 if (!claimR.has_value())
1828 (*sleClaimID)[sfAccount],
1831 (*sleClaimID)[sfSignatureReward],
1835 if (!scopeResult.has_value())
1836 return scopeResult.error();
1838 auto const& [rewardAccounts, rewardPoolSrc, sendingAmount, srcChain, signatureReward] =
1839 scopeResult.value();
1842 auto const r = finalizeClaimHelper(
1854 OnTransferFail::keepClaim,
1855 DepositAuthPolicy::dstCanBypass,
1857 if (!r.isTesSuccess())
1870 auto const maxSpend = [&] {
1871 auto const amount = ctx.
tx[sfAmount];
1872 if (amount.native() && amount.signum() > 0)
1873 return amount.xrp();
1883 auto const amount = ctx.
tx[sfAmount];
1884 auto const bridgeSpec = ctx.
tx[sfXChainBridge];
1886 if (amount.signum() <= 0 || !
isLegalNet(amount))
1889 if (amount.issue() != bridgeSpec.lockingChainIssue() &&
1890 amount.issue() != bridgeSpec.issuingChainIssue())
1899 auto const bridgeSpec = ctx.
tx[sfXChainBridge];
1900 auto const amount = ctx.
tx[sfAmount];
1902 auto const sleBridge = readBridge(ctx.
view, bridgeSpec);
1908 AccountID const thisDoor = (*sleBridge)[sfAccount];
1911 if (thisDoor == account)
1917 bool isLockingChain =
false;
1919 if (thisDoor == bridgeSpec.lockingChainDoor())
1920 isLockingChain =
true;
1921 else if (thisDoor == bridgeSpec.issuingChainDoor())
1922 isLockingChain =
false;
1929 if (bridgeSpec.lockingChainIssue() != ctx.
tx[sfAmount].issue())
1934 if (bridgeSpec.issuingChainIssue() != ctx.
tx[sfAmount].issue())
1946 auto const account =
ctx_.
tx[sfAccount];
1947 auto const amount =
ctx_.
tx[sfAmount];
1948 auto const bridgeSpec =
ctx_.
tx[sfXChainBridge];
1953 auto const sleBridge = readBridge(psb, bridgeSpec);
1957 auto const dst = (*sleBridge)[sfAccount];
1960 TransferHelperSubmittingAccountInfo submittingAccountInfo{
1963 auto const thTer = transferHelper(
1970 CanCreateDstPolicy::no,
1971 DepositAuthPolicy::normal,
1972 submittingAccountInfo,
1988 auto const reward = ctx.
tx[sfSignatureReward];
1999 auto const account = ctx.
tx[sfAccount];
2000 auto const bridgeSpec = ctx.
tx[sfXChainBridge];
2001 auto const sleBridge = readBridge(ctx.
view, bridgeSpec);
2009 auto const reward = ctx.
tx[sfSignatureReward];
2011 if (reward != (*sleBridge)[sfSignatureReward])
2022 auto const balance = (*sleAcc)[sfBalance];
2023 auto const reserve =
2026 if (balance < reserve)
2036 auto const account =
ctx_.
tx[sfAccount];
2037 auto const bridgeSpec =
ctx_.
tx[sfXChainBridge];
2038 auto const reward =
ctx_.
tx[sfSignatureReward];
2039 auto const otherChainSrc =
ctx_.
tx[sfOtherChainSource];
2045 auto const sleBridge = peekBridge(
ctx_.
view(), bridgeSpec);
2049 std::uint32_t const claimID = (*sleBridge)[sfXChainClaimID] + 1;
2053 (*sleBridge)[sfXChainClaimID] = claimID;
2061 (*sleClaimID)[sfAccount] = account;
2062 (*sleClaimID)[sfXChainBridge] = bridgeSpec;
2063 (*sleClaimID)[sfXChainClaimID] = claimID;
2064 (*sleClaimID)[sfOtherChainSource] = otherChainSrc;
2065 (*sleClaimID)[sfSignatureReward] = reward;
2066 sleClaimID->setFieldArray(
2067 sfXChainClaimAttestations,
STArray{sfXChainClaimAttestations});
2077 (*sleClaimID)[sfOwnerNode] = *page;
2094 return attestationpreflight<Attestations::AttestationClaim>(ctx);
2100 return attestationPreclaim<Attestations::AttestationClaim>(ctx);
2106 return attestationDoApply<Attestations::AttestationClaim>(
ctx_);
2114 return attestationpreflight<Attestations::AttestationCreateAccount>(ctx);
2120 return attestationPreclaim<Attestations::AttestationCreateAccount>(ctx);
2126 return attestationDoApply<Attestations::AttestationCreateAccount>(
ctx_);
2134 auto const amount = ctx.
tx[sfAmount];
2136 if (amount.signum() <= 0 || !amount.native())
2139 auto const reward = ctx.
tx[sfSignatureReward];
2140 if (reward.signum() < 0 || !reward.native())
2143 if (reward.issue() != amount.issue())
2154 STAmount const reward = ctx.
tx[sfSignatureReward];
2156 auto const sleBridge = readBridge(ctx.
view, bridgeSpec);
2162 if (reward != (*sleBridge)[sfSignatureReward])
2168 (*sleBridge)[~sfMinAccountCreateAmount];
2170 if (!minCreateAmount)
2173 if (amount < *minCreateAmount)
2176 if (minCreateAmount->issue() != amount.
issue())
2179 AccountID const thisDoor = (*sleBridge)[sfAccount];
2181 if (thisDoor == account)
2199 if (bridgeSpec.
issue(srcChain) != ctx.
tx[sfAmount].issue())
2222 auto const sleBridge = peekBridge(psb, bridge);
2226 auto const dst = (*sleBridge)[sfAccount];
2229 TransferHelperSubmittingAccountInfo submittingAccountInfo{
2231 STAmount const toTransfer = amount + reward;
2232 auto const thTer = transferHelper(
2239 CanCreateDstPolicy::yes,
2240 DepositAuthPolicy::normal,
2241 submittingAccountInfo,
2247 (*sleBridge)[sfXChainAccountCreateCount] =
2248 (*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.