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 = view.read(
keylet::account(attestationSignerAccount)))
108 if (accountFromPK == attestationSignerAccount)
113 JLOG(j.
trace()) <<
"Attempt to add an attestation with "
114 "disabled master key.";
122 regularKey != accountFromPK)
126 JLOG(j.
trace()) <<
"Attempt to add an attestation with "
127 "account present and non-present regular key.";
131 JLOG(j.
trace()) <<
"Attempt to add an attestation with "
132 "account present and mismatched "
133 "regular key/public key.";
144 JLOG(j.
trace()) <<
"Attempt to add an attestation with non-existant account "
145 "and mismatched pk/account pair.";
164enum class CheckDst {
check, ignore };
165template <
class TAttestation>
166Expected<std::vector<AccountID>,
TER>
168 XChainAttestationsBase<TAttestation>& attestations,
169 ReadView
const& view,
170 typename TAttestation::MatchFields
const& toMatch,
179 attestations.erase_if([&](
auto const& a) {
180 return checkAttestationPublicKey(view, signersList, a.keyAccount, a.publicKey, j) !=
tesSUCCESS;
185 rewardAccounts.
reserve(attestations.size());
187 for (
auto const& a : attestations)
189 auto const matchR = a.match(toMatch);
196 auto i = signersList.
find(a.keyAccount);
197 if (i == signersList.
end())
200 UNREACHABLE(
"xrpl::claimHelper : invalid inputs");
206 rewardAccounts.
push_back(a.rewardAccount);
209 if (weight >= quorum)
210 return rewardAccounts;
246struct OnNewAttestationResult
254template <
class TAttestation>
255[[nodiscard]] OnNewAttestationResult
257 XChainAttestationsBase<TAttestation>& attestations,
258 ReadView
const& view,
259 typename TAttestation::TSignedAttestation
const* attBegin,
260 typename TAttestation::TSignedAttestation
const* attEnd,
265 bool changed =
false;
266 for (
auto att = attBegin; att != attEnd; ++att)
268 if (checkAttestationPublicKey(view, signersList, att->attestationSignerAccount, att->publicKey, j) !=
278 auto const& claimSigningAccount = att->attestationSignerAccount;
280 attestations.begin(),
282 [&](
auto const& a) { return a.keyAccount == claimSigningAccount; });
283 i != attestations.end())
287 *i = TAttestation{*att};
297 auto r = claimHelper(
298 attestations, view,
typename TAttestation::MatchFields{*attBegin}, CheckDst::check, quorum, signersList, j);
303 return {std::move(r.value()), changed};
309Expected<std::vector<AccountID>,
TER>
311 XChainClaimAttestations& attestations,
312 ReadView
const& view,
313 STAmount
const& sendingAmount,
314 bool wasLockingChainSend,
319 XChainClaimAttestation::MatchFields toMatch{sendingAmount, wasLockingChainSend,
std::nullopt};
320 return claimHelper(attestations, view, toMatch, CheckDst::ignore, quorum, signersList, j);
323enum class CanCreateDstPolicy {
no,
yes };
325enum class DepositAuthPolicy { normal, dstCanBypass };
329struct TransferHelperSubmittingAccountInfo
332 STAmount preFeeBalance;
333 STAmount postFeeBalance;
366 CanCreateDstPolicy canCreate,
367 DepositAuthPolicy depositAuthPolicy,
375 if (
auto sleDst = psb.read(dstK))
385 bool const canBypassDepositAuth = dst == claimOwner && depositAuthPolicy == DepositAuthPolicy::dstCanBypass;
387 if (!canBypassDepositAuth && (sleDst->getFlags() &
lsfDepositAuth) &&
393 else if (!amt.native() || canCreate == CanCreateDstPolicy::no)
401 XRPL_ASSERT(sleSrc,
"xrpl::transferHelper : non-null source account");
406 auto const ownerCount = sleSrc->getFieldU32(sfOwnerCount);
407 auto const reserve = psb.fees().accountReserve(ownerCount);
409 auto const availableBalance = [&]() -> STAmount {
410 STAmount
const curBal = (*sleSrc)[sfBalance];
414 if (!submittingAccountInfo || submittingAccountInfo->account != src ||
415 submittingAccountInfo->postFeeBalance != curBal)
417 return submittingAccountInfo->preFeeBalance;
420 if (availableBalance < amt + reserve)
426 auto sleDst = psb.peek(dstK);
429 if (canCreate == CanCreateDstPolicy::no)
434 if (amt < psb.fees().reserve)
436 JLOG(j.
trace()) <<
"Insufficient payment to create account.";
442 sleDst->setAccountID(sfAccount, dst);
443 sleDst->setFieldU32(sfSequence, psb.seq());
448 (*sleSrc)[sfBalance] = (*sleSrc)[sfBalance] - amt;
449 (*sleDst)[sfBalance] = (*sleDst)[sfBalance] + amt;
456 auto const result =
flow(
481enum class OnTransferFail {
488struct FinalizeClaimHelperResult
508 if ((!mainFundsTer || *mainFundsTer ==
tesSUCCESS) && (!rewardTer || *rewardTer ==
tesSUCCESS) &&
515 return *mainFundsTer;
523 if (mainFundsTer && mainFundsTer !=
tesSUCCESS)
524 return *mainFundsTer;
561FinalizeClaimHelperResult
563 PaymentSandbox& outerSb,
564 STXChainBridge
const& bridgeSpec,
568 STAmount
const& sendingAmount,
570 STAmount
const& rewardPool,
573 Keylet
const& claimIDKeylet,
574 OnTransferFail onTransferFail,
575 DepositAuthPolicy depositAuthPolicy,
578 FinalizeClaimHelperResult result;
581 STAmount
const thisChainAmount = [&] {
582 STAmount r = sendingAmount;
583 r.setIssue(bridgeSpec.issue(dstChain));
586 auto const& thisDoor = bridgeSpec.door(dstChain);
589 PaymentSandbox innerSb{&outerSb};
600 result.mainFundsTer = transferHelper(
607 CanCreateDstPolicy::yes,
612 if (!
isTesSuccess(*result.mainFundsTer) && onTransferFail == OnTransferFail::keepClaim)
618 result.rewardTer = [&]() ->
TER {
619 if (rewardAccounts.
empty())
625 STAmount
const share = [&] {
626 auto const round_mode = innerSb.rules().enabled(fixXChainRewardRounding)
631 STAmount
const den{rewardAccounts.
size()};
632 return divide(rewardPool, den, rewardPool.issue());
634 STAmount distributed = rewardPool.zeroed();
635 for (
auto const& rewardAccount : rewardAccounts)
637 auto const thTer = transferHelper(
645 CanCreateDstPolicy::no,
646 DepositAuthPolicy::normal,
654 distributed += share;
660 if (distributed > rewardPool)
667 (onTransferFail == OnTransferFail::keepClaim || *result.rewardTer ==
tecINTERNAL))
677 innerSb.apply(outerSb);
681 if (
auto const sleClaimID = outerSb.peek(claimIDKeylet))
683 auto const cidOwner = (*sleClaimID)[sfAccount];
687 auto const page = (*sleClaimID)[sfOwnerNode];
690 JLOG(j.
fatal()) <<
"Unable to delete xchain seq number from owner.";
696 outerSb.erase(sleClaimID);
715getSignersListAndQuorum(ReadView
const& view,
SLE const& sleBridge,
beast::Journal j)
720 AccountID const thisDoor = sleBridge[sfAccount];
721 auto const sleDoor = [&] {
return view.read(
keylet::account(thisDoor)); }();
733 q = (*sleS)[sfSignerQuorum];
742 for (
auto const& as : *accountSigners)
744 r[as.account] = as.weight;
750template <
class R,
class F>
752readOrpeekBridge(F&& getter, STXChainBridge
const& bridgeSpec)
755 if (
auto r = getter(bridgeSpec, ct))
757 if ((*r)[sfXChainBridge] == bridgeSpec)
768peekBridge(ApplyView& v, STXChainBridge
const& bridgeSpec)
770 return readOrpeekBridge<SLE>(
778readBridge(ReadView
const& v, STXChainBridge
const& bridgeSpec)
780 return readOrpeekBridge<SLE const>(
789template <
class TIter>
791applyClaimAttestations(
796 STXChainBridge
const& bridgeSpec,
802 if (attBegin == attEnd)
805 PaymentSandbox psb(&view);
811 OnNewAttestationResult newAttResult;
812 STAmount rewardAmount;
816 auto const scopeResult = [&]() -> Expected<ScopeResult, TER> {
821 auto const sleClaimID = psb.peek(claimIDKeylet);
828 for (
auto att = attBegin; att != attEnd; ++att)
830 if (!signersList.
contains(att->attestationSignerAccount))
840 AccountID const otherChainSource = (*sleClaimID)[sfOtherChainSource];
841 if (attBegin->sendingAccount != otherChainSource)
851 if (attDstChain != dstChain)
857 XChainClaimAttestations curAtts{sleClaimID->getFieldArray(sfXChainClaimAttestations)};
859 auto const newAttResult =
860 onNewAttestations(curAtts, view, &atts[0], &atts[0] + atts.
size(), quorum, signersList, j);
863 sleClaimID->setFieldArray(sfXChainClaimAttestations, curAtts.toSTArray());
864 psb.update(sleClaimID);
866 return ScopeResult{newAttResult, (*sleClaimID)[sfSignatureReward], (*sleClaimID)[sfAccount]};
869 if (!scopeResult.has_value())
870 return scopeResult.error();
872 auto const& [newAttResult, rewardAmount, cidOwner] = scopeResult.value();
873 auto const& [rewardAccounts, attListChanged] = newAttResult;
874 if (rewardAccounts && attBegin->dst)
876 auto const r = finalizeClaimHelper(
882 attBegin->sendingAmount,
888 OnTransferFail::keepClaim,
889 DepositAuthPolicy::normal,
892 auto const rTer = r.ter();
903template <
class TIter>
905applyCreateAccountAttestations(
912 STXChainBridge
const& bridgeSpec,
913 Keylet
const& bridgeK,
919 if (attBegin == attEnd)
922 PaymentSandbox psb(&view);
924 auto const claimCountResult = [&]() -> Expected<std::uint64_t, TER> {
925 auto const sleBridge = psb.peek(bridgeK);
929 return (*sleBridge)[sfXChainAccountClaimCount];
932 if (!claimCountResult.has_value())
933 return claimCountResult.error();
937 if (attBegin->createCount <= claimCount)
952 if (attDstChain != dstChain)
962 OnNewAttestationResult newAttResult;
964 XChainCreateAccountAttestations curAtts;
967 auto const scopeResult = [&]() -> Expected<ScopeResult, TER> {
975 auto const sleClaimID = psb.peek(claimIDKeylet);
976 bool createCID =
false;
981 auto const sleDoor = psb.peek(doorK);
986 auto const balance = (*sleDoor)[sfBalance];
987 auto const reserve = psb.fees().accountReserve((*sleDoor)[sfOwnerCount] + 1);
989 if (balance < reserve)
995 for (
auto att = attBegin; att != attEnd; ++att)
997 if (!signersList.
contains(att->attestationSignerAccount))
1006 XChainCreateAccountAttestations curAtts = [&] {
1008 return XChainCreateAccountAttestations{sleClaimID->getFieldArray(sfXChainCreateAccountAttestations)};
1009 return XChainCreateAccountAttestations{};
1012 auto const newAttResult =
1013 onNewAttestations(curAtts, view, &atts[0], &atts[0] + atts.
size(), quorum, signersList, j);
1021 sleClaimID->setFieldArray(sfXChainCreateAccountAttestations, curAtts.toSTArray());
1022 psb.update(sleClaimID);
1024 return ScopeResult{newAttResult, createCID, curAtts};
1027 if (!scopeResult.has_value())
1028 return scopeResult.error();
1030 auto const& [attResult, createCID, curAtts] = scopeResult.value();
1031 auto const& [rewardAccounts, attListChanged] = attResult;
1034 if (rewardAccounts && claimCount + 1 == attBegin->createCount)
1036 auto const r = finalizeClaimHelper(
1042 attBegin->sendingAmount,
1044 attBegin->rewardAmount,
1048 OnTransferFail::removeClaim,
1049 DepositAuthPolicy::normal,
1052 auto const rTer = r.ter();
1061 auto const sleBridge = psb.peek(bridgeK);
1064 (*sleBridge)[sfXChainAccountClaimCount] = attBegin->createCount;
1065 psb.update(sleBridge);
1070 (*createdSleClaimID)[sfAccount] = doorAccount;
1071 (*createdSleClaimID)[sfXChainBridge] = bridgeSpec;
1072 (*createdSleClaimID)[sfXChainAccountCreateCount] = attBegin->createCount;
1073 createdSleClaimID->setFieldArray(sfXChainCreateAccountAttestations, curAtts.toSTArray());
1079 (*createdSleClaimID)[sfOwnerNode] = *
page;
1081 auto const sleDoor = psb.peek(doorK);
1087 psb.insert(createdSleClaimID);
1088 psb.update(sleDoor);
1096template <
class TAttestation>
1098toClaim(STTx
const& tx)
1107 o.setAccountID(sfAccount, o[sfOtherChainSource]);
1108 return TAttestation(o);
1116template <
class TAttestation>
1118attestationPreflight(PreflightContext
const& ctx)
1123 auto const att = toClaim<TAttestation>(ctx.tx);
1127 STXChainBridge
const bridgeSpec = ctx.tx[sfXChainBridge];
1128 if (!att->verify(bridgeSpec))
1130 if (!att->validAmounts())
1133 if (att->sendingAmount.signum() <= 0)
1136 if (att->sendingAmount.issue() != expectedIssue)
1142template <
class TAttestation>
1144attestationPreclaim(PreclaimContext
const& ctx)
1146 auto const att = toClaim<TAttestation>(ctx.tx);
1151 STXChainBridge
const bridgeSpec = ctx.tx[sfXChainBridge];
1152 auto const sleBridge = readBridge(ctx.view, bridgeSpec);
1158 AccountID const attestationSignerAccount{ctx.tx[sfAttestationSignerAccount]};
1159 PublicKey
const pk{ctx.tx[sfPublicKey]};
1162 auto const [signersList, quorum, slTer] = getSignersListAndQuorum(ctx.view, *sleBridge, ctx.j);
1167 return checkAttestationPublicKey(ctx.view, signersList, attestationSignerAccount, pk, ctx.j);
1170template <
class TAttestation>
1172attestationDoApply(ApplyContext& ctx)
1174 auto const att = toClaim<TAttestation>(ctx.tx);
1179 STXChainBridge
const bridgeSpec = ctx.tx[sfXChainBridge];
1183 STXChainBridge::ChainType srcChain;
1190 auto const scopeResult = [&]() -> Expected<ScopeResult, TER> {
1195 auto sleBridge = readBridge(ctx.view(), bridgeSpec);
1200 Keylet
const bridgeK{ltBRIDGE, sleBridge->key()};
1201 AccountID const thisDoor = (*sleBridge)[sfAccount];
1205 if (thisDoor == bridgeSpec.lockingChainDoor())
1207 else if (thisDoor == bridgeSpec.issuingChainDoor())
1215 auto [signersList, quorum, slTer] = getSignersListAndQuorum(ctx.view(), *sleBridge, ctx.journal);
1220 return ScopeResult{srcChain, std::move(signersList), quorum, thisDoor, bridgeK};
1223 if (!scopeResult.has_value())
1224 return scopeResult.error();
1226 auto const& [srcChain, signersList, quorum, thisDoor, bridgeK] = scopeResult.value();
1234 return applyClaimAttestations(
1235 ctx.view(), ctx.rawView(), &*att, &*att + 1, bridgeSpec, srcChain, signersList, quorum, ctx.journal);
1239 return applyCreateAccountAttestations(
1261 auto const account = ctx.
tx[sfAccount];
1262 auto const reward = ctx.
tx[sfSignatureReward];
1263 auto const minAccountCreate = ctx.
tx[~sfMinAccountCreateAmount];
1264 auto const bridgeSpec = ctx.
tx[sfXChainBridge];
1266 if (bridgeSpec.lockingChainDoor() == bridgeSpec.issuingChainDoor())
1271 if (bridgeSpec.lockingChainDoor() != account && bridgeSpec.issuingChainDoor() != account)
1276 if (
isXRP(bridgeSpec.lockingChainIssue()) !=
isXRP(bridgeSpec.issuingChainIssue()))
1283 if (!
isXRP(reward) || reward.signum() < 0)
1288 if (minAccountCreate &&
1289 ((!
isXRP(*minAccountCreate) || minAccountCreate->signum() <= 0) || !
isXRP(bridgeSpec.lockingChainIssue()) ||
1290 !
isXRP(bridgeSpec.issuingChainIssue())))
1295 if (
isXRP(bridgeSpec.issuingChainIssue()))
1300 static auto const rootAccount =
1302 if (bridgeSpec.issuingChainDoor() != rootAccount)
1311 if (bridgeSpec.issuingChainDoor() != bridgeSpec.issuingChainIssue().account)
1317 if (bridgeSpec.lockingChainDoor() == bridgeSpec.lockingChainIssue().account)
1330 auto const account = ctx.
tx[sfAccount];
1331 auto const bridgeSpec = ctx.
tx[sfXChainBridge];
1345 if (!
isXRP(bridgeSpec.issue(chainType)))
1364 auto const balance = (*sleAcc)[sfBalance];
1367 if (balance < reserve)
1377 auto const account =
ctx_.
tx[sfAccount];
1378 auto const bridgeSpec =
ctx_.
tx[sfXChainBridge];
1379 auto const reward =
ctx_.
tx[sfSignatureReward];
1380 auto const minAccountCreate =
ctx_.
tx[~sfMinAccountCreateAmount];
1391 (*sleBridge)[sfAccount] = account;
1392 (*sleBridge)[sfSignatureReward] = reward;
1393 if (minAccountCreate)
1394 (*sleBridge)[sfMinAccountCreateAmount] = *minAccountCreate;
1395 (*sleBridge)[sfXChainBridge] = bridgeSpec;
1396 (*sleBridge)[sfXChainClaimID] = 0;
1397 (*sleBridge)[sfXChainAccountCreateCount] = 0;
1398 (*sleBridge)[sfXChainAccountClaimCount] = 0;
1405 (*sleBridge)[sfOwnerNode] = *page;
1427 auto const account = ctx.
tx[sfAccount];
1428 auto const reward = ctx.
tx[~sfSignatureReward];
1429 auto const minAccountCreate = ctx.
tx[~sfMinAccountCreateAmount];
1430 auto const bridgeSpec = ctx.
tx[sfXChainBridge];
1433 if (!reward && !minAccountCreate && !clearAccountCreate)
1439 if (minAccountCreate && clearAccountCreate)
1445 if (bridgeSpec.lockingChainDoor() != account && bridgeSpec.issuingChainDoor() != account)
1450 if (reward && (!
isXRP(*reward) || reward->signum() < 0))
1455 if (minAccountCreate &&
1456 ((!
isXRP(*minAccountCreate) || minAccountCreate->signum() <= 0) || !
isXRP(bridgeSpec.lockingChainIssue()) ||
1457 !
isXRP(bridgeSpec.issuingChainIssue())))
1468 auto const account = ctx.
tx[sfAccount];
1469 auto const bridgeSpec = ctx.
tx[sfXChainBridge];
1484 auto const account =
ctx_.
tx[sfAccount];
1485 auto const bridgeSpec =
ctx_.
tx[sfXChainBridge];
1486 auto const reward =
ctx_.
tx[~sfSignatureReward];
1487 auto const minAccountCreate =
ctx_.
tx[~sfMinAccountCreateAmount];
1501 (*sleBridge)[sfSignatureReward] = *reward;
1502 if (minAccountCreate)
1504 (*sleBridge)[sfMinAccountCreateAmount] = *minAccountCreate;
1506 if (clearAccountCreate && sleBridge->isFieldPresent(sfMinAccountCreateAmount))
1508 sleBridge->makeFieldAbsent(sfMinAccountCreateAmount);
1521 auto const amount = ctx.
tx[sfAmount];
1523 if (amount.signum() <= 0 ||
1537 STAmount const& thisChainAmount = ctx.
tx[sfAmount];
1538 auto const claimID = ctx.
tx[sfXChainClaimID];
1540 auto const sleBridge = readBridge(ctx.
view, bridgeSpec);
1551 auto const thisDoor = (*sleBridge)[sfAccount];
1552 bool isLockingChain =
false;
1555 isLockingChain =
true;
1557 isLockingChain =
false;
1585 auto const otherChainAmount = [&]() ->
STAmount {
1603 if ((*sleClaimID)[sfAccount] != account)
1620 auto const dst =
ctx_.
tx[sfDestination];
1623 auto const claimID =
ctx_.
tx[sfXChainClaimID];
1642 auto const sleBridge = peekBridge(psb, bridgeSpec);
1643 auto const sleClaimID = psb.
peek(claimIDKeylet);
1645 if (!(sleBridge && sleClaimID && sleAcct))
1648 AccountID const thisDoor = (*sleBridge)[sfAccount];
1661 auto const sendingAmount = [&]() ->
STAmount {
1667 auto const [signersList, quorum, slTer] = getSignersListAndQuorum(
ctx_.
view(), *sleBridge,
ctx_.
journal);
1674 auto const claimR = onClaim(
1682 if (!claimR.has_value())
1687 (*sleClaimID)[sfAccount],
1690 (*sleClaimID)[sfSignatureReward],
1694 if (!scopeResult.has_value())
1695 return scopeResult.error();
1697 auto const& [rewardAccounts, rewardPoolSrc, sendingAmount, srcChain, signatureReward] = scopeResult.value();
1700 auto const r = finalizeClaimHelper(
1712 OnTransferFail::keepClaim,
1713 DepositAuthPolicy::dstCanBypass,
1715 if (!r.isTesSuccess())
1728 auto const maxSpend = [&] {
1729 auto const amount = ctx.
tx[sfAmount];
1730 if (amount.native() && amount.signum() > 0)
1731 return amount.xrp();
1741 auto const amount = ctx.
tx[sfAmount];
1742 auto const bridgeSpec = ctx.
tx[sfXChainBridge];
1744 if (amount.signum() <= 0 || !
isLegalNet(amount))
1747 if (amount.issue() != bridgeSpec.lockingChainIssue() && amount.issue() != bridgeSpec.issuingChainIssue())
1756 auto const bridgeSpec = ctx.
tx[sfXChainBridge];
1757 auto const amount = ctx.
tx[sfAmount];
1759 auto const sleBridge = readBridge(ctx.
view, bridgeSpec);
1765 AccountID const thisDoor = (*sleBridge)[sfAccount];
1768 if (thisDoor == account)
1774 bool isLockingChain =
false;
1776 if (thisDoor == bridgeSpec.lockingChainDoor())
1777 isLockingChain =
true;
1778 else if (thisDoor == bridgeSpec.issuingChainDoor())
1779 isLockingChain =
false;
1786 if (bridgeSpec.lockingChainIssue() != ctx.
tx[sfAmount].issue())
1791 if (bridgeSpec.issuingChainIssue() != ctx.
tx[sfAmount].issue())
1803 auto const account =
ctx_.
tx[sfAccount];
1804 auto const amount =
ctx_.
tx[sfAmount];
1805 auto const bridgeSpec =
ctx_.
tx[sfXChainBridge];
1810 auto const sleBridge = readBridge(psb, bridgeSpec);
1814 auto const dst = (*sleBridge)[sfAccount];
1819 auto const thTer = transferHelper(
1826 CanCreateDstPolicy::no,
1827 DepositAuthPolicy::normal,
1828 submittingAccountInfo,
1844 auto const reward = ctx.
tx[sfSignatureReward];
1855 auto const account = ctx.
tx[sfAccount];
1856 auto const bridgeSpec = ctx.
tx[sfXChainBridge];
1857 auto const sleBridge = readBridge(ctx.
view, bridgeSpec);
1865 auto const reward = ctx.
tx[sfSignatureReward];
1867 if (reward != (*sleBridge)[sfSignatureReward])
1878 auto const balance = (*sleAcc)[sfBalance];
1881 if (balance < reserve)
1891 auto const account =
ctx_.
tx[sfAccount];
1892 auto const bridgeSpec =
ctx_.
tx[sfXChainBridge];
1893 auto const reward =
ctx_.
tx[sfSignatureReward];
1894 auto const otherChainSrc =
ctx_.
tx[sfOtherChainSource];
1900 auto const sleBridge = peekBridge(
ctx_.
view(), bridgeSpec);
1904 std::uint32_t const claimID = (*sleBridge)[sfXChainClaimID] + 1;
1911 (*sleBridge)[sfXChainClaimID] = claimID;
1922 (*sleClaimID)[sfAccount] = account;
1923 (*sleClaimID)[sfXChainBridge] = bridgeSpec;
1924 (*sleClaimID)[sfXChainClaimID] = claimID;
1925 (*sleClaimID)[sfOtherChainSource] = otherChainSrc;
1926 (*sleClaimID)[sfSignatureReward] = reward;
1927 sleClaimID->setFieldArray(sfXChainClaimAttestations,
STArray{sfXChainClaimAttestations});
1934 (*sleClaimID)[sfOwnerNode] = *page;
1951 return attestationPreflight<Attestations::AttestationClaim>(ctx);
1957 return attestationPreclaim<Attestations::AttestationClaim>(ctx);
1963 return attestationDoApply<Attestations::AttestationClaim>(
ctx_);
1971 return attestationPreflight<Attestations::AttestationCreateAccount>(ctx);
1977 return attestationPreclaim<Attestations::AttestationCreateAccount>(ctx);
1983 return attestationDoApply<Attestations::AttestationCreateAccount>(
ctx_);
1991 auto const amount = ctx.
tx[sfAmount];
1993 if (amount.signum() <= 0 || !amount.native())
1996 auto const reward = ctx.
tx[sfSignatureReward];
1997 if (reward.signum() < 0 || !reward.native())
2000 if (reward.issue() != amount.issue())
2011 STAmount const reward = ctx.
tx[sfSignatureReward];
2013 auto const sleBridge = readBridge(ctx.
view, bridgeSpec);
2019 if (reward != (*sleBridge)[sfSignatureReward])
2026 if (!minCreateAmount)
2029 if (amount < *minCreateAmount)
2032 if (minCreateAmount->issue() != amount.issue())
2035 AccountID const thisDoor = (*sleBridge)[sfAccount];
2037 if (thisDoor == account)
2054 if (bridgeSpec.
issue(srcChain) != ctx.
tx[sfAmount].issue())
2077 auto const sleBridge = peekBridge(psb, bridge);
2081 auto const dst = (*sleBridge)[sfAccount];
2085 STAmount const toTransfer = amount + reward;
2086 auto const thTer = transferHelper(
2093 CanCreateDstPolicy::yes,
2094 DepositAuthPolicy::normal,
2095 submittingAccountInfo,
2101 (*sleBridge)[sfXChainAccountCreateCount] = (*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 std::uint32_t getFlagsMask(PreflightContext const &ctx)
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 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.
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
void setIssue(Asset const &asset)
Set the Issue for this amount.
Issue const & issue() const
std::uint32_t getFlags() const
AccountID const & issuingChainDoor() const
static ChainType dstChain(bool wasLockingChainSend)
AccountID const & lockingChainDoor() const
static ChainType srcChain(bool wasLockingChainSend)
Issue const & issue(ChainType ct) const
Issue const & issuingChainIssue() const
static ChainType otherChain(ChainType ct)
Issue const & lockingChainIssue() 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 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 NotTEC preflight(PreflightContext const &ctx)
static TER preclaim(PreclaimContext 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 > peek(Keylet const &k) override
Prepare to modify the SLE associated with key.
std::shared_ptr< SLE const > read(Keylet const &k) const override
Return the state item associated with a key.
T emplace_back(T... args)
void check(bool condition, std::string const &message)
Keylet signers(AccountID const &account) noexcept
A SignerList.
Keylet depositPreauth(AccountID const &owner, AccountID const &preauthorized) noexcept
A DepositPreauth.
Keylet bridge(STXChainBridge const &bridge, STXChainBridge::ChainType chainType)
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Keylet xChainCreateAccountClaimID(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 xChainClaimID(STXChainBridge const &bridge, std::uint64_t seq)
std::uint32_t ownerCount(Env const &env, Account const &account)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
STAmount divide(STAmount const &amount, Rate const &rate)
bool isTerRetry(TER x) noexcept
Unexpected(E(&)[N]) -> Unexpected< E const * >
bool isXRP(AccountID const &c)
bool isLegalNet(STAmount const &value)
constexpr std::uint32_t tfBridgeModifyMask
base_uint< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
Seed generateSeed(std::string const &passPhrase)
Generate a seed deterministically.
std::pair< PublicKey, SecretKey > generateKeyPair(KeyType type, Seed const &seed)
Generate a key pair deterministically.
std::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
constexpr std::uint32_t tfClearAccountCreateAmount
TERSubset< CanCvtToTER > TER
void adjustOwnerCount(ApplyView &view, std::shared_ptr< SLE > const &sle, std::int32_t amount, beast::Journal j)
Adjust the owner count up or down.
bool isTefFailure(TER x) noexcept
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.
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
AccountID calcAccountID(PublicKey const &pk)
@ temXCHAIN_BRIDGE_BAD_MIN_ACCOUNT_CREATE_AMOUNT
@ temXCHAIN_BRIDGE_NONDOOR_OWNER
@ temXCHAIN_BRIDGE_BAD_ISSUES
@ temXCHAIN_BRIDGE_BAD_REWARD_AMOUNT
@ temXCHAIN_EQUAL_DOOR_ACCOUNTS
bool isTesSuccess(TER x) noexcept
@ tecXCHAIN_INSUFF_CREATE_AMOUNT
@ tecXCHAIN_NO_SIGNERS_LIST
@ tecXCHAIN_SENDING_ACCOUNT_MISMATCH
@ tecXCHAIN_BAD_TRANSFER_ISSUE
@ tecXCHAIN_PROOF_UNKNOWN_KEY
@ tecXCHAIN_ACCOUNT_CREATE_PAST
@ tecXCHAIN_PAYMENT_FAILED
@ tecXCHAIN_ACCOUNT_CREATE_TOO_MANY
@ tecXCHAIN_CREATE_ACCOUNT_NONXRP_ISSUE
@ tecXCHAIN_BAD_PUBLIC_KEY_ACCOUNT_PAIR
@ tecXCHAIN_CREATE_ACCOUNT_DISABLED
@ tecINSUFFICIENT_RESERVE
@ tecXCHAIN_CLAIM_NO_QUORUM
@ tecXCHAIN_REWARD_MISMATCH
bool isTecClaim(TER x) noexcept
@ lsfAllowTrustLineClawback
constexpr size_t xbridgeMaxAccountCreateClaims
TERSubset< CanCvtToNotTEC > NotTEC
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.