7 Commits b048526b32 ... 557507b137

Autor SHA1 Mensaje Fecha
  Shomari 557507b137 Fix "main" chain handling. hace 1 mes
  Shomari a5b6cf149e Add (initial) sponsor addresses. hace 1 mes
  Shomari 951632a25e Add $HUSH rewards to sponsors page. hace 1 mes
  Shomari dc0d10861d Add WIF to fusion inputs. hace 1 mes
  Shomari 808ce42fa5 Fix UTXOs update. hace 1 mes
  Shomari 1b135d9ef9 Enable "manual" building + broadcast from shared details. hace 1 mes
  Shomari 240622d9b8 Fix wallet creation issues? hace 1 mes

+ 29 - 8
web/components/Wallet/Welcome.vue

@@ -27,7 +27,13 @@ const balance = computed(() => {
         return 0
         return 0
     }
     }
 
 
-    const totalValue = Wallet.fusionInputs.reduce(
+    const inputs = []
+
+    Object.keys(Wallet.fusionInputs).forEach(_outpoint => {
+        inputs.push(Wallet.fusionInputs[_outpoint])
+    })
+
+    const totalValue = inputs.reduce(
         (acc, utxo) => acc + utxo.value, 0
         (acc, utxo) => acc + utxo.value, 0
     )
     )
     // console.log('TOTAL VALUE', totalValue)
     // console.log('TOTAL VALUE', totalValue)
@@ -43,8 +49,12 @@ const cashout = async () => {
     console.log('COMPLETE FUSION', response)
     console.log('COMPLETE FUSION', response)
 }
 }
 
 
-const consolidate = () => {
-    alert('WIP?? sorry...')
+const consolidate = async () => {
+    // alert('WIP?? sorry...')
+
+    const response = await Wallet.signFusion()
+        .catch(err => console.error(err))
+    console.log('SIGN FUSION', response)
 }
 }
 
 
 const startFusion = () => {
 const startFusion = () => {
@@ -55,22 +65,33 @@ const init = () => {
     /* Initialize locals. */
     /* Initialize locals. */
     let address
     let address
 
 
+    if (typeof props.cashAddress === 'undefined' || !props.cashAddress || props.cashAddress === '') {
+        console.log('RELOAD PAGE FOR CASH ADDRESS!!')
+        const router = useRouter()
+        // router.push({ path: "/admin/liquidity?setup-complete" })
+        router.push({ path: "/admin" })
+        return
+    }
+
     /* Initialize #? Hush addresses. */
     /* Initialize #? Hush addresses. */
     hushAddresses.value = []
     hushAddresses.value = []
 
 
     for (let i = 0; i < 20; i++) {
     for (let i = 0; i < 20; i++) {
         // HUSH == 0x48555348 == 1,213,551,432
         // HUSH == 0x48555348 == 1,213,551,432
-        // address = await Wallet.getBchAddress(HUSH_PROTOCOL_ID, 0, i)
+        // address = Wallet.getBchAddress(HUSH_PROTOCOL_ID, 0, i)
         address = Wallet.keychain[HUSH_PROTOCOL_ID][i].address
         address = Wallet.keychain[HUSH_PROTOCOL_ID][i].address
         // console.log('GET BCH ADDRESS', i, address)
         // console.log('GET BCH ADDRESS', i, address)
         hushAddresses.value.push(address)
         hushAddresses.value.push(address)
     }
     }
 
 
+
 }
 }
 
 
 onMounted(() => {
 onMounted(() => {
     // console.log('KEYCHAIN', Wallet.keychain)
     // console.log('KEYCHAIN', Wallet.keychain)
     // init()
     // init()
+
+    // FIXME Race conditions with loading time and reloading...
     setTimeout(init, 1000)
     setTimeout(init, 1000)
 })
 })
 
 
@@ -97,7 +118,7 @@ onMounted(() => {
                         Bitcoin Cash Address
                         Bitcoin Cash Address
                     </h2>
                     </h2>
 
 
-                    <NuxtLink :to="'https://3xpl.com/bitcoin-cash/address/' + props.cashAddress.slice(12)" target="_blank" class="col-span-2 text-base sm:text-xl text-blue-500 truncate hover:underline">
+                    <NuxtLink v-if="props.cashAddress" :to="'https://explorer.melroy.org/address/' + props.cashAddress.slice(12)" target="_blank" class="col-span-2 text-base sm:text-xl text-blue-500 truncate hover:underline">
                         {{props.cashAddress.slice(12)}}
                         {{props.cashAddress.slice(12)}}
                     </NuxtLink>
                     </NuxtLink>
 
 
@@ -105,7 +126,7 @@ onMounted(() => {
                         Current Balance
                         Current Balance
                     </h3>
                     </h3>
 
 
-                    <h3 class="text-green-900 text-xl font-medium">
+                    <h3 v-if="balance" class="text-green-900 text-xl font-medium">
                         {{balance}}
                         {{balance}}
                         <small class="text-sm">sats</small>
                         <small class="text-sm">sats</small>
                     </h3>
                     </h3>
@@ -114,7 +135,7 @@ onMounted(() => {
                 <div v-for="(address, index) of hushAddresses" :key="address" class="text-xs">
                 <div v-for="(address, index) of hushAddresses" :key="address" class="text-xs">
                     <div class="grid grid-cols-4 items-center gap-3">
                     <div class="grid grid-cols-4 items-center gap-3">
                         <span class="text-right">Hush #{{(index + 1)}}</span>
                         <span class="text-right">Hush #{{(index + 1)}}</span>
-                        <NuxtLink :to="'https://3xpl.com/bitcoin-cash/address/' + address.slice(12)" target="_blank" class="col-span-3 text-blue-500 hover:underline">{{address}}</NuxtLink>
+                        <NuxtLink :to="'https://explorer.melroy.org/address/' + address.slice(12)" target="_blank" class="col-span-3 text-blue-500 hover:underline">{{address}}</NuxtLink>
                     </div>
                     </div>
                 </div>
                 </div>
             </div>
             </div>
@@ -141,7 +162,7 @@ onMounted(() => {
                 <!-- <div v-for="(address, index) of hushAddresses" :key="address" class="text-xs">
                 <!-- <div v-for="(address, index) of hushAddresses" :key="address" class="text-xs">
                     <div class="grid grid-cols-4 items-center gap-3">
                     <div class="grid grid-cols-4 items-center gap-3">
                         <span class="text-right">Hush #{{(index + 1)}}</span>
                         <span class="text-right">Hush #{{(index + 1)}}</span>
-                        <NuxtLink :to="'https://3xpl.com/bitcoin-cash/address/' + address.slice(12)" target="_blank" class="col-span-3 text-blue-500 hover:underline">{{address}}</NuxtLink>
+                        <NuxtLink :to="'https://explorer.melroy.org/address/' + address.slice(12)" target="_blank" class="col-span-3 text-blue-500 hover:underline">{{address}}</NuxtLink>
                     </div>
                     </div>
                 </div> -->
                 </div> -->
             </div>
             </div>

+ 76 - 89
web/handlers/buildSharedTx.ts

@@ -7,115 +7,102 @@ import { utf8ToBin } from '@nexajs/utils'
 
 
 const bchjs = new BCHJS()
 const bchjs = new BCHJS()
 
 
+/* Initialize constants. */
+const HUSH_PROTOCOL_ID = 0x48555348
+
+
 /**
 /**
  * Build Shared Transaction
  * Build Shared Transaction
  *
  *
  * Combine all participating inputs and outputs into one (signed) transaction.
  * Combine all participating inputs and outputs into one (signed) transaction.
- *
- * NOTE: ALL inputs are ALREADY signed by their respective participants.
  */
  */
-export default function (_inputs, _outputs) {
+export default function (_sessionid, _inputs, _outputs) {
+console.log('BUILD SHARED TX', _sessionid, _inputs, _outputs)
     /* Initialize locals. */
     /* Initialize locals. */
+    let accountIdx
+    let addressIdx
+    let changeIdx
+    let childNode
+    let data
+    let ecPair
+    // let ownedInputs
+    let protocolId
+    let msg
     let rawTx
     let rawTx
-    let safeBalance
-    let utxo
+    let redeemScript
+    let script
+    let wif
 
 
+    /* Initialize transaction builde.r */
     const transactionBuilder = new bchjs.TransactionBuilder()
     const transactionBuilder = new bchjs.TransactionBuilder()
-let inputIdx
-    this.fusionInputs.forEach((_utxo) => {
-        /* Set UTXO. */
-        utxo = _utxo
-        console.log('UTXO', utxo)
-inputIdx = 0//utxo.tx_pos
-        transactionBuilder.addInput(utxo.tx_hash, utxo.tx_pos)
-
-        const originalAmount = utxo.value
-
-        const remainder = originalAmount - satsNeeded
-        console.log('REMAINDER', remainder);
-
-        if (remainder < 0) {
-            throw new Error('Selected UTXO does not have enough satoshis')
-        }
-
-
-        const protocolId = '1337'
-        const msg = 'building...'
-
-        const script = [
-            utf8ToBin(protocolId),
-            utf8ToBin(msg),
-        ]
-        console.log('my SCRIPT', script)
-        console.log('encodeNullData', encodeNullData(script))
-
-        // Compile the script array into a bitcoin-compliant hex encoded string.
-        // const data = bchjs.Script.encode(script)
-        const data = Buffer.from(encodeNullData(script))
-        console.log('OP_RETURN (data)', data)
 
 
-        // Add the OP_RETURN output.
-        // transactionBuilder.addOutput(data, 0)
-        transactionBuilder.addOutput(data, 0)
+console.log('DO WE HAVE FUSION INPUTS??', this.fusionInputs)
 
 
+    /* Initialize our addresses. */
+    const ourAddresses = []
 
 
+    /* Handle fusion inputs. */
+    Object.keys(this.fusionInputs).forEach(_outpoint => {
+        const ourInput = this.fusionInputs[_outpoint]
+        console.log('OUR INPUT', ourInput)
 
 
-        // Send payment
-        // transactionBuilder.addOutput(receiver, satsNeeded)
-        transactionBuilder.addOutput(receiver, paymentAmount)
-
-        // Send the BCH change back to the payment part
-        // transactionBuilder.addOutput(account.address, remainder - 300)
+        ourAddresses.push(ourInput.address)
     })
     })
+    console.log('OUR ADDRESSES', ourAddresses)
 
 
-    /* Initialize redeem script. */
-    // FIXME Why do we need this??
-    let redeemScript
-
-    /* Convert mnemonic to seed. */
-    const seed = mnemonicToSeed(this.mnemonic)
-
-    /* Conver to seed buffer. */
-    // FIXME Migrate to TypedArrays.
-    const seedBuffer = Buffer.from(seed, 'hex')
-
-    /* Generate master node. */
-    const masterNode = bchjs.HDNode.fromSeed(seedBuffer)
+    /* Initialize address index. */
+    // addressIdx = 0
 
 
-/* Set account index. */
-const accountIdx = 0
-/* Set change index. */
-const changeIdx = 0
-/* Set address index. */
-const addressIdx = 0
+    /* Initialize owned inputs. */
+    // ownedInputs = []
 
 
-    /* Generate child node. */
-    const chidleNode = masterNode
-        .derivePath(`m/44'/145'/${accountIdx}'/${changeIdx}/${addressIdx}`)
+    /* Handle inputs. */
+    _inputs.forEach(_input => {
+        /* Add input. */
+        transactionBuilder.addInput(_input.tx_hash, _input.tx_pos)
 
 
-    /* Generate wallet import format (WIF). */
-    const wif = bchjs.HDNode.toWIF(chidleNode)
-    // console.log('BCH WIF', wif)
-
-    /* Generate elliptic pair. */
-    const ecPair = bchjs.ECPair.fromWIF(wif)
-
-    /* Sign transaction. */
-    transactionBuilder.sign(
-        inputIdx,
-        ecPair,
-        redeemScript,
-        Transaction.SIGHASH_ALL,
-        utxo.value,
-    )
+// console.log('VALIDATING (SELF) INPUT', _input)
+//         /* Validate (our) address. */
+//         if (ourAddresses.includes(_input.address)) {
+//             ownedInputs.push(addressIdx)
+//         }
+//         addressIdx++
+    })
+    // console.log('OUR INPUTS INDEX', ownedInputs)
+
+    /* Set protocol ID. */
+    protocolId = '1337'
+
+    /* Set protocol message. */
+    msg = 'FINAL!'
+
+    script = [
+        utf8ToBin(protocolId),
+        utf8ToBin(msg),
+        // utf8ToBin(_sessionid),
+    ]
+    // console.log('my SCRIPT', script)
+    // console.log('encodeNullData', encodeNullData(script))
+
+    // Compile the script array into a bitcoin-compliant hex encoded string.
+    // const data = bchjs.Script.encode(script)
+    data = Buffer.from(encodeNullData(script))
+    // console.log('OP_RETURN (data)', data)
+
+    // Add the OP_RETURN output.
+    transactionBuilder.addOutput(data, 0)
+
+    /* Handle outputs. */
+    _outputs.forEach(_output => {
+        /* Add output. */
+        transactionBuilder.addOutput(_output.address, _output.value)
+    })
 
 
     /* Generate (incomplete) transaction. */
     /* Generate (incomplete) transaction. */
-    const tx = transactionBuilder.transaction.buildIncomplete()
-    // console.log('TRANSACTION', tx)
-
-    /* Convert to (raw) hex. */
-    rawTx = tx.toHex()
+    const transaction = transactionBuilder.transaction.buildIncomplete()
+    console.log('TRANSACTION', transaction)
 
 
     /* Return raw (hex) transaction. */
     /* Return raw (hex) transaction. */
-    return rawTx
+    // return transaction
+    return transactionBuilder
 }
 }

+ 67 - 36
web/handlers/signSharedTx.ts

@@ -5,6 +5,7 @@ import { mnemonicToSeed } from '@nexajs/hdnode'
 import { encodeNullData } from '@nexajs/script'
 import { encodeNullData } from '@nexajs/script'
 import { utf8ToBin } from '@nexajs/utils'
 import { utf8ToBin } from '@nexajs/utils'
 
 
+/* Initialize BCHJS. */
 const bchjs = new BCHJS()
 const bchjs = new BCHJS()
 
 
 /* Initialize constants. */
 /* Initialize constants. */
@@ -16,20 +17,19 @@ const HUSH_PROTOCOL_ID = 0x48555348
  *
  *
  * Combine all participating inputs and outputs into one (signed) transaction.
  * Combine all participating inputs and outputs into one (signed) transaction.
  */
  */
-export default function (_sessionid, _mnemonic, _inputs, _outputs) {
+export default function (_sessionid, _inputs, _outputs) {
 console.log('SIGN SHARED TX', _sessionid, _inputs, _outputs)
 console.log('SIGN SHARED TX', _sessionid, _inputs, _outputs)
     /* Initialize locals. */
     /* Initialize locals. */
-    let accountIdx
-    let addressIdx
-    let changeIdx
-    let childNode
+    // let accountIdx
+    // let addressIdx
+    // let changeIdx
+    // let childNode
     let data
     let data
     let ecPair
     let ecPair
-    let hushIndexes
-    let ownedInputs
+    // let ownedInputs
     let protocolId
     let protocolId
     let msg
     let msg
-    let rawTx
+    // let rawTx
     let redeemScript
     let redeemScript
     let script
     let script
     let wif
     let wif
@@ -37,17 +37,45 @@ console.log('SIGN SHARED TX', _sessionid, _inputs, _outputs)
     /* Initialize transaction builde.r */
     /* Initialize transaction builde.r */
     const transactionBuilder = new bchjs.TransactionBuilder()
     const transactionBuilder = new bchjs.TransactionBuilder()
 
 
+console.log('DO WE HAVE FUSION INPUTS??', this.fusionInputs)
+
+    /* Initialize our addresses. */
+    const ourAddresses = []
+
+    /* Handle fusion inputs. */
+    Object.keys(this.fusionInputs).forEach(_outpoint => {
+        const ourInput = this.fusionInputs[_outpoint]
+        console.log('OUR INPUT', ourInput)
+
+        ourAddresses.push(ourInput.address)
+    })
+    console.log('OUR ADDRESSES', ourAddresses)
+
+    /* Initialize address index. */
+    // addressIdx = 0
+
+    /* Initialize owned inputs. */
+    // ownedInputs = []
+
     /* Handle inputs. */
     /* Handle inputs. */
     _inputs.forEach(_input => {
     _inputs.forEach(_input => {
         /* Add input. */
         /* Add input. */
         transactionBuilder.addInput(_input.tx_hash, _input.tx_pos)
         transactionBuilder.addInput(_input.tx_hash, _input.tx_pos)
+
+// console.log('VALIDATING (SELF) INPUT', _input)
+//         /* Validate (our) address. */
+//         if (ourAddresses.includes(_input.address)) {
+//             ownedInputs.push(addressIdx)
+//         }
+//         addressIdx++
     })
     })
+    // console.log('OUR INPUTS INDEX', ownedInputs)
 
 
     /* Set protocol ID. */
     /* Set protocol ID. */
     protocolId = '1337'
     protocolId = '1337'
 
 
     /* Set protocol message. */
     /* Set protocol message. */
-    msg = 'finalization...'
+    msg = 'FINAL!'
 
 
     script = [
     script = [
         utf8ToBin(protocolId),
         utf8ToBin(protocolId),
@@ -71,69 +99,72 @@ console.log('SIGN SHARED TX', _sessionid, _inputs, _outputs)
         transactionBuilder.addOutput(_output.address, _output.value)
         transactionBuilder.addOutput(_output.address, _output.value)
     })
     })
 
 
-
-
     /* Convert mnemonic to seed. */
     /* Convert mnemonic to seed. */
-    const seed = mnemonicToSeed(_mnemonic)
+    // const seed = mnemonicToSeed(_mnemonic)
 
 
     /* Conver to seed buffer. */
     /* Conver to seed buffer. */
     // FIXME Migrate to TypedArrays.
     // FIXME Migrate to TypedArrays.
-    const seedBuffer = Buffer.from(seed, 'hex')
+    // const seedBuffer = Buffer.from(seed, 'hex')
 
 
     /* Generate master node. */
     /* Generate master node. */
-    const masterNode = bchjs.HDNode.fromSeed(seedBuffer)
+    // const masterNode = bchjs.HDNode.fromSeed(seedBuffer)
 
 
 // FIXME Identify our owned inputs.
 // FIXME Identify our owned inputs.
-ownedInputs = [ 0, 1, 2, 3, 4, 5, 6 ]
-// hushIndexes = [ 0, 1, 2, 3, 4, 5, 6 ]
-// 0 - L58m5XW3cYG84ZN5Cbqqap7Mvx1TihNNMPSq7Vw9W7t3oHeuS36q
-// 1 - L2qsjy4xprtF2hocseepEtKM3V6y5hHjvkX5K7zedeBjmd6forbb
-// 2 - L4FmiWogy4THbosEUHbfLgxgTQpZ1e4dFDrAoik2fvoQ9TNKCsRe
+// ownedInputs = [ 0, 1, 2, 3, 4, 5, 6 ]
+
     for (let i = 0; i < _inputs.length; i++) {
     for (let i = 0; i < _inputs.length; i++) {
+        const input = _inputs[i]
+        console.log('AN INPUT---', input)
+
+        const address = input.address
+        console.log('INPUT ADDR', address)
         /* Verify input ownership. */
         /* Verify input ownership. */
-        if (!ownedInputs.includes(i)) {
+        // if (!ownedInputs.includes(i)) {
+        // if (typeof input.wif === 'undefined' || input.wif === null) {
+        if (!ourAddresses.includes(address)) {
             continue
             continue
         }
         }
 
 
         /* Set account index. */
         /* Set account index. */
         // accountIdx = 0
         // accountIdx = 0
-        accountIdx = HUSH_PROTOCOL_ID
+        // accountIdx = HUSH_PROTOCOL_ID
         /* Set change index. */
         /* Set change index. */
-        changeIdx = 0
+        // changeIdx = 0
         /* Set address index. */
         /* Set address index. */
-        // addressIdx = 0
-        // addressIdx = hushIndexes[i]
-        addressIdx = _inputs[i].address_idx
-        console.log('ADDRESS IDX')
+        // addressIdx = _inputs[i].address_idx
+        // console.log('ADDRESS IDX')
 
 
         /* Generate child node. */
         /* Generate child node. */
-        childNode = masterNode
-            .derivePath(`m/44'/145'/${accountIdx}'/${changeIdx}/${addressIdx}`)
+        // childNode = masterNode
+        //     .derivePath(`m/44'/145'/${accountIdx}'/${changeIdx}/${addressIdx}`)
 
 
         /* Generate wallet import format (WIF). */
         /* Generate wallet import format (WIF). */
-        wif = bchjs.HDNode.toWIF(childNode)
-        // console.log('BCH WIF', i, wif)
+        // wif = bchjs.HDNode.toWIF(childNode)
+
+        /* Set WIF. */
+        wif = this.getWifForAddress(address)
+        console.log('BCH WIF', wif)
 
 
         /* Generate elliptic pair. */
         /* Generate elliptic pair. */
         ecPair = bchjs.ECPair.fromWIF(wif)
         ecPair = bchjs.ECPair.fromWIF(wif)
-console.log('PARAMS', i, redeemScript, _inputs[i].value)
+console.log('SIGNING!', i, redeemScript, input.value)
         /* Sign (our own) input. */
         /* Sign (our own) input. */
         transactionBuilder.sign(
         transactionBuilder.sign(
             i,
             i,
             ecPair,
             ecPair,
             redeemScript,
             redeemScript,
             Transaction.SIGHASH_ALL,
             Transaction.SIGHASH_ALL,
-            _inputs[i].value,
+            input.value,
         )
         )
     }
     }
 
 
     /* Generate (incomplete) transaction. */
     /* Generate (incomplete) transaction. */
-    const tx = transactionBuilder.transaction.buildIncomplete()
-    // console.log('TRANSACTION', tx)
+    const transaction = transactionBuilder.transaction.buildIncomplete()
+    // console.log('TRANSACTION', transaction)
 
 
     /* Convert to (raw) hex. */
     /* Convert to (raw) hex. */
-    rawTx = tx.toHex()
+    // rawTx = tx.toHex()
 
 
     /* Return raw (hex) transaction. */
     /* Return raw (hex) transaction. */
-    return rawTx
+    return transaction
 }
 }

+ 170 - 17
web/pages/sponsors/[...pageid].vue

@@ -19,10 +19,115 @@ console.log('NETWORK ID', networkid)
 const campaignid = route?.params?.pageid[1]
 const campaignid = route?.params?.pageid[1]
 console.log('CAMPAIGN ID', campaignid)
 console.log('CAMPAIGN ID', campaignid)
 
 
-// onMounted(() => {
-//     console.log('Mounted!')
-//     // Now it's safe to perform setup operations.
-// })
+const campaigns = ref(null)
+const campaignTitle = ref(null)
+const donationAddress = ref(null)
+const networkTitle = ref(null)
+
+const init = () => {
+    /* Handle campaign id. */
+    switch(campaignid) {
+    case 'seekers':
+        campaignTitle.value = 'Privacy Seekers'
+        break
+    case 'masters':
+        campaignTitle.value = 'Privacy Masters'
+        break
+    case 'gurus':
+        campaignTitle.value = 'Privacy Gurus'
+        break
+    }
+
+    /* Handle network id. */
+    switch(networkid) {
+    case 'btc':
+        networkTitle.value = 'Bitcoin'
+        break
+    case 'bch':
+        networkTitle.value = 'Bitcoin Cash'
+        break
+    case 'nexa':
+        networkTitle.value = 'Nexa'
+        break
+    }
+
+    /* Initialize ALL campaigns handler. */
+    campaigns.value = {}
+
+    /* Initialize Seekers handler. */
+    campaigns.value['seekers'] = {}
+
+    /* Initialize Masters handler. */
+    campaigns.value['masters'] = {}
+
+    /* Initialize Gurus handler. */
+    campaigns.value['gurus'] = {}
+
+    /* Initialize Seekers (Bitcoin) handler. */
+    campaigns.value['seekers']['btc'] = {
+        address: 'bitcoin:3Gwb2zrg64REcnDFdGHeAUMuibfpk932Kr',
+        round: 1,
+        goal: 0,
+        donated: 0,
+        hasAirdrop: true,
+        createdAt: 0,
+        updatedAt: 0,
+    }
+
+    /* Initialize Seekers (Bitcoin Cash) handler. */
+    campaigns.value['seekers']['bch'] = {
+        address: 'bitcoincash:qrqdff68n8wm757kvfumylxs47tud3fuvqz3h6depv',
+        round: 1,
+        goal: 0,
+        donated: 0,
+        hasAirdrop: true,
+        createdAt: 0,
+        updatedAt: 0,
+    }
+
+    /* Initialize Seekers (Nexa) handler. */
+    campaigns.value['seekers']['nexa'] = {
+        address: 'nexa:nqtsq5g5fxezfwrhc323dm9npzy77lay7p26x903hkk4u8zu',
+        round: 1,
+        goal: 0,
+        donated: 0,
+        hasAirdrop: true,
+        createdAt: 0,
+        updatedAt: 0,
+    }
+
+    campaigns.value['masters']['btc'] = {
+        address: 'bitcoin:3EQELPmJREqt3gVyELGYFnzLxV6Lnthudk',
+        round: 1,
+        goal: 0,
+        donated: 0,
+        hasAirdrop: true,
+        createdAt: 0,
+        updatedAt: 0,
+    }
+    campaigns.value['masters']['bch'] = {}
+    campaigns.value['masters']['nexa'] = {}
+
+    campaigns.value['gurus']['btc'] = {
+        address: 'bitcoin:34XzM3e3Tsf4wLGGcFCPRyoTP1NF6HF53z',
+        round: 1,
+        goal: 0,
+        donated: 0,
+        hasAirdrop: true,
+        createdAt: 0,
+        updatedAt: 0,
+    }
+    campaigns.value['gurus']['bch'] = {}
+    campaigns.value['gurus']['nexa'] = {}
+
+    /* Set donation address. */
+    donationAddress.value = campaigns.value[campaignid][networkid].address
+
+}
+
+onMounted(() => {
+    init()
+})
 
 
 // onBeforeUnmount(() => {
 // onBeforeUnmount(() => {
 //     console.log('Before Unmount!')
 //     console.log('Before Unmount!')
@@ -33,9 +138,13 @@ console.log('CAMPAIGN ID', campaignid)
 <template>
 <template>
     <main class="max-w-5xl mx-auto py-5 flex flex-col gap-4">
     <main class="max-w-5xl mx-auto py-5 flex flex-col gap-4">
         <h1 class="text-5xl font-medium">
         <h1 class="text-5xl font-medium">
-            Sponsors — {{ networkid }} — {{ campaignid }}
+            Sponsors for {{networkTitle}}
         </h1>
         </h1>
 
 
+        <h2 class="text-5xl font-light italic">
+            {{campaignTitle}}
+        </h2>
+
         <section class="flex flex-col gap-4">
         <section class="flex flex-col gap-4">
             <h2 class="text-rose-500 text-2xl font-bold uppercase">
             <h2 class="text-rose-500 text-2xl font-bold uppercase">
                 Do Not Send From ANY Exchange
                 Do Not Send From ANY Exchange
@@ -45,6 +154,10 @@ console.log('CAMPAIGN ID', campaignid)
                 Rewards tokens, ie $HUSH, will be sent directly to Sponsors point of delivery.
                 Rewards tokens, ie $HUSH, will be sent directly to Sponsors point of delivery.
                 In order to GUARANTEE receipt of ALL rewards, please send from a Wallet/Address that you HOLD THE KEYS.
                 In order to GUARANTEE receipt of ALL rewards, please send from a Wallet/Address that you HOLD THE KEYS.
             </p>
             </p>
+
+            <div>
+                0 of 27 campaigns completed for $HUSH airdrop!
+            </div>
         </section>
         </section>
 
 
         <section>
         <section>
@@ -63,33 +176,73 @@ console.log('CAMPAIGN ID', campaignid)
             Lorem, ipsum dolor sit amet consectetur adipisicing elit. Id eius voluptatem minus natus at eveniet dolorum eos mollitia, maxime animi excepturi harum omnis illum odit recusandae pariatur! Unde, explicabo molestias.
             Lorem, ipsum dolor sit amet consectetur adipisicing elit. Id eius voluptatem minus natus at eveniet dolorum eos mollitia, maxime animi excepturi harum omnis illum odit recusandae pariatur! Unde, explicabo molestias.
         </p>
         </p>
 
 
-        <section>
+        <NuxtLink :to="donationAddress" v-if="campaigns" class="p-5 flex flex-col gap-3 bg-sky-100 border-4 border-sky-300 rounded-3xl shadow">
+            <h3 class="text-gray-500 text-3xl font-light tracking-widest">
+                {{networkTitle}}
+            </h3>
+
+            <h3 class="font-medium tracking-tight">
+                {{donationAddress}}
+            </h3>
+        </NuxtLink>
+
+        <section v-if="campaigns">
             <h2>
             <h2>
-                Bitcoin Seekers Round 1
+                Privacy Masters
             </h2>
             </h2>
 
 
             <h3>
             <h3>
-                3FDveRn9A2cdqJqy7LDQu48crEfYLJhYDV
+                Bitcoin
             </h3>
             </h3>
-        </section>
 
 
-        <section>
-            <h2>
-                Bitcoin Cash Seekers Round 1
-            </h2>
+            <h3>
+                {{campaigns.masters.btc.address}}
+            </h3>
+
+            <h3>
+                Bitcoin Cash
+            </h3>
+
+            <h3>
+                bitcoincash:qzl4kq5wapcpae9zc7sql5hz5xmj8fqrqs5c7kgywy
+            </h3>
 
 
             <h3>
             <h3>
-                qzdyw35wslfrk6qjrcva2ujzkwv5a6ufl5uhg5xjkg
+                Nexa
+            </h3>
+
+            <h3>
+                nexa:nqtsq5g5egqz48van0zjx2xtxl38ec3czapdtryewwe5he0z
             </h3>
             </h3>
         </section>
         </section>
 
 
-        <section>
+        <section v-if="campaigns">
             <h2>
             <h2>
-                Nexa Seekers Round 1
+                Privacy Gurus
             </h2>
             </h2>
 
 
             <h3>
             <h3>
-                nexa:XXX
+                Bitcoin
+            </h3>
+
+            <h3>
+                {{campaigns.gurus.btc.address}}
+            </h3>
+
+            <h3>
+                Bitcoin Cash
+            </h3>
+
+            <h3>
+                bitcoincash:qqfk0ag6tnzgxevfzp9ma7qw0npd9vwe65v40e22a9
+            </h3>
+
+            <h3>
+                Nexa
+            </h3>
+
+            <h3>
+                nexa:nqtsq5g5ya3jv0tv36je7d8ld8vsds0vfqmt0g9lryhqnv6m
             </h3>
             </h3>
         </section>
         </section>
     </main>
     </main>

+ 106 - 20
web/pages/sponsors/index.vue

@@ -47,12 +47,16 @@ const System = useSystemStore()
         <SponsorHeading />
         <SponsorHeading />
 
 
         <div>
         <div>
-            <h2 class="text-4xl font-medium">
-                Privacy Seekers - Unlock Higher Tiers
+            <h3 class="pl-3 text-sky-300 text-2xl font-medium uppercase">
+                For Privacy Seekers
+            </h3>
+
+            <h2 class="text-sky-700 text-7xl font-light italic">
+                Unlock Higher Tiers
             </h2>
             </h2>
 
 
-            <p class="py-5">
-                Will introduce higher blending tiers for large bag holders.
+            <p class="py-5 text-gray-600 text-lg leading-7">
+                Will introduce higher CoinJoin tiers for large bag holders.
             </p>
             </p>
 
 
             <div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
             <div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
@@ -62,13 +66,17 @@ const System = useSystemStore()
                     </h2>
                     </h2>
 
 
                     <h3 class="py-2 text-sm">
                     <h3 class="py-2 text-sm">
-                        Unlock the 0.1 BTC tier for blender pools
+                        Unlock the 0.1 BTC tier for CoinJoin pools
                     </h3>
                     </h3>
 
 
                     <h3 class="px-3 py-1 bg-amber-200 text-center text-lg text-amber-900 font-medium border border-amber-400 rounded-lg shadow group-hover:bg-sky-700 group-hover:text-sky-100 group-hover:border-sky-300">
                     <h3 class="px-3 py-1 bg-amber-200 text-center text-lg text-amber-900 font-medium border border-amber-400 rounded-lg shadow group-hover:bg-sky-700 group-hover:text-sky-100 group-hover:border-sky-300">
                         <span class="text-2xl font-bold">0.100000 BTC</span>
                         <span class="text-2xl font-bold">0.100000 BTC</span>
                         <span class="block text-sm">remaining to unlock the next tier</span>
                         <span class="block text-sm">remaining to unlock the next tier</span>
                     </h3>
                     </h3>
+
+                    <p class="mt-3 text-xs text-gray-700 text-center italic">
+                        + qualified for $HUSH BRC-20 token airdrop
+                    </p>
                 </NuxtLink>
                 </NuxtLink>
 
 
                 <NuxtLink to="/sponsors/bch/seekers" class="group px-5 py-7 bg-sky-200 rounded-xl border border-sky-300 hover:bg-sky-100">
                 <NuxtLink to="/sponsors/bch/seekers" class="group px-5 py-7 bg-sky-200 rounded-xl border border-sky-300 hover:bg-sky-100">
@@ -77,13 +85,17 @@ const System = useSystemStore()
                     </h2>
                     </h2>
 
 
                     <h3 class="py-2 text-sm">
                     <h3 class="py-2 text-sm">
-                        Unlock the 10 BCH tier for blender pools
+                        Unlock the 10 BCH tier for CoinJoin pools
                     </h3>
                     </h3>
 
 
                     <h3 class="px-3 py-1 bg-amber-200 text-center text-lg text-amber-900 font-medium border border-amber-400 rounded-lg shadow group-hover:bg-sky-700 group-hover:text-sky-100 group-hover:border-sky-300">
                     <h3 class="px-3 py-1 bg-amber-200 text-center text-lg text-amber-900 font-medium border border-amber-400 rounded-lg shadow group-hover:bg-sky-700 group-hover:text-sky-100 group-hover:border-sky-300">
                         <span class="text-2xl font-bold">10.000000 BCH</span>
                         <span class="text-2xl font-bold">10.000000 BCH</span>
                         <span class="block text-sm">remaining to unlock the next tier</span>
                         <span class="block text-sm">remaining to unlock the next tier</span>
                     </h3>
                     </h3>
+
+                    <p class="mt-3 text-xs text-gray-700 text-center italic">
+                        + qualified for $HUSH cash token airdrop
+                    </p>
                 </NuxtLink>
                 </NuxtLink>
 
 
                 <NuxtLink to="/sponsors/nexa/seekers" class="group px-5 py-7 bg-sky-200 rounded-xl border border-sky-300 hover:bg-sky-100">
                 <NuxtLink to="/sponsors/nexa/seekers" class="group px-5 py-7 bg-sky-200 rounded-xl border border-sky-300 hover:bg-sky-100">
@@ -92,12 +104,16 @@ const System = useSystemStore()
                     </h2>
                     </h2>
 
 
                     <h3 class="py-2 text-sm">
                     <h3 class="py-2 text-sm">
-                        Adding 1B NEXA, 10B NEXA and 100B NEXA blender pools
+                        Adding 1B NEXA, 10B NEXA and 100B NEXA CoinJoin pools
                     </h3>
                     </h3>
 
 
                     <h3 class="px-3 py-1 bg-amber-200 text-lg text-amber-900 font-medium border border-amber-400 rounded-lg shadow group-hover:bg-sky-700 group-hover:text-sky-100 group-hover:border-sky-300">
                     <h3 class="px-3 py-1 bg-amber-200 text-lg text-amber-900 font-medium border border-amber-400 rounded-lg shadow group-hover:bg-sky-700 group-hover:text-sky-100 group-hover:border-sky-300">
                         <span class="text-2xl font-bold">1.00B NEXA</span> to unlock next tier
                         <span class="text-2xl font-bold">1.00B NEXA</span> to unlock next tier
                     </h3>
                     </h3>
+
+                    <p class="mt-3 text-xs text-gray-700 text-center italic">
+                        + qualified for $HUSH native token airdrop
+                    </p>
                 </NuxtLink>
                 </NuxtLink>
 
 
                 <div class="cursor-not-allowed group px-5 py-7 bg-sky-200 rounded-xl border border-sky-300 opacity-30">
                 <div class="cursor-not-allowed group px-5 py-7 bg-sky-200 rounded-xl border border-sky-300 opacity-30">
@@ -106,7 +122,7 @@ const System = useSystemStore()
                     </h2>
                     </h2>
 
 
                     <h3 class="py-2 text-sm">
                     <h3 class="py-2 text-sm">
-                        Adding 50 LTC, 500 LTC and 5K LTC blender pools
+                        Adding 50 LTC, 500 LTC and 5K LTC CoinJoin pools
                     </h3>
                     </h3>
 
 
                     <h3 class="px-3 py-1 bg-amber-200 text-lg text-amber-900 font-medium border border-amber-400 rounded-lg shadow">
                     <h3 class="px-3 py-1 bg-amber-200 text-lg text-amber-900 font-medium border border-amber-400 rounded-lg shadow">
@@ -120,7 +136,7 @@ const System = useSystemStore()
                     </h2>
                     </h2>
 
 
                     <h3 class="py-2 text-sm">
                     <h3 class="py-2 text-sm">
-                        Adding 5K FLUX, 50K FLUX and 500K FLUX blender pools
+                        Adding 5K FLUX, 50K FLUX and 500K FLUX CoinJoin pools
                     </h3>
                     </h3>
 
 
                     <h3 class="px-3 py-1 bg-amber-200 text-lg text-amber-900 font-medium border border-amber-400 rounded-lg shadow">
                     <h3 class="px-3 py-1 bg-amber-200 text-lg text-amber-900 font-medium border border-amber-400 rounded-lg shadow">
@@ -134,7 +150,7 @@ const System = useSystemStore()
                     </h2>
                     </h2>
 
 
                     <h3 class="py-2 text-sm">
                     <h3 class="py-2 text-sm">
-                        Adding 5K XEC, 50K XEC and 500K XEC blender pools
+                        Adding 5K XEC, 50K XEC and 500K XEC CoinJoin pools
                     </h3>
                     </h3>
 
 
                     <h3 class="px-3 py-1 bg-amber-200 text-lg text-amber-900 font-medium border border-amber-400 rounded-lg shadow">
                     <h3 class="px-3 py-1 bg-amber-200 text-lg text-amber-900 font-medium border border-amber-400 rounded-lg shadow">
@@ -142,19 +158,64 @@ const System = useSystemStore()
                     </h3>
                     </h3>
                 </div>
                 </div>
 
 
-                <!-- <div class="cursor-not-allowed group px-5 py-7 bg-sky-200 rounded-xl border border-sky-300 opacity-30">
+                <div class="cursor-not-allowed group px-5 py-7 bg-sky-200 rounded-xl border border-sky-300 opacity-30">
+                    <h2 class="text-xl text-gray-700 font-medium tracking-widest uppercase">
+                        Doge
+                    </h2>
+
+                    <h3 class="py-2 text-sm">
+                        Adding 5K DOGE, 50K DOGE and 500K DOGE CoinJoin pools
+                    </h3>
+
+                    <h3 class="px-3 py-1 bg-amber-200 text-lg text-amber-900 font-medium border border-amber-400 rounded-lg shadow">
+                        <span class="text-2xl font-bold">5K DOGE</span> to unlock next tier
+                    </h3>
+                </div>
+
+                <div class="cursor-not-allowed group px-5 py-7 bg-sky-200 rounded-xl border border-sky-300 opacity-30">
                     <h2 class="text-xl text-gray-700 font-medium tracking-widest uppercase">
                     <h2 class="text-xl text-gray-700 font-medium tracking-widest uppercase">
                         Dash
                         Dash
                     </h2>
                     </h2>
 
 
                     <h3 class="py-2 text-sm">
                     <h3 class="py-2 text-sm">
-                        Adding 5K DASH, 50K DASH and 500K DASH blender pools
+                        Adding 5K DASH, 50K DASH and 500K DASH CoinJoin pools
                     </h3>
                     </h3>
 
 
                     <h3 class="px-3 py-1 bg-amber-200 text-lg text-amber-900 font-medium border border-amber-400 rounded-lg shadow">
                     <h3 class="px-3 py-1 bg-amber-200 text-lg text-amber-900 font-medium border border-amber-400 rounded-lg shadow">
                         <span class="text-2xl font-bold">5K DASH</span> to unlock next tier
                         <span class="text-2xl font-bold">5K DASH</span> to unlock next tier
                     </h3>
                     </h3>
-                </div> -->
+                </div>
+
+                <div class="cursor-not-allowed group px-5 py-7 bg-sky-200 rounded-xl border border-sky-300 opacity-30">
+                    <h2 class="text-xl text-gray-700 font-medium tracking-widest uppercase">
+                        Kaspa
+                    </h2>
+
+                    <h3 class="py-2 text-sm">
+                        Adding 50K KAS, 500K KAS and 5M KAS CoinJoin pools
+                    </h3>
+
+                    <h3 class="px-3 py-1 bg-amber-200 text-lg text-amber-900 font-medium border border-amber-400 rounded-lg shadow">
+                        <span class="text-2xl font-bold">50K KAS</span> to unlock next tier
+                    </h3>
+                </div>
+
+                <div class="cursor-help group px-5 py-7 bg-sky-200 rounded-xl border border-sky-300">
+                    <h2 class="flex items-center gap-2 text-xl text-rose-700 font-medium tracking-widest uppercase">
+                        Sponsors Vote
+
+                        <!-- <svg class="h-8 w-auto" data-slot="icon" fill="none" stroke-width="1.5" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
+                            <path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5"></path>
+                        </svg> -->
+                        <svg class="h-8 w-auto" data-slot="icon" fill="none" stroke-width="1.5" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
+                            <path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75 11.25 15 15 9.75M21 12c0 1.268-.63 2.39-1.593 3.068a3.745 3.745 0 0 1-1.043 3.296 3.745 3.745 0 0 1-3.296 1.043A3.745 3.745 0 0 1 12 21c-1.268 0-2.39-.63-3.068-1.593a3.746 3.746 0 0 1-3.296-1.043 3.745 3.745 0 0 1-1.043-3.296A3.745 3.745 0 0 1 3 12c0-1.268.63-2.39 1.593-3.068a3.745 3.745 0 0 1 1.043-3.296 3.746 3.746 0 0 1 3.296-1.043A3.746 3.746 0 0 1 12 3c1.268 0 2.39.63 3.068 1.593a3.746 3.746 0 0 1 3.296 1.043 3.746 3.746 0 0 1 1.043 3.296A3.745 3.745 0 0 1 21 12Z"></path>
+                        </svg>
+                    </h2>
+
+                    <p class="py-2 text-sm italic leading-6">
+                        All Sponsors will be invited to vote for the <span class="font-bold">FINAL network integration</span> into the inaugural launch of the HYM cloud network, before <span class="font-bold">"locking in $HUSH rewards"</span> and moving on to Phase II (Zero-Knowledge + Incognito Cash).
+                    </p>
+                </div>
 
 
             </div>
             </div>
 
 
@@ -164,11 +225,15 @@ const System = useSystemStore()
         <SponsorHeading />
         <SponsorHeading />
 
 
         <div>
         <div>
-            <h2 class="text-4xl font-medium">
-                Privacy Masters - Wallet Integrations + Dev Kits
+            <h3 class="pl-3 text-sky-300 text-2xl font-medium uppercase">
+                For Privacy Masters
+            </h3>
+
+            <h2 class="text-sky-700 text-7xl font-light italic">
+                Wallet Integrations + Dev Kits
             </h2>
             </h2>
 
 
-            <p class="py-5">
+            <p class="py-5 text-gray-600 text-lg leading-7">
                 Will offer native integration with the ecosystem's MOST popular wallets.
                 Will offer native integration with the ecosystem's MOST popular wallets.
             </p>
             </p>
 
 
@@ -209,6 +274,10 @@ const System = useSystemStore()
                             Unstoppable wallet
                             Unstoppable wallet
                         </li>
                         </li>
                     </ol>
                     </ol>
+
+                    <p class="mt-3 text-xs text-gray-700 text-center italic">
+                        + qualified for $HUSH BRC-20 token airdrop
+                    </p>
                 </NuxtLink>
                 </NuxtLink>
 
 
                 <section>
                 <section>
@@ -328,12 +397,17 @@ const System = useSystemStore()
         <SponsorHeading />
         <SponsorHeading />
 
 
         <div>
         <div>
-            <h2 class="text-4xl font-medium">
-                Privacy Gurus - Native Apps
+            <h3 class="pl-3 text-sky-300 text-2xl font-medium uppercase">
+                For Privacy Gurus
+            </h3>
+
+            <h2 class="text-sky-700 text-7xl font-light italic">
+                Incognito Cash Apps
             </h2>
             </h2>
 
 
-            <p class="py-5">
-                Will introduce native Android and iOS applications.
+            <p class="py-5 text-gray-600 text-lg leading-7">
+                We will introduce native Android and iOS applications to support the NEW Incognito network
+                — supporting ALL networks with $NITO native assets.
             </p>
             </p>
 
 
             <div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
             <div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
@@ -359,6 +433,10 @@ const System = useSystemStore()
                         <li>Mac desktop app</li>
                         <li>Mac desktop app</li>
                         <li>Linux desktop app</li>
                         <li>Linux desktop app</li>
                     </ol>
                     </ol>
+
+                    <p class="mt-3 text-xs text-gray-700 text-center italic">
+                        + qualified for $HUSH BRC-20 token airdrop
+                    </p>
                 </NuxtLink>
                 </NuxtLink>
 
 
                 <div class="cursor-not-allowed group px-5 py-7 bg-sky-200 rounded-xl border border-sky-300 opacity-30">
                 <div class="cursor-not-allowed group px-5 py-7 bg-sky-200 rounded-xl border border-sky-300 opacity-30">
@@ -383,6 +461,10 @@ const System = useSystemStore()
                         <li>Mac desktop app</li>
                         <li>Mac desktop app</li>
                         <li>Linux desktop app</li>
                         <li>Linux desktop app</li>
                     </ol>
                     </ol>
+
+                    <p class="mt-3 text-xs text-gray-700 text-center italic">
+                        + qualified for $HUSH cash token airdrop
+                    </p>
                 </div>
                 </div>
 
 
                 <div class="cursor-not-allowed group px-5 py-7 bg-sky-200 rounded-xl border border-sky-300 opacity-30">
                 <div class="cursor-not-allowed group px-5 py-7 bg-sky-200 rounded-xl border border-sky-300 opacity-30">
@@ -407,6 +489,10 @@ const System = useSystemStore()
                         <li>Mac desktop app</li>
                         <li>Mac desktop app</li>
                         <li>Linux desktop app</li>
                         <li>Linux desktop app</li>
                     </ol>
                     </ol>
+
+                    <p class="mt-3 text-xs text-gray-700 text-center italic">
+                        + qualified for $HUSH native token airdrop
+                    </p>
                 </div>
                 </div>
 
 
             </div>
             </div>

+ 55 - 6
web/server/routes/v1.post.ts

@@ -28,6 +28,7 @@ export default defineEventHandler(async (event) => {
     let response
     let response
     let session
     let session
     let success
     let success
+    let unlocked
 
 
     /* Set database. */
     /* Set database. */
     const Db = event.context.Db
     const Db = event.context.Db
@@ -58,11 +59,23 @@ export default defineEventHandler(async (event) => {
     // const rawTx = body.rawTx
     // const rawTx = body.rawTx
     // console.log('RAW TRANSACTION', rawTx)
     // console.log('RAW TRANSACTION', rawTx)
 
 
-    components = body.components
-    components = decryptForPubkey(binToHex(Wallet.privateKey), components)
-    components = binToUtf8(components)
-    components = JSON.parse(components)
-    console.log('COMPONENTS', components)
+    /* Validate components. */
+    if (body.components) {
+        components = body.components
+        components = decryptForPubkey(binToHex(Wallet.privateKey), components)
+        components = binToUtf8(components)
+        components = JSON.parse(components)
+        console.log('COMPONENTS', components)
+    }
+
+    /* Validate unlocked. */
+    if (body.unlocked) {
+        unlocked = body.unlocked
+        unlocked = decryptForPubkey(binToHex(Wallet.privateKey), unlocked)
+        unlocked = binToUtf8(unlocked)
+        unlocked = JSON.parse(unlocked)
+        console.log('UNLOCKED', unlocked)
+    }
 
 
     /* Validate auth ID. */
     /* Validate auth ID. */
     if (typeof authid === 'undefined' || authid === null) {
     if (typeof authid === 'undefined' || authid === null) {
@@ -118,6 +131,42 @@ console.log('FUSION', fusion)
         return 'Oops! Authorization failed!'
         return 'Oops! Authorization failed!'
     }
     }
 
 
+
+
+    if (actionid === 'unlock-components') {
+        /* Update progress. */
+        // fusion.progress = 75.5
+
+        /* Set (new) updated at (timestamp). */
+        fusion.updatedAt = moment().unix()
+
+        console.log('***UNLOCK COMPONENT(S)***', unlocked)
+        // await Db.put('fusions', '4e9654f9-3de9-4f9a-8169-3834f40847f5', fusion)
+
+        const inputs = fusion.inputs
+        console.log('INPUTS', inputs)
+
+        /* Handle inputs. */
+        Object.keys(inputs).forEach(_outpoint => {
+console.log('OUTPOINT', _outpoint)
+            /* Handle unlocked (scripts). */
+            Object.keys(unlocked).forEach(_lockpoint => {
+console.log('LOCKPOINT', _lockpoint)
+                const unlock = unlocked[_lockpoint]
+console.log('UNLOCK', unlock)
+                /* Validate transaction hash. */
+                if (inputs[_outpoint].tx_hash === unlock.tx_hash) {
+console.log('FOUND A MATCH', unlock.tx_hash)
+                    /* Set unlocking script. */
+                    inputs[_outpoint].unlocking = unlock.unlocking
+                }
+            })
+        })
+console.log('UPDATED FUSION', fusion)
+        return 'almost there...'
+    }
+
+
     fusion.numGuests = Object.keys(fusion.guests).length
     fusion.numGuests = Object.keys(fusion.guests).length
 
 
     /* Update progress. */
     /* Update progress. */
@@ -130,7 +179,7 @@ console.log('FUSION', fusion)
             componentid = sha256(_component.tx_hash + ':' + _component.tx_pos)
             componentid = sha256(_component.tx_hash + ':' + _component.tx_pos)
             fusion.inputs[componentid] = {
             fusion.inputs[componentid] = {
                 ..._component,
                 ..._component,
-                signature: null,
+                unlocking: null,
             }
             }
         }
         }
 
 

+ 83 - 34
web/stores/wallet.ts

@@ -3,14 +3,20 @@ import { defineStore } from 'pinia'
 import moment from 'moment'
 import moment from 'moment'
 
 
 import BCHJS from '@psf/bch-js'
 import BCHJS from '@psf/bch-js'
-import { mnemonicToEntropy } from '@nexajs/hdnode'
+import { sha256 } from '@nexajs/crypto'
+import {
+    mnemonicToEntropy,
+    mnemonicToSeed,
+} from '@nexajs/hdnode'
 import { Wallet } from '@nexajs/wallet'
 import { Wallet } from '@nexajs/wallet'
 
 
 import _broadcast from './wallet/broadcast.ts'
 import _broadcast from './wallet/broadcast.ts'
 import _completeFusion from './wallet/completeFusion.ts'
 import _completeFusion from './wallet/completeFusion.ts'
+import _getWifForAddress from './wallet/getWifForAddress.ts'
 import _setEntropy from './wallet/setEntropy.ts'
 import _setEntropy from './wallet/setEntropy.ts'
 import _setupKeychain from './wallet/setupKeychain.ts'
 import _setupKeychain from './wallet/setupKeychain.ts'
 import _setupHushKeychain from './wallet/setupHushKeychain.ts'
 import _setupHushKeychain from './wallet/setupHushKeychain.ts'
+import _signFusion from './wallet/signFusion.ts'
 import _startFusion from './wallet/startFusion.ts'
 import _startFusion from './wallet/startFusion.ts'
 
 
 /* Initialize constants. */
 /* Initialize constants. */
@@ -142,32 +148,25 @@ export const useWalletStore = defineStore('wallet', {
                 return null
                 return null
             }
             }
 
 
-            const collection = _state._utxos
-            // console.log('COLLECTION (fusionInputs)', collection)
+            // const collection = _state._utxos
+            console.log('STATE (utxos)', _state._utxos)
 
 
-            const mainList = []
+            /* Initialize inputs (collection). */
+            let inputs = {}
 
 
-            collection[0]?.forEach(_account => {
-                // console.log('ACCOUNT (0)', _account)
-                _account.utxos.forEach(_utxo => {
-                    mainList.push({
-                        address: _account.address,
-                        ..._utxo,
-                    })
-                })
-            })
+            /* Verify Main chain. */
+            if (_state._utxos[0]) {
+                inputs = { ...inputs, ..._state._utxos[0] }
+            }
 
 
-            collection[HUSH_PROTOCOL_ID]?.forEach(_account => {
-                // console.log('ACCOUNT (1213551432)', _account)
-                _account.utxos.forEach(_utxo => {
-                    mainList.push({
-                        address: _account.address,
-                        ..._utxo,
-                    })
-                })
-            })
+            /* Verify Hush chain. */
+            if (_state._utxos[HUSH_PROTOCOL_ID]) {
+                inputs = { ...inputs, ..._state._utxos[HUSH_PROTOCOL_ID] }
+            }
+            console.log('FUSION (inputs)', inputs)
 
 
-            return mainList
+            /* Return inputs. */
+            return inputs
         },
         },
 
 
         fusionAddrs() {
         fusionAddrs() {
@@ -275,17 +274,17 @@ _setupHushKeychain.bind(this)()
          * Will return the "child" address of a master node,
          * Will return the "child" address of a master node,
          * based on the account index, change flag and address index.
          * based on the account index, change flag and address index.
          */
          */
-        async getBchAddress(
+        getBchAddress(
             _accountIdx = 0,
             _accountIdx = 0,
             _isChange = 0, // NOTE: 0 = false, 1 = true
             _isChange = 0, // NOTE: 0 = false, 1 = true
             _addressIdx = 0,
             _addressIdx = 0,
         ) {
         ) {
             /* Set root seed. */
             /* Set root seed. */
-            const rootSeed = await bchjs.Mnemonic.toSeed(this.mnemonic)
+            const rootSeed = mnemonicToSeed(this.mnemonic)
             // console.log('rootSeed', rootSeed)
             // console.log('rootSeed', rootSeed)
 
 
             /* Set HD master node. */
             /* Set HD master node. */
-            const masterHdnode = bchjs.HDNode.fromSeed(rootSeed)
+            const masterHdnode = bchjs.HDNode.fromSeed(Buffer.from(rootSeed, 'hex') )
             // console.log('masterHdnode', masterHdnode);
             // console.log('masterHdnode', masterHdnode);
 
 
             /* Set child node. */
             /* Set child node. */
@@ -336,7 +335,25 @@ _setupHushKeychain.bind(this)()
             console.log('HUSH UTXOS', data)
             console.log('HUSH UTXOS', data)
 
 
             // FIXME Update the deltas ONLY!
             // FIXME Update the deltas ONLY!
-            // this._utxos[HUSH_PROTOCOL_ID] = data?.utxos
+            this._utxos[HUSH_PROTOCOL_ID] = {}
+
+            /* Handle unspent outputs. */
+            data.forEach(_unspent => {
+                _unspent.utxos.forEach(_utxo => {
+                    // console.log('ADDING HUSH UTXO...', _utxo)
+
+                    /* Generate outpoint (hash). */
+                    const outpoint = sha256(_utxo.tx_hash + ':' + _utxo.tx_pos)
+
+                    /* Add to UTXOs. */
+                    this._utxos[HUSH_PROTOCOL_ID][outpoint] = {
+                        address: _unspent.address,
+                        ..._utxo,
+                        wif: _getWifForAddress.bind(this)(_unspent.address),
+                    }
+                })
+            })
+
 
 
             /* Request history data. */
             /* Request history data. */
             data = await $fetch('/api/electrum', {
             data = await $fetch('/api/electrum', {
@@ -377,16 +394,13 @@ _setupHushKeychain.bind(this)()
                 let bchAddress2
                 let bchAddress2
                 let bchAddress3
                 let bchAddress3
 
 
-                bchAddress1 = await this.getBchAddress(0, 0, 0)
-                    .catch(err => console.error(err))
+                bchAddress1 = this.getBchAddress(0, 0, 0)
                 // console.log('BCH ADDRESS-1', bchAddress1)
                 // console.log('BCH ADDRESS-1', bchAddress1)
 
 
-                bchAddress2 = await this.getBchAddress(0, 0, 1)
-                    .catch(err => console.error(err))
+                bchAddress2 = this.getBchAddress(0, 0, 1)
                 // console.log('BCH ADDRESS-2', bchAddress2)
                 // console.log('BCH ADDRESS-2', bchAddress2)
 
 
-                bchAddress3 = await this.getBchAddress(0, 0, 2)
-                    .catch(err => console.error(err))
+                bchAddress3 = this.getBchAddress(0, 0, 2)
                 // console.log('BCH ADDRESS-3', bchAddress3)
                 // console.log('BCH ADDRESS-3', bchAddress3)
 
 
                 data = await $fetch('/api/electrum', {
                 data = await $fetch('/api/electrum', {
@@ -402,8 +416,29 @@ _setupHushKeychain.bind(this)()
                 })
                 })
                 console.log('MAIN WALLET DATA', data)
                 console.log('MAIN WALLET DATA', data)
 
 
+                // if (!this._utxos[0]) {
+                    this._utxos[0] = {}
+                // }
+
+                /* Handle unspent outputs. */
+                data.forEach(_unspent => {
+                    _unspent.utxos.forEach(_utxo => {
+                        console.log('ADDING UTXO...', _utxo)
+
+                        /* Generate outpoint (hash). */
+                        const outpoint = sha256(_utxo.tx_hash + ':' + _utxo.tx_pos)
+
+                        /* Add to UTXOs. */
+                        this._utxos[0][outpoint] = {
+                            address: _unspent.address,
+                            ..._utxo,
+                            wif: _getWifForAddress.bind(this)(_unspent.address),
+                        }
+                    })
+                })
+
                 // FIXME Update the delta ONLY!
                 // FIXME Update the delta ONLY!
-                this._utxos[0] = data?.utxos
+                // this._utxos[0] = data?.utxos
             }
             }
 
 
             return true
             return true
@@ -439,11 +474,25 @@ _setupHushKeychain.bind(this)()
             }
             }
         },
         },
 
 
+        /**
+         * Get WIF for Address
+         *
+         * TBD..
+         */
+        getWifForAddress(_address) {
+            return _getWifForAddress.bind(this)(_address)
+        },
+
         async startFusion() {
         async startFusion() {
             /* Start fusions. */
             /* Start fusions. */
             return _startFusion.bind(this)()
             return _startFusion.bind(this)()
         },
         },
 
 
+        async signFusion() {
+            /* Start fusions. */
+            return _signFusion.bind(this)()
+        },
+
         async completeFusion() {
         async completeFusion() {
             /* Start fusions. */
             /* Start fusions. */
             return _completeFusion.bind(this)()
             return _completeFusion.bind(this)()

+ 83 - 15
web/stores/wallet/completeFusion.ts

@@ -1,5 +1,8 @@
 /* Import modules. */
 /* Import modules. */
-import signSharedTx from '../../handlers/signSharedTx.ts'
+import { TransactionBuilder } from 'bitcoinjs-lib'
+import { hexToBin } from '@nexajs/utils'
+
+import buildSharedTx from '../../handlers/buildSharedTx.ts'
 
 
 const DUST_VAL = 546
 const DUST_VAL = 546
 
 
@@ -23,14 +26,14 @@ export default async function () {
 
 
     /* Set inputs. */
     /* Set inputs. */
     inputs = session.inputs
     inputs = session.inputs
-    // console.log('INPUTS', inputs)
+    console.log('INPUTS', inputs)
 
 
     /* Initialize keys. */
     /* Initialize keys. */
     keys = []
     keys = []
 
 
     /* Handle (input) keys. */
     /* Handle (input) keys. */
-    Object.keys(inputs).forEach(_inputid => {
-        keys.push(_inputid)
+    Object.keys(inputs).forEach(_outpoint => {
+        keys.push(_outpoint)
     })
     })
     // console.log('KEYS', keys)
     // console.log('KEYS', keys)
 
 
@@ -48,13 +51,13 @@ export default async function () {
         console.log('HANDLE INPUT', input)
         console.log('HANDLE INPUT', input)
 
 
         /* Find address index for input. */
         /* Find address index for input. */
-        for (let i = 0; i < this.fusionInputs.length; i++) {
-            if (this.fusionInputs[i].address === input.address) {
-                input.address_idx = i
-                console.log('ADDRESS INDEX', i)
-                break
-            }
-        }
+        // for (let i = 0; i < this.fusionInputs.length; i++) {
+        //     if (this.fusionInputs[i].address === input.address) {
+        //         input.address_idx = i
+        //         console.log('ADDRESS INDEX', i)
+        //         break
+        //     }
+        // }
 
 
         /* Add input. */
         /* Add input. */
         sortedInputs.push(input)
         sortedInputs.push(input)
@@ -90,11 +93,76 @@ export default async function () {
     // console.log('OUTPUTS (sorted)', sortedOutputs)
     // console.log('OUTPUTS (sorted)', sortedOutputs)
 
 
     /* Sign shared transaction. */
     /* Sign shared transaction. */
-    rawTx = signSharedTx(
-        sessionid, this.mnemonic, sortedInputs, sortedOutputs)
-    console.log('RAW TX', rawTx)
+    const transactionBuilder = buildSharedTx.bind(this)(
+        sessionid, sortedInputs, sortedOutputs)
+// transactionBuilder.transaction.tx.ins[0].script = script
+    console.log('FINALIZED TRANSACTION', transactionBuilder)
+
+// console.log('UNLOCKING', inputs['185ad6a10ea70d977d943a910f54dc446163a16771017c6df35c7893c1db0c35'])
+
+
+    const transaction = transactionBuilder.transaction.buildIncomplete()
+    // const transaction = transactionBuilder.transaction
+    console.log('TRANSACTION', transaction)
+
+const scripts = []
+Object.keys(inputs).forEach(_outpoint => {
+    const input = inputs[_outpoint]
+    console.log('SCRIPT INPUT', input)
 
 
-    response = await this.broadcast('BCH', rawTx)
+    scripts.push({
+        id: _outpoint,
+        script: Buffer.from(input.unlocking, 'hex')
+    })
+})
+console.log('SCRIPTS', scripts)
+// const script = Buffer.from(hexToBin(inputs['185ad6a10ea70d977d943a910f54dc446163a16771017c6df35c7893c1db0c35'].unlocking))
+// console.log('SCRIPT', script)
+    // transaction.ins[0].script = script
+    transaction.ins[0].script = scripts[0].script
+    console.log('TRANSACTION (hex)', transaction.toHex())
+
+    // transaction.ins[0].script = Buffer.from(hexToBin(inputs['185ad6a10ea70d977d943a910f54dc446163a16771017c6df35c7893c1db0c35'].unlocking))
+
+    // const transaction2 = transactionBuilder.transaction.build()
+
+    // const transactionBuilder2 = TransactionBuilder.fromTransaction(
+    //     transaction,
+    //     'mainnet'
+    //   )
+    // console.log('TX BUILDER-2', transactionBuilder2)
+
+      // build tx
+    //   const tx = transactionBuilder2.build()
+    //   const tx = transactionBuilder2.transaction.buildIncomplete()
+    //   console.log('TX BUILDER 2', tx)
+    //   // output rawhex
+    //   const txHex = tx.toHex()
+    //   console.log('TX HEX', txHex)
+
+    /* Convert to (raw) hex. */
+    // rawTx = tx.toHex()
+
+    response = await this.broadcast('BCH', transaction.toHex())
         .catch(err => console.error(err))
         .catch(err => console.error(err))
     console.log('BROADCAST (response)', response)
     console.log('BROADCAST (response)', response)
 }
 }
+
+
+    // // Overwrite the tx inputs of the first partially-signed TX with the signed
+    // // inputs from the other two transactions.
+    // txObj.ins[1].script = txObj2.ins[1].script
+    // txObj.ins[2].script = txObj3.ins[2].script
+
+    // // console.log(`Fully-signed txObj.ins: ${JSON.stringify(txObj.ins, null, 2)}`)
+
+    // // Port the transaction object into the TransactionBuilder.
+    // const transactionBuilder = Bitcoin.TransactionBuilder.fromTransaction(
+    //   txObj,
+    //   'mainnet'
+    // )
+
+    // // build tx
+    // const tx = transactionBuilder.build()
+    // // output rawhex
+    // const txHex = tx.toHex()

+ 81 - 0
web/stores/wallet/getWifForAddress.ts

@@ -0,0 +1,81 @@
+/* Import modules. */
+import BCHJS from '@psf/bch-js'
+import { mnemonicToSeed } from '@nexajs/hdnode'
+
+/* Initialize BCHJS. */
+const bchjs = new BCHJS()
+
+/* Initialize constants. */
+const HUSH_PROTOCOL_ID = 0x48555348
+
+
+/**
+ * Get WIF For An Address
+ *
+ * Will return the wallet import format (WIF) for a specific address.
+ */
+export default function (_address) {
+    /* Initialize locals. */
+    let accountIdx
+    let addressIdx
+    let changeIdx
+    let childNode
+    let mainAddress
+    let wif
+
+    /* Set main (wallet) address. */
+    mainAddress = this.getBchAddress(0, 0, 0)
+
+    if (mainAddress === _address) {
+        /* Set account index. */
+        accountIdx = 0 // NOTE: This is the Main chain
+
+        /* Set address index. */
+        addressIdx = 0
+    } else {
+        /* Set account index. */
+        accountIdx = HUSH_PROTOCOL_ID // NOTE: This is the Hush chain
+
+        /* Handle fusion addresses. */
+        Object.keys(this.fusionAddrs).forEach(_addressIdx => {
+            /* Set fusion address. */
+            const fusionAddress = this.fusionAddrs[_addressIdx]
+
+            /* Validate address. */
+            if (_address === fusionAddress.address) {
+                /* Set address index. */
+                addressIdx = _addressIdx
+            }
+        })
+    }
+    // console.log('ACCOUNT IDX', accountIdx)
+    // console.log('ADDRESS IDX', addressIdx)
+
+    if (typeof addressIdx === 'undefined' || addressIdx === null) {
+        throw new Error(`Oops! There is NO private key for [ ${_address} ]`)
+    }
+
+    /* Set change index. */
+    changeIdx = 0
+
+    /* Convert mnemonic to seed. */
+    const seed = mnemonicToSeed(this.mnemonic)
+
+    /* Conver to seed buffer. */
+    // FIXME Migrate to TypedArrays.
+    const seedBuffer = Buffer.from(seed, 'hex')
+
+    /* Generate master node. */
+    const masterNode = bchjs.HDNode.fromSeed(seedBuffer)
+
+    /* Generate child node. */
+    childNode = masterNode
+        .derivePath(`m/44'/145'/${accountIdx}'/${changeIdx}/${addressIdx}`)
+
+    /* Generate wallet import format (WIF). */
+    wif = bchjs.HDNode.toWIF(childNode)
+    // console.log('BCH WIF', i, wif)
+
+    /* Return WIF. */
+    return wif
+}

+ 1 - 1
web/stores/wallet/setupHushKeychain.ts

@@ -18,7 +18,7 @@ export default async function () {
         /* Set address index. */
         /* Set address index. */
         addressIdx = i
         addressIdx = i
 
 
-        address = await this.getBchAddress(HUSH_PROTOCOL_ID, CHANGE_IDX, addressIdx)
+        address = this.getBchAddress(HUSH_PROTOCOL_ID, CHANGE_IDX, addressIdx)
 
 
         pkg = {
         pkg = {
             address,
             address,

+ 1 - 1
web/stores/wallet/setupKeychain.ts

@@ -18,7 +18,7 @@ export default async function () {
         /* Set address index. */
         /* Set address index. */
         addressIdx = i
         addressIdx = i
 
 
-        address = await this.getBchAddress(PROTOCOL_ID, CHANGE_IDX, addressIdx)
+        address = this.getBchAddress(PROTOCOL_ID, CHANGE_IDX, addressIdx)
 
 
         pkg = {
         pkg = {
             address,
             address,

+ 160 - 0
web/stores/wallet/signFusion.ts

@@ -0,0 +1,160 @@
+/* Import modules. */
+import { encryptForPubkey } from '@nexajs/crypto'
+import { binToHex } from '@nexajs/utils'
+
+import signSharedTx from '../../handlers/signSharedTx.ts'
+
+const DUST_VAL = 546
+
+export default async function () {
+    /* Initialize locals. */
+    let blindComponents
+    let clubWallet
+    let inputs
+    let keys
+    let outputs
+    let publicKey
+    // let rawTx
+    let response
+    let session
+    let sessionid
+    let transaction
+
+    // FIXME Where do we get the session ID from??
+    sessionid = '4e9654f9-3de9-4f9a-8169-3834f40847f5'
+
+    /* Request session details. */
+    session = await $fetch(`http://localhost:39159/v1/fusion/${sessionid}`)
+        .catch(err => console.error(err))
+    console.log('SESSION', session)
+
+    /* Set inputs. */
+    inputs = session.inputs
+    // console.log('INPUTS', inputs)
+
+    /* Initialize keys. */
+    keys = []
+
+    /* Handle (input) keys. */
+    Object.keys(inputs).forEach(_inputid => {
+        keys.push(_inputid)
+    })
+    // console.log('KEYS', keys)
+
+    /* Sort (input) keys. */
+    keys.sort()
+    // console.log('KEYS (sorted)', keys)
+
+    /* Initialize sorted inputs. */
+    const sortedInputs = []
+
+    /* Handle (input) keys. */
+    keys.forEach(_keyid => {
+        /* Set input. */
+        const input = inputs[_keyid]
+        console.log('HANDLE INPUT', input)
+
+        // let addressIdx = 0
+
+        // /* Find address index for input. */
+        // Object.keys(this.fusionInputs).forEach(_outpoint => {
+        //     /* Set fusion input. */
+        //     const fusionInput = this.fusionInputs[_outpoint]
+        //     console.log('FUSION INPUT', fusionInput)
+
+        //     if (fusionInput.address === input.address) {
+        //         input.address_idx = addressIdx
+        //         console.log('ADDED ADDRESS INDEX', addressIdx)
+        //         // break
+        //     }
+
+        //     addressIdx++
+        // })
+
+        /* Add input. */
+        sortedInputs.push(input)
+    })
+    // console.log('INPUTS (sorted)', sortedInputs)
+
+    outputs = session.outputs
+    // console.log('OUTPUTS', outputs)
+
+    /* Initialize (output) keys. */
+    keys = []
+
+    /* Handle keys. */
+    Object.keys(outputs).forEach(_outputid => {
+        keys.push(_outputid)
+    })
+    // console.log('KEYS', keys)
+
+    /* Sort (output) keys. */
+    keys.sort()
+    // console.log('KEYS (sorted)', keys)
+
+    /* Initialize sorted outputs. */
+    const sortedOutputs = []
+
+    /* Handle (output) keys. */
+    keys.forEach(_keyid => {
+        if (outputs[_keyid].value >= DUST_VAL) {
+            /* Add input. */
+            sortedOutputs.push(outputs[_keyid])
+        }
+    })
+    // console.log('OUTPUTS (sorted)', sortedOutputs)
+
+    /* Sign shared transaction. */
+    transaction = signSharedTx.bind(this)(
+        sessionid, sortedInputs, sortedOutputs)
+    console.log('(partially) SIGNED TRANSACTION', transaction)
+    // txObj.ins[1].script = txObj2.ins[1].script
+
+    /* Initailize unlocked. */
+    let unlocked = {}
+
+    transaction.ins.forEach(_input => {
+        /* Validate (unlocked) script. */
+        if (_input.script) {
+            /* Add input. */
+            unlocked[binToHex(_input.hash)] = {
+                tx_hash: binToHex(_input.hash.reverse()),
+                unlocking: binToHex(_input.script),
+            }
+        }
+    })
+    console.log('UNLOCKED', unlocked)
+
+    /* Prepare unlocked (inputs) for encryption. */
+    unlocked = JSON.stringify(unlocked)
+    // console.log('FUSION (unlocked)', unlocked)
+
+    // TODO Handle any filtering required BEFORE submitting for fusion.
+
+    clubWallet = await $fetch('/api/wallet')
+        .catch(err => console.error(err))
+    // console.log('CLUB WALLET', clubWallet)
+
+    // FIXME Retrieve public key from a "public" endpoint.
+    publicKey = clubWallet.publicKey
+    // console.log('CLUB PUBLIC KEY', publicKey)
+
+    /* Generate blind components. */
+    blindComponents = encryptForPubkey(publicKey, unlocked)
+    // console.log('BLINDED COMPONENTS', blindComponents)
+
+    const body = {
+        authid: binToHex(this.wallet.publicKey),
+        actionid: 'unlock-components',
+        // tierid,
+        unlocked: blindComponents,
+    }
+    console.log('BODY', body)
+
+    response = await $fetch('/v1', {
+        method: 'POST',
+        body,
+    })
+    .catch(err => console.error(err))
+    console.log('RESPONSE', response)
+}

+ 23 - 8
web/stores/wallet/startFusion.ts

@@ -31,7 +31,11 @@ export default async function () {
     const maxOutputCount = 17
     const maxOutputCount = 17
 
 
     /* Clone fusion inputs. */
     /* Clone fusion inputs. */
-    fusionInputs = [ ...this.fusionInputs ]
+    fusionInputs = []
+
+    Object.keys(this.fusionInputs).forEach(_outpoint => {
+        fusionInputs.push(this.fusionInputs[_outpoint])
+    })
 
 
     const tierScales = [
     const tierScales = [
         10000,      12000,      15000,      18000,      22000,      27000,      33000,      39000,      47000,      56000,      68000,      82000,
         10000,      12000,      15000,      18000,      22000,      27000,      33000,      39000,      47000,      56000,      68000,      82000,
@@ -108,9 +112,17 @@ export default async function () {
 // return
 // return
 
 
     /* Initialize components. */
     /* Initialize components. */
-    // NOTE: Automatically add ALL fusion inputs.
+    // NOTE: Automatically clone + add ALL fusion inputs.
     components = [ ...fusionInputs ]
     components = [ ...fusionInputs ]
 
 
+    /* Sanitize (cloned input) components. */
+    Object.keys(components).forEach(_outpoint => {
+        const component = components[_outpoint]
+
+        /* Delete WIF. */
+        delete component.wif
+    })
+
     /* Set tier ID. */
     /* Set tier ID. */
     tierid = bestTiers.tierid
     tierid = bestTiers.tierid
 
 
@@ -148,14 +160,17 @@ export default async function () {
     blindComponents = encryptForPubkey(publicKey, components)
     blindComponents = encryptForPubkey(publicKey, components)
     // console.log('BLINDED COMPONENTS', blindComponents)
     // console.log('BLINDED COMPONENTS', blindComponents)
 
 
+    const body = {
+        authid: binToHex(this.wallet.publicKey),
+        actionid: 'submit-components',
+        tierid,
+        components: blindComponents,
+    }
+    // console.log('BODY', body)
+
     response = await $fetch('/v1', {
     response = await $fetch('/v1', {
         method: 'POST',
         method: 'POST',
-        body: {
-            authid: binToHex(this.wallet.publicKey),
-            actionid: 'submit-components',
-            tierid,
-            components: blindComponents,
-        },
+        body,
     })
     })
     .catch(err => console.error(err))
     .catch(err => console.error(err))
     console.log('RESPONSE', response)
     console.log('RESPONSE', response)