Transaction.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. <template>
  2. <main class="p-10">
  3. <h1 class="text-3xl">Transaction Details</h1>
  4. <div class="w-max mt-5 p-3 border-2 bg-pink-100 border-pink-300 rounded-xl">
  5. <span class="block text-gray-500 font-bold text-sm">TRANSACTION HASH</span>
  6. <span class="text-2xl text-gray-600 font-medium">{{hash}}</span>
  7. </div>
  8. <div v-if="valueDisplay" class="w-max mt-5 p-3 border-2 bg-pink-100 border-pink-300 rounded-xl">
  9. <span class="block text-gray-500 font-bold text-sm">VALUE</span>
  10. <span class="text-2xl text-gray-600 font-medium">{{valueDisplay}}</span>
  11. </div>
  12. <div class="w-max mt-5 p-3 border-2 bg-pink-100 border-pink-300 rounded-xl">
  13. <span class="block text-gray-500 font-bold text-sm">FROM</span>
  14. <span class="text-2xl text-gray-600 font-medium">{{from}}</span>
  15. </div>
  16. <div v-if="to" class="w-max mt-5 p-3 border-2 bg-pink-100 border-pink-300 rounded-xl">
  17. <span class="block text-gray-500 font-bold text-sm">TO</span>
  18. <span class="text-2xl text-gray-600 font-medium">{{to}}</span>
  19. </div>
  20. <div class="w-max grid grid-cols-4">
  21. <div class="w-max mt-5 p-3 border-2 bg-pink-100 border-pink-300 rounded-xl">
  22. <span class="block text-gray-500 font-bold text-sm">GAS RESERVED</span>
  23. <span class="text-2xl text-gray-600 font-medium">{{gasReservedDisplay}}</span>
  24. </div>
  25. <div class="w-max mt-5 p-3 border-2 bg-pink-100 border-pink-300 rounded-xl">
  26. <span class="block text-gray-500 font-bold text-sm">GAS PRICE</span>
  27. <span class="text-2xl text-gray-600 font-medium">{{gasPriceDisplay}}</span>
  28. </div>
  29. <div class="w-max mt-5 p-3 border-2 bg-pink-100 border-pink-300 rounded-xl">
  30. <span class="block text-gray-500 font-bold text-sm">GAS USED</span>
  31. <span class="text-2xl text-gray-600 font-medium">{{gasUsedDisplay}}</span>
  32. </div>
  33. <div class="w-max mt-5 p-3 border-2 bg-pink-100 border-pink-300 rounded-xl">
  34. <span class="block text-gray-500 font-bold text-sm">CUMULATIVE GAS USED</span>
  35. <span class="text-2xl text-gray-600 font-medium">{{cGasUsedDisplay}}</span>
  36. </div>
  37. </div>
  38. <div class="w-max grid grid-cols-3 gap-5">
  39. <div class="w-max mt-5 p-3 border-2 bg-pink-100 border-pink-300 rounded-xl text-center">
  40. <span class="block text-gray-500 font-bold text-sm">NONCE</span>
  41. <span class="text-2xl text-gray-600 font-medium">{{nonce}}</span>
  42. </div>
  43. <div class="w-max mt-5 p-3 border-2 bg-pink-100 border-pink-300 rounded-xl text-center">
  44. <span class="block text-gray-500 font-bold text-sm">INDEX</span>
  45. <span class="text-2xl text-gray-600 font-medium">{{index}}</span>
  46. </div>
  47. <div class="w-max mt-5 p-3 border-2 bg-pink-100 border-pink-300 rounded-xl text-center">
  48. <span class="block text-gray-500 font-bold text-sm">STATUS</span>
  49. <span class="text-2xl text-gray-600 font-medium">{{status}}</span>
  50. </div>
  51. </div>
  52. <div class="w-80 grid grid-cols-2 gap-5">
  53. <div class="w-max mt-5 p-3 border-2 bg-pink-100 border-pink-300 rounded-xl">
  54. <span class="block text-gray-500 font-bold text-sm">BLOCK NUMBER</span>
  55. <span class="text-2xl text-gray-600 font-medium">{{blockNumberDisplay}}</span>
  56. </div>
  57. <div class="w-max mt-5 p-3 border-2 bg-pink-100 border-pink-300 rounded-xl">
  58. <span class="block text-gray-500 font-bold text-sm">BLOCK HASH</span>
  59. <span class="text-2xl text-gray-600 font-medium">{{blockHash}}</span>
  60. </div>
  61. </div>
  62. <div v-if="contractAddress" class="w-max mt-5 p-3 border-2 bg-pink-100 border-pink-300 rounded-xl">
  63. <span class="block text-gray-500 font-bold text-sm">CONTRACT ADDRESS</span>
  64. <NuxtLink :to="'/sbch/address/' + contractAddress" class="text-2xl text-blue-500 font-medium hover:underline">
  65. {{contractAddress}}
  66. </NuxtLink>
  67. </div>
  68. <div class="w-max mt-5 p-3 border-2 bg-pink-100 border-pink-300 rounded-xl">
  69. <span class="block text-gray-500 font-bold text-sm">INPUT</span>
  70. <span class="text-2xl text-gray-600 font-medium">{{inputDisplay}}</span>
  71. </div>
  72. <div v-if="logs && logs.length" class="w-max mt-5 p-3 border-2 bg-pink-100 border-pink-300 rounded-xl">
  73. <span class="block text-gray-500 font-bold text-sm">
  74. EVENT LOGS
  75. </span>
  76. <div v-for="evt of logs" :key="evt.address">
  77. <span class="block text-xl text-gray-400 font-medium">
  78. index <span class="text-gray-600">{{Number(evt.logIndex)}}</span>
  79. </span>
  80. <span class="block text-xl text-gray-400 font-medium">
  81. address <span class="text-gray-600">{{evt.address}}</span>
  82. </span>
  83. <span class="block text-xl text-gray-400 font-medium">
  84. data <span class="text-gray-600">{{evt.data}}</span>
  85. </span>
  86. <!--
  87. Approval (owneraddress, spenderaddress, valueuint256)
  88. 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925
  89. -->
  90. <div class="p-3">
  91. <span class="block text-gray-500 font-bold text-sm">
  92. TOPICS
  93. </span>
  94. <div v-for="topic of evt.topics" :key="topic">
  95. <span class="block text-xl font-medium text-gray-600">
  96. {{topic}}
  97. </span>
  98. </div>
  99. </div>
  100. <span class="block text-xl text-gray-400 font-medium">
  101. removed <span class="text-gray-600">{{evt.removed}}</span>
  102. </span>
  103. </div>
  104. </div>
  105. <div class="mt-10">
  106. <h1 class="text-xl font-bold text-gray-400">RAW DATA</h1>
  107. <div class="p-5 h-48 overflow-scroll bg-yellow-50 border-4 border-yellow-300 rounded">
  108. <pre v-html="rawData" />
  109. </div>
  110. </div>
  111. <div class="mt-10">
  112. <h1 class="text-xl font-bold text-gray-400">RAW RECEIPT</h1>
  113. <div class="p-5 h-48 overflow-scroll bg-yellow-50 border-4 border-yellow-300 rounded">
  114. <pre v-html="rawReceipt" />
  115. </div>
  116. </div>
  117. </main>
  118. </template>
  119. <script>
  120. /* global BigInt */
  121. /* Import modules. */
  122. // import Nito from 'nitojs'
  123. import numeral from 'numeral'
  124. export default {
  125. data: () => {
  126. return {
  127. usd: null,
  128. hash: null,
  129. blockHash: null,
  130. blockNumber: null,
  131. from: null,
  132. to: null,
  133. gasReserved: null,
  134. gasPrice: null,
  135. gasUsed: null,
  136. cGasUsed: null,
  137. input: null,
  138. nonce: null,
  139. index: null,
  140. value: null,
  141. contractAddress: null,
  142. status: null,
  143. logs: null,
  144. rawData: null,
  145. rawReceipt: null,
  146. }
  147. },
  148. computed: {
  149. valueDisplay() {
  150. if (!this.value) return null
  151. /* Calculate satoshis. */
  152. const satoshis = this.value / BigInt(10000000000)
  153. /* Calculate BCH. */
  154. const bch = Number(satoshis) / 100000000.0
  155. /* Return formatted. */
  156. return numeral(bch).format('0,0.00[000000]') + ' BCH | ' + numeral(satoshis).format('0,0') + ' satoshis'
  157. },
  158. blockNumberDisplay() {
  159. if (!this.blockNumber) return 'n/a'
  160. /* Return formatted. */
  161. return numeral(this.blockNumber).format('0,0')
  162. },
  163. gasReservedDisplay() {
  164. if (!this.gasReserved) return 'n/a'
  165. /* Return formatted. */
  166. return numeral(this.gasReserved).format('0,0') + ' wei'
  167. },
  168. gasUsedDisplay() {
  169. if (!this.gasUsed) return 'n/a'
  170. /* Return formatted. */
  171. return numeral(this.gasUsed).format('0,0') + ' wei'
  172. },
  173. cGasUsedDisplay() {
  174. if (!this.cGasUsed) return 'n/a'
  175. /* Return formatted. */
  176. return numeral(this.cGasUsed).format('0,0') + ' wei'
  177. },
  178. gasPriceDisplay() {
  179. if (!this.gasPrice) return 'n/a'
  180. /* Return formatted. */
  181. return numeral(this.gasPrice / BigInt(1000000000)).format('0,0.00[000000]') + ' gWei'
  182. },
  183. inputDisplay() {
  184. if (!this.input) return 'n/a'
  185. /* Return formatted. */
  186. return this.input.slice(0, 50) + ' ...'
  187. },
  188. },
  189. methods: {
  190. async getTransaction(_txid) {
  191. /* Build request. */
  192. const request = {
  193. id: 0,
  194. jsonrpc: '2.0',
  195. method: 'eth_getTransactionByHash',
  196. params: [ _txid ],
  197. }
  198. // console.log('REQUEST', request);
  199. // /* Make RPC request. */
  200. // const response = await fetch
  201. // // ('https://smartbch.apecs.dev/mainnet')
  202. // ('https://smartbch.fountainhead.cash/mainnet')
  203. // // ('https://smartbch.apecs.dev/testnet')
  204. // .set('Content-Type', 'application/json')
  205. // .send(request)
  206. // .catch(err => console.error(err))
  207. // // console.log('STATUS RESPONSE', response)
  208. // /* Validate response. */
  209. // if (!response) {
  210. // throw new Error('Request failed to SmartBCH node.')
  211. // }
  212. // /* Set body. */
  213. // const body = response.body
  214. // console.log('BODY (getTransaction)', body)
  215. // /* Validate body result. */
  216. // if (body && body.result) {
  217. // /* Set raw data. */
  218. // this.rawData += JSON.stringify(body.result, null, 4)
  219. // /* Set (transaction) hash. */
  220. // this.hash = body.result.hash
  221. // /* Set block hash. */
  222. // this.blockHash = body.result.blockHash
  223. // /* Set block number. */
  224. // this.blockNumber = BigInt(body.result.blockNumber)
  225. // /* Set from. */
  226. // this.from = body.result.from
  227. // /* Set to. */
  228. // this.to = body.result.to
  229. // /* Set gas amount (reserved). */
  230. // this.gasReserved = BigInt(body.result.gas)
  231. // /* Set gas price. */
  232. // this.gasPrice = BigInt(body.result.gasPrice)
  233. // /* Set input. */
  234. // this.input = body.result.input
  235. // /* Set nonce. */
  236. // this.nonce = BigInt(body.result.nonce)
  237. // /* Set (transaction) index. */
  238. // this.index = BigInt(body.result.transactionIndex)
  239. // /* Set value. */
  240. // this.value = BigInt(body.result.value ? body.result.value : 0)
  241. // }
  242. },
  243. async getReceipt(_txid) {
  244. /* Build request. */
  245. const request = {
  246. id: 0,
  247. jsonrpc: '2.0',
  248. method: 'eth_getTransactionReceipt',
  249. params: [ _txid ],
  250. }
  251. // console.log('REQUEST', request);
  252. // /* Make RPC request. */
  253. // const response = await fetch
  254. // // ('https://smartbch.apecs.dev/mainnet')
  255. // ('https://smartbch.fountainhead.cash/mainnet')
  256. // // ('https://smartbch.apecs.dev/testnet')
  257. // .set('Content-Type', 'application/json')
  258. // .send(request)
  259. // .catch(err => console.error(err))
  260. // // console.log('STATUS RESPONSE', response)
  261. // /* Validate response. */
  262. // if (!response) {
  263. // throw new Error('Request failed to SmartBCH node.')
  264. // }
  265. // /* Set body. */
  266. // const body = response.body
  267. // console.log('BODY (getReceipt)', body)
  268. // /* Validate body result. */
  269. // if (body && body.result) {
  270. // /* Set raw receipt. */
  271. // this.rawReceipt += JSON.stringify(body.result, null, 4)
  272. // /* Set gas used. */
  273. // this.gasUsed = BigInt(body.result.gasUsed)
  274. // /* Set (cumulative) gas used. */
  275. // this.cGasUsed = BigInt(body.result.cumulativeGasUsed)
  276. // /* Set (cumulative) gas used. */
  277. // this.contractAddress = body.result.contractAddress
  278. // /* Set status. */
  279. // this.status = BigInt(body.result.status)
  280. // /* Set logs. */
  281. // this.logs = body.result.logs
  282. // }
  283. },
  284. },
  285. created: async function () {
  286. if (!this.$route.params || !this.$route.params.txid) {
  287. // throw new Error('No transaction provided')
  288. return // DO NOT THROW (due to SSR)
  289. }
  290. /* Initialize raw data. */
  291. this.rawData = ''
  292. /* Initialize raw receipt. */
  293. this.rawReceipt = ''
  294. /* Set transaction id. */
  295. const txid = this.$route.params.txid
  296. console.log('TXID', txid)
  297. this.usd = await Nito.Markets.getTicker('BCH')
  298. .catch(err => console.error(err))
  299. console.log('USD', this.usd)
  300. this.getTransaction(txid)
  301. this.getReceipt(txid)
  302. /* Retrieve session. */
  303. // const session = await this.hasSession()
  304. // .catch(err => console.error('Session Error:', err))
  305. /* Validate session. */
  306. // if (!session) {
  307. // return
  308. // }
  309. },
  310. mounted: function () {
  311. //
  312. },
  313. }
  314. </script>