Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

XLS-85d: Token-Enabled Escrows #5185

Open
wants to merge 16 commits into
base: develop
Choose a base branch
from
Open
2 changes: 1 addition & 1 deletion include/xrpl/protocol/Feature.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ namespace detail {
// Feature.cpp. Because it's only used to reserve storage, and determine how
// large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than
// the actual number of amendments. A LogicError on startup will verify this.
static constexpr std::size_t numFeatures = 83;
static constexpr std::size_t numFeatures = 84;

/** Amendments that this server supports and the default voting behavior.
Whether they are enabled depends on the Rules defined in the validated
Expand Down
3 changes: 2 additions & 1 deletion include/xrpl/protocol/LedgerFormats.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,8 @@ enum LedgerSpecificFlags {
0x10000000, // True, reject new paychans
lsfDisallowIncomingTrustline =
0x20000000, // True, reject new trustlines (only if no issued assets)
// 0x40000000 is available
lsfAllowTokenLocking =
0x40000000, // True, enable token locking
lsfAllowTrustLineClawback =
0x80000000, // True, enable clawback

Expand Down
42 changes: 42 additions & 0 deletions include/xrpl/protocol/STAmount.h
Original file line number Diff line number Diff line change
Expand Up @@ -688,6 +688,48 @@ isXRP(STAmount const& amount)
return amount.native();
}

/** returns true if adding or subtracting results in less than or equal to
* 0.01% precision loss **/
inline bool
isAddable(STAmount const& amt1, STAmount const& amt2)
{
// special case: adding anything to zero is always fine
if (amt1 == beast::zero || amt2 == beast::zero)
return true;

// special case: adding two xrp amounts together.
// this is just an overflow check
if (isXRP(amt1) && isXRP(amt2))
{
XRPAmount A = (amt1.signum() == -1 ? -(amt1.xrp()) : amt1.xrp());
XRPAmount B = (amt2.signum() == -1 ? -(amt2.xrp()) : amt2.xrp());

XRPAmount finalAmt = A + B;
return (finalAmt >= A && finalAmt >= B);
}

static const STAmount one{IOUAmount{1, 0}, noIssue()};
static const STAmount maxLoss{IOUAmount{1, -4}, noIssue()};

STAmount A = amt1;
STAmount B = amt2;

if (isXRP(A))
A = STAmount{IOUAmount{A.xrp().drops(), -6}, noIssue()};

if (isXRP(B))
B = STAmount{IOUAmount{B.xrp().drops(), -6}, noIssue()};

A.setIssue(noIssue());
B.setIssue(noIssue());

STAmount lhs = divide((A - B) + B, A, noIssue()) - one;
STAmount rhs = divide((B - A) + A, B, noIssue()) - one;

return ((rhs.negative() ? -rhs : rhs) + (lhs.negative() ? -lhs : lhs)) <=
maxLoss;
}

// Since `canonicalize` does not have access to a ledger, this is needed to put
// the low-level routine stAmountCanonicalize on an amendment switch. Only
// transactions need to use this switchover. Outside of a transaction it's safe
Expand Down
1 change: 1 addition & 0 deletions include/xrpl/protocol/TER.h
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ enum TECcodes : TERUnderlyingType {
tecARRAY_TOO_LARGE = 191,
tecLOCKED = 192,
tecBAD_CREDENTIALS = 193,
tecPRECISION_LOSS = 194,
};

//------------------------------------------------------------------------------
Expand Down
1 change: 1 addition & 0 deletions include/xrpl/protocol/TxFlags.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ constexpr std::uint32_t asfDisallowIncomingCheck = 13;
constexpr std::uint32_t asfDisallowIncomingPayChan = 14;
constexpr std::uint32_t asfDisallowIncomingTrustline = 15;
constexpr std::uint32_t asfAllowTrustLineClawback = 16;
constexpr std::uint32_t asfAllowTokenLocking = 17;

// OfferCreate flags:
constexpr std::uint32_t tfPassive = 0x00010000;
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 @@ -29,6 +29,7 @@
// If you add an amendment here, then do not forget to increment `numFeatures`
// in include/xrpl/protocol/Feature.h.

XRPL_FEATURE(TokenEscrow, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(Credentials, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(AMMClawback, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FIX (AMMv1_2, Supported::yes, VoteBehavior::DefaultNo)
Expand Down
2 changes: 2 additions & 0 deletions include/xrpl/protocol/detail/ledger_entries.macro
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,8 @@ LEDGER_ENTRY(ltESCROW, 0x0075, Escrow, ({
{sfPreviousTxnID, soeREQUIRED},
{sfPreviousTxnLgrSeq, soeREQUIRED},
{sfDestinationNode, soeOPTIONAL},
{sfTransferRate, soeOPTIONAL},
{sfIssuerNode, soeOPTIONAL},
}))

/** A ledger object describing a single unidirectional XRP payment channel.
Expand Down
1 change: 1 addition & 0 deletions src/libxrpl/protocol/TER.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ transResults()
MAKE_ERROR(tecARRAY_TOO_LARGE, "Array is too large."),
MAKE_ERROR(tecLOCKED, "Fund is locked."),
MAKE_ERROR(tecBAD_CREDENTIALS, "Bad credentials."),
MAKE_ERROR(tecPRECISION_LOSS, "The amounts used by the transaction cannot interact."),

MAKE_ERROR(tefALREADY, "The exact transaction was already in this ledger."),
MAKE_ERROR(tefBAD_ADD_AUTH, "Not authorized to add account."),
Expand Down
28 changes: 28 additions & 0 deletions src/test/app/AccountDelete_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,34 @@ class AccountDelete_test : public beast::unit_test::suite
jv[sfOfferSequence.jsonName] = seq;
return jv;
};

bool const withTokenEscrow =
env.current()->rules().enabled(featureTokenEscrow);
if (withTokenEscrow)
{
Account const carol("carol");
auto const USD = gw["USD"];
env.fund(XRP(100000), carol);
env(fset(gw, asfAllowTokenLocking));
env.close();
env.trust(USD(10000), carol);
env.close();
env(pay(gw, carol, USD(100)));
env.close();

std::uint32_t const escrowSeq{env.seq(carol)};
env(escrowCreate(carol, becky, USD(1), env.now() + 2s));
env.close();

env(acctdelete(gw, becky),
fee(acctDelFee),
ter(tecHAS_OBLIGATIONS));
env.close();

env(escrowCancel(becky, carol, escrowSeq));
env.close();
}

env(escrowCancel(becky, alice, escrowSeq));
env.close();

Expand Down
Loading
Loading