Initial release.
[robmyers:dogecode.git] / dogecode / network.py
1 # network.py - Accessing the dogepartyd json-rpc api.
2 # Copyright (C) 2014 Rob Myers rob@robmyers.org
3 #
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation, either version 3 of the License, or 
7 # (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
17 ################################################################################
18 # Imports
19 ################################################################################
20
21 import json                                                                     
22 import sys                                                                      
23 import requests
24
25
26 ################################################################################
27 # Dogeparty API access
28 ################################################################################
29
30 headers = {'content-type': 'application/json'}
31
32 class DogepartyApi(object):
33     """Connect to and call the Dogeparty API"""
34
35     def __init__(self, user, password, host='localhost', port='5000'):
36         """Configure the API connection"""
37         self.host = 'http://{}:{}@{}:{}'.format(user,
38                                                 password,
39                                                 host,
40                                                 port)
41
42     def call_api(self, method, params):
43         """Call dogepartyd via the json-rpc interface"""
44         payload = {
45             "method": method,
46             "params": params,
47             "jsonrpc": "2.0",
48             "id": 0
49         }
50         response = requests.post(self.host, data=json.dumps(payload), headers=headers)
51         try:
52             return response.json()['result']
53         except KeyError:
54             print(response.json())
55             return False
56
57     def send_token(self, from_address, to_address, token, amount, fee):
58         """Send the given amount of tokens"""
59         result = False
60         params = {'source': from_address,
61                   'destination': to_address,
62                   'asset': token,
63                   'quantity': int(amount),
64                   'fee': int(fee),
65                   'encoding': 'opreturn'}
66         tx_hash = self.call_api("do_send", params)
67         if tx_hash:
68             result = tx_hash
69         return result
70     
71     def __new_address_for_code(self):
72         """Return a new address to receive the tokens representing the program"""
73         return ""
74
75     def __get_account_token_amount(self, address, token):
76         """Return the amount of token address has, 0 for none"""
77         return 0
78
79     def address_has_no_code_tokens(self, address):
80         """Check that address has no code tokens"""
81         has_none = True
82         for token in translation.TOKENS:
83             count = self.get_account_token_amount(address, token)
84             if token > 0:
85                 has_none = False
86                 break
87         return has_none
88
89     def address_has_sufficient_tokens(self, address, token_pairs, warning_level=10):
90         """Check that address has sufficient tokens to send to express the program
91         encoded in token_pairs, warning if sending would reduce the amount of
92         tokens too low"""
93         totals = {}
94         for pair in token_pairs:
95             totals[pair[0]] = totals.get(pair[0], 0) + pair[1]
96         enough = True
97         for token, count in totals.items():
98             available = get_account_token_amount(address, token)
99             if (available - count) < warning_level:
100                 print("This program requires {} {} tokens. Address {} currently has {} . After this program it will only have {} .".format(count, token, address, available, available - count))
101             if available < count:
102                 print("Account {} has insufficient {} tokens ({})to send the {} needed to represent this program.".format(address, token, available, count))
103                 enough = False
104                 break
105         return enough
106
107     def __address_has_sufficient_fees(self, address, token_pairs, fee, warning_level=100):
108         """Check that the account has sufficient Dogecoins to pay the fees for all
109         the token transactions"""
110         total_required = len(token_pairs) * fee
111         #FIXME: work
112         return False
113     
114     def __upload_code(from_address, to_address, token_pairs, fee):
115         """Check that from_address has sufficient tokens and that to_address has
116         none, then create transactions to transfer the token amounts expressed
117         in token pairs from from_address to to_address"""
118         if self.address_has_sufficient_tokens(from_address, token_pairs) and \
119            self.address_has_no_code_tokens(to_address):
120             pass
121         pass
122     
123     def token_transactions_for_address(self, receiver):
124         """Get the token transactions (and any doge transfers) sent to the adress.
125            This is insecure for fetching programs without further filtering."""
126         params = {'filters': {'field':'destination',
127                               'op':'==',
128                               'value':receiver},
129                   'order_by':'tx_index',
130                   'order_dir':'ASC'}
131         sends = self.call_api('get_sends', params)
132         return sends
133
134     
135     def token_transactions_for_address_from_sender(self, receiver, sender):
136         """Get the token transactions (and any doge transfers) sent to the adress from the sender"""
137         params = {'filters': [{'field':'destination',
138                                'op':'==',
139                                'value':receiver},
140                               {'field':'sender',
141                                'op':'==',
142                                'value':sender}],
143                   'order_by':'tx_index',
144                   'order_dir':'ASC'}
145         sends = self.call_api('get_sends', params)
146         return sends