Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mpt base10 #1

Merged
merged 3 commits into from
Oct 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/ripple-binary-codec/src/types/serialized-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class SerializedType {
* Can be customized for sidechains and amendments.
* @returns any type, if not overloaded returns hexString representation of bytes
*/
toJSON(_definitions?: XrplDefinitionsBase): JSON {
toJSON(_definitions?: XrplDefinitionsBase, _fieldName?: string): JSON {
return this.toHex()
}

Expand Down
11 changes: 9 additions & 2 deletions packages/ripple-binary-codec/src/types/st-object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { BinaryParser } from '../serdes/binary-parser'
import { BinarySerializer, BytesList } from '../serdes/binary-serializer'

import { STArray } from './st-array'
import { UInt64 } from './uint-64'

const OBJECT_END_MARKER_BYTE = Uint8Array.from([0xe1])
const OBJECT_END_MARKER = 'ObjectEndMarker'
Expand Down Expand Up @@ -137,6 +138,8 @@ class STObject extends SerializedType {
? this.from(xAddressDecoded[field.name], undefined, definitions)
: field.type.name === 'STArray'
? STArray.from(xAddressDecoded[field.name], definitions)
: field.type.name === 'UInt64'
? UInt64.from(xAddressDecoded[field.name], field.name)
: field.associatedType.from(xAddressDecoded[field.name])

if (associatedValue == undefined) {
Expand All @@ -155,7 +158,11 @@ class STObject extends SerializedType {
// Account field
// The Account field must not be a part of the UNLModify pseudotransaction encoding, due to a bug in rippled
const isUnlModifyWorkaround = field.name == 'Account' && isUnlModify
bytes.writeFieldAndValue(field, associatedValue, isUnlModifyWorkaround)
bytes.writeFieldAndValue(
field,
associatedValue as SerializedType,
isUnlModifyWorkaround,
)
if (field.type.name === ST_OBJECT) {
bytes.put(OBJECT_END_MARKER_BYTE)
}
Expand All @@ -182,7 +189,7 @@ class STObject extends SerializedType {

accumulator[field.name] = objectParser
.readFieldValue(field)
.toJSON(definitions)
.toJSON(definitions, field.name)
}

return accumulator
Expand Down
40 changes: 35 additions & 5 deletions packages/ripple-binary-codec/src/types/uint-64.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import { UInt } from './uint'
import { BinaryParser } from '../serdes/binary-parser'
import { bytesToHex, concat, hexToBytes } from '@xrplf/isomorphic/utils'
import { readUInt32BE, writeUInt32BE } from '../utils'
import { DEFAULT_DEFINITIONS, XrplDefinitionsBase } from '../enums'

const HEX_REGEX = /^[a-fA-F0-9]{1,16}$/
const BASE10_REGEX = /^[0-9]{1,20}$/
const mask = BigInt(0x00000000ffffffff)

/**
Expand All @@ -29,7 +31,10 @@ class UInt64 extends UInt {
* @param val A UInt64, hex-string, bigInt, or number
* @returns A UInt64 object
*/
static from<T extends UInt64 | string | bigint | number>(val: T): UInt64 {
static from<T extends UInt64 | string | bigint | number>(
val: T,
fieldName: string = '',
): UInt64 {
if (val instanceof UInt64) {
return val
}
Expand All @@ -51,11 +56,23 @@ class UInt64 extends UInt {
}

if (typeof val === 'string') {
if (!HEX_REGEX.test(val)) {
if (
fieldName == 'MaximumAmount' ||
fieldName == 'OutstandingAmount' ||
fieldName == 'LockedAmount' ||
fieldName == 'MPTAmount'
) {
if (!BASE10_REGEX.test(val)) {
throw new Error(`${fieldName} ${val} is not a valid base 10 string`)
}
val = BigInt(val).toString(16) as T
}

if (typeof val === 'string' && !HEX_REGEX.test(val)) {
throw new Error(`${val} is not a valid hex-string`)
}

const strBuf = val.padStart(16, '0')
const strBuf = (val as string).padStart(16, '0')
buf = hexToBytes(strBuf)
return new UInt64(buf)
}
Expand All @@ -76,8 +93,21 @@ class UInt64 extends UInt {
*
* @returns a hex-string
*/
toJSON(): string {
return bytesToHex(this.bytes)
toJSON(
_definitions: XrplDefinitionsBase = DEFAULT_DEFINITIONS,
fieldName: string = '',
): string {
const hexString = bytesToHex(this.bytes)
if (
fieldName == 'MaximumAmount' ||
fieldName == 'OutstandingAmount' ||
fieldName == 'LockedAmount' ||
fieldName == 'MPTAmount'
) {
return BigInt('0x' + hexString).toString(10)
}

return hexString
}

/**
Expand Down
44 changes: 43 additions & 1 deletion packages/ripple-binary-codec/test/uint.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { UInt8, UInt64 } from '../src/types'
import { encode } from '../src'
import { encode, decode } from '../src'

const binary =
'11007222000300003700000000000000003800000000000000006280000000000000000000000000000000000000005553440000000000000000000000000000000000000000000000000166D5438D7EA4C680000000000000000000000000005553440000000000AE123A8556F3CF91154711376AFB0F894F832B3D67D5438D7EA4C680000000000000000000000000005553440000000000F51DFC2A09D62CBBA1DFBDD4691DAC96AD98B90F'
Expand Down Expand Up @@ -96,6 +96,40 @@ const jsonEntry2 = {
index: '0000041EFD027808D3F78C8352F97E324CB816318E00B977C74ECDDC7CD975B2',
}

const mptIssuanceEntryBinary =
'11007E22000000222400000333250000033934000000000000000030187FFFFFFFFFFFFFFF3019000000000000006455854FCC08F5C602AEAF4F577316248BECCBEC82310B30DC66E1438E07F86E6E7D701EC1EC7B226E616D65223A2255532054726561737572792042696C6C20546F6B656E222C2273796D626F6C223A225553544254222C22646563696D616C73223A322C22746F74616C537570706C79223A313030303030302C22697373756572223A225553205472656173757279222C22697373756544617465223A22323032342D30332D3235222C226D6174757269747944617465223A22323032352D30332D3235222C226661636556616C7565223A2231303030222C22696E74657265737452617465223A22322E35222C22696E7465726573744672657175656E6379223A22517561727465726C79222C22636F6C6C61746572616C223A22555320476F7665726E6D656E74222C226A7572697364696374696F6E223A22556E6974656420537461746573222C22726567756C61746F7279436F6D706C69616E6365223A2253454320526567756C6174696F6E73222C22736563757269747954797065223A2254726561737572792042696C6C222C2265787465726E616C5F75726C223A2268747470733A2F2F6578616D706C652E636F6D2F742D62696C6C2D746F6B656E2D6D657461646174612E6A736F6E227D8414F52140C352B66DC5507C7C0236F7241469E56C1300101403'

const mptIssuanceEntryJson = {
AssetScale: 3,
Flags: 34,
Issuer: 'rPM3PTTfpJVjEcb3aSoZGizLbVBz2B7LQF',
LedgerEntryType: 'MPTokenIssuance',
MPTokenMetadata:
'7B226E616D65223A2255532054726561737572792042696C6C20546F6B656E222C2273796D626F6C223A225553544254222C22646563696D616C73223A322C22746F74616C537570706C79223A313030303030302C22697373756572223A225553205472656173757279222C22697373756544617465223A22323032342D30332D3235222C226D6174757269747944617465223A22323032352D30332D3235222C226661636556616C7565223A2231303030222C22696E74657265737452617465223A22322E35222C22696E7465726573744672657175656E6379223A22517561727465726C79222C22636F6C6C61746572616C223A22555320476F7665726E6D656E74222C226A7572697364696374696F6E223A22556E6974656420537461746573222C22726567756C61746F7279436F6D706C69616E6365223A2253454320526567756C6174696F6E73222C22736563757269747954797065223A2254726561737572792042696C6C222C2265787465726E616C5F75726C223A2268747470733A2F2F6578616D706C652E636F6D2F742D62696C6C2D746F6B656E2D6D657461646174612E6A736F6E227D',
MaximumAmount: '9223372036854775807',
OutstandingAmount: '100',
OwnerNode: '0000000000000000',
PreviousTxnID:
'854FCC08F5C602AEAF4F577316248BECCBEC82310B30DC66E1438E07F86E6E7D',
PreviousTxnLgrSeq: 825,
Sequence: 819,
}

const mptokenEntryJson = {
Account: 'rhWhvQ4kMaYB9sX25S13PYGJnF1H1pAmRp',
Flags: 0,
LedgerEntryType: 'MPToken',
MPTAmount: '100',
MPTokenIssuanceID: '0000032A0BEB4029FD60F77F484D8D16C2505E861DB5394B',
OwnerNode: '0000000000000000',
PreviousTxnID:
'FB4131A4FE8EE2E0A48C7BB668980DD975F529EABF55C190F3F1867469534669',
PreviousTxnLgrSeq: 816,
}

const mptokenEntryBinary =
'11007F22000000002500000330340000000000000000301B000000000000006455FB4131A4FE8EE2E0A48C7BB668980DD975F529EABF55C190F3F186746953466981142667B68E9BEA7242611581F0EB4630F2E844226901150000032A0BEB4029FD60F77F484D8D16C2505E861DB5394B'

it('compareToTests[0]', () => {
expect(UInt8.from(124).compareTo(UInt64.from(124))).toBe(0)
})
Expand Down Expand Up @@ -144,3 +178,11 @@ 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)
})
24 changes: 17 additions & 7 deletions packages/xrpl/src/models/transactions/MPTokenIssuanceCreate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { isHex } from '../utils'
import { BaseTransaction, GlobalFlags, validateBaseTransaction } from './common'
import type { TransactionMetadataBase } from './metadata'

const SANITY_CHECK = /^[0-9]+$/u

/**
* Transaction Flags for an MPTokenIssuanceCreate Transaction.
*
Expand Down Expand Up @@ -75,17 +77,13 @@ export interface MPTokenIssuanceCreate extends BaseTransaction {
*/
AssetScale?: number
/**
* Specifies the hex-encoded maximum asset amount of this token that should ever be issued.
* Specifies the maximum asset amount of this token that should ever be issued.
* It is a non-negative integer that can store a range of up to 63 bits. If not set, the max
* amount will default to the largest unsigned 63-bit integer (0x7FFFFFFFFFFFFFFF)
*
* Helper function `mptUint64ToHex` can be used to help converting from base 10 or 16 string
* to a valid value.
* amount will default to the largest unsigned 63-bit integer (0x7FFFFFFFFFFFFFFF or 9223372036854775807)
*
* Example:
* ```
* MaximumAmount: '3e8' // 0x3E8 in hex or 1000 in decimal
* MaximumAmount: mptUint64ToHex('1000') // 1000 in decimal using helper function
* MaximumAmount: '9223372036854775807'
* ```
*/
MaximumAmount?: string
Expand Down Expand Up @@ -129,4 +127,16 @@ export function validateMPTokenIssuanceCreate(
'MPTokenIssuanceCreate: MPTokenMetadata must be in hex format',
)
}

if (typeof tx.MaximumAmount === 'string') {
if (!SANITY_CHECK.exec(tx.MaximumAmount))
throw new ValidationError('MPTokenIssuanceCreate: Invalid MaximumAmount')
else if (
BigInt(tx.MaximumAmount) > BigInt(`9223372036854775807`) ||
BigInt(tx.MaximumAmount) < BigInt(`0`)
)
throw new ValidationError(
'MPTokenIssuanceCreate: MaximumAmount out of range',
)
}
}
2 changes: 0 additions & 2 deletions packages/xrpl/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ import {
} from './timeConversion'
import verifyPaymentChannelClaim from './verifyPaymentChannelClaim'
import { xrpToDrops, dropsToXrp } from './xrpConversion'
import { mptUint64ToHex } from './mptConversion'

/**
* Check if a secret is valid.
Expand Down Expand Up @@ -230,5 +229,4 @@ export {
getNFTokenID,
parseNFTokenID,
getXChainClaimID,
mptUint64ToHex,
}
61 changes: 0 additions & 61 deletions packages/xrpl/src/utils/mptConversion.ts

This file was deleted.

4 changes: 2 additions & 2 deletions packages/xrpl/test/integration/transactions/clawback.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ describe('Clawback', function () {
assert.equal(
// @ts-ignore
ledgerEntryResponse.result.node.MPTAmount,
'7fffffffffffffff',
'9223372036854775807',
)

// actual test - clawback
Expand All @@ -200,7 +200,7 @@ describe('Clawback', function () {
assert.equal(
// @ts-ignore
ledgerEntryResponse.result.node.MPTAmount,
'7ffffffffffffe0b',
'9223372036854775307',
)
},
TIMEOUT,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
type XrplIntegrationTestContext,
} from '../setup'
import { testTransaction } from '../utils'
import { mptUint64ToHex } from '../../../src/utils'

// how long before each test case times out
const TIMEOUT = 20000
Expand All @@ -27,7 +26,7 @@ describe('MPTokenIssuanceCreate', function () {
const tx: MPTokenIssuanceCreate = {
TransactionType: 'MPTokenIssuanceCreate',
Account: testContext.wallet.classicAddress,
MaximumAmount: mptUint64ToHex('9223372036854775807'), // 0x7fffffffffffffff
MaximumAmount: '9223372036854775807', // 0x7fffffffffffffff
AssetScale: 2,
}

Expand All @@ -43,6 +42,11 @@ describe('MPTokenIssuanceCreate', function () {
1,
'Should be exactly one issuance on the ledger',
)
assert.equal(
// @ts-ignore
accountObjectsResponse.result.account_objects[0].MaximumAmount,
`9223372036854775807`,
)
},
TIMEOUT,
)
Expand Down
11 changes: 11 additions & 0 deletions packages/xrpl/test/integration/transactions/payment.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,17 @@ describe('Payment', function () {
}

await testTransaction(testContext.client, payTx, testContext.wallet)

accountObjectsResponse = await testContext.client.request({
command: 'account_objects',
account: testContext.wallet.classicAddress,
type: 'mpt_issuance',
})
assert.equal(
// @ts-ignore
accountObjectsResponse.result.account_objects[0].OutstandingAmount,
`100`,
)
},
TIMEOUT,
)
Expand Down
Loading
Loading