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

Support alt. native assets #2596

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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: 2 additions & 0 deletions packages/ripple-binary-codec/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
} from './enums'
import { XrplDefinitions } from './enums/xrpl-definitions'
import { coreTypes } from './types'
import { nativeAsset } from './nativeasset'

const {
signingData,
Expand Down Expand Up @@ -138,4 +139,5 @@ export {
XrplDefinitionsBase,
DEFAULT_DEFINITIONS,
coreTypes,
nativeAsset,
}
19 changes: 19 additions & 0 deletions packages/ripple-binary-codec/src/nativeasset.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
class NativeAsset {
private nativeAsset = 'XRP'

constructor() {
//
}

set(asset: string): void {
this.nativeAsset = asset.trim().toUpperCase()
}

get(): string {
return this.nativeAsset
}
}

const nativeAsset = new NativeAsset()

export { nativeAsset }
20 changes: 10 additions & 10 deletions packages/ripple-binary-codec/src/types/amount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const MIN_IOU_EXPONENT = -96
const MAX_IOU_EXPONENT = 80
const MAX_IOU_PRECISION = 16
const MAX_DROPS = new Decimal('1e17')
const MIN_XRP = new Decimal('1e-6')
const MIN_NATIVE_ASSET = new Decimal('1e-6')
const mask = bigInt(0x00000000ffffffff)

/**
Expand Down Expand Up @@ -74,7 +74,7 @@ class Amount extends SerializedType {

let amount = Buffer.alloc(8)
if (typeof value === 'string') {
Amount.assertXrpIsValid(value)
Amount.assertNativeAssetIsValid(value)

const number = bigInt(value)

Expand Down Expand Up @@ -135,8 +135,8 @@ class Amount extends SerializedType {
* @returns An Amount object
*/
static fromParser(parser: BinaryParser): Amount {
const isXRP = parser.peek() & 0x80
const numBytes = isXRP ? 48 : 8
const isNativeAsset = parser.peek() & 0x80
const numBytes = isNativeAsset ? 48 : 8
return new Amount(parser.read(numBytes))
}

Expand Down Expand Up @@ -186,19 +186,19 @@ class Amount extends SerializedType {
}

/**
* Validate XRP amount
* Validate Native Asset amount
*
* @param amount String representing XRP amount
* @param amount String representing Native Asset amount
* @returns void, but will throw if invalid amount
*/
private static assertXrpIsValid(amount: string): void {
private static assertNativeAssetIsValid(amount: string): void {
if (amount.indexOf('.') !== -1) {
throw new Error(`${amount.toString()} is an illegal amount`)
}

const decimal = new Decimal(amount)
if (!decimal.isZero()) {
if (decimal.lt(MIN_XRP) || decimal.gt(MAX_DROPS)) {
if (decimal.lt(MIN_NATIVE_ASSET) || decimal.gt(MAX_DROPS)) {
throw new Error(`${amount.toString()} is an illegal amount`)
}
}
Expand Down Expand Up @@ -244,9 +244,9 @@ class Amount extends SerializedType {
}

/**
* Test if this amount is in units of Native Currency(XRP)
* Test if this amount is in units of Native Currency(Native Asset)
*
* @returns true if Native (XRP)
* @returns true if Native (Native Asset)
*/
private isNative(): boolean {
return (this.bytes[0] & 0x80) === 0
Expand Down
15 changes: 8 additions & 7 deletions packages/ripple-binary-codec/src/types/currency.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Hash160 } from './hash-160'
import { Buffer } from 'buffer/'
import { nativeAsset } from '../nativeasset'

const XRP_HEX_REGEX = /^0{40}$/
const NATIVE_ASSET_HEX_REGEX = /^0{40}$/
const ISO_REGEX = /^[A-Z0-9a-z?!@#$%^&*(){}[\]|]{3}$/
const HEX_REGEX = /^[A-F0-9]{40}$/
// eslint-disable-next-line no-control-regex
Expand All @@ -12,7 +13,7 @@ const STANDARD_FORMAT_HEX_REGEX = /^0{24}[\x00-\x7F]{6}0{10}$/
*/
function isoToBytes(iso: string): Buffer {
const bytes = Buffer.alloc(20)
if (iso !== 'XRP') {
if (iso !== nativeAsset.get()) {
const isoBytes = iso.split('').map((c) => c.charCodeAt(0))
bytes.set(isoBytes, 12)
}
Expand All @@ -28,7 +29,7 @@ function isIsoCode(iso: string): boolean {

function isoCodeFromHex(code: Buffer): string | null {
const iso = code.toString()
if (iso === 'XRP') {
if (iso === nativeAsset.get()) {
return null
}
if (isIsoCode(iso)) {
Expand Down Expand Up @@ -81,15 +82,15 @@ function bytesFromRepresentation(input: string): Buffer {
* Class defining how to encode and decode Currencies
*/
class Currency extends Hash160 {
static readonly XRP = new Currency(Buffer.alloc(20))
static readonly NATIVE_ASSET = new Currency(Buffer.alloc(20))
private readonly _iso: string | null

constructor(byteBuf: Buffer) {
super(byteBuf ?? Currency.XRP.bytes)
super(byteBuf ?? Currency.NATIVE_ASSET.bytes)
const hex = this.bytes.toString('hex')

if (XRP_HEX_REGEX.test(hex)) {
this._iso = 'XRP'
if (NATIVE_ASSET_HEX_REGEX.test(hex)) {
this._iso = nativeAsset.get()
} else if (STANDARD_FORMAT_HEX_REGEX.test(hex)) {
this._iso = isoCodeFromHex(this.bytes.slice(12, 15))
} else {
Expand Down
6 changes: 4 additions & 2 deletions packages/ripple-binary-codec/src/types/issue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { Currency } from './currency'
import { JsonObject, SerializedType } from './serialized-type'
import { Buffer } from 'buffer/'

import { nativeAsset } from '../nativeasset'

/**
* Interface for JSON objects that represent amounts
*/
Expand Down Expand Up @@ -66,7 +68,7 @@ class Issue extends SerializedType {
*/
static fromParser(parser: BinaryParser): Issue {
const currency = parser.read(20)
if (new Currency(currency).toJSON() === 'XRP') {
if (new Currency(currency).toJSON() === nativeAsset.get()) {
return new Issue(currency)
}
const currencyAndIssuer = [currency, parser.read(20)]
Expand All @@ -81,7 +83,7 @@ class Issue extends SerializedType {
toJSON(): IssueObject {
const parser = new BinaryParser(this.toString())
const currency = Currency.fromParser(parser) as Currency
if (currency.toJSON() === 'XRP') {
if (currency.toJSON() === nativeAsset.get()) {
return { currency: currency.toJSON() }
}
const issuer = AccountID.fromParser(parser) as AccountID
Expand Down
53 changes: 53 additions & 0 deletions packages/ripple-binary-codec/test/native-asset.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
const { encode } = require('./../src/index')
const { nativeAsset } = require('./../src/nativeasset')

const baseTxXrp = {
TransactionType: 'TrustSet',
Account: 'ra5nK24KXen9AHvsdFTKHSANinZseWnPcX',
LimitAmount: {
currency: 'XRP',
issuer: 'rsP3mgGb2tcYUrxiLFiHJiQXhsziegtwBc',
value: '100',
},
}

const baseTxXah = {
TransactionType: 'TrustSet',
Account: 'ra5nK24KXen9AHvsdFTKHSANinZseWnPcX',
LimitAmount: {
currency: 'XAH',
issuer: 'rsP3mgGb2tcYUrxiLFiHJiQXhsziegtwBc',
value: '100',
},
}

describe('XRP Native asset', function () {
it('XRP as native to be native', function () {
nativeAsset.set('XRP')

expect(encode(baseTxXrp).slice(24, 64)).toEqual(
'0000000000000000000000000000000000000000',
)
})
it('XRP as non-native to be non-native', function () {
nativeAsset.set('XAH')

expect(encode(baseTxXrp).slice(24, 64)).toEqual(
'0000000000000000000000005852500000000000',
)
})
it('XAH as native to be native', function () {
nativeAsset.set('XAH')

expect(encode(baseTxXah).slice(24, 64)).toEqual(
'0000000000000000000000000000000000000000',
)
})
it('XAH as non-native to be non-native', function () {
nativeAsset.set('XRP')

expect(encode(baseTxXah).slice(24, 64)).toEqual(
'0000000000000000000000005841480000000000',
)
})
})