import { PublicKey } from './bitcore/publickey.js'; import { PrivateKey } from './bitcore/privatekey.js'; import { Script } from './bitcore/script.js'; import { type TapNode, type TapLeaf } from './bitcore/script/taproot.js'; import { Transaction } from './bitcore/transaction/transaction.js'; import { Output } from './bitcore/transaction/output.js'; import { UnspentOutput, UnspentOutputData } from './bitcore/transaction/unspentoutput.js'; import { Address } from './bitcore/address.js'; import { Network, type NetworkName } from './bitcore/networks.js'; import type { Buffer } from 'buffer/'; /** * Standard NFT metadata structure * Compatible with OpenSea and other marketplaces */ export interface NFTMetadata { /** NFT name */ name: string; /** NFT description */ description: string; /** Image URI (IPFS CID, Arweave, or URL) */ image: string; /** Optional attributes/traits */ attributes?: NFTAttribute[]; /** Optional collection identifier */ collection?: string; /** Optional creator address */ creator?: string; /** Optional external URL */ external_url?: string; /** Optional animation URL */ animation_url?: string; /** Optional background color (hex code without #) */ background_color?: string; } /** * NFT attribute/trait */ export interface NFTAttribute { /** Trait type (e.g., "Rarity", "Color") */ trait_type: string; /** Trait value */ value: string | number; /** Optional display type */ display_type?: 'number' | 'boost_percentage' | 'boost_number' | 'date'; } /** * Collection metadata structure */ export interface NFTCollectionMetadata { /** Collection name */ name: string; /** Collection description */ description: string; /** Total supply */ totalSupply: number; /** Creator address */ creator: string; /** Optional royalty percentage (0-100) */ royalty?: number; /** Optional collection image */ image?: string; /** Optional external URL */ external_url?: string; } /** * NFT data interface (plain object representation) */ export interface NFTData { /** Taproot script locking the NFT */ script: Script; /** NFT address */ address: Address; /** Metadata hash (32 bytes, stored on-chain) */ metadataHash: Buffer; /** Full metadata (stored off-chain) */ metadata: NFTMetadata; /** NFT value in satoshis */ satoshis: number; /** Optional transaction ID if minted */ txid?: string; /** Optional output index if minted */ outputIndex?: number; /** Script tree commitment public key (required for script-path) */ commitment: PublicKey; /** Merkle root of script tree (required for script-path) */ merkleRoot: Buffer; /** Control block for script-path spending (required) */ controlBlock: Buffer; /** Script leaves with merkle paths (required for script-path) */ leaves: TapLeaf[]; } /** * NFT transfer record for provenance tracking */ export interface NFTTransfer { /** Transaction ID */ txid: string; /** Sender address (null for mint) */ from: string | null; /** Recipient address */ to: string; /** Metadata hash (must remain constant) */ metadataHash: string; /** Timestamp */ timestamp: number; /** Optional block height */ blockHeight?: number; } /** * NFT minting configuration */ export interface NFTMintConfig { /** Owner's private key */ ownerKey: PrivateKey; /** NFT metadata */ metadata: NFTMetadata; /** NFT value in satoshis (default: 1000 = 0.001 XPI) */ satoshis?: number; /** Optional collection hash */ collectionHash?: Buffer; /** Network (default: livenet) */ network?: Network | NetworkName; } /** * NFT UTXO information */ export interface NFTUtxo { /** Transaction ID */ txid: string; /** Output index */ outputIndex: number; /** Taproot script with state */ script: Script; /** NFT value in satoshis */ satoshis: number; } /** * NFT transfer configuration */ export interface NFTTransferConfig { /** Current owner's private key */ currentOwnerKey: PrivateKey; /** New owner's public key */ newOwnerKey: PublicKey; /** Current NFT UTXO */ nftUtxo: NFTUtxo; /** Metadata hash (must match UTXO) */ metadataHash: Buffer; /** Script-path spending data (required for all NFT transfers) */ scriptPathData: { /** Internal public key (before tweaking) */ internalPubKey: PublicKey; /** Merkle root of script tree */ merkleRoot: Buffer; /** Control block for script path spending */ controlBlock: Buffer; /** Script to execute (e.g., OP_CHECKSIG) */ tapScript: Script; }; /** Optional fee in satoshis */ fee?: number; } /** * NFT with script path information */ export interface NFTWithScriptPath extends NFTData { /** Commitment public key */ commitment: PublicKey; /** Merkle root of script tree */ merkleRoot: Buffer; /** Array of leaf scripts with merkle paths */ leaves: TapLeaf[]; } /** * NFT that belongs to a collection */ export interface NFTWithCollection extends NFTData { /** Collection hash identifier */ collectionHash: Buffer; } /** * NFT information extracted from script */ export interface NFTInfo { /** Commitment public key from script */ commitment: PublicKey; /** Metadata hash from state parameter */ metadataHash: Buffer; /** NFT address */ address: Address; } /** * NFT JSON serialization format */ export interface NFTObject { /** Script as hex string */ script: string; /** Address as string */ address: string; /** Metadata hash as hex string */ metadataHash: string; /** Full metadata object */ metadata: NFTMetadata; /** NFT value in satoshis */ satoshis: number; /** Optional transaction ID */ txid?: string; /** Optional output index */ outputIndex?: number; /** Commitment public key (hex) - required for script-path */ commitment: string; /** Merkle root (hex) - required for script-path */ merkleRoot: string; /** Control block (hex) - required for script-path spending */ controlBlock: string; /** Optional collection hash (hex) */ collectionHash?: string; } /** * NFT Class - Represents a Lotus NFT instance * * This class provides an object-oriented interface for working with NFTs. * It wraps NFT data and provides methods for common operations like * transferring, verifying, and updating NFT state. * * @example * ```typescript * // Create a new NFT * const nft = new NFT({ * metadata: { name: 'My NFT', description: '...', image: 'ipfs://...' }, * ownerKey: privateKey.publicKey, * satoshis: 1000, * }) * * // Transfer to new owner * const transferTx = nft.transfer(newOwnerKey, currentOwnerPrivateKey) * * // Verify metadata * const isValid = nft.verifyMetadata() * ``` */ export declare class NFT { private _script; private _address; private _metadataHash; private _metadata; private _satoshis; private _txid?; private _outputIndex?; private _commitment?; private _merkleRoot?; private _controlBlock?; private _leaves?; private _collectionHash?; /** * Create a new NFT instance * * @param config - NFT configuration */ constructor(config: { /** NFT metadata */ metadata: NFTMetadata; /** Owner's public key */ ownerKey: PublicKey; /** NFT value in satoshis (default: 1000) */ satoshis?: number; /** Network (default: livenet) */ network?: Network; /** Optional script tree for advanced spending conditions */ scriptTree?: TapNode; /** Optional collection hash for collection NFTs */ collectionHash?: Buffer; /** Optional transaction ID if already minted */ txid?: string; /** Optional output index if already minted */ outputIndex?: number; }); /** * Create NFT instance from existing script * * @param script - Taproot script with state * @param metadata - NFT metadata * @param satoshis - NFT value * @param txid - Optional transaction ID * @param outputIndex - Optional output index * @returns NFT instance */ static fromScript(script: Script, metadata: NFTMetadata, satoshis: number, txid?: string, outputIndex?: number): NFT; /** * Create NFT instance from UTXO * * @param utxo - Unspent output or NFT UTXO information * @param metadata - NFT metadata * @returns NFT instance */ static fromUTXO(utxo: UnspentOutput | NFTUtxo | UnspentOutputData, metadata: NFTMetadata): NFT; get script(): Script; get address(): Address; get metadataHash(): Buffer; get metadata(): NFTMetadata; get satoshis(): number; get txid(): string | undefined; get outputIndex(): number | undefined; get commitment(): PublicKey | undefined; get merkleRoot(): Buffer | undefined; get leaves(): TapLeaf[] | undefined; get controlBlock(): Buffer | undefined; get collectionHash(): Buffer | undefined; /** * Check if this NFT has script tree (script path spending) */ hasScriptTree(): boolean; /** * Check if this NFT belongs to a collection */ isCollectionNFT(): boolean; /** * Verify that the metadata matches the on-chain hash * * @returns true if metadata is valid */ verifyMetadata(): boolean; /** * Create a transfer transaction to a new owner * * @param newOwnerKey - New owner's public key * @param currentOwnerKey - Current owner's private key * @param fee - Optional transaction fee in satoshis * @returns Signed transfer transaction * * @throws Error if NFT doesn't have UTXO information */ transfer(newOwnerKey: PublicKey, currentOwnerKey: PrivateKey, fee?: number): Transaction; /** * Update the UTXO information after the NFT is minted or transferred * * @param txid - Transaction ID * @param outputIndex - Output index */ updateUTXO(txid: string, outputIndex: number): void; /** * Get comprehensive NFT information * * @returns NFT info object */ getInfo(): NFTInfo; /** * Create an Output object for this NFT * * @returns Output instance */ toOutput(): Output; /** * Create an UnspentOutput object for this NFT * * @returns UnspentOutput instance * @throws Error if NFT doesn't have UTXO information */ toUnspentOutput(): UnspentOutput; /** * Get NFT UTXO information * * @returns NFT UTXO data * @throws Error if NFT doesn't have UTXO information */ getUtxo(): NFTUtxo; /** * Serialize NFT to JSON * * @returns JSON representation */ toJSON(): NFTObject; /** * Serialize NFT to a plain object matching the NFTData interface * * @returns NFTData interface object */ toObject(): NFTData; /** * Get string representation of the NFT * * @returns String representation */ toString(): string; } /** * NFT Utility Class */ export declare class NFTUtil { /** * Hash NFT metadata to 32-byte commitment * * Creates a SHA256 hash of the JSON-stringified metadata. * This hash is stored in the Taproot state parameter on-chain. * * @param metadata - NFT metadata object * @returns 32-byte hash * * @example * ```typescript * const metadata = { * name: 'Lotus NFT #1', * description: 'First NFT', * image: 'ipfs://Qm...', * } * const hash = NFTUtil.hashMetadata(metadata) * console.log(hash.toString('hex')) // 32-byte hex string * ``` */ static hashMetadata(metadata: NFTMetadata): Buffer; /** * Hash collection metadata * * @param collectionInfo - Collection metadata * @returns 32-byte hash */ static hashCollection(collectionInfo: NFTCollectionMetadata): Buffer; /** * Create combined hash for collection NFT * * Combines collection hash with individual NFT metadata for * NFTs that belong to a collection. * * @param collectionHash - Collection hash * @param nftMetadata - Individual NFT metadata * @returns 32-byte combined hash */ static hashCollectionNFT(collectionHash: Buffer, nftMetadata: NFTMetadata): Buffer; /** * Verify metadata matches hash * * @param metadata - NFT metadata * @param hash - Claimed hash * @returns true if metadata matches hash */ static verifyMetadata(metadata: NFTMetadata, hash: Buffer): boolean; /** * Verify collection NFT metadata * * @param collectionHash - Collection hash * @param nftMetadata - NFT metadata * @param hash - Claimed combined hash * @returns true if metadata matches hash */ static verifyCollectionNFT(collectionHash: Buffer, nftMetadata: NFTMetadata, hash: Buffer): boolean; /** * Extract state from NFT script * * @param script - Taproot script * @returns Metadata hash or null if no state * @throws Error if not a valid Taproot script */ static extractMetadataHash(script: Script): Buffer | null; /** * Create an NFT with metadata validation (script-path spending) * * Creates an NFT that validates the metadata hash on-chain using script-path spending. * The metadata hash is stored in the script state and validated during spending. * * @param ownerKey - Owner's public key * @param metadata - NFT metadata * @param satoshis - NFT value in satoshis (default: 1000) * @param network - Network (default: livenet) * @returns NFT instance with metadata validation * * @example * ```typescript * const ownerKey = new PrivateKey() * const metadata = { * name: 'My NFT', * description: 'A unique collectible', * image: 'ipfs://Qm...', * } * const nft = NFTUtil.createNFT(ownerKey.publicKey, metadata) * console.log('NFT address:', nft.address.toString()) * console.log('Metadata hash:', nft.metadataHash.toString('hex')) * ``` */ static createNFT(ownerKey: PublicKey, metadata: NFTMetadata, satoshis?: number, network?: Network | NetworkName): NFTData; static createScriptPathNFT(ownerKey: PublicKey, metadata: NFTMetadata, scriptTree: TapNode, satoshis?: number, network?: Network): NFTWithScriptPath; /** * Create a collection NFT * * Creates an NFT that belongs to a collection. The metadata hash includes * both the collection identifier and individual NFT metadata. * * @param ownerKey - Owner's public key * @param collectionHash - Collection hash * @param nftMetadata - Individual NFT metadata * @param satoshis - NFT value in satoshis (default: 1000) * @param network - Network * @returns NFT instance with collection info */ static createCollectionNFT(ownerKey: PublicKey, collectionHash: Buffer, nftMetadata: NFTMetadata, satoshis?: number, network?: Network): NFTWithCollection; /** * Mint a single NFT * * Creates a transaction that mints an NFT by creating a Taproot output * with metadata commitment in the state parameter. * * Note: This function creates the output structure. You need to add inputs * and sign the transaction. * * @param config - Mint configuration * @returns Transaction with NFT output (needs inputs and signing) * * @example * ```typescript * const tx = NFTUtil.mintNFT({ * ownerKey: privateKey, * metadata: { * name: 'My NFT', * description: 'A unique collectible', * image: 'ipfs://Qm...', * }, * satoshis: 1000, * }) * * // Add funding input and change output * tx.from(utxo) * tx.change(changeAddress) * tx.sign(privateKey) * ``` */ static mintNFT(config: NFTMintConfig): Transaction; /** * Mint multiple NFTs in a single transaction (batch minting) * * @param ownerKey - Owner's private key * @param nftMetadataList - Array of NFT metadata * @param satoshisPerNFT - Value per NFT (default: 1000) * @param network - Network * @returns Transaction with multiple NFT outputs */ static mintBatch(ownerKey: PrivateKey, nftMetadataList: NFTMetadata[], satoshisPerNFT?: number, network?: Network): Transaction; /** * Mint a collection of NFTs * * @param ownerKey - Owner's private key * @param collectionInfo - Collection metadata * @param nftMetadataList - Array of individual NFT metadata * @param satoshisPerNFT - Value per NFT (default: 1000) * @param network - Network * @returns Transaction with collection NFT outputs */ static mintCollection(ownerKey: PrivateKey, collectionInfo: NFTCollectionMetadata, nftMetadataList: NFTMetadata[], satoshisPerNFT?: number, network?: Network): Transaction; /** * Transfer an NFT to a new owner (key path) * * Creates a transaction that transfers an NFT by spending the current * NFT UTXO and creating a new NFT output for the new owner with the * same metadata hash. * * @param config - Transfer configuration * @returns Signed transaction ready to broadcast * * @example * ```typescript * const transferTx = NFTUtil.transferNFT({ * currentOwnerKey: currentOwner, * newOwnerKey: newOwner.publicKey, * nftUtxo: { * txid: 'abc123...', * outputIndex: 0, * script: nftScript, * satoshis: 1000, * }, * metadataHash: metadataHash, * }) * * console.log('Transfer TX:', transferTx.serialize()) * ``` */ static transferNFT(config: NFTTransferConfig): Transaction; /** * Validate NFT transfer preserves metadata * * Verifies that an NFT transfer maintains the same metadata hash * from input to output, ensuring NFT authenticity. * * @param inputScript - Input script * @param outputScript - Output script * @returns true if metadata hash is preserved */ static validateTransfer(inputScript: Script, outputScript: Script): boolean; /** * Trace NFT provenance * * Verifies that all transfers in the provenance chain maintain the * same metadata hash, proving authenticity from mint to current owner. * * @param transfers - Array of transfers (chronological order) * @returns true if provenance is valid */ static verifyProvenance(transfers: NFTTransfer[]): boolean; /** * Check if a script is an NFT (has state parameter) * * @param script - Script to check * @returns true if script is an NFT */ static isNFT(script: Script): boolean; /** * Get NFT info from script * * @param script - NFT script * @returns NFT information * @throws Error if not a valid NFT */ static getNFTInfo(script: Script): NFTInfo; } //# sourceMappingURL=nft.d.ts.map