Exemple #1
0
    async def get(self):

        try:
            offset = int(self.get_query_argument('offset', 0))
            limit = int(self.get_query_argument('limit', 10))
        except ValueError:
            raise JSONHTTPError(400, body={'errors': [{'id': 'bad_arguments', 'message': 'Bad Arguments'}]})

        query = self.get_query_argument('query', None)
        apps = parse_boolean(self.get_query_argument('apps', None))
        payment_address = self.get_query_argument('payment_address', None)
        if payment_address and not validate_address(payment_address):
            raise JSONHTTPError(400, body={'errors': [{'id': 'bad_arguments', 'message': 'Invalid payment_address'}]})

        if query is None:
            if payment_address:
                async with self.db:
                    rows = await self.db.fetch(
                        "SELECT * FROM users WHERE payment_address = $3 "
                        "ORDER BY payment_address, name, username "
                        "OFFSET $1 LIMIT $2",
                        offset, limit, payment_address)
                results = [user_row_for_json(self.request, row) for row in rows]
            else:
                results = []
        else:
            # strip punctuation
            query = ''.join([c for c in query if c not in string.punctuation])
            # split words and add in partial matching flags
            query = '|'.join(['{}:*'.format(word) for word in query.split(' ') if word])
            args = [offset, limit, query]
            where_q = []
            if payment_address:
                where_q.append("payment_address = ${}".format(len(args) + 1))
                args.append(payment_address)
            if apps is not None:
                where_q.append("is_app = ${}".format(len(args) + 1))
                args.append(apps)
            where_q = " AND {}".format(" AND ".join(where_q)) if where_q else ""
            sql = ("SELECT * FROM "
                   "(SELECT * FROM users, TO_TSQUERY($3) AS q "
                   "WHERE (tsv @@ q){}) AS t1 "
                   "ORDER BY TS_RANK_CD(t1.tsv, TO_TSQUERY($3)) DESC, name, username "
                   "OFFSET $1 LIMIT $2"
                   .format(where_q))
            async with self.db:
                rows = await self.db.fetch(sql, *args)
            results = [user_row_for_json(self.request, row) for row in rows]
        querystring = 'query={}'.format(query)
        if apps is not None:
            querystring += '&apps={}'.format('true' if apps else 'false')
        if payment_address:
            querystring += '&payment_address={}'.format(payment_address)

        self.write({
            'query': querystring,
            'offset': offset,
            'limit': limit,
            'results': results
        })
Exemple #2
0
    def unsubscribe(self, *addresses):
        for address in addresses:
            if not validate_address(address):
                raise JsonRPCInvalidParamsError(data={'id': 'bad_arguments', 'message': 'Bad Arguments'})

        self.request_handler.unsubscribe(addresses)

        return True
Exemple #3
0
    async def get_balance(self, address):

        if not validate_address(address):
            raise JsonRPCInvalidParamsError(data={
                'id': 'invalid_address',
                'message': 'Invalid Address'
            })

        confirmed, unconfirmed = await self.get_balances(address)

        return {
            "confirmed_balance": hex(confirmed),
            "unconfirmed_balance": hex(unconfirmed)
        }
Exemple #4
0
    def test_validate_address(self):

        self.assertTrue(
            utils.validate_address(
                "0x056db290f8ba3250ca64a45d16284d04bc6f5fbf"))
        self.assertTrue(
            utils.validate_address(
                u"0x056db290f8ba3250ca64a45d16284d04bc6f5fbf"))
        self.assertFalse(utils.validate_address("hello"))
        self.assertFalse(utils.validate_address("0x12345"))
        self.assertFalse(utils.validate_address(None))
        self.assertFalse(utils.validate_address({}))
        self.assertFalse(
            utils.validate_address(0x056db290f8ba3250ca64a45d16284d04bc6f5fbf))
        self.assertFalse(
            utils.validate_address(
                "0x114655db4898a6580f0abfc53fc0c0a88110724abf8d41f2abf206c69d7d4c821ed2cdf6939484ef6aebc39ce5662363b82140106bbc374a0f1381b6948214b001"
            ))
Exemple #5
0
    async def unsubscribe(self, *addresses):

        for address in addresses:
            if not validate_address(address):
                raise JsonRPCInvalidParamsError(data={
                    'id': 'bad_arguments',
                    'message': 'Bad Arguments'
                })

        async with self.db:

            await self.db.execute(
                "DELETE FROM notification_registrations WHERE token_id = $1 AND ({})"
                .format(' OR '.join('eth_address = ${}'.format(i + 2)
                                    for i, _ in enumerate(addresses))),
                self.user_token_id, *addresses)

            await self.db.commit()

        return True
Exemple #6
0
    async def subscribe(self, *addresses):

        insert_args = []
        for address in addresses:
            if not validate_address(address):
                raise JsonRPCInvalidParamsError(data={
                    'id': 'bad_arguments',
                    'message': 'Bad Arguments'
                })
            insert_args.extend([self.user_token_id, address])

        async with self.db:

            await self.db.execute(
                "INSERT INTO notification_registrations VALUES {} ON CONFLICT DO NOTHING"
                .format(', '.join('(${}, ${})'.format((i * 2) + 1, (i * 2) + 2)
                                  for i, _ in enumerate(addresses))),
                *insert_args)

            await self.db.commit()

        return True
    async def post(self):

        if 'reputation' not in self.application.config or 'id' not in self.application.config['reputation']:
            raise HTTPError(404)

        try:
            address = self.verify_request()
        except JSONHTTPError:
            raise HTTPError(404)

        if address != self.application.config['reputation']['id']:
            raise HTTPError(404)

        if not all(x in self.json for x in ['address', 'score', 'count']):
            raise JSONHTTPError(400, body={'errors': [{'id': 'bad_arguments', 'message': 'Bad Arguments'}]})

        token_id = self.json['address']
        if not validate_address(token_id):
            raise JSONHTTPError(400, body={'errors': [{'id': 'invalid_address', 'message': 'Invalid Address'}]})

        count = self.json['count']
        count = parse_int(count)
        if count is None:
            raise JSONHTTPError(400, body={'errors': [{'id': 'invalid_count', 'message': 'Invalid Count'}]})

        score = self.json['score']
        if isinstance(score, str) and validate_decimal_string(score):
            score = Decimal(score)
        if not isinstance(score, (int, float, Decimal)):
            raise JSONHTTPError(400, body={'errors': [{'id': 'invalid_score', 'message': 'Invalid Score'}]})

        async with self.db:
            await self.db.execute("UPDATE apps SET reputation_score = $1, review_count = $2 WHERE token_id = $3",
                                  score, count, token_id)
            await self.db.commit()

        self.set_status(204)
Exemple #8
0
    async def create_transaction_skeleton(self,
                                          *,
                                          to_address,
                                          from_address,
                                          value=0,
                                          nonce=None,
                                          gas=None,
                                          gas_price=None,
                                          data=None):

        if not validate_address(from_address):
            raise JsonRPCInvalidParamsError(data={
                'id': 'invalid_from_address',
                'message': 'Invalid From Address'
            })

        if not validate_address(to_address):
            raise JsonRPCInvalidParamsError(data={
                'id': 'invalid_to_address',
                'message': 'Invalid To Address'
            })

        if value:
            value = parse_int(value)
            if value is None:
                raise JsonRPCInvalidParamsError(data={
                    'id': 'invalid_value',
                    'message': 'Invalid Value'
                })

        # check optional arguments

        if nonce is None:
            # check cache for nonce
            nonce = self.redis.get("nonce:{}".format(from_address))
            if nonce:
                nonce = int(nonce)
            # get the network's value too
            nw_nonce = await self.eth.eth_getTransactionCount(from_address)
            if nonce is None or nw_nonce > nonce:
                # if not cached, or the cached value is lower than
                # the network value, use the network value!
                nonce = nw_nonce
        else:
            nonce = parse_int(nonce)
            if nonce is None:
                raise JsonRPCInvalidParamsError(data={
                    'id': 'invalid_nonce',
                    'message': 'Invalid Nonce'
                })

        if data is not None:
            if isinstance(data, int):
                data = hex(data)
            if isinstance(data, str):
                try:
                    data = data_decoder(data)
                except binascii.Error:
                    pass
            if not isinstance(data, bytes):
                raise JsonRPCInvalidParamsError(data={
                    'id': 'invalid_data',
                    'message': 'Invalid Data field'
                })
        else:
            data = b''

        if gas is None:
            # if there is data the default startgas value wont be enough
            if data:
                gas = await self.eth.eth_estimateGas(from_address,
                                                     to_address,
                                                     nonce=nonce,
                                                     data=data)
            else:
                gas = DEFAULT_STARTGAS
        else:
            gas = parse_int(gas)
            if gas is None:
                raise JsonRPCInvalidParamsError(data={
                    'id': 'invalid_gas',
                    'message': 'Invalid Gas'
                })

        if gas_price is None:
            gas_price = DEFAULT_GASPRICE
        else:
            gas_price = parse_int(gas_price)
            if gas_price is None:
                raise JsonRPCInvalidParamsError(data={
                    'id': 'invalid_gas_price',
                    'message': 'Invalid Gas Price'
                })

        tx = create_transaction(nonce=nonce,
                                gasprice=gas_price,
                                startgas=gas,
                                to=to_address,
                                value=value,
                                data=data)

        transaction = encode_transaction(tx)

        return transaction
    async def post(self):
        """Handles submitting a new app to the directory service"""

        if not self.current_user:
            raise JSONHTTPError(401)

        if not all(x in self.json for x in ['display_name', 'token_id']):
            raise JSONHTTPError(400,
                                body={
                                    'errors': [{
                                        'id': 'bad_arguments',
                                        'message': 'Bad Arguments'
                                    }]
                                })

        token_id = self.json['token_id']
        if not validate_address(token_id):
            raise JSONHTTPError(400,
                                body={
                                    'errors': [{
                                        'id': 'invalid_token_id',
                                        'message': 'Invalid Arguments'
                                    }]
                                })

        # check if the user has already submitted this app
        async with self.db:
            existing = await self.db.fetchrow(
                "SELECT * FROM submissions WHERE submitter_token_id = $1 AND app_token_id = $2",
                self.current_user, self.json['token_id'])
        if existing:
            raise JSONHTTPError(400,
                                body={
                                    'errors': [{
                                        'id': 'already_exists',
                                        'message': 'App already exists'
                                    }]
                                })

        # check if the app has already been submitted (by someone else for e.g.)
        async with self.db:
            existing = await self.db.fetchrow(
                "SELECT * FROM apps WHERE token_id = $1",
                self.json['token_id'])

        # TODO: maybe this is actually ok (but it would be weird)
        if existing:
            raise JSONHTTPError(400,
                                body={
                                    'errors': [{
                                        'id': 'already_exists',
                                        'message': 'App already exists'
                                    }]
                                })

        client = IdServiceClient(use_tornado=True)
        bot = await client.get_user(self.json['token_id'])
        if bot is None:
            raise JSONHTTPError(
                400,
                body={
                    'errors': [{
                        'id':
                        'not_found',
                        'message':
                        'Cannot find given address in the id service'
                    }]
                })

        username = bot['username']
        payment_address = bot['payment_address']
        display_name = self.json['display_name']

        init_request = ['paymentAddress', 'language']
        languages = ['en']
        interfaces = ['ChatBot']
        protocol = 'sofa-v1.0'

        avatar_url = self.json.get('avatar_url', None)
        if not avatar_url:
            avatar_url = 'https://token-id-service.herokuapp.com/identicon/{}.png'.format(
                token_id)

        async with self.db:
            await self.db.execute(
                "INSERT INTO apps "
                "(token_id, name) VALUES ($1, $2) ", token_id, display_name)
            await self.db.execute(
                "INSERT INTO sofa_manifests "
                "(token_id, payment_address, username, init_request, languages, interfaces, protocol, avatar_url) "
                "VALUES "
                "($1, $2, $3, $4, $5, $6, $7, $8)", token_id, payment_address,
                username, init_request, languages, interfaces, protocol,
                avatar_url)
            await self.db.execute(
                "INSERT INTO submissions "
                "(app_token_id, submitter_token_id) "
                "VALUES "
                "($1, $2)", token_id, self.current_user)
            row = await self.db.fetchrow(
                "SELECT * FROM apps JOIN sofa_manifests ON apps.token_id = sofa_manifests.token_id WHERE apps.token_id = $1",
                token_id)
            await self.db.commit()

        self.write(response_for_row(row))
    async def put(self):
        """Handles submitting a new app to the directory service"""

        if not self.current_user:
            raise JSONHTTPError(401)

        if not all(x in self.json for x in ['display_name', 'token_id']):
            raise JSONHTTPError(400,
                                body={
                                    'errors': [{
                                        'id': 'bad_arguments',
                                        'message': 'Bad Arguments'
                                    }]
                                })

        token_id = self.json['token_id']
        if not validate_address(token_id):
            raise JSONHTTPError(400,
                                body={
                                    'errors': [{
                                        'id': 'invalid_address',
                                        'message': 'Invalid Arguments'
                                    }]
                                })

        # check if the user has already submitted this app
        async with self.db:
            existing = await self.db.fetchrow(
                "SELECT * FROM submissions WHERE submitter_token_id = $1 AND app_token_id = $2",
                self.current_user, self.json['token_id'])
        if not existing:
            raise JSONHTTPError(400,
                                body={
                                    'errors': [{
                                        'id': 'app_does_not_exists',
                                        'message': 'App Doesn\'t exists'
                                    }]
                                })

        display_name = self.json['display_name']
        avatar_url = self.json.get('avatar_url', None)
        if not avatar_url:
            avatar_url = 'https://token-id-service.herokuapp.com/identicon/{}.png'.format(
                token_id)

        async with self.db:
            await self.db.execute(
                "UPDATE apps "
                "SET name = $1 "
                "WHERE token_id = $2", display_name, token_id)
            await self.db.execute(
                "UPDATE sofa_manifests "
                "SET avatar_url = $1 "
                "WHERE token_id = $2", avatar_url, token_id)
            row = await self.db.fetchrow(
                "SELECT * FROM apps "
                "JOIN sofa_manifests ON apps.token_id = sofa_manifests.token_id "
                "JOIN submissions ON submissions.app_token_id = apps.token_id "
                "WHERE apps.token_id = $1", token_id)
            await self.db.commit()

        self.write(response_for_row(row))
Exemple #11
0
    async def get(self, force_featured=None):

        try:
            offset = int(self.get_query_argument('offset', 0))
            limit = int(self.get_query_argument('limit', 10))
        except ValueError:
            raise JSONHTTPError(400, body={'errors': [{'id': 'bad_arguments', 'message': 'Bad Arguments'}]})

        query = self.get_query_argument('query', None)
        payment_address = self.get_query_argument('payment_address', None)
        if payment_address and not validate_address(payment_address):
            raise JSONHTTPError(400, body={'errors': [{'id': 'bad_arguments', 'message': 'Invalid payment_address'}]})

        if force_featured:
            featured = True
        else:
            featured = self.get_query_argument('featured', 'false')
            if featured.lower() == 'false':
                featured = False
            else:
                featured = True

        if query is None:
            where_q = []
            order_by = []
            args = [offset, limit]
            if payment_address:
                where_q.append("payment_address = ${}".format(len(args) + 1))
                args.append(payment_address)
                order_by.append(payment_address)
            if featured:
                where_q.append("featured = ${}".format(len(args) + 1))
                args.append(True)
            where_q.append("blocked = ${}".format(len(args) + 1))
            args.append(False)
            where_q.append("is_app = ${}".format(len(args) + 1))
            args.append(True)
            order_by.extend(['name', 'username'])
            async with self.db:
                sql = ("SELECT * FROM users WHERE {} "
                       "ORDER BY {} "
                       "OFFSET $1 LIMIT $2".format(" AND ".join(where_q), ", ".join(order_by)))
                rows = await self.db.fetch(
                    sql,
                    *args)
            results = [user_row_for_json(self.request, row) for row in rows]
        else:
            # strip punctuation
            query = ''.join([c for c in query if c not in string.punctuation])
            # split words and add in partial matching flags
            query = '|'.join(['{}:*'.format(word) for word in query.split(' ') if word])
            args = [offset, limit, query]
            where_q = []
            if payment_address:
                where_q.append("payment_address = ${}".format(len(args) + 1))
                args.append(payment_address)
            if featured:
                where_q.append("featured = ${}".format(len(args) + 1))
                args.append(True)
            where_q.append("is_app = ${}".format(len(args) + 1))
            args.append(True)
            where_q.append("blocked = ${}".format(len(args) + 1))
            args.append(False)
            where_q.append("is_app = ${}".format(len(args) + 1))
            args.append(True)
            where_q = " AND {}".format(" AND ".join(where_q)) if where_q else ""
            sql = ("SELECT * FROM "
                   "(SELECT * FROM users, TO_TSQUERY($3) AS q "
                   "WHERE (tsv @@ q){}) AS t1 "
                   "ORDER BY TS_RANK_CD(t1.tsv, TO_TSQUERY($3)) DESC, name, username "
                   "OFFSET $1 LIMIT $2"
                   .format(where_q))
            async with self.db:
                rows = await self.db.fetch(sql, *args)
            results = [user_row_for_json(self.request, row) for row in rows]
        querystring = 'query={}'.format(query)
        if payment_address:
            querystring += '&payment_address={}'.format(payment_address)

        self.write({
            'query': querystring,
            'offset': offset,
            'limit': limit,
            'results': results
        })
Exemple #12
0
    async def post(self):

        address = self.verify_request()
        payload = self.json

        # check if the address has already registered a username
        async with self.db:
            row = await self.db.fetchrow("SELECT * FROM users WHERE token_id = $1", address)
        if row is not None:
            raise JSONHTTPError(400, body={'errors': [{'id': 'already_registered', 'message': 'The provided token id address is already registered'}]})

        if 'username' in payload:

            username = payload['username']

            if not validate_username(username):
                raise JSONHTTPError(400, body={'errors': [{'id': 'invalid_username', 'message': 'Invalid Username'}]})

            # check username doesn't already exist
            async with self.db:
                row = await self.db.fetchrow("SELECT * FROM users WHERE lower(username) = lower($1)", username)
            if row is not None:
                raise JSONHTTPError(400, body={'errors': [{'id': 'username_taken', 'message': 'Username Taken'}]})

        else:

            # generate temporary username
            for i in itertools.count():
                username = generate_username(MIN_AUTOID_LENGTH + i)
                async with self.db:
                    row = await self.db.fetchrow("SELECT * FROM users WHERE lower(username) = lower($1)", username)
                if row is None:
                    break

        if 'payment_address' in payload:
            payment_address = payload['payment_address']
            if not validate_address(payment_address):
                raise JSONHTTPError(400, body={'errors': [{'id': 'invalid_payment_address', 'message': 'Invalid Payment Address'}]})
        else:
            #raise JSONHTTPError(400, body={'errors': [{'id': 'bad_arguments', 'message': 'Missing Payment Address'}]})
            # TODO: not required right now
            payment_address = None

        if 'is_app' in payload:
            is_app = parse_boolean(payload['is_app'])
            if is_app is None:
                raise JSONHTTPError(400, body={'errors': [{'id': 'bad_arguments', 'message': 'Bad Arguments'}]})
        else:
            is_app = False

        if 'avatar' in payload:
            avatar = payload['avatar']
            if not isinstance(avatar, str):
                raise JSONHTTPError(400, body={'errors': [{'id': 'bad_arguments', 'message': 'Bad Arguments'}]})
        else:
            avatar = None

        if 'name' in payload:
            name = payload['name']
            if not isinstance(name, str):
                raise JSONHTTPError(400, body={'errors': [{'id': 'bad_arguments', 'message': 'Bad Arguments'}]})
        else:
            name = None

        if 'about' in payload:
            about = payload['about']
            if not isinstance(about, str):
                raise JSONHTTPError(400, body={'errors': [{'id': 'bad_arguments', 'message': 'Bad Arguments'}]})
        else:
            about = None

        if 'location' in payload:
            location = payload['location']
            if not isinstance(location, str):
                raise JSONHTTPError(400, body={'errors': [{'id': 'bad_arguments', 'message': 'Bad Arguments'}]})
        else:
            location = None

        async with self.db:
            await self.db.execute("INSERT INTO users "
                                  "(username, token_id, payment_address, name, avatar, is_app, about, location) "
                                  "VALUES "
                                  "($1, $2, $3, $4, $5, $6, $7, $8)",
                                  username, address, payment_address, name, avatar, is_app, about, location)
            user = await self.db.fetchrow("SELECT * FROM users WHERE token_id = $1", address)
            await self.db.commit()

        self.write(user_row_for_json(self.request, user))
Exemple #13
0
    async def update_user(self, address):

        try:
            payload = self.json
        except:
            raise JSONHTTPError(400, body={'errors': [{'id': 'bad_data', 'message': 'Error decoding data. Expected JSON content'}]})

        async with self.db:

            # make sure a user with the given address exists
            user = await self.db.fetchrow("SELECT * FROM users WHERE token_id = $1", address)
            if user is None:
                raise JSONHTTPError(404, body={'errors': [{'id': 'not_found', 'message': 'Not Found'}]})

            # backwards compat
            if 'custom' in payload:
                custom = payload.pop('custom')
                if 'name' in custom:
                    payload['name'] = custom['name']
                if 'avatar' in custom:
                    payload['avatar'] = custom['avatar']
                if 'about' in custom:
                    payload['about'] = custom['about']
                if 'location' in custom:
                    payload['location'] = custom['location']

            if not any(x in payload for x in ['username', 'about', 'name', 'avatar', 'payment_address', 'is_app', 'location']):
                raise JSONHTTPError(400, body={'errors': [{'id': 'bad_arguments', 'message': 'Bad Arguments'}]})

            if 'username' in payload and user['username'] != payload['username']:
                username = payload['username']
                if not validate_username(username):
                    raise JSONHTTPError(400, body={'errors': [{'id': 'invalid_username', 'message': 'Invalid Username'}]})

                # make sure the username isn't used by a different user
                row = await self.db.fetchrow("SELECT * FROM users WHERE lower(username) = lower($1)", username)
                if row is not None:
                    raise JSONHTTPError(400, body={'errors': [{'id': 'username_taken', 'message': 'Username Taken'}]})

                await self.db.execute("UPDATE users SET username = $1 WHERE token_id = $2", username, address)

            if 'payment_address' in payload and payload['payment_address'] != user['payment_address']:
                payment_address = payload['payment_address']
                if not validate_address(payment_address):
                    raise JSONHTTPError(400, body={'errors': [{'id': 'invalid_payment_address', 'message': 'Invalid Payment Address'}]})
                await self.db.execute("UPDATE users SET payment_address = $1 WHERE token_id = $2", payment_address, address)

            if 'is_app' in payload and payload['is_app'] != user['is_app']:
                is_app = parse_boolean(payload['is_app'])
                if not isinstance(is_app, bool):
                    raise JSONHTTPError(400, body={'errors': [{'id': 'bad_arguments', 'message': 'Bad Arguments'}]})
                await self.db.execute("UPDATE users SET is_app = $1 WHERE token_id = $2", is_app, address)

            if 'name' in payload and payload['name'] != user['name']:
                name = payload['name']
                if not isinstance(name, str):
                    raise JSONHTTPError(400, body={'errors': [{'id': 'bad_arguments', 'message': 'Invalid Name'}]})
                await self.db.execute("UPDATE users SET name = $1 WHERE token_id = $2", name, address)

            if 'avatar' in payload and payload['avatar'] != user['avatar']:
                avatar = payload['avatar']
                if not isinstance(avatar, str):
                    raise JSONHTTPError(400, body={'errors': [{'id': 'bad_arguments', 'message': 'Invalid Avatar'}]})
                await self.db.execute("UPDATE users SET avatar = $1 WHERE token_id = $2", avatar, address)

            if 'about' in payload and payload['about'] != user['about']:
                about = payload['about']
                if not isinstance(about, str):
                    raise JSONHTTPError(400, body={'errors': [{'id': 'bad_arguments', 'message': 'Invalid About'}]})
                await self.db.execute("UPDATE users SET about = $1 WHERE token_id = $2", about, address)

            if 'location' in payload and payload['location'] != user['location']:
                location = payload['location']
                if not isinstance(location, str):
                    raise JSONHTTPError(400, body={'errors': [{'id': 'bad_arguments', 'message': 'Invalid Location'}]})
                await self.db.execute("UPDATE users SET location = $1 WHERE token_id = $2", location, address)

            user = await self.db.fetchrow("SELECT * FROM users WHERE token_id = $1", address)
            await self.db.commit()

        self.write(user_row_for_json(self.request, user))
Exemple #14
0
    def do_POST(self):

        # TODO: figure out why read is blocking here
        data = self.rfile.read(len(self.rfile.peek()))
        data = data.decode('utf-8')
        data = json.loads(data)

        if self.path == "/v1/tx/skel":

            gas_price = parse_int(
                data['gas_price']) if 'gas_price' in data else DEFAULT_GASPRICE
            gas = parse_int(data['gas']) if 'gas' in data else DEFAULT_STARTGAS
            nonce = parse_int(data['nonce']) if 'nonce' in data else 0

            if 'value' not in data or 'from' not in data or 'to' not in data:
                self.write_data(
                    400, {
                        'errors': [{
                            'id': 'bad_arguments',
                            'message': 'Bad Arguments'
                        }]
                    })
                return
            value = parse_int(data['value'])
            to_address = data['to']
            from_address = data['from']

            if not validate_address(to_address):
                self.write_data(
                    400, {
                        'errors': [{
                            'id': 'invalid_to_address',
                            'message': 'Invalid To Address'
                        }]
                    })
                return
            if not validate_address(from_address):
                self.write_data(
                    400, {
                        'errors': [{
                            'id': 'invalid_from_address',
                            'message': 'Invalid From Address'
                        }]
                    })
                return

            tx = create_transaction(nonce=nonce,
                                    gasprice=gas_price,
                                    startgas=gas,
                                    to=to_address,
                                    value=value)

            transaction = encode_transaction(tx)

            self.write_data(
                200, {
                    "tx_data": {
                        "nonce": hex(nonce),
                        "from": from_address,
                        "to": to_address,
                        "value": hex(value),
                        "startGas": hex(gas),
                        "gasPrice": hex(gas_price)
                    },
                    "tx": transaction
                })

        elif self.path == "/v1/tx":

            tx = decode_transaction(data['tx'])

            if 'signature' in data:

                sig = data_decoder(data['signature'])

                add_signature_to_transaction(tx, sig)

            self.write_data(200, {"tx_hash": data_encoder(tx.hash)})

        else:

            self.write_data(404)