Last active
November 30, 2023 10:17
-
-
Save N3TC4T/a20fb528931ed009ebdd708be4938748 to your computer and use it in GitHub Desktop.
Calculate NFToken ID from transaction
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const { decodeAccountID } = require('ripple-address-codec'); | |
const BigNumber = require('bignumber.js'); | |
const getTokenID = (transaction) => { | |
const { Account, Issuer, NFTokenTaxon, TransferFee, Flags, meta } = transaction || {}; | |
// Validate transaction input data | |
if (!Account || !Issuer || !NFTokenTaxon || !TransferFee || !Flags) { | |
throw new Error('Invalid transaction data.'); | |
} | |
// Validate meta data | |
if (typeof meta !== 'object' || !Array.isArray(meta.AffectedNodes)) { | |
throw new Error('Invalid meta data.'); | |
} | |
// fixNFTokenRemint amendment will include the minted nfTokenId in the metaData | |
// Amendment: AE35ABDEFBDE520372B31C957020B34A7A4A9DC3115A69803A44016477C84D6E | |
// Check if 'nftoken_id' presence in meta | |
if (Object.prototype.hasOwnProperty.call(meta, 'nftoken_id')) { | |
return meta.nftoken_id; | |
} | |
// Fetch minted token sequence | |
let TokenSequence; | |
let NextTokenSequence; | |
let FirstNFTokenSequence; | |
meta.AffectedNodes.forEach((node) => { | |
if (node.ModifiedNode && node.ModifiedNode.LedgerEntryType === 'AccountRoot') { | |
const { PreviousFields, FinalFields } = node.ModifiedNode; | |
if (PreviousFields && FinalFields && FinalFields.Account === (Issuer || Account)) { | |
TokenSequence = PreviousFields.MintedNFTokens; | |
NextTokenSequence = FinalFields.MintedNFTokens; | |
FirstNFTokenSequence = PreviousFields.FirstNFTokenSequence || FinalFields.FirstNFTokenSequence; | |
} | |
} | |
}); | |
// First minted token, set token sequence to zero | |
if (typeof TokenSequence === 'undefined' && NextTokenSequence === 1) { | |
TokenSequence = 0; | |
} | |
// Include first NFToken Sequence, introduced in `fixNFTokenRemint` | |
TokenSequence += FirstNFTokenSequence ?? 0; | |
// Decode account id | |
const DecodedIssuerID = decodeAccountID(Issuer || Account); | |
// Using BigNumber.js guarantees that we are getting correct result when TokenSequence value is big | |
const UnscrambleTaxon = new BigNumber(384160001) | |
.multipliedBy(TokenSequence) | |
.modulo(4294967296) | |
.plus(2459) | |
.modulo(4294967296) | |
.toNumber(); | |
// Calculate ciphered taxon | |
const CipheredTaxon = (NFTokenTaxon ^ UnscrambleTaxon) >>> 0; | |
const TokenID = Buffer.concat([ | |
Buffer.from([(Flags >> 8) & 0xff, Flags & 0xff]), | |
Buffer.from([(TransferFee >> 8) & 0xff, TransferFee & 0xff]), | |
DecodedIssuerID, | |
Buffer.from([ | |
(CipheredTaxon >> 24) & 0xff, | |
(CipheredTaxon >> 16) & 0xff, | |
(CipheredTaxon >> 8) & 0xff, | |
CipheredTaxon & 0xff, | |
]), | |
Buffer.from([ | |
(TokenSequence >> 24) & 0xff, | |
(TokenSequence >> 16) & 0xff, | |
(TokenSequence >> 8) & 0xff, | |
TokenSequence & 0xff, | |
]), | |
]); | |
// should be 32 bytes | |
if (TokenID.length !== 32) { | |
throw new Error(`Calculated TokenID have unexpected length, expected 32, received ${TokenID.length}`); | |
} | |
return TokenID.toString('hex').toUpperCase(); | |
}; | |
const tokenID = getTokenID(transaction); | |
console.log(tokenID); |
Thank god someone is here to help us!! Thanks for publishing this mate and making it public.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@N3TC4T
Voting is reaching go-live on this amendment:
https://xrpl.org/known-amendments.html#fixnftokenremint
And since we use the sequence (minted tokens) here:
https://gist.github.com/N3TC4T/a20fb528931ed009ebdd708be4938748
To compute NFT, this amendment would change this calculation as that field from accountroot becomes part of the NFT sequence.
Changes required to make this compatible with the new amendment (and keep it backwards compatible):
This is backwards compatible because it will do nothing if the AccountRoot didn't have, and didn't get, the new
FirstNFTokenSequence
field.If the field was there or has been created, it adds the value to the
TokenSequence
as per new behaviour past activation of the amendment: https://xrpl.org/known-amendments.html#fixnftokenremintAdd (on top)
Add (in AccountRoot fields condition)
After the TokenSequence = 0 fallback: