thornode.py 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. #!/usr/bin/env python3
  2. import json, re, time
  3. from http.server import HTTPServer, BaseHTTPRequestHandler
  4. from mmgen.cfg import Config
  5. from mmgen.util import msg, make_timestr
  6. cfg = Config()
  7. def make_inbound_addr(proto, mmtype):
  8. from mmgen.tool.coin import tool_cmd
  9. n = int(time.time()) // (60 * 60 * 24) # increments once every 24 hrs
  10. return tool_cmd(
  11. cfg = cfg,
  12. cmdname = 'pubhash2addr',
  13. proto = proto,
  14. mmtype = mmtype).pubhash2addr(f'{n:040x}')
  15. data_template = {
  16. 'inbound_address': None,
  17. 'inbound_confirmation_blocks': 4,
  18. 'inbound_confirmation_seconds': 2400,
  19. 'outbound_delay_blocks': 5,
  20. 'outbound_delay_seconds': 30,
  21. 'fees': {
  22. 'asset': 'LTC.LTC',
  23. 'affiliate': '0',
  24. 'outbound': '878656',
  25. 'liquidity': '8945012',
  26. 'total': '9823668',
  27. 'slippage_bps': 31,
  28. 'total_bps': 34
  29. },
  30. 'expiry': None,
  31. 'warning': 'Do not cache this response. Do not send funds after the expiry.',
  32. '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.',
  33. 'dust_threshold': '10000',
  34. 'recommended_min_amount_in': '1222064',
  35. 'recommended_gas_rate': '6',
  36. 'gas_rate_units': 'satsperbyte',
  37. 'expected_amount_out': None,
  38. 'max_streaming_quantity': 0,
  39. 'streaming_swap_blocks': 0,
  40. 'total_swap_seconds': 2430
  41. }
  42. # https://thornode.ninerealms.com/thorchain/quote/swap?from_asset=BCH.BCH&to_asset=LTC.LTC&amount=1000000
  43. sample_request = 'GET /thorchain/quote/swap?from_asset=BCH.BCH&to_asset=LTC.LTC&amount=1000000000 HTTP/1.1'
  44. request_pat = r'/thorchain/quote/swap\?from_asset=(\S+)\.(\S+)&to_asset=(\S+)\.(\S+)&amount=(\d+) HTTP/'
  45. prices = { 'BTC': 97000, 'LTC': 115, 'BCH': 330 }
  46. def create_data(request_line):
  47. m = re.search(request_pat, request_line)
  48. try:
  49. _, send_coin, _, recv_coin, amt_atomic = m.groups()
  50. except Exception as e:
  51. msg(f'{type(e)}: {e}')
  52. return {}
  53. from mmgen.protocol import init_proto
  54. send_proto = init_proto(cfg, send_coin, network='regtest', need_amt=True)
  55. in_amt = send_proto.coin_amt(int(amt_atomic), from_unit='satoshi')
  56. out_amt = in_amt * (prices[send_coin] / prices[recv_coin])
  57. addr = make_inbound_addr(send_proto, send_proto.preferred_mmtypes[0])
  58. expiry = int(time.time()) + (10 * 60)
  59. return data_template | {
  60. 'expected_amount_out': str(out_amt.to_unit('satoshi')),
  61. 'expiry': expiry,
  62. 'inbound_address': addr,
  63. }
  64. class handler(BaseHTTPRequestHandler):
  65. header = b'HTTP/1.1 200 OK\nContent-type: application/json\n\n'
  66. def do_GET(self):
  67. # print(f'Thornode server received:\n {self.requestline}')
  68. self.wfile.write(self.header + json.dumps(create_data(self.requestline)).encode())
  69. def run_thornode_server(server_class=HTTPServer, handler_class=handler):
  70. print('Thornode server listening on port 18800')
  71. server_address = ('localhost', 18800)
  72. httpd = server_class(server_address, handler_class)
  73. httpd.serve_forever()
  74. print('Thornode server exiting')