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 sleDst->setAccountID(sfAccount, dst);
469 sleDst->setFieldU32(sfSequence, psb.seq());
474 (*sleSrc)[sfBalance] = (*sleSrc)[sfBalance] - amt;
475 (*sleDst)[sfBalance] = (*sleDst)[sfBalance] + amt;
482 auto const result =
flow(
497 if (
auto const r = result.result();
508enum class OnTransferFail {
515struct FinalizeClaimHelperResult
536 if ((!mainFundsTer || *mainFundsTer ==
tesSUCCESS) &&
545 return *mainFundsTer;
554 if (mainFundsTer && mainFundsTer !=
tesSUCCESS)
555 return *mainFundsTer;
592FinalizeClaimHelperResult
594 PaymentSandbox& outerSb,
595 STXChainBridge
const& bridgeSpec,
599 STAmount
const& sendingAmount,
601 STAmount
const& rewardPool,
604 Keylet
const& claimIDKeylet,
605 OnTransferFail onTransferFail,
606 DepositAuthPolicy depositAuthPolicy,
609 FinalizeClaimHelperResult result;
613 STAmount
const thisChainAmount = [&] {
614 STAmount r = sendingAmount;
615 r.setIssue(bridgeSpec.issue(dstChain));
618 auto const& thisDoor = bridgeSpec.door(dstChain);
621 PaymentSandbox innerSb{&outerSb};
632 result.mainFundsTer = transferHelper(
639 CanCreateDstPolicy::yes,
645 onTransferFail == OnTransferFail::keepClaim)
651 result.rewardTer = [&]() ->
TER {
652 if (rewardAccounts.empty())
658 STAmount
const share = [&] {
659 auto const round_mode =
660 innerSb.rules().enabled(fixXChainRewardRounding)
665 STAmount
const den{rewardAccounts.size()};
666 return divide(rewardPool, den, rewardPool.issue());
668 STAmount distributed = rewardPool.zeroed();
669 for (
auto const& rewardAccount : rewardAccounts)
671 auto const thTer = transferHelper(
679 CanCreateDstPolicy::no,
680 DepositAuthPolicy::normal,
688 distributed += share;
694 if (distributed > rewardPool)
701 (onTransferFail == OnTransferFail::keepClaim ||
713 innerSb.apply(outerSb);
717 if (
auto const sleClaimID = outerSb.peek(claimIDKeylet))
719 auto const cidOwner = (*sleClaimID)[sfAccount];
723 auto const page = (*sleClaimID)[sfOwnerNode];
724 if (!outerSb.dirRemove(
728 <<
"Unable to delete xchain seq number from owner.";
734 outerSb.erase(sleClaimID);
753getSignersListAndQuorum(
754 ReadView
const& view,
755 SLE const& sleBridge,
761 AccountID const thisDoor = sleBridge[sfAccount];
762 auto const sleDoor = [&] {
return view.read(
keylet::account(thisDoor)); }();
774 q = (*sleS)[sfSignerQuorum];
783 for (
auto const& as : *accountSigners)
785 r[as.account] = as.weight;
791template <
class R,
class F>
793readOrpeekBridge(F&& getter, STXChainBridge
const& bridgeSpec)
796 if (
auto r = getter(bridgeSpec, ct))
798 if ((*r)[sfXChainBridge] == bridgeSpec)
809peekBridge(ApplyView& v, STXChainBridge
const& bridgeSpec)
811 return readOrpeekBridge<SLE>(
818readBridge(ReadView
const& v, STXChainBridge
const& bridgeSpec)
820 return readOrpeekBridge<SLE const>(
830template <
class TIter>
832applyClaimAttestations(
837 STXChainBridge
const& bridgeSpec,
843 if (attBegin == attEnd)
846 PaymentSandbox psb(&view);
848 auto const claimIDKeylet =
853 OnNewAttestationResult newAttResult;
854 STAmount rewardAmount;
858 auto const scopeResult = [&]() -> Expected<ScopeResult, TER> {
863 auto const sleClaimID = psb.peek(claimIDKeylet);
870 for (
auto att = attBegin; att != attEnd; ++att)
872 if (!signersList.
contains(att->attestationSignerAccount))
882 AccountID const otherChainSource = (*sleClaimID)[sfOtherChainSource];
883 if (attBegin->sendingAccount != otherChainSource)
895 if (attDstChain != dstChain)
901 XChainClaimAttestations curAtts{
902 sleClaimID->getFieldArray(sfXChainClaimAttestations)};
904 auto const newAttResult = onNewAttestations(
908 &atts[0] + atts.
size(),
914 sleClaimID->setFieldArray(
915 sfXChainClaimAttestations, curAtts.toSTArray());
916 psb.update(sleClaimID);
920 (*sleClaimID)[sfSignatureReward],
921 (*sleClaimID)[sfAccount]};
924 if (!scopeResult.has_value())
925 return scopeResult.error();
927 auto const& [newAttResult, rewardAmount, cidOwner] = scopeResult.value();
928 auto const& [rewardAccounts, attListChanged] = newAttResult;
929 if (rewardAccounts && attBegin->dst)
931 auto const r = finalizeClaimHelper(
937 attBegin->sendingAmount,
943 OnTransferFail::keepClaim,
944 DepositAuthPolicy::normal,
947 auto const rTer = r.ter();
959template <
class TIter>
961applyCreateAccountAttestations(
968 STXChainBridge
const& bridgeSpec,
969 Keylet
const& bridgeK,
975 if (attBegin == attEnd)
978 PaymentSandbox psb(&view);
980 auto const claimCountResult = [&]() -> Expected<std::uint64_t, TER> {
981 auto const sleBridge = psb.peek(bridgeK);
985 return (*sleBridge)[sfXChainAccountClaimCount];
988 if (!claimCountResult.has_value())
989 return claimCountResult.error();
993 if (attBegin->createCount <= claimCount)
1010 if (attDstChain != dstChain)
1016 auto const claimIDKeylet =
1021 OnNewAttestationResult newAttResult;
1023 XChainCreateAccountAttestations curAtts;
1026 auto const scopeResult = [&]() -> Expected<ScopeResult, TER> {
1034 auto const sleClaimID = psb.peek(claimIDKeylet);
1035 bool createCID =
false;
1040 auto const sleDoor = psb.peek(doorK);
1045 auto const balance = (*sleDoor)[sfBalance];
1046 auto const reserve =
1047 psb.fees().accountReserve((*sleDoor)[sfOwnerCount] + 1);
1049 if (balance < reserve)
1055 for (
auto att = attBegin; att != attEnd; ++att)
1057 if (!signersList.
contains(att->attestationSignerAccount))
1066 XChainCreateAccountAttestations curAtts = [&] {
1068 return XChainCreateAccountAttestations{
1069 sleClaimID->getFieldArray(
1070 sfXChainCreateAccountAttestations)};
1071 return XChainCreateAccountAttestations{};
1074 auto const newAttResult = onNewAttestations(
1078 &atts[0] + atts.
size(),
1089 sleClaimID->setFieldArray(
1090 sfXChainCreateAccountAttestations, curAtts.toSTArray());
1091 psb.update(sleClaimID);
1093 return ScopeResult{newAttResult, createCID, curAtts};
1096 if (!scopeResult.has_value())
1097 return scopeResult.error();
1099 auto const& [attResult, createCID, curAtts] = scopeResult.value();
1100 auto const& [rewardAccounts, attListChanged] = attResult;
1103 if (rewardAccounts && claimCount + 1 == attBegin->createCount)
1105 auto const r = finalizeClaimHelper(
1111 attBegin->sendingAmount,
1113 attBegin->rewardAmount,
1117 OnTransferFail::removeClaim,
1118 DepositAuthPolicy::normal,
1121 auto const rTer = r.ter();
1131 auto const sleBridge = psb.peek(bridgeK);
1134 (*sleBridge)[sfXChainAccountClaimCount] = attBegin->createCount;
1135 psb.update(sleBridge);
1140 (*createdSleClaimID)[sfAccount] = doorAccount;
1141 (*createdSleClaimID)[sfXChainBridge] = bridgeSpec;
1142 (*createdSleClaimID)[sfXChainAccountCreateCount] =
1143 attBegin->createCount;
1144 createdSleClaimID->setFieldArray(
1145 sfXChainCreateAccountAttestations, curAtts.toSTArray());
1148 auto const page = psb.dirInsert(
1154 (*createdSleClaimID)[sfOwnerNode] = *
page;
1156 auto const sleDoor = psb.peek(doorK);
1162 psb.insert(createdSleClaimID);
1163 psb.update(sleDoor);
1171template <
class TAttestation>
1173toClaim(STTx
const& tx)
1182 o.setAccountID(sfAccount, o[sfOtherChainSource]);
1183 return TAttestation(o);
1191template <
class TAttestation>
1193attestationpreflight(PreflightContext
const& ctx)
1198 auto const att = toClaim<TAttestation>(ctx.tx);
1202 STXChainBridge
const bridgeSpec = ctx.tx[sfXChainBridge];
1203 if (!att->verify(bridgeSpec))
1205 if (!att->validAmounts())
1208 if (att->sendingAmount.signum() <= 0)
1210 auto const expectedIssue =
1212 if (att->sendingAmount.issue() != expectedIssue)
1218template <
class TAttestation>
1220attestationPreclaim(PreclaimContext
const& ctx)
1222 auto const att = toClaim<TAttestation>(ctx.tx);
1227 STXChainBridge
const bridgeSpec = ctx.tx[sfXChainBridge];
1228 auto const sleBridge = readBridge(ctx.view, bridgeSpec);
1234 AccountID const attestationSignerAccount{
1235 ctx.tx[sfAttestationSignerAccount]};
1236 PublicKey
const pk{ctx.tx[sfPublicKey]};
1239 auto const [signersList, quorum, slTer] =
1240 getSignersListAndQuorum(ctx.view, *sleBridge, ctx.j);
1245 return checkAttestationPublicKey(
1246 ctx.view, signersList, attestationSignerAccount, pk, ctx.j);
1249template <
class TAttestation>
1251attestationDoApply(ApplyContext& ctx)
1253 auto const att = toClaim<TAttestation>(ctx.tx);
1258 STXChainBridge
const bridgeSpec = ctx.tx[sfXChainBridge];
1262 STXChainBridge::ChainType srcChain;
1269 auto const scopeResult = [&]() -> Expected<ScopeResult, TER> {
1274 auto sleBridge = readBridge(ctx.view(), bridgeSpec);
1279 Keylet
const bridgeK{ltBRIDGE, sleBridge->key()};
1280 AccountID const thisDoor = (*sleBridge)[sfAccount];
1284 if (thisDoor == bridgeSpec.lockingChainDoor())
1286 else if (thisDoor == bridgeSpec.issuingChainDoor())
1295 auto [signersList, quorum, slTer] =
1296 getSignersListAndQuorum(ctx.view(), *sleBridge, ctx.journal);
1302 srcChain, std::move(signersList), quorum, thisDoor, bridgeK};
1305 if (!scopeResult.has_value())
1306 return scopeResult.error();
1308 auto const& [srcChain, signersList, quorum, thisDoor, bridgeK] =
1309 scopeResult.value();
1317 return applyClaimAttestations(
1330 Attestations::AttestationCreateAccount>)
1332 return applyCreateAccountAttestations(
1354 auto const account = ctx.
tx[sfAccount];
1355 auto const reward = ctx.
tx[sfSignatureReward];
1356 auto const minAccountCreate = ctx.
tx[~sfMinAccountCreateAmount];
1357 auto const bridgeSpec = ctx.
tx[sfXChainBridge];
1359 if (bridgeSpec.lockingChainDoor() == bridgeSpec.issuingChainDoor())
1364 if (bridgeSpec.lockingChainDoor() != account &&
1365 bridgeSpec.issuingChainDoor() != account)
1370 if (
isXRP(bridgeSpec.lockingChainIssue()) !=
1371 isXRP(bridgeSpec.issuingChainIssue()))
1378 if (!
isXRP(reward) || reward.signum() < 0)
1383 if (minAccountCreate &&
1384 ((!
isXRP(*minAccountCreate) || minAccountCreate->signum() <= 0) ||
1385 !
isXRP(bridgeSpec.lockingChainIssue()) ||
1386 !
isXRP(bridgeSpec.issuingChainIssue())))
1391 if (
isXRP(bridgeSpec.issuingChainIssue()))
1400 if (bridgeSpec.issuingChainDoor() != rootAccount)
1409 if (bridgeSpec.issuingChainDoor() !=
1410 bridgeSpec.issuingChainIssue().account)
1416 if (bridgeSpec.lockingChainDoor() == bridgeSpec.lockingChainIssue().account)
1429 auto const account = ctx.
tx[sfAccount];
1430 auto const bridgeSpec = ctx.
tx[sfXChainBridge];
1446 if (!
isXRP(bridgeSpec.issue(chainType)))
1448 auto const sleIssuer =
1466 auto const balance = (*sleAcc)[sfBalance];
1467 auto const reserve =
1470 if (balance < reserve)
1480 auto const account =
ctx_.
tx[sfAccount];
1481 auto const bridgeSpec =
ctx_.
tx[sfXChainBridge];
1482 auto const reward =
ctx_.
tx[sfSignatureReward];
1483 auto const minAccountCreate =
ctx_.
tx[~sfMinAccountCreateAmount];
1495 (*sleBridge)[sfAccount] = account;
1496 (*sleBridge)[sfSignatureReward] = reward;
1497 if (minAccountCreate)
1498 (*sleBridge)[sfMinAccountCreateAmount] = *minAccountCreate;
1499 (*sleBridge)[sfXChainBridge] = bridgeSpec;
1500 (*sleBridge)[sfXChainClaimID] = 0;
1501 (*sleBridge)[sfXChainAccountCreateCount] = 0;
1502 (*sleBridge)[sfXChainAccountClaimCount] = 0;
1510 (*sleBridge)[sfOwnerNode] = *page;
1532 auto const account = ctx.
tx[sfAccount];
1533 auto const reward = ctx.
tx[~sfSignatureReward];
1534 auto const minAccountCreate = ctx.
tx[~sfMinAccountCreateAmount];
1535 auto const bridgeSpec = ctx.
tx[sfXChainBridge];
1536 bool const clearAccountCreate =
1539 if (!reward && !minAccountCreate && !clearAccountCreate)
1545 if (minAccountCreate && clearAccountCreate)
1551 if (bridgeSpec.lockingChainDoor() != account &&
1552 bridgeSpec.issuingChainDoor() != account)
1557 if (reward && (!
isXRP(*reward) || reward->signum() < 0))
1562 if (minAccountCreate &&
1563 ((!
isXRP(*minAccountCreate) || minAccountCreate->signum() <= 0) ||
1564 !
isXRP(bridgeSpec.lockingChainIssue()) ||
1565 !
isXRP(bridgeSpec.issuingChainIssue())))
1576 auto const account = ctx.
tx[sfAccount];
1577 auto const bridgeSpec = ctx.
tx[sfXChainBridge];
1593 auto const account =
ctx_.
tx[sfAccount];
1594 auto const bridgeSpec =
ctx_.
tx[sfXChainBridge];
1595 auto const reward =
ctx_.
tx[~sfSignatureReward];
1596 auto const minAccountCreate =
ctx_.
tx[~sfMinAccountCreateAmount];
1597 bool const clearAccountCreate =
1607 auto const sleBridge =
1613 (*sleBridge)[sfSignatureReward] = *reward;
1614 if (minAccountCreate)
1616 (*sleBridge)[sfMinAccountCreateAmount] = *minAccountCreate;
1618 if (clearAccountCreate &&
1619 sleBridge->isFieldPresent(sfMinAccountCreateAmount))
1621 sleBridge->makeFieldAbsent(sfMinAccountCreateAmount);
1634 auto const amount = ctx.
tx[sfAmount];
1636 if (amount.signum() <= 0 ||
1651 STAmount const& thisChainAmount = ctx.
tx[sfAmount];
1652 auto const claimID = ctx.
tx[sfXChainClaimID];
1654 auto const sleBridge = readBridge(ctx.
view, bridgeSpec);
1665 auto const thisDoor = (*sleBridge)[sfAccount];
1666 bool isLockingChain =
false;
1669 isLockingChain =
true;
1671 isLockingChain =
false;
1700 auto const otherChainAmount = [&]() ->
STAmount {
1709 auto const sleClaimID =
1719 if ((*sleClaimID)[sfAccount] != account)
1736 auto const dst =
ctx_.
tx[sfDestination];
1739 auto const claimID =
ctx_.
tx[sfXChainClaimID];
1758 auto const sleBridge = peekBridge(psb, bridgeSpec);
1759 auto const sleClaimID = psb.
peek(claimIDKeylet);
1761 if (!(sleBridge && sleClaimID && sleAcct))
1764 AccountID const thisDoor = (*sleBridge)[sfAccount];
1778 auto const sendingAmount = [&]() ->
STAmount {
1784 auto const [signersList, quorum, slTer] =
1791 sleClaimID->getFieldArray(sfXChainClaimAttestations)};
1793 auto const claimR = onClaim(
1802 if (!claimR.has_value())
1807 (*sleClaimID)[sfAccount],
1810 (*sleClaimID)[sfSignatureReward],
1814 if (!scopeResult.has_value())
1815 return scopeResult.error();
1817 auto const& [rewardAccounts, rewardPoolSrc, sendingAmount, srcChain, signatureReward] =
1818 scopeResult.value();
1821 auto const r = finalizeClaimHelper(
1833 OnTransferFail::keepClaim,
1834 DepositAuthPolicy::dstCanBypass,
1836 if (!r.isTesSuccess())
1849 auto const maxSpend = [&] {
1850 auto const amount = ctx.
tx[sfAmount];
1851 if (amount.native() && amount.signum() > 0)
1852 return amount.xrp();
1862 auto const amount = ctx.
tx[sfAmount];
1863 auto const bridgeSpec = ctx.
tx[sfXChainBridge];
1865 if (amount.signum() <= 0 || !
isLegalNet(amount))
1868 if (amount.issue() != bridgeSpec.lockingChainIssue() &&
1869 amount.issue() != bridgeSpec.issuingChainIssue())
1878 auto const bridgeSpec = ctx.
tx[sfXChainBridge];
1879 auto const amount = ctx.
tx[sfAmount];
1881 auto const sleBridge = readBridge(ctx.
view, bridgeSpec);
1887 AccountID const thisDoor = (*sleBridge)[sfAccount];
1890 if (thisDoor == account)
1896 bool isLockingChain =
false;
1898 if (thisDoor == bridgeSpec.lockingChainDoor())
1899 isLockingChain =
true;
1900 else if (thisDoor == bridgeSpec.issuingChainDoor())
1901 isLockingChain =
false;
1908 if (bridgeSpec.lockingChainIssue() != ctx.
tx[sfAmount].issue())
1913 if (bridgeSpec.issuingChainIssue() != ctx.
tx[sfAmount].issue())
1925 auto const account =
ctx_.
tx[sfAccount];
1926 auto const amount =
ctx_.
tx[sfAmount];
1927 auto const bridgeSpec =
ctx_.
tx[sfXChainBridge];
1932 auto const sleBridge = readBridge(psb, bridgeSpec);
1936 auto const dst = (*sleBridge)[sfAccount];
1939 TransferHelperSubmittingAccountInfo submittingAccountInfo{
1942 auto const thTer = transferHelper(
1949 CanCreateDstPolicy::no,
1950 DepositAuthPolicy::normal,
1951 submittingAccountInfo,
1967 auto const reward = ctx.
tx[sfSignatureReward];
1978 auto const account = ctx.
tx[sfAccount];
1979 auto const bridgeSpec = ctx.
tx[sfXChainBridge];
1980 auto const sleBridge = readBridge(ctx.
view, bridgeSpec);
1988 auto const reward = ctx.
tx[sfSignatureReward];
1990 if (reward != (*sleBridge)[sfSignatureReward])
2001 auto const balance = (*sleAcc)[sfBalance];
2002 auto const reserve =
2005 if (balance < reserve)
2015 auto const account =
ctx_.
tx[sfAccount];
2016 auto const bridgeSpec =
ctx_.
tx[sfXChainBridge];
2017 auto const reward =
ctx_.
tx[sfSignatureReward];
2018 auto const otherChainSrc =
ctx_.
tx[sfOtherChainSource];
2024 auto const sleBridge = peekBridge(
ctx_.
view(), bridgeSpec);
2028 std::uint32_t const claimID = (*sleBridge)[sfXChainClaimID] + 1;
2035 (*sleBridge)[sfXChainClaimID] = claimID;
2046 (*sleClaimID)[sfAccount] = account;
2047 (*sleClaimID)[sfXChainBridge] = bridgeSpec;
2048 (*sleClaimID)[sfXChainClaimID] = claimID;
2049 (*sleClaimID)[sfOtherChainSource] = otherChainSrc;
2050 (*sleClaimID)[sfSignatureReward] = reward;
2051 sleClaimID->setFieldArray(
2052 sfXChainClaimAttestations,
STArray{sfXChainClaimAttestations});
2062 (*sleClaimID)[sfOwnerNode] = *page;
2079 return attestationpreflight<Attestations::AttestationClaim>(ctx);
2085 return attestationPreclaim<Attestations::AttestationClaim>(ctx);
2091 return attestationDoApply<Attestations::AttestationClaim>(
ctx_);
2099 return attestationpreflight<Attestations::AttestationCreateAccount>(ctx);
2105 return attestationPreclaim<Attestations::AttestationCreateAccount>(ctx);
2111 return attestationDoApply<Attestations::AttestationCreateAccount>(
ctx_);
2119 auto const amount = ctx.
tx[sfAmount];
2121 if (amount.signum() <= 0 || !amount.native())
2124 auto const reward = ctx.
tx[sfSignatureReward];
2125 if (reward.signum() < 0 || !reward.native())
2128 if (reward.issue() != amount.issue())
2139 STAmount const reward = ctx.
tx[sfSignatureReward];
2141 auto const sleBridge = readBridge(ctx.
view, bridgeSpec);
2147 if (reward != (*sleBridge)[sfSignatureReward])
2153 (*sleBridge)[~sfMinAccountCreateAmount];
2155 if (!minCreateAmount)
2158 if (amount < *minCreateAmount)
2161 if (minCreateAmount->issue() != amount.
issue())
2164 AccountID const thisDoor = (*sleBridge)[sfAccount];
2166 if (thisDoor == account)
2184 if (bridgeSpec.
issue(srcChain) != ctx.
tx[sfAmount].issue())
2207 auto const sleBridge = peekBridge(psb, bridge);
2211 auto const dst = (*sleBridge)[sfAccount];
2214 TransferHelperSubmittingAccountInfo submittingAccountInfo{
2216 STAmount const toTransfer = amount + reward;
2217 auto const thTer = transferHelper(
2224 CanCreateDstPolicy::yes,
2225 DepositAuthPolicy::normal,
2226 submittingAccountInfo,
2232 (*sleBridge)[sfXChainAccountCreateCount] =
2233 (*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.