async def withdraw_bulk(*args, **kwargs): try: WithdrawValidator.validate_withdraw(kwargs) except Exception as e: return WithdrawValidator.error_400(str(e)) try: request = await withdraw_handler.withdraw_bulk(*args, **kwargs) except Exception as e: return WithdrawValidator.error_500(str(e)) return request
async def is_valid_address(*args, **kwargs): try: WithdrawValidator.validate_is_valid_address(kwargs) except Exception as e: return WithdrawValidator.error_400(str(e)) try: request = await withdraw_handler.is_valid_address(*args, **kwargs) except Exception as e: return WithdrawValidator.error_500(str(e)) return request
async def create_token(*args, **kwargs): try: WithdrawValidator.validate_create_token(kwargs) except Exception as e: return WithdrawValidator.error_400(str(e)) try: request = await withdraw_handler.create_token(*args, **kwargs) except Exception as e: return WithdrawValidator.error_500(str(e)) return request
async def hot_wallet_history(*args, **kwargs): try: request = await withdraw_handler.hot_wallet_history(*args, **kwargs) except Exception as e: return WithdrawValidator.error_500(str(e)) return request
async def available_tokens(*args, **kwargs): try: request = await withdraw_handler.available_tokens(*args, **kwargs) except Exception as e: return WithdrawValidator.error_500(str(e)) return request
async def available_tokens(self, *args, **kwargs): try: token_names = [] async for token in self.db.available_tokens.find(): token_names.append(token) return token_names except Exception as e: return WithdrawValidator.error_500(str(e))
async def func_wrapper(*args, **kwargs): if check_sig: try: signature_validator.verify(kwargs) except: return WithdrawValidator.error_403('Invalid signature') kwargs = signature_validator.hex_to_json(kwargs['message']) return signature_validator.sign(await func(*args, **kwargs)) else: return await func(*args, **kwargs)
async def register_token(self, *args, **kwargs): try: await self.db.available_tokens.insert_one({ "_id": kwargs.get("token_name"), "contract_address": kwargs.get("contract_address"), "blockchain": kwargs.get("blockchain") }) except Exception as e: return WithdrawValidator.error_500(str(e)) return {'success': True}
async def hot_wallet_history(self, *args, **kwargs): try: executed_requests = [] async for executed in self.db.executed_withdraws.find( {}, { '_id': 0, 'timestamp': 0 }): executed['execution_time'] = executed[ 'execution_time'].isoformat() executed_requests.append(executed) return executed_requests except Exception as e: return WithdrawValidator.error_500(str(e))
async def send_to_cold_wallet(*args, **kwargs): try: WithdrawValidator.validate_withdraw(kwargs) WithdrawValidator.validate_cold_wallet_address(kwargs) except Exception as e: return WithdrawValidator.error_400(str(e)) try: request = await withdraw_handler.withdraw(*args, **kwargs) except Exception as e: return WithdrawValidator.error_500(str(e)) return request
async def execute_withdraws(self): print('reload') try: self.reload_connections() except Exception as e: return WithdrawValidator.error_500(str(e)) print('reloaded') query = { 'timestamp': {'$lte': datetime.datetime.utcnow() - datetime.timedelta(milliseconds=WITHDRAW_DELAY)} } print('start loop') document_count = await self.db.withdraw_requests.count_documents(query) print('document_count: ', document_count) while document_count != 0: withdrawal_requests = {} for coinid in bitcoinlike_coinids: withdrawal_requests[coinid] = [] for coinid in ethereumlike_coinids: withdrawal_requests[coinid] = [] cursor = self.db.withdraw_requests.find(query) cursor.limit(OUTPUTS_PER_TX) to_delete = [] pprint(await self.db.withdraw_requests.count_documents(query)) async for withdrawal in cursor: if await self.db.executed_withdraws.find_one({'_id': withdrawal['_id']}): to_delete.append(withdrawal) print('deleted', withdrawal) else: withdrawal_requests[withdrawal['coinid']].append(withdrawal) print('appended', withdrawal) for expired in to_delete: await self.db.withdraw_requests.delete_one({'_id': expired['_id']}) print('deleted') for coinid, withdrawals in withdrawal_requests.items(): if coinid in ('BTCTEST', 'LTCTEST', 'QTUMTEST') and withdrawals: connection = self.connections[coinid] addresses_with_amount = { withdrawal['address']: withdrawal['amount'] / decimals_k for withdrawal in withdrawals } try: txid = connection.sendmany('', addresses_with_amount) for withdrawal in withdrawals: withdrawal['txid'] = txid withdrawal['execution_time'] = datetime.datetime.utcnow() await self.db.executed_withdraws.insert_one(withdrawal) await self.db.withdraw_requests.delete_one({'_id': withdrawal['_id']}) print('executed') except Exception as e: pprint(WithdrawValidator.error_500(str(e))) pprint(addresses_with_amount) else: for withdrawal in withdrawals: if coinid in ('ETH', 'ETHRINKEBY', 'ETHROPSTEN'): connection = self.connections[coinid] address = Web3.toChecksumAddress(withdrawal['address']) try: txid = connection.eth.sendTransaction({ 'to': address, 'from': hot_wallets[coinid], 'value': Web3.toWei(withdrawal['amount'] / decimals_k, 'ether') }) txid = encode_hex(txid)[0].decode() withdrawal['txid'] = txid withdrawal['execution_time'] = datetime.datetime.utcnow() await self.db.executed_withdraws.insert_one(withdrawal) await self.db.withdraw_requests.delete_one({'_id': withdrawal['_id']}) print('executed') except Exception as e: pprint(WithdrawValidator.error_500(str(e))) pprint(withdrawal) else: token = await self.db.available_tokens.find_one({'_id': coinid}) if token is None: pprint(WithdrawValidator.error_500('Unsupported coinid')) elif token['blockchain'] in ('QTUM', 'QTUMTEST'): connection = self.connections[coinid] address = Bip32Addresses.address_to_hex(withdrawal['address']) handler = Qrc20.from_connection( connection, token['contract_address'], erc20_abi ) handler.set_send_params({ 'gasLimit': transfer_settings[token['blockchain']]['gasLimit'], 'gasPrice': transfer_settings[token['blockchain']]['gasPrice'], 'sender': hot_wallets[coinid] }) try: txid = handler.transfer(address, withdrawal['amount'])['txid'] withdrawal['txid'] = txid withdrawal['execution_time'] = datetime.datetime.utcnow() await self.db.executed_withdraws.insert_one(withdrawal) await self.db.withdraw_requests.delete_one({'_id': withdrawal['_id']}) print('executed') except Exception as e: pprint(WithdrawValidator.error_500(str(e))) pprint(withdrawal) elif token['blockchain'] in ('ETHRINKEBY', 'ETH'): connection = self.connections[coinid] address = Web3.toChecksumAddress(withdrawal['address']) handler = Erc20.from_connection( connection, token['contract_address'], erc20_abi ) handler.set_send_params({ 'gasLimit': transfer_settings[token['blockchain']]['gasLimit'], 'gasPrice': transfer_settings[token['blockchain']]['gasPrice'], 'sender': hot_wallets[coinid]}) try: txid = handler.transfer(address, withdrawal['amount'])['txid'] withdrawal['txid'] = txid withdrawal['execution_time'] = datetime.datetime.utcnow() await self.db.executed_withdraws.insert_one(withdrawal) await self.db.withdraw_requests.delete_one({'_id': withdrawal['_id']}) print('executed') except Exception as e: pprint(WithdrawValidator.error_500(str(e))) pprint(withdrawal) document_count = await self.db.withdraw_requests.count_documents(query) print('document_count: ', document_count)
async def create_token(self, *args, **kwargs): try: super().reload_connections() except Exception as e: return WithdrawValidator.error_500(str(e)) token_name = kwargs.get('token_name') token_symbol = kwargs.get('token_symbol') total_supply = kwargs.get('total_supply') token_decimals = kwargs.get('decimals') blockchain = kwargs.get('blockchain') is_burnable = kwargs.get('is_burnable') is_mintable = kwargs.get('is_mintable') token_class_name = token_name.replace(' ', '_') await self.db.create_token_requests.insert_one({ 'token_name': token_name, 'token_symbol': token_symbol, 'total_supply': total_supply, 'token_decimals': token_decimals, 'blockchain': blockchain, 'is_burnable': is_burnable, 'is_mintable': is_mintable, 'timestamp': datetime.datetime.utcnow() }) formatted_code = erc20_code.format(token_name=token_name, token_class_name=token_class_name, token_symbol=token_symbol, token_decimals=token_decimals, total_supply=total_supply) try: contract_code = compile_source(formatted_code)['<stdin>:%s' % token_name]['bin'] except Exception as e: return WithdrawValidator.error_500(str(e)) if blockchain in ['QTUM', 'QTUMTEST']: qtum_connection = self.connections[blockchain] contract_handler = QtumContractHandler.from_connection( qtum_connection, None, '{}') contract_handler.set_send_params({ 'gasLimit': deploy_settings[blockchain]['gasLimit'], 'gasPrice': deploy_settings[blockchain]['gasPrice'], 'sender': hot_wallets[blockchain] }) try: result = contract_handler.deploy_contract(contract_code) except Exception as e: return WithdrawValidator.error_500( "Couldn't deploy smart contract. %s" % str(e)) return result elif blockchain in ['ETH', 'ETHRINKEBY', 'ETHROPSTEN']: connection = self.connections[blockchain] contract_address = make_contract_address( hot_wallets[blockchain], connection.eth.getTransactionCount(hot_wallets[blockchain])) custom_token_contract = connection.eth.contract( abi=erc20_abi, bytecode=contract_code) try: contract_data = custom_token_contract.constructor( ).buildTransaction( transaction={ 'from': hot_wallets[blockchain], 'gas': deploy_settings[blockchain]['gasLimit'], 'gasPrice': deploy_settings[blockchain]['gasPrice'], }) except Exception as e: return WithdrawValidator.error_500( 'Error building transaction. %s' % str(e)) try: tx_hash = connection.eth.sendTransaction(contract_data) except Exception as e: return WithdrawValidator.error_500( "Error sending transaction. %s" % str(e)) if tx_hash is None: return WithdrawValidator.error_500( "Error sending transaction. Hash is None") tx_hex = encode_hex(tx_hash)[0].decode() return {'txid': tx_hex, 'contract_address': contract_address} else: return WithdrawValidator.error_403('Unsupported blockchain')
async def withdraw_custom_token(self, *args, **kwargs): """ Withdraw custom token to user wallet Accepts: - address [hex string] (withdrawal address in hex form) - amount [int] withdrawal amount multiplied by decimals_k (10**8) - blockchain [string] token's blockchain (QTUMTEST, ETH) - contract_address [hex string] token contract address Returns dictionary with following fields: - txid [string] """ try: super().reload_connections() except Exception as e: return WithdrawValidator.error_500(str(e)) address = kwargs.get("address") amount = kwargs.get("amount") blockchain = kwargs.get("blockchain") contract_address = kwargs.get("contract_address") await self.db.withdraw_custom_token_requests.insert_one({ 'address': address, 'amount': amount, 'blockchain': blockchain, 'contract_address': contract_address, 'timestamp': datetime.datetime.utcnow() }) connection = self.connections[blockchain] if blockchain in ['QTUMTEST', 'QTUM']: address = Bip32Addresses.address_to_hex(address) handler = Qrc20.from_connection(connection, contract_address, erc20_abi) handler.set_send_params({ 'gasLimit': transfer_settings[blockchain]['gasLimit'], 'gasPrice': transfer_settings[blockchain]['gasPrice'], 'sender': hot_wallets[blockchain] }) try: txid = handler.transfer(address, amount)['txid'] except Exception as e: return WithdrawValidator.error_500(str(e)) elif blockchain in ['ETH', 'ETHRINKEBY', 'ETHROPSTEN']: address = Web3.toChecksumAddress(address) contract_address = Web3.toChecksumAddress(contract_address) handler = Erc20.from_connection(connection, contract_address, erc20_abi) handler.set_send_params({ 'gasLimit': transfer_settings[blockchain]['gasLimit'], 'gasPrice': transfer_settings[blockchain]['gasPrice'], 'sender': hot_wallets[blockchain] }) try: txid = handler.transfer(address, amount)['txid'] except Exception as e: return WithdrawValidator.error_500(str(e)) else: return WithdrawValidator.error_403('Unsupported blockchain') return {'txid': txid}
async def withdraw(self, *args, **kwargs): """ Withdraw funds to user wallet Accepts: - coinid [string] (blockchain id (example: BTCTEST, LTCTEST)) - address [string] withdrawal address (in hex for tokens) - amount [int] withdrawal amount multiplied by decimals_k (10**8) Returns dictionary with following fields: - txid [string] """ try: super().reload_connections() except Exception as e: return WithdrawValidator.error_500(str(e)) coinid = kwargs.get("coinid") address = kwargs.get("address") amount = int(kwargs.get("amount")) txid = None connection = self.connections[coinid] if coinid in ['BTCTEST', 'LTCTEST', 'QTUMTEST', 'BTC', 'LTC', 'QTUM']: try: txid = connection.sendtoaddress(address, str(amount / decimals_k)) except Exception as e: return WithdrawValidator.error_400(str(e)) elif coinid in ['ETH', 'ETHRINKEBY', 'ETHROPSTEN']: address = Web3.toChecksumAddress(address) try: txid = connection.eth.sendTransaction({ 'to': address, 'from': hot_wallets[coinid], 'value': Web3.toWei(amount / decimals_k, 'ether') }) txid = encode_hex(txid)[0].decode() except Exception as e: return WithdrawValidator.error_500(str(e)) else: token = await self.db.available_tokens.find_one({'_id': coinid}) if token is None: return WithdrawValidator.error_500('Unsupported coinid') elif token['blockchain'] in ('QTUM', 'QTUMTEST'): connection = self.connections[coinid] address = Bip32Addresses.address_to_hex(address) handler = Qrc20.from_connection(connection, token['contract_address'], erc20_abi) handler.set_send_params({ 'gasLimit': transfer_settings[token['blockchain']]['gasLimit'], 'gasPrice': transfer_settings[token['blockchain']]['gasPrice'], 'sender': hot_wallets[coinid] }) print(hot_wallets[coinid]) try: txid = handler.transfer(address, amount)['txid'] except Exception as e: return WithdrawValidator.error_500(str(e)) elif token['blockchain'] in ('ETHRINKEBY', 'ETH'): connection = self.connections[coinid] address = Web3.toChecksumAddress(address) handler = Erc20.from_connection(connection, token['contract_address'], erc20_abi) handler.set_send_params({ 'gasLimit': transfer_settings[token['blockchain']]['gasLimit'], 'gasPrice': transfer_settings[token['blockchain']]['gasPrice'], 'sender': hot_wallets[coinid] }) try: txid = handler.transfer(address, amount)['txid'] except Exception as e: return WithdrawValidator.error_500(str(e)) await self.db.executed_withdraws.insert_one({ 'coinid': coinid, 'address': address, 'amount': amount, 'txid': txid, 'timestamp': datetime.datetime.utcnow(), 'execution_time': datetime.datetime.utcnow() }) return {'txid': txid}