Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions include/xrpl/ledger/helpers/RepoHelpers.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#pragma once

#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Asset.h>
#include <xrpl/protocol/STAmount.h>
#include <xrpl/protocol/STLedgerEntry.h>
#include <xrpl/protocol/TER.h>

#include <cstdint>

namespace xrpl {
namespace repo {

/**
* Seconds in a year, the denominator of the annualized interest rate.
*/

/**
* A repo is active once the buyer has accepted it, which is recorded by
* sfStartDate. Before that it is a pending offer.
*/
[[nodiscard]] inline bool
isActive(SLE::const_ref sleRepo)
{
return sleRepo->isFieldPresent(sfStartDate);
}

/**
* The amount the seller owes to repurchase the collateral.
*
* PurchasePrice * (1 + InterestRate * elapsed / kSecondsInYear), where elapsed
* runs from StartDate to the close time, capped at MaturityDate so the seller
* never pays for time past maturity. Computed in Number and rounded up, so
* rounding never favours the seller.
*/
[[nodiscard]] STAmount
repurchaseAmount(SLE::const_ref sleRepo, std::uint32_t closeTime);

/**
* Lock the collateral out of the seller's spendable balance.
*
* XRP is deducted from the account balance by the caller; this handles the
* issued-asset cases the same way an escrow does.
*/
[[nodiscard]] TER
lockCollateral(
ApplyView& view,
AccountID const& issuer,
AccountID const& seller,
STAmount const& amount,
beast::Journal journal);

/**
* The XLS-85 checks that decide whether collateral may be locked at all.
*
* Both parties are checked, not just the seller: the buyer receives the
* collateral if the repo defaults, so an unauthorized or frozen buyer would
* leave the collateral unable to move at exactly the moment it must.
*/
[[nodiscard]] TER
checkCollateral(
ReadView const& view,
AccountID const& seller,
AccountID const& buyer,
STAmount const& collateral,
beast::Journal journal);

/**
* Return the locked collateral to an account and remove the entry.
*
* Used by cancel, close and default; they differ only in who receives the
* collateral and whether any cash moved first.
*/
[[nodiscard]] TER
releaseAndDelete(
ApplyViewContext ctx,
SLE::ref sleRepo,
AccountID const& receiver,
beast::Journal journal);

} // namespace repo
} // namespace xrpl
12 changes: 12 additions & 0 deletions include/xrpl/protocol/Indexes.h
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,18 @@ vault(uint256 const& vaultKey)
Keylet
loanBroker(AccountID const& owner, SeqProxy const& seq) noexcept;

/**
* A repurchase agreement, keyed by the seller and the creating sequence.
*/
Keylet
repo(AccountID const& seller, SeqProxy const& seq) noexcept;

inline Keylet
repo(uint256 const& repoID)
{
return {ltREPO, repoID};
}

inline Keylet
loanBroker(uint256 const& key)
{
Expand Down
2 changes: 2 additions & 0 deletions include/xrpl/protocol/TER.h
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,8 @@ enum TECcodes : TERUnderlyingType {
tecNO_SPONSOR_PERMISSION = 200,
tecOUT_OF_GAS = 201,
tecBYTECODE_REJECTED = 202,
tecREPO_ACTIVE = 211,
tecREPO_PENDING = 212,
};

//------------------------------------------------------------------------------
Expand Down
1 change: 1 addition & 0 deletions include/xrpl/protocol/detail/features.macro
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
// Add new amendments to the top of this list.
// Keep it sorted in reverse chronological order.

XRPL_FEATURE(Repo, Supported::No, VoteBehavior::DefaultNo)
XRPL_FEATURE(SmartEscrow, Supported::No, VoteBehavior::DefaultNo)
XRPL_FEATURE(LendingProtocolV1_2, Supported::No, VoteBehavior::DefaultNo)
XRPL_FIX (Cleanup3_5_0, Supported::Yes, VoteBehavior::DefaultNo)
Expand Down
24 changes: 24 additions & 0 deletions include/xrpl/protocol/detail/ledger_entries.macro
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,30 @@ LEDGER_ENTRY(ltVAULT, 0x0084, Vault, vault, ({
// no PermissionedDomainID ever (use MPTIssuance.sfDomainID)
}))

/**
* A bilateral repurchase agreement. The seller locks collateral and receives
* cash; the entry is pending until the buyer accepts, active thereafter.
* \sa keylet::repo
*/
LEDGER_ENTRY(ltREPO, 0x0095, Repo, repo, ({
{sfAccount, SoeRequired},
{sfCounterparty, SoeRequired},
{sfCollateralAmount, SoeRequired, SoeMptSupported},
{sfPurchasePrice, SoeRequired, SoeMptSupported},
{sfInterestRate, SoeRequired},
{sfExpiration, SoeRequired},
{sfStartDate, SoeOptional},
{sfMaturityDate, SoeRequired},
{sfGracePeriod, SoeRequired},
{sfTransferRate, SoeOptional},
{sfData, SoeOptional},
{sfOwnerNode, SoeRequired},
{sfDestinationNode, SoeRequired},
{sfIssuerNode, SoeOptional},
{sfPreviousTxnID, SoeRequired},
{sfPreviousTxnLgrSeq, SoeRequired},
}))

/** Reserve 0x0084-0x0087 for future Vault-related objects. */

/** A ledger object representing a loan broker
Expand Down
4 changes: 4 additions & 0 deletions include/xrpl/protocol/detail/sfields.macro
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ TYPED_SFIELD(sfConfidentialBalanceVersion, UINT32, 69)
TYPED_SFIELD(sfSponsoredOwnerCount, UINT32, 70)
TYPED_SFIELD(sfSponsoringOwnerCount, UINT32, 71)
TYPED_SFIELD(sfSponsoringAccountCount, UINT32, 72)
TYPED_SFIELD(sfMaturityDate, UINT32, 95)
TYPED_SFIELD(sfRemainingOwnerCount, UINT32, 73)
TYPED_SFIELD(sfSponsorFlags, UINT32, 74)
TYPED_SFIELD(sfSubscriptionDate, UINT32, 75)
Expand Down Expand Up @@ -220,6 +221,7 @@ TYPED_SFIELD(sfLoanID, UINT256, 38)
TYPED_SFIELD(sfReferenceHolding, UINT256, 39)
TYPED_SFIELD(sfBlindingFactor, UINT256, 40)
TYPED_SFIELD(sfObjectID, UINT256, 41)
TYPED_SFIELD(sfRepoID, UINT256, 47)

// number (common)
TYPED_SFIELD(sfNumber, NUMBER, 1)
Expand Down Expand Up @@ -282,6 +284,8 @@ TYPED_SFIELD(sfLPTokenBalance, AMOUNT, 31)
TYPED_SFIELD(sfFeeAmount, AMOUNT, 32)
TYPED_SFIELD(sfMaxFee, AMOUNT, 33)
TYPED_SFIELD(sfFeeAmountDelta, AMOUNT, 34)
TYPED_SFIELD(sfCollateralAmount, AMOUNT, 39)
TYPED_SFIELD(sfPurchasePrice, AMOUNT, 40)

// variable length (common)
TYPED_SFIELD(sfPublicKey, VL, 1)
Expand Down
57 changes: 57 additions & 0 deletions include/xrpl/protocol/detail/transactions.macro
Original file line number Diff line number Diff line change
Expand Up @@ -1181,3 +1181,60 @@ TRANSACTION(ttUNL_MODIFY, 102, UNLModify,
{sfLedgerSequence, SoeRequired},
{sfUNLModifyValidator, SoeRequired},
}))

/** This transaction type offers a repurchase agreement and locks its collateral. */
#if TRANSACTION_INCLUDE
# include <xrpl/tx/transactors/repo/RepoCreate.h>
#endif
TRANSACTION(ttREPO_CREATE, 114, RepoCreate,
({.delegable = Delegation::Delegable, .amendment = featureRepo}),
({
{sfCounterparty, SoeRequired},
{sfCollateralAmount, SoeRequired, SoeMptSupported},
{sfPurchasePrice, SoeRequired, SoeMptSupported},
{sfInterestRate, SoeRequired},
{sfExpiration, SoeRequired},
{sfMaturityDate, SoeRequired},
{sfGracePeriod, SoeRequired},
{sfData, SoeOptional},
}))

/** This transaction type accepts a pending repo, delivering the cash. */
#if TRANSACTION_INCLUDE
# include <xrpl/tx/transactors/repo/RepoAccept.h>
#endif
TRANSACTION(ttREPO_ACCEPT, 115, RepoAccept,
({.delegable = Delegation::Delegable, .amendment = featureRepo}),
({
{sfRepoID, SoeRequired},
}))

/** This transaction type cancels a pending repo and returns the collateral. */
#if TRANSACTION_INCLUDE
# include <xrpl/tx/transactors/repo/RepoCancel.h>
#endif
TRANSACTION(ttREPO_CANCEL, 116, RepoCancel,
({.delegable = Delegation::Delegable, .amendment = featureRepo}),
({
{sfRepoID, SoeRequired},
}))

/** This transaction type repurchases the collateral, paying principal plus interest. */
#if TRANSACTION_INCLUDE
# include <xrpl/tx/transactors/repo/RepoClose.h>
#endif
TRANSACTION(ttREPO_CLOSE, 117, RepoClose,
({.delegable = Delegation::Delegable, .amendment = featureRepo}),
({
{sfRepoID, SoeRequired},
}))

/** This transaction type closes out a defaulted repo, delivering the collateral. */
#if TRANSACTION_INCLUDE
# include <xrpl/tx/transactors/repo/RepoDefault.h>
#endif
TRANSACTION(ttREPO_DEFAULT, 118, RepoDefault,
({.delegable = Delegation::Delegable, .amendment = featureRepo}),
({
{sfRepoID, SoeRequired},
}))
Loading