xrpld
Loading...
Searching...
No Matches
EscrowHelpers.h
1#pragma once
2
3#include <xrpl/basics/Log.h>
4#include <xrpl/ledger/ApplyView.h>
5#include <xrpl/ledger/View.h>
6#include <xrpl/ledger/helpers/AccountRootHelpers.h>
7#include <xrpl/ledger/helpers/MPTokenHelpers.h>
8#include <xrpl/ledger/helpers/RippleStateHelpers.h>
9#include <xrpl/protocol/Feature.h>
10#include <xrpl/protocol/Indexes.h>
11#include <xrpl/protocol/MPTAmount.h>
12#include <xrpl/protocol/Rate.h>
13
14namespace xrpl {
15
16template <ValidIssueType T>
17TER
19 ApplyView& view,
20 Rate lockedRate,
21 SLE::ref sleDest,
22 STAmount const& xrpBalance,
23 STAmount const& amount,
24 AccountID const& issuer,
25 AccountID const& sender,
26 AccountID const& receiver,
27 bool createAsset,
28 beast::Journal journal);
29
30template <>
31inline TER
33 ApplyView& view,
34 Rate lockedRate,
35 SLE::ref sleDest,
36 STAmount const& xrpBalance,
37 STAmount const& amount,
38 AccountID const& issuer,
39 AccountID const& sender,
40 AccountID const& receiver,
41 bool createAsset,
42 beast::Journal journal)
43{
44 Issue const& issue = amount.get<Issue>();
45 Keylet const trustLineKey = keylet::trustLine(receiver, issue);
46 bool const recvLow = issuer > receiver;
47 bool const senderIssuer = issuer == sender;
48 bool const receiverIssuer = issuer == receiver;
49
50 if (senderIssuer)
51 return tecINTERNAL; // LCOV_EXCL_LINE
52
53 if (receiverIssuer)
54 return tesSUCCESS;
55
56 if (!view.exists(trustLineKey) && createAsset)
57 {
58 // Can the account cover the trust line's reserve?
59 if (std::uint32_t const ownerCount = {sleDest->at(sfOwnerCount)};
60 xrpBalance < view.fees().accountReserve(ownerCount + 1))
61 {
62 JLOG(journal.trace()) << "Trust line does not exist. "
63 "Insufficient reserve to create line.";
64
66 }
67
68 Currency const currency = issue.currency;
69 STAmount initialBalance(issue);
70 initialBalance.get<Issue>().account = noAccount();
71
72 if (TER const ter = trustCreate(
73 view, // payment sandbox
74 recvLow, // is dest low?
75 issuer, // source
76 receiver, // destination
77 trustLineKey.key, // ledger index
78 sleDest, // Account to add to
79 false, // authorize account
80 !sleDest->isFlag(lsfDefaultRipple), //
81 false, // freeze trust line
82 false, // deep freeze trust line
83 initialBalance, // zero initial balance
84 Issue(currency, receiver), // limit of zero
85 0, // quality in
86 0, // quality out
87 journal); // journal
88 !isTesSuccess(ter))
89 {
90 return ter; // LCOV_EXCL_LINE
91 }
92
93 view.update(sleDest);
94 }
95
96 if (!view.exists(trustLineKey) && !receiverIssuer)
97 return tecNO_LINE;
98
99 auto const xferRate = transferRate(view, amount);
100 // update if issuer rate is less than locked rate
101 if (xferRate < lockedRate)
102 lockedRate = xferRate;
103
104 // Transfer Rate only applies when:
105 // 1. Issuer is not involved in the transfer (senderIssuer or
106 // receiverIssuer)
107 // 2. The locked rate is different from the parity rate
108
109 // NOTE: Transfer fee in escrow works a bit differently from a normal
110 // payment. In escrow, the fee is deducted from the locked/sending amount,
111 // whereas in a normal payment, the transfer fee is taken on top of the
112 // sending amount.
113 auto finalAmt = amount;
114 if ((!senderIssuer && !receiverIssuer) && lockedRate != kParityRate)
115 {
116 // compute transfer fee, if any
117 auto const xferFee =
118 amount.value() - divideRound(amount, lockedRate, amount.get<Issue>(), true);
119 // compute balance to transfer
120 finalAmt = amount.value() - xferFee;
121 }
122
123 // validate the line limit if the account submitting txn is not the receiver
124 // of the funds
125 if (!createAsset)
126 {
127 auto const sleRippleState = view.peek(trustLineKey);
128 if (!sleRippleState)
129 return tecINTERNAL; // LCOV_EXCL_LINE
130
131 // if the issuer is the high, then we use the low limit
132 // otherwise we use the high limit
133 STAmount const lineLimit =
134 sleRippleState->getFieldAmount(recvLow ? sfLowLimit : sfHighLimit);
135
136 STAmount lineBalance = sleRippleState->getFieldAmount(sfBalance);
137
138 // flip the sign of the line balance if the issuer is not high
139 if (!recvLow)
140 lineBalance.negate();
141
142 // add the final amount to the line balance
143 lineBalance += finalAmt;
144
145 // if the transfer would exceed the line limit return tecLIMIT_EXCEEDED
146 if (lineLimit < lineBalance)
147 return tecLIMIT_EXCEEDED;
148 }
149
150 // if destination is not the issuer then transfer funds
151 if (!receiverIssuer)
152 {
153 auto const ter = directSendNoFee(view, issuer, receiver, finalAmt, true, journal);
154 if (!isTesSuccess(ter))
155 return ter; // LCOV_EXCL_LINE
156 }
157 return tesSUCCESS;
158}
159
160template <>
161inline TER
163 ApplyView& view,
164 Rate lockedRate,
165 SLE::ref sleDest,
166 STAmount const& xrpBalance,
167 STAmount const& amount,
168 AccountID const& issuer,
169 AccountID const& sender,
170 AccountID const& receiver,
171 bool createAsset,
172 beast::Journal journal)
173{
174 bool const senderIssuer = issuer == sender;
175 bool const receiverIssuer = issuer == receiver;
176
177 auto const mptID = amount.get<MPTIssue>().getMptID();
178 auto const issuanceKey = keylet::mptokenIssuance(mptID);
179 if (!view.exists(keylet::mptoken(issuanceKey.key, receiver)) && createAsset && !receiverIssuer)
180 {
181 if (std::uint32_t const ownerCount = {sleDest->at(sfOwnerCount)};
182 xrpBalance < view.fees().accountReserve(ownerCount + 1))
183 {
185 }
186
187 if (auto const ter = createMPToken(view, mptID, receiver, 0); !isTesSuccess(ter))
188 {
189 return ter; // LCOV_EXCL_LINE
190 }
191
192 // update owner count.
193 adjustOwnerCount(view, sleDest, 1, journal);
194 }
195
196 if (!view.exists(keylet::mptoken(issuanceKey.key, receiver)) && !receiverIssuer)
197 return tecNO_PERMISSION;
198
199 auto const xferRate = transferRate(view, amount);
200 // update if issuer rate is less than locked rate
201 if (xferRate < lockedRate)
202 lockedRate = xferRate;
203
204 // Transfer Rate only applies when:
205 // 1. Issuer is not involved in the transfer (senderIssuer or
206 // receiverIssuer)
207 // 2. The locked rate is different from the parity rate
208
209 // NOTE: Transfer fee in escrow works a bit differently from a normal
210 // payment. In escrow, the fee is deducted from the locked/sending amount,
211 // whereas in a normal payment, the transfer fee is taken on top of the
212 // sending amount.
213 auto finalAmt = amount;
214 if ((!senderIssuer && !receiverIssuer) && lockedRate != kParityRate)
215 {
216 // compute transfer fee, if any
217 auto const xferFee = amount.value() - divideRound(amount, lockedRate, amount.asset(), true);
218 // compute balance to transfer
219 finalAmt = amount.value() - xferFee;
220 }
221 return unlockEscrowMPT(
222 view,
223 sender,
224 receiver,
225 finalAmt,
226 view.rules().enabled(fixTokenEscrowV1) ? amount : finalAmt,
227 journal);
228}
229
230} // namespace xrpl
A generic endpoint for log messages.
Definition Journal.h:38
Stream trace() const
Severity stream access functions.
Definition Journal.h:291
Writeable view to a ledger, for applying a transaction.
Definition ApplyView.h:118
virtual SLE::pointer peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
virtual void update(SLE::ref sle)=0
Indicate changes to a peeked SLE.
A currency issued by an account.
Definition Issue.h:13
Currency currency
Definition Issue.h:15
virtual Rules const & rules() const =0
Returns the tx processing rules.
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.
Definition Rules.cpp:171
constexpr TIss const & get() const
void negate()
Definition STAmount.h:568
Asset const & asset() const
Definition STAmount.h:478
STAmount const & value() const noexcept
Definition STAmount.h:592
std::shared_ptr< STLedgerEntry > const & ref
Keylet mptokenIssuance(std::uint32_t seq, AccountID const &issuer) noexcept
Definition Indexes.cpp:521
Keylet mptoken(MPTID const &issuanceID, AccountID const &holder) noexcept
Definition Indexes.cpp:533
Keylet trustLine(AccountID const &id0, AccountID const &id1, Currency const &currency) noexcept
The index of a trust line for a given currency.
Definition Indexes.cpp:241
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
TER escrowUnlockApplyHelper(ApplyView &view, Rate lockedRate, SLE::ref sleDest, STAmount const &xrpBalance, STAmount const &amount, AccountID const &issuer, AccountID const &sender, AccountID const &receiver, bool createAsset, beast::Journal journal)
TER trustCreate(ApplyView &view, bool const bSrcHigh, AccountID const &uSrcAccountID, AccountID const &uDstAccountID, uint256 const &uIndex, SLE::ref sleAccount, bool const bAuth, bool const bNoRipple, bool const bFreeze, bool bDeepFreeze, STAmount const &saBalance, STAmount const &saLimit, std::uint32_t uQualityIn, std::uint32_t uQualityOut, beast::Journal j)
Create a trust line.
BaseUInt< 160, detail::CurrencyTag > Currency
Currency is a hash representing a specific currency.
Definition UintTypes.h:36
TER unlockEscrowMPT(ApplyView &view, AccountID const &uGrantorID, AccountID const &uGranteeID, STAmount const &netAmount, STAmount const &grossAmount, beast::Journal j)
TER createMPToken(ApplyView &view, MPTID const &mptIssuanceID, AccountID const &account, std::uint32_t const flags)
Rate transferRate(ReadView const &view, AccountID const &issuer)
Returns IOU issuer transfer fee as Rate.
Rate const kParityRate
A transfer rate signifying a 1:1 exchange.
TER directSendNoFee(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, bool bCheckIssuer, beast::Journal j)
Calls static directSendNoFeeIOU if saAmount represents Issue.
void adjustOwnerCount(ApplyView &view, SLE::ref sle, std::int32_t amount, beast::Journal j)
Adjust the owner count up or down.
TER escrowUnlockApplyHelper< MPTIssue >(ApplyView &view, Rate lockedRate, SLE::ref sleDest, STAmount const &xrpBalance, STAmount const &amount, AccountID const &issuer, AccountID const &sender, AccountID const &receiver, bool createAsset, beast::Journal journal)
BaseUInt< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
Definition AccountID.h:28
AccountID const & noAccount()
A placeholder for empty accounts.
TER escrowUnlockApplyHelper< Issue >(ApplyView &view, Rate lockedRate, SLE::ref sleDest, STAmount const &xrpBalance, STAmount const &amount, AccountID const &issuer, AccountID const &sender, AccountID const &receiver, bool createAsset, beast::Journal journal)
bool isTesSuccess(TER x) noexcept
Definition TER.h:663
TERSubset< CanCvtToTER > TER
Definition TER.h:634
@ tecNO_LINE_INSUF_RESERVE
Definition TER.h:290
@ tecINTERNAL
Definition TER.h:308
@ tecNO_LINE
Definition TER.h:299
@ tecINSUFFICIENT_RESERVE
Definition TER.h:305
@ tecLIMIT_EXCEEDED
Definition TER.h:359
@ tecNO_PERMISSION
Definition TER.h:303
STAmount divideRound(STAmount const &amount, Rate const &rate, bool roundUp)
Definition Rate2.cpp:80
@ tesSUCCESS
Definition TER.h:240
A pair of SHAMap key and LedgerEntryType.
Definition Keylet.h:19
Represents a transfer rate.
Definition Rate.h:20