ripple-binary-codec 1.7.1 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/dist/enums/definitions.json +250 -1
  2. package/dist/enums/src/enums/definitions.json +250 -1
  3. package/dist/types/index.js +2 -0
  4. package/dist/types/index.js.map +1 -1
  5. package/dist/types/issue.d.ts +39 -0
  6. package/dist/types/issue.js +81 -0
  7. package/dist/types/issue.js.map +1 -0
  8. package/dist/types/xchain-bridge.d.ts +45 -0
  9. package/dist/types/xchain-bridge.js +102 -0
  10. package/dist/types/xchain-bridge.js.map +1 -0
  11. package/package.json +3 -4
  12. package/src/README.md +3 -0
  13. package/src/binary.ts +188 -0
  14. package/src/coretypes.ts +31 -0
  15. package/src/enums/README.md +144 -0
  16. package/src/enums/bytes.ts +75 -0
  17. package/src/enums/constants.ts +4 -0
  18. package/src/enums/definitions.json +2599 -0
  19. package/src/enums/field.ts +85 -0
  20. package/src/enums/index.ts +34 -0
  21. package/src/enums/utils-renumber.ts +134 -0
  22. package/src/enums/xrpl-definitions-base.ts +111 -0
  23. package/src/enums/xrpl-definitions.ts +32 -0
  24. package/src/hash-prefixes.ts +40 -0
  25. package/src/hashes.ts +76 -0
  26. package/src/index.ts +141 -0
  27. package/src/ledger-hashes.ts +187 -0
  28. package/src/quality.ts +39 -0
  29. package/src/serdes/binary-parser.ts +217 -0
  30. package/src/serdes/binary-serializer.ts +166 -0
  31. package/src/shamap.ts +186 -0
  32. package/src/types/account-id.ts +86 -0
  33. package/src/types/amount.ts +256 -0
  34. package/src/types/blob.ts +43 -0
  35. package/src/types/currency.ts +140 -0
  36. package/src/types/hash-128.ts +33 -0
  37. package/src/types/hash-160.ts +20 -0
  38. package/src/types/hash-256.ts +16 -0
  39. package/src/types/hash.ts +81 -0
  40. package/src/types/index.ts +61 -0
  41. package/src/types/issue.ts +96 -0
  42. package/src/types/path-set.ts +290 -0
  43. package/src/types/serialized-type.ts +120 -0
  44. package/src/types/st-array.ts +107 -0
  45. package/src/types/st-object.ts +192 -0
  46. package/src/types/uint-16.ts +49 -0
  47. package/src/types/uint-32.ts +56 -0
  48. package/src/types/uint-64.ts +105 -0
  49. package/src/types/uint-8.ts +49 -0
  50. package/src/types/uint.ts +57 -0
  51. package/src/types/vector-256.ts +84 -0
  52. package/test/amount.test.js +0 -43
  53. package/test/binary-json.test.js +0 -45
  54. package/test/binary-parser.test.js +0 -396
  55. package/test/binary-serializer.test.js +0 -289
  56. package/test/definitions.test.js +0 -160
  57. package/test/fixtures/account-tx-transactions.db +0 -0
  58. package/test/fixtures/codec-fixtures.json +0 -4466
  59. package/test/fixtures/data-driven-tests.json +0 -2919
  60. package/test/fixtures/delivermin-tx-binary.json +0 -1
  61. package/test/fixtures/delivermin-tx.json +0 -98
  62. package/test/fixtures/deposit-preauth-tx-binary.json +0 -1
  63. package/test/fixtures/deposit-preauth-tx-meta-binary.json +0 -1
  64. package/test/fixtures/deposit-preauth-tx.json +0 -58
  65. package/test/fixtures/escrow-cancel-binary.json +0 -1
  66. package/test/fixtures/escrow-cancel-tx.json +0 -6
  67. package/test/fixtures/escrow-create-binary.json +0 -1
  68. package/test/fixtures/escrow-create-tx.json +0 -10
  69. package/test/fixtures/escrow-finish-binary.json +0 -1
  70. package/test/fixtures/escrow-finish-meta-binary.json +0 -1
  71. package/test/fixtures/escrow-finish-tx.json +0 -95
  72. package/test/fixtures/ledger-full-38129.json +0 -1
  73. package/test/fixtures/ledger-full-40000.json +0 -1
  74. package/test/fixtures/negative-unl.json +0 -12
  75. package/test/fixtures/nf-token.json +0 -547
  76. package/test/fixtures/payment-channel-claim-binary.json +0 -1
  77. package/test/fixtures/payment-channel-claim-tx.json +0 -8
  78. package/test/fixtures/payment-channel-create-binary.json +0 -1
  79. package/test/fixtures/payment-channel-create-tx.json +0 -11
  80. package/test/fixtures/payment-channel-fund-binary.json +0 -1
  81. package/test/fixtures/payment-channel-fund-tx.json +0 -7
  82. package/test/fixtures/signerlistset-tx-binary.json +0 -1
  83. package/test/fixtures/signerlistset-tx-meta-binary.json +0 -1
  84. package/test/fixtures/signerlistset-tx.json +0 -94
  85. package/test/fixtures/ticket-create-binary.json +0 -1
  86. package/test/fixtures/ticket-create-tx.json +0 -7
  87. package/test/fixtures/x-codec-fixtures.json +0 -188
  88. package/test/hash.test.js +0 -135
  89. package/test/ledger.test.js +0 -29
  90. package/test/lower-case-hex.test.js +0 -46
  91. package/test/pseudo-transaction.test.js +0 -38
  92. package/test/quality.test.js +0 -15
  93. package/test/shamap.test.js +0 -89
  94. package/test/signing-data-encoding.test.js +0 -242
  95. package/test/tx-encode-decode.test.js +0 -119
  96. package/test/types.test.js +0 -34
  97. package/test/uint.test.js +0 -148
  98. package/test/utils.js +0 -30
  99. package/test/x-address.test.js +0 -181
@@ -0,0 +1,187 @@
1
+ import * as assert from 'assert'
2
+ import { ShaMap, ShaMapNode, ShaMapLeaf } from './shamap'
3
+ import { HashPrefix } from './hash-prefixes'
4
+ import { Sha512Half } from './hashes'
5
+ import { BinarySerializer, serializeObject } from './binary'
6
+ import { Hash256 } from './types/hash-256'
7
+ import { STObject } from './types/st-object'
8
+ import { UInt64 } from './types/uint-64'
9
+ import { UInt32 } from './types/uint-32'
10
+ import { UInt8 } from './types/uint-8'
11
+ import { BinaryParser } from './serdes/binary-parser'
12
+ import { JsonObject } from './types/serialized-type'
13
+ import bigInt = require('big-integer')
14
+ import { XrplDefinitionsBase } from './enums'
15
+
16
+ /**
17
+ * Computes the hash of a list of objects
18
+ *
19
+ * @param itemizer Converts an item into a format that can be added to SHAMap
20
+ * @param itemsJson Array of items to add to a SHAMap
21
+ * @returns the hash of the SHAMap
22
+ */
23
+ function computeHash(
24
+ itemizer: (item: JsonObject) => [Hash256?, ShaMapNode?, ShaMapLeaf?],
25
+ itemsJson: Array<JsonObject>,
26
+ ): Hash256 {
27
+ const map = new ShaMap()
28
+ itemsJson.forEach((item) => map.addItem(...itemizer(item)))
29
+ return map.hash()
30
+ }
31
+
32
+ /**
33
+ * Interface describing a transaction item
34
+ */
35
+ interface transactionItemObject extends JsonObject {
36
+ hash: string
37
+ metaData: JsonObject
38
+ }
39
+
40
+ /**
41
+ * Convert a transaction into an index and an item
42
+ *
43
+ * @param json transaction with metadata
44
+ * @returns a tuple of index and item to be added to SHAMap
45
+ */
46
+ function transactionItemizer(
47
+ json: transactionItemObject,
48
+ ): [Hash256, ShaMapNode, undefined] {
49
+ assert.ok(json.hash)
50
+ const index = Hash256.from(json.hash)
51
+ const item = {
52
+ hashPrefix() {
53
+ return HashPrefix.transaction
54
+ },
55
+ toBytesSink(sink) {
56
+ const serializer = new BinarySerializer(sink)
57
+ serializer.writeLengthEncoded(STObject.from(json))
58
+ serializer.writeLengthEncoded(STObject.from(json.metaData))
59
+ },
60
+ } as ShaMapNode
61
+ return [index, item, undefined]
62
+ }
63
+
64
+ /**
65
+ * Interface describing an entry item
66
+ */
67
+ interface entryItemObject extends JsonObject {
68
+ index: string
69
+ }
70
+
71
+ /**
72
+ * Convert an entry to a pair Hash256 and ShaMapNode
73
+ *
74
+ * @param json JSON describing a ledger entry item
75
+ * @returns a tuple of index and item to be added to SHAMap
76
+ */
77
+ function entryItemizer(
78
+ json: entryItemObject,
79
+ ): [Hash256, ShaMapNode, undefined] {
80
+ const index = Hash256.from(json.index)
81
+ const bytes = serializeObject(json)
82
+ const item = {
83
+ hashPrefix() {
84
+ return HashPrefix.accountStateEntry
85
+ },
86
+ toBytesSink(sink) {
87
+ sink.put(bytes)
88
+ },
89
+ } as ShaMapNode
90
+ return [index, item, undefined]
91
+ }
92
+
93
+ /**
94
+ * Function computing the hash of a transaction tree
95
+ *
96
+ * @param param An array of transaction objects to hash
97
+ * @returns A Hash256 object
98
+ */
99
+ function transactionTreeHash(param: Array<JsonObject>): Hash256 {
100
+ const itemizer = transactionItemizer as (
101
+ json: JsonObject,
102
+ ) => [Hash256, ShaMapNode, undefined]
103
+ return computeHash(itemizer, param)
104
+ }
105
+
106
+ /**
107
+ * Function computing the hash of accountState
108
+ *
109
+ * @param param A list of accountStates hash
110
+ * @returns A Hash256 object
111
+ */
112
+ function accountStateHash(param: Array<JsonObject>): Hash256 {
113
+ const itemizer = entryItemizer as (
114
+ json: JsonObject,
115
+ ) => [Hash256, ShaMapNode, undefined]
116
+ return computeHash(itemizer, param)
117
+ }
118
+
119
+ /**
120
+ * Interface describing a ledger header
121
+ */
122
+ interface ledgerObject {
123
+ ledger_index: number
124
+ total_coins: string | number | bigInt.BigInteger
125
+ parent_hash: string
126
+ transaction_hash: string
127
+ account_hash: string
128
+ parent_close_time: number
129
+ close_time: number
130
+ close_time_resolution: number
131
+ close_flags: number
132
+ }
133
+
134
+ /**
135
+ * Serialize and hash a ledger header
136
+ *
137
+ * @param header a ledger header
138
+ * @returns the hash of header
139
+ */
140
+ function ledgerHash(header: ledgerObject): Hash256 {
141
+ const hash = new Sha512Half()
142
+ hash.put(HashPrefix.ledgerHeader)
143
+ assert.ok(header.parent_close_time !== undefined)
144
+ assert.ok(header.close_flags !== undefined)
145
+
146
+ UInt32.from<number>(header.ledger_index).toBytesSink(hash)
147
+ UInt64.from<bigInt.BigInteger>(
148
+ bigInt(String(header.total_coins)),
149
+ ).toBytesSink(hash)
150
+ Hash256.from<string>(header.parent_hash).toBytesSink(hash)
151
+ Hash256.from<string>(header.transaction_hash).toBytesSink(hash)
152
+ Hash256.from<string>(header.account_hash).toBytesSink(hash)
153
+ UInt32.from<number>(header.parent_close_time).toBytesSink(hash)
154
+ UInt32.from<number>(header.close_time).toBytesSink(hash)
155
+ UInt8.from<number>(header.close_time_resolution).toBytesSink(hash)
156
+ UInt8.from<number>(header.close_flags).toBytesSink(hash)
157
+ return hash.finish()
158
+ }
159
+
160
+ /**
161
+ * Decodes a serialized ledger header
162
+ *
163
+ * @param binary A serialized ledger header
164
+ * @param definitions Type definitions to parse the ledger objects.
165
+ * Used if there are non-default ledger objects to decode.
166
+ * @returns A JSON object describing a ledger header
167
+ */
168
+ function decodeLedgerData(
169
+ binary: string,
170
+ definitions?: XrplDefinitionsBase,
171
+ ): object {
172
+ assert.ok(typeof binary === 'string', 'binary must be a hex string')
173
+ const parser = new BinaryParser(binary, definitions)
174
+ return {
175
+ ledger_index: parser.readUInt32(),
176
+ total_coins: parser.readType(UInt64).valueOf().toString(),
177
+ parent_hash: parser.readType(Hash256).toHex(),
178
+ transaction_hash: parser.readType(Hash256).toHex(),
179
+ account_hash: parser.readType(Hash256).toHex(),
180
+ parent_close_time: parser.readUInt32(),
181
+ close_time: parser.readUInt32(),
182
+ close_time_resolution: parser.readUInt8(),
183
+ close_flags: parser.readUInt8(),
184
+ }
185
+ }
186
+
187
+ export { accountStateHash, transactionTreeHash, ledgerHash, decodeLedgerData }
package/src/quality.ts ADDED
@@ -0,0 +1,39 @@
1
+ import { coreTypes } from './types'
2
+ import { Decimal } from 'decimal.js'
3
+ import bigInt = require('big-integer')
4
+ import { Buffer } from 'buffer/'
5
+
6
+ /**
7
+ * class for encoding and decoding quality
8
+ */
9
+ class quality {
10
+ /**
11
+ * Encode quality amount
12
+ *
13
+ * @param arg string representation of an amount
14
+ * @returns Serialized quality
15
+ */
16
+ static encode(quality: string): Buffer {
17
+ const decimal = new Decimal(quality)
18
+ const exponent = decimal.e - 15
19
+ const qualityString = decimal.times(`1e${-exponent}`).abs().toString()
20
+ const bytes = coreTypes.UInt64.from(bigInt(qualityString)).toBytes()
21
+ bytes[0] = exponent + 100
22
+ return bytes
23
+ }
24
+
25
+ /**
26
+ * Decode quality amount
27
+ *
28
+ * @param arg hex-string denoting serialized quality
29
+ * @returns deserialized quality
30
+ */
31
+ static decode(quality: string): Decimal {
32
+ const bytes = Buffer.from(quality, 'hex').slice(-8)
33
+ const exponent = bytes[0] - 100
34
+ const mantissa = new Decimal(`0x${bytes.slice(1).toString('hex')}`)
35
+ return mantissa.times(`1e${exponent}`)
36
+ }
37
+ }
38
+
39
+ export { quality }
@@ -0,0 +1,217 @@
1
+ import * as assert from 'assert'
2
+ import {
3
+ XrplDefinitionsBase,
4
+ DEFAULT_DEFINITIONS,
5
+ FieldInstance,
6
+ } from '../enums'
7
+ import { type SerializedType } from '../types/serialized-type'
8
+ import { Buffer } from 'buffer/'
9
+
10
+ /**
11
+ * BinaryParser is used to compute fields and values from a HexString
12
+ */
13
+ class BinaryParser {
14
+ private bytes: Buffer
15
+ definitions: XrplDefinitionsBase
16
+
17
+ /**
18
+ * Initialize bytes to a hex string
19
+ *
20
+ * @param hexBytes a hex string
21
+ * @param definitions Rippled definitions used to parse the values of transaction types and such.
22
+ * Can be customized for sidechains and amendments.
23
+ */
24
+ constructor(
25
+ hexBytes: string,
26
+ definitions: XrplDefinitionsBase = DEFAULT_DEFINITIONS,
27
+ ) {
28
+ this.bytes = Buffer.from(hexBytes, 'hex')
29
+ this.definitions = definitions
30
+ }
31
+
32
+ /**
33
+ * Peek the first byte of the BinaryParser
34
+ *
35
+ * @returns The first byte of the BinaryParser
36
+ */
37
+ peek(): number {
38
+ assert.ok(this.bytes.byteLength !== 0)
39
+ return this.bytes[0]
40
+ }
41
+
42
+ /**
43
+ * Consume the first n bytes of the BinaryParser
44
+ *
45
+ * @param n the number of bytes to skip
46
+ */
47
+ skip(n: number): void {
48
+ assert.ok(n <= this.bytes.byteLength)
49
+ this.bytes = this.bytes.slice(n)
50
+ }
51
+
52
+ /**
53
+ * read the first n bytes from the BinaryParser
54
+ *
55
+ * @param n The number of bytes to read
56
+ * @return The bytes
57
+ */
58
+ read(n: number): Buffer {
59
+ assert.ok(n <= this.bytes.byteLength)
60
+
61
+ const slice = this.bytes.slice(0, n)
62
+ this.skip(n)
63
+ return slice
64
+ }
65
+
66
+ /**
67
+ * Read an integer of given size
68
+ *
69
+ * @param n The number of bytes to read
70
+ * @return The number represented by those bytes
71
+ */
72
+ readUIntN(n: number): number {
73
+ assert.ok(0 < n && n <= 4, 'invalid n')
74
+ return this.read(n).reduce((a, b) => (a << 8) | b) >>> 0
75
+ }
76
+
77
+ readUInt8(): number {
78
+ return this.readUIntN(1)
79
+ }
80
+
81
+ readUInt16(): number {
82
+ return this.readUIntN(2)
83
+ }
84
+
85
+ readUInt32(): number {
86
+ return this.readUIntN(4)
87
+ }
88
+
89
+ size(): number {
90
+ return this.bytes.byteLength
91
+ }
92
+
93
+ end(customEnd?: number): boolean {
94
+ const length = this.bytes.byteLength
95
+ return length === 0 || (customEnd !== undefined && length <= customEnd)
96
+ }
97
+
98
+ /**
99
+ * Reads variable length encoded bytes
100
+ *
101
+ * @return The variable length bytes
102
+ */
103
+ readVariableLength(): Buffer {
104
+ return this.read(this.readVariableLengthLength())
105
+ }
106
+
107
+ /**
108
+ * Reads the length of the variable length encoded bytes
109
+ *
110
+ * @return The length of the variable length encoded bytes
111
+ */
112
+ readVariableLengthLength(): number {
113
+ const b1 = this.readUInt8()
114
+ if (b1 <= 192) {
115
+ return b1
116
+ } else if (b1 <= 240) {
117
+ const b2 = this.readUInt8()
118
+ return 193 + (b1 - 193) * 256 + b2
119
+ } else if (b1 <= 254) {
120
+ const b2 = this.readUInt8()
121
+ const b3 = this.readUInt8()
122
+ return 12481 + (b1 - 241) * 65536 + b2 * 256 + b3
123
+ }
124
+ throw new Error('Invalid variable length indicator')
125
+ }
126
+
127
+ /**
128
+ * Reads the field ordinal from the BinaryParser
129
+ *
130
+ * @return Field ordinal
131
+ */
132
+ readFieldOrdinal(): number {
133
+ let type = this.readUInt8()
134
+ let nth = type & 15
135
+ type >>= 4
136
+
137
+ if (type === 0) {
138
+ type = this.readUInt8()
139
+ if (type === 0 || type < 16) {
140
+ throw new Error('Cannot read FieldOrdinal, type_code out of range')
141
+ }
142
+ }
143
+
144
+ if (nth === 0) {
145
+ nth = this.readUInt8()
146
+ if (nth === 0 || nth < 16) {
147
+ throw new Error('Cannot read FieldOrdinal, field_code out of range')
148
+ }
149
+ }
150
+
151
+ return (type << 16) | nth
152
+ }
153
+
154
+ /**
155
+ * Read the field from the BinaryParser
156
+ *
157
+ * @return The field represented by the bytes at the head of the BinaryParser
158
+ */
159
+ readField(): FieldInstance {
160
+ return this.definitions.field.fromString(this.readFieldOrdinal().toString())
161
+ }
162
+
163
+ /**
164
+ * Read a given type from the BinaryParser
165
+ *
166
+ * @param type The type that you want to read from the BinaryParser
167
+ * @return The instance of that type read from the BinaryParser
168
+ */
169
+ readType(type: typeof SerializedType): SerializedType {
170
+ return type.fromParser(this)
171
+ }
172
+
173
+ /**
174
+ * Get the type associated with a given field
175
+ *
176
+ * @param field The field that you wan to get the type of
177
+ * @return The type associated with the given field
178
+ */
179
+ typeForField(field: FieldInstance): typeof SerializedType {
180
+ return field.associatedType
181
+ }
182
+
183
+ /**
184
+ * Read value of the type specified by field from the BinaryParser
185
+ *
186
+ * @param field The field that you want to get the associated value for
187
+ * @return The value associated with the given field
188
+ */
189
+ readFieldValue(field: FieldInstance): SerializedType {
190
+ const type = this.typeForField(field)
191
+ if (!type) {
192
+ throw new Error(`unsupported: (${field.name}, ${field.type.name})`)
193
+ }
194
+ const sizeHint = field.isVariableLengthEncoded
195
+ ? this.readVariableLengthLength()
196
+ : undefined
197
+ const value = type.fromParser(this, sizeHint)
198
+ if (value === undefined) {
199
+ throw new Error(
200
+ `fromParser for (${field.name}, ${field.type.name}) -> undefined `,
201
+ )
202
+ }
203
+ return value
204
+ }
205
+
206
+ /**
207
+ * Get the next field and value from the BinaryParser
208
+ *
209
+ * @return The field and value
210
+ */
211
+ readFieldAndValue(): [FieldInstance, SerializedType] {
212
+ const field = this.readField()
213
+ return [field, this.readFieldValue(field)]
214
+ }
215
+ }
216
+
217
+ export { BinaryParser }
@@ -0,0 +1,166 @@
1
+ import * as assert from 'assert'
2
+ import { FieldInstance } from '../enums'
3
+ import { type SerializedType } from '../types/serialized-type'
4
+ import { Buffer } from 'buffer/'
5
+
6
+ /**
7
+ * Bytes list is a collection of buffer objects
8
+ */
9
+ class BytesList {
10
+ private bytesArray: Array<Buffer> = []
11
+
12
+ /**
13
+ * Get the total number of bytes in the BytesList
14
+ *
15
+ * @return the number of bytes
16
+ */
17
+ public getLength(): number {
18
+ return Buffer.concat(this.bytesArray).byteLength
19
+ }
20
+
21
+ /**
22
+ * Put bytes in the BytesList
23
+ *
24
+ * @param bytesArg A Buffer
25
+ * @return this BytesList
26
+ */
27
+ public put(bytesArg: Buffer): BytesList {
28
+ const bytes = Buffer.from(bytesArg) // Temporary, to catch instances of Uint8Array being passed in
29
+ this.bytesArray.push(bytes)
30
+ return this
31
+ }
32
+
33
+ /**
34
+ * Write this BytesList to the back of another bytes list
35
+ *
36
+ * @param list The BytesList to write to
37
+ */
38
+ public toBytesSink(list: BytesList): void {
39
+ list.put(this.toBytes())
40
+ }
41
+
42
+ public toBytes(): Buffer {
43
+ return Buffer.concat(this.bytesArray)
44
+ }
45
+
46
+ toHex(): string {
47
+ return this.toBytes().toString('hex').toUpperCase()
48
+ }
49
+ }
50
+
51
+ /**
52
+ * BinarySerializer is used to write fields and values to buffers
53
+ */
54
+ class BinarySerializer {
55
+ private sink: BytesList = new BytesList()
56
+
57
+ constructor(sink: BytesList) {
58
+ this.sink = sink
59
+ }
60
+
61
+ /**
62
+ * Write a value to this BinarySerializer
63
+ *
64
+ * @param value a SerializedType value
65
+ */
66
+ write(value: SerializedType): void {
67
+ value.toBytesSink(this.sink)
68
+ }
69
+
70
+ /**
71
+ * Write bytes to this BinarySerializer
72
+ *
73
+ * @param bytes the bytes to write
74
+ */
75
+ put(bytes: Buffer): void {
76
+ this.sink.put(bytes)
77
+ }
78
+
79
+ /**
80
+ * Write a value of a given type to this BinarySerializer
81
+ *
82
+ * @param type the type to write
83
+ * @param value a value of that type
84
+ */
85
+ writeType(type: typeof SerializedType, value: SerializedType): void {
86
+ this.write(type.from(value))
87
+ }
88
+
89
+ /**
90
+ * Write BytesList to this BinarySerializer
91
+ *
92
+ * @param bl BytesList to write to BinarySerializer
93
+ */
94
+ writeBytesList(bl: BytesList): void {
95
+ bl.toBytesSink(this.sink)
96
+ }
97
+
98
+ /**
99
+ * Calculate the header of Variable Length encoded bytes
100
+ *
101
+ * @param length the length of the bytes
102
+ */
103
+ private encodeVariableLength(length: number): Buffer {
104
+ const lenBytes = Buffer.alloc(3)
105
+ if (length <= 192) {
106
+ lenBytes[0] = length
107
+ return lenBytes.slice(0, 1)
108
+ } else if (length <= 12480) {
109
+ length -= 193
110
+ lenBytes[0] = 193 + (length >>> 8)
111
+ lenBytes[1] = length & 0xff
112
+ return lenBytes.slice(0, 2)
113
+ } else if (length <= 918744) {
114
+ length -= 12481
115
+ lenBytes[0] = 241 + (length >>> 16)
116
+ lenBytes[1] = (length >> 8) & 0xff
117
+ lenBytes[2] = length & 0xff
118
+ return lenBytes.slice(0, 3)
119
+ }
120
+ throw new Error('Overflow error')
121
+ }
122
+
123
+ /**
124
+ * Write field and value to BinarySerializer
125
+ *
126
+ * @param field field to write to BinarySerializer
127
+ * @param value value to write to BinarySerializer
128
+ */
129
+ writeFieldAndValue(
130
+ field: FieldInstance,
131
+ value: SerializedType,
132
+ isUnlModifyWorkaround = false,
133
+ ): void {
134
+ const associatedValue = field.associatedType.from(value)
135
+ assert.ok(associatedValue.toBytesSink !== undefined)
136
+ assert.ok(field.name !== undefined)
137
+
138
+ this.sink.put(field.header)
139
+
140
+ if (field.isVariableLengthEncoded) {
141
+ this.writeLengthEncoded(associatedValue, isUnlModifyWorkaround)
142
+ } else {
143
+ associatedValue.toBytesSink(this.sink)
144
+ }
145
+ }
146
+
147
+ /**
148
+ * Write a variable length encoded value to the BinarySerializer
149
+ *
150
+ * @param value length encoded value to write to BytesList
151
+ */
152
+ public writeLengthEncoded(
153
+ value: SerializedType,
154
+ isUnlModifyWorkaround = false,
155
+ ): void {
156
+ const bytes = new BytesList()
157
+ if (!isUnlModifyWorkaround) {
158
+ // this part doesn't happen for the Account field in a UNLModify transaction
159
+ value.toBytesSink(bytes)
160
+ }
161
+ this.put(this.encodeVariableLength(bytes.getLength()))
162
+ this.writeBytesList(bytes)
163
+ }
164
+ }
165
+
166
+ export { BytesList, BinarySerializer }