-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Description
Summary
Inner objects in the JSON format of transactions have an awkward format consisting of a JSON object with one key, which is the object type, whose value is the actual contents of the inner object.
They would be more concise and generally easier to parse if they were "unwrapped".
Motivation
It's somewhat awkward to parse through a lot of these types of objects and also a hassle to create objects in this format. Intuitively, people just care about the contents of the inner object, so it's easy to forget that you need to wrap it. And if you're iterating over a mixed list, it's usually more awkward to iterate over the keys of the wrappers to figure out what type they are than it would be to just check a type field.
{
// ... other transaction fields ...
"Memos": [
{
"Memo": {
"MemoType": "687474703a2f2f6578616d706c652e636f6d2f6d656d6f2f67656e65726963",
"MemoData": "72656e74"
}
},
{
"Memo": {
"MemoType": "746578742f706c61696e",
"MemoData": "4920616d207369636b206f66207772617070696e67206d79206d656d6f73206c696b6520746869732e"
}
}
]
}
Solution
When serializing "inner objects" to JSON, instead of using an object in an object, serialize the object with its keys at the top level alongside a field that indicates the inner object type. There are several other cases of using this paradigm in the API, including lists of transactions (TransactionType
), ledger entries (LedgerEntryType
), and subscription messages (type
).
I suggest ObjectType
as the type field, although Type
would also be fine. For example:
{
// ... other transaction fields ...
"Memos": [
{
"ObjectType": "Memo",
"MemoType": "687474703a2f2f6578616d706c652e636f6d2f6d656d6f2f67656e65726963",
"MemoData": "72656e74"
},
{
"ObjectType": "Memo",
"MemoType": "746578742f706c61696e",
"MemoData": "4920616d207369636b206f66207772617070696e67206d79206d656d6f73206c696b6520746869732e"
}
]
}
A list of places this should apply (maybe not exhaustive):
- Members of the
Memos
common field of transactions - Members of the
Signers
common field of transactions. - Members of the
SignerEntries
field of SignerListSet transactions, andSignerEntries
field of SignerList ledger entries. - Members of the
AffectedNodes
field in transaction metadata. - Members of the
NFTokens
field of NFTokenPage ledger entries. - Members of the
PriceDataSeries
field of Oracle ledger entries. - Members of the
AuthAccounts
field of AMMBid transactions andAuctionSlot.AuthAccounts
field of AMM ledger entries. - Members of the
VoteSlots
field of AMM ledger entries. - Members of the
AuthorizeCredentials
andUnauthorizeCredentials
fields of DepositPreauth transactions and same-named fields of DepositPreauth ledger entries. - Members of the
Permissions
field of DelegateSet transactions andPermissions
field of Delegate ledger entries. - Probably some XChain stuff (I'm not going to look too closely since I don't think this amendment is likely to become enabled)
- Members of the
RawTransactions
andBatchSigners
fields of Batch transactions.
See also: sfields.macro
OBJECT type fields
This change should be gated by an API version switch (API v3 or whichever). However, it does not change the binary format of transactions so it does not need to be on an amendment.
Optionally, client applications and/or signing functions that take transaction JSON can accept user input that omits the Type
field in a context where it's obvious what type it should be (only one type is allowed in the array and the appropriate fields for that type are supplied).
Paths Not Taken
Omitting the type field entirely seems reasonable in many of these cases, since inner objects are usually used in lists that can only contain one type. But, since there's at least one case of a list with mixed objects (AffectedNodes
), it seems best to just always provide the type field for consistency.