1- import { concat } from '@xrplf/isomorphic/utils'
1+ import { bytesToHex , concat } from '@xrplf/isomorphic/utils'
22import { BinaryParser } from '../serdes/binary-parser'
33
44import { AccountID } from './account-id'
55import { Currency } from './currency'
66import { JsonObject , SerializedType } from './serialized-type'
77import { Hash192 } from './hash-192'
8+ import { readUInt32BE , writeUInt32BE } from '../utils'
89
910interface XRPIssue extends JsonObject {
1011 currency : string
@@ -35,21 +36,23 @@ function isIssueObject(arg): arg is IssueObject {
3536 return isXRP || isIOU || isMPT
3637}
3738
39+ const MPT_WIDTH = 44
40+ const NO_ACCOUNT = AccountID . from ( '0000000000000000000000000000000000000001' )
41+
3842/**
39- * Class for serializing/Deserializing Amounts
43+ * Class for serializing/Deserializing Issue
4044 */
4145class Issue extends SerializedType {
42- static readonly ZERO_ISSUED_CURRENCY : Issue = new Issue ( new Uint8Array ( 20 ) )
46+ static readonly XRP_ISSUE : Issue = new Issue ( new Uint8Array ( 20 ) )
4347
4448 constructor ( bytes : Uint8Array ) {
45- super ( bytes ?? Issue . ZERO_ISSUED_CURRENCY . bytes )
49+ super ( bytes ?? Issue . XRP_ISSUE . bytes )
4650 }
4751
4852 /**
49- * Construct an amount from an IOU or string amount
53+ * Construct Issue from XRPIssue, IOUIssue or MPTIssue
5054 *
51- * @param value An Amount, object representing an IOU, MPTAmount, or a string
52- * representing an integer amount
55+ * @param value An object representing an XRPIssue, IOUIssue or MPTIssue
5356 * @returns An Issue object
5457 */
5558 static from < T extends Issue | IssueObject > ( value : T ) : Issue {
@@ -76,45 +79,69 @@ class Issue extends SerializedType {
7679 const mptIssuanceIdBytes = Hash192 . from (
7780 value . mpt_issuance_id . toString ( ) ,
7881 ) . toBytes ( )
79- return new Issue ( mptIssuanceIdBytes )
82+ const issuerAccount = mptIssuanceIdBytes . slice ( 4 )
83+ const sequence = Number ( readUInt32BE ( mptIssuanceIdBytes . slice ( 0 , 4 ) , 0 ) ) // sequence is in Big-endian format in mpt_issuance_id
84+
85+ // Convert to Little-endian
86+ const sequenceBuffer = new Uint8Array ( 4 )
87+ new DataView ( sequenceBuffer . buffer ) . setUint32 ( 0 , sequence , true )
88+
89+ return new Issue (
90+ concat ( [ issuerAccount , NO_ACCOUNT . toBytes ( ) , sequenceBuffer ] ) ,
91+ )
8092 }
8193 }
8294
83- throw new Error ( 'Invalid type to construct an Amount ' )
95+ throw new Error ( 'Invalid type to construct an Issue ' )
8496 }
8597
8698 /**
87- * Read an amount from a BinaryParser
99+ * Read Issue from a BinaryParser
88100 *
89- * @param parser BinaryParser to read the Amount from
90- * @param hint The number of bytes to consume from the parser.
91- * For an MPT amount, pass 24 (the fixed length for Hash192).
101+ * @param parser BinaryParser to read the Issue from
92102 *
93103 * @returns An Issue object
94104 */
95- static fromParser ( parser : BinaryParser , hint ?: number ) : Issue {
96- if ( hint === Hash192 . width ) {
97- const mptBytes = parser . read ( Hash192 . width )
98- return new Issue ( mptBytes )
105+ static fromParser ( parser : BinaryParser ) : Issue {
106+ // XRP
107+ const currencyOrAccount = parser . read ( 20 )
108+ if ( new Currency ( currencyOrAccount ) . toJSON ( ) === 'XRP' ) {
109+ return new Issue ( currencyOrAccount )
99110 }
100- const currency = parser . read ( 20 )
101- if ( new Currency ( currency ) . toJSON ( ) === 'XRP' ) {
102- return new Issue ( currency )
111+
112+ // MPT
113+ const issuerAccountId = new AccountID ( parser . read ( 20 ) )
114+ if ( NO_ACCOUNT . toHex ( ) === issuerAccountId . toHex ( ) ) {
115+ const sequence = parser . read ( 4 )
116+ return new Issue (
117+ concat ( [ currencyOrAccount , NO_ACCOUNT . toBytes ( ) , sequence ] ) ,
118+ )
103119 }
104- const currencyAndIssuer = [ currency , parser . read ( 20 ) ]
105- return new Issue ( concat ( currencyAndIssuer ) )
120+
121+ // IOU
122+ return new Issue ( concat ( [ currencyOrAccount , issuerAccountId . toBytes ( ) ] ) )
106123 }
107124
108125 /**
109- * Get the JSON representation of this Amount
126+ * Get the JSON representation of this IssueObject
110127 *
111128 * @returns the JSON interpretation of this.bytes
112129 */
113130 toJSON ( ) : IssueObject {
114- // If the buffer is exactly 24 bytes, treat it as an MPT amount.
115- if ( this . toBytes ( ) . length === Hash192 . width ) {
131+ // If the buffer is exactly 44 bytes, treat it as an MPTIssue.
132+ if ( this . toBytes ( ) . length === MPT_WIDTH ) {
133+ const issuerAccount = this . toBytes ( ) . slice ( 0 , 20 )
134+ const sequence = new DataView ( this . toBytes ( ) . slice ( 40 ) . buffer ) . getUint32 (
135+ 0 ,
136+ true ,
137+ )
138+
139+ // sequence part of mpt_issuance_id should be in Big-endian
140+ const sequenceBuffer = new Uint8Array ( 4 )
141+ writeUInt32BE ( sequenceBuffer , sequence , 0 )
142+
116143 return {
117- mpt_issuance_id : this . toHex ( ) . toUpperCase ( ) ,
144+ mpt_issuance_id : bytesToHex ( concat ( [ sequenceBuffer , issuerAccount ] ) ) ,
118145 }
119146 }
120147
0 commit comments