def test_validate_erc20_approve_data_ng_token_send_value_less_than_minimum(self): method = '095ea7b3' spender_eth_address = format(0, '024x') + os.environ['PRIVATE_CHAIN_BRIDGE_ADDRESS'][2:] token_send_value = format(1000000000000000000 - 1, '064x') test_tx = method + spender_eth_address + token_send_value with self.assertRaises(ValidationError) as e: PrivateChainUtil.validate_erc20_approve_data(test_tx) self.assertEqual(e.exception.args[0], '999999999999999999 is less than the minimum of 1000000000000000000')
def test_validate_erc20_approve_data_ng_method(self): method = 'aaaaaaaa' spender_eth_address = format(0, '024x') + os.environ['PRIVATE_CHAIN_BRIDGE_ADDRESS'][2:] token_send_value = format(100, '064x') test_tx = method + spender_eth_address + token_send_value with self.assertRaises(ValidationError) as e: PrivateChainUtil.validate_erc20_approve_data(test_tx) self.assertEqual(e.exception.args[0], 'method is invalid')
def test_validate_erc20_approve_data_ng_spender_eth_address(self): method = '095ea7b3' spender_eth_address = format(10, '064x') token_send_value = format(100, '064x') test_tx = method + spender_eth_address + token_send_value with self.assertRaises(ValidationError) as e: PrivateChainUtil.validate_erc20_approve_data(test_tx) self.assertEqual(e.exception.args[0], 'spender_eth_address is invalid')
def test_validate_erc20_approve_data_ok_token_send_value_zero(self): method = '095ea7b3' spender_eth_address = format(0, '024x') + os.environ['PRIVATE_CHAIN_BRIDGE_ADDRESS'][2:] token_send_value = format(0, '064x') test_tx = method + spender_eth_address + token_send_value # 例外が発生しないこと # 引数で利用する spender_eth_address は先頭に 0x が付き、かつ40文字想定なので '0x' + spender_eth_address[24:] のように修正している PrivateChainUtil.validate_erc20_approve_data(test_tx)
def exec_main_proc(self): ################ # get parameter ################ sort_key = TimeUtil.generate_sort_key() from_user_eth_address = self.event['requestContext']['authorizer'][ 'claims']['custom:private_eth_address'] user_id = self.event['requestContext']['authorizer']['claims'][ 'cognito:username'] allowance = PrivateChainUtil.get_allowance(from_user_eth_address) transaction_count = PrivateChainUtil.get_transaction_count( from_user_eth_address) ################ # validation ################ # validate raw_transaction # init_approve_signed_transaction if int(allowance, 16) != 0: # allowance が設定されている場合は必須 if self.params.get('init_approve_signed_transaction') is None: raise ValidationError( 'init_approve_signed_transaction is invalid.') # data init_approve_data = PrivateChainUtil.get_data_from_raw_transaction( self.params['init_approve_signed_transaction'], transaction_count) PrivateChainUtil.validate_erc20_approve_data(init_approve_data) if int(init_approve_data[72:], 16) != 0: raise ValidationError('Value of init_approve is invalid.') transaction_count = PrivateChainUtil.increment_transaction_count( transaction_count) # approve_signed_transaction approve_data = PrivateChainUtil.get_data_from_raw_transaction( self.params['approve_signed_transaction'], transaction_count) PrivateChainUtil.validate_erc20_approve_data(approve_data) # 日次の限度額を超えていた場合は例外 sum_price = self.__get_token_send_value_today(user_id) if Decimal(os.environ['DAILY_LIMIT_TOKEN_SEND_VALUE'] ) < sum_price + Decimal(int(approve_data[72:], 16)): raise ValidationError('Token withdrawal limit has been exceeded.') transaction_count = PrivateChainUtil.increment_transaction_count( transaction_count) # relay_signed_transaction relay_data = PrivateChainUtil.get_data_from_raw_transaction( self.params['relay_signed_transaction'], transaction_count) PrivateChainUtil.validate_erc20_relay_data(relay_data) # approve と relay の value が同一であること approve_value = int(approve_data[72:], 16) relay_value = int(relay_data[72:], 16) if approve_value != relay_value: raise ValidationError('approve and relay values do not match.') ####################### # send_raw_transaction ####################### # 既に approve されている場合(allowance の戻り値が 0 ではない場合)、該当の approve を削除する(0 で更新) if int(allowance, 16) != 0: PrivateChainUtil.send_raw_transaction( self.params.get('init_approve_signed_transaction')) # approve 実施 approve_transaction_hash = PrivateChainUtil.send_raw_transaction( self.params.get('approve_signed_transaction')) self.__create_send_info_with_approve_transaction_hash( sort_key, user_id, approve_transaction_hash, relay_value) # token_send_table への書き込み完了後に出金関連の例外が発生した場合は、token_send_table のステータスを fail に更新する try: # relay 実施 relay_transaction_hash = PrivateChainUtil.send_raw_transaction( self.params.get('relay_signed_transaction')) self.__update_send_info_with_relay_transaction_hash( sort_key, user_id, relay_transaction_hash) # transaction の完了を確認 is_completed = PrivateChainUtil.is_transaction_completed( relay_transaction_hash) except SendTransactionError as e: # ステータスを fail に更新し中断 self.__update_send_info_with_send_status(sort_key, user_id, 'fail') raise e except ReceiptError: # send_value の値が残高を超えた場合や、処理最小・最大値の範囲に収まっていない場合に ReceiptError が発生するため # ValidationError として処理を中断する # ステータスを fail に更新 self.__update_send_info_with_send_status(sort_key, user_id, 'fail') raise ValidationError('send_value') # transaction が完了していた場合、ステータスを done に更新 if is_completed: self.__update_send_info_with_send_status(sort_key, user_id, 'done') return { 'statusCode': 200, 'body': json.dumps({'is_completed': is_completed}) }