MPT Support for library and binary codec
This commit is contained in:
Shawn Xie
2024-12-11 13:38:13 -08:00
committed by GitHub
parent e3188b83ed
commit b04efe8c9e
47 changed files with 3042 additions and 1067 deletions

View File

@@ -1,5 +1,7 @@
import { coreTypes } from '../src/types'
import fixtures from './fixtures/data-driven-tests.json'
import { makeParser } from '../src/binary'
const { Amount } = coreTypes
function amountErrorTests() {
@@ -25,6 +27,16 @@ describe('Amount', function () {
it('can be parsed from', function () {
expect(Amount.from('1000000') instanceof Amount).toBe(true)
expect(Amount.from('1000000').toJSON()).toEqual('1000000')
// it not valid to have negative XRP. But we test it anyways
// to ensure logic correctness for toJSON of the Amount class
{
const parser = makeParser('0000000000000001')
const value = parser.readType(Amount)
const json = value.toJSON()
expect(json).toEqual('-1')
}
const fixture = {
value: '1',
issuer: '0000000000000000000000000000000000000000',
@@ -38,5 +50,35 @@ describe('Amount', function () {
}
expect(amt.toJSON()).toEqual(rewritten)
})
it('can be parsed from MPT', function () {
let fixture = {
value: '100',
mpt_issuance_id: '00002403C84A0A28E0190E208E982C352BBD5006600555CF',
}
let amt = Amount.from(fixture)
expect(amt.toJSON()).toEqual(fixture)
fixture = {
value: '9223372036854775807',
mpt_issuance_id: '00002403C84A0A28E0190E208E982C352BBD5006600555CF',
}
amt = Amount.from(fixture)
expect(amt.toJSON()).toEqual(fixture)
// it not valid to have negative MPT. But we test it anyways
// to ensure logic correctness for toJSON of the Amount class
{
const parser = makeParser(
'20000000000000006400002403C84A0A28E0190E208E982C352BBD5006600555CF',
)
const value = parser.readType(Amount)
const json = value.toJSON()
expect(json).toEqual({
mpt_issuance_id: '00002403C84A0A28E0190E208E982C352BBD5006600555CF',
value: '-100',
})
}
})
amountErrorTests()
})

View File

@@ -22,6 +22,7 @@ function assertEqualAmountJSON(actual, expected) {
}
expect(actual.currency).toEqual(expected.currency)
expect(actual.issuer).toEqual(expected.issuer)
expect(actual.mpt_issuance_id).toEqual(expected.mpt_issuance_id)
expect(
actual.value === expected.value ||
new BigNumber(actual.value).eq(new BigNumber(expected.value)),
@@ -207,12 +208,12 @@ function amountParsingTests() {
return
}
const parser = makeParser(f.expected_hex)
const testName = `values_tests[${i}] parses ${f.expected_hex.slice(
const hexToJsonTestName = `values_tests[${i}] parses ${f.expected_hex.slice(
0,
16,
)}...
as ${JSON.stringify(f.test_json)}`
it(testName, () => {
it(hexToJsonTestName, () => {
const value = parser.readType(Amount)
// May not actually be in canonical form. The fixtures are to be used
// also for json -> binary;
@@ -223,6 +224,15 @@ function amountParsingTests() {
expect((exponent.e ?? 0) - 15).toEqual(f?.exponent)
}
})
const jsonToHexTestName = `values_tests[${i}] parses ${JSON.stringify(
f.test_json,
)}...
as ${f.expected_hex.slice(0, 16)}`
it(jsonToHexTestName, () => {
const amt = Amount.from(f.test_json)
expect(amt.toHex()).toEqual(f.expected_hex)
})
})
}

View File

@@ -2499,7 +2499,7 @@
"type_id": 6,
"is_native": true,
"type": "Amount",
"expected_hex": "0000000000000001",
"error": "Value is negative",
"is_negative": true
},
{
@@ -2914,6 +2914,170 @@
"type": "Amount",
"error": "10000000000000000000 absolute XRP is bigger than max native value 100000000000.0",
"is_negative": true
},
{
"test_json": {
"mpt_issuance_id": "00002403C84A0A28E0190E208E982C352BBD5006600555CF",
"value": "9223372036854775808"
},
"type": "Amount",
"error": "Value is too large"
},
{
"test_json": {
"mpt_issuance_id": "00002403C84A0A28E0190E208E982C352BBD5006600555CF",
"value": "18446744073709551615"
},
"type": "Amount",
"error": "Value is too large"
},
{
"test_json": {
"mpt_issuance_id": "00002403C84A0A28E0190E208E982C352BBD5006600555CF",
"value": "-1"
},
"type": "Amount",
"error": "Value is negative"
},
{
"test_json": {
"mpt_issuance_id": "00002403C84A0A28E0190E208E982C352BBD5006600555CF",
"value": "10.1"
},
"type": "Amount",
"error": "Value has decimal point"
},
{
"test_json": {
"mpt_issuance_id": "10",
"value": "10"
},
"type": "Amount",
"error": "mpt_issuance_id has invalid hash length"
},
{
"test_json": {
"mpt_issuance_id": "00002403C84A0A28E0190E208E982C352BBD5006600555CF",
"value": "10",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji"
},
"type": "Amount",
"error": "Issuer not valid for MPT"
},
{
"test_json": {
"mpt_issuance_id": "00002403C84A0A28E0190E208E982C352BBD5006600555CF",
"value": "10",
"currency": "USD"
},
"type": "Amount",
"error": "Currency not valid for MPT"
},
{
"test_json": {
"mpt_issuance_id": "00002403C84A0A28E0190E208E982C352BBD5006600555CF",
"value": "a"
},
"type": "Amount",
"error": "Value has incorrect hex format"
},
{
"test_json": {
"mpt_issuance_id": "00002403C84A0A28E0190E208E982C352BBD5006600555CF",
"value": "0xy"
},
"type": "Amount",
"error": "Value has bad hex character"
},
{
"test_json": {
"mpt_issuance_id": "00002403C84A0A28E0190E208E982C352BBD5006600555CF",
"value": "/"
},
"type": "Amount",
"error": "Value has bad character"
},
{
"test_json": {
"mpt_issuance_id": "00002403C84A0A28E0190E208E982C352BBD5006600555CF",
"value": "0x8000000000000000"
},
"type": "Amount",
"error": "Hex value out of range"
},
{
"test_json": {
"mpt_issuance_id": "00002403C84A0A28E0190E208E982C352BBD5006600555CF",
"value": "0xFFFFFFFFFFFFFFFF"
},
"type": "Amount",
"error": "Hex value out of range"
},
{
"test_json": {
"mpt_issuance_id":"00002403C84A0A28E0190E208E982C352BBD5006600555CF",
"value": "9223372036854775807"
},
"type_id": 6,
"is_native": false,
"type": "Amount",
"expected_hex": "607FFFFFFFFFFFFFFF00002403C84A0A28E0190E208E982C352BBD5006600555CF",
"is_negative": false
},
{
"test_json": {
"mpt_issuance_id":"00002403C84A0A28E0190E208E982C352BBD5006600555CF",
"value": "0"
},
"type_id": 6,
"is_native": false,
"type": "Amount",
"expected_hex": "60000000000000000000002403C84A0A28E0190E208E982C352BBD5006600555CF",
"is_negative": false
},
{
"test_json": {
"mpt_issuance_id":"00002403C84A0A28E0190E208E982C352BBD5006600555CF",
"value": "-0"
},
"type_id": 6,
"is_native": false,
"type": "Amount",
"expected_hex": "60000000000000000000002403C84A0A28E0190E208E982C352BBD5006600555CF",
"is_negative": false
},
{
"test_json": {
"mpt_issuance_id":"00002403C84A0A28E0190E208E982C352BBD5006600555CF",
"value": "100"
},
"type_id": 6,
"is_native": false,
"type": "Amount",
"expected_hex": "60000000000000006400002403C84A0A28E0190E208E982C352BBD5006600555CF",
"is_negative": false
},
{
"test_json": {
"mpt_issuance_id":"00002403C84A0A28E0190E208E982C352BBD5006600555CF",
"value": "0xa"
},
"type_id": 6,
"is_native": false,
"type": "Amount",
"expected_hex": "60000000000000000A00002403C84A0A28E0190E208E982C352BBD5006600555CF",
"is_negative": false
},
{
"test_json": {
"mpt_issuance_id":"00002403C84A0A28E0190E208E982C352BBD5006600555CF",
"value": "0x7FFFFFFFFFFFFFFF"
},
"type_id": 6,
"is_native": false,
"type": "Amount",
"expected_hex": "607FFFFFFFFFFFFFFF00002403C84A0A28E0190E208E982C352BBD5006600555CF",
"is_negative": false
}
]
}

View File

@@ -1,4 +1,11 @@
import { Hash128, Hash160, Hash256, AccountID, Currency } from '../src/types'
import {
Hash128,
Hash160,
Hash192,
Hash256,
AccountID,
Currency,
} from '../src/types'
describe('Hash128', function () {
it('has a static width member', function () {
@@ -51,6 +58,33 @@ describe('Hash160', function () {
})
})
describe('Hash192', function () {
it('has a static width member', function () {
expect(Hash192.width).toBe(24)
})
it('has a ZERO_192 member', function () {
expect(Hash192.ZERO_192.toJSON()).toBe(
'000000000000000000000000000000000000000000000000',
)
})
it('can be compared against another', function () {
const h1 = Hash192.from('100000000000000000000000000000000000000000000000')
const h2 = Hash192.from('200000000000000000000000000000000000000000000000')
const h3 = Hash192.from('000000000000000000000000000000000000000000000003')
expect(h1.lt(h2)).toBe(true)
expect(h3.lt(h2)).toBe(true)
})
it('throws when constructed from invalid hash length', () => {
expect(() =>
Hash192.from('10000000000000000000000000000000000000000000000'),
).toThrow(new Error('Invalid Hash length 23'))
expect(() =>
Hash192.from('10000000000000000000000000000000000000000000000000'),
).toThrow(new Error('Invalid Hash length 25'))
})
})
describe('Hash256', function () {
it('has a static width member', function () {
expect(Hash256.width).toBe(32)

View File

@@ -1,5 +1,5 @@
import { UInt8, UInt64 } from '../src/types'
import { encode } from '../src'
import { encode, decode } from '../src'
const binary =
'11007222000300003700000000000000003800000000000000006280000000000000000000000000000000000000005553440000000000000000000000000000000000000000000000000166D5438D7EA4C680000000000000000000000000005553440000000000AE123A8556F3CF91154711376AFB0F894F832B3D67D5438D7EA4C680000000000000000000000000005553440000000000F51DFC2A09D62CBBA1DFBDD4691DAC96AD98B90F'
@@ -96,6 +96,40 @@ const jsonEntry2 = {
index: '0000041EFD027808D3F78C8352F97E324CB816318E00B977C74ECDDC7CD975B2',
}
const mptIssuanceEntryBinary =
'11007E220000006224000002DF25000002E434000000000000000030187FFFFFFFFFFFFFFF30190000000000000064552E78C1FFBDDAEE077253CEB12CFEA83689AA0899F94762190A357208DADC76FE701EC1EC7B226E616D65223A2255532054726561737572792042696C6C20546F6B656E222C2273796D626F6C223A225553544254222C22646563696D616C73223A322C22746F74616C537570706C79223A313030303030302C22697373756572223A225553205472656173757279222C22697373756544617465223A22323032342D30332D3235222C226D6174757269747944617465223A22323032352D30332D3235222C226661636556616C7565223A2231303030222C22696E74657265737452617465223A22322E35222C22696E7465726573744672657175656E6379223A22517561727465726C79222C22636F6C6C61746572616C223A22555320476F7665726E6D656E74222C226A7572697364696374696F6E223A22556E6974656420537461746573222C22726567756C61746F7279436F6D706C69616E6365223A2253454320526567756C6174696F6E73222C22736563757269747954797065223A2254726561737572792042696C6C222C2265787465726E616C5F75726C223A2268747470733A2F2F6578616D706C652E636F6D2F742D62696C6C2D746F6B656E2D6D657461646174612E6A736F6E227D8414A4D893CFBC4DC6AE877EB585F90A3B47528B958D051003'
const mptIssuanceEntryJson = {
AssetScale: 3,
Flags: 98,
Issuer: 'rGpdGXDV2RFPeLEfWS9RFo5Nh9cpVDToZa',
LedgerEntryType: 'MPTokenIssuance',
MPTokenMetadata:
'7B226E616D65223A2255532054726561737572792042696C6C20546F6B656E222C2273796D626F6C223A225553544254222C22646563696D616C73223A322C22746F74616C537570706C79223A313030303030302C22697373756572223A225553205472656173757279222C22697373756544617465223A22323032342D30332D3235222C226D6174757269747944617465223A22323032352D30332D3235222C226661636556616C7565223A2231303030222C22696E74657265737452617465223A22322E35222C22696E7465726573744672657175656E6379223A22517561727465726C79222C22636F6C6C61746572616C223A22555320476F7665726E6D656E74222C226A7572697364696374696F6E223A22556E6974656420537461746573222C22726567756C61746F7279436F6D706C69616E6365223A2253454320526567756C6174696F6E73222C22736563757269747954797065223A2254726561737572792042696C6C222C2265787465726E616C5F75726C223A2268747470733A2F2F6578616D706C652E636F6D2F742D62696C6C2D746F6B656E2D6D657461646174612E6A736F6E227D',
MaximumAmount: '9223372036854775807',
OutstandingAmount: '100',
OwnerNode: '0000000000000000',
PreviousTxnID:
'2E78C1FFBDDAEE077253CEB12CFEA83689AA0899F94762190A357208DADC76FE',
PreviousTxnLgrSeq: 740,
Sequence: 735,
}
const mptokenEntryJson = {
Account: 'raDQsd1s8rqGjL476g59a9vVNi1rSwrC44',
Flags: 0,
LedgerEntryType: 'MPToken',
MPTAmount: '100',
MPTokenIssuanceID: '000002DF71CAE59C9B7E56587FFF74D4EA5830D9BE3CE0CC',
OwnerNode: '0000000000000000',
PreviousTxnID:
'222EF3C7E82D8A44984A66E2B8E357CB536EC2547359CCF70E56E14BC4C284C8',
PreviousTxnLgrSeq: 741,
}
const mptokenEntryBinary =
'11007F220000000025000002E5340000000000000000301A000000000000006455222EF3C7E82D8A44984A66E2B8E357CB536EC2547359CCF70E56E14BC4C284C881143930DB9A74C26D96CB58ADFFD7E8BB78BCFE62340115000002DF71CAE59C9B7E56587FFF74D4EA5830D9BE3CE0CC'
it('compareToTests[0]', () => {
expect(UInt8.from(124).compareTo(UInt64.from(124))).toBe(0)
})
@@ -144,3 +178,20 @@ it('valueOf tests', () => {
expect(val.valueOf() | 0x2).toBe(3)
})
it('UInt64 is parsed as base 10 for MPT amounts', () => {
expect(encode(mptIssuanceEntryJson)).toEqual(mptIssuanceEntryBinary)
expect(decode(mptIssuanceEntryBinary)).toEqual(mptIssuanceEntryJson)
expect(encode(mptokenEntryJson)).toEqual(mptokenEntryBinary)
expect(decode(mptokenEntryBinary)).toEqual(mptokenEntryJson)
const decodedIssuance = decode(mptIssuanceEntryBinary)
expect(typeof decodedIssuance.MaximumAmount).toBe('string')
expect(decodedIssuance.MaximumAmount).toBe('9223372036854775807')
expect(decodedIssuance.OutstandingAmount).toBe('100')
const decodedToken = decode(mptokenEntryBinary)
expect(typeof decodedToken.MPTAmount).toBe('string')
expect(decodedToken.MPTAmount).toBe('100')
})