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>
24#include <xrpld/ledger/ApplyView.h>
25#include <xrpld/ledger/PaymentSandbox.h>
26#include <xrpld/ledger/View.h>
27#include <xrpl/basics/Log.h>
28#include <xrpl/basics/Number.h>
29#include <xrpl/basics/chrono.h>
30#include <xrpl/beast/utility/Journal.h>
31#include <xrpl/beast/utility/instrumentation.h>
32#include <xrpl/protocol/AccountID.h>
33#include <xrpl/protocol/Feature.h>
34#include <xrpl/protocol/Indexes.h>
35#include <xrpl/protocol/PublicKey.h>
36#include <xrpl/protocol/SField.h>
37#include <xrpl/protocol/STAmount.h>
38#include <xrpl/protocol/STObject.h>
39#include <xrpl/protocol/STXChainBridge.h>
40#include <xrpl/protocol/TER.h>
41#include <xrpl/protocol/TxFlags.h>
42#include <xrpl/protocol/XChainAttestations.h>
43#include <xrpl/protocol/XRPAmount.h>
110checkAttestationPublicKey(
111 ReadView
const& view,
113 AccountID const& attestationSignerAccount,
117 if (!signersList.
contains(attestationSignerAccount))
124 if (
auto const sleAttestationSigningAccount =
127 if (accountFromPK == attestationSignerAccount)
130 if (sleAttestationSigningAccount->getFieldU32(sfFlags) &
133 JLOG(j.
trace()) <<
"Attempt to add an attestation with "
134 "disabled master key.";
142 (*sleAttestationSigningAccount)[~sfRegularKey];
143 regularKey != accountFromPK)
148 <<
"Attempt to add an attestation with "
149 "account present and non-present regular key.";
153 JLOG(j.
trace()) <<
"Attempt to add an attestation with "
154 "account present and mismatched "
155 "regular key/public key.";
167 <<
"Attempt to add an attestation with non-existant account "
168 "and mismatched pk/account pair.";
187enum class CheckDst {
check, ignore };
188template <
class TAttestation>
189Expected<std::vector<AccountID>,
TER>
191 XChainAttestationsBase<TAttestation>& attestations,
192 ReadView
const& view,
193 typename TAttestation::MatchFields
const& toMatch,
202 attestations.erase_if([&](
auto const& a) {
203 return checkAttestationPublicKey(
204 view, signersList, a.keyAccount, a.publicKey, j) !=
210 rewardAccounts.reserve(attestations.size());
212 for (
auto const& a : attestations)
214 auto const matchR = a.match(toMatch);
220 (checkDst == CheckDst::check && matchR !=
match))
222 auto i = signersList.
find(a.keyAccount);
223 if (i == signersList.
end())
226 "ripple::claimHelper : invalid inputs");
231 rewardAccounts.push_back(a.rewardAccount);
234 if (weight >= quorum)
235 return rewardAccounts;
271struct OnNewAttestationResult
279template <
class TAttestation>
280[[nodiscard]] OnNewAttestationResult
282 XChainAttestationsBase<TAttestation>& attestations,
283 ReadView
const& view,
284 typename TAttestation::TSignedAttestation
const* attBegin,
285 typename TAttestation::TSignedAttestation
const* attEnd,
290 bool changed =
false;
291 for (
auto att = attBegin; att != attEnd; ++att)
293 if (checkAttestationPublicKey(
296 att->attestationSignerAccount,
307 auto const& claimSigningAccount = att->attestationSignerAccount;
309 attestations.begin(),
312 return a.keyAccount == claimSigningAccount;
314 i != attestations.end())
318 *i = TAttestation{*att};
323 attestations.emplace_back(*att);
328 auto r = claimHelper(
331 typename TAttestation::MatchFields{*attBegin},
338 return {std::nullopt, changed};
340 return {std::move(r.value()), changed};
346Expected<std::vector<AccountID>,
TER>
348 XChainClaimAttestations& attestations,
349 ReadView
const& view,
350 STAmount
const& sendingAmount,
351 bool wasLockingChainSend,
356 XChainClaimAttestation::MatchFields toMatch{
357 sendingAmount, wasLockingChainSend, std::nullopt};
359 attestations, view, toMatch, CheckDst::ignore, quorum, signersList, j);
362enum class CanCreateDstPolicy {
no,
yes };
364enum class DepositAuthPolicy { normal, dstCanBypass };
368struct TransferHelperSubmittingAccountInfo
371 STAmount preFeeBalance;
372 STAmount postFeeBalance;
405 CanCreateDstPolicy canCreate,
406 DepositAuthPolicy depositAuthPolicy,
408 submittingAccountInfo,
415 if (
auto sleDst = psb.read(dstK))
425 bool const canBypassDepositAuth = dst == claimOwner &&
426 depositAuthPolicy == DepositAuthPolicy::dstCanBypass;
428 if (!canBypassDepositAuth && (sleDst->getFlags() &
lsfDepositAuth) &&
434 else if (!amt.native() || canCreate == CanCreateDstPolicy::no)
442 XRPL_ASSERT(sleSrc,
"ripple::transferHelper : non-null source account");
447 auto const ownerCount = sleSrc->getFieldU32(sfOwnerCount);
448 auto const reserve = psb.fees().accountReserve(ownerCount);
450 auto const availableBalance = [&]() -> STAmount {
451 STAmount
const curBal = (*sleSrc)[sfBalance];
455 if (!submittingAccountInfo ||
456 submittingAccountInfo->account != src ||
457 submittingAccountInfo->postFeeBalance != curBal)
459 return submittingAccountInfo->preFeeBalance;
462 if (availableBalance < amt + reserve)
468 auto sleDst = psb.peek(dstK);
471 if (canCreate == CanCreateDstPolicy::no)
476 if (amt < psb.fees().accountReserve(0))
478 JLOG(j.
trace()) <<
"Insufficient payment to create account.";
484 psb.rules().enabled(featureDeletableAccounts) ? psb.seq() : 1};
486 sleDst = std::make_shared<SLE>(dstK);
487 sleDst->setAccountID(sfAccount, dst);
488 sleDst->setFieldU32(sfSequence, seqno);
493 (*sleSrc)[sfBalance] = (*sleSrc)[sfBalance] - amt;
494 (*sleDst)[sfBalance] = (*sleDst)[sfBalance] + amt;
501 auto const result =
flow(
515 if (
auto const r = result.result();
526enum class OnTransferFail {
533struct FinalizeClaimHelperResult
554 if ((!mainFundsTer || *mainFundsTer ==
tesSUCCESS) &&
563 return *mainFundsTer;
572 if (mainFundsTer && mainFundsTer !=
tesSUCCESS)
573 return *mainFundsTer;
610FinalizeClaimHelperResult
612 PaymentSandbox& outerSb,
613 STXChainBridge
const& bridgeSpec,
617 STAmount
const& sendingAmount,
619 STAmount
const& rewardPool,
622 Keylet
const& claimIDKeylet,
623 OnTransferFail onTransferFail,
624 DepositAuthPolicy depositAuthPolicy,
627 FinalizeClaimHelperResult result;
631 STAmount
const thisChainAmount = [&] {
632 STAmount r = sendingAmount;
633 r.setIssue(bridgeSpec.issue(dstChain));
636 auto const& thisDoor = bridgeSpec.door(dstChain);
639 PaymentSandbox innerSb{&outerSb};
650 result.mainFundsTer = transferHelper(
657 CanCreateDstPolicy::yes,
663 onTransferFail == OnTransferFail::keepClaim)
669 result.rewardTer = [&]() ->
TER {
670 if (rewardAccounts.empty())
676 STAmount
const share = [&] {
677 auto const round_mode =
678 innerSb.rules().enabled(fixXChainRewardRounding)
683 STAmount
const den{rewardAccounts.size()};
684 return divide(rewardPool, den, rewardPool.issue());
686 STAmount distributed = rewardPool.zeroed();
687 for (
auto const& rewardAccount : rewardAccounts)
689 auto const thTer = transferHelper(
697 CanCreateDstPolicy::no,
698 DepositAuthPolicy::normal,
706 distributed += share;
712 if (distributed > rewardPool)
719 (onTransferFail == OnTransferFail::keepClaim ||
731 innerSb.apply(outerSb);
735 if (
auto const sleClaimID = outerSb.peek(claimIDKeylet))
737 auto const cidOwner = (*sleClaimID)[sfAccount];
741 auto const page = (*sleClaimID)[sfOwnerNode];
742 if (!outerSb.dirRemove(
746 <<
"Unable to delete xchain seq number from owner.";
752 outerSb.erase(sleClaimID);
771getSignersListAndQuorum(
772 ReadView
const& view,
773 SLE const& sleBridge,
779 AccountID const thisDoor = sleBridge[sfAccount];
780 auto const sleDoor = [&] {
return view.read(
keylet::account(thisDoor)); }();
792 q = (*sleS)[sfSignerQuorum];
801 for (
auto const& as : *accountSigners)
803 r[as.account] = as.weight;
809template <
class R,
class F>
811readOrpeekBridge(F&& getter, STXChainBridge
const& bridgeSpec)
814 if (
auto r = getter(bridgeSpec, ct))
816 if ((*r)[sfXChainBridge] == bridgeSpec)
827peekBridge(ApplyView& v, STXChainBridge
const& bridgeSpec)
829 return readOrpeekBridge<SLE>(
836readBridge(ReadView
const& v, STXChainBridge
const& bridgeSpec)
838 return readOrpeekBridge<SLE const>(
848template <
class TIter>
850applyClaimAttestations(
855 STXChainBridge
const& bridgeSpec,
861 if (attBegin == attEnd)
864 PaymentSandbox psb(&view);
866 auto const claimIDKeylet =
871 OnNewAttestationResult newAttResult;
872 STAmount rewardAmount;
876 auto const scopeResult = [&]() -> Expected<ScopeResult, TER> {
881 auto const sleClaimID = psb.peek(claimIDKeylet);
888 for (
auto att = attBegin; att != attEnd; ++att)
890 if (!signersList.
contains(att->attestationSignerAccount))
900 AccountID const otherChainSource = (*sleClaimID)[sfOtherChainSource];
901 if (attBegin->sendingAccount != otherChainSource)
913 if (attDstChain != dstChain)
919 XChainClaimAttestations curAtts{
920 sleClaimID->getFieldArray(sfXChainClaimAttestations)};
922 auto const newAttResult = onNewAttestations(
926 &atts[0] + atts.
size(),
932 sleClaimID->setFieldArray(
933 sfXChainClaimAttestations, curAtts.toSTArray());
934 psb.update(sleClaimID);
938 (*sleClaimID)[sfSignatureReward],
939 (*sleClaimID)[sfAccount]};
942 if (!scopeResult.has_value())
943 return scopeResult.error();
945 auto const& [newAttResult, rewardAmount, cidOwner] = scopeResult.value();
946 auto const& [rewardAccounts, attListChanged] = newAttResult;
947 if (rewardAccounts && attBegin->dst)
949 auto const r = finalizeClaimHelper(
955 attBegin->sendingAmount,
961 OnTransferFail::keepClaim,
962 DepositAuthPolicy::normal,
965 auto const rTer = r.ter();
977template <
class TIter>
979applyCreateAccountAttestations(
986 STXChainBridge
const& bridgeSpec,
987 Keylet
const& bridgeK,
993 if (attBegin == attEnd)
996 PaymentSandbox psb(&view);
998 auto const claimCountResult = [&]() -> Expected<std::uint64_t, TER> {
999 auto const sleBridge = psb.peek(bridgeK);
1003 return (*sleBridge)[sfXChainAccountClaimCount];
1006 if (!claimCountResult.has_value())
1007 return claimCountResult.error();
1011 if (attBegin->createCount <= claimCount)
1028 if (attDstChain != dstChain)
1034 auto const claimIDKeylet =
1039 OnNewAttestationResult newAttResult;
1041 XChainCreateAccountAttestations curAtts;
1044 auto const scopeResult = [&]() -> Expected<ScopeResult, TER> {
1052 auto const sleClaimID = psb.peek(claimIDKeylet);
1053 bool createCID =
false;
1058 auto const sleDoor = psb.peek(doorK);
1063 auto const balance = (*sleDoor)[sfBalance];
1064 auto const reserve =
1065 psb.fees().accountReserve((*sleDoor)[sfOwnerCount] + 1);
1067 if (balance < reserve)
1073 for (
auto att = attBegin; att != attEnd; ++att)
1075 if (!signersList.
contains(att->attestationSignerAccount))
1084 XChainCreateAccountAttestations curAtts = [&] {
1086 return XChainCreateAccountAttestations{
1087 sleClaimID->getFieldArray(
1088 sfXChainCreateAccountAttestations)};
1089 return XChainCreateAccountAttestations{};
1092 auto const newAttResult = onNewAttestations(
1096 &atts[0] + atts.
size(),
1107 sleClaimID->setFieldArray(
1108 sfXChainCreateAccountAttestations, curAtts.toSTArray());
1109 psb.update(sleClaimID);
1111 return ScopeResult{newAttResult, createCID, curAtts};
1114 if (!scopeResult.has_value())
1115 return scopeResult.error();
1117 auto const& [attResult, createCID, curAtts] = scopeResult.value();
1118 auto const& [rewardAccounts, attListChanged] = attResult;
1121 if (rewardAccounts && claimCount + 1 == attBegin->createCount)
1123 auto const r = finalizeClaimHelper(
1129 attBegin->sendingAmount,
1131 attBegin->rewardAmount,
1135 OnTransferFail::removeClaim,
1136 DepositAuthPolicy::normal,
1139 auto const rTer = r.ter();
1149 auto const sleBridge = psb.peek(bridgeK);
1152 (*sleBridge)[sfXChainAccountClaimCount] = attBegin->createCount;
1153 psb.update(sleBridge);
1157 auto const createdSleClaimID = std::make_shared<SLE>(claimIDKeylet);
1158 (*createdSleClaimID)[sfAccount] = doorAccount;
1159 (*createdSleClaimID)[sfXChainBridge] = bridgeSpec;
1160 (*createdSleClaimID)[sfXChainAccountCreateCount] =
1161 attBegin->createCount;
1162 createdSleClaimID->setFieldArray(
1163 sfXChainCreateAccountAttestations, curAtts.toSTArray());
1166 auto const page = psb.dirInsert(
1172 (*createdSleClaimID)[sfOwnerNode] = *
page;
1174 auto const sleDoor = psb.peek(doorK);
1180 psb.insert(createdSleClaimID);
1181 psb.update(sleDoor);
1189template <
class TAttestation>
1191toClaim(STTx
const& tx)
1194 std::is_same_v<TAttestation, Attestations::AttestationClaim> ||
1195 std::is_same_v<TAttestation, Attestations::AttestationCreateAccount>);
1200 o.setAccountID(sfAccount, o[sfOtherChainSource]);
1201 return TAttestation(o);
1206 return std::nullopt;
1209template <
class TAttestation>
1211attestationPreflight(PreflightContext
const& ctx)
1213 if (!ctx.rules.enabled(featureXChainBridge))
1225 auto const att = toClaim<TAttestation>(ctx.tx);
1229 STXChainBridge
const bridgeSpec = ctx.tx[sfXChainBridge];
1230 if (!att->verify(bridgeSpec))
1232 if (!att->validAmounts())
1235 if (att->sendingAmount.signum() <= 0)
1237 auto const expectedIssue =
1239 if (att->sendingAmount.issue() != expectedIssue)
1245template <
class TAttestation>
1247attestationPreclaim(PreclaimContext
const& ctx)
1249 auto const att = toClaim<TAttestation>(ctx.tx);
1253 STXChainBridge
const bridgeSpec = ctx.tx[sfXChainBridge];
1254 auto const sleBridge = readBridge(ctx.view, bridgeSpec);
1260 AccountID const attestationSignerAccount{
1261 ctx.tx[sfAttestationSignerAccount]};
1262 PublicKey
const pk{ctx.tx[sfPublicKey]};
1265 auto const [signersList, quorum, slTer] =
1266 getSignersListAndQuorum(ctx.view, *sleBridge, ctx.j);
1271 return checkAttestationPublicKey(
1272 ctx.view, signersList, attestationSignerAccount, pk, ctx.j);
1275template <
class TAttestation>
1277attestationDoApply(ApplyContext& ctx)
1279 auto const att = toClaim<TAttestation>(ctx.tx);
1284 STXChainBridge
const bridgeSpec = ctx.tx[sfXChainBridge];
1288 STXChainBridge::ChainType srcChain;
1295 auto const scopeResult = [&]() -> Expected<ScopeResult, TER> {
1300 auto sleBridge = readBridge(ctx.view(), bridgeSpec);
1305 Keylet
const bridgeK{ltBRIDGE, sleBridge->key()};
1306 AccountID const thisDoor = (*sleBridge)[sfAccount];
1310 if (thisDoor == bridgeSpec.lockingChainDoor())
1312 else if (thisDoor == bridgeSpec.issuingChainDoor())
1321 auto [signersList, quorum, slTer] =
1322 getSignersListAndQuorum(ctx.view(), *sleBridge, ctx.journal);
1328 srcChain, std::move(signersList), quorum, thisDoor, bridgeK};
1331 if (!scopeResult.has_value())
1332 return scopeResult.error();
1334 auto const& [srcChain, signersList, quorum, thisDoor, bridgeK] =
1335 scopeResult.value();
1338 std::is_same_v<TAttestation, Attestations::AttestationClaim> ||
1339 std::is_same_v<TAttestation, Attestations::AttestationCreateAccount>);
1341 if constexpr (std::is_same_v<TAttestation, Attestations::AttestationClaim>)
1343 return applyClaimAttestations(
1356 Attestations::AttestationCreateAccount>)
1358 return applyCreateAccountAttestations(
1389 auto const account = ctx.
tx[sfAccount];
1390 auto const reward = ctx.
tx[sfSignatureReward];
1391 auto const minAccountCreate = ctx.
tx[~sfMinAccountCreateAmount];
1392 auto const bridgeSpec = ctx.
tx[sfXChainBridge];
1394 if (bridgeSpec.lockingChainDoor() == bridgeSpec.issuingChainDoor())
1399 if (bridgeSpec.lockingChainDoor() != account &&
1400 bridgeSpec.issuingChainDoor() != account)
1405 if (
isXRP(bridgeSpec.lockingChainIssue()) !=
1406 isXRP(bridgeSpec.issuingChainIssue()))
1413 if (!
isXRP(reward) || reward.signum() < 0)
1418 if (minAccountCreate &&
1419 ((!
isXRP(*minAccountCreate) || minAccountCreate->signum() <= 0) ||
1420 !
isXRP(bridgeSpec.lockingChainIssue()) ||
1421 !
isXRP(bridgeSpec.issuingChainIssue())))
1426 if (
isXRP(bridgeSpec.issuingChainIssue()))
1435 if (bridgeSpec.issuingChainDoor() != rootAccount)
1444 if (bridgeSpec.issuingChainDoor() !=
1445 bridgeSpec.issuingChainIssue().account)
1451 if (bridgeSpec.lockingChainDoor() == bridgeSpec.lockingChainIssue().account)
1464 auto const account = ctx.
tx[sfAccount];
1465 auto const bridgeSpec = ctx.
tx[sfXChainBridge];
1481 if (!
isXRP(bridgeSpec.issue(chainType)))
1483 auto const sleIssuer =
1501 auto const balance = (*sleAcc)[sfBalance];
1502 auto const reserve =
1505 if (balance < reserve)
1515 auto const account =
ctx_.
tx[sfAccount];
1516 auto const bridgeSpec =
ctx_.
tx[sfXChainBridge];
1517 auto const reward =
ctx_.
tx[sfSignatureReward];
1518 auto const minAccountCreate =
ctx_.
tx[~sfMinAccountCreateAmount];
1528 auto const sleBridge = std::make_shared<SLE>(bridgeKeylet);
1530 (*sleBridge)[sfAccount] = account;
1531 (*sleBridge)[sfSignatureReward] = reward;
1532 if (minAccountCreate)
1533 (*sleBridge)[sfMinAccountCreateAmount] = *minAccountCreate;
1534 (*sleBridge)[sfXChainBridge] = bridgeSpec;
1535 (*sleBridge)[sfXChainClaimID] = 0;
1536 (*sleBridge)[sfXChainAccountCreateCount] = 0;
1537 (*sleBridge)[sfXChainAccountClaimCount] = 0;
1545 (*sleBridge)[sfOwnerNode] = *page;
1570 auto const account = ctx.
tx[sfAccount];
1571 auto const reward = ctx.
tx[~sfSignatureReward];
1572 auto const minAccountCreate = ctx.
tx[~sfMinAccountCreateAmount];
1573 auto const bridgeSpec = ctx.
tx[sfXChainBridge];
1574 bool const clearAccountCreate =
1577 if (!reward && !minAccountCreate && !clearAccountCreate)
1583 if (minAccountCreate && clearAccountCreate)
1589 if (bridgeSpec.lockingChainDoor() != account &&
1590 bridgeSpec.issuingChainDoor() != account)
1595 if (reward && (!
isXRP(*reward) || reward->signum() < 0))
1600 if (minAccountCreate &&
1601 ((!
isXRP(*minAccountCreate) || minAccountCreate->signum() <= 0) ||
1602 !
isXRP(bridgeSpec.lockingChainIssue()) ||
1603 !
isXRP(bridgeSpec.issuingChainIssue())))
1614 auto const account = ctx.
tx[sfAccount];
1615 auto const bridgeSpec = ctx.
tx[sfXChainBridge];
1631 auto const account =
ctx_.
tx[sfAccount];
1632 auto const bridgeSpec =
ctx_.
tx[sfXChainBridge];
1633 auto const reward =
ctx_.
tx[~sfSignatureReward];
1634 auto const minAccountCreate =
ctx_.
tx[~sfMinAccountCreateAmount];
1635 bool const clearAccountCreate =
1645 auto const sleBridge =
1651 (*sleBridge)[sfSignatureReward] = *reward;
1652 if (minAccountCreate)
1654 (*sleBridge)[sfMinAccountCreateAmount] = *minAccountCreate;
1656 if (clearAccountCreate &&
1657 sleBridge->isFieldPresent(sfMinAccountCreateAmount))
1659 sleBridge->makeFieldAbsent(sfMinAccountCreateAmount);
1681 auto const amount = ctx.
tx[sfAmount];
1683 if (amount.signum() <= 0 ||
1698 STAmount const& thisChainAmount = ctx.
tx[sfAmount];
1699 auto const claimID = ctx.
tx[sfXChainClaimID];
1701 auto const sleBridge = readBridge(ctx.
view, bridgeSpec);
1712 auto const thisDoor = (*sleBridge)[sfAccount];
1713 bool isLockingChain =
false;
1716 isLockingChain =
true;
1718 isLockingChain =
false;
1747 auto const otherChainAmount = [&]() ->
STAmount {
1756 auto const sleClaimID =
1766 if ((*sleClaimID)[sfAccount] != account)
1783 auto const dst =
ctx_.
tx[sfDestination];
1786 auto const claimID =
ctx_.
tx[sfXChainClaimID];
1805 auto const sleBridge = peekBridge(psb, bridgeSpec);
1806 auto const sleClaimID = psb.
peek(claimIDKeylet);
1808 if (!(sleBridge && sleClaimID && sleAcct))
1811 AccountID const thisDoor = (*sleBridge)[sfAccount];
1825 auto const sendingAmount = [&]() ->
STAmount {
1831 auto const [signersList, quorum, slTer] =
1838 sleClaimID->getFieldArray(sfXChainClaimAttestations)};
1840 auto const claimR = onClaim(
1849 if (!claimR.has_value())
1854 (*sleClaimID)[sfAccount],
1857 (*sleClaimID)[sfSignatureReward],
1861 if (!scopeResult.has_value())
1862 return scopeResult.error();
1864 auto const& [rewardAccounts, rewardPoolSrc, sendingAmount, srcChain, signatureReward] =
1865 scopeResult.value();
1868 auto const r = finalizeClaimHelper(
1880 OnTransferFail::keepClaim,
1881 DepositAuthPolicy::dstCanBypass,
1883 if (!r.isTesSuccess())
1896 auto const maxSpend = [&] {
1897 auto const amount = ctx.
tx[sfAmount];
1898 if (amount.native() && amount.signum() > 0)
1899 return amount.xrp();
1918 auto const amount = ctx.
tx[sfAmount];
1919 auto const bridgeSpec = ctx.
tx[sfXChainBridge];
1921 if (amount.signum() <= 0 || !
isLegalNet(amount))
1924 if (amount.issue() != bridgeSpec.lockingChainIssue() &&
1925 amount.issue() != bridgeSpec.issuingChainIssue())
1934 auto const bridgeSpec = ctx.
tx[sfXChainBridge];
1935 auto const amount = ctx.
tx[sfAmount];
1937 auto const sleBridge = readBridge(ctx.
view, bridgeSpec);
1943 AccountID const thisDoor = (*sleBridge)[sfAccount];
1946 if (thisDoor == account)
1952 bool isLockingChain =
false;
1954 if (thisDoor == bridgeSpec.lockingChainDoor())
1955 isLockingChain =
true;
1956 else if (thisDoor == bridgeSpec.issuingChainDoor())
1957 isLockingChain =
false;
1964 if (bridgeSpec.lockingChainIssue() != ctx.
tx[sfAmount].issue())
1969 if (bridgeSpec.issuingChainIssue() != ctx.
tx[sfAmount].issue())
1981 auto const account =
ctx_.
tx[sfAccount];
1982 auto const amount =
ctx_.
tx[sfAmount];
1983 auto const bridgeSpec =
ctx_.
tx[sfXChainBridge];
1988 auto const sleBridge = readBridge(psb, bridgeSpec);
1992 auto const dst = (*sleBridge)[sfAccount];
1995 TransferHelperSubmittingAccountInfo submittingAccountInfo{
1998 auto const thTer = transferHelper(
2005 CanCreateDstPolicy::no,
2006 DepositAuthPolicy::normal,
2007 submittingAccountInfo,
2032 auto const reward = ctx.
tx[sfSignatureReward];
2043 auto const account = ctx.
tx[sfAccount];
2044 auto const bridgeSpec = ctx.
tx[sfXChainBridge];
2045 auto const sleBridge = readBridge(ctx.
view, bridgeSpec);
2053 auto const reward = ctx.
tx[sfSignatureReward];
2055 if (reward != (*sleBridge)[sfSignatureReward])
2066 auto const balance = (*sleAcc)[sfBalance];
2067 auto const reserve =
2070 if (balance < reserve)
2080 auto const account =
ctx_.
tx[sfAccount];
2081 auto const bridgeSpec =
ctx_.
tx[sfXChainBridge];
2082 auto const reward =
ctx_.
tx[sfSignatureReward];
2083 auto const otherChainSrc =
ctx_.
tx[sfOtherChainSource];
2089 auto const sleBridge = peekBridge(
ctx_.
view(), bridgeSpec);
2093 std::uint32_t const claimID = (*sleBridge)[sfXChainClaimID] + 1;
2097 (*sleBridge)[sfXChainClaimID] = claimID;
2103 auto const sleClaimID = std::make_shared<SLE>(claimIDKeylet);
2105 (*sleClaimID)[sfAccount] = account;
2106 (*sleClaimID)[sfXChainBridge] = bridgeSpec;
2107 (*sleClaimID)[sfXChainClaimID] = claimID;
2108 (*sleClaimID)[sfOtherChainSource] = otherChainSrc;
2109 (*sleClaimID)[sfSignatureReward] = reward;
2110 sleClaimID->setFieldArray(
2111 sfXChainClaimAttestations,
STArray{sfXChainClaimAttestations});
2121 (*sleClaimID)[sfOwnerNode] = *page;
2138 return attestationPreflight<Attestations::AttestationClaim>(ctx);
2144 return attestationPreclaim<Attestations::AttestationClaim>(ctx);
2150 return attestationDoApply<Attestations::AttestationClaim>(
ctx_);
2158 return attestationPreflight<Attestations::AttestationCreateAccount>(ctx);
2164 return attestationPreclaim<Attestations::AttestationCreateAccount>(ctx);
2170 return attestationDoApply<Attestations::AttestationCreateAccount>(
ctx_);
2187 auto const amount = ctx.
tx[sfAmount];
2189 if (amount.signum() <= 0 || !amount.native())
2192 auto const reward = ctx.
tx[sfSignatureReward];
2193 if (reward.signum() < 0 || !reward.native())
2196 if (reward.issue() != amount.issue())
2207 STAmount const reward = ctx.
tx[sfSignatureReward];
2209 auto const sleBridge = readBridge(ctx.
view, bridgeSpec);
2215 if (reward != (*sleBridge)[sfSignatureReward])
2221 (*sleBridge)[~sfMinAccountCreateAmount];
2223 if (!minCreateAmount)
2226 if (amount < *minCreateAmount)
2229 if (minCreateAmount->issue() != amount.
issue())
2232 AccountID const thisDoor = (*sleBridge)[sfAccount];
2234 if (thisDoor == account)
2252 if (bridgeSpec.
issue(srcChain) != ctx.
tx[sfAmount].issue())
2275 auto const sleBridge = peekBridge(psb, bridge);
2279 auto const dst = (*sleBridge)[sfAccount];
2282 TransferHelperSubmittingAccountInfo submittingAccountInfo{
2284 STAmount const toTransfer = amount + reward;
2285 auto const thTer = transferHelper(
2292 CanCreateDstPolicy::yes,
2293 DepositAuthPolicy::normal,
2294 submittingAccountInfo,
2300 (*sleBridge)[sfXChainAccountCreateCount] =
2301 (*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 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.
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
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
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
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)
std::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
static bool adjustOwnerCount(ApplyContext &ctx, int count)
NotTEC preflight2(PreflightContext const &ctx)
Checks whether the signature appears valid.
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
constexpr std::uint32_t tfUniversalMask
Unexpected(E(&)[N]) -> Unexpected< E const * >
Seed generateSeed(std::string const &passPhrase)
Generate a seed deterministically.
TERSubset< CanCvtToTER > TER
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.