thornode.py 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  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. test.cmdtest_d.httpd.thornode: Thornode WSGI http server
  12. """
  13. import time, re, json
  14. from mmgen.cfg import Config
  15. from mmgen.amt import UniAmt
  16. from . import HTTPD
  17. cfg = Config()
  18. # https://thornode.ninerealms.com/thorchain/quote/swap?from_asset=BCH.BCH&to_asset=LTC.LTC&amount=1000000
  19. sample_request = 'GET /thorchain/quote/swap?from_asset=BCH.BCH&to_asset=LTC.LTC&amount=1000000000'
  20. request_pat = r'/thorchain/quote/swap\?from_asset=(\S+)\.(\S+)&to_asset=(\S+)\.(\S+)&amount=(\d+)'
  21. prices = { 'BTC': 97000, 'LTC': 115, 'BCH': 330 }
  22. data_template = {
  23. 'inbound_address': None,
  24. 'inbound_confirmation_blocks': 4,
  25. 'inbound_confirmation_seconds': 2400,
  26. 'outbound_delay_blocks': 5,
  27. 'outbound_delay_seconds': 30,
  28. 'fees': {
  29. 'asset': 'LTC.LTC',
  30. 'affiliate': '0',
  31. 'outbound': '878656',
  32. 'liquidity': '8945012',
  33. 'total': '9823668',
  34. 'slippage_bps': 31,
  35. 'total_bps': 34
  36. },
  37. 'expiry': None,
  38. 'warning': 'Do not cache this response. Do not send funds after the expiry.',
  39. 'notes': 'First output should be to inbound_address, second output should be change back to self, third output should be OP_RETURN, limited to 80 bytes. Do not send below the dust threshold. Do not use exotic spend scripts, locks or address formats.',
  40. 'dust_threshold': '10000',
  41. 'recommended_min_amount_in': '1222064',
  42. 'recommended_gas_rate': '6',
  43. 'gas_rate_units': 'satsperbyte',
  44. 'expected_amount_out': None,
  45. 'max_streaming_quantity': 0,
  46. 'streaming_swap_blocks': 0,
  47. 'total_swap_seconds': 2430
  48. }
  49. def make_inbound_addr(proto, mmtype):
  50. from mmgen.tool.coin import tool_cmd
  51. n = int(time.time()) // (60 * 60 * 24) # increments once every 24 hrs
  52. return tool_cmd(
  53. cfg = cfg,
  54. cmdname = 'pubhash2addr',
  55. proto = proto,
  56. mmtype = mmtype).pubhash2addr(f'{n:040x}')
  57. class ThornodeServer(HTTPD):
  58. name = 'thornode server'
  59. port = 18800
  60. content_type = 'application/json'
  61. def make_response_body(self, method, environ):
  62. from wsgiref.util import request_uri
  63. m = re.search(request_pat, request_uri(environ))
  64. _, send_coin, _, recv_coin, amt_atomic = m.groups()
  65. from mmgen.protocol import init_proto
  66. send_proto = init_proto(cfg, send_coin, network='regtest', need_amt=True)
  67. in_amt = UniAmt(int(amt_atomic), from_unit='satoshi')
  68. out_amt = in_amt * (prices[send_coin] / prices[recv_coin])
  69. addr = make_inbound_addr(send_proto, send_proto.preferred_mmtypes[0])
  70. data = data_template | {
  71. 'expected_amount_out': str(out_amt.to_unit('satoshi')),
  72. 'expiry': int(time.time()) + (10 * 60),
  73. 'inbound_address': addr,
  74. }
  75. return json.dumps(data).encode()