mirror of
https://github.com/XRPLF/xrpl-dev-portal.git
synced 2025-11-20 11:45:50 +00:00
Binary serialization: implement MPT amounts in sample code
This commit is contained in:
@@ -133,12 +133,13 @@ def accountid_to_bytes(address):
|
|||||||
|
|
||||||
def amount_to_bytes(a):
|
def amount_to_bytes(a):
|
||||||
"""
|
"""
|
||||||
Serializes an "Amount" type, which can be either XRP or an issued currency:
|
Serializes an "Amount" type, which can be XRP, an issued currency, or MPT:
|
||||||
- XRP: total 64 bits: 0, followed by 1 ("is positive"), then 0, then 61 bit UInt amount
|
- XRP: total 64 bits: 0, followed by 1 ("is positive"), then 0, then 61 bit UInt amount
|
||||||
- Issued Currency: total 384 bits: 64 bits of amount, followed by 160 bit currency code and
|
- Issued Currency: total 384 bits: 64 bits of amount, followed by 160 bit
|
||||||
160 bit issuer AccountID.
|
currency code and 160 bit issuer AccountID.
|
||||||
- MPT: 8-bit header with the binary value 01100000 (0x60), then 64 bit UInt amount,
|
- MPT: total 264 bits: 8-bit header with the binary value 01100000 (0x60),
|
||||||
32 bit Sequence number, and 160 bit issuer AccountID.
|
then 64 bit amount, 32 bit Sequence number, and 160 bit issuer AccountID.
|
||||||
|
The Sequence and issuer are adjoined as mpt_issuance_id.
|
||||||
"""
|
"""
|
||||||
if type(a) == str:
|
if type(a) == str:
|
||||||
# is XRP
|
# is XRP
|
||||||
@@ -153,17 +154,26 @@ def amount_to_bytes(a):
|
|||||||
xrp_amt = -xrp_amt
|
xrp_amt = -xrp_amt
|
||||||
return xrp_amt.to_bytes(8, byteorder="big", signed=False)
|
return xrp_amt.to_bytes(8, byteorder="big", signed=False)
|
||||||
elif type(a) == dict:
|
elif type(a) == dict:
|
||||||
#TODO: handle mpt amounts
|
if sorted(a.keys()) == ["mpt_issuance_id", "value"]:
|
||||||
if sorted(a.keys()) != ["currency", "issuer", "value"]:
|
# MPT Amount
|
||||||
|
mpt_prefix = uint8_to_bytes(0x60)
|
||||||
|
mpt_amt = int(a["value"])
|
||||||
|
assert mpt_amt < 2**63 and mpt_amt >= 0
|
||||||
|
mpt_amt_bytes = mpt_amt.to_bytes(8, byteorder="big", signed=False)
|
||||||
|
mpt_issuance_id = uint192_to_bytes(a["mpt_issuance_id"])
|
||||||
|
return mpt_prefix + mpt_amt_bytes + mpt_issuance_id
|
||||||
|
|
||||||
|
elif sorted(a.keys()) != ["currency", "issuer", "value"]:
|
||||||
raise ValueError("amount must have currency, value, issuer only (actually had: %s)" %
|
raise ValueError("amount must have currency, value, issuer only (actually had: %s)" %
|
||||||
sorted(a.keys()))
|
sorted(a.keys()))
|
||||||
|
|
||||||
|
# Fungible token amount (non-MPT)
|
||||||
issued_amt = IssuedAmount(a["value"]).to_bytes()
|
issued_amt = IssuedAmount(a["value"]).to_bytes()
|
||||||
logger.debug("Issued amount: %s"%issued_amt.hex())
|
logger.debug("Issued amount: %s"%issued_amt.hex())
|
||||||
currency_code = currency_code_to_bytes(a["currency"])
|
currency_code = currency_code_to_bytes(a["currency"])
|
||||||
return issued_amt + currency_code + decode_address(a["issuer"])
|
return issued_amt + currency_code + decode_address(a["issuer"])
|
||||||
else:
|
else:
|
||||||
raise ValueError("amount must be XRP string or {currency, value, issuer}")
|
raise ValueError("amount must be XRP string, {currency, value, issuer}, or {mpt_issuance_id, value}")
|
||||||
|
|
||||||
def array_to_bytes(array):
|
def array_to_bytes(array):
|
||||||
"""
|
"""
|
||||||
@@ -389,6 +399,12 @@ def uint64_to_bytes(i):
|
|||||||
raise ValueError("UInt64 is not 64 bits long")
|
raise ValueError("UInt64 is not 64 bits long")
|
||||||
return b
|
return b
|
||||||
|
|
||||||
|
def uint192_to_bytes(i):
|
||||||
|
b = hex_to_bytes(i)
|
||||||
|
if len(b) != 24: # 24 bytes = 192 bits
|
||||||
|
raise ValueError("UInt192 is not 192 bits long")
|
||||||
|
return b
|
||||||
|
|
||||||
def uint384_to_bytes(i):
|
def uint384_to_bytes(i):
|
||||||
b = hex_to_bytes(i)
|
b = hex_to_bytes(i)
|
||||||
if len(b) != 8: # 8 bytes = 64 bits
|
if len(b) != 8: # 8 bytes = 64 bits
|
||||||
@@ -440,6 +456,7 @@ def field_to_bytes(field_name, field_val):
|
|||||||
"UInt16": uint16_to_bytes,
|
"UInt16": uint16_to_bytes,
|
||||||
"UInt32": uint32_to_bytes,
|
"UInt32": uint32_to_bytes,
|
||||||
"UInt64": uint64_to_bytes,
|
"UInt64": uint64_to_bytes,
|
||||||
|
"UInt192": uint192_to_bytes,
|
||||||
"UInt384": uint384_to_bytes,
|
"UInt384": uint384_to_bytes,
|
||||||
"Vector256": vector256_to_bytes,
|
"Vector256": vector256_to_bytes,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -244,8 +244,8 @@ The _Amount_ type (also called "STAmount") is a special field type that represen
|
|||||||
|
|
||||||
Multi-Purpose Tokens (MPTs) consist of four segments in order:
|
Multi-Purpose Tokens (MPTs) consist of four segments in order:
|
||||||
|
|
||||||
1. 8 bits indicating that this is an MPT. The most significant bit is `0` to indicate that it's not a fungible token. The second bit is `1` to indicate that it is postiive. The third most significant bit is `1` to indicate that it is an MPT. The remaining 5 bits are reserved and must all be `0`.
|
1. 8 bits indicating that this is an MPT. The most significant bit is `0` to indicate that it's not a fungible token. The second bit is `1` to indicate that it is postiive. The third most significant bit is `1` to indicate that it is an MPT. The remaining 5 bits are reserved and must all be `0`. In other words, the first byte is `0x60`.
|
||||||
2. 64 bits indicating the quantity of the MPT, as a 64-bit _signed_ integer. (However, in most contexts, negative amounts are not allowed.)
|
2. 64 bits indicating the quantity of the MPT, as a 64-bit unsigned integer. (However, the maximum amount cannot be larger than 2<sup>63</sup>-1.)
|
||||||
3. 32 bits indicating the `Sequence` number of the transaction that created the MPT issuance.
|
3. 32 bits indicating the `Sequence` number of the transaction that created the MPT issuance.
|
||||||
4. 160 bits indicating the [AccountID][] of the MPT's issuer.
|
4. 160 bits indicating the [AccountID][] of the MPT's issuer.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user