Skip to content

Commit

Permalink
CFToken implementation from shawnxie999:cft-set
Browse files Browse the repository at this point in the history
  • Loading branch information
gregtatcam committed Dec 3, 2023
1 parent 46f3d3e commit a9246c3
Show file tree
Hide file tree
Showing 22 changed files with 425 additions and 3 deletions.
6 changes: 6 additions & 0 deletions Builds/CMake/RippledCore.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,10 @@ target_sources (rippled PRIVATE
src/ripple/app/tx/impl/AMMWithdraw.cpp
src/ripple/app/tx/impl/ApplyContext.cpp
src/ripple/app/tx/impl/BookTip.cpp
src/ripple/app/tx/impl/CFTokenIssuanceCreate.cpp
src/ripple/app/tx/impl/CFTokenIssuanceDestroy.cpp
src/ripple/app/tx/impl/CFTokenAuthorize.cpp
src/ripple/app/tx/impl/CFTokenIssuanceSet.cpp
src/ripple/app/tx/impl/CancelCheck.cpp
src/ripple/app/tx/impl/CancelOffer.cpp
src/ripple/app/tx/impl/CashCheck.cpp
Expand Down Expand Up @@ -782,6 +786,7 @@ if (tests)
src/test/app/AMM_test.cpp
src/test/app/AMMCalc_test.cpp
src/test/app/AMMExtended_test.cpp
src/test/app/CFToken_test.cpp
src/test/app/Check_test.cpp
src/test/app/Clawback_test.cpp
src/test/app/CrossingLimits_test.cpp
Expand Down Expand Up @@ -930,6 +935,7 @@ if (tests)
src/test/jtx/impl/Account.cpp
src/test/jtx/impl/AMM.cpp
src/test/jtx/impl/AMMTest.cpp
src/test/jtx/impl/cft.cpp
src/test/jtx/impl/Env.cpp
src/test/jtx/impl/JSONRPCClient.cpp
src/test/jtx/impl/TestHelpers.cpp
Expand Down
163 changes: 163 additions & 0 deletions src/ripple/app/tx/impl/InvariantCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,8 @@ LedgerEntryTypesMatch::visitEntry(
case ltXCHAIN_OWNED_CLAIM_ID:
case ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID:
case ltDID:
case ltCFTOKEN_ISSUANCE:
case ltCFTOKEN:
break;
default:
invalidTypeAdded_ = true;
Expand Down Expand Up @@ -799,4 +801,165 @@ ValidClawback::finalize(
return true;
}

//------------------------------------------------------------------------------

void
ValidCFTIssuance::visitEntry(
bool isDelete,
std::shared_ptr<SLE const> const& before,
std::shared_ptr<SLE const> const& after)
{
if (after && after->getType() == ltCFTOKEN_ISSUANCE)
{
if (isDelete)
cftIssuancesDeleted_++;
else if (!before)
cftIssuancesCreated_++;
}

if (after && after->getType() == ltCFTOKEN)
{
if (isDelete)
cftokensDeleted_++;
else if (!before)
cftokensCreated_++;
}
}

bool
ValidCFTIssuance::finalize(
STTx const& tx,
TER const result,
XRPAmount const _fee,
ReadView const& _view,
beast::Journal const& j)
{
if (tx.getTxnType() == ttCFTOKEN_ISSUANCE_CREATE && result == tesSUCCESS)
{
if (cftIssuancesCreated_ == 0)
{
JLOG(j.fatal()) << "Invariant failed: CFT issuance creation "
"succeeded without creating a CFT issuance";
}
else if (cftIssuancesDeleted_ != 0)
{
JLOG(j.fatal()) << "Invariant failed: CFT issuance creation "
"succeeded while removing CFT issuances";
}
else if (cftIssuancesCreated_ > 1)
{
JLOG(j.fatal()) << "Invariant failed: CFT issuance creation "
"succeeded but created multiple issuances";
}

return cftIssuancesCreated_ == 1 && cftIssuancesDeleted_ == 0;
}

if (tx.getTxnType() == ttCFTOKEN_ISSUANCE_DESTROY && result == tesSUCCESS)
{
if (cftIssuancesDeleted_ == 0)
{
JLOG(j.fatal()) << "Invariant failed: CFT issuance deletion "
"succeeded without removing a CFT issuance";
}
else if (cftIssuancesCreated_ > 0)
{
JLOG(j.fatal()) << "Invariant failed: CFT issuance deletion "
"succeeded while creating CFT issuances";
}
else if (cftIssuancesDeleted_ > 1)
{
JLOG(j.fatal()) << "Invariant failed: CFT issuance deletion "
"succeeded but deleted multiple issuances";
}

return cftIssuancesCreated_ == 0 && cftIssuancesDeleted_ == 1;
}

if (tx.getTxnType() == ttCFTOKEN_AUTHORIZE && result == tesSUCCESS)
{
bool const submittedByIssuer = tx.isFieldPresent(sfCFTokenHolder);

if (cftIssuancesCreated_ > 0)
{
JLOG(j.fatal()) << "Invariant failed: CFT authorize "
"succeeded but created CFT issuances";
return false;
}
else if (cftIssuancesDeleted_ > 0)
{
JLOG(j.fatal()) << "Invariant failed: CFT authorize "
"succeeded but deleted issuances";
return false;
}
else if (
submittedByIssuer && (cftokensCreated_ > 0 || cftokensDeleted_ > 0))
{
JLOG(j.fatal())
<< "Invariant failed: CFT authorize submitted by issuer "
"succeeded but created/deleted cftokens";
return false;
}
else if (
!submittedByIssuer && (cftokensCreated_ + cftokensDeleted_ != 1))
{
// if the holder submitted this tx, then a cftoken must be either
// created or deleted.
JLOG(j.fatal())
<< "Invariant failed: CFT authorize submitted by holder "
"succeeded but created/deleted bad number of cftokens";
return false;
}

return true;
}

if (tx.getTxnType() == ttCFTOKEN_ISSUANCE_SET && result == tesSUCCESS)
{
if (cftIssuancesDeleted_ > 0)
{
JLOG(j.fatal()) << "Invariant failed: CFT issuance set "
"succeeded while removing CFT issuances";
}
else if (cftIssuancesCreated_ > 0)
{
JLOG(j.fatal()) << "Invariant failed: CFT issuance set "
"succeeded while creating CFT issuances";
}
else if (cftokensDeleted_ > 0)
{
JLOG(j.fatal()) << "Invariant failed: CFT issuance set "
"succeeded while removing CFTokens";
}
else if (cftokensCreated_ > 0)
{
JLOG(j.fatal()) << "Invariant failed: CFT issuance set "
"succeeded while creating CFTokens";
}

return cftIssuancesCreated_ == 0 && cftIssuancesDeleted_ == 0 &&
cftokensCreated_ == 0 && cftokensDeleted_ == 0;
}

if (cftIssuancesCreated_ != 0)
{
JLOG(j.fatal()) << "Invariant failed: a CFT issuance was created";
}
else if (cftIssuancesDeleted_ != 0)
{
JLOG(j.fatal()) << "Invariant failed: a CFT issuance was deleted";
}
else if (cftokensCreated_ != 0)
{
JLOG(j.fatal()) << "Invariant failed: a CFToken was created";
}
else if (cftokensDeleted_ != 0)
{
JLOG(j.fatal()) << "Invariant failed: a CFToken was deleted";
}

return cftIssuancesCreated_ == 0 && cftIssuancesDeleted_ == 0 &&
cftokensCreated_ == 0 && cftokensDeleted_ == 0;
}

} // namespace ripple
27 changes: 26 additions & 1 deletion src/ripple/app/tx/impl/InvariantCheck.h
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,30 @@ class ValidClawback
beast::Journal const&);
};

class ValidCFTIssuance
{
std::uint32_t cftIssuancesCreated_ = 0;
std::uint32_t cftIssuancesDeleted_ = 0;

std::uint32_t cftokensCreated_ = 0;
std::uint32_t cftokensDeleted_ = 0;

public:
void
visitEntry(
bool,
std::shared_ptr<SLE const> const&,
std::shared_ptr<SLE const> const&);

bool
finalize(
STTx const&,
TER const,
XRPAmount const,
ReadView const&,
beast::Journal const&);
};

// additional invariant checks can be declared above and then added to this
// tuple
using InvariantChecks = std::tuple<
Expand All @@ -432,7 +456,8 @@ using InvariantChecks = std::tuple<
ValidNewAccountRoot,
ValidNFTokenPage,
NFTokenCountTracking,
ValidClawback>;
ValidClawback,
ValidCFTIssuance>;

/**
* @brief get a tuple of all invariant checks
Expand Down
12 changes: 12 additions & 0 deletions src/ripple/app/tx/impl/applySteps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
#include <ripple/app/tx/impl/AMMVote.h>
#include <ripple/app/tx/impl/AMMWithdraw.h>
#include <ripple/app/tx/impl/ApplyContext.h>
#include <ripple/app/tx/impl/CFTokenAuthorize.h>
#include <ripple/app/tx/impl/CFTokenIssuanceCreate.h>
#include <ripple/app/tx/impl/CFTokenIssuanceDestroy.h>
#include <ripple/app/tx/impl/CFTokenIssuanceSet.h>
#include <ripple/app/tx/impl/CancelCheck.h>
#include <ripple/app/tx/impl/CancelOffer.h>
#include <ripple/app/tx/impl/CashCheck.h>
Expand Down Expand Up @@ -159,6 +163,14 @@ with_txn_type(TxType txnType, F&& f)
return f.template operator()<DIDSet>();
case ttDID_DELETE:
return f.template operator()<DIDDelete>();
case ttCFTOKEN_ISSUANCE_CREATE:
return f.template operator()<CFTokenIssuanceCreate>();
case ttCFTOKEN_ISSUANCE_DESTROY:
return f.template operator()<CFTokenIssuanceDestroy>();
case ttCFTOKEN_AUTHORIZE:
return f.template operator()<CFTokenAuthorize>();
case ttCFTOKEN_ISSUANCE_SET:
return f.template operator()<CFTokenIssuanceSet>();
default:
throw UnknownTxnType(txnType);
}
Expand Down
3 changes: 2 additions & 1 deletion src/ripple/protocol/Feature.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,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 = 65;
static constexpr std::size_t numFeatures = 66;

/** Amendments that this server supports and the default voting behavior.
Whether they are enabled depends on the Rules defined in the validated
Expand Down Expand Up @@ -352,6 +352,7 @@ extern uint256 const featureXChainBridge;
extern uint256 const fixDisallowIncomingV1;
extern uint256 const featureDID;
extern uint256 const fixFillOrKill;
extern uint256 const featureCFTokensV1;

} // namespace ripple

Expand Down
14 changes: 14 additions & 0 deletions src/ripple/protocol/Indexes.h
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,20 @@ xChainCreateAccountClaimID(STXChainBridge const& bridge, std::uint64_t seq);
Keylet
did(AccountID const& account) noexcept;

Keylet
cftIssuance(AccountID const& issuer, std::uint32_t seq) noexcept;

inline Keylet
cftIssuance(uint256 const& issuance)
{
return {ltCFTOKEN_ISSUANCE, issuance};
}

Keylet
cftoken(uint256 const& issuanceID, AccountID const& holder) noexcept;

Keylet
cft_dir(uint256 const& id) noexcept;
} // namespace keylet

// Everything below is deprecated and should be removed in favor of keylets:
Expand Down
24 changes: 24 additions & 0 deletions src/ripple/protocol/LedgerFormats.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,18 @@ enum LedgerEntryType : std::uint16_t
*/
ltDID = 0x0049,

/** A ledger object representing an individual CFToken asset type, but not
* any balances of that asset itself.
\sa keylet::cftIssuance
*/
ltCFTOKEN_ISSUANCE = 0x007e,

/** A ledger object representing an individual CFToken balance.
\sa keylet::cftoken
*/
ltCFTOKEN = 0x007f,
//---------------------------------------------------------------------------
/** A special type, matching any ledger entry type.
Expand Down Expand Up @@ -303,6 +315,18 @@ enum LedgerSpecificFlags {

// ltNFTOKEN_OFFER
lsfSellNFToken = 0x00000001,

// ltCFTOKEN_ISSUANCE
lsfCFTLocked = 0x00000001, // Also used in ltCFTOKEN
lsfCFTCanLock = 0x00000002,
lsfCFTRequireAuth = 0x00000004,
lsfCFTCanEscrow = 0x00000008,
lsfCFTCanTrade = 0x00000010,
lsfCFTCanTransfer = 0x00000020,
lsfCFTCanClawback = 0x00000040,

// ltCFTOKEN
lsfCFTAuthorized = 0x00000002,
};

//------------------------------------------------------------------------------
Expand Down
3 changes: 3 additions & 0 deletions src/ripple/protocol/Protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ std::size_t constexpr maxDIDAttestationLength = 256;
/** The maximum length of a domain */
std::size_t constexpr maxDomainLength = 256;

/** The maximum length of CFTokenMetadata */
std::size_t constexpr maxCFTokenMetadataLength = 1024;

/** A ledger index. */
using LedgerIndex = std::uint32_t;

Expand Down
Loading

0 comments on commit a9246c3

Please sign in to comment.