Skip to content

Instantly share code, notes, and snippets.

@sappenin
Last active April 27, 2023 18:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sappenin/2c923bb249d4e9dd153e2e5f32f96d92 to your computer and use it in GitHub Desktop.
Save sappenin/2c923bb249d4e9dd153e2e5f32f96d92 to your computer and use it in GitHub Desktop.
Idea: Add CFTs inside of an STAmount

CFTs as STAmounts

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.

Summary

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.

Binary Encoding

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:

  1. Parse off the Field ID with a type_code (STI_AMOUNT). This indicates the following bytes are an STAmount.
  2. 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 is 0, then continue.
  3. Ignore (for now) the 2nd bit (this is the sign-bit, and is always 1 for both XRP and CFT).
  4. Inspect the 3rd bit. If 0, then parse as an XRP value per usual. However, if 1, then parse the bytes as a CFT.

Encoding for XRP Values (backward compatible)

┌────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ ┌─────────────────┐┌────────────────────────┐┌────────────┐┌─────────────────────────────────────────────┐ │
│ │        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││                                             │ │
│ └─────────────────┘└────────────────────────┘└────────────┘└─────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

Encoding for CFT Values (backward compatible)

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.

C++

CFTAmount.h

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.

STAmount.h

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.

Examples

Payment RPC JSON

Payment w\ XRP

{
  "TransactionType" : "Payment",
  "Account" : "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
  "Destination" : "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX",
  "Amount" : "1", // <-- Drops
  "Fee": "12",
  "Flags": 2147483648,
  "Sequence": 2,
}

Payment w\ CFT

{
  "TransactionType" : "Payment",
  "Account" : "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
  "Destination" : "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX",
  "Amount" : {
     "currency" : "USD",
     "value" : "1",
     "issuer" : "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
     "isCft": true,
  },
  "Fee": "12",
  "Flags": 2147483648,
  "Sequence": 2,
}

Payment w\ IOU

{
  "TransactionType" : "Payment",
  "Account" : "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
  "Destination" : "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX",
  "Amount" : {
     "currency" : "USD",
     "value" : "1",
     "issuer" : "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn"
  },
  "Fee": "12",
  "Flags": 2147483648,
  "Sequence": 2,
}

Amount in Java

public interface CFTCurrencyAmount extends CurrencyAmount {

  ...

  UnsignedLong value();

  String currency();

  Address issuer();
}

Appendix

TBD.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment