Disclaimer: This gist was done quickly, and likely has typos or errors. It is not meant to be "correct", but instead is aimed at describing a possible idea that could be formalized as part of CFTs or otherwise.
In the discussion for the CFT proposal, this comment points out that it might be necessary to create a new type of SerializedType
that is not an STAmount
-- to support CFT amounts. While this is one potential path forward, this gist explores the consequences of encoding CFT information inside of an STAmount.
To support this idea, we first need a way to leverage the current STAmount binary encoding. To accomplish this, we notice that for XRP amounts, the maximum amount of XRP (10^17 drops) only requires 57 bits. However, in the current XRP
amount encoding, there are 62 bits available, so we can repurpose one to indicate if an amount is indeed a CFT or not.
The rules for reading the binary amount fields would be backward compatible, as follows:
- Parse off the Field ID with a type_code (
STI_AMOUNT
). This indicates the following bytes are anSTAmount
. - Inspect the next bit. If
1
, then this is not a CFT (instead this is a regular IOU token amount). However, if the first bit is0
, then continue. - Ignore (for now) the 2nd bit (this is the sign-bit, and is always 1 for both XRP and CFT).
- Inspect the 3rd bit. If
0
, then parse as an XRP value per usual. However, if1
, then parse the bytes as a CFT.
┌────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ ┌─────────────────┐┌────────────────────────┐┌────────────┐┌─────────────────────────────────────────────┐ │
│ │ 0 ││ 1 ││ 0 ││ │ │
│ │ ││ ││ ││ integer drops │ │
│ │ "Not XRP" bit ││ Sign bit (always 1; ││"IsCFT" bit ││ (61 bits) │ │
│ │0=XRP/CFT; 1=IOU ││ positive) ││0=XRP; 1=CFT││ │ │
│ └─────────────────┘└────────────────────────┘└────────────┘└─────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
This encoding focuses on the first 3 bytes of a CFT:
┌────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ ┌─────────────────┐┌────────────────────────┐┌────────────┐┌─────────────────────────────────────────────┐ │
│ │ 0 ││ 1 ││ 1 ││ │ │
│ │ ││ ││ ││ Remaining CFT Bytes │ │
│ │ "Not XRP" bit ││ Sign bit (always 1; ││"IsCFT" bit ││ (389 bits) │ │
│ │0=XRP/CFT; 1=IOU ││ positive) ││0=XRP; 1=CFT││ │ │
│ └─────────────────┘└────────────────────────┘└────────────┘└─────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
This encoding focuses on the rest of the bytes of a CFT:
┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ ┌─────────────────┐┌──────────────────┐┌──────────────────────┐┌──────────────────────────┐┌──────────────────────────┐│
│ │ [0][1][1] ││ ││ ││ ││ ││
│ │ ││ Reserved ││ CFT Amount Value ││ Currency Code ││ Issuer AcountID ││
│ │ IsCFT=true ││ (5 bits) ││ (64 bits) ││ (160 bits) ││ (160 bits) ││
│ │ ││ ││ ││ ││ ││
│ └─────────────────┘└──────────────────┘└──────────────────────┘└──────────────────────────┘└──────────────────────────┘│
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
In this new construction, you can calculate the XRP serialized format by taking standard 64-bit unsigned integer and performing a bitwise-OR with 0x4000000000000000
.
Likewise, you can calculate the CFT serialized format by taking standard 64-bit unsigned integer and performing a bitwise-OR with 0x6000000000000000
.
This would be a new sibling class of XRPAmount
and IOUAmount
, but would hold a std::int64_t
for the amount, and an Issue
for the Issuer/Currency information.
This class would likely need a new boolean called bool mIsCft
or else an enum
value to represent the three distinct sub-types. This class would also need to be refactored to account for CFT in all of its calculations.
{
"TransactionType" : "Payment",
"Account" : "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"Destination" : "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX",
"Amount" : "1", // <-- Drops
"Fee": "12",
"Flags": 2147483648,
"Sequence": 2,
}
{
"TransactionType" : "Payment",
"Account" : "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"Destination" : "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX",
"Amount" : {
"currency" : "USD",
"value" : "1",
"issuer" : "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"isCft": true,
},
"Fee": "12",
"Flags": 2147483648,
"Sequence": 2,
}
{
"TransactionType" : "Payment",
"Account" : "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"Destination" : "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX",
"Amount" : {
"currency" : "USD",
"value" : "1",
"issuer" : "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn"
},
"Fee": "12",
"Flags": 2147483648,
"Sequence": 2,
}
public interface CFTCurrencyAmount extends CurrencyAmount {
...
UnsignedLong value();
String currency();
Address issuer();
}
TBD.