Skip to content
Draft
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
103 changes: 83 additions & 20 deletions xrpl/ledger-entry-types/mptoken_issuance.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,30 +19,37 @@ const (
LsfMPTCanTransfer uint32 = 0x00000020
// LsfMPTCanClawback if set, indicates that the issuer may use the Clawback transaction to claw back value from individual holders.
LsfMPTCanClawback uint32 = 0x00000040
// LsfMPTCanConfidentialAmount if set, indicates that confidential transfers are enabled for this token issuance.
LsfMPTCanConfidentialAmount uint32 = 0x00000080
// LsfMPTCanHoldConfidentialBalance if set, indicates that holders may hold confidential balances for this token issuance.
LsfMPTCanHoldConfidentialBalance uint32 = 0x00000080
)

// Ledger-state mutable flags for MPTokenIssuance (Lsmf prefix).
// Ledger-state mutable flags for MPTokenIssuance (Lsmf prefix) record future permissions and an opt-out.
// CanEnable permissions allow only a later transition from disabled to enabled; they never
// permit disabling. CanMutate permissions allow repeated metadata or transfer-fee updates.
// CannotEnableCanHoldConfidentialBalance permanently records the confidential opt-out.
const (
// LsmfMPTCanMutateCanLock indicates the CanLock property can be mutated.
LsmfMPTCanMutateCanLock uint32 = 0x00000002
// LsmfMPTCanMutateRequireAuth indicates the RequireAuth property can be mutated.
LsmfMPTCanMutateRequireAuth uint32 = 0x00000004
// LsmfMPTCanMutateCanEscrow indicates the CanEscrow property can be mutated.
LsmfMPTCanMutateCanEscrow uint32 = 0x00000008
// LsmfMPTCanMutateCanTrade indicates the CanTrade property can be mutated.
LsmfMPTCanMutateCanTrade uint32 = 0x00000010
// LsmfMPTCanMutateCanTransfer indicates the CanTransfer property can be mutated.
LsmfMPTCanMutateCanTransfer uint32 = 0x00000020
// LsmfMPTCanMutateCanClawback indicates the CanClawback property can be mutated.
LsmfMPTCanMutateCanClawback uint32 = 0x00000040
// LsmfMPTCanMutateMetadata indicates the MPTokenMetadata can be mutated.
// LsmfMPTCanEnableCanLock records one-way permission to enable CanLock after issuance.
LsmfMPTCanEnableCanLock uint32 = 0x00000002
// LsmfMPTCanEnableRequireAuth records one-way permission to enable RequireAuth after issuance.
LsmfMPTCanEnableRequireAuth uint32 = 0x00000004
// LsmfMPTCanEnableCanEscrow records one-way permission to enable CanEscrow after issuance.
LsmfMPTCanEnableCanEscrow uint32 = 0x00000008
// LsmfMPTCanEnableCanTrade records one-way permission to enable CanTrade after issuance.
LsmfMPTCanEnableCanTrade uint32 = 0x00000010
// LsmfMPTCanEnableCanTransfer records one-way permission to enable CanTransfer after issuance.
LsmfMPTCanEnableCanTransfer uint32 = 0x00000020
// LsmfMPTCanEnableCanClawback records one-way permission to enable CanClawback after issuance.
LsmfMPTCanEnableCanClawback uint32 = 0x00000040
// LsmfMPTCannotEnableCanHoldConfidentialBalance records a permanent opt-out from enabling confidential balances.
LsmfMPTCannotEnableCanHoldConfidentialBalance uint32 = 0x00000080
// LsmfMPTCanMutateMetadata records repeatable permission to replace MPTokenMetadata.
LsmfMPTCanMutateMetadata uint32 = 0x00010000
// LsmfMPTCanMutateTransferFee indicates the TransferFee can be mutated.
// LsmfMPTCanMutateTransferFee records repeatable permission to replace TransferFee.
LsmfMPTCanMutateTransferFee uint32 = 0x00020000
// LsmfMPTCannotMutateCanConfidentialAmount if set, the lsfMPTCanConfidentialAmount flag can never be changed after the token is issued.
LsmfMPTCannotMutateCanConfidentialAmount uint32 = 0x00040000

// MPTokenIssuanceMutableFlagsMask contains every valid ledger MutableFlags bit.
// Bit 0x01 is reserved.
MPTokenIssuanceMutableFlagsMask uint32 = 0x000300FE
)

// An MPTokenIssuance entry represents a single MPT issuance and holds data associated with the issuance itself.
Expand Down Expand Up @@ -87,7 +94,9 @@ type MPTokenIssuance struct {
LockedAmount uint64 `json:",omitempty"`
// DomainID is the ledger entry ID of a permissioned domain that grants access to the MPT.
DomainID string `json:",omitempty"`
// MutableFlags indicates which properties of this MPT can be mutated after creation.
// MutableFlags records one-way future-enable permissions for ordinary capabilities,
// repeatable mutation permission for metadata and transfer fees, and a permanent
// opt-out from enabling confidential balances.
MutableFlags uint32 `json:",omitempty"`
// The issuer's encryption key for confidential transfers.
// Required if confidential transfers are enabled.
Expand Down Expand Up @@ -139,3 +148,57 @@ func (c *MPTokenIssuance) SetLsfMPTCanTransfer() {
func (c *MPTokenIssuance) SetLsfMPTCanClawback() {
c.Flags |= LsfMPTCanClawback
}

// SetLsfMPTCanHoldConfidentialBalance sets the confidential balance capability.
func (c *MPTokenIssuance) SetLsfMPTCanHoldConfidentialBalance() {
c.Flags |= LsfMPTCanHoldConfidentialBalance
}

func (c *MPTokenIssuance) setMutableFlag(flag uint32) {
c.MutableFlags |= flag
}

// SetLsmfMPTCanEnableCanLock records one-way permission to enable CanLock after issuance.
func (c *MPTokenIssuance) SetLsmfMPTCanEnableCanLock() {
c.setMutableFlag(LsmfMPTCanEnableCanLock)
}

// SetLsmfMPTCanEnableRequireAuth records one-way permission to enable RequireAuth after issuance.
func (c *MPTokenIssuance) SetLsmfMPTCanEnableRequireAuth() {
c.setMutableFlag(LsmfMPTCanEnableRequireAuth)
}

// SetLsmfMPTCanEnableCanEscrow records one-way permission to enable CanEscrow after issuance.
func (c *MPTokenIssuance) SetLsmfMPTCanEnableCanEscrow() {
c.setMutableFlag(LsmfMPTCanEnableCanEscrow)
}

// SetLsmfMPTCanEnableCanTrade records one-way permission to enable CanTrade after issuance.
func (c *MPTokenIssuance) SetLsmfMPTCanEnableCanTrade() {
c.setMutableFlag(LsmfMPTCanEnableCanTrade)
}

// SetLsmfMPTCanEnableCanTransfer records one-way permission to enable CanTransfer after issuance.
func (c *MPTokenIssuance) SetLsmfMPTCanEnableCanTransfer() {
c.setMutableFlag(LsmfMPTCanEnableCanTransfer)
}

// SetLsmfMPTCanEnableCanClawback records one-way permission to enable CanClawback after issuance.
func (c *MPTokenIssuance) SetLsmfMPTCanEnableCanClawback() {
c.setMutableFlag(LsmfMPTCanEnableCanClawback)
}

// SetLsmfMPTCannotEnableCanHoldConfidentialBalance records a permanent opt-out from enabling confidential balances.
func (c *MPTokenIssuance) SetLsmfMPTCannotEnableCanHoldConfidentialBalance() {
c.setMutableFlag(LsmfMPTCannotEnableCanHoldConfidentialBalance)
}

// SetLsmfMPTCanMutateMetadata records repeatable permission to replace MPTokenMetadata.
func (c *MPTokenIssuance) SetLsmfMPTCanMutateMetadata() {
c.setMutableFlag(LsmfMPTCanMutateMetadata)
}

// SetLsmfMPTCanMutateTransferFee records repeatable permission to replace TransferFee.
func (c *MPTokenIssuance) SetLsmfMPTCanMutateTransferFee() {
c.setMutableFlag(LsmfMPTCanMutateTransferFee)
}
75 changes: 71 additions & 4 deletions xrpl/ledger-entry-types/mptoken_issuance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ func TestMPTokenIssuanceSerialization(t *testing.T) {
PreviousTxnID: types.Hash256("8089451B193AAD110ACED3D62BE79BB523658545E6EE8B7BB0BE573FED9BCBFB"),
PreviousTxnLgrSeq: 234644,
Sequence: 1,
MutableFlags: LsmfMPTCanMutateCanLock | LsmfMPTCanMutateMetadata,
MutableFlags: LsmfMPTCanEnableCanLock | LsmfMPTCanMutateMetadata,
},
expected: `{
"index": "A738A1E6E8505E1FC77BBB9FEF84FF9A9C609F2739E0F9573CDD6367100A0AA9",
Expand All @@ -364,11 +364,11 @@ func TestMPTokenIssuanceSerialization(t *testing.T) {
}`,
},
{
name: "pass - valid MPTokenIssuance with LsfMPTCanConfidentialAmount",
name: "pass - valid MPTokenIssuance with LsfMPTCanHoldConfidentialBalance",
mpTokenIssuance: &MPTokenIssuance{
Index: types.Hash256("A738A1E6E8505E1FC77BBB9FEF84FF9A9C609F2739E0F9573CDD6367100A0AA9"),
LedgerEntryType: MPTokenIssuanceEntry,
Flags: LsfMPTCanConfidentialAmount,
Flags: LsfMPTCanHoldConfidentialBalance,
Issuer: types.Address("rLUEXYuLiQptky37CqLcm9USQpPiz5rkpD"),
AssetScale: 2,
MaximumAmount: 1000,
Expand Down Expand Up @@ -401,7 +401,7 @@ func TestMPTokenIssuanceSerialization(t *testing.T) {
mpTokenIssuance: &MPTokenIssuance{
Index: types.Hash256("A738A1E6E8505E1FC77BBB9FEF84FF9A9C609F2739E0F9573CDD6367100A0AA9"),
LedgerEntryType: MPTokenIssuanceEntry,
Flags: LsfMPTCanConfidentialAmount | LsfMPTCanTransfer,
Flags: LsfMPTCanHoldConfidentialBalance | LsfMPTCanTransfer,
Issuer: types.Address("rLUEXYuLiQptky37CqLcm9USQpPiz5rkpD"),
AssetScale: 2,
MaximumAmount: 1000,
Expand Down Expand Up @@ -445,3 +445,70 @@ func TestMPTokenIssuanceSerialization(t *testing.T) {
})
}
}

func TestMPTokenIssuanceFlagValuesAndSettersPreserveBits(t *testing.T) {
require.Equal(t, uint32(0x02), LsfMPTCanLock)
require.Equal(t, uint32(0x04), LsfMPTRequireAuth)
require.Equal(t, uint32(0x08), LsfMPTCanEscrow)
require.Equal(t, uint32(0x10), LsfMPTCanTrade)
require.Equal(t, uint32(0x20), LsfMPTCanTransfer)
require.Equal(t, uint32(0x40), LsfMPTCanClawback)
require.Equal(t, uint32(0x80), LsfMPTCanHoldConfidentialBalance)

tests := []struct {
name string
set func(*MPTokenIssuance)
literal uint32
}{
{"CanLock", (*MPTokenIssuance).SetLsfMPTCanLock, 0x02},
{"RequireAuth", (*MPTokenIssuance).SetLsfMPTRequireAuth, 0x04},
{"CanEscrow", (*MPTokenIssuance).SetLsfMPTCanEscrow, 0x08},
{"CanTrade", (*MPTokenIssuance).SetLsfMPTCanTrade, 0x10},
{"CanTransfer", (*MPTokenIssuance).SetLsfMPTCanTransfer, 0x20},
{"CanClawback", (*MPTokenIssuance).SetLsfMPTCanClawback, 0x40},
{"CanHoldConfidentialBalance", (*MPTokenIssuance).SetLsfMPTCanHoldConfidentialBalance, 0x80},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
issuance := &MPTokenIssuance{Flags: 0x100}
test.set(issuance)
require.Equal(t, uint32(0x100)|test.literal, issuance.Flags)
})
}
}

func TestMPTokenIssuanceMutableFlagValuesAndSettersPreserveBits(t *testing.T) {
require.Equal(t, uint32(0x02), LsmfMPTCanEnableCanLock)
require.Equal(t, uint32(0x04), LsmfMPTCanEnableRequireAuth)
require.Equal(t, uint32(0x08), LsmfMPTCanEnableCanEscrow)
require.Equal(t, uint32(0x10), LsmfMPTCanEnableCanTrade)
require.Equal(t, uint32(0x20), LsmfMPTCanEnableCanTransfer)
require.Equal(t, uint32(0x40), LsmfMPTCanEnableCanClawback)
require.Equal(t, uint32(0x80), LsmfMPTCannotEnableCanHoldConfidentialBalance)
require.Equal(t, uint32(0x10000), LsmfMPTCanMutateMetadata)
require.Equal(t, uint32(0x20000), LsmfMPTCanMutateTransferFee)
require.Equal(t, uint32(0x000300FE), MPTokenIssuanceMutableFlagsMask)

tests := []struct {
name string
set func(*MPTokenIssuance)
literal uint32
}{
{"CanEnableCanLock", (*MPTokenIssuance).SetLsmfMPTCanEnableCanLock, 0x02},
{"CanEnableRequireAuth", (*MPTokenIssuance).SetLsmfMPTCanEnableRequireAuth, 0x04},
{"CanEnableCanEscrow", (*MPTokenIssuance).SetLsmfMPTCanEnableCanEscrow, 0x08},
{"CanEnableCanTrade", (*MPTokenIssuance).SetLsmfMPTCanEnableCanTrade, 0x10},
{"CanEnableCanTransfer", (*MPTokenIssuance).SetLsmfMPTCanEnableCanTransfer, 0x20},
{"CanEnableCanClawback", (*MPTokenIssuance).SetLsmfMPTCanEnableCanClawback, 0x40},
{"CannotEnableCanHoldConfidentialBalance", (*MPTokenIssuance).SetLsmfMPTCannotEnableCanHoldConfidentialBalance, 0x80},
{"CanMutateMetadata", (*MPTokenIssuance).SetLsmfMPTCanMutateMetadata, 0x10000},
{"CanMutateTransferFee", (*MPTokenIssuance).SetLsmfMPTCanMutateTransferFee, 0x20000},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
issuance := &MPTokenIssuance{MutableFlags: 0x80000000}
test.set(issuance)
require.Equal(t, uint32(0x80000000)|test.literal, issuance.MutableFlags)
})
}
}
18 changes: 8 additions & 10 deletions xrpl/transaction/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,10 @@ var (
// ErrHolderAccountConflict is returned when the holder account is the same as the issuing account.
ErrHolderAccountConflict = errors.New("holder must be different from the account")

// ErrMPTIssuanceCreateMutableFlagsZero is returned when MutableFlags is set to zero in MPTokenIssuanceCreate.
ErrMPTIssuanceCreateMutableFlagsZero = errors.New("mptoken issuance create: MutableFlags cannot be zero")
// ErrMPTIssuanceCreateInvalidMutableFlags is returned when MutableFlags is zero or contains an unsupported bit.
ErrMPTIssuanceCreateInvalidMutableFlags = errors.New("mptoken issuance create: MutableFlags must contain only supported non-zero flags")
// ErrMPTIssuanceCreateTransferFeeWithConfidentialBalance is returned when a non-zero TransferFee is used with confidential balances.
ErrMPTIssuanceCreateTransferFeeWithConfidentialBalance = errors.New("mptoken issuance create: non-zero TransferFee cannot be set with TfMPTCanHoldConfidentialBalance")
// ErrMPTIssuanceCreateDomainIDInvalid is returned when DomainID is not a valid 64-character hexadecimal string.
ErrMPTIssuanceCreateDomainIDInvalid = errors.New("mptoken issuance create: DomainID must be a valid 64-character hexadecimal string")
// ErrMPTIssuanceCreateDomainIDRequiresRequireAuth is returned when DomainID is set without enabling TfMPTRequireAuth flag.
Expand All @@ -232,20 +234,16 @@ var (
ErrMPTIssuanceSetHolderMutuallyExclusive = errors.New("mptoken issuance set: Holder is mutually exclusive with MutableFlags/MPTokenMetadata/TransferFee/DomainID")
// ErrMPTIssuanceSetFlagsMutuallyExclusive is returned when non-zero Flags are set together with DynamicMPT fields.
ErrMPTIssuanceSetFlagsMutuallyExclusive = errors.New("mptoken issuance set: Flags is mutually exclusive with MutableFlags/MPTokenMetadata/TransferFee")
// ErrMPTIssuanceSetMutableFlagsZero is returned when MutableFlags is set to zero.
ErrMPTIssuanceSetMutableFlagsZero = errors.New("mptoken issuance set: MutableFlags cannot be zero")
// ErrMPTIssuanceSetMutableFlagsConflict is returned when MutableFlags has both set and clear for the same flag.
ErrMPTIssuanceSetMutableFlagsConflict = errors.New("mptoken issuance set: cannot set and clear the same flag simultaneously")
// ErrMPTIssuanceSetTransferFeeWithClearCanTransfer is returned when a non-zero TransferFee is set together with tmfMPTClearCanTransfer.
ErrMPTIssuanceSetTransferFeeWithClearCanTransfer = errors.New("mptoken issuance set: non-zero TransferFee cannot be set together with tmfMPTClearCanTransfer")
// ErrMPTIssuanceSetInvalidMutableFlags is returned when MutableFlags is zero or contains an unsupported bit.
ErrMPTIssuanceSetInvalidMutableFlags = errors.New("mptoken issuance set: MutableFlags must contain only supported non-zero flags")
// ErrMPTIssuanceSetTransferFeeWithConfidentialBalance is returned when a non-zero TransferFee enables confidential balances.
ErrMPTIssuanceSetTransferFeeWithConfidentialBalance = errors.New("mptoken issuance set: non-zero TransferFee cannot be set with TmfMPTSetCanHoldConfidentialBalance")
// ErrMPTIssuanceSetDomainIDInvalid is returned when DomainID is not a valid 64-character hexadecimal string (and not empty).
ErrMPTIssuanceSetDomainIDInvalid = errors.New("mptoken issuance set: DomainID must be a valid 64-character hexadecimal string or empty")
// ErrMPTIssuanceSetKeyConflict is returned when encryption keys are set together with Holder.
ErrMPTIssuanceSetKeyConflict = errors.New("mptoken issuance set: encryption keys cannot be set together with Holder")
// ErrMPTIssuanceSetAuditorRequiresIssuerKey is returned when AuditorEncryptionKey is set without IssuerEncryptionKey.
ErrMPTIssuanceSetAuditorRequiresIssuerKey = errors.New("mptoken issuance set: AuditorEncryptionKey requires IssuerEncryptionKey to be set")
// ErrMPTIssuanceSetKeysWithClearCanConfidentialAmount is returned when encryption keys are set together with tmfMPTClearCanConfidentialAmount.
ErrMPTIssuanceSetKeysWithClearCanConfidentialAmount = errors.New("mptoken issuance set: encryption keys cannot be set together with tmfMPTClearCanConfidentialAmount")
// ErrMPTIssuanceSetInvalidKeyLength is returned when an encryption key has an invalid length.
ErrMPTIssuanceSetInvalidKeyLength = errors.New("mptoken issuance set: encryption key must be 66 hex characters (33-byte compressed EC point)")

Expand Down
Loading
Loading