1#include <xrpl/basics/Log.h>
2#include <xrpl/basics/Number.h>
3#include <xrpl/basics/chrono.h>
4#include <xrpl/beast/utility/Journal.h>
5#include <xrpl/beast/utility/instrumentation.h>
6#include <xrpl/ledger/ApplyView.h>
7#include <xrpl/ledger/PaymentSandbox.h>
8#include <xrpl/ledger/helpers/AccountRootHelpers.h>
9#include <xrpl/ledger/helpers/DirectoryHelpers.h>
10#include <xrpl/protocol/AccountID.h>
11#include <xrpl/protocol/Feature.h>
12#include <xrpl/protocol/Indexes.h>
13#include <xrpl/protocol/PublicKey.h>
14#include <xrpl/protocol/SField.h>
15#include <xrpl/protocol/STAmount.h>
16#include <xrpl/protocol/STObject.h>
17#include <xrpl/protocol/STXChainBridge.h>
18#include <xrpl/protocol/TER.h>
19#include <xrpl/protocol/TxFlags.h>
20#include <xrpl/protocol/XChainAttestations.h>
21#include <xrpl/protocol/XRPAmount.h>
22#include <xrpl/tx/SignerEntries.h>
23#include <xrpl/tx/Transactor.h>
24#include <xrpl/tx/paths/Flow.h>
25#include <xrpl/tx/transactors/bridge/XChainBridge.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) & lsfDisableMaster) != 0u)
114 JLOG(j.
trace()) <<
"Attempt to add an attestation with "
115 "disabled master key.";
123 (*sleAttestationSigningAccount)[~sfRegularKey];
124 regularKey != accountFromPK)
128 JLOG(j.
trace()) <<
"Attempt to add an attestation with "
129 "account present and non-present regular key.";
133 JLOG(j.
trace()) <<
"Attempt to add an attestation with "
134 "account present and mismatched "
135 "regular key/public key.";
146 JLOG(j.
trace()) <<
"Attempt to add an attestation with non-existant account "
147 "and mismatched pk/account pair.";
166enum class CheckDst {
check, ignore };
167template <
class TAttestation>
168Expected<std::vector<AccountID>,
TER>
170 XChainAttestationsBase<TAttestation>& attestations,
171 ReadView
const& view,
172 typename TAttestation::MatchFields
const& toMatch,
181 attestations.erase_if([&](
auto const& a) {
182 return checkAttestationPublicKey(view, signersList, a.keyAccount, a.publicKey, j) !=
188 rewardAccounts.reserve(attestations.size());
190 for (
auto const& a : attestations)
192 auto const matchR = a.match(toMatch);
199 auto i = signersList.
find(a.keyAccount);
200 if (i == signersList.
end())
203 UNREACHABLE(
"xrpl::claimHelper : invalid inputs");
209 rewardAccounts.push_back(a.rewardAccount);
212 if (weight >= quorum)
213 return rewardAccounts;
249struct OnNewAttestationResult
257template <
class TAttestation>
258[[nodiscard]] OnNewAttestationResult
260 XChainAttestationsBase<TAttestation>& attestations,
261 ReadView
const& view,
262 typename TAttestation::TSignedAttestation
const* attBegin,
263 typename TAttestation::TSignedAttestation
const* attEnd,
268 bool changed =
false;
269 for (
auto att = attBegin; att != attEnd; ++att)
271 auto const ter = checkAttestationPublicKey(
272 view, signersList, att->attestationSignerAccount, att->publicKey, j);
282 auto const& claimSigningAccount = att->attestationSignerAccount;
284 attestations.begin(),
286 [&](
auto const& a) { return a.keyAccount == claimSigningAccount; });
287 i != attestations.end())
291 *i = TAttestation{*att};
296 attestations.emplace_back(*att);
301 auto r = claimHelper(
304 typename TAttestation::MatchFields{*attBegin},
313 return {std::move(r.value()), changed};
319Expected<std::vector<AccountID>,
TER>
321 XChainClaimAttestations& attestations,
322 ReadView
const& view,
323 STAmount
const& sendingAmount,
324 bool wasLockingChainSend,
329 XChainClaimAttestation::MatchFields
const toMatch{
331 return claimHelper(attestations, view, toMatch, CheckDst::ignore, quorum, signersList, j);
334enum class CanCreateDstPolicy {
no,
yes };
336enum class DepositAuthPolicy { normal, dstCanBypass };
340struct TransferHelperSubmittingAccountInfo
343 STAmount preFeeBalance_;
344 STAmount postFeeBalance;
377 CanCreateDstPolicy canCreate,
378 DepositAuthPolicy depositAuthPolicy,
386 if (
auto sleDst = psb.read(dstK))
390 if (((sleDst->getFlags() & lsfRequireDestTag) != 0u) && !dstTag)
396 bool const canBypassDepositAuth =
397 dst == claimOwner && depositAuthPolicy == DepositAuthPolicy::dstCanBypass;
399 if (!canBypassDepositAuth && ((sleDst->getFlags() & lsfDepositAuth) != 0u) &&
405 else if (!amt.native() || canCreate == CanCreateDstPolicy::no)
413 XRPL_ASSERT(sleSrc,
"xrpl::transferHelper : non-null source account");
418 auto const ownerCount = sleSrc->getFieldU32(sfOwnerCount);
419 auto const reserve = psb.fees().accountReserve(ownerCount);
421 auto const availableBalance = [&]() -> STAmount {
422 STAmount curBal = (*sleSrc)[sfBalance];
426 if (!submittingAccountInfo || submittingAccountInfo->account != src ||
427 submittingAccountInfo->postFeeBalance != curBal)
429 return submittingAccountInfo->preFeeBalance_;
432 if (availableBalance < amt + reserve)
438 auto sleDst = psb.peek(dstK);
441 if (canCreate == CanCreateDstPolicy::no)
446 if (amt < psb.fees().reserve)
448 JLOG(j.
trace()) <<
"Insufficient payment to create account.";
454 sleDst->setAccountID(sfAccount, dst);
455 sleDst->setFieldU32(sfSequence, psb.seq());
460 (*sleSrc)[sfBalance] = (*sleSrc)[sfBalance] - amt;
461 (*sleDst)[sfBalance] = (*sleDst)[sfBalance] + amt;
468 auto const result =
flow(
493enum class OnTransferFail {
500struct FinalizeClaimHelperResult
528 return *mainFundsTer;
537 return *mainFundsTer;
574FinalizeClaimHelperResult
576 PaymentSandbox& outerSb,
577 STXChainBridge
const& bridgeSpec,
581 STAmount
const& sendingAmount,
583 STAmount
const& rewardPool,
586 Keylet
const& claimIDKeylet,
587 OnTransferFail onTransferFail,
588 DepositAuthPolicy depositAuthPolicy,
591 FinalizeClaimHelperResult result;
594 STAmount
const thisChainAmount = [&] {
595 STAmount r = sendingAmount;
596 r.setIssue(bridgeSpec.issue(dstChain));
599 auto const& thisDoor = bridgeSpec.door(dstChain);
602 PaymentSandbox innerSb{&outerSb};
613 result.mainFundsTer = transferHelper(
620 CanCreateDstPolicy::yes,
625 if (!
isTesSuccess(*result.mainFundsTer) && onTransferFail == OnTransferFail::keepClaim)
631 result.rewardTer = [&]() ->
TER {
632 if (rewardAccounts.empty())
638 STAmount
const share = [&] {
639 auto const round_mode = innerSb.rules().enabled(fixXChainRewardRounding)
644 STAmount
const den{rewardAccounts.size()};
645 return divide(rewardPool, den, rewardPool.issue());
647 STAmount distributed = rewardPool.zeroed();
648 for (
auto const& rewardAccount : rewardAccounts)
650 auto const thTer = transferHelper(
658 CanCreateDstPolicy::no,
659 DepositAuthPolicy::normal,
667 distributed += share;
673 if (distributed > rewardPool)
680 (onTransferFail == OnTransferFail::keepClaim || *result.rewardTer ==
tecINTERNAL))
690 innerSb.apply(outerSb);
694 if (
auto const sleClaimID = outerSb.peek(claimIDKeylet))
696 auto const cidOwner = (*sleClaimID)[sfAccount];
700 auto const page = (*sleClaimID)[sfOwnerNode];
703 JLOG(j.
fatal()) <<
"Unable to delete xchain seq number from owner.";
709 outerSb.erase(sleClaimID);
728getSignersListAndQuorum(ReadView
const& view,
SLE const& sleBridge,
beast::Journal j)
733 AccountID const thisDoor = sleBridge[sfAccount];
734 auto const sleDoor = [&] {
return view.read(
keylet::account(thisDoor)); }();
746 q = (*sleS)[sfSignerQuorum];
755 for (
auto const& as : *accountSigners)
757 r[as.account] = as.weight;
763template <
class R,
class F>
765readOrpeekBridge(F&& getter, STXChainBridge
const& bridgeSpec)
768 if (
auto r = getter(bridgeSpec, ct))
770 if ((*r)[sfXChainBridge] == bridgeSpec)
781peekBridge(ApplyView& v, STXChainBridge
const& bridgeSpec)
783 return readOrpeekBridge<SLE>(
791readBridge(ReadView
const& v, STXChainBridge
const& bridgeSpec)
793 return readOrpeekBridge<SLE const>(
802template <
class TIter>
804applyClaimAttestations(
809 STXChainBridge
const& bridgeSpec,
815 if (attBegin == attEnd)
818 PaymentSandbox psb(&view);
824 OnNewAttestationResult newAttResult;
825 STAmount rewardAmount;
829 auto const scopeResult = [&]() -> Expected<ScopeResult, TER> {
834 auto const sleClaimID = psb.peek(claimIDKeylet);
841 for (
auto att = attBegin; att != attEnd; ++att)
843 if (!signersList.
contains(att->attestationSignerAccount))
853 AccountID const otherChainSource = (*sleClaimID)[sfOtherChainSource];
854 if (attBegin->sendingAccount != otherChainSource)
865 if (attDstChain != dstChain)
871 XChainClaimAttestations curAtts{sleClaimID->getFieldArray(sfXChainClaimAttestations)};
873 auto const newAttResult = onNewAttestations(
877 &atts[0] + atts.
size(),
883 sleClaimID->setFieldArray(sfXChainClaimAttestations, curAtts.toSTArray());
884 psb.update(sleClaimID);
887 newAttResult, (*sleClaimID)[sfSignatureReward], (*sleClaimID)[sfAccount]};
890 if (!scopeResult.has_value())
891 return scopeResult.error();
893 auto const& [newAttResult, rewardAmount, cidOwner] = scopeResult.value();
894 auto const& [rewardAccounts, attListChanged] = newAttResult;
895 if (rewardAccounts && attBegin->dst)
897 auto const r = finalizeClaimHelper(
903 attBegin->sendingAmount,
909 OnTransferFail::keepClaim,
910 DepositAuthPolicy::normal,
913 auto const rTer = r.ter();
925template <
class TIter>
927applyCreateAccountAttestations(
934 STXChainBridge
const& bridgeSpec,
935 Keylet
const& bridgeK,
941 if (attBegin == attEnd)
944 PaymentSandbox psb(&view);
946 auto const claimCountResult = [&]() -> Expected<std::uint64_t, TER> {
947 auto const sleBridge = psb.peek(bridgeK);
951 return (*sleBridge)[sfXChainAccountClaimCount];
954 if (!claimCountResult.has_value())
955 return claimCountResult.error();
959 if (attBegin->createCount <= claimCount)
975 if (attDstChain != dstChain)
981 auto const claimIDKeylet =
986 OnNewAttestationResult newAttResult;
988 XChainCreateAccountAttestations curAtts;
991 auto const scopeResult = [&]() -> Expected<ScopeResult, TER> {
999 auto const sleClaimID = psb.peek(claimIDKeylet);
1000 bool createCID =
false;
1005 auto const sleDoor = psb.peek(doorK);
1010 auto const balance = (*sleDoor)[sfBalance];
1011 auto const reserve = psb.fees().accountReserve((*sleDoor)[sfOwnerCount] + 1);
1013 if (balance < reserve)
1019 for (
auto att = attBegin; att != attEnd; ++att)
1021 if (!signersList.
contains(att->attestationSignerAccount))
1030 XChainCreateAccountAttestations curAtts = [&] {
1033 return XChainCreateAccountAttestations{
1034 sleClaimID->getFieldArray(sfXChainCreateAccountAttestations)};
1036 return XChainCreateAccountAttestations{};
1039 auto const newAttResult = onNewAttestations(
1043 &atts[0] + atts.
size(),
1054 sleClaimID->setFieldArray(sfXChainCreateAccountAttestations, curAtts.toSTArray());
1055 psb.update(sleClaimID);
1057 return ScopeResult{newAttResult, createCID, curAtts};
1060 if (!scopeResult.has_value())
1061 return scopeResult.error();
1063 auto const& [attResult, createCID, curAtts] = scopeResult.value();
1064 auto const& [rewardAccounts, attListChanged] = attResult;
1067 if (rewardAccounts && claimCount + 1 == attBegin->createCount)
1069 auto const r = finalizeClaimHelper(
1075 attBegin->sendingAmount,
1077 attBegin->rewardAmount,
1081 OnTransferFail::removeClaim,
1082 DepositAuthPolicy::normal,
1085 auto const rTer = r.ter();
1094 auto const sleBridge = psb.peek(bridgeK);
1097 (*sleBridge)[sfXChainAccountClaimCount] = attBegin->createCount;
1098 psb.update(sleBridge);
1103 (*createdSleClaimID)[sfAccount] = doorAccount;
1104 (*createdSleClaimID)[sfXChainBridge] = bridgeSpec;
1105 (*createdSleClaimID)[sfXChainAccountCreateCount] = attBegin->createCount;
1106 createdSleClaimID->setFieldArray(sfXChainCreateAccountAttestations, curAtts.toSTArray());
1109 auto const page = psb.dirInsert(
1113 (*createdSleClaimID)[sfOwnerNode] = *
page;
1115 auto const sleDoor = psb.peek(doorK);
1121 psb.insert(createdSleClaimID);
1122 psb.update(sleDoor);
1130template <
class TAttestation>
1132toClaim(STTx
const& tx)
1141 o.setAccountID(sfAccount, o[sfOtherChainSource]);
1142 return TAttestation(o);
1150template <
class TAttestation>
1152attestationPreflight(PreflightContext
const& ctx)
1157 auto const att = toClaim<TAttestation>(ctx.tx);
1161 STXChainBridge
const bridgeSpec = ctx.tx[sfXChainBridge];
1162 if (!att->verify(bridgeSpec))
1164 if (!att->validAmounts())
1167 if (att->sendingAmount.signum() <= 0)
1170 if (att->sendingAmount.issue() != expectedIssue)
1176template <
class TAttestation>
1178attestationPreclaim(PreclaimContext
const& ctx)
1180 auto const att = toClaim<TAttestation>(ctx.tx);
1185 STXChainBridge
const bridgeSpec = ctx.tx[sfXChainBridge];
1186 auto const sleBridge = readBridge(ctx.view, bridgeSpec);
1192 AccountID const attestationSignerAccount{ctx.tx[sfAttestationSignerAccount]};
1193 PublicKey
const pk{ctx.tx[sfPublicKey]};
1196 auto const [signersList, quorum, slTer] = getSignersListAndQuorum(ctx.view, *sleBridge, ctx.j);
1201 return checkAttestationPublicKey(ctx.view, signersList, attestationSignerAccount, pk, ctx.j);
1204template <
class TAttestation>
1206attestationDoApply(ApplyContext& ctx)
1208 auto const att = toClaim<TAttestation>(ctx.tx);
1215 STXChainBridge
const bridgeSpec = ctx.tx[sfXChainBridge];
1219 STXChainBridge::ChainType srcChain = STXChainBridge::ChainType::locking;
1226 auto const scopeResult = [&]() -> Expected<ScopeResult, TER> {
1231 auto sleBridge = readBridge(ctx.view(), bridgeSpec);
1236 Keylet
const bridgeK{ltBRIDGE, sleBridge->key()};
1237 AccountID const thisDoor = (*sleBridge)[sfAccount];
1241 if (thisDoor == bridgeSpec.lockingChainDoor())
1245 else if (thisDoor == bridgeSpec.issuingChainDoor())
1257 auto [signersList, quorum, slTer] =
1258 getSignersListAndQuorum(ctx.view(), *sleBridge, ctx.journal);
1263 return ScopeResult{srcChain, std::move(signersList), quorum, thisDoor, bridgeK};
1266 if (!scopeResult.has_value())
1267 return scopeResult.error();
1269 auto const& [srcChain, signersList, quorum, thisDoor, bridgeK] = scopeResult.value();
1277 return applyClaimAttestations(
1290 return applyCreateAccountAttestations(
1312 auto const account = ctx.
tx[sfAccount];
1313 auto const reward = ctx.
tx[sfSignatureReward];
1314 auto const minAccountCreate = ctx.
tx[~sfMinAccountCreateAmount];
1315 auto const bridgeSpec = ctx.
tx[sfXChainBridge];
1317 if (bridgeSpec.lockingChainDoor() == bridgeSpec.issuingChainDoor())
1322 if (bridgeSpec.lockingChainDoor() != account && bridgeSpec.issuingChainDoor() != account)
1327 if (
isXRP(bridgeSpec.lockingChainIssue()) !=
isXRP(bridgeSpec.issuingChainIssue()))
1334 if (!
isXRP(reward) || reward.signum() < 0)
1339 if (minAccountCreate &&
1340 ((!
isXRP(*minAccountCreate) || minAccountCreate->signum() <= 0) ||
1341 !
isXRP(bridgeSpec.lockingChainIssue()) || !
isXRP(bridgeSpec.issuingChainIssue())))
1346 if (
isXRP(bridgeSpec.issuingChainIssue()))
1353 if (bridgeSpec.issuingChainDoor() != rootAccount)
1362 if (bridgeSpec.issuingChainDoor() != bridgeSpec.issuingChainIssue().account)
1368 if (bridgeSpec.lockingChainDoor() == bridgeSpec.lockingChainIssue().account)
1381 auto const account = ctx.
tx[sfAccount];
1382 auto const bridgeSpec = ctx.
tx[sfXChainBridge];
1398 if (!
isXRP(bridgeSpec.issue(chainType)))
1407 if ((sleIssuer->getFlags() & lsfAllowTrustLineClawback) != 0u)
1417 auto const balance = (*sleAcc)[sfBalance];
1420 if (balance < reserve)
1430 auto const account =
ctx_.
tx[sfAccount];
1431 auto const bridgeSpec =
ctx_.
tx[sfXChainBridge];
1432 auto const reward =
ctx_.
tx[sfSignatureReward];
1433 auto const minAccountCreate =
ctx_.
tx[~sfMinAccountCreateAmount];
1445 (*sleBridge)[sfAccount] = account;
1446 (*sleBridge)[sfSignatureReward] = reward;
1447 if (minAccountCreate)
1448 (*sleBridge)[sfMinAccountCreateAmount] = *minAccountCreate;
1449 (*sleBridge)[sfXChainBridge] = bridgeSpec;
1450 (*sleBridge)[sfXChainClaimID] = 0;
1451 (*sleBridge)[sfXChainAccountCreateCount] = 0;
1452 (*sleBridge)[sfXChainAccountClaimCount] = 0;
1460 (*sleBridge)[sfOwnerNode] = *page;
1476 return tfXChainModifyBridgeMask;
1482 auto const account = ctx.
tx[sfAccount];
1483 auto const reward = ctx.
tx[~sfSignatureReward];
1484 auto const minAccountCreate = ctx.
tx[~sfMinAccountCreateAmount];
1485 auto const bridgeSpec = ctx.
tx[sfXChainBridge];
1486 bool const clearAccountCreate = (ctx.
tx.
getFlags() & tfClearAccountCreateAmount) != 0u;
1488 if (!reward && !minAccountCreate && !clearAccountCreate)
1494 if (minAccountCreate && clearAccountCreate)
1500 if (bridgeSpec.lockingChainDoor() != account && bridgeSpec.issuingChainDoor() != account)
1505 if (reward && (!
isXRP(*reward) || reward->signum() < 0))
1510 if (minAccountCreate &&
1511 ((!
isXRP(*minAccountCreate) || minAccountCreate->signum() <= 0) ||
1512 !
isXRP(bridgeSpec.lockingChainIssue()) || !
isXRP(bridgeSpec.issuingChainIssue())))
1523 auto const account = ctx.
tx[sfAccount];
1524 auto const bridgeSpec = ctx.
tx[sfXChainBridge];
1540 auto const account =
ctx_.
tx[sfAccount];
1541 auto const bridgeSpec =
ctx_.
tx[sfXChainBridge];
1542 auto const reward =
ctx_.
tx[~sfSignatureReward];
1543 auto const minAccountCreate =
ctx_.
tx[~sfMinAccountCreateAmount];
1544 bool const clearAccountCreate = (
ctx_.
tx.
getFlags() & tfClearAccountCreateAmount) != 0u;
1558 (*sleBridge)[sfSignatureReward] = *reward;
1559 if (minAccountCreate)
1561 (*sleBridge)[sfMinAccountCreateAmount] = *minAccountCreate;
1563 if (clearAccountCreate && sleBridge->isFieldPresent(sfMinAccountCreateAmount))
1565 sleBridge->makeFieldAbsent(sfMinAccountCreateAmount);
1578 auto const amount = ctx.
tx[sfAmount];
1580 if (amount.signum() <= 0 ||
1595 STAmount const& thisChainAmount = ctx.
tx[sfAmount];
1596 auto const claimID = ctx.
tx[sfXChainClaimID];
1598 auto const sleBridge = readBridge(ctx.
view, bridgeSpec);
1609 auto const thisDoor = (*sleBridge)[sfAccount];
1610 bool isLockingChain =
false;
1614 isLockingChain =
true;
1618 isLockingChain =
false;
1649 auto const otherChainAmount = [&]() ->
STAmount {
1671 if ((*sleClaimID)[sfAccount] != account)
1688 auto const dst =
ctx_.
tx[sfDestination];
1691 auto const claimID =
ctx_.
tx[sfXChainClaimID];
1710 auto const sleBridge = peekBridge(psb, bridgeSpec);
1711 auto const sleClaimID = psb.
peek(claimIDKeylet);
1713 if (!(sleBridge && sleClaimID && sleAcct))
1716 AccountID const thisDoor = (*sleBridge)[sfAccount];
1735 auto const sendingAmount = [&]() ->
STAmount {
1741 auto const [signersList, quorum, slTer] =
1749 auto const claimR = onClaim(
1757 if (!claimR.has_value())
1762 (*sleClaimID)[sfAccount],
1765 (*sleClaimID)[sfSignatureReward],
1769 if (!scopeResult.has_value())
1770 return scopeResult.error();
1772 auto const& [rewardAccounts, rewardPoolSrc, sendingAmount, srcChain, signatureReward] =
1773 scopeResult.value();
1776 auto const r = finalizeClaimHelper(
1788 OnTransferFail::keepClaim,
1789 DepositAuthPolicy::dstCanBypass,
1791 if (!r.isTesSuccess())
1804 auto const maxSpend = [&] {
1805 auto const amount = ctx.
tx[sfAmount];
1806 if (amount.native() && amount.signum() > 0)
1807 return amount.xrp();
1817 auto const amount = ctx.
tx[sfAmount];
1818 auto const bridgeSpec = ctx.
tx[sfXChainBridge];
1820 if (amount.signum() <= 0 || !
isLegalNet(amount))
1823 if (amount.issue() != bridgeSpec.lockingChainIssue() &&
1824 amount.issue() != bridgeSpec.issuingChainIssue())
1833 auto const bridgeSpec = ctx.
tx[sfXChainBridge];
1834 auto const amount = ctx.
tx[sfAmount];
1836 auto const sleBridge = readBridge(ctx.
view, bridgeSpec);
1842 AccountID const thisDoor = (*sleBridge)[sfAccount];
1845 if (thisDoor == account)
1851 bool isLockingChain =
false;
1853 if (thisDoor == bridgeSpec.lockingChainDoor())
1855 isLockingChain =
true;
1857 else if (thisDoor == bridgeSpec.issuingChainDoor())
1859 isLockingChain =
false;
1869 if (bridgeSpec.lockingChainIssue() != ctx.
tx[sfAmount].issue())
1874 if (bridgeSpec.issuingChainIssue() != ctx.
tx[sfAmount].issue())
1886 auto const account =
ctx_.
tx[sfAccount];
1887 auto const amount =
ctx_.
tx[sfAmount];
1888 auto const bridgeSpec =
ctx_.
tx[sfXChainBridge];
1894 auto const sleBridge = readBridge(psb, bridgeSpec);
1898 auto const dst = (*sleBridge)[sfAccount];
1901 TransferHelperSubmittingAccountInfo submittingAccountInfo{
1904 auto const thTer = transferHelper(
1911 CanCreateDstPolicy::no,
1912 DepositAuthPolicy::normal,
1913 submittingAccountInfo,
1929 auto const reward = ctx.
tx[sfSignatureReward];
1940 auto const account = ctx.
tx[sfAccount];
1941 auto const bridgeSpec = ctx.
tx[sfXChainBridge];
1942 auto const sleBridge = readBridge(ctx.
view, bridgeSpec);
1950 auto const reward = ctx.
tx[sfSignatureReward];
1952 if (reward != (*sleBridge)[sfSignatureReward])
1963 auto const balance = (*sleAcc)[sfBalance];
1966 if (balance < reserve)
1976 auto const account =
ctx_.
tx[sfAccount];
1977 auto const bridgeSpec =
ctx_.
tx[sfXChainBridge];
1978 auto const reward =
ctx_.
tx[sfSignatureReward];
1979 auto const otherChainSrc =
ctx_.
tx[sfOtherChainSource];
1985 auto const sleBridge = peekBridge(
ctx_.
view(), bridgeSpec);
1989 std::uint32_t const claimID = (*sleBridge)[sfXChainClaimID] + 1;
1996 (*sleBridge)[sfXChainClaimID] = claimID;
2007 (*sleClaimID)[sfAccount] = account;
2008 (*sleClaimID)[sfXChainBridge] = bridgeSpec;
2009 (*sleClaimID)[sfXChainClaimID] = claimID;
2010 (*sleClaimID)[sfOtherChainSource] = otherChainSrc;
2011 (*sleClaimID)[sfSignatureReward] = reward;
2012 sleClaimID->setFieldArray(sfXChainClaimAttestations,
STArray{sfXChainClaimAttestations});
2020 (*sleClaimID)[sfOwnerNode] = *page;
2037 return attestationPreflight<Attestations::AttestationClaim>(ctx);
2043 return attestationPreclaim<Attestations::AttestationClaim>(ctx);
2049 return attestationDoApply<Attestations::AttestationClaim>(
ctx_);
2057 return attestationPreflight<Attestations::AttestationCreateAccount>(ctx);
2063 return attestationPreclaim<Attestations::AttestationCreateAccount>(ctx);
2069 return attestationDoApply<Attestations::AttestationCreateAccount>(
ctx_);
2077 auto const amount = ctx.
tx[sfAmount];
2079 if (amount.signum() <= 0 || !amount.native())
2082 auto const reward = ctx.
tx[sfSignatureReward];
2083 if (reward.signum() < 0 || !reward.native())
2086 if (reward.issue() != amount.issue())
2097 STAmount const reward = ctx.
tx[sfSignatureReward];
2099 auto const sleBridge = readBridge(ctx.
view, bridgeSpec);
2105 if (reward != (*sleBridge)[sfSignatureReward])
2112 if (!minCreateAmount)
2115 if (amount < *minCreateAmount)
2118 if (minCreateAmount->issue() != amount.issue())
2121 AccountID const thisDoor = (*sleBridge)[sfAccount];
2123 if (thisDoor == account)
2146 if (bridgeSpec.
issue(srcChain) != ctx.
tx[sfAmount].issue())
2169 auto const sleBridge = peekBridge(psb, bridge);
2173 auto const dst = (*sleBridge)[sfAccount];
2176 TransferHelperSubmittingAccountInfo submittingAccountInfo{
2178 STAmount const toTransfer = amount + reward;
2179 auto const thTer = transferHelper(
2186 CanCreateDstPolicy::yes,
2187 DepositAuthPolicy::normal,
2188 submittingAccountInfo,
2194 (*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.
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)
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.
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)
Returns a function that sets the owner on a directory SLE.
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
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.