You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
// current connected account address infoconstaddressInfo={output: ...,scripthash: ...,network: ...,}// query all atomicals balanceconstbalance=awaitfetch(`${electrumUrl}/blockchain.atomicals.listscripthash?params=["${addressInfo.scripthash}",true]`,{signal: controller.signal}).then((res)=>{returnres.json();});// pure utxos without any assetsconstpureUTXOs=balance.utxos.filter((utxo: any)=>{if(Array.isArray(utxo.atomicals)){returnutxo.atomicals.length==0;}if(typeofutxo.atomicals==='object'){returnObject.keys(utxo.atomicals).length===0;}// unreachablereturnfalse;}).sort((a: any,b: any)=>b.value-a.value);constatomicals=balance.atomicals;constutxos=balance.utxos;constfs: Record<string,any>={};for(constutxoofutxos){// compatible with old formatif(Array.isArray(utxo.atomicals)){// ignore merged assetsif(utxo.atomicals.length!==1){continue;}constatomicalId=utxo.atomicals[0];constatomical=atomicals[atomicalId].data;if(atomical.type!=='FT'){continue;}utxo.atomical_value=utxo.value;if(atomical.utxos){atomical.utxos.push(utxo);atomical.atomical_value+=utxo.value;}else{atomical.utxos=[utxo];atomical.atomical_value=utxo.value;}fs[atomicalId]=atomical;}// new formatelseif(typeofutxo.atomicals==='object'){// ignore merged assetsif(Object.keys(utxo.atomicals).length!==1){continue;}for(constatomicalIdinutxo.atomicals){constatomical=atomicals[atomicalId].data;if(atomical.type!=='FT'){continue;}utxo.atomical_value=utxo.atomicals[atomicalId];if(atomical.utxos){atomical.utxos.push(utxo);atomical.atomical_value+=utxo.atomical_value;}else{atomical.utxos=[utxo];atomical.atomical_value=utxo.atomical_value;}fs[atomicalId]=atomical;}}}constallFTs=Object.values(fs);// pick a FT from allFTsconstftUTXOs=selectedFT.utxos;// send ft amountconstamount=1;// input ft valueletinputFTValue=0;// remainder ft valueletremainderFTValue=0;// input ft utxosconstrevealInputs=[];for(constutxoofftUTXOs){inputFTValue+=utxo.atomical_value;revealInputs.push(utxo);remainderFTValue=inputFTValue-amount;if(remainderFTValue>=0){break;}}constpayload: Record<string,Record<number,number>>={};constrevealOutputs=[{// send to any addressaddress: toAddress,// ft value less than the dust amount(546) will be partially colored.value: Math.max(amount,546),},];payload[selectedFT.atomical_id]={0: amount,};if(remainderFTValue){revealOutputs.push({address: address,// ft value less than the dust amount(546) will be partially colored.value: Math.max(remainderFTValue,546),});payload[selectedFT.atomical_id][1]=remainderFTValue;}// prepare commit reveal configconstbuffer=newAtomicalsPayload(payload).cbor();// user's public key to xpubconstselfXOnly=toXOnly(Buffer.from(publicKey,'hex'));// use `z` op typeconst{ scriptP2TR, hashLockP2TR }=prepareCommitRevealConfig('z',selfXOnly,buffer,addressInfo.network);consthashLockP2TROutputLen=hashLockP2TR.redeem!.output!.length;// calculate feeconstrevealFee=calculateAmountRequiredForReveal(feeRate,revealInputs.length,revealOutputs.length,hashLockP2TROutputLen);// calculate need for reveal transactionconstrevealNeed=revealFee+revealOutputs.reduce((acc,output)=>acc+output.value,0)-revealInputs.reduce((acc,input)=>acc+input.value,0);// prepare commit transaction// reveal transaction outputconstoutputs=[{address: scriptP2TR.address!,value: revealNeed,},];constinputs=[];letinputSats=0;letok=false;letfee=0;// calculate utxo inputs and feefor(constutxoofpureUTXOs){inputSats+=utxo.value;inputs.push(utxo);fee=calculateFeesRequiredForCommit(feeRate,inputs.length,1);letv=inputSats-fee-revealNeed;if(v>=0){if(v>=546){fee=calculateFeesRequiredForCommit(feeRate,inputs.length,2);v=inputSats-fee-revealNeed;if(v>=546){outputs.push({
address,value: v,});}}ok=true;break;}}if(!ok){thrownewError('Insufficient funds');}// create commit psbtconstcommitPsbt=newbitcoin.Psbt({network: addressInfo.network});for(constinputofinputs){commitPsbt.addInput({hash: input.txid,index: input.index,sequence: 0xfffffffd,witnessUtxo: {script: addressInfo.output,value: input.value,},tapInternalKey: selfXOnly,});}commitPsbt.addOutputs(outputs);// get the transaction txid for reveal input utxo hashconsttx=commitPsbt.__CACHE.__TXasTransaction;consttxId=tx.getId();// create reveal psbtconstrevealPsbt=newbitcoin.Psbt({network: addressInfo.network});// build tap leaf scriptconsttapLeafScript={leafVersion: hashLockP2TR!.redeem!.redeemVersion,script: hashLockP2TR!.redeem!.output,controlBlock: hashLockP2TR.witness![hashLockP2TR.witness!.length-1],};revealPsbt.addInput({sequence: 0xfffffffd,// commit transaction txidhash: txId,index: 0,witnessUtxo: {value: revealNeed,script: hashLockP2TR.output!},tapLeafScript: [tapLeafScriptasany],});// add reveal inputsfor(constrevealInputofrevealInputs){// revealPsbt.addInput({sequence: 0xfffffffd,hash: revealInput.txid,index: revealInput.index,witnessUtxo: {value: revealInput.value,script: addressInfo.output},tapInternalKey: selfXOnly,});}revealPsbt.addOutputs(revealOutputs);// sign commit psbtconstsignedCommitPsbt=awaitwindow.wizz.signPsbt(commitPsbt.toHex());// sign reveal psbt with `signAtomical` optionconstsignedRevealPsbt=awaitwindow.wizz.signPsbt(revealPsbt.toHex(),{signAtomical: true});// broadcast commit transactionconstcommitTxId=awaitwindow.wizz.pushPsbt(signedCommitPsbt);// broadcast reveal transactionconstrevealTxId=awaitwindow.wizz.pushPsbt(signedRevealPsbt);