authFusion.ts 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. /* Import modules. */
  2. import { encryptForPubkey } from '@nexajs/crypto'
  3. import { randomOutputsForTier } from '@nexajs/privacy'
  4. import { binToHex } from '@nexajs/utils'
  5. import BCHJS from '@psf/bch-js'
  6. /* Initialize BCHJS. */
  7. const bchjs = new BCHJS()
  8. export default async function () {
  9. console.log('Starting fusions...')
  10. /* Initialize locals. */
  11. let blindComponents
  12. let components
  13. let cipherTokens
  14. let fusionInputs
  15. let inputAmount
  16. let publicKey
  17. let rawTx
  18. let inputs
  19. let outputs
  20. let response
  21. let clubWallet
  22. let tierScale
  23. const feeOffset = 1034//10034
  24. const maxOutputCount = 17
  25. /* Clone fusion inputs. */
  26. fusionInputs = [ ...this.fusionInputs ]
  27. const tierScales = [
  28. 10000, 12000, 15000, 18000, 22000, 27000, 33000, 39000, 47000, 56000, 68000, 82000,
  29. 100000, 120000, 150000, 180000, 220000, 270000, 330000, 390000, 470000, 560000, 680000, 820000,
  30. 1000000, 1200000, 1500000, 1800000, 2200000, 2700000, 3300000, 3900000, 4700000, 5600000, 6800000, 8200000,
  31. 10000000, 12000000, 15000000, 18000000, 22000000, 27000000, 33000000, 39000000, 47000000, 56000000, 68000000, 82000000,
  32. 100000000, 120000000, 150000000, 180000000, 220000000, 270000000, 330000000, 390000000, 470000000, 560000000, 680000000, 820000000,
  33. 1000000000, 1200000000, 1500000000, 1800000000, 2200000000, 2700000000, 3300000000, 3900000000, 4700000000, 5600000000, 6800000000, 8200000000,
  34. ]
  35. const bestTiers = {}
  36. for (let i = 0; i < fusionInputs.length; i++) {
  37. /* Set input amount. */
  38. inputAmount = fusionInputs[i].value
  39. console.log('INPUT AMOUNT', inputAmount)
  40. /* Handle ALL tier scales. */
  41. tierScales.forEach(_tierScale => {
  42. try {
  43. /* Request (random) outputs. */
  44. response = randomOutputsForTier(
  45. inputAmount,
  46. _tierScale,
  47. feeOffset,
  48. maxOutputCount,
  49. )
  50. /* Validate tier outputs. */
  51. if (response && response.length > 1) {
  52. console.log('TIER', _tierScale, 'INPUT #', i, response)
  53. /* Test for the best tiers. */
  54. if (typeof bestTiers[i] === 'undefined' || response.length > bestTiers[i]?.outputs.length) {
  55. const numOutputs = response.length
  56. console.log('NUM OUTPUTS', numOutputs)
  57. // const fee = bchjs.BitcoinCash.getByteCount({ P2PKH: 1 }, { P2PKH: numOutputs })
  58. const fee = bchjs.BitcoinCash.getByteCount({ P2PKH: 1 }, { P2PKH: 1 })
  59. console.log('FEE', fee)
  60. const outputs = response.map(_outputValue => {
  61. return {
  62. address: this.getFusionAddress(),
  63. // value: (_outputValue - Math.ceil(fee / numOutputs)),
  64. value: (_outputValue - fee),
  65. }
  66. })
  67. bestTiers[i] = {
  68. tierid: _tierScale,
  69. outputs,
  70. }
  71. }
  72. }
  73. } catch (err) {
  74. // console.error(err)
  75. }
  76. })
  77. }
  78. console.log('BEST TIERS', bestTiers)
  79. // return
  80. /* Initialize components. */
  81. components = []
  82. /* Add best tiers to components. */
  83. // NOTE: Best tiers index is derived from inputs index.
  84. Object.keys(bestTiers).forEach(_tierIdx => {
  85. /* Add (matching) input to components. */
  86. components.push(fusionInputs[_tierIdx])
  87. /* Set tier. */
  88. const tier = bestTiers[_tierIdx]
  89. /* Add (output) components. */
  90. components.push(tier)
  91. })
  92. /* Validate components. */
  93. if (components.length === 0) {
  94. throw new Error('Oops! You MUST provide components to the Club.')
  95. }
  96. /* Prepare components for encryption. */
  97. components = JSON.stringify(components)
  98. // console.log('FUSION (components)', components)
  99. // TODO Handle any filtering required BEFORE submitting for fusion.
  100. clubWallet = await $fetch('/api/wallet')
  101. .catch(err => console.error(err))
  102. // console.log('CLUB WALLET', clubWallet)
  103. // FIXME Retrieve public key from a "public" endpoint.
  104. publicKey = clubWallet.publicKey
  105. // console.log('CLUB PUBLIC KEY', publicKey)
  106. /* Generate blind components. */
  107. blindComponents = encryptForPubkey(publicKey, components)
  108. // console.log('BLINDED COMPONENTS', blindComponents)
  109. response = await $fetch('/v1', {
  110. method: 'POST',
  111. body: {
  112. authid: binToHex(this.wallet.publicKey),
  113. actionid: 'submit-components',
  114. components: blindComponents,
  115. },
  116. })
  117. .catch(err => console.error(err))
  118. console.log('RESPONSE', response)
  119. }