rippled
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#include <xrpl/tx/transactors/token/MPTokenAuthorize.h>
14
15namespace xrpl {
16
17template <ValidIssueType T>
18TER
20 ApplyView& view,
21 Rate lockedRate,
22 std::shared_ptr<SLE> const& sleDest,
23 STAmount const& xrpBalance,
24 STAmount const& amount,
25 AccountID const& issuer,
26 AccountID const& sender,
27 AccountID const& receiver,
28 bool createAsset,
29 beast::Journal journal);
30
31template <>
32inline TER
34 ApplyView& view,
35 Rate lockedRate,
36 std::shared_ptr<SLE> const& sleDest,
37 STAmount const& xrpBalance,
38 STAmount const& amount,
39 AccountID const& issuer,
40 AccountID const& sender,
41 AccountID const& receiver,
42 bool createAsset,
43 beast::Journal journal)
44{
45 Keylet const trustLineKey = keylet::line(receiver, amount.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 = amount.getCurrency();
69 STAmount initialBalance(amount.issue());
70 initialBalance.setIssuer(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->getFlags() & lsfDefaultRipple) == 0, //
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 != parityRate)
115 {
116 // compute transfer fee, if any
117 auto const xferFee = amount.value() - divideRound(amount, lockedRate, amount.issue(), true);
118 // compute balance to transfer
119 finalAmt = amount.value() - xferFee;
120 }
121
122 // validate the line limit if the account submitting txn is not the receiver
123 // of the funds
124 if (!createAsset)
125 {
126 auto const sleRippleState = view.peek(trustLineKey);
127 if (!sleRippleState)
128 return tecINTERNAL; // LCOV_EXCL_LINE
129
130 // if the issuer is the high, then we use the low limit
131 // otherwise we use the high limit
132 STAmount const lineLimit =
133 sleRippleState->getFieldAmount(recvLow ? sfLowLimit : sfHighLimit);
134
135 STAmount lineBalance = sleRippleState->getFieldAmount(sfBalance);
136
137 // flip the sign of the line balance if the issuer is not high
138 if (!recvLow)
139 lineBalance.negate();
140
141 // add the final amount to the line balance
142 lineBalance += finalAmt;
143
144 // if the transfer would exceed the line limit return tecLIMIT_EXCEEDED
145 if (lineLimit < lineBalance)
146 return tecLIMIT_EXCEEDED;
147 }
148
149 // if destination is not the issuer then transfer funds
150 if (!receiverIssuer)
151 {
152 auto const ter = rippleCredit(view, issuer, receiver, finalAmt, true, journal);
153 if (!isTesSuccess(ter))
154 return ter; // LCOV_EXCL_LINE
155 }
156 return tesSUCCESS;
157}
158
159template <>
160inline TER
162 ApplyView& view,
163 Rate lockedRate,
164 std::shared_ptr<SLE> const& sleDest,
165 STAmount const& xrpBalance,
166 STAmount const& amount,
167 AccountID const& issuer,
168 AccountID const& sender,
169 AccountID const& receiver,
170 bool createAsset,
171 beast::Journal journal)
172{
173 bool const senderIssuer = issuer == sender;
174 bool const receiverIssuer = issuer == receiver;
175
176 auto const mptID = amount.get<MPTIssue>().getMptID();
177 auto const issuanceKey = keylet::mptIssuance(mptID);
178 if (!view.exists(keylet::mptoken(issuanceKey.key, receiver)) && createAsset && !receiverIssuer)
179 {
180 if (std::uint32_t const ownerCount = {sleDest->at(sfOwnerCount)};
181 xrpBalance < view.fees().accountReserve(ownerCount + 1))
182 {
184 }
185
186 if (auto const ter = MPTokenAuthorize::createMPToken(view, mptID, receiver, 0);
187 !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 != parityRate)
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 }
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:40
Stream trace() const
Severity stream access functions.
Definition Journal.h:295
Writeable view to a ledger, for applying a transaction.
Definition ApplyView.h:116
virtual void update(std::shared_ptr< SLE > const &sle)=0
Indicate changes to a peeked SLE.
virtual std::shared_ptr< SLE > peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
A currency issued by an account.
Definition Issue.h:13
static TER createMPToken(ApplyView &view, MPTID const &mptIssuanceID, AccountID const &account, std::uint32_t const flags)
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:120
void setIssuer(AccountID const &uIssuer)
Definition STAmount.h:572
void negate()
Definition STAmount.h:548
Keylet mptIssuance(std::uint32_t seq, AccountID const &issuer) noexcept
Definition Indexes.cpp:474
Keylet line(AccountID const &id0, AccountID const &id1, Currency const &currency) noexcept
The index of a trust line for a given currency.
Definition Indexes.cpp:220
Keylet mptoken(MPTID const &issuanceID, AccountID const &holder) noexcept
Definition Indexes.cpp:486
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
TER rippleUnlockEscrowMPT(ApplyView &view, AccountID const &uGrantorID, AccountID const &uGranteeID, STAmount const &netAmount, STAmount const &grossAmount, beast::Journal j)
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.
TER escrowUnlockApplyHelper< MPTIssue >(ApplyView &view, Rate lockedRate, std::shared_ptr< SLE > const &sleDest, STAmount const &xrpBalance, STAmount const &amount, AccountID const &issuer, AccountID const &sender, AccountID const &receiver, bool createAsset, beast::Journal journal)
TERSubset< CanCvtToTER > TER
Definition TER.h:622
void adjustOwnerCount(ApplyView &view, std::shared_ptr< SLE > const &sle, std::int32_t amount, beast::Journal j)
Adjust the owner count up or down.
Rate transferRate(ReadView const &view, AccountID const &issuer)
Returns IOU issuer transfer fee as Rate.
TER escrowUnlockApplyHelper(ApplyView &view, Rate lockedRate, std::shared_ptr< SLE > const &sleDest, STAmount const &xrpBalance, STAmount const &amount, AccountID const &issuer, AccountID const &sender, AccountID const &receiver, bool createAsset, beast::Journal journal)
AccountID const & noAccount()
A placeholder for empty accounts.
bool isTesSuccess(TER x) noexcept
Definition TER.h:651
TER escrowUnlockApplyHelper< Issue >(ApplyView &view, Rate lockedRate, std::shared_ptr< SLE > const &sleDest, STAmount const &xrpBalance, STAmount const &amount, AccountID const &issuer, AccountID const &sender, AccountID const &receiver, bool createAsset, beast::Journal journal)
@ tecNO_LINE_INSUF_RESERVE
Definition TER.h:273
@ tecINTERNAL
Definition TER.h:291
@ tecNO_LINE
Definition TER.h:282
@ tecINSUFFICIENT_RESERVE
Definition TER.h:288
@ tecLIMIT_EXCEEDED
Definition TER.h:342
@ tecNO_PERMISSION
Definition TER.h:286
STAmount divideRound(STAmount const &amount, Rate const &rate, bool roundUp)
Definition Rate2.cpp:80
@ tesSUCCESS
Definition TER.h:225
Rate const parityRate
A transfer rate signifying a 1:1 exchange.
TER rippleCredit(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, bool bCheckIssuer, beast::Journal j)
Calls static rippleCreditIOU if saAmount represents Issue.
A pair of SHAMap key and LedgerEntryType.
Definition Keylet.h:19
uint256 key
Definition Keylet.h:20
Represents a transfer rate.
Definition Rate.h:20