예제 #1
0
 def test_validate_erc20_transfer_data_ng_tip_value_greater_than_maximum(self):
     method = 'a9059cbb'
     to_address = format(10, '064x')
     tip_value = format(10 ** 24 + 1, '064x')
     test_tx = method + to_address + tip_value
     with self.assertRaises(ValidationError) as e:
         PrivateChainUtil.validate_erc20_transfer_data(test_tx, '0x' + to_address[24:])
     self.assertEqual(
         e.exception.args[0],
         '1000000000000000000000001 is greater than the maximum of 1000000000000000000000000'
     )
예제 #2
0
 def test_validate_message_signature_ng(self):
     web3 = Web3(HTTPProvider('http://localhost:8584'))
     test_account = web3.eth.account.create()
     test_message = 'hogepiyo'
     failure_signature = '0xabcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef' \
                         '0123456789abcdef0123456789abcdef0123456789ab'
     with self.assertRaises(BadSignature) as e:
         PrivateChainUtil.validate_message_signature(
             test_message,
             failure_signature,
             test_account.address
         )
     self.assertEqual(e.exception.args[0], 'Invalid signature')
예제 #3
0
 def validate_params(self):
     # single
     validate(self.params, self.get_schema())
     # relational
     PrivateChainUtil.validate_message_signature(
         self.event['requestContext']['authorizer']['claims']['cognito:username'],
         self.params['signature'],
         self.params['wallet_address']
     )
     # 既に登録済みの場合は処理中断
     if UserUtil.exists_private_eth_address(self.dynamodb,
                                            self.event['requestContext']['authorizer']['claims']['cognito:username']):
         raise ValidationError('private_eth_address is exists.')
예제 #4
0
 def test_validate_raw_transaction_signature_ok(self):
     web3 = Web3(HTTPProvider('http://localhost:8584'))
     test_account = web3.eth.account.create()
     transaction = {
         'to': '0xF0109fC8DF283027b6285cc889F5aA624EaC1F55',
         'value': 1000000000,
         'gas': 2000000,
         'gasPrice': 234567897654321,
         'nonce': 0,
         'chainId': 1
     }
     signed = web3.eth.account.sign_transaction(transaction, test_account.key)
     # 例外が発生しないこと
     PrivateChainUtil.validate_raw_transaction_signature(signed.rawTransaction.hex(), test_account.address)
예제 #5
0
 def test_validate_message_signature_ok(self):
     web3 = Web3(HTTPProvider('http://localhost:8584'))
     test_account = web3.eth.account.create()
     test_message = 'hogepiyo'
     sign_message = web3.eth.account.sign_message(
         encode_defunct(text=test_message),
         private_key=test_account.key.hex()
     )
     # 例外が発生しないこと
     PrivateChainUtil.validate_message_signature(
         test_message,
         sign_message['signature'].hex(),
         test_account.address
     )
 def __get_timestamp_by_block_number(self, block_number):
     url = 'https://' + os.environ[
         'PRIVATE_CHAIN_EXECUTE_API_HOST'] + '/production/eth/get_block_by_number'
     payload_dict = {
         'block_num': block_number,
     }
     return PrivateChainUtil.send_transaction(
         request_url=url, payload_dict=payload_dict).get('timestamp')
    def __is_burnable_user(eth_address, tip_value, burn_value):
        # get_balance
        token = PrivateChainUtil.get_balance(eth_address)

        # return result
        if int(token, 16) >= tip_value + burn_value:
            return True
        return False
 def __polling_to_private_chain(self, purchase_transaction):
     try:
         if PrivateChainUtil.is_transaction_completed(purchase_transaction):
             return 'done'
         return 'doing'
     except (SendTransactionError, ReceiptError) as e:
         logging.info(e)
         return 'fail'
예제 #9
0
 def __get_apply_relay_events_specified_block_range(self, from_block, to_block, user_eth_address):
     url = 'https://' + os.environ['PRIVATE_CHAIN_EXECUTE_API_HOST'] + '/production/wallet/apply_relay_events'
     payload_dict = {
         'from_block': from_block,
         'to_block': to_block,
         'recipient_eth_address': user_eth_address[2:],
     }
     return PrivateChainUtil.send_transaction(request_url=url, payload_dict=payload_dict)
예제 #10
0
 def test_get_data_from_raw_transaction_ng_failure_v(self):
     web3 = Web3(HTTPProvider('http://localhost:8584'))
     test_account = web3.eth.account.create()
     test_data = '0xa9059cbb'
     nonce = 10
     transaction = {
         'nonce': nonce,
         'gasPrice': 0,
         'gas': 100000,
         'to': web3.toChecksumAddress(os.environ['PRIVATE_CHAIN_ALIS_TOKEN_ADDRESS']),
         'value': 0,
         'data': test_data,
         'chainId': 8994
     }
     signed = web3.eth.account.sign_transaction(transaction, test_account.key)
     with self.assertRaises(ValidationError) as e:
         PrivateChainUtil.get_data_from_raw_transaction(signed.rawTransaction.hex(), format(nonce, '#x'))
     self.assertEqual(e.exception.args[0], 'v is invalid')
예제 #11
0
 def test_get_data_from_raw_transaction_ng_failure_to(self):
     web3 = Web3(HTTPProvider('http://localhost:8584'))
     test_account = web3.eth.account.create()
     test_data = '0xa9059cbb'
     nonce = 10
     transaction = {
         'nonce': nonce,
         'gasPrice': 0,
         'gas': 100000,
         'to': test_account.address,
         'value': 0,
         'data': test_data,
         'chainId': 8995
     }
     signed = web3.eth.account.sign_transaction(transaction, test_account.key)
     with self.assertRaises(ValidationError) as e:
         PrivateChainUtil.get_data_from_raw_transaction(signed.rawTransaction.hex(), format(nonce, '#x'))
     self.assertEqual(e.exception.args[0], 'private_chain_alis_token_address is invalid')
 def __validate_has_not_token(self, params):
     address = params.get('custom:private_eth_address')
     if address is not None:
         url = 'https://' + os.environ[
             'PRIVATE_CHAIN_EXECUTE_API_HOST'] + '/production/wallet/balance'
         payload = {'private_eth_address': address[2:]}
         token = PrivateChainUtil.send_transaction(request_url=url,
                                                   payload_dict=payload)
         if token is not None and token != '0x0000000000000000000000000000000000000000000000000000000000000000':
             raise ValidationError("Do not allow phone number updates")
예제 #13
0
 def test_validate_raw_transaction_signature_ng(self):
     web3 = Web3(HTTPProvider('http://localhost:8584'))
     test_account = web3.eth.account.create()
     transaction = {
         'to': '0xF0109fC8DF283027b6285cc889F5aA624EaC1F55',
         'value': 1000000000,
         'gas': 2000000,
         'gasPrice': 234567897654321,
         'nonce': 0,
         'chainId': 1
     }
     signed = web3.eth.account.sign_transaction(transaction, test_account.key)
     failure_address = '0x123456789a123456789a123456789a123456789a'
     with self.assertRaises(ValidationError) as e:
         PrivateChainUtil.validate_raw_transaction_signature(
             signed.rawTransaction.hex(),
             failure_address
         )
     self.assertEqual(e.exception.args[0], 'Signature is invalid')
 def __get_allowance(from_user_eth_address):
     payload = {
         'from_user_eth_address': from_user_eth_address,
         'owner_eth_address': from_user_eth_address[2:],
         'spender_eth_address':
         os.environ['PRIVATE_CHAIN_BRIDGE_ADDRESS'][2:]
     }
     url = 'https://' + os.environ[
         'PRIVATE_CHAIN_EXECUTE_API_HOST'] + '/production/wallet/allowance'
     return PrivateChainUtil.send_transaction(request_url=url,
                                              payload_dict=payload)
    def exec_main_proc(self):
        address = self.event['requestContext']['authorizer']['claims'].get(
            'custom:private_eth_address')

        # nonce を取得
        if address is None:
            # まだウォレットアドレスを作成していないユーザには 0 を返す
            nonce = '0x0'
        else:
            nonce = PrivateChainUtil.get_transaction_count(address)

        return {'statusCode': 200, 'body': json.dumps({'nonce': nonce})}
예제 #16
0
    def validate_params(self):
        # 認証・ウォレット情報が登録済であること
        UserUtil.verified_phone_and_email(self.event)
        UserUtil.validate_private_eth_address(
            self.dynamodb, self.event['requestContext']['authorizer']['claims']
            ['cognito:username'])
        # single
        validate(self.params, self.get_schema())
        # 署名が正しいこと
        if self.params.get('init_approve_signed_transaction') is not None:
            PrivateChainUtil.validate_raw_transaction_signature(
                self.params['init_approve_signed_transaction'],
                self.event['requestContext']['authorizer']['claims']
                ['custom:private_eth_address'])
        PrivateChainUtil.validate_raw_transaction_signature(
            self.params['approve_signed_transaction'],
            self.event['requestContext']['authorizer']['claims']
            ['custom:private_eth_address'])
        PrivateChainUtil.validate_raw_transaction_signature(
            self.params['relay_signed_transaction'],
            self.event['requestContext']['authorizer']['claims']
            ['custom:private_eth_address'])

        # pinコードを検証
        self.__validate_pin_code(self.params['access_token'],
                                 self.params['pin_code'])
예제 #17
0
 def test_is_transaction_completed_ok_last(self):
     with patch('requests.post') as mock_post:
         mock_post.side_effect = [
             FakeResponse(status_code=200, text='{}'),
             FakeResponse(status_code=200, text='{}'),
             FakeResponse(status_code=200, text='{}'),
             FakeResponse(status_code=200, text='{}'),
             FakeResponse(status_code=200, text='{"result": {"logs": [{"type": "mined"}]}}')
         ]
         tran = '0x1234567890123456789012345678901234567890'
         response = PrivateChainUtil.is_transaction_completed(transaction=tran)
         self.assertEqual(response, True)
         self.assertEqual(mock_post.call_count, settings.TRANSACTION_CONFIRM_COUNT)
예제 #18
0
    def test_send_raw_transaction_ok(self):
        test_raw_transaction = '0xabcdef0123456789'
        test_url = 'https://' + os.environ['PRIVATE_CHAIN_EXECUTE_API_HOST'] + '/production/eth/send_raw_transaction'
        magic_lib = MagicMock(return_value='0x10')
        with patch('private_chain_util.PrivateChainUtil.send_transaction', magic_lib):
            result = PrivateChainUtil.send_raw_transaction(test_raw_transaction)
            self.assertEqual('0x10', result)

            _, kwargs = magic_lib.call_args
            expect_payload = {
                'raw_transaction': test_raw_transaction
            }
            self.assertEqual(test_url, kwargs['request_url'])
            self.assertEqual(expect_payload, kwargs['payload_dict'])
 def __relay(from_user_eth_address, recipient_eth_address, send_value,
             nonce):
     payload = {
         'from_user_eth_address': from_user_eth_address,
         'recipient_eth_address': recipient_eth_address[2:],
         'nonce': nonce,
         'amount': format(send_value, '064x')
     }
     url = 'https://' + os.environ[
         'PRIVATE_CHAIN_EXECUTE_API_HOST'] + '/production/wallet/relay'
     # relay 実施
     result = PrivateChainUtil.send_transaction(request_url=url,
                                                payload_dict=payload)
     return result
    def exec_main_proc(self):
        from_user_eth_address = self.event['requestContext']['authorizer']['claims'].get('custom:private_eth_address')

        # allowance を取得
        # まだウォレットアドレスを作成していないユーザには 0 を返す
        if from_user_eth_address is None:
            allowance = '0x0'
        else:
            allowance = PrivateChainUtil.get_allowance(from_user_eth_address)

        return {
            'statusCode': 200,
            'body': json.dumps({'allowance': allowance})
        }
    def validate_params(self):
        # 認証・ウォレット情報が登録済であること
        UserUtil.verified_phone_and_email(self.event)
        UserUtil.validate_private_eth_address(
            self.dynamodb, self.event['requestContext']['authorizer']['claims']
            ['cognito:username'])

        # single
        validate(self.params, self.get_schema())
        # 署名が正しいこと
        PrivateChainUtil.validate_raw_transaction_signature(
            self.params['tip_signed_transaction'], self.event['requestContext']
            ['authorizer']['claims']['custom:private_eth_address'])
        PrivateChainUtil.validate_raw_transaction_signature(
            self.params['burn_signed_transaction'],
            self.event['requestContext']['authorizer']['claims']
            ['custom:private_eth_address'])

        # relation
        # 公開されている記事であること
        DBUtil.validate_article_existence(self.dynamodb,
                                          self.params['article_id'],
                                          status='public')
 def __approve(from_user_eth_address, send_value, nonce):
     payload = {
         'from_user_eth_address': from_user_eth_address,
         'spender_eth_address':
         os.environ['PRIVATE_CHAIN_BRIDGE_ADDRESS'][2:],
         'nonce': nonce,
         'value': format(send_value, '064x')
     }
     url = 'https://' + os.environ[
         'PRIVATE_CHAIN_EXECUTE_API_HOST'] + '/production/wallet/approve'
     # approve 実施
     result = PrivateChainUtil.send_transaction(request_url=url,
                                                payload_dict=payload)
     return result
예제 #23
0
    def test_get_transaction_count_ok(self):
        test_address = '0x401BA17D89D795B3C6e373c5062F1C3F8979e73B'
        test_url = 'https://' + os.environ['PRIVATE_CHAIN_EXECUTE_API_HOST'] + '/production/eth/get_transaction_count'
        test_count = '0x10'
        magic_lib = MagicMock(return_value=test_count)
        with patch('private_chain_util.PrivateChainUtil.send_transaction', magic_lib):
            result = PrivateChainUtil.get_transaction_count(test_address)
            self.assertEqual(test_count, result)

            _, kwargs = magic_lib.call_args
            expect_payload = {
                'from_user_eth_address': test_address
            }
            self.assertEqual(test_url, kwargs['request_url'])
            self.assertEqual(expect_payload, kwargs['payload_dict'])
    def exec_main_proc(self):
        user_id = self.event['requestContext']['authorizer']['claims'][
            'cognito:username']
        address = self.event['requestContext']['authorizer']['claims'].get(
            'custom:private_eth_address')

        # 現在のトークン量を取得
        # まだウォレットアドレスを作成していないユーザには 0 を返す
        if address is None:
            balance = '0x0'
        elif not UserUtil.exists_private_eth_address(self.dynamodb, user_id):
            # Cognito上にprivate_eth_addressは存在するが、カストディ規制のウォレット移行が完了していないユーザにも0を返す
            balance = '0x0'
        else:
            balance = PrivateChainUtil.get_balance(address)

        return {'statusCode': 200, 'body': json.dumps({'result': balance})}
예제 #25
0
    def test_get_allowance_ok(self):
        test_address = '0x401BA17D89D795B3C6e373c5062F1C3F8979e73B'
        test_url = 'https://' + os.environ['PRIVATE_CHAIN_EXECUTE_API_HOST'] + '/production/wallet/allowance'
        test_allowance = '0x10'
        magic_lib = MagicMock(return_value=test_allowance)
        with patch('private_chain_util.PrivateChainUtil.send_transaction', magic_lib):
            result = PrivateChainUtil.get_allowance(test_address)
            self.assertEqual(test_allowance, result)

            _, kwargs = magic_lib.call_args
            expect_payload = {
                'from_user_eth_address': test_address,
                'owner_eth_address': test_address[2:],
                'spender_eth_address': os.environ['PRIVATE_CHAIN_BRIDGE_ADDRESS'][2:]
            }
            self.assertEqual(test_url, kwargs['request_url'])
            self.assertEqual(expect_payload, kwargs['payload_dict'])
예제 #26
0
 def test_get_data_from_raw_transaction_ok_with_nonce_zero(self):
     web3 = Web3(HTTPProvider('http://localhost:8584'))
     test_account = web3.eth.account.create()
     test_data = '0xa9059cbb'
     nonce = 0
     transaction = {
         'nonce': nonce,
         'gasPrice': 0,
         'gas': 100000,
         'to': web3.toChecksumAddress(os.environ['PRIVATE_CHAIN_ALIS_TOKEN_ADDRESS']),
         'value': 0,
         'data': test_data,
         'chainId': 8995
     }
     signed = web3.eth.account.sign_transaction(transaction, test_account.key)
     actual = PrivateChainUtil.get_data_from_raw_transaction(signed.rawTransaction.hex(), format(nonce, '#x'))
     self.assertEqual(test_data[2:], actual)
예제 #27
0
    def test_main_ok_call_validate_methods(self):
        test_tip_value = 10
        to_address = format(10, '064x')
        burn_value = int(test_tip_value / Decimal(10))
        raw_transactions = self.create_singed_transactions(
            to_address, test_tip_value, burn_value)

        with patch('me_wallet_tip.UserUtil.get_private_eth_address') as mock_get_private_eth_address, \
                patch('me_wallet_tip.UserUtil.verified_phone_and_email') as mock_verified_phone_and_email, \
                patch('me_wallet_tip.UserUtil.validate_private_eth_address') as mock_validate_private_eth_address, \
                patch('me_wallet_tip.PrivateChainUtil.validate_raw_transaction_signature') as mock_validate_signature, \
                patch('me_wallet_tip.PrivateChainUtil.validate_erc20_transfer_data') \
                as mock_validate_erc20_transfer_data:
            mock_get_private_eth_address.return_value = '0x' + to_address[24:]
            target_article_id = self.article_info_table_items[0]['article_id']

            event = {
                'body': {
                    'article_id':
                    target_article_id,
                    'tip_signed_transaction':
                    raw_transactions['tip'].rawTransaction.hex(),
                    'burn_signed_transaction':
                    raw_transactions['burn'].rawTransaction.hex()
                },
                'requestContext': {
                    'authorizer': {
                        'claims': {
                            'cognito:username': '******',
                            'custom:private_eth_address':
                            self.test_account.address,
                            'phone_number_verified': 'true',
                            'email_verified': 'true'
                        }
                    }
                }
            }
            event['body'] = json.dumps(event['body'])

            response = MeWalletTip(event, {}, self.dynamodb,
                                   cognito=None).main()
            self.assertEqual(response['statusCode'], 200)
            # verified_phone_and_email
            args, _ = mock_verified_phone_and_email.call_args
            self.assertEqual(event, args[0])
            # validate_private_eth_address
            args, _ = mock_validate_private_eth_address.call_args
            self.assertEqual(self.dynamodb, args[0])
            self.assertEqual('act_user_01', args[1])
            # validate_raw_transaction_signature
            args, _ = mock_validate_signature.call_args_list[0]
            self.assertEqual(raw_transactions['tip'].rawTransaction.hex(),
                             args[0])
            self.assertEqual(self.test_account.address, args[1])
            args, _ = mock_validate_signature.call_args_list[1]
            self.assertEqual(raw_transactions['burn'].rawTransaction.hex(),
                             args[0])
            self.assertEqual(self.test_account.address, args[1])
            # validate_erc20_transfer_data
            args, _ = mock_validate_erc20_transfer_data.call_args_list[0]
            tip_data = PrivateChainUtil.get_data_from_raw_transaction(
                raw_transactions['tip'].rawTransaction.hex(), '0x5')
            self.assertEqual(tip_data, args[0])
            self.assertEqual('0x' + to_address[24:], args[1])
            args, _ = mock_validate_erc20_transfer_data.call_args_list[1]
            burn_data = PrivateChainUtil.get_data_from_raw_transaction(
                raw_transactions['burn'].rawTransaction.hex(), '0x6')
            self.assertEqual(burn_data, args[0])
            self.assertEqual('0x' + os.environ['BURN_ADDRESS'], args[1])
예제 #28
0
    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})
        }
예제 #29
0
 def __get_relay_paused():
     return PrivateChainUtil.send_transaction(
         'https://' + os.environ['PRIVATE_CHAIN_EXECUTE_API_HOST'] +
         '/production/wallet/relay_paused')
예제 #30
0
 def __get_min_single_relay_amount():
     return PrivateChainUtil.send_transaction(
         'https://' + os.environ['PRIVATE_CHAIN_EXECUTE_API_HOST'] +
         '/production/wallet/min_single_relay_amount')