Skip to content

Metadata Transactions

Chun Lam edited this page Feb 21, 2024 · 3 revisions
import { MetadataHttp, MetadataQueryParams, MetadataType, MosaicId, NamespaceId, PublicAccount, 
    AccountMetadataTransaction, MosaicMetadataTransaction, NamespaceMetadataTransaction, Listener, 
    Deadline, NetworkType, KeyGenerator, AggregateTransaction, Account, HashLockTransaction,
    NetworkCurrencyMosaic, UInt64, TransactionHttp } from "tsjs-xpx-chain-sdk";

const API_URL = 'http://localhost:3000';
const networkType = NetworkType.TEST_NET;
const generationHash = "56D112C98F7A7E34D1AEDC4BD01BC06CA2276DD546A93E36690B785E82439CA9"; // from block 1

const metadataHttp = new MetadataHttp(API_URL);
const transactionHttp = new TransactionHttp(API_URL);
let listener = new Listener(API_URL);

const signerAccount = Account.createFromPrivateKey(
    '<your_privateKey>',
    networkType, 1);

const targetPublicAccount = PublicAccount.createFromPublicKey("F06FE22FBA1E116B8F0E673BA4EE424B16BD6EA7548ED259F3DCEBF8D74C49B9", networkType, 1);

const sendAccountMedataTransaction = () =>{
    
    // search targetKey, account type metadata
    let metadataQueryParams = new MetadataQueryParams();
    metadataQueryParams.metadataType = MetadataType.ACCOUNT;
    metadataQueryParams.targetKey = targetPublicAccount;
    metadataQueryParams.scopedMetadataKey = KeyGenerator.generateUInt64Key("myKey");

    metadataHttp.searchMetadata(metadataQueryParams).subscribe({
        next: metadataSearchResult => {
            let oldMetadataValue = ""; // set empty previous value
            if(metadataSearchResult.metadataEntries.length){
                oldMetadataValue = metadataSearchResult.metadataEntries[0].value;
            }

            let accountMetadataTxn = AccountMetadataTransaction.create(
                Deadline.create(),
                targetPublicAccount,
                "myKey",
                "newValue",
                oldMetadataValue,
                networkType
            );

            // will need to use AggregateBonded, it only work that way
            let aggregateBondedTxn = AggregateTransaction.createBondedV1(
                Deadline.create(),
                [ 
                    accountMetadataTxn.toAggregateV1(signerAccount.publicAccount) 
                ],
                networkType
            )

            let signedAbtTransaction = signerAccount.preV2Sign(aggregateBondedTxn, generationHash);

            let lockhashTx = HashLockTransaction.create(
                Deadline.create(),
                NetworkCurrencyMosaic.createRelative(10), // 10 XPX to lock
                UInt64.fromUint(10000), // duration in block
                signedAbtTransaction,
                networkType
            );

            let signedLockHashTransaction = signerAccount.preV2Sign(lockhashTx, generationHash);

            listener.open().then(()=>{

                let initial = 0;
                let announced = false;
                let lockHashConfirmed = false;
                let lockhashConfirmedAt = 0;
                console.log("Listening");
            
                let confirmedListener = listener.confirmed(signerAccount.address).subscribe((confirmedTx)=>{
                    
                    if(confirmedTx.transactionInfo!.hash === signedLockHashTransaction.hash){
                        lockHashConfirmed = true;
                        lockhashConfirmedAt = confirmedTx.transactionInfo!.height.compact();
                        console.log("Lockhash Confirmed", lockhashConfirmedAt);
                    }
                    else if(confirmedTx.transactionInfo!.hash === signedAbtTransaction.hash){
                        console.log("ABT Confirmed");
                        confirmedListener.unsubscribe();
                        newBlockListener.unsubscribe();
                        listener.close();
                    }
                });
            
                let newBlockListener = listener.newBlock().subscribe((blockInfo)=>{
                    console.log(blockInfo.height.compact());
                    if(initial === 0){
                        initial = blockInfo.height.compact();
                    }
                    else if(lockhashConfirmedAt && ( lockhashConfirmedAt + 1 < blockInfo.height.compact()) && lockHashConfirmed && !announced){
                        transactionHttp.announceAggregateBonded(signedAbtTransaction);
                        announced = true;
                        console.log("announced");
                        confirmedListener.unsubscribe();
                        newBlockListener.unsubscribe();
                        listener.close();
                        // wait for confirmation or cosign of the transaction
                    }
                });
            
                transactionHttp.announce(signedLockHashTransaction).subscribe(
                    (message)=>{
                        console.log(message);
                    },
                    (error)=>{
                        console.log(error);
                    }
                );
                
            });

        }, error: error => {
            console.error(error);
        }
    })
}

const sendMosaicMedataTransaction = () =>{
    const xpxMosaicId = new MosaicId("13bfc518e40549d7");

    // search mosaic type metadata
    let metadataQueryParams = new MetadataQueryParams();
    metadataQueryParams.metadataType = MetadataType.MOSAIC;
    metadataQueryParams.targetId = xpxMosaicId;
    metadataQueryParams.scopedMetadataKey = KeyGenerator.generateUInt64Key("myKey");

    metadataHttp.searchMetadata(metadataQueryParams).subscribe({
        next: metadataSearchResult => {
            let oldMetadataValue = ""; // set empty previous value
            if(metadataSearchResult.metadataEntries.length){
                oldMetadataValue = metadataSearchResult.metadataEntries[0].value;
            }

            let mosaicMetadataTxn = MosaicMetadataTransaction.create(
                Deadline.create(),
                targetPublicAccount,
                xpxMosaicId,
                "myKey",
                "newValue",
                oldMetadataValue,
                networkType
            );

            // will need to use AggregateBonded, it only work that way
            let aggregateBondedTxn = AggregateTransaction.createBondedV1(
                Deadline.create(),
                [ 
                    mosaicMetadataTxn.toAggregateV1(signerAccount.publicAccount) 
                ],
                networkType
            )

            let signedAbtTransaction = signerAccount.preV2Sign(aggregateBondedTxn, generationHash);

            let lockhashTx = HashLockTransaction.create(
                Deadline.create(),
                NetworkCurrencyMosaic.createRelative(10), // 10 XPX to lock
                UInt64.fromUint(10000), // duration in block
                signedAbtTransaction,
                networkType
            );

            let signedLockHashTransaction = signerAccount.preV2Sign(lockhashTx, generationHash);

            listener.open().then(()=>{

                let initial = 0;
                let announced = false;
                let lockHashConfirmed = false;
                let lockhashConfirmedAt = 0;
                console.log("Listening");
            
                let confirmedListener = listener.confirmed(signerAccount.address).subscribe((confirmedTx)=>{
                    
                    if(confirmedTx.transactionInfo!.hash === signedLockHashTransaction.hash){
                        lockHashConfirmed = true;
                        lockhashConfirmedAt = confirmedTx.transactionInfo!.height.compact();
                        console.log("Lockhash Confirmed", lockhashConfirmedAt);
                    }
                    else if(confirmedTx.transactionInfo!.hash === signedAbtTransaction.hash){
                        console.log("ABT Confirmed");
                        confirmedListener.unsubscribe();
                        newBlockListener.unsubscribe();
                        listener.close();
                    }
                });
            
                let newBlockListener = listener.newBlock().subscribe((blockInfo)=>{
                    console.log(blockInfo.height.compact());
                    if(initial === 0){
                        initial = blockInfo.height.compact();
                    }
                    else if(lockhashConfirmedAt && ( lockhashConfirmedAt + 1 < blockInfo.height.compact()) && lockHashConfirmed && !announced){
                        transactionHttp.announceAggregateBonded(signedAbtTransaction);
                        announced = true;
                        console.log("announced");
                        confirmedListener.unsubscribe();
                        newBlockListener.unsubscribe();
                        listener.close();
                        // wait for confirmation or cosign of the transaction
                    }
                });
            
                transactionHttp.announce(signedLockHashTransaction).subscribe(
                    (message)=>{
                        console.log(message);
                    },
                    (error)=>{
                        console.log(error);
                    }
                );
                
            });
        }, error: error => {
            console.error(error);
        }
    })
}

const sendNamespaceMedataTransaction = () =>{
    const xpxNamespaceId = new NamespaceId("prx.xpx");

    // search namespace type metadata
    let metadataQueryParams = new MetadataQueryParams();
    metadataQueryParams.metadataType = MetadataType.NAMESPACE;
    metadataQueryParams.targetId = xpxNamespaceId;
    metadataQueryParams.scopedMetadataKey = KeyGenerator.generateUInt64Key("myKey");

    metadataHttp.searchMetadata(metadataQueryParams).subscribe({
        next: metadataSearchResult => {
            let oldMetadataValue = ""; // set empty previous value
            if(metadataSearchResult.metadataEntries.length){
                oldMetadataValue = metadataSearchResult.metadataEntries[0].value;
            }

            let namespaceMetadataTxn = NamespaceMetadataTransaction.create(
                Deadline.create(),
                targetPublicAccount,
                xpxNamespaceId,
                "myKey",
                "newValue",
                oldMetadataValue,
                networkType
            );

            // will need to use AggregateBonded, it only work that way
            let aggregateBondedTxn = AggregateTransaction.createBondedV1(
                Deadline.create(),
                [ 
                    namespaceMetadataTxn.toAggregateV1(signerAccount.publicAccount) 
                ],
                networkType
            )

            let signedAbtTransaction = signerAccount.preV2Sign(aggregateBondedTxn, generationHash);

            let lockhashTx = HashLockTransaction.create(
                Deadline.create(),
                NetworkCurrencyMosaic.createRelative(10), // 10 XPX to lock
                UInt64.fromUint(10000), // duration in block
                signedAbtTransaction,
                networkType
            );

            let signedLockHashTransaction = signerAccount.preV2Sign(lockhashTx, generationHash);

            listener.open().then(()=>{

                let initial = 0;
                let announced = false;
                let lockHashConfirmed = false;
                let lockhashConfirmedAt = 0;
                console.log("Listening");
            
                let confirmedListener = listener.confirmed(signerAccount.address).subscribe((confirmedTx)=>{
                    
                    if(confirmedTx.transactionInfo!.hash === signedLockHashTransaction.hash){
                        lockHashConfirmed = true;
                        lockhashConfirmedAt = confirmedTx.transactionInfo!.height.compact();
                        console.log("Lockhash Confirmed", lockhashConfirmedAt);
                    }
                    else if(confirmedTx.transactionInfo!.hash === signedAbtTransaction.hash){
                        console.log("ABT Confirmed");
                        confirmedListener.unsubscribe();
                        newBlockListener.unsubscribe();
                        listener.close();
                    }
                });
            
                let newBlockListener = listener.newBlock().subscribe((blockInfo)=>{
                    console.log(blockInfo.height.compact());
                    if(initial === 0){
                        initial = blockInfo.height.compact();
                    }
                    else if(lockhashConfirmedAt && ( lockhashConfirmedAt + 1 < blockInfo.height.compact()) && lockHashConfirmed && !announced){
                        transactionHttp.announceAggregateBonded(signedAbtTransaction);
                        announced = true;
                        console.log("announced");
                        confirmedListener.unsubscribe();
                        newBlockListener.unsubscribe();
                        listener.close();
                        // wait for confirmation or cosign of the transaction
                    }
                });
            
                transactionHttp.announce(signedLockHashTransaction).subscribe({
                    next: (message)=>{
                        console.log(message);
                    },
                    error: (error)=>{
                        console.log(error);
                    }
                });
                
            });
        }, error: error => {
            console.error(error);
        }
    })
}