info.py 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. #!/usr/bin/env python3
  2. #
  3. # MMGen Wallet, a terminal-based cryptocurrency wallet
  4. # Copyright (C)2013-2025 The MMGen Project <mmgen@tuta.io>
  5. # Licensed under the GNU General Public License, Version 3:
  6. # https://www.gnu.org/licenses
  7. # Public project repositories:
  8. # https://github.com/mmgen/mmgen-wallet
  9. # https://gitlab.com/mmgen/mmgen-wallet
  10. """
  11. proto.eth.tx.info: Ethereum transaction info class
  12. """
  13. from ....tx.info import TxInfo, mmid_disp
  14. from ....color import red, yellow, blue, cyan, pink
  15. from ....obj import NonNegativeInt
  16. class TxInfo(TxInfo):
  17. to_addr_key = 'to'
  18. def format_body(self, blockcount, nonmm_str, max_mmwid, enl, *, terse, sort):
  19. tx = self.tx
  20. t = tx.txobj
  21. td = t['data']
  22. to_addr = t[self.to_addr_key]
  23. tokenswap = tx.is_swap and tx.is_token
  24. fs = """
  25. From: {f}{f_mmid}
  26. {toaddr} {t}{t_mmid}{tvault}
  27. Amount: {a} {c}
  28. Gas price: {g} Gwei
  29. Gas limit: {G}{G_dec}
  30. Nonce: {n}
  31. Data: {d}
  32. """.strip().replace('\t', '') + ('\nMemo: {m}' if tx.is_swap else '')
  33. return fs.format(
  34. f = t['from'].hl(0),
  35. t = to_addr.hl(0) if to_addr else blue('None'),
  36. a = t['amt'].hl(),
  37. toaddr = ('Router:' if tokenswap else 'Vault:' if tx.is_swap else 'To:').ljust(8),
  38. tvault = (f'\nVault: {cyan(tx.token_vault_addr)}' if tokenswap else ''),
  39. n = t['nonce'].hl(),
  40. d = blue('None') if not td else '{}... ({} bytes)'.format(td[:40], len(td)//2),
  41. m = pink(tx.swap_memo) if tx.is_swap else None,
  42. c = tx.proto.dcoin if len(tx.outputs) else '',
  43. g = yellow(tx.pretty_fmt_fee(t['gasPrice'].to_unit('Gwei'))),
  44. G = NonNegativeInt(tx.total_gas).hl(),
  45. G_dec = red(f" ({t['startGas']} + {t['router_gas']})") if tokenswap else '',
  46. f_mmid = mmid_disp(tx.inputs[0], nonmm_str),
  47. t_mmid = mmid_disp(tx.outputs[0], nonmm_str) if tx.outputs and not tx.is_swap else '') + '\n\n'
  48. def format_abs_fee(self, iwidth, /, *, color=None):
  49. return self.tx.fee.fmt(iwidth, color=color) + (' (max)' if self.tx.txobj['data'] else '')
  50. def format_rel_fee(self):
  51. return ' ({} of spend amount)'.format(
  52. pink('{:0.6f}%'.format(self.tx.fee / self.tx.send_amt * 100))
  53. )
  54. def format_verbose_footer(self):
  55. if self.tx.txobj['data'] and not self.tx.is_swap:
  56. from ....util import pp_fmt
  57. from ..contract import parse_abi
  58. return '\nParsed contract data: ' + pp_fmt(parse_abi(self.tx.txobj['data']))
  59. else:
  60. return ''
  61. class TokenTxInfo(TxInfo):
  62. to_addr_key = 'token_to'
  63. def format_rel_fee(self):
  64. return ''
  65. def format_body(self, *args, **kwargs):
  66. return 'Token: {d} {c}\n{r}'.format(
  67. d = self.tx.txobj['token_addr'].hl(0),
  68. c = blue('(' + self.tx.proto.dcoin + ')'),
  69. r = super().format_body(*args, **kwargs))