mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-12-06 17:27:59 +00:00
Add parseNFTokenID and tests (#1961)
* Add parseNFTokenID and tests * Lint * Move parseNFTokenID to utils * Lint * Move the NFTokenID into models * Move NFTokenID type out of models * Lint * Remove extra type and lint
This commit is contained in:
@@ -6,6 +6,7 @@ Subscribe to [the **xrpl-announce** mailing list](https://groups.google.com/g/xr
|
|||||||
### Added
|
### Added
|
||||||
* `federator_info` RPC support
|
* `federator_info` RPC support
|
||||||
* Helper method for creating a cross-chain payment to/from a sidechain
|
* Helper method for creating a cross-chain payment to/from a sidechain
|
||||||
|
* Helper method for parsing an NFTokenID
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
* Type of TrustSet transaction edited, specifically LimitAmount property type (fixed typescript issue)
|
* Type of TrustSet transaction edited, specifically LimitAmount property type (fixed typescript issue)
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import {
|
|||||||
hashEscrow,
|
hashEscrow,
|
||||||
hashPaymentChannel,
|
hashPaymentChannel,
|
||||||
} from './hashes'
|
} from './hashes'
|
||||||
|
import parseNFTokenID from './parseNFTokenID'
|
||||||
import {
|
import {
|
||||||
percentToTransferRate,
|
percentToTransferRate,
|
||||||
decimalToTransferRate,
|
decimalToTransferRate,
|
||||||
@@ -215,4 +216,5 @@ export {
|
|||||||
encodeForSigning,
|
encodeForSigning,
|
||||||
encodeForSigningClaim,
|
encodeForSigningClaim,
|
||||||
createCrossChainPayment,
|
createCrossChainPayment,
|
||||||
|
parseNFTokenID,
|
||||||
}
|
}
|
||||||
|
|||||||
81
packages/xrpl/src/utils/parseNFTokenID.ts
Normal file
81
packages/xrpl/src/utils/parseNFTokenID.ts
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-magic-numbers -- Doing hex string parsing. */
|
||||||
|
import BigNumber from 'bignumber.js'
|
||||||
|
import { encodeAccountID } from 'ripple-address-codec'
|
||||||
|
|
||||||
|
import { XrplError } from '../errors'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An issuer may issue several NFTs with the same taxon; to ensure that NFTs are
|
||||||
|
* spread across multiple pages we lightly mix the taxon up by using the sequence
|
||||||
|
* (which is not under the issuer's direct control) as the seed for a simple linear
|
||||||
|
* congruential generator.
|
||||||
|
*
|
||||||
|
* From the Hull-Dobell theorem we know that f(x)=(m*x+c) mod n will yield a
|
||||||
|
* permutation of [0, n) when n is a power of 2 if m is congruent to 1 mod 4 and
|
||||||
|
* c is odd. By doing a bitwise XOR with this permutation we can scramble/unscramble
|
||||||
|
* the taxon.
|
||||||
|
*
|
||||||
|
* The XLS-20d proposal fixes m = 384160001 and c = 2459.
|
||||||
|
* We then take the modulus of 2^32 which is 4294967296.
|
||||||
|
*
|
||||||
|
* @param taxon - The scrambled or unscrambled taxon (The XOR is both the encoding and decoding)
|
||||||
|
* @param tokenSeq - The account sequence when the token was minted. Used as a psuedorandom seed.
|
||||||
|
* @returns the opposite taxon. If the taxon was scrambled it becomes unscrambled, and vice versa.
|
||||||
|
*/
|
||||||
|
function unscrambleTaxon(taxon: number, tokenSeq: number): number {
|
||||||
|
/* eslint-disable no-bitwise -- XOR is part of the encode/decode scheme. */
|
||||||
|
return (taxon ^ (384160001 * tokenSeq + 2459)) % 4294967296
|
||||||
|
/* eslint-enable no-bitwise */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses an NFTokenID into the information it is encoding.
|
||||||
|
*
|
||||||
|
* Example decoding:
|
||||||
|
*
|
||||||
|
* 000B 0539 C35B55AA096BA6D87A6E6C965A6534150DC56E5E 12C5D09E 0000000C
|
||||||
|
* +--- +--- +--------------------------------------- +------- +-------
|
||||||
|
* | | | | |
|
||||||
|
* | | | | `---> Sequence: 12
|
||||||
|
* | | | |
|
||||||
|
* | | | `---> Scrambled Taxon: 314,953,886
|
||||||
|
* | | | Unscrambled Taxon: 1337
|
||||||
|
* | | |
|
||||||
|
* | | `---> Issuer: rJoxBSzpXhPtAuqFmqxQtGKjA13jUJWthE
|
||||||
|
* | |
|
||||||
|
* | `---> TransferFee: 1337.0 bps or 13.37%
|
||||||
|
* |
|
||||||
|
* `---> Flags: 11 -> lsfBurnable, lsfOnlyXRP and lsfTransferable
|
||||||
|
*
|
||||||
|
* @param tokenID - A hex string which identifies an NFToken on the ledger.
|
||||||
|
* @throws XrplError when given an invalid tokenID.
|
||||||
|
* @returns a decoded tokenID with all fields encoded within.
|
||||||
|
*/
|
||||||
|
export default function parseNFTokenID(tokenID: string): {
|
||||||
|
TokenID: string
|
||||||
|
Flags: number
|
||||||
|
TransferFee: number
|
||||||
|
Issuer: string
|
||||||
|
Taxon: number
|
||||||
|
Sequence: number
|
||||||
|
} {
|
||||||
|
const expectedLength = 64
|
||||||
|
if (tokenID.length !== expectedLength) {
|
||||||
|
throw new XrplError(`Attempting to parse a tokenID with length ${tokenID.length}
|
||||||
|
, but expected a token with length ${expectedLength}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
const scrambledTaxon = new BigNumber(tokenID.substring(48, 56), 16).toNumber()
|
||||||
|
const sequence = new BigNumber(tokenID.substring(56, 64), 16).toNumber()
|
||||||
|
|
||||||
|
const NFTokenIDData = {
|
||||||
|
TokenID: tokenID,
|
||||||
|
Flags: new BigNumber(tokenID.substring(0, 4), 16).toNumber(),
|
||||||
|
TransferFee: new BigNumber(tokenID.substring(4, 8), 16).toNumber(),
|
||||||
|
Issuer: encodeAccountID(Buffer.from(tokenID.substring(8, 48), 'hex')),
|
||||||
|
Taxon: unscrambleTaxon(scrambledTaxon, sequence),
|
||||||
|
Sequence: sequence,
|
||||||
|
}
|
||||||
|
|
||||||
|
return NFTokenIDData
|
||||||
|
}
|
||||||
27
packages/xrpl/test/utils/parseNFTokenID.ts
Normal file
27
packages/xrpl/test/utils/parseNFTokenID.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { assert } from 'chai'
|
||||||
|
import { parseNFTokenID } from 'xrpl-local'
|
||||||
|
|
||||||
|
import { assertResultMatch } from '../testUtils'
|
||||||
|
|
||||||
|
describe('parseNFTokenID', function () {
|
||||||
|
it('decode a valid NFTokenID', function () {
|
||||||
|
const tokenID =
|
||||||
|
'000B0539C35B55AA096BA6D87A6E6C965A6534150DC56E5E12C5D09E0000000C'
|
||||||
|
const result = parseNFTokenID(tokenID)
|
||||||
|
const expected = {
|
||||||
|
TokenID: tokenID,
|
||||||
|
Flags: 11,
|
||||||
|
TransferFee: 1337,
|
||||||
|
Issuer: 'rJoxBSzpXhPtAuqFmqxQtGKjA13jUJWthE',
|
||||||
|
Taxon: 1337,
|
||||||
|
Sequence: 12,
|
||||||
|
}
|
||||||
|
assertResultMatch(result, expected)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('fail when given invalid NFTokenID', function () {
|
||||||
|
assert.throws(() => {
|
||||||
|
parseNFTokenID('ABCD')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user