mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-04 19:25:51 +00:00
Merge branch 'develop' into ripple/smart-escrow
This commit is contained in:
@@ -20,6 +20,8 @@
|
|||||||
#ifndef RIPPLE_PROTOCOL_PERMISSION_H_INCLUDED
|
#ifndef RIPPLE_PROTOCOL_PERMISSION_H_INCLUDED
|
||||||
#define RIPPLE_PROTOCOL_PERMISSION_H_INCLUDED
|
#define RIPPLE_PROTOCOL_PERMISSION_H_INCLUDED
|
||||||
|
|
||||||
|
#include <xrpl/protocol/Rules.h>
|
||||||
|
#include <xrpl/protocol/TER.h>
|
||||||
#include <xrpl/protocol/TxFormats.h>
|
#include <xrpl/protocol/TxFormats.h>
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
@@ -53,6 +55,8 @@ class Permission
|
|||||||
private:
|
private:
|
||||||
Permission();
|
Permission();
|
||||||
|
|
||||||
|
std::unordered_map<std::uint16_t, uint256> txFeatureMap_;
|
||||||
|
|
||||||
std::unordered_map<std::uint16_t, Delegation> delegatableTx_;
|
std::unordered_map<std::uint16_t, Delegation> delegatableTx_;
|
||||||
|
|
||||||
std::unordered_map<std::string, GranularPermissionType>
|
std::unordered_map<std::string, GranularPermissionType>
|
||||||
@@ -80,7 +84,8 @@ public:
|
|||||||
getGranularTxType(GranularPermissionType const& gpType) const;
|
getGranularTxType(GranularPermissionType const& gpType) const;
|
||||||
|
|
||||||
bool
|
bool
|
||||||
isDelegatable(std::uint32_t const& permissionValue) const;
|
isDelegatable(std::uint32_t const& permissionValue, Rules const& rules)
|
||||||
|
const;
|
||||||
|
|
||||||
// for tx level permission, permission value is equal to tx type plus one
|
// for tx level permission, permission value is equal to tx type plus one
|
||||||
uint32_t
|
uint32_t
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ enum TxType : std::uint16_t
|
|||||||
#pragma push_macro("TRANSACTION")
|
#pragma push_macro("TRANSACTION")
|
||||||
#undef TRANSACTION
|
#undef TRANSACTION
|
||||||
|
|
||||||
#define TRANSACTION(tag, value, name, delegatable, fields) tag = value,
|
#define TRANSACTION(tag, value, ...) tag = value,
|
||||||
|
|
||||||
#include <xrpl/protocol/detail/transactions.macro>
|
#include <xrpl/protocol/detail/transactions.macro>
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,8 @@
|
|||||||
// If you add an amendment here, then do not forget to increment `numFeatures`
|
// If you add an amendment here, then do not forget to increment `numFeatures`
|
||||||
// in include/xrpl/protocol/Feature.h.
|
// in include/xrpl/protocol/Feature.h.
|
||||||
|
|
||||||
XRPL_FEATURE(SmartEscrow, Supported::yes, VoteBehavior::DefaultNo)
|
XRPL_FEATURE(SmartEscrow, Supported::no, VoteBehavior::DefaultNo)
|
||||||
|
XRPL_FIX (DelegateV1_1, Supported::no, VoteBehavior::DefaultNo)
|
||||||
XRPL_FIX (PriceOracleOrder, Supported::no, VoteBehavior::DefaultNo)
|
XRPL_FIX (PriceOracleOrder, Supported::no, VoteBehavior::DefaultNo)
|
||||||
XRPL_FIX (MPTDeliveredAmount, Supported::no, VoteBehavior::DefaultNo)
|
XRPL_FIX (MPTDeliveredAmount, Supported::no, VoteBehavior::DefaultNo)
|
||||||
XRPL_FIX (AMMClawbackRounding, Supported::yes, VoteBehavior::DefaultNo)
|
XRPL_FIX (AMMClawbackRounding, Supported::yes, VoteBehavior::DefaultNo)
|
||||||
|
|||||||
@@ -22,14 +22,17 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TRANSACTION(tag, value, name, delegatable, fields)
|
* TRANSACTION(tag, value, name, delegatable, amendments, fields)
|
||||||
*
|
*
|
||||||
* You must define a transactor class in the `ripple` namespace named `name`,
|
* You must define a transactor class in the `ripple` namespace named `name`,
|
||||||
* and include its header in `src/xrpld/app/tx/detail/applySteps.cpp`.
|
* and include its header in `src/xrpld/app/tx/detail/applySteps.cpp`.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** This transaction type executes a payment. */
|
/** This transaction type executes a payment. */
|
||||||
TRANSACTION(ttPAYMENT, 0, Payment, Delegation::delegatable, ({
|
TRANSACTION(ttPAYMENT, 0, Payment,
|
||||||
|
Delegation::delegatable,
|
||||||
|
uint256{},
|
||||||
|
({
|
||||||
{sfDestination, soeREQUIRED},
|
{sfDestination, soeREQUIRED},
|
||||||
{sfAmount, soeREQUIRED, soeMPTSupported},
|
{sfAmount, soeREQUIRED, soeMPTSupported},
|
||||||
{sfSendMax, soeOPTIONAL, soeMPTSupported},
|
{sfSendMax, soeOPTIONAL, soeMPTSupported},
|
||||||
@@ -42,7 +45,10 @@ TRANSACTION(ttPAYMENT, 0, Payment, Delegation::delegatable, ({
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction type creates an escrow object. */
|
/** This transaction type creates an escrow object. */
|
||||||
TRANSACTION(ttESCROW_CREATE, 1, EscrowCreate, Delegation::delegatable, ({
|
TRANSACTION(ttESCROW_CREATE, 1, EscrowCreate,
|
||||||
|
Delegation::delegatable,
|
||||||
|
uint256{},
|
||||||
|
({
|
||||||
{sfDestination, soeREQUIRED},
|
{sfDestination, soeREQUIRED},
|
||||||
{sfDestinationTag, soeOPTIONAL},
|
{sfDestinationTag, soeOPTIONAL},
|
||||||
{sfAmount, soeREQUIRED, soeMPTSupported},
|
{sfAmount, soeREQUIRED, soeMPTSupported},
|
||||||
@@ -54,7 +60,10 @@ TRANSACTION(ttESCROW_CREATE, 1, EscrowCreate, Delegation::delegatable, ({
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction type completes an existing escrow. */
|
/** This transaction type completes an existing escrow. */
|
||||||
TRANSACTION(ttESCROW_FINISH, 2, EscrowFinish, Delegation::delegatable, ({
|
TRANSACTION(ttESCROW_FINISH, 2, EscrowFinish,
|
||||||
|
Delegation::delegatable,
|
||||||
|
uint256{},
|
||||||
|
({
|
||||||
{sfOwner, soeREQUIRED},
|
{sfOwner, soeREQUIRED},
|
||||||
{sfOfferSequence, soeREQUIRED},
|
{sfOfferSequence, soeREQUIRED},
|
||||||
{sfFulfillment, soeOPTIONAL},
|
{sfFulfillment, soeOPTIONAL},
|
||||||
@@ -65,7 +74,10 @@ TRANSACTION(ttESCROW_FINISH, 2, EscrowFinish, Delegation::delegatable, ({
|
|||||||
|
|
||||||
|
|
||||||
/** This transaction type adjusts various account settings. */
|
/** This transaction type adjusts various account settings. */
|
||||||
TRANSACTION(ttACCOUNT_SET, 3, AccountSet, Delegation::notDelegatable, ({
|
TRANSACTION(ttACCOUNT_SET, 3, AccountSet,
|
||||||
|
Delegation::notDelegatable,
|
||||||
|
uint256{},
|
||||||
|
({
|
||||||
{sfEmailHash, soeOPTIONAL},
|
{sfEmailHash, soeOPTIONAL},
|
||||||
{sfWalletLocator, soeOPTIONAL},
|
{sfWalletLocator, soeOPTIONAL},
|
||||||
{sfWalletSize, soeOPTIONAL},
|
{sfWalletSize, soeOPTIONAL},
|
||||||
@@ -79,20 +91,29 @@ TRANSACTION(ttACCOUNT_SET, 3, AccountSet, Delegation::notDelegatable, ({
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction type cancels an existing escrow. */
|
/** This transaction type cancels an existing escrow. */
|
||||||
TRANSACTION(ttESCROW_CANCEL, 4, EscrowCancel, Delegation::delegatable, ({
|
TRANSACTION(ttESCROW_CANCEL, 4, EscrowCancel,
|
||||||
|
Delegation::delegatable,
|
||||||
|
uint256{},
|
||||||
|
({
|
||||||
{sfOwner, soeREQUIRED},
|
{sfOwner, soeREQUIRED},
|
||||||
{sfOfferSequence, soeREQUIRED},
|
{sfOfferSequence, soeREQUIRED},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction type sets or clears an account's "regular key". */
|
/** This transaction type sets or clears an account's "regular key". */
|
||||||
TRANSACTION(ttREGULAR_KEY_SET, 5, SetRegularKey, Delegation::notDelegatable, ({
|
TRANSACTION(ttREGULAR_KEY_SET, 5, SetRegularKey,
|
||||||
|
Delegation::notDelegatable,
|
||||||
|
uint256{},
|
||||||
|
({
|
||||||
{sfRegularKey, soeOPTIONAL},
|
{sfRegularKey, soeOPTIONAL},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
// 6 deprecated
|
// 6 deprecated
|
||||||
|
|
||||||
/** This transaction type creates an offer to trade one asset for another. */
|
/** This transaction type creates an offer to trade one asset for another. */
|
||||||
TRANSACTION(ttOFFER_CREATE, 7, OfferCreate, Delegation::delegatable, ({
|
TRANSACTION(ttOFFER_CREATE, 7, OfferCreate,
|
||||||
|
Delegation::delegatable,
|
||||||
|
uint256{},
|
||||||
|
({
|
||||||
{sfTakerPays, soeREQUIRED},
|
{sfTakerPays, soeREQUIRED},
|
||||||
{sfTakerGets, soeREQUIRED},
|
{sfTakerGets, soeREQUIRED},
|
||||||
{sfExpiration, soeOPTIONAL},
|
{sfExpiration, soeOPTIONAL},
|
||||||
@@ -101,14 +122,20 @@ TRANSACTION(ttOFFER_CREATE, 7, OfferCreate, Delegation::delegatable, ({
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction type cancels existing offers to trade one asset for another. */
|
/** This transaction type cancels existing offers to trade one asset for another. */
|
||||||
TRANSACTION(ttOFFER_CANCEL, 8, OfferCancel, Delegation::delegatable, ({
|
TRANSACTION(ttOFFER_CANCEL, 8, OfferCancel,
|
||||||
|
Delegation::delegatable,
|
||||||
|
uint256{},
|
||||||
|
({
|
||||||
{sfOfferSequence, soeREQUIRED},
|
{sfOfferSequence, soeREQUIRED},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
// 9 deprecated
|
// 9 deprecated
|
||||||
|
|
||||||
/** This transaction type creates a new set of tickets. */
|
/** This transaction type creates a new set of tickets. */
|
||||||
TRANSACTION(ttTICKET_CREATE, 10, TicketCreate, Delegation::delegatable, ({
|
TRANSACTION(ttTICKET_CREATE, 10, TicketCreate,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureTicketBatch,
|
||||||
|
({
|
||||||
{sfTicketCount, soeREQUIRED},
|
{sfTicketCount, soeREQUIRED},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
@@ -117,13 +144,19 @@ TRANSACTION(ttTICKET_CREATE, 10, TicketCreate, Delegation::delegatable, ({
|
|||||||
/** This transaction type modifies the signer list associated with an account. */
|
/** This transaction type modifies the signer list associated with an account. */
|
||||||
// The SignerEntries are optional because a SignerList is deleted by
|
// The SignerEntries are optional because a SignerList is deleted by
|
||||||
// setting the SignerQuorum to zero and omitting SignerEntries.
|
// setting the SignerQuorum to zero and omitting SignerEntries.
|
||||||
TRANSACTION(ttSIGNER_LIST_SET, 12, SignerListSet, Delegation::notDelegatable, ({
|
TRANSACTION(ttSIGNER_LIST_SET, 12, SignerListSet,
|
||||||
|
Delegation::notDelegatable,
|
||||||
|
uint256{},
|
||||||
|
({
|
||||||
{sfSignerQuorum, soeREQUIRED},
|
{sfSignerQuorum, soeREQUIRED},
|
||||||
{sfSignerEntries, soeOPTIONAL},
|
{sfSignerEntries, soeOPTIONAL},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction type creates a new unidirectional XRP payment channel. */
|
/** This transaction type creates a new unidirectional XRP payment channel. */
|
||||||
TRANSACTION(ttPAYCHAN_CREATE, 13, PaymentChannelCreate, Delegation::delegatable, ({
|
TRANSACTION(ttPAYCHAN_CREATE, 13, PaymentChannelCreate,
|
||||||
|
Delegation::delegatable,
|
||||||
|
uint256{},
|
||||||
|
({
|
||||||
{sfDestination, soeREQUIRED},
|
{sfDestination, soeREQUIRED},
|
||||||
{sfAmount, soeREQUIRED},
|
{sfAmount, soeREQUIRED},
|
||||||
{sfSettleDelay, soeREQUIRED},
|
{sfSettleDelay, soeREQUIRED},
|
||||||
@@ -133,14 +166,20 @@ TRANSACTION(ttPAYCHAN_CREATE, 13, PaymentChannelCreate, Delegation::delegatable,
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction type funds an existing unidirectional XRP payment channel. */
|
/** This transaction type funds an existing unidirectional XRP payment channel. */
|
||||||
TRANSACTION(ttPAYCHAN_FUND, 14, PaymentChannelFund, Delegation::delegatable, ({
|
TRANSACTION(ttPAYCHAN_FUND, 14, PaymentChannelFund,
|
||||||
|
Delegation::delegatable,
|
||||||
|
uint256{},
|
||||||
|
({
|
||||||
{sfChannel, soeREQUIRED},
|
{sfChannel, soeREQUIRED},
|
||||||
{sfAmount, soeREQUIRED},
|
{sfAmount, soeREQUIRED},
|
||||||
{sfExpiration, soeOPTIONAL},
|
{sfExpiration, soeOPTIONAL},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction type submits a claim against an existing unidirectional payment channel. */
|
/** This transaction type submits a claim against an existing unidirectional payment channel. */
|
||||||
TRANSACTION(ttPAYCHAN_CLAIM, 15, PaymentChannelClaim, Delegation::delegatable, ({
|
TRANSACTION(ttPAYCHAN_CLAIM, 15, PaymentChannelClaim,
|
||||||
|
Delegation::delegatable,
|
||||||
|
uint256{},
|
||||||
|
({
|
||||||
{sfChannel, soeREQUIRED},
|
{sfChannel, soeREQUIRED},
|
||||||
{sfAmount, soeOPTIONAL},
|
{sfAmount, soeOPTIONAL},
|
||||||
{sfBalance, soeOPTIONAL},
|
{sfBalance, soeOPTIONAL},
|
||||||
@@ -150,7 +189,10 @@ TRANSACTION(ttPAYCHAN_CLAIM, 15, PaymentChannelClaim, Delegation::delegatable, (
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction type creates a new check. */
|
/** This transaction type creates a new check. */
|
||||||
TRANSACTION(ttCHECK_CREATE, 16, CheckCreate, Delegation::delegatable, ({
|
TRANSACTION(ttCHECK_CREATE, 16, CheckCreate,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureChecks,
|
||||||
|
({
|
||||||
{sfDestination, soeREQUIRED},
|
{sfDestination, soeREQUIRED},
|
||||||
{sfSendMax, soeREQUIRED},
|
{sfSendMax, soeREQUIRED},
|
||||||
{sfExpiration, soeOPTIONAL},
|
{sfExpiration, soeOPTIONAL},
|
||||||
@@ -159,19 +201,28 @@ TRANSACTION(ttCHECK_CREATE, 16, CheckCreate, Delegation::delegatable, ({
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction type cashes an existing check. */
|
/** This transaction type cashes an existing check. */
|
||||||
TRANSACTION(ttCHECK_CASH, 17, CheckCash, Delegation::delegatable, ({
|
TRANSACTION(ttCHECK_CASH, 17, CheckCash,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureChecks,
|
||||||
|
({
|
||||||
{sfCheckID, soeREQUIRED},
|
{sfCheckID, soeREQUIRED},
|
||||||
{sfAmount, soeOPTIONAL},
|
{sfAmount, soeOPTIONAL},
|
||||||
{sfDeliverMin, soeOPTIONAL},
|
{sfDeliverMin, soeOPTIONAL},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction type cancels an existing check. */
|
/** This transaction type cancels an existing check. */
|
||||||
TRANSACTION(ttCHECK_CANCEL, 18, CheckCancel, Delegation::delegatable, ({
|
TRANSACTION(ttCHECK_CANCEL, 18, CheckCancel,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureChecks,
|
||||||
|
({
|
||||||
{sfCheckID, soeREQUIRED},
|
{sfCheckID, soeREQUIRED},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction type grants or revokes authorization to transfer funds. */
|
/** This transaction type grants or revokes authorization to transfer funds. */
|
||||||
TRANSACTION(ttDEPOSIT_PREAUTH, 19, DepositPreauth, Delegation::delegatable, ({
|
TRANSACTION(ttDEPOSIT_PREAUTH, 19, DepositPreauth,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureDepositPreauth,
|
||||||
|
({
|
||||||
{sfAuthorize, soeOPTIONAL},
|
{sfAuthorize, soeOPTIONAL},
|
||||||
{sfUnauthorize, soeOPTIONAL},
|
{sfUnauthorize, soeOPTIONAL},
|
||||||
{sfAuthorizeCredentials, soeOPTIONAL},
|
{sfAuthorizeCredentials, soeOPTIONAL},
|
||||||
@@ -179,14 +230,20 @@ TRANSACTION(ttDEPOSIT_PREAUTH, 19, DepositPreauth, Delegation::delegatable, ({
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction type modifies a trustline between two accounts. */
|
/** This transaction type modifies a trustline between two accounts. */
|
||||||
TRANSACTION(ttTRUST_SET, 20, TrustSet, Delegation::delegatable, ({
|
TRANSACTION(ttTRUST_SET, 20, TrustSet,
|
||||||
|
Delegation::delegatable,
|
||||||
|
uint256{},
|
||||||
|
({
|
||||||
{sfLimitAmount, soeOPTIONAL},
|
{sfLimitAmount, soeOPTIONAL},
|
||||||
{sfQualityIn, soeOPTIONAL},
|
{sfQualityIn, soeOPTIONAL},
|
||||||
{sfQualityOut, soeOPTIONAL},
|
{sfQualityOut, soeOPTIONAL},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction type deletes an existing account. */
|
/** This transaction type deletes an existing account. */
|
||||||
TRANSACTION(ttACCOUNT_DELETE, 21, AccountDelete, Delegation::notDelegatable, ({
|
TRANSACTION(ttACCOUNT_DELETE, 21, AccountDelete,
|
||||||
|
Delegation::notDelegatable,
|
||||||
|
uint256{},
|
||||||
|
({
|
||||||
{sfDestination, soeREQUIRED},
|
{sfDestination, soeREQUIRED},
|
||||||
{sfDestinationTag, soeOPTIONAL},
|
{sfDestinationTag, soeOPTIONAL},
|
||||||
{sfCredentialIDs, soeOPTIONAL},
|
{sfCredentialIDs, soeOPTIONAL},
|
||||||
@@ -195,7 +252,10 @@ TRANSACTION(ttACCOUNT_DELETE, 21, AccountDelete, Delegation::notDelegatable, ({
|
|||||||
// 22 reserved
|
// 22 reserved
|
||||||
|
|
||||||
/** This transaction mints a new NFT. */
|
/** This transaction mints a new NFT. */
|
||||||
TRANSACTION(ttNFTOKEN_MINT, 25, NFTokenMint, Delegation::delegatable, ({
|
TRANSACTION(ttNFTOKEN_MINT, 25, NFTokenMint,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureNonFungibleTokensV1,
|
||||||
|
({
|
||||||
{sfNFTokenTaxon, soeREQUIRED},
|
{sfNFTokenTaxon, soeREQUIRED},
|
||||||
{sfTransferFee, soeOPTIONAL},
|
{sfTransferFee, soeOPTIONAL},
|
||||||
{sfIssuer, soeOPTIONAL},
|
{sfIssuer, soeOPTIONAL},
|
||||||
@@ -206,13 +266,19 @@ TRANSACTION(ttNFTOKEN_MINT, 25, NFTokenMint, Delegation::delegatable, ({
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction burns (i.e. destroys) an existing NFT. */
|
/** This transaction burns (i.e. destroys) an existing NFT. */
|
||||||
TRANSACTION(ttNFTOKEN_BURN, 26, NFTokenBurn, Delegation::delegatable, ({
|
TRANSACTION(ttNFTOKEN_BURN, 26, NFTokenBurn,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureNonFungibleTokensV1,
|
||||||
|
({
|
||||||
{sfNFTokenID, soeREQUIRED},
|
{sfNFTokenID, soeREQUIRED},
|
||||||
{sfOwner, soeOPTIONAL},
|
{sfOwner, soeOPTIONAL},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction creates a new offer to buy or sell an NFT. */
|
/** This transaction creates a new offer to buy or sell an NFT. */
|
||||||
TRANSACTION(ttNFTOKEN_CREATE_OFFER, 27, NFTokenCreateOffer, Delegation::delegatable, ({
|
TRANSACTION(ttNFTOKEN_CREATE_OFFER, 27, NFTokenCreateOffer,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureNonFungibleTokensV1,
|
||||||
|
({
|
||||||
{sfNFTokenID, soeREQUIRED},
|
{sfNFTokenID, soeREQUIRED},
|
||||||
{sfAmount, soeREQUIRED},
|
{sfAmount, soeREQUIRED},
|
||||||
{sfDestination, soeOPTIONAL},
|
{sfDestination, soeOPTIONAL},
|
||||||
@@ -221,25 +287,37 @@ TRANSACTION(ttNFTOKEN_CREATE_OFFER, 27, NFTokenCreateOffer, Delegation::delegata
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction cancels an existing offer to buy or sell an existing NFT. */
|
/** This transaction cancels an existing offer to buy or sell an existing NFT. */
|
||||||
TRANSACTION(ttNFTOKEN_CANCEL_OFFER, 28, NFTokenCancelOffer, Delegation::delegatable, ({
|
TRANSACTION(ttNFTOKEN_CANCEL_OFFER, 28, NFTokenCancelOffer,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureNonFungibleTokensV1,
|
||||||
|
({
|
||||||
{sfNFTokenOffers, soeREQUIRED},
|
{sfNFTokenOffers, soeREQUIRED},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction accepts an existing offer to buy or sell an existing NFT. */
|
/** This transaction accepts an existing offer to buy or sell an existing NFT. */
|
||||||
TRANSACTION(ttNFTOKEN_ACCEPT_OFFER, 29, NFTokenAcceptOffer, Delegation::delegatable, ({
|
TRANSACTION(ttNFTOKEN_ACCEPT_OFFER, 29, NFTokenAcceptOffer,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureNonFungibleTokensV1,
|
||||||
|
({
|
||||||
{sfNFTokenBuyOffer, soeOPTIONAL},
|
{sfNFTokenBuyOffer, soeOPTIONAL},
|
||||||
{sfNFTokenSellOffer, soeOPTIONAL},
|
{sfNFTokenSellOffer, soeOPTIONAL},
|
||||||
{sfNFTokenBrokerFee, soeOPTIONAL},
|
{sfNFTokenBrokerFee, soeOPTIONAL},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction claws back issued tokens. */
|
/** This transaction claws back issued tokens. */
|
||||||
TRANSACTION(ttCLAWBACK, 30, Clawback, Delegation::delegatable, ({
|
TRANSACTION(ttCLAWBACK, 30, Clawback,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureClawback,
|
||||||
|
({
|
||||||
{sfAmount, soeREQUIRED, soeMPTSupported},
|
{sfAmount, soeREQUIRED, soeMPTSupported},
|
||||||
{sfHolder, soeOPTIONAL},
|
{sfHolder, soeOPTIONAL},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction claws back tokens from an AMM pool. */
|
/** This transaction claws back tokens from an AMM pool. */
|
||||||
TRANSACTION(ttAMM_CLAWBACK, 31, AMMClawback, Delegation::delegatable, ({
|
TRANSACTION(ttAMM_CLAWBACK, 31, AMMClawback,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureAMMClawback,
|
||||||
|
({
|
||||||
{sfHolder, soeREQUIRED},
|
{sfHolder, soeREQUIRED},
|
||||||
{sfAsset, soeREQUIRED},
|
{sfAsset, soeREQUIRED},
|
||||||
{sfAsset2, soeREQUIRED},
|
{sfAsset2, soeREQUIRED},
|
||||||
@@ -247,14 +325,20 @@ TRANSACTION(ttAMM_CLAWBACK, 31, AMMClawback, Delegation::delegatable, ({
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction type creates an AMM instance */
|
/** This transaction type creates an AMM instance */
|
||||||
TRANSACTION(ttAMM_CREATE, 35, AMMCreate, Delegation::delegatable, ({
|
TRANSACTION(ttAMM_CREATE, 35, AMMCreate,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureAMM,
|
||||||
|
({
|
||||||
{sfAmount, soeREQUIRED},
|
{sfAmount, soeREQUIRED},
|
||||||
{sfAmount2, soeREQUIRED},
|
{sfAmount2, soeREQUIRED},
|
||||||
{sfTradingFee, soeREQUIRED},
|
{sfTradingFee, soeREQUIRED},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction type deposits into an AMM instance */
|
/** This transaction type deposits into an AMM instance */
|
||||||
TRANSACTION(ttAMM_DEPOSIT, 36, AMMDeposit, Delegation::delegatable, ({
|
TRANSACTION(ttAMM_DEPOSIT, 36, AMMDeposit,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureAMM,
|
||||||
|
({
|
||||||
{sfAsset, soeREQUIRED},
|
{sfAsset, soeREQUIRED},
|
||||||
{sfAsset2, soeREQUIRED},
|
{sfAsset2, soeREQUIRED},
|
||||||
{sfAmount, soeOPTIONAL},
|
{sfAmount, soeOPTIONAL},
|
||||||
@@ -265,7 +349,10 @@ TRANSACTION(ttAMM_DEPOSIT, 36, AMMDeposit, Delegation::delegatable, ({
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction type withdraws from an AMM instance */
|
/** This transaction type withdraws from an AMM instance */
|
||||||
TRANSACTION(ttAMM_WITHDRAW, 37, AMMWithdraw, Delegation::delegatable, ({
|
TRANSACTION(ttAMM_WITHDRAW, 37, AMMWithdraw,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureAMM,
|
||||||
|
({
|
||||||
{sfAsset, soeREQUIRED},
|
{sfAsset, soeREQUIRED},
|
||||||
{sfAsset2, soeREQUIRED},
|
{sfAsset2, soeREQUIRED},
|
||||||
{sfAmount, soeOPTIONAL},
|
{sfAmount, soeOPTIONAL},
|
||||||
@@ -275,14 +362,20 @@ TRANSACTION(ttAMM_WITHDRAW, 37, AMMWithdraw, Delegation::delegatable, ({
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction type votes for the trading fee */
|
/** This transaction type votes for the trading fee */
|
||||||
TRANSACTION(ttAMM_VOTE, 38, AMMVote, Delegation::delegatable, ({
|
TRANSACTION(ttAMM_VOTE, 38, AMMVote,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureAMM,
|
||||||
|
({
|
||||||
{sfAsset, soeREQUIRED},
|
{sfAsset, soeREQUIRED},
|
||||||
{sfAsset2, soeREQUIRED},
|
{sfAsset2, soeREQUIRED},
|
||||||
{sfTradingFee, soeREQUIRED},
|
{sfTradingFee, soeREQUIRED},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction type bids for the auction slot */
|
/** This transaction type bids for the auction slot */
|
||||||
TRANSACTION(ttAMM_BID, 39, AMMBid, Delegation::delegatable, ({
|
TRANSACTION(ttAMM_BID, 39, AMMBid,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureAMM,
|
||||||
|
({
|
||||||
{sfAsset, soeREQUIRED},
|
{sfAsset, soeREQUIRED},
|
||||||
{sfAsset2, soeREQUIRED},
|
{sfAsset2, soeREQUIRED},
|
||||||
{sfBidMin, soeOPTIONAL},
|
{sfBidMin, soeOPTIONAL},
|
||||||
@@ -291,20 +384,29 @@ TRANSACTION(ttAMM_BID, 39, AMMBid, Delegation::delegatable, ({
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction type deletes AMM in the empty state */
|
/** This transaction type deletes AMM in the empty state */
|
||||||
TRANSACTION(ttAMM_DELETE, 40, AMMDelete, Delegation::delegatable, ({
|
TRANSACTION(ttAMM_DELETE, 40, AMMDelete,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureAMM,
|
||||||
|
({
|
||||||
{sfAsset, soeREQUIRED},
|
{sfAsset, soeREQUIRED},
|
||||||
{sfAsset2, soeREQUIRED},
|
{sfAsset2, soeREQUIRED},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transactions creates a crosschain sequence number */
|
/** This transactions creates a crosschain sequence number */
|
||||||
TRANSACTION(ttXCHAIN_CREATE_CLAIM_ID, 41, XChainCreateClaimID, Delegation::delegatable, ({
|
TRANSACTION(ttXCHAIN_CREATE_CLAIM_ID, 41, XChainCreateClaimID,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureXChainBridge,
|
||||||
|
({
|
||||||
{sfXChainBridge, soeREQUIRED},
|
{sfXChainBridge, soeREQUIRED},
|
||||||
{sfSignatureReward, soeREQUIRED},
|
{sfSignatureReward, soeREQUIRED},
|
||||||
{sfOtherChainSource, soeREQUIRED},
|
{sfOtherChainSource, soeREQUIRED},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transactions initiates a crosschain transaction */
|
/** This transactions initiates a crosschain transaction */
|
||||||
TRANSACTION(ttXCHAIN_COMMIT, 42, XChainCommit, Delegation::delegatable, ({
|
TRANSACTION(ttXCHAIN_COMMIT, 42, XChainCommit,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureXChainBridge,
|
||||||
|
({
|
||||||
{sfXChainBridge, soeREQUIRED},
|
{sfXChainBridge, soeREQUIRED},
|
||||||
{sfXChainClaimID, soeREQUIRED},
|
{sfXChainClaimID, soeREQUIRED},
|
||||||
{sfAmount, soeREQUIRED},
|
{sfAmount, soeREQUIRED},
|
||||||
@@ -312,7 +414,10 @@ TRANSACTION(ttXCHAIN_COMMIT, 42, XChainCommit, Delegation::delegatable, ({
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction completes a crosschain transaction */
|
/** This transaction completes a crosschain transaction */
|
||||||
TRANSACTION(ttXCHAIN_CLAIM, 43, XChainClaim, Delegation::delegatable, ({
|
TRANSACTION(ttXCHAIN_CLAIM, 43, XChainClaim,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureXChainBridge,
|
||||||
|
({
|
||||||
{sfXChainBridge, soeREQUIRED},
|
{sfXChainBridge, soeREQUIRED},
|
||||||
{sfXChainClaimID, soeREQUIRED},
|
{sfXChainClaimID, soeREQUIRED},
|
||||||
{sfDestination, soeREQUIRED},
|
{sfDestination, soeREQUIRED},
|
||||||
@@ -321,7 +426,10 @@ TRANSACTION(ttXCHAIN_CLAIM, 43, XChainClaim, Delegation::delegatable, ({
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction initiates a crosschain account create transaction */
|
/** This transaction initiates a crosschain account create transaction */
|
||||||
TRANSACTION(ttXCHAIN_ACCOUNT_CREATE_COMMIT, 44, XChainAccountCreateCommit, Delegation::delegatable, ({
|
TRANSACTION(ttXCHAIN_ACCOUNT_CREATE_COMMIT, 44, XChainAccountCreateCommit,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureXChainBridge,
|
||||||
|
({
|
||||||
{sfXChainBridge, soeREQUIRED},
|
{sfXChainBridge, soeREQUIRED},
|
||||||
{sfDestination, soeREQUIRED},
|
{sfDestination, soeREQUIRED},
|
||||||
{sfAmount, soeREQUIRED},
|
{sfAmount, soeREQUIRED},
|
||||||
@@ -329,7 +437,10 @@ TRANSACTION(ttXCHAIN_ACCOUNT_CREATE_COMMIT, 44, XChainAccountCreateCommit, Deleg
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction adds an attestation to a claim */
|
/** This transaction adds an attestation to a claim */
|
||||||
TRANSACTION(ttXCHAIN_ADD_CLAIM_ATTESTATION, 45, XChainAddClaimAttestation, Delegation::delegatable, ({
|
TRANSACTION(ttXCHAIN_ADD_CLAIM_ATTESTATION, 45, XChainAddClaimAttestation,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureXChainBridge,
|
||||||
|
({
|
||||||
{sfXChainBridge, soeREQUIRED},
|
{sfXChainBridge, soeREQUIRED},
|
||||||
|
|
||||||
{sfAttestationSignerAccount, soeREQUIRED},
|
{sfAttestationSignerAccount, soeREQUIRED},
|
||||||
@@ -345,7 +456,10 @@ TRANSACTION(ttXCHAIN_ADD_CLAIM_ATTESTATION, 45, XChainAddClaimAttestation, Deleg
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction adds an attestation to an account */
|
/** This transaction adds an attestation to an account */
|
||||||
TRANSACTION(ttXCHAIN_ADD_ACCOUNT_CREATE_ATTESTATION, 46, XChainAddAccountCreateAttestation, Delegation::delegatable, ({
|
TRANSACTION(ttXCHAIN_ADD_ACCOUNT_CREATE_ATTESTATION, 46, XChainAddAccountCreateAttestation,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureXChainBridge,
|
||||||
|
({
|
||||||
{sfXChainBridge, soeREQUIRED},
|
{sfXChainBridge, soeREQUIRED},
|
||||||
|
|
||||||
{sfAttestationSignerAccount, soeREQUIRED},
|
{sfAttestationSignerAccount, soeREQUIRED},
|
||||||
@@ -362,31 +476,46 @@ TRANSACTION(ttXCHAIN_ADD_ACCOUNT_CREATE_ATTESTATION, 46, XChainAddAccountCreateA
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction modifies a sidechain */
|
/** This transaction modifies a sidechain */
|
||||||
TRANSACTION(ttXCHAIN_MODIFY_BRIDGE, 47, XChainModifyBridge, Delegation::delegatable, ({
|
TRANSACTION(ttXCHAIN_MODIFY_BRIDGE, 47, XChainModifyBridge,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureXChainBridge,
|
||||||
|
({
|
||||||
{sfXChainBridge, soeREQUIRED},
|
{sfXChainBridge, soeREQUIRED},
|
||||||
{sfSignatureReward, soeOPTIONAL},
|
{sfSignatureReward, soeOPTIONAL},
|
||||||
{sfMinAccountCreateAmount, soeOPTIONAL},
|
{sfMinAccountCreateAmount, soeOPTIONAL},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transactions creates a sidechain */
|
/** This transactions creates a sidechain */
|
||||||
TRANSACTION(ttXCHAIN_CREATE_BRIDGE, 48, XChainCreateBridge, Delegation::delegatable, ({
|
TRANSACTION(ttXCHAIN_CREATE_BRIDGE, 48, XChainCreateBridge,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureXChainBridge,
|
||||||
|
({
|
||||||
{sfXChainBridge, soeREQUIRED},
|
{sfXChainBridge, soeREQUIRED},
|
||||||
{sfSignatureReward, soeREQUIRED},
|
{sfSignatureReward, soeREQUIRED},
|
||||||
{sfMinAccountCreateAmount, soeOPTIONAL},
|
{sfMinAccountCreateAmount, soeOPTIONAL},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction type creates or updates a DID */
|
/** This transaction type creates or updates a DID */
|
||||||
TRANSACTION(ttDID_SET, 49, DIDSet, Delegation::delegatable, ({
|
TRANSACTION(ttDID_SET, 49, DIDSet,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureDID,
|
||||||
|
({
|
||||||
{sfDIDDocument, soeOPTIONAL},
|
{sfDIDDocument, soeOPTIONAL},
|
||||||
{sfURI, soeOPTIONAL},
|
{sfURI, soeOPTIONAL},
|
||||||
{sfData, soeOPTIONAL},
|
{sfData, soeOPTIONAL},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction type deletes a DID */
|
/** This transaction type deletes a DID */
|
||||||
TRANSACTION(ttDID_DELETE, 50, DIDDelete, Delegation::delegatable, ({}))
|
TRANSACTION(ttDID_DELETE, 50, DIDDelete,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureDID,
|
||||||
|
({}))
|
||||||
|
|
||||||
/** This transaction type creates an Oracle instance */
|
/** This transaction type creates an Oracle instance */
|
||||||
TRANSACTION(ttORACLE_SET, 51, OracleSet, Delegation::delegatable, ({
|
TRANSACTION(ttORACLE_SET, 51, OracleSet,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featurePriceOracle,
|
||||||
|
({
|
||||||
{sfOracleDocumentID, soeREQUIRED},
|
{sfOracleDocumentID, soeREQUIRED},
|
||||||
{sfProvider, soeOPTIONAL},
|
{sfProvider, soeOPTIONAL},
|
||||||
{sfURI, soeOPTIONAL},
|
{sfURI, soeOPTIONAL},
|
||||||
@@ -396,18 +525,27 @@ TRANSACTION(ttORACLE_SET, 51, OracleSet, Delegation::delegatable, ({
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction type deletes an Oracle instance */
|
/** This transaction type deletes an Oracle instance */
|
||||||
TRANSACTION(ttORACLE_DELETE, 52, OracleDelete, Delegation::delegatable, ({
|
TRANSACTION(ttORACLE_DELETE, 52, OracleDelete,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featurePriceOracle,
|
||||||
|
({
|
||||||
{sfOracleDocumentID, soeREQUIRED},
|
{sfOracleDocumentID, soeREQUIRED},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction type fixes a problem in the ledger state */
|
/** This transaction type fixes a problem in the ledger state */
|
||||||
TRANSACTION(ttLEDGER_STATE_FIX, 53, LedgerStateFix, Delegation::delegatable, ({
|
TRANSACTION(ttLEDGER_STATE_FIX, 53, LedgerStateFix,
|
||||||
|
Delegation::delegatable,
|
||||||
|
fixNFTokenPageLinks,
|
||||||
|
({
|
||||||
{sfLedgerFixType, soeREQUIRED},
|
{sfLedgerFixType, soeREQUIRED},
|
||||||
{sfOwner, soeOPTIONAL},
|
{sfOwner, soeOPTIONAL},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction type creates a MPTokensIssuance instance */
|
/** This transaction type creates a MPTokensIssuance instance */
|
||||||
TRANSACTION(ttMPTOKEN_ISSUANCE_CREATE, 54, MPTokenIssuanceCreate, Delegation::delegatable, ({
|
TRANSACTION(ttMPTOKEN_ISSUANCE_CREATE, 54, MPTokenIssuanceCreate,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureMPTokensV1,
|
||||||
|
({
|
||||||
{sfAssetScale, soeOPTIONAL},
|
{sfAssetScale, soeOPTIONAL},
|
||||||
{sfTransferFee, soeOPTIONAL},
|
{sfTransferFee, soeOPTIONAL},
|
||||||
{sfMaximumAmount, soeOPTIONAL},
|
{sfMaximumAmount, soeOPTIONAL},
|
||||||
@@ -416,25 +554,37 @@ TRANSACTION(ttMPTOKEN_ISSUANCE_CREATE, 54, MPTokenIssuanceCreate, Delegation::de
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction type destroys a MPTokensIssuance instance */
|
/** This transaction type destroys a MPTokensIssuance instance */
|
||||||
TRANSACTION(ttMPTOKEN_ISSUANCE_DESTROY, 55, MPTokenIssuanceDestroy, Delegation::delegatable, ({
|
TRANSACTION(ttMPTOKEN_ISSUANCE_DESTROY, 55, MPTokenIssuanceDestroy,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureMPTokensV1,
|
||||||
|
({
|
||||||
{sfMPTokenIssuanceID, soeREQUIRED},
|
{sfMPTokenIssuanceID, soeREQUIRED},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction type sets flags on a MPTokensIssuance or MPToken instance */
|
/** This transaction type sets flags on a MPTokensIssuance or MPToken instance */
|
||||||
TRANSACTION(ttMPTOKEN_ISSUANCE_SET, 56, MPTokenIssuanceSet, Delegation::delegatable, ({
|
TRANSACTION(ttMPTOKEN_ISSUANCE_SET, 56, MPTokenIssuanceSet,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureMPTokensV1,
|
||||||
|
({
|
||||||
{sfMPTokenIssuanceID, soeREQUIRED},
|
{sfMPTokenIssuanceID, soeREQUIRED},
|
||||||
{sfHolder, soeOPTIONAL},
|
{sfHolder, soeOPTIONAL},
|
||||||
{sfDomainID, soeOPTIONAL},
|
{sfDomainID, soeOPTIONAL},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction type authorizes a MPToken instance */
|
/** This transaction type authorizes a MPToken instance */
|
||||||
TRANSACTION(ttMPTOKEN_AUTHORIZE, 57, MPTokenAuthorize, Delegation::delegatable, ({
|
TRANSACTION(ttMPTOKEN_AUTHORIZE, 57, MPTokenAuthorize,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureMPTokensV1,
|
||||||
|
({
|
||||||
{sfMPTokenIssuanceID, soeREQUIRED},
|
{sfMPTokenIssuanceID, soeREQUIRED},
|
||||||
{sfHolder, soeOPTIONAL},
|
{sfHolder, soeOPTIONAL},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction type create an Credential instance */
|
/** This transaction type create an Credential instance */
|
||||||
TRANSACTION(ttCREDENTIAL_CREATE, 58, CredentialCreate, Delegation::delegatable, ({
|
TRANSACTION(ttCREDENTIAL_CREATE, 58, CredentialCreate,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureCredentials,
|
||||||
|
({
|
||||||
{sfSubject, soeREQUIRED},
|
{sfSubject, soeREQUIRED},
|
||||||
{sfCredentialType, soeREQUIRED},
|
{sfCredentialType, soeREQUIRED},
|
||||||
{sfExpiration, soeOPTIONAL},
|
{sfExpiration, soeOPTIONAL},
|
||||||
@@ -442,44 +592,65 @@ TRANSACTION(ttCREDENTIAL_CREATE, 58, CredentialCreate, Delegation::delegatable,
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction type accept an Credential object */
|
/** This transaction type accept an Credential object */
|
||||||
TRANSACTION(ttCREDENTIAL_ACCEPT, 59, CredentialAccept, Delegation::delegatable, ({
|
TRANSACTION(ttCREDENTIAL_ACCEPT, 59, CredentialAccept,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureCredentials,
|
||||||
|
({
|
||||||
{sfIssuer, soeREQUIRED},
|
{sfIssuer, soeREQUIRED},
|
||||||
{sfCredentialType, soeREQUIRED},
|
{sfCredentialType, soeREQUIRED},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction type delete an Credential object */
|
/** This transaction type delete an Credential object */
|
||||||
TRANSACTION(ttCREDENTIAL_DELETE, 60, CredentialDelete, Delegation::delegatable, ({
|
TRANSACTION(ttCREDENTIAL_DELETE, 60, CredentialDelete,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureCredentials,
|
||||||
|
({
|
||||||
{sfSubject, soeOPTIONAL},
|
{sfSubject, soeOPTIONAL},
|
||||||
{sfIssuer, soeOPTIONAL},
|
{sfIssuer, soeOPTIONAL},
|
||||||
{sfCredentialType, soeREQUIRED},
|
{sfCredentialType, soeREQUIRED},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction type modify a NFToken */
|
/** This transaction type modify a NFToken */
|
||||||
TRANSACTION(ttNFTOKEN_MODIFY, 61, NFTokenModify, Delegation::delegatable, ({
|
TRANSACTION(ttNFTOKEN_MODIFY, 61, NFTokenModify,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureDynamicNFT,
|
||||||
|
({
|
||||||
{sfNFTokenID, soeREQUIRED},
|
{sfNFTokenID, soeREQUIRED},
|
||||||
{sfOwner, soeOPTIONAL},
|
{sfOwner, soeOPTIONAL},
|
||||||
{sfURI, soeOPTIONAL},
|
{sfURI, soeOPTIONAL},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction type creates or modifies a Permissioned Domain */
|
/** This transaction type creates or modifies a Permissioned Domain */
|
||||||
TRANSACTION(ttPERMISSIONED_DOMAIN_SET, 62, PermissionedDomainSet, Delegation::delegatable, ({
|
TRANSACTION(ttPERMISSIONED_DOMAIN_SET, 62, PermissionedDomainSet,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featurePermissionedDomains,
|
||||||
|
({
|
||||||
{sfDomainID, soeOPTIONAL},
|
{sfDomainID, soeOPTIONAL},
|
||||||
{sfAcceptedCredentials, soeREQUIRED},
|
{sfAcceptedCredentials, soeREQUIRED},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction type deletes a Permissioned Domain */
|
/** This transaction type deletes a Permissioned Domain */
|
||||||
TRANSACTION(ttPERMISSIONED_DOMAIN_DELETE, 63, PermissionedDomainDelete, Delegation::delegatable, ({
|
TRANSACTION(ttPERMISSIONED_DOMAIN_DELETE, 63, PermissionedDomainDelete,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featurePermissionedDomains,
|
||||||
|
({
|
||||||
{sfDomainID, soeREQUIRED},
|
{sfDomainID, soeREQUIRED},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction type delegates authorized account specified permissions */
|
/** This transaction type delegates authorized account specified permissions */
|
||||||
TRANSACTION(ttDELEGATE_SET, 64, DelegateSet, Delegation::notDelegatable, ({
|
TRANSACTION(ttDELEGATE_SET, 64, DelegateSet,
|
||||||
|
Delegation::notDelegatable,
|
||||||
|
featurePermissionDelegation,
|
||||||
|
({
|
||||||
{sfAuthorize, soeREQUIRED},
|
{sfAuthorize, soeREQUIRED},
|
||||||
{sfPermissions, soeREQUIRED},
|
{sfPermissions, soeREQUIRED},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction creates a single asset vault. */
|
/** This transaction creates a single asset vault. */
|
||||||
TRANSACTION(ttVAULT_CREATE, 65, VaultCreate, Delegation::delegatable, ({
|
TRANSACTION(ttVAULT_CREATE, 65, VaultCreate,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureSingleAssetVault,
|
||||||
|
({
|
||||||
{sfAsset, soeREQUIRED, soeMPTSupported},
|
{sfAsset, soeREQUIRED, soeMPTSupported},
|
||||||
{sfAssetsMaximum, soeOPTIONAL},
|
{sfAssetsMaximum, soeOPTIONAL},
|
||||||
{sfMPTokenMetadata, soeOPTIONAL},
|
{sfMPTokenMetadata, soeOPTIONAL},
|
||||||
@@ -490,7 +661,10 @@ TRANSACTION(ttVAULT_CREATE, 65, VaultCreate, Delegation::delegatable, ({
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction updates a single asset vault. */
|
/** This transaction updates a single asset vault. */
|
||||||
TRANSACTION(ttVAULT_SET, 66, VaultSet, Delegation::delegatable, ({
|
TRANSACTION(ttVAULT_SET, 66, VaultSet,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureSingleAssetVault,
|
||||||
|
({
|
||||||
{sfVaultID, soeREQUIRED},
|
{sfVaultID, soeREQUIRED},
|
||||||
{sfAssetsMaximum, soeOPTIONAL},
|
{sfAssetsMaximum, soeOPTIONAL},
|
||||||
{sfDomainID, soeOPTIONAL},
|
{sfDomainID, soeOPTIONAL},
|
||||||
@@ -498,18 +672,27 @@ TRANSACTION(ttVAULT_SET, 66, VaultSet, Delegation::delegatable, ({
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction deletes a single asset vault. */
|
/** This transaction deletes a single asset vault. */
|
||||||
TRANSACTION(ttVAULT_DELETE, 67, VaultDelete, Delegation::delegatable, ({
|
TRANSACTION(ttVAULT_DELETE, 67, VaultDelete,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureSingleAssetVault,
|
||||||
|
({
|
||||||
{sfVaultID, soeREQUIRED},
|
{sfVaultID, soeREQUIRED},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction trades assets for shares with a vault. */
|
/** This transaction trades assets for shares with a vault. */
|
||||||
TRANSACTION(ttVAULT_DEPOSIT, 68, VaultDeposit, Delegation::delegatable, ({
|
TRANSACTION(ttVAULT_DEPOSIT, 68, VaultDeposit,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureSingleAssetVault,
|
||||||
|
({
|
||||||
{sfVaultID, soeREQUIRED},
|
{sfVaultID, soeREQUIRED},
|
||||||
{sfAmount, soeREQUIRED, soeMPTSupported},
|
{sfAmount, soeREQUIRED, soeMPTSupported},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction trades shares for assets with a vault. */
|
/** This transaction trades shares for assets with a vault. */
|
||||||
TRANSACTION(ttVAULT_WITHDRAW, 69, VaultWithdraw, Delegation::delegatable, ({
|
TRANSACTION(ttVAULT_WITHDRAW, 69, VaultWithdraw,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureSingleAssetVault,
|
||||||
|
({
|
||||||
{sfVaultID, soeREQUIRED},
|
{sfVaultID, soeREQUIRED},
|
||||||
{sfAmount, soeREQUIRED, soeMPTSupported},
|
{sfAmount, soeREQUIRED, soeMPTSupported},
|
||||||
{sfDestination, soeOPTIONAL},
|
{sfDestination, soeOPTIONAL},
|
||||||
@@ -517,14 +700,20 @@ TRANSACTION(ttVAULT_WITHDRAW, 69, VaultWithdraw, Delegation::delegatable, ({
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction claws back tokens from a vault. */
|
/** This transaction claws back tokens from a vault. */
|
||||||
TRANSACTION(ttVAULT_CLAWBACK, 70, VaultClawback, Delegation::delegatable, ({
|
TRANSACTION(ttVAULT_CLAWBACK, 70, VaultClawback,
|
||||||
|
Delegation::delegatable,
|
||||||
|
featureSingleAssetVault,
|
||||||
|
({
|
||||||
{sfVaultID, soeREQUIRED},
|
{sfVaultID, soeREQUIRED},
|
||||||
{sfHolder, soeREQUIRED},
|
{sfHolder, soeREQUIRED},
|
||||||
{sfAmount, soeOPTIONAL, soeMPTSupported},
|
{sfAmount, soeOPTIONAL, soeMPTSupported},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
/** This transaction type batches together transactions. */
|
/** This transaction type batches together transactions. */
|
||||||
TRANSACTION(ttBATCH, 71, Batch, Delegation::notDelegatable, ({
|
TRANSACTION(ttBATCH, 71, Batch,
|
||||||
|
Delegation::notDelegatable,
|
||||||
|
featureBatch,
|
||||||
|
({
|
||||||
{sfRawTransactions, soeREQUIRED},
|
{sfRawTransactions, soeREQUIRED},
|
||||||
{sfBatchSigners, soeOPTIONAL},
|
{sfBatchSigners, soeOPTIONAL},
|
||||||
}))
|
}))
|
||||||
@@ -533,7 +722,10 @@ TRANSACTION(ttBATCH, 71, Batch, Delegation::notDelegatable, ({
|
|||||||
|
|
||||||
For details, see: https://xrpl.org/amendments.html
|
For details, see: https://xrpl.org/amendments.html
|
||||||
*/
|
*/
|
||||||
TRANSACTION(ttAMENDMENT, 100, EnableAmendment, Delegation::notDelegatable, ({
|
TRANSACTION(ttAMENDMENT, 100, EnableAmendment,
|
||||||
|
Delegation::notDelegatable,
|
||||||
|
uint256{},
|
||||||
|
({
|
||||||
{sfLedgerSequence, soeREQUIRED},
|
{sfLedgerSequence, soeREQUIRED},
|
||||||
{sfAmendment, soeREQUIRED},
|
{sfAmendment, soeREQUIRED},
|
||||||
}))
|
}))
|
||||||
@@ -541,7 +733,10 @@ TRANSACTION(ttAMENDMENT, 100, EnableAmendment, Delegation::notDelegatable, ({
|
|||||||
/** This system-generated transaction type is used to update the network's fee settings.
|
/** This system-generated transaction type is used to update the network's fee settings.
|
||||||
For details, see: https://xrpl.org/fee-voting.html
|
For details, see: https://xrpl.org/fee-voting.html
|
||||||
*/
|
*/
|
||||||
TRANSACTION(ttFEE, 101, SetFee, Delegation::notDelegatable, ({
|
TRANSACTION(ttFEE, 101, SetFee,
|
||||||
|
Delegation::notDelegatable,
|
||||||
|
uint256{},
|
||||||
|
({
|
||||||
{sfLedgerSequence, soeOPTIONAL},
|
{sfLedgerSequence, soeOPTIONAL},
|
||||||
// Old version uses raw numbers
|
// Old version uses raw numbers
|
||||||
{sfBaseFee, soeOPTIONAL},
|
{sfBaseFee, soeOPTIONAL},
|
||||||
@@ -561,7 +756,10 @@ TRANSACTION(ttFEE, 101, SetFee, Delegation::notDelegatable, ({
|
|||||||
|
|
||||||
For details, see: https://xrpl.org/negative-unl.html
|
For details, see: https://xrpl.org/negative-unl.html
|
||||||
*/
|
*/
|
||||||
TRANSACTION(ttUNL_MODIFY, 102, UNLModify, Delegation::notDelegatable, ({
|
TRANSACTION(ttUNL_MODIFY, 102, UNLModify,
|
||||||
|
Delegation::notDelegatable,
|
||||||
|
uint256{},
|
||||||
|
({
|
||||||
{sfUNLModifyDisabling, soeREQUIRED},
|
{sfUNLModifyDisabling, soeREQUIRED},
|
||||||
{sfLedgerSequence, soeREQUIRED},
|
{sfLedgerSequence, soeREQUIRED},
|
||||||
{sfUNLModifyValidator, soeREQUIRED},
|
{sfUNLModifyValidator, soeREQUIRED},
|
||||||
|
|||||||
@@ -713,7 +713,7 @@ JSS(write_load); // out: GetCounts
|
|||||||
#pragma push_macro("TRANSACTION")
|
#pragma push_macro("TRANSACTION")
|
||||||
#undef TRANSACTION
|
#undef TRANSACTION
|
||||||
|
|
||||||
#define TRANSACTION(tag, value, name, delegatable, fields) JSS(name);
|
#define TRANSACTION(tag, value, name, ...) JSS(name);
|
||||||
|
|
||||||
#include <xrpl/protocol/detail/transactions.macro>
|
#include <xrpl/protocol/detail/transactions.macro>
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#include <xrpl/beast/utility/instrumentation.h>
|
#include <xrpl/beast/utility/instrumentation.h>
|
||||||
|
#include <xrpl/protocol/Feature.h>
|
||||||
#include <xrpl/protocol/Permissions.h>
|
#include <xrpl/protocol/Permissions.h>
|
||||||
#include <xrpl/protocol/jss.h>
|
#include <xrpl/protocol/jss.h>
|
||||||
|
|
||||||
@@ -25,11 +26,24 @@ namespace ripple {
|
|||||||
|
|
||||||
Permission::Permission()
|
Permission::Permission()
|
||||||
{
|
{
|
||||||
|
txFeatureMap_ = {
|
||||||
|
#pragma push_macro("TRANSACTION")
|
||||||
|
#undef TRANSACTION
|
||||||
|
|
||||||
|
#define TRANSACTION(tag, value, name, delegatable, amendment, ...) \
|
||||||
|
{value, amendment},
|
||||||
|
|
||||||
|
#include <xrpl/protocol/detail/transactions.macro>
|
||||||
|
|
||||||
|
#undef TRANSACTION
|
||||||
|
#pragma pop_macro("TRANSACTION")
|
||||||
|
};
|
||||||
|
|
||||||
delegatableTx_ = {
|
delegatableTx_ = {
|
||||||
#pragma push_macro("TRANSACTION")
|
#pragma push_macro("TRANSACTION")
|
||||||
#undef TRANSACTION
|
#undef TRANSACTION
|
||||||
|
|
||||||
#define TRANSACTION(tag, value, name, delegatable, fields) {value, delegatable},
|
#define TRANSACTION(tag, value, name, delegatable, ...) {value, delegatable},
|
||||||
|
|
||||||
#include <xrpl/protocol/detail/transactions.macro>
|
#include <xrpl/protocol/detail/transactions.macro>
|
||||||
|
|
||||||
@@ -118,7 +132,9 @@ Permission::getGranularTxType(GranularPermissionType const& gpType) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Permission::isDelegatable(std::uint32_t const& permissionValue) const
|
Permission::isDelegatable(
|
||||||
|
std::uint32_t const& permissionValue,
|
||||||
|
Rules const& rules) const
|
||||||
{
|
{
|
||||||
auto const granularPermission =
|
auto const granularPermission =
|
||||||
getGranularName(static_cast<GranularPermissionType>(permissionValue));
|
getGranularName(static_cast<GranularPermissionType>(permissionValue));
|
||||||
@@ -126,7 +142,27 @@ Permission::isDelegatable(std::uint32_t const& permissionValue) const
|
|||||||
// granular permissions are always allowed to be delegated
|
// granular permissions are always allowed to be delegated
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
auto const it = delegatableTx_.find(permissionValue - 1);
|
auto const txType = permissionToTxType(permissionValue);
|
||||||
|
auto const it = delegatableTx_.find(txType);
|
||||||
|
|
||||||
|
if (rules.enabled(fixDelegateV1_1))
|
||||||
|
{
|
||||||
|
if (it == delegatableTx_.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto const txFeaturesIt = txFeatureMap_.find(txType);
|
||||||
|
XRPL_ASSERT(
|
||||||
|
txFeaturesIt != txFeatureMap_.end(),
|
||||||
|
"ripple::Permissions::isDelegatable : tx exists in txFeatureMap_");
|
||||||
|
|
||||||
|
// fixDelegateV1_1: Delegation is only allowed if the required amendment
|
||||||
|
// for the transaction is enabled. For transactions that do not require
|
||||||
|
// an amendment, delegation is always allowed.
|
||||||
|
if (txFeaturesIt->second != uint256{} &&
|
||||||
|
!rules.enabled(txFeaturesIt->second))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (it != delegatableTx_.end() && it->second == Delegation::notDelegatable)
|
if (it != delegatableTx_.end() && it->second == Delegation::notDelegatable)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ TxFormats::TxFormats()
|
|||||||
#undef TRANSACTION
|
#undef TRANSACTION
|
||||||
|
|
||||||
#define UNWRAP(...) __VA_ARGS__
|
#define UNWRAP(...) __VA_ARGS__
|
||||||
#define TRANSACTION(tag, value, name, delegatable, fields) \
|
#define TRANSACTION(tag, value, name, delegatable, amendment, fields) \
|
||||||
add(jss::name, tag, UNWRAP fields, commonFields);
|
add(jss::name, tag, UNWRAP fields, commonFields);
|
||||||
|
|
||||||
#include <xrpl/protocol/detail/transactions.macro>
|
#include <xrpl/protocol/detail/transactions.macro>
|
||||||
|
|||||||
@@ -2442,8 +2442,7 @@ class AMMClawback_test : public beast::unit_test::suite
|
|||||||
void
|
void
|
||||||
run() override
|
run() override
|
||||||
{
|
{
|
||||||
FeatureBitset const all{
|
FeatureBitset const all = jtx::testable_amendments();
|
||||||
jtx::testable_amendments() | fixAMMClawbackRounding};
|
|
||||||
|
|
||||||
testInvalidRequest();
|
testInvalidRequest();
|
||||||
testFeatureDisabled(all - featureAMMClawback);
|
testFeatureDisabled(all - featureAMMClawback);
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#include <test/jtx.h>
|
#include <test/jtx.h>
|
||||||
|
#include <test/jtx/CaptureLogs.h>
|
||||||
#include <test/jtx/delegate.h>
|
#include <test/jtx/delegate.h>
|
||||||
|
|
||||||
#include <xrpl/protocol/Feature.h>
|
#include <xrpl/protocol/Feature.h>
|
||||||
@@ -139,12 +140,12 @@ class Delegate_test : public beast::unit_test::suite
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
testInvalidRequest()
|
testInvalidRequest(FeatureBitset features)
|
||||||
{
|
{
|
||||||
testcase("test invalid DelegateSet");
|
testcase("test invalid DelegateSet");
|
||||||
using namespace jtx;
|
using namespace jtx;
|
||||||
|
|
||||||
Env env(*this);
|
Env env(*this, features);
|
||||||
Account gw{"gateway"};
|
Account gw{"gateway"};
|
||||||
Account alice{"alice"};
|
Account alice{"alice"};
|
||||||
Account bob{"bob"};
|
Account bob{"bob"};
|
||||||
@@ -216,22 +217,17 @@ class Delegate_test : public beast::unit_test::suite
|
|||||||
}
|
}
|
||||||
|
|
||||||
// non-delegatable transaction
|
// non-delegatable transaction
|
||||||
|
auto const res = features[fixDelegateV1_1] ? ter(temMALFORMED)
|
||||||
|
: ter(tecNO_PERMISSION);
|
||||||
{
|
{
|
||||||
env(delegate::set(gw, alice, {"SetRegularKey"}),
|
env(delegate::set(gw, alice, {"SetRegularKey"}), res);
|
||||||
ter(tecNO_PERMISSION));
|
env(delegate::set(gw, alice, {"AccountSet"}), res);
|
||||||
env(delegate::set(gw, alice, {"AccountSet"}),
|
env(delegate::set(gw, alice, {"SignerListSet"}), res);
|
||||||
ter(tecNO_PERMISSION));
|
env(delegate::set(gw, alice, {"DelegateSet"}), res);
|
||||||
env(delegate::set(gw, alice, {"SignerListSet"}),
|
env(delegate::set(gw, alice, {"EnableAmendment"}), res);
|
||||||
ter(tecNO_PERMISSION));
|
env(delegate::set(gw, alice, {"UNLModify"}), res);
|
||||||
env(delegate::set(gw, alice, {"DelegateSet"}),
|
env(delegate::set(gw, alice, {"SetFee"}), res);
|
||||||
ter(tecNO_PERMISSION));
|
env(delegate::set(gw, alice, {"Batch"}), res);
|
||||||
env(delegate::set(gw, alice, {"SetRegularKey"}),
|
|
||||||
ter(tecNO_PERMISSION));
|
|
||||||
env(delegate::set(gw, alice, {"EnableAmendment"}),
|
|
||||||
ter(tecNO_PERMISSION));
|
|
||||||
env(delegate::set(gw, alice, {"UNLModify"}), ter(tecNO_PERMISSION));
|
|
||||||
env(delegate::set(gw, alice, {"SetFee"}), ter(tecNO_PERMISSION));
|
|
||||||
env(delegate::set(gw, alice, {"Batch"}), ter(tecNO_PERMISSION));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -536,7 +532,7 @@ class Delegate_test : public beast::unit_test::suite
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
testPaymentGranular()
|
testPaymentGranular(FeatureBitset features)
|
||||||
{
|
{
|
||||||
testcase("test payment granular");
|
testcase("test payment granular");
|
||||||
using namespace jtx;
|
using namespace jtx;
|
||||||
@@ -706,6 +702,158 @@ class Delegate_test : public beast::unit_test::suite
|
|||||||
env.require(balance(alice, USD(50)));
|
env.require(balance(alice, USD(50)));
|
||||||
BEAST_EXPECT(env.balance(bob, USD) == USD(0));
|
BEAST_EXPECT(env.balance(bob, USD) == USD(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// disallow cross currency payment with only PaymentBurn/PaymentMint
|
||||||
|
// permission
|
||||||
|
{
|
||||||
|
Env env(*this, features);
|
||||||
|
Account const alice{"alice"};
|
||||||
|
Account const bob{"bob"};
|
||||||
|
Account const gw{"gateway"};
|
||||||
|
Account const carol{"carol"};
|
||||||
|
auto const USD = gw["USD"];
|
||||||
|
|
||||||
|
env.fund(XRP(10000), alice, bob, carol, gw);
|
||||||
|
env.close();
|
||||||
|
env.trust(USD(50000), alice);
|
||||||
|
env.trust(USD(50000), bob);
|
||||||
|
env.trust(USD(50000), carol);
|
||||||
|
env(pay(gw, alice, USD(10000)));
|
||||||
|
env(pay(gw, bob, USD(10000)));
|
||||||
|
env(pay(gw, carol, USD(10000)));
|
||||||
|
env.close();
|
||||||
|
|
||||||
|
auto const result = features[fixDelegateV1_1]
|
||||||
|
? static_cast<TER>(tecNO_DELEGATE_PERMISSION)
|
||||||
|
: static_cast<TER>(tesSUCCESS);
|
||||||
|
auto const offerCount = features[fixDelegateV1_1] ? 1 : 0;
|
||||||
|
|
||||||
|
// PaymentMint
|
||||||
|
{
|
||||||
|
env(offer(carol, XRP(100), USD(501)));
|
||||||
|
BEAST_EXPECT(expectOffers(env, carol, 1));
|
||||||
|
env(delegate::set(gw, bob, {"PaymentMint"}));
|
||||||
|
env.close();
|
||||||
|
|
||||||
|
// post-amendment: fixDelegateV1_1
|
||||||
|
// bob can not send cross currency payment on behalf of the gw,
|
||||||
|
// even with PaymentMint permission and gw being the issuer.
|
||||||
|
env(pay(gw, alice, USD(5000)),
|
||||||
|
path(~USD),
|
||||||
|
sendmax(XRP(1001)),
|
||||||
|
txflags(tfPartialPayment),
|
||||||
|
delegate::as(bob),
|
||||||
|
ter(result));
|
||||||
|
BEAST_EXPECT(expectOffers(env, carol, offerCount));
|
||||||
|
|
||||||
|
// succeed with direct payment
|
||||||
|
env(pay(gw, alice, USD(100)), delegate::as(bob));
|
||||||
|
env.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// PaymentBurn
|
||||||
|
{
|
||||||
|
env(offer(bob, XRP(100), USD(501)));
|
||||||
|
BEAST_EXPECT(expectOffers(env, bob, 1));
|
||||||
|
env(delegate::set(alice, bob, {"PaymentBurn"}));
|
||||||
|
env.close();
|
||||||
|
|
||||||
|
// post-amendment: fixDelegateV1_1
|
||||||
|
// bob can not send cross currency payment on behalf of alice,
|
||||||
|
// even with PaymentBurn permission and gw being the issuer.
|
||||||
|
env(pay(alice, gw, USD(5000)),
|
||||||
|
path(~USD),
|
||||||
|
sendmax(XRP(1001)),
|
||||||
|
txflags(tfPartialPayment),
|
||||||
|
delegate::as(bob),
|
||||||
|
ter(result));
|
||||||
|
BEAST_EXPECT(expectOffers(env, bob, offerCount));
|
||||||
|
|
||||||
|
// succeed with direct payment
|
||||||
|
env(pay(alice, gw, USD(100)), delegate::as(bob));
|
||||||
|
env.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PaymentMint and PaymentBurn for MPT
|
||||||
|
{
|
||||||
|
std::string logs;
|
||||||
|
Env env(*this, features, std::make_unique<CaptureLogs>(&logs));
|
||||||
|
Account const alice{"alice"};
|
||||||
|
Account const bob{"bob"};
|
||||||
|
Account const gw{"gateway"};
|
||||||
|
|
||||||
|
MPTTester mpt(env, gw, {.holders = {alice, bob}});
|
||||||
|
mpt.create(
|
||||||
|
{.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanTransfer});
|
||||||
|
|
||||||
|
mpt.authorize({.account = alice});
|
||||||
|
mpt.authorize({.account = bob});
|
||||||
|
|
||||||
|
auto const MPT = mpt["MPT"];
|
||||||
|
env(pay(gw, alice, MPT(500)));
|
||||||
|
env(pay(gw, bob, MPT(500)));
|
||||||
|
env.close();
|
||||||
|
auto aliceMPT = env.balance(alice, MPT);
|
||||||
|
auto bobMPT = env.balance(bob, MPT);
|
||||||
|
|
||||||
|
// PaymentMint
|
||||||
|
{
|
||||||
|
env(delegate::set(gw, bob, {"PaymentMint"}));
|
||||||
|
env.close();
|
||||||
|
|
||||||
|
if (!features[fixDelegateV1_1])
|
||||||
|
{
|
||||||
|
// pre-amendment: PaymentMint is not supported for MPT
|
||||||
|
env(pay(gw, alice, MPT(50)),
|
||||||
|
delegate::as(bob),
|
||||||
|
ter(tefEXCEPTION));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
env(pay(gw, alice, MPT(50)), delegate::as(bob));
|
||||||
|
BEAST_EXPECT(env.balance(alice, MPT) == aliceMPT + MPT(50));
|
||||||
|
BEAST_EXPECT(env.balance(bob, MPT) == bobMPT);
|
||||||
|
aliceMPT = env.balance(alice, MPT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PaymentBurn
|
||||||
|
{
|
||||||
|
env(delegate::set(alice, bob, {"PaymentBurn"}));
|
||||||
|
env.close();
|
||||||
|
|
||||||
|
if (!features[fixDelegateV1_1])
|
||||||
|
{
|
||||||
|
// pre-amendment: PaymentBurn is not supported for MPT
|
||||||
|
env(pay(alice, gw, MPT(50)),
|
||||||
|
delegate::as(bob),
|
||||||
|
ter(tefEXCEPTION));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
env(pay(alice, gw, MPT(50)), delegate::as(bob));
|
||||||
|
BEAST_EXPECT(env.balance(alice, MPT) == aliceMPT - MPT(50));
|
||||||
|
BEAST_EXPECT(env.balance(bob, MPT) == bobMPT);
|
||||||
|
aliceMPT = env.balance(alice, MPT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Payment transaction for MPT is allowed for both pre and post
|
||||||
|
// amendment
|
||||||
|
{
|
||||||
|
env(delegate::set(
|
||||||
|
alice, bob, {"PaymentBurn", "PaymentMint", "Payment"}));
|
||||||
|
env.close();
|
||||||
|
env(pay(alice, gw, MPT(50)), delegate::as(bob));
|
||||||
|
BEAST_EXPECT(env.balance(alice, MPT) == aliceMPT - MPT(50));
|
||||||
|
BEAST_EXPECT(env.balance(bob, MPT) == bobMPT);
|
||||||
|
aliceMPT = env.balance(alice, MPT);
|
||||||
|
env(pay(alice, bob, MPT(100)), delegate::as(bob));
|
||||||
|
BEAST_EXPECT(env.balance(alice, MPT) == aliceMPT - MPT(100));
|
||||||
|
BEAST_EXPECT(env.balance(bob, MPT) == bobMPT + MPT(100));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -1476,18 +1624,216 @@ class Delegate_test : public beast::unit_test::suite
|
|||||||
BEAST_EXPECT(env.balance(edward) == edwardBalance);
|
BEAST_EXPECT(env.balance(edward) == edwardBalance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
testPermissionValue(FeatureBitset features)
|
||||||
|
{
|
||||||
|
testcase("test permission value");
|
||||||
|
using namespace jtx;
|
||||||
|
|
||||||
|
Env env(*this, features);
|
||||||
|
|
||||||
|
Account alice{"alice"};
|
||||||
|
Account bob{"bob"};
|
||||||
|
env.fund(XRP(100000), alice, bob);
|
||||||
|
env.close();
|
||||||
|
|
||||||
|
auto buildRequest = [&](auto value) -> Json::Value {
|
||||||
|
Json::Value jv;
|
||||||
|
jv[jss::TransactionType] = jss::DelegateSet;
|
||||||
|
jv[jss::Account] = alice.human();
|
||||||
|
jv[sfAuthorize.jsonName] = bob.human();
|
||||||
|
|
||||||
|
Json::Value permissionsJson(Json::arrayValue);
|
||||||
|
Json::Value permissionValue;
|
||||||
|
permissionValue[sfPermissionValue.jsonName] = value;
|
||||||
|
Json::Value permissionObj;
|
||||||
|
permissionObj[sfPermission.jsonName] = permissionValue;
|
||||||
|
permissionsJson.append(permissionObj);
|
||||||
|
jv[sfPermissions.jsonName] = permissionsJson;
|
||||||
|
|
||||||
|
return jv;
|
||||||
|
};
|
||||||
|
|
||||||
|
// invalid permission value.
|
||||||
|
// neither granular permission nor transaction level permission
|
||||||
|
for (auto value : {0, 100000, 54321})
|
||||||
|
{
|
||||||
|
auto jv = buildRequest(value);
|
||||||
|
if (!features[fixDelegateV1_1])
|
||||||
|
env(jv);
|
||||||
|
else
|
||||||
|
env(jv, ter(temMALFORMED));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
testTxReqireFeatures(FeatureBitset features)
|
||||||
|
{
|
||||||
|
testcase("test delegate disabled tx");
|
||||||
|
using namespace jtx;
|
||||||
|
|
||||||
|
// map of tx and required feature.
|
||||||
|
// non-delegatable tx are not included.
|
||||||
|
// NFTokenMint, NFTokenBurn, NFTokenCreateOffer, NFTokenCancelOffer,
|
||||||
|
// NFTokenAcceptOffer are not included, they are tested separately.
|
||||||
|
std::unordered_map<std::string, uint256> txRequiredFeatures{
|
||||||
|
{"TicketCreate", featureTicketBatch},
|
||||||
|
{"CheckCreate", featureChecks},
|
||||||
|
{"CheckCash", featureChecks},
|
||||||
|
{"CheckCancel", featureChecks},
|
||||||
|
{"DepositPreauth", featureDepositPreauth},
|
||||||
|
{"Clawback", featureClawback},
|
||||||
|
{"AMMClawback", featureAMMClawback},
|
||||||
|
{"AMMCreate", featureAMM},
|
||||||
|
{"AMMDeposit", featureAMM},
|
||||||
|
{"AMMWithdraw", featureAMM},
|
||||||
|
{"AMMVote", featureAMM},
|
||||||
|
{"AMMBid", featureAMM},
|
||||||
|
{"AMMDelete", featureAMM},
|
||||||
|
{"XChainCreateClaimID", featureXChainBridge},
|
||||||
|
{"XChainCommit", featureXChainBridge},
|
||||||
|
{"XChainClaim", featureXChainBridge},
|
||||||
|
{"XChainAccountCreateCommit", featureXChainBridge},
|
||||||
|
{"XChainAddClaimAttestation", featureXChainBridge},
|
||||||
|
{"XChainAddAccountCreateAttestation", featureXChainBridge},
|
||||||
|
{"XChainModifyBridge", featureXChainBridge},
|
||||||
|
{"XChainCreateBridge", featureXChainBridge},
|
||||||
|
{"DIDSet", featureDID},
|
||||||
|
{"DIDDelete", featureDID},
|
||||||
|
{"OracleSet", featurePriceOracle},
|
||||||
|
{"OracleDelete", featurePriceOracle},
|
||||||
|
{"LedgerStateFix", fixNFTokenPageLinks},
|
||||||
|
{"MPTokenIssuanceCreate", featureMPTokensV1},
|
||||||
|
{"MPTokenIssuanceDestroy", featureMPTokensV1},
|
||||||
|
{"MPTokenIssuanceSet", featureMPTokensV1},
|
||||||
|
{"MPTokenAuthorize", featureMPTokensV1},
|
||||||
|
{"CredentialCreate", featureCredentials},
|
||||||
|
{"CredentialAccept", featureCredentials},
|
||||||
|
{"CredentialDelete", featureCredentials},
|
||||||
|
{"NFTokenModify", featureDynamicNFT},
|
||||||
|
{"PermissionedDomainSet", featurePermissionedDomains},
|
||||||
|
{"PermissionedDomainDelete", featurePermissionedDomains},
|
||||||
|
{"VaultCreate", featureSingleAssetVault},
|
||||||
|
{"VaultSet", featureSingleAssetVault},
|
||||||
|
{"VaultDelete", featureSingleAssetVault},
|
||||||
|
{"VaultDeposit", featureSingleAssetVault},
|
||||||
|
{"VaultWithdraw", featureSingleAssetVault},
|
||||||
|
{"VaultClawback", featureSingleAssetVault}};
|
||||||
|
|
||||||
|
// fixDelegateV1_1 post-amendment: can not delegate tx if any
|
||||||
|
// required feature disabled.
|
||||||
|
{
|
||||||
|
auto txAmendmentDisabled = [&](FeatureBitset features,
|
||||||
|
std::string const& tx) {
|
||||||
|
BEAST_EXPECT(txRequiredFeatures.contains(tx));
|
||||||
|
|
||||||
|
Env env(*this, features - txRequiredFeatures[tx]);
|
||||||
|
|
||||||
|
Account const alice{"alice"};
|
||||||
|
Account const bob{"bob"};
|
||||||
|
env.fund(XRP(100000), alice, bob);
|
||||||
|
env.close();
|
||||||
|
|
||||||
|
if (!features[fixDelegateV1_1])
|
||||||
|
env(delegate::set(alice, bob, {tx}));
|
||||||
|
else
|
||||||
|
env(delegate::set(alice, bob, {tx}), ter(temMALFORMED));
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto const& tx : txRequiredFeatures)
|
||||||
|
txAmendmentDisabled(features, tx.first);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if all the required features in txRequiredFeatures are enabled, will
|
||||||
|
// succeed
|
||||||
|
{
|
||||||
|
auto txAmendmentEnabled = [&](std::string const& tx) {
|
||||||
|
Env env(*this, features);
|
||||||
|
|
||||||
|
Account const alice{"alice"};
|
||||||
|
Account const bob{"bob"};
|
||||||
|
env.fund(XRP(100000), alice, bob);
|
||||||
|
env.close();
|
||||||
|
|
||||||
|
env(delegate::set(alice, bob, {tx}));
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto const& tx : txRequiredFeatures)
|
||||||
|
txAmendmentEnabled(tx.first);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NFTokenMint, NFTokenBurn, NFTokenCreateOffer, NFTokenCancelOffer, and
|
||||||
|
// NFTokenAcceptOffer are tested separately. Since
|
||||||
|
// featureNonFungibleTokensV1_1 includes the functionality of
|
||||||
|
// featureNonFungibleTokensV1, fixNFTokenNegOffer, and fixNFTokenDirV1,
|
||||||
|
// both featureNonFungibleTokensV1_1 and featureNonFungibleTokensV1 need
|
||||||
|
// to be disabled to block these transactions from being delegated.
|
||||||
|
{
|
||||||
|
Env env(
|
||||||
|
*this,
|
||||||
|
features - featureNonFungibleTokensV1 -
|
||||||
|
featureNonFungibleTokensV1_1);
|
||||||
|
|
||||||
|
Account const alice{"alice"};
|
||||||
|
Account const bob{"bob"};
|
||||||
|
env.fund(XRP(100000), alice, bob);
|
||||||
|
env.close();
|
||||||
|
|
||||||
|
for (auto const tx :
|
||||||
|
{"NFTokenMint",
|
||||||
|
"NFTokenBurn",
|
||||||
|
"NFTokenCreateOffer",
|
||||||
|
"NFTokenCancelOffer",
|
||||||
|
"NFTokenAcceptOffer"})
|
||||||
|
{
|
||||||
|
if (!features[fixDelegateV1_1])
|
||||||
|
env(delegate::set(alice, bob, {tx}));
|
||||||
|
else
|
||||||
|
env(delegate::set(alice, bob, {tx}), ter(temMALFORMED));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NFTokenMint, NFTokenBurn, NFTokenCreateOffer, NFTokenCancelOffer, and
|
||||||
|
// NFTokenAcceptOffer are allowed to be delegated if either
|
||||||
|
// featureNonFungibleTokensV1 or featureNonFungibleTokensV1_1 is
|
||||||
|
// enabled.
|
||||||
|
{
|
||||||
|
for (auto const feature :
|
||||||
|
{featureNonFungibleTokensV1, featureNonFungibleTokensV1_1})
|
||||||
|
{
|
||||||
|
Env env(*this, features - feature);
|
||||||
|
Account const alice{"alice"};
|
||||||
|
Account const bob{"bob"};
|
||||||
|
env.fund(XRP(100000), alice, bob);
|
||||||
|
env.close();
|
||||||
|
|
||||||
|
for (auto const tx :
|
||||||
|
{"NFTokenMint",
|
||||||
|
"NFTokenBurn",
|
||||||
|
"NFTokenCreateOffer",
|
||||||
|
"NFTokenCancelOffer",
|
||||||
|
"NFTokenAcceptOffer"})
|
||||||
|
env(delegate::set(alice, bob, {tx}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
run() override
|
run() override
|
||||||
{
|
{
|
||||||
|
FeatureBitset const all = jtx::testable_amendments();
|
||||||
|
|
||||||
testFeatureDisabled();
|
testFeatureDisabled();
|
||||||
testDelegateSet();
|
testDelegateSet();
|
||||||
testInvalidRequest();
|
testInvalidRequest(all);
|
||||||
|
testInvalidRequest(all - fixDelegateV1_1);
|
||||||
testReserve();
|
testReserve();
|
||||||
testFee();
|
testFee();
|
||||||
testSequence();
|
testSequence();
|
||||||
testAccountDelete();
|
testAccountDelete();
|
||||||
testDelegateTransaction();
|
testDelegateTransaction();
|
||||||
testPaymentGranular();
|
testPaymentGranular(all);
|
||||||
|
testPaymentGranular(all - fixDelegateV1_1);
|
||||||
testTrustSetGranular();
|
testTrustSetGranular();
|
||||||
testAccountSetGranular();
|
testAccountSetGranular();
|
||||||
testMPTokenIssuanceSetGranular();
|
testMPTokenIssuanceSetGranular();
|
||||||
@@ -1495,6 +1841,10 @@ class Delegate_test : public beast::unit_test::suite
|
|||||||
testSingleSignBadSecret();
|
testSingleSignBadSecret();
|
||||||
testMultiSign();
|
testMultiSign();
|
||||||
testMultiSignQuorumNotMet();
|
testMultiSignQuorumNotMet();
|
||||||
|
testPermissionValue(all);
|
||||||
|
testPermissionValue(all - fixDelegateV1_1);
|
||||||
|
testTxReqireFeatures(all);
|
||||||
|
testTxReqireFeatures(all - fixDelegateV1_1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
BEAST_DEFINE_TESTSUITE(Delegate, app, ripple);
|
BEAST_DEFINE_TESTSUITE(Delegate, app, ripple);
|
||||||
|
|||||||
@@ -23,7 +23,6 @@
|
|||||||
#include <xrpl/basics/Log.h>
|
#include <xrpl/basics/Log.h>
|
||||||
#include <xrpl/protocol/Feature.h>
|
#include <xrpl/protocol/Feature.h>
|
||||||
#include <xrpl/protocol/Indexes.h>
|
#include <xrpl/protocol/Indexes.h>
|
||||||
#include <xrpl/protocol/TxFlags.h>
|
|
||||||
#include <xrpl/protocol/st.h>
|
#include <xrpl/protocol/st.h>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
@@ -51,6 +50,11 @@ DelegateSet::preflight(PreflightContext const& ctx)
|
|||||||
{
|
{
|
||||||
if (!permissionSet.insert(permission[sfPermissionValue]).second)
|
if (!permissionSet.insert(permission[sfPermissionValue]).second)
|
||||||
return temMALFORMED;
|
return temMALFORMED;
|
||||||
|
|
||||||
|
if (ctx.rules.enabled(fixDelegateV1_1) &&
|
||||||
|
!Permission::getInstance().isDelegatable(
|
||||||
|
permission[sfPermissionValue], ctx.rules))
|
||||||
|
return temMALFORMED;
|
||||||
}
|
}
|
||||||
|
|
||||||
return preflight2(ctx);
|
return preflight2(ctx);
|
||||||
@@ -68,9 +72,21 @@ DelegateSet::preclaim(PreclaimContext const& ctx)
|
|||||||
auto const& permissions = ctx.tx.getFieldArray(sfPermissions);
|
auto const& permissions = ctx.tx.getFieldArray(sfPermissions);
|
||||||
for (auto const& permission : permissions)
|
for (auto const& permission : permissions)
|
||||||
{
|
{
|
||||||
auto const permissionValue = permission[sfPermissionValue];
|
if (!ctx.view.rules().enabled(fixDelegateV1_1) &&
|
||||||
if (!Permission::getInstance().isDelegatable(permissionValue))
|
!Permission::getInstance().isDelegatable(
|
||||||
|
permission[sfPermissionValue], ctx.view.rules()))
|
||||||
|
{
|
||||||
|
// Before fixDelegateV1_1:
|
||||||
|
// - The check was performed during preclaim.
|
||||||
|
// - Transactions from amendments not yet enabled could still be
|
||||||
|
// delegated.
|
||||||
|
//
|
||||||
|
// After fixDelegateV1_1:
|
||||||
|
// - The check is performed during preflight.
|
||||||
|
// - Transactions from amendments not yet enabled can no longer be
|
||||||
|
// delegated.
|
||||||
return tecNO_PERMISSION;
|
return tecNO_PERMISSION;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
|
|||||||
@@ -265,8 +265,33 @@ Payment::checkPermission(ReadView const& view, STTx const& tx)
|
|||||||
loadGranularPermission(sle, ttPAYMENT, granularPermissions);
|
loadGranularPermission(sle, ttPAYMENT, granularPermissions);
|
||||||
|
|
||||||
auto const& dstAmount = tx.getFieldAmount(sfAmount);
|
auto const& dstAmount = tx.getFieldAmount(sfAmount);
|
||||||
auto const& amountIssue = dstAmount.issue();
|
// post-amendment: disallow cross currency payments for PaymentMint and
|
||||||
|
// PaymentBurn
|
||||||
|
if (view.rules().enabled(fixDelegateV1_1))
|
||||||
|
{
|
||||||
|
auto const& amountAsset = dstAmount.asset();
|
||||||
|
if (tx.isFieldPresent(sfSendMax) &&
|
||||||
|
tx[sfSendMax].asset() != amountAsset)
|
||||||
|
return tecNO_DELEGATE_PERMISSION;
|
||||||
|
|
||||||
|
if (granularPermissions.contains(PaymentMint) && !isXRP(amountAsset) &&
|
||||||
|
amountAsset.getIssuer() == tx[sfAccount])
|
||||||
|
return tesSUCCESS;
|
||||||
|
|
||||||
|
if (granularPermissions.contains(PaymentBurn) && !isXRP(amountAsset) &&
|
||||||
|
amountAsset.getIssuer() == tx[sfDestination])
|
||||||
|
return tesSUCCESS;
|
||||||
|
|
||||||
|
return tecNO_DELEGATE_PERMISSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calling dstAmount.issue() in the next line would throw if it holds MPT.
|
||||||
|
// That exception would be caught in preclaim and returned as tefEXCEPTION.
|
||||||
|
// This check is just a cleaner, more explicit way to get the same result.
|
||||||
|
if (dstAmount.holds<MPTIssue>())
|
||||||
|
return tefEXCEPTION;
|
||||||
|
|
||||||
|
auto const& amountIssue = dstAmount.issue();
|
||||||
if (granularPermissions.contains(PaymentMint) && !isXRP(amountIssue) &&
|
if (granularPermissions.contains(PaymentMint) && !isXRP(amountIssue) &&
|
||||||
amountIssue.account == tx[sfAccount])
|
amountIssue.account == tx[sfAccount])
|
||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
|
|||||||
@@ -97,8 +97,8 @@ with_txn_type(TxType txnType, F&& f)
|
|||||||
#pragma push_macro("TRANSACTION")
|
#pragma push_macro("TRANSACTION")
|
||||||
#undef TRANSACTION
|
#undef TRANSACTION
|
||||||
|
|
||||||
#define TRANSACTION(tag, value, name, delegatable, fields) \
|
#define TRANSACTION(tag, value, name, ...) \
|
||||||
case tag: \
|
case tag: \
|
||||||
return f.template operator()<name>();
|
return f.template operator()<name>();
|
||||||
|
|
||||||
#include <xrpl/protocol/detail/transactions.macro>
|
#include <xrpl/protocol/detail/transactions.macro>
|
||||||
|
|||||||
Reference in New Issue
Block a user