Exemple #1
0
    def test_script_hash_variable_with_builtin(self):
        from boa3.neo3.contracts import CallFlags
        call_flag = Integer(CallFlags.ALL).to_byte_array(signed=True,
                                                         min_length=1)
        twenty = Integer(20).to_byte_array()
        base58_identifier = String(Interop.Base58Decode.method_name).to_bytes()

        expected_output = (
            Opcode.INITSLOT + b'\x00\x01' + Opcode.LDARG0 + Opcode.DUP +
            Opcode.SIZE + Opcode.JMPIFNOT +
            Integer(47).to_byte_array(min_length=1) + Opcode.DUP +
            Opcode.ISTYPE + Type.str.stack_item + Opcode.JMPIF +
            Integer(4).to_byte_array(min_length=1) + Opcode.CONVERT +
            Type.str.stack_item + Opcode.PUSH1 + Opcode.PACK +
            Opcode.PUSHDATA1 +
            Integer(len(base58_identifier)).to_byte_array(min_length=1) +
            base58_identifier + Opcode.PUSHDATA1 +
            Integer(len(STD_LIB_SCRIPT)).to_byte_array(min_length=1) +
            STD_LIB_SCRIPT + Opcode.PUSHDATA1 +
            Integer(len(call_flag)).to_byte_array(min_length=1) + call_flag +
            Opcode.ROT + Opcode.ROT + Opcode.SYSCALL +
            Interop.CallContract.interop_method_hash + Opcode.DUP +
            Opcode.SIZE + Opcode.PUSHDATA1 +
            Integer(len(twenty)).to_byte_array(min_length=1) + twenty +
            Opcode.CONVERT + Type.int.stack_item + Opcode.JMPGT +
            Integer(8).to_byte_array(min_length=1) + Opcode.DUP + Opcode.SIZE +
            Opcode.DEC + Opcode.RIGHT + Opcode.JMP +
            Integer(9).to_byte_array(min_length=1) + Opcode.PUSH1 +
            Opcode.PUSHDATA1 +
            Integer(len(twenty)).to_byte_array(min_length=1) + twenty +
            Opcode.CONVERT + Type.int.stack_item + Opcode.SUBSTR +
            Opcode.CONVERT + Type.bytes.stack_item + Opcode.RET)

        path = self.get_contract_path('ScriptHashVariableBuiltinCall.py')
        output = Boa3.compile(path)
        self.assertEqual(expected_output, output)

        from boa3.neo import to_script_hash
        from base58 import b58encode
        engine = TestEngine()

        script_hash = to_script_hash('123')
        result = self.run_smart_contract(engine,
                                         path,
                                         'Main',
                                         '123',
                                         expected_result_type=bytes)
        self.assertEqual(script_hash, result)

        value = b58encode('123')
        if isinstance(value, int):
            value = Integer(value).to_byte_array()

        script_hash = to_script_hash(value)
        result = self.run_smart_contract(engine,
                                         path,
                                         'Main',
                                         value,
                                         expected_result_type=bytes)
        self.assertEqual(script_hash, result)
Exemple #2
0
    def test_bytes_script_hash(self):
        from boa3.neo import cryptography, to_script_hash

        input = b'\x01\x02\x03'
        expected_output = cryptography.hash160(input)
        output = to_script_hash(input)

        self.assertEqual(expected_output, output)
Exemple #3
0
    def test_string_script_hash(self):
        from boa3.neo import cryptography, to_script_hash

        input = String('123').to_bytes()
        expected_output = cryptography.hash160(input)
        output = to_script_hash(input)

        self.assertEqual(expected_output, output)
Exemple #4
0
    def test_integer_script_hash(self):
        from boa3.neo import cryptography, to_script_hash

        input = Integer(123).to_byte_array()
        expected_output = cryptography.hash160(input)
        output = to_script_hash(input)

        self.assertEqual(expected_output, output)
Exemple #5
0
    def test_string_script_hash(self):
        import base58
        from boa3.neo import to_script_hash

        input = String('123').to_bytes()
        expected_output = base58.b58decode(input)[1:]
        output = to_script_hash(input)

        self.assertEqual(expected_output, output)
    def test_script_hash_variable_with_builtin(self):
        path = self.get_contract_path('ScriptHashVariableBuiltinCall.py')
        from boa3.neo import to_script_hash
        from base58 import b58encode
        engine = TestEngine()

        script_hash = to_script_hash('123')
        result = self.run_smart_contract(engine, path, 'Main', '123',
                                         expected_result_type=bytes)
        self.assertEqual(script_hash, result)

        value = b58encode('123')
        if isinstance(value, int):
            value = Integer(value).to_byte_array()

        script_hash = to_script_hash(value)
        result = self.run_smart_contract(engine, path, 'Main', value,
                                         expected_result_type=bytes)
        self.assertEqual(script_hash, result)
    def test_script_hash_str_with_builtin(self):
        from boa3.neo import to_script_hash
        script_hash = to_script_hash(String('123').to_bytes())

        path = self.get_contract_path('ScriptHashStrBuiltinCall.py')
        output = Boa3.compile(path)

        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'Main')
        self.assertEqual(script_hash, result)
Exemple #8
0
    def test_script_hash_int_with_builtin(self):
        from boa3.neo import to_script_hash
        script_hash = to_script_hash(Integer(123).to_byte_array())

        path = self.get_contract_path('ScriptHashIntBuiltinCall.py')
        output = Boa3.compile(path)

        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'Main')
        self.assertEqual(script_hash, result)
    def test_script_hash_str(self):
        from boa3.neo import to_script_hash
        script_hash = to_script_hash(String('123').to_bytes())

        path = self.get_contract_path('ScriptHashStr.py')
        output = Boa3.compile(path)

        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'Main',
                                         expected_result_type=bytes)
        self.assertEqual(script_hash, result)
Exemple #10
0
    def test_address_script_hash(self):
        from base58 import b58decode
        from boa3.neo import cryptography, to_script_hash

        input = String('Nd7eAuHsKvvzHzSPyuJQALcYCcUrcwvm5W').to_bytes()
        expected_output = b58decode(input)[1:21]
        wrong_output = cryptography.hash160(input)
        output = to_script_hash(input)

        self.assertNotEqual(wrong_output, output)
        self.assertEqual(expected_output, output)
    def test_check_witness_imported_as(self):
        path = self.get_contract_path('CheckWitnessImportedAs.py')
        account = to_script_hash(b'NiNmXL8FjEUEs1nfX9uHFBNaenxDHJtmuB')

        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'Main', account)
        self.assertEqual(False, result)

        engine.add_signer_account(account)
        result = self.run_smart_contract(engine, path, 'Main', account)
        self.assertEqual(True, result)
    def visit_Call(self, call: ast.Call) -> ast.AST:
        """
        Visitor of a function call node

        :param call: the python ast function call node
        """
        if isinstance(call.func, ast.Attribute):
            from boa3.model.builtin.builtin import Builtin
            if call.func.attr == Builtin.ScriptHash.identifier:
                from boa3.constants import SYS_VERSION_INFO
                from boa3.model.type.type import Type
                types = {
                    Type.int.identifier: int,
                    Type.str.identifier: str,
                    Type.bytes.identifier: bytes
                }
                literal: tuple = ((ast.Constant, ) if SYS_VERSION_INFO >=
                                  (3, 8) else (ast.Num, ast.Str, ast.Bytes))

                if isinstance(call.func.value, literal) and len(
                        call.args) == 0:
                    value = ast.literal_eval(call.func.value)
                    if not isinstance(value, tuple(types.values())):
                        return call
                elif (isinstance(call.func.value,
                                 ast.Name)  # checks if is the name of a type
                      and call.func.value.id in
                      types  # and if the arguments is from the same type
                      and len(call.args) == 1
                      and isinstance(call.args[0], literal)):
                    value = ast.literal_eval(call.args[0])
                    if not isinstance(value, (types[call.func.value.id], )):
                        return call
                else:
                    return call

                from boa3.neo import to_script_hash
                # value must be bytes
                if isinstance(value, int):
                    from boa3.neo.vm.type.Integer import Integer
                    value = Integer(value).to_byte_array()
                elif isinstance(value, str):
                    from boa3.neo.vm.type.String import String
                    value = String(value).to_bytes()
                return self.parse_to_node(str(to_script_hash(value)), call)

        return call
    def test_script_hash_variable(self):
        path = self.get_contract_path('ScriptHashVariable.py')
        engine = TestEngine()
        with self.assertRaises(TestExecutionException):
            self.run_smart_contract(engine, path, 'Main', 123)

        from boa3.neo import to_script_hash
        from base58 import b58encode
        value = b58encode(Integer(123).to_byte_array())
        if isinstance(value, int):
            value = Integer(value).to_byte_array()

        script_hash = to_script_hash(value)

        result = self.run_smart_contract(engine, path, 'Main', value,
                                         expected_result_type=bytes)
        self.assertEqual(script_hash, result)
Exemple #14
0
class TestHTLCTemplate(BoaTest):

    default_folder: str = 'examples'

    OWNER_SCRIPT_HASH = bytes(20)
    OTHER_ACCOUNT_1 = to_script_hash(b'NiNmXL8FjEUEs1nfX9uHFBNaenxDHJtmuB')
    OTHER_ACCOUNT_2 = bytes(range(20))

    def test_HTLC_compile(self):
        path = self.get_contract_path('HTLC.py')
        Boa3.compile(path)

    def test_HTLC_deploy(self):
        path = self.get_contract_path('HTLC.py')
        engine = TestEngine()

        # deploying the smart contract
        result = self.run_smart_contract(
            engine,
            path,
            'deploy',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        # deploy can not occur more than once
        result = self.run_smart_contract(
            engine,
            path,
            'deploy',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(False, result)

    def test_HTLC_atomic_swap(self):
        path = self.get_contract_path('HTLC.py')
        engine = TestEngine()

        # can not atomic_swap() without deploying first
        result = self.run_smart_contract(
            engine,
            path,
            'atomic_swap',
            self.OWNER_SCRIPT_HASH,
            NEO_SCRIPT,
            10 * 10**8,
            self.OTHER_ACCOUNT_1,
            GAS_SCRIPT,
            10000 * 10**8,
            hash160(String('unit test').to_bytes()),
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(False, result)

        # deploying contract
        result = self.run_smart_contract(
            engine,
            path,
            'deploy',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        # starting atomic swap by using the atomic_swap method
        result = self.run_smart_contract(
            engine,
            path,
            'atomic_swap',
            self.OWNER_SCRIPT_HASH,
            NEO_SCRIPT,
            10 * 10**8,
            self.OTHER_ACCOUNT_1,
            GAS_SCRIPT,
            10000 * 10**8,
            hash160(String('unit test').to_bytes()),
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

    def test_HTLC_onNEP17Payment(self):
        path = self.get_contract_path('HTLC.py')
        engine = TestEngine()
        transferred_amount_neo = 10 * 10**8
        transferred_amount_gas = 10000 * 10**8

        output, manifest = self.compile_and_save(path)
        htlc_address = hash160(output)

        aux_path = self.get_contract_path('examples/test_native',
                                          'auxiliary_contract.py')
        output, manifest = self.compile_and_save(aux_path)
        aux_address = hash160(output)

        aux_path2 = self.get_contract_path('examples/test_native',
                                           'auxiliary_contract_2.py')
        output, manifest = self.compile_and_save(aux_path2)
        aux_address2 = hash160(output)

        engine.add_neo(aux_address, transferred_amount_neo)
        engine.add_gas(aux_address2, transferred_amount_gas)

        # deploying contract
        result = self.run_smart_contract(
            engine,
            path,
            'deploy',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        # starting atomic swap
        result = self.run_smart_contract(
            engine,
            path,
            'atomic_swap',
            aux_address,
            NEO_SCRIPT,
            transferred_amount_neo,
            aux_address2,
            GAS_SCRIPT,
            transferred_amount_gas,
            hash160(String('unit test').to_bytes()),
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        # transfer wil be aborted at onPayment if the transfer is not valid
        with self.assertRaises(TestExecutionException,
                               msg=self.ABORTED_CONTRACT_MSG):
            self.run_smart_contract(engine,
                                    aux_path,
                                    'calling_transfer',
                                    NEO_SCRIPT,
                                    aux_address,
                                    htlc_address,
                                    transferred_amount_neo - 100,
                                    None,
                                    signer_accounts=[self.OWNER_SCRIPT_HASH],
                                    expected_result_type=bool)

        # since the transfer was aborted, it was not registered in the events
        transfer_events = engine.get_events('Transfer')
        self.assertEqual(0, len(transfer_events))

        # saving the balance to compare after the transfer
        balance_neo_sender_before = self.run_smart_contract(
            engine, NEO_SCRIPT, 'balanceOf', aux_address)
        balance_neo_receiver_before = self.run_smart_contract(
            engine, NEO_SCRIPT, 'balanceOf', htlc_address)

        # this transfer will be accepted
        result = self.run_smart_contract(engine,
                                         aux_path,
                                         'calling_transfer',
                                         NEO_SCRIPT,
                                         aux_address,
                                         htlc_address,
                                         transferred_amount_neo,
                                         None,
                                         signer_accounts=[aux_address],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        # transfer was accepted so it was registered
        transfer_events = engine.get_events('Transfer')
        self.assertEqual(1, len(transfer_events))
        self.assertEqual(3, len(transfer_events[0].arguments))

        sender, receiver, amount = transfer_events[0].arguments
        if isinstance(sender, str):
            sender = String(sender).to_bytes()
        if isinstance(receiver, str):
            receiver = String(receiver).to_bytes()
        self.assertEqual(aux_address, sender)
        self.assertEqual(htlc_address, receiver)
        self.assertEqual(transferred_amount_neo, amount)

        # saving the balance after to compare with the balance before the transfer
        balance_neo_sender_after = self.run_smart_contract(
            engine, NEO_SCRIPT, 'balanceOf', aux_address)
        balance_neo_receiver_after = self.run_smart_contract(
            engine, NEO_SCRIPT, 'balanceOf', htlc_address)

        self.assertEqual(balance_neo_sender_before - transferred_amount_neo,
                         balance_neo_sender_after)
        self.assertEqual(balance_neo_receiver_before + transferred_amount_neo,
                         balance_neo_receiver_after)

        # transfer won't be accepted, because amount is wrong
        with self.assertRaises(TestExecutionException,
                               msg=self.ABORTED_CONTRACT_MSG):
            self.run_smart_contract(engine,
                                    aux_path2,
                                    'calling_transfer',
                                    GAS_SCRIPT,
                                    aux_address2,
                                    htlc_address,
                                    transferred_amount_gas - 100,
                                    None,
                                    signer_accounts=[aux_address2],
                                    expected_result_type=bool)

        transfer_events = engine.get_events('Transfer')
        # the NEO transfer
        self.assertEqual(1, len(transfer_events))

        # saving the balance to compare after the transfer
        balance_gas_sender_before = self.run_smart_contract(
            engine, GAS_SCRIPT, 'balanceOf', aux_address2)
        balance_gas_receiver_before = self.run_smart_contract(
            engine, GAS_SCRIPT, 'balanceOf', htlc_address)

        # this transfer will be accepted
        result = self.run_smart_contract(engine,
                                         aux_path2,
                                         'calling_transfer',
                                         GAS_SCRIPT,
                                         aux_address2,
                                         htlc_address,
                                         transferred_amount_gas,
                                         None,
                                         signer_accounts=[aux_address2],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        # the transfer was accepted so it was registered
        transfer_events = engine.get_events('Transfer')
        self.assertEqual(2, len(transfer_events))
        self.assertEqual(3, len(transfer_events[1].arguments))

        sender, receiver, amount = transfer_events[1].arguments
        if isinstance(sender, str):
            sender = String(sender).to_bytes()
        if isinstance(receiver, str):
            receiver = String(receiver).to_bytes()
        self.assertEqual(aux_address2, sender)
        self.assertEqual(htlc_address, receiver)
        self.assertEqual(transferred_amount_gas, amount)

        # saving the balance after to compare with the balance before the transfer
        balance_gas_sender_after = self.run_smart_contract(
            engine, GAS_SCRIPT, 'balanceOf', aux_address2)
        balance_gas_receiver_after = self.run_smart_contract(
            engine, GAS_SCRIPT, 'balanceOf', htlc_address)

        self.assertEqual(balance_gas_sender_before - transferred_amount_gas,
                         balance_gas_sender_after)
        self.assertEqual(balance_gas_receiver_before + transferred_amount_gas,
                         balance_gas_receiver_after)

    def test_HTLC_withdraw(self):
        path = self.get_contract_path('HTLC.py')
        engine = TestEngine()
        transferred_amount_neo = 10 * 10**8
        transferred_amount_gas = 10000 * 10**8

        output, manifest = self.compile_and_save(path)
        htlc_address = hash160(output)

        aux_path = self.get_contract_path('examples/test_native',
                                          'auxiliary_contract.py')
        output, manifest = self.compile_and_save(aux_path)
        aux_address = hash160(output)

        aux_path2 = self.get_contract_path('examples/test_native',
                                           'auxiliary_contract_2.py')
        output, manifest = self.compile_and_save(aux_path2)
        aux_address2 = hash160(output)

        engine.add_neo(aux_address, transferred_amount_neo)
        engine.add_gas(aux_address2, transferred_amount_gas)

        # deploying smart contract
        result = self.run_smart_contract(
            engine,
            path,
            'deploy',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        # saving the balance to compare after the withdraw
        balance_neo_person_a_before = self.run_smart_contract(
            engine, NEO_SCRIPT, 'balanceOf', aux_address)
        balance_neo_person_b_before = self.run_smart_contract(
            engine, NEO_SCRIPT, 'balanceOf', aux_address2)
        balance_neo_htlc_before = self.run_smart_contract(
            engine, NEO_SCRIPT, 'balanceOf', htlc_address)
        balance_gas_person_a_before = self.run_smart_contract(
            engine, GAS_SCRIPT, 'balanceOf', aux_address)
        balance_gas_person_b_before = self.run_smart_contract(
            engine, GAS_SCRIPT, 'balanceOf', aux_address2)
        balance_gas_htlc_before = self.run_smart_contract(
            engine, GAS_SCRIPT, 'balanceOf', htlc_address)

        # starting atomic swap by using the atomic_swap method
        result = self.run_smart_contract(
            engine,
            path,
            'atomic_swap',
            aux_address,
            NEO_SCRIPT,
            transferred_amount_neo,
            aux_address2,
            GAS_SCRIPT,
            transferred_amount_gas,
            hash160(String('unit test').to_bytes()),
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        # won't be able to withdraw, because no one transferred cryptocurrency to the smart contract
        result = self.run_smart_contract(engine,
                                         path,
                                         'withdraw',
                                         'unit test',
                                         signer_accounts=[aux_address],
                                         expected_result_type=bool)
        self.assertEqual(False, result)

        result = self.run_smart_contract(engine,
                                         aux_path,
                                         'calling_transfer',
                                         NEO_SCRIPT,
                                         aux_address,
                                         htlc_address,
                                         transferred_amount_neo,
                                         None,
                                         signer_accounts=[aux_address],
                                         expected_result_type=bool)
        self.assertEqual(True, result)
        transfer_events = engine.get_events('Transfer')
        self.assertEqual(1, len(transfer_events))

        result = self.run_smart_contract(engine,
                                         aux_path2,
                                         'calling_transfer',
                                         GAS_SCRIPT,
                                         aux_address2,
                                         htlc_address,
                                         transferred_amount_gas,
                                         None,
                                         signer_accounts=[aux_address2],
                                         expected_result_type=bool)
        self.assertEqual(True, result)
        transfer_events = engine.get_events('Transfer')
        self.assertEqual(2, len(transfer_events))

        # the withdraw will fail, because the secret is wrong
        result = self.run_smart_contract(engine,
                                         path,
                                         'withdraw',
                                         'wrong one',
                                         signer_accounts=[aux_address],
                                         expected_result_type=bool)
        self.assertEqual(False, result)

        # the withdraw will occur
        result = self.run_smart_contract(
            engine,
            path,
            'withdraw',
            'unit test',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        # the transfer were accepted so they were registered
        transfer_events = engine.get_events('Transfer')
        self.assertEqual(4, len(transfer_events))
        self.assertEqual(3, len(transfer_events[2].arguments))

        sender, receiver, amount = transfer_events[2].arguments
        if isinstance(sender, str):
            sender = String(sender).to_bytes()
        if isinstance(receiver, str):
            receiver = String(receiver).to_bytes()
        self.assertEqual(htlc_address, sender)
        self.assertEqual(aux_address, receiver)
        self.assertEqual(transferred_amount_gas, amount)

        self.assertEqual(3, len(transfer_events[3].arguments))
        sender, receiver, amount = transfer_events[3].arguments
        if isinstance(sender, str):
            sender = String(sender).to_bytes()
        if isinstance(receiver, str):
            receiver = String(receiver).to_bytes()
        self.assertEqual(htlc_address, sender)
        self.assertEqual(aux_address2, receiver)
        self.assertEqual(transferred_amount_neo, amount)

        # saving the balance after to compare with the balance before the transfer
        balance_neo_person_a_after = self.run_smart_contract(
            engine, NEO_SCRIPT, 'balanceOf', aux_address)
        balance_neo_person_b_after = self.run_smart_contract(
            engine, NEO_SCRIPT, 'balanceOf', aux_address2)
        balance_neo_htlc_after = self.run_smart_contract(
            engine, NEO_SCRIPT, 'balanceOf', htlc_address)
        balance_gas_person_a_after = self.run_smart_contract(
            engine, GAS_SCRIPT, 'balanceOf', aux_address)
        balance_gas_person_b_after = self.run_smart_contract(
            engine, GAS_SCRIPT, 'balanceOf', aux_address2)
        balance_gas_htlc_after = self.run_smart_contract(
            engine, GAS_SCRIPT, 'balanceOf', htlc_address)

        self.assertEqual(balance_neo_person_a_before - transferred_amount_neo,
                         balance_neo_person_a_after)
        self.assertEqual(balance_neo_person_b_before + transferred_amount_neo,
                         balance_neo_person_b_after)
        self.assertEqual(balance_neo_htlc_before, balance_neo_htlc_after)
        self.assertEqual(balance_gas_person_a_before + transferred_amount_gas,
                         balance_gas_person_a_after)
        self.assertEqual(balance_gas_person_b_before - transferred_amount_gas,
                         balance_gas_person_b_after)
        self.assertEqual(balance_gas_htlc_before, balance_gas_htlc_after)

    def test_HTLC_refund(self):
        path = self.get_contract_path('HTLC.py')
        engine = TestEngine()
        transferred_amount_neo = 10 * 10**8
        transferred_amount_gas = 10000 * 10**8

        output, manifest = self.compile_and_save(path)
        htlc_address = hash160(output)

        aux_path = self.get_contract_path('examples/test_native',
                                          'auxiliary_contract.py')
        output, manifest = self.compile_and_save(aux_path)
        aux_address = hash160(output)

        aux_path2 = self.get_contract_path('examples/test_native',
                                           'auxiliary_contract_2.py')
        output, manifest = self.compile_and_save(aux_path2)
        aux_address2 = hash160(output)

        engine.add_neo(aux_address, transferred_amount_neo)
        engine.add_gas(aux_address2, transferred_amount_gas)

        result = self.run_smart_contract(
            engine,
            path,
            'deploy',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        result = self.run_smart_contract(
            engine,
            path,
            'atomic_swap',
            aux_address,
            NEO_SCRIPT,
            transferred_amount_neo,
            aux_address2,
            GAS_SCRIPT,
            transferred_amount_gas,
            hash160(String('unit test').to_bytes()),
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        # won't be able to refund, because not enough time has passed
        result = self.run_smart_contract(
            engine,
            path,
            'refund',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(False, result)

        # this simulates a new block in the blockchain
        # get_time only changes value when a new block enters the blockchain
        engine.increase_block()
        # will be able to refund, because enough time has passed
        result = self.run_smart_contract(engine,
                                         path,
                                         'refund',
                                         signer_accounts=[aux_address],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        transfer_events: List[Notification] = []
        # no one transferred cryptocurrency to the contract, so no one was refunded and no Transfer occurred
        # removing possible GAS minting from the List
        for k in engine.get_events('Transfer'):
            if k.arguments[0] is not None:
                transfer_events.append(k)
        self.assertEqual(0, len(transfer_events))

        # starting atomic swap by using the atomic_swap method
        result = self.run_smart_contract(
            engine,
            path,
            'atomic_swap',
            aux_address,
            NEO_SCRIPT,
            transferred_amount_neo,
            aux_address2,
            GAS_SCRIPT,
            transferred_amount_gas,
            hash160(String('unit test').to_bytes()),
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        result = self.run_smart_contract(engine,
                                         aux_path,
                                         'calling_transfer',
                                         NEO_SCRIPT,
                                         aux_address,
                                         htlc_address,
                                         transferred_amount_neo,
                                         None,
                                         signer_accounts=[aux_address],
                                         expected_result_type=bool)
        self.assertEqual(True, result)
        for k in engine.get_events('Transfer'):
            if k.arguments[0] is not None:
                transfer_events.append(k)
        self.assertEqual(1, len(transfer_events))
        self.assertEqual(3, len(transfer_events[0].arguments))

        engine.increase_block()
        # will be able to refund, because enough time has passed
        result = self.run_smart_contract(engine,
                                         path,
                                         'refund',
                                         signer_accounts=[aux_address],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        # OWNER transferred cryptocurrency to the contract, so only he will be refunded
        transfer_events = []
        # removing possible GAS minting from the List
        for k in engine.get_events('Transfer'):
            if k.arguments[0] is not None:
                transfer_events.append(k)
        self.assertEqual(2, len(transfer_events))
        self.assertEqual(3, len(transfer_events[1].arguments))

        # HTLC returning the tokens
        sender, receiver, amount = transfer_events[1].arguments
        if isinstance(sender, str):
            sender = String(sender).to_bytes()
        if isinstance(receiver, str):
            receiver = String(receiver).to_bytes()
        self.assertEqual(htlc_address, sender)
        self.assertEqual(aux_address, receiver)
        self.assertEqual(transferred_amount_neo, amount)

        result = self.run_smart_contract(
            engine,
            path,
            'atomic_swap',
            aux_address,
            NEO_SCRIPT,
            transferred_amount_neo,
            aux_address2,
            GAS_SCRIPT,
            transferred_amount_gas,
            hash160(String('unit test').to_bytes()),
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        result = self.run_smart_contract(engine,
                                         aux_path,
                                         'calling_transfer',
                                         NEO_SCRIPT,
                                         aux_address,
                                         htlc_address,
                                         transferred_amount_neo,
                                         None,
                                         signer_accounts=[aux_address],
                                         expected_result_type=bool)
        self.assertEqual(True, result)
        transfer_events = []
        for k in engine.get_events('Transfer'):
            if k.arguments[0] is not None:
                transfer_events.append(k)
        self.assertEqual(3, len(transfer_events))
        self.assertEqual(3, len(transfer_events[2].arguments))

        result = self.run_smart_contract(engine,
                                         aux_path2,
                                         'calling_transfer',
                                         GAS_SCRIPT,
                                         aux_address2,
                                         htlc_address,
                                         transferred_amount_gas,
                                         None,
                                         signer_accounts=[aux_address2],
                                         expected_result_type=bool)
        self.assertEqual(True, result)
        transfer_events = []
        for k in engine.get_events('Transfer'):
            if k.arguments[0] is not None:
                transfer_events.append(k)
        self.assertEqual(4, len(transfer_events))
        self.assertEqual(3, len(transfer_events[3].arguments))

        engine.increase_block()
        # will be able to refund, because enough time has passed
        result = self.run_smart_contract(engine,
                                         path,
                                         'refund',
                                         signer_accounts=[aux_address],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        # OWNER and OTHER_ACCOUNT transferred cryptocurrency to the contract, so they both will be refunded
        transfer_events = []
        # removing possible GAS minting from the List
        for k in engine.get_events('Transfer'):
            if k.arguments[0] is not None:
                transfer_events.append(k)
        self.assertEqual(6, len(transfer_events))
        self.assertEqual(3, len(transfer_events[4].arguments))
        self.assertEqual(3, len(transfer_events[5].arguments))

        sender, receiver, amount = transfer_events[4].arguments
        if isinstance(sender, str):
            sender = String(sender).to_bytes()
        if isinstance(receiver, str):
            receiver = String(receiver).to_bytes()
        self.assertEqual(htlc_address, sender)
        self.assertEqual(aux_address, receiver)
        self.assertEqual(transferred_amount_neo, amount)

        sender, receiver, amount = transfer_events[5].arguments
        if isinstance(sender, str):
            sender = String(sender).to_bytes()
        if isinstance(receiver, str):
            receiver = String(receiver).to_bytes()
        self.assertEqual(htlc_address, sender)
        self.assertEqual(aux_address2, receiver)
        self.assertEqual(transferred_amount_gas, amount)
class TestTemplate(BoaTest):

    default_folder: str = 'examples'

    OWNER_SCRIPT_HASH = bytes(20)
    OTHER_ACCOUNT_1 = to_script_hash(b'NiNmXL8FjEUEs1nfX9uHFBNaenxDHJtmuB')
    OTHER_ACCOUNT_2 = bytes(range(20))

    def test_wrapped_neo_compile(self):
        path = self.get_contract_path('wrapped_neo.py')
        Boa3.compile(path)

    def test_wrapped_neo_deploy(self):
        path = self.get_contract_path('wrapped_neo.py')
        engine = TestEngine()

        # needs the owner signature
        result = self.run_smart_contract(engine,
                                         path,
                                         method='deploy',
                                         expected_result_type=bool)
        self.assertEqual(False, result)

        # should return false if the signature isn't from the owner
        result = self.run_smart_contract(
            engine,
            path,
            'deploy',
            signer_accounts=[self.OTHER_ACCOUNT_1],
            expected_result_type=bool)
        self.assertEqual(False, result)

        result = self.run_smart_contract(
            engine,
            path,
            'deploy',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        # must always return false after first execution
        result = self.run_smart_contract(
            engine,
            path,
            'deploy',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(False, result)

    def test_wrapped_neo_symbol(self):
        path = self.get_contract_path('wrapped_neo.py')
        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'symbol')
        self.assertEqual('zNEO', result)

    def test_wrapped_neo_decimals(self):
        path = self.get_contract_path('wrapped_neo.py')
        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'decimals')
        self.assertEqual(8, result)

    def test_wrapped_neo_total_supply(self):
        total_supply = 10_000_000 * 10**8

        path = self.get_contract_path('wrapped_neo.py')
        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'totalSupply')
        self.assertEqual(0, result)
        result = self.run_smart_contract(
            engine,
            path,
            'deploy',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)
        result = self.run_smart_contract(engine, path, 'totalSupply')
        self.assertEqual(total_supply, result)

    def test_wrapped_neo_total_balance_of(self):
        total_supply = 10_000_000 * 10**8

        path = self.get_contract_path('wrapped_neo.py')
        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'balanceOf',
                                         self.OWNER_SCRIPT_HASH)
        self.assertEqual(0, result)

        result = self.run_smart_contract(
            engine,
            path,
            'deploy',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        result = self.run_smart_contract(engine, path, 'balanceOf',
                                         self.OWNER_SCRIPT_HASH)
        self.assertEqual(total_supply, result)

        # should fail when the script length is not 20
        with self.assertRaises(TestExecutionException,
                               msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path, 'balanceOf', bytes(10))
        with self.assertRaises(TestExecutionException,
                               msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path, 'balanceOf', bytes(30))

    @unittest.skip(
        'Examples need to be changed to test with the latest Neo version')
    def test_wrapped_neo_total_transfer(self):
        transferred_amount = 10 * 10**8  # 10 tokens

        path = self.get_contract_path('wrapped_neo.py')
        engine = TestEngine()

        # should fail before running deploy
        result = self.run_smart_contract(engine,
                                         path,
                                         'transfer',
                                         self.OWNER_SCRIPT_HASH,
                                         self.OTHER_ACCOUNT_1,
                                         transferred_amount,
                                         "",
                                         expected_result_type=bool)
        self.assertEqual(False, result)

        result = self.run_smart_contract(
            engine,
            path,
            'deploy',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        # should fail if the sender doesn't sign
        result = self.run_smart_contract(engine,
                                         path,
                                         'transfer',
                                         self.OWNER_SCRIPT_HASH,
                                         self.OTHER_ACCOUNT_1,
                                         transferred_amount,
                                         "",
                                         expected_result_type=bool)
        self.assertEqual(False, result)

        # should fail if the sender doesn't have enough balance
        result = self.run_smart_contract(
            engine,
            path,
            'transfer',
            self.OTHER_ACCOUNT_1,
            self.OWNER_SCRIPT_HASH,
            transferred_amount,
            "",
            signer_accounts=[self.OTHER_ACCOUNT_1],
            expected_result_type=bool)
        self.assertEqual(False, result)

        # should fail when any of the scripts' length is not 20
        with self.assertRaises(TestExecutionException,
                               msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path,
                                    'transfer', self.OWNER_SCRIPT_HASH,
                                    bytes(10), transferred_amount, "")
        with self.assertRaises(TestExecutionException,
                               msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path, 'transfer', bytes(10),
                                    self.OTHER_ACCOUNT_1, transferred_amount,
                                    "")

        # should fail when the amount is less than 0
        with self.assertRaises(TestExecutionException,
                               msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path, 'transfer',
                                    self.OTHER_ACCOUNT_1,
                                    self.OWNER_SCRIPT_HASH, -10, "")

        # fire the transfer event when transferring to yourself
        balance_before = self.run_smart_contract(engine, path, 'balanceOf',
                                                 self.OWNER_SCRIPT_HASH)
        result = self.run_smart_contract(
            engine,
            path,
            'transfer',
            self.OWNER_SCRIPT_HASH,
            self.OWNER_SCRIPT_HASH,
            transferred_amount,
            "",
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)
        transfer_events = engine.get_events('Transfer')
        self.assertEqual(1, len(transfer_events))
        self.assertEqual(3, len(transfer_events[0].arguments))

        sender, receiver, amount = transfer_events[0].arguments
        if isinstance(sender, str):
            sender = String(sender).to_bytes()
        if isinstance(receiver, str):
            receiver = String(receiver).to_bytes()
        self.assertEqual(self.OWNER_SCRIPT_HASH, sender)
        self.assertEqual(self.OWNER_SCRIPT_HASH, receiver)
        self.assertEqual(transferred_amount, amount)

        # transferring to yourself doesn't change the balance
        balance_after = self.run_smart_contract(engine, path, 'balanceOf',
                                                self.OWNER_SCRIPT_HASH)
        self.assertEqual(balance_before, balance_after)

        # does fire the transfer event when transferring to someone other than yourself
        balance_sender_before = self.run_smart_contract(
            engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH)
        balance_receiver_before = self.run_smart_contract(
            engine, path, 'balanceOf', self.OTHER_ACCOUNT_1)
        result = self.run_smart_contract(
            engine,
            path,
            'transfer',
            self.OWNER_SCRIPT_HASH,
            self.OTHER_ACCOUNT_1,
            transferred_amount,
            "",
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)
        transfer_events = engine.get_events('Transfer')
        self.assertEqual(1, len(transfer_events))
        self.assertEqual(3, len(transfer_events[0].arguments))

        sender, receiver, amount = transfer_events[0].arguments
        if isinstance(sender, str):
            sender = String(sender).to_bytes()
        if isinstance(receiver, str):
            receiver = String(receiver).to_bytes()
        self.assertEqual(self.OWNER_SCRIPT_HASH, sender)
        self.assertEqual(self.OTHER_ACCOUNT_1, receiver)
        self.assertEqual(transferred_amount, amount)

        # transferring to someone other than yourself does change the balance
        balance_sender_after = self.run_smart_contract(engine, path,
                                                       'balanceOf',
                                                       self.OWNER_SCRIPT_HASH)
        balance_receiver_after = self.run_smart_contract(
            engine, path, 'balanceOf', self.OTHER_ACCOUNT_1)
        self.assertEqual(balance_sender_before - transferred_amount,
                         balance_sender_after)
        self.assertEqual(balance_receiver_before + transferred_amount,
                         balance_receiver_after)

    def test_wrapped_neo_verify(self):
        path = self.get_contract_path('wrapped_neo.py')
        engine = TestEngine()

        # should fail without signature
        result = self.run_smart_contract(engine,
                                         path,
                                         'verify',
                                         expected_result_type=bool)
        self.assertEqual(False, result)

        # should fail if not signed by the owner
        result = self.run_smart_contract(
            engine,
            path,
            'verify',
            signer_accounts=[self.OTHER_ACCOUNT_1],
            expected_result_type=bool)
        self.assertEqual(False, result)

        result = self.run_smart_contract(
            engine,
            path,
            'verify',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

    @unittest.skip(
        'Examples need to be changed to test with the latest Neo version')
    def test_wrapped_neo_burn(self):
        path = self.get_contract_path('wrapped_neo.py')
        engine = TestEngine()

        output, manifest = self.compile_and_save(path)
        wrapped_neo_address = hash160(output)

        engine.add_neo(wrapped_neo_address, 10_000_000 * 10**8)
        burned_amount = 100 * 10**8

        # deploying this smart contract will give 10m total supply * 10^8 zNEOs to OWNER
        result = self.run_smart_contract(
            engine,
            path,
            'deploy',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        # burning zNEO will end up giving NEO to the one who burned it
        neo_wrapped_before = self.run_smart_contract(engine, NEO_SCRIPT,
                                                     'balanceOf',
                                                     wrapped_neo_address)
        neo_owner_before = self.run_smart_contract(engine, NEO_SCRIPT,
                                                   'balanceOf',
                                                   self.OWNER_SCRIPT_HASH)
        zneo_owner_before = self.run_smart_contract(engine, path, 'balanceOf',
                                                    self.OWNER_SCRIPT_HASH)
        # in this case, NEO will be given to the OWNER_SCRIPT_HASH
        result = self.run_smart_contract(
            engine,
            path,
            'burn',
            self.OWNER_SCRIPT_HASH,
            burned_amount,
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertIsVoid(result)

        transfer_events = engine.get_events('Transfer')
        self.assertEqual(2, len(transfer_events))
        self.assertEqual(3, len(transfer_events[0].arguments))

        sender, receiver, amount = transfer_events[0].arguments
        if isinstance(sender, str):
            sender = String(sender).to_bytes()
        if isinstance(receiver, str):
            receiver = String(receiver).to_bytes()
        self.assertEqual(self.OWNER_SCRIPT_HASH, sender)
        self.assertEqual(None, receiver)
        self.assertEqual(burned_amount, amount)

        self.assertEqual(3, len(transfer_events[1].arguments))

        sender, receiver, amount = transfer_events[1].arguments
        if isinstance(sender, str):
            sender = String(sender).to_bytes()
        if isinstance(receiver, str):
            receiver = String(receiver).to_bytes()
        self.assertEqual(wrapped_neo_address, sender)
        self.assertEqual(self.OWNER_SCRIPT_HASH, receiver)
        self.assertEqual(burned_amount, amount)

        # balance after burning
        neo_wrapped_after = self.run_smart_contract(engine, NEO_SCRIPT,
                                                    'balanceOf',
                                                    wrapped_neo_address)
        neo_owner_after = self.run_smart_contract(engine, NEO_SCRIPT,
                                                  'balanceOf',
                                                  self.OWNER_SCRIPT_HASH)
        zneo_owner_after = self.run_smart_contract(engine, path, 'balanceOf',
                                                   self.OWNER_SCRIPT_HASH)
        self.assertEqual(neo_wrapped_before - burned_amount, neo_wrapped_after)
        self.assertEqual(neo_owner_before + burned_amount, neo_owner_after)
        self.assertEqual(zneo_owner_before - burned_amount, zneo_owner_after)

        # should fail when the script length is not 20
        with self.assertRaises(TestExecutionException,
                               msg=self.ABORTED_CONTRACT_MSG):
            self.run_smart_contract(engine,
                                    path,
                                    'burn',
                                    bytes(15),
                                    burned_amount,
                                    signer_accounts=[self.OWNER_SCRIPT_HASH])
        # or amount is less than 0
        with self.assertRaises(TestExecutionException,
                               msg=self.ABORTED_CONTRACT_MSG):
            self.run_smart_contract(engine,
                                    path,
                                    'burn',
                                    self.OWNER_SCRIPT_HASH,
                                    -1,
                                    signer_accounts=[self.OWNER_SCRIPT_HASH])

    def test_wrapped_neo_approve(self):
        path = self.get_contract_path('wrapped_neo.py')
        path_aux_contract = self.get_contract_path(
            'examples/test_native', 'example_contract_for_wrapped_tokens.py')
        engine = TestEngine()
        engine.add_contract(path.replace('.py', '.nef'))

        output, manifest = self.compile_and_save(path)
        wrapped_neo_address = hash160(output)
        output, manifest = self.compile_and_save(path_aux_contract)
        aux_contract_address = hash160(output)

        allowed_amount = 10 * 10**8

        # this approve will fail, because aux_contract_address doesn't have enough zNEO
        result = self.run_smart_contract(
            engine,
            path_aux_contract,
            'calling_approve',
            wrapped_neo_address,
            self.OTHER_ACCOUNT_1,
            allowed_amount,
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(False, result)

        # deploying this smart contract will give 10m total supply * 10^8 zNEOs to OWNER
        result = self.run_smart_contract(
            engine,
            path,
            'deploy',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        # OWNER will give zNEO to aux_contract_address so that it can approve
        result = self.run_smart_contract(
            engine,
            path,
            'transfer',
            self.OWNER_SCRIPT_HASH,
            aux_contract_address,
            allowed_amount,
            None,
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        # this approve will succeed, because aux_contract_address have enough zNEO
        result = self.run_smart_contract(
            engine,
            path_aux_contract,
            'calling_approve',
            wrapped_neo_address,
            self.OTHER_ACCOUNT_1,
            allowed_amount,
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        # approved fired an event
        approval_events = engine.get_events('Approval')
        self.assertEqual(1, len(approval_events))

        owner, spender, amount = approval_events[0].arguments
        if isinstance(owner, str):
            sender = String(owner).to_bytes()
        if isinstance(spender, str):
            receiver = String(spender).to_bytes()
        self.assertEqual(aux_contract_address, owner)
        self.assertEqual(self.OTHER_ACCOUNT_1, spender)
        self.assertEqual(allowed_amount, amount)

    def test_wrapped_neo_allowance(self):
        path = self.get_contract_path('wrapped_neo.py')
        path_aux_contract = self.get_contract_path(
            'examples/test_native', 'example_contract_for_wrapped_tokens.py')
        engine = TestEngine()
        engine.add_contract(path.replace('.py', '.nef'))

        output, manifest = self.compile_and_save(path)
        wrapped_neo_address = hash160(output)
        output, manifest = self.compile_and_save(path_aux_contract)
        aux_contract_address = hash160(output)

        allowed_amount = 10 * 10**8

        # aux_contract_address did not approve OTHER_SCRIPT_HASH
        result = self.run_smart_contract(
            engine,
            path,
            'allowance',
            aux_contract_address,
            self.OTHER_ACCOUNT_1,
            signer_accounts=[aux_contract_address],
            expected_result_type=bool)
        self.assertEqual(0, result)

        # deploying smart contract
        result = self.run_smart_contract(
            engine,
            path,
            'deploy',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        # OWNER will give zNEO to aux_contract_address so that it can approve
        result = self.run_smart_contract(
            engine,
            path,
            'transfer',
            self.OWNER_SCRIPT_HASH,
            aux_contract_address,
            allowed_amount,
            None,
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        # this approve will succeed, because aux_contract_address have enough zNEO
        result = self.run_smart_contract(
            engine,
            path_aux_contract,
            'calling_approve',
            wrapped_neo_address,
            self.OTHER_ACCOUNT_1,
            allowed_amount,
            signer_accounts=[aux_contract_address],
            expected_result_type=bool)
        self.assertEqual(True, result)

        # aux_contract_address allowed OTHER_SCRIPT_HASH to spend transferred_amount of zNEO
        result = self.run_smart_contract(
            engine,
            path,
            'allowance',
            aux_contract_address,
            self.OTHER_ACCOUNT_1,
            signer_accounts=[aux_contract_address])
        self.assertEqual(allowed_amount, result)

    @unittest.skip(
        'Examples need to be changed to test with the latest Neo version')
    def test_wrapped_neo_transfer_from(self):
        path = self.get_contract_path('wrapped_neo.py')
        path_aux_contract = self.get_contract_path(
            'examples/test_native', 'example_contract_for_wrapped_tokens.py')
        engine = TestEngine()
        engine.add_contract(path.replace('.py', '.nef'))

        output, manifest = self.compile_and_save(path)
        wrapped_neo_address = hash160(output)
        output, manifest = self.compile_and_save(path_aux_contract)
        aux_contract_address = hash160(output)

        allowed_amount = 10 * 10**8

        # deploying smart contract
        result = self.run_smart_contract(
            engine,
            path,
            'deploy',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        # OWNER will give zNEO to aux_contract_address so that it can approve another contracts
        result = self.run_smart_contract(
            engine,
            path,
            'transfer',
            self.OWNER_SCRIPT_HASH,
            aux_contract_address,
            10_000_000 * 10**8,
            None,
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        # this approve will succeed, because aux_contract_address have enough zNEO
        result = self.run_smart_contract(
            engine,
            path_aux_contract,
            'calling_approve',
            wrapped_neo_address,
            self.OTHER_ACCOUNT_1,
            allowed_amount,
            signer_accounts=[aux_contract_address],
            expected_result_type=bool)
        self.assertEqual(True, result)

        transferred_amount = allowed_amount

        # this transfer will fail,
        # because OTHER_SCRIPT_HASH is not allowed to transfer more than aux_contract_address approved
        result = self.run_smart_contract(
            engine,
            path,
            'transfer_from',
            self.OTHER_ACCOUNT_1,
            aux_contract_address,
            self.OTHER_ACCOUNT_2,
            transferred_amount + 1 * 10**8,
            None,
            signer_accounts=[self.OTHER_ACCOUNT_1],
            expected_result_type=bool)
        self.assertEqual(False, result)
        transfer_events = engine.get_events('Transfer')
        self.assertEqual(0, len(transfer_events))

        # this transfer will succeed and will fire the Transfer event
        balance_spender_before = self.run_smart_contract(
            engine, path, 'balanceOf', self.OTHER_ACCOUNT_1)
        balance_sender_before = self.run_smart_contract(
            engine, path, 'balanceOf', aux_contract_address)
        balance_receiver_before = self.run_smart_contract(
            engine, path, 'balanceOf', self.OTHER_ACCOUNT_2)
        result = self.run_smart_contract(
            engine,
            path,
            'transfer_from',
            self.OTHER_ACCOUNT_1,
            aux_contract_address,
            self.OTHER_ACCOUNT_2,
            transferred_amount,
            None,
            signer_accounts=[self.OTHER_ACCOUNT_1],
            expected_result_type=bool)
        self.assertEqual(True, result)
        transfer_events = engine.get_events('Transfer')
        self.assertEqual(1, len(transfer_events))
        self.assertEqual(3, len(transfer_events[0].arguments))

        sender, receiver, amount = transfer_events[0].arguments
        if isinstance(sender, str):
            sender = String(sender).to_bytes()
        if isinstance(receiver, str):
            receiver = String(receiver).to_bytes()
        self.assertEqual(aux_contract_address, sender)
        self.assertEqual(self.OTHER_ACCOUNT_2, receiver)
        self.assertEqual(transferred_amount, amount)

        # transferring changed the balance
        balance_spender_after = self.run_smart_contract(
            engine, path, 'balanceOf', self.OTHER_ACCOUNT_1)
        balance_sender_after = self.run_smart_contract(engine, path,
                                                       'balanceOf',
                                                       aux_contract_address)
        balance_receiver_after = self.run_smart_contract(
            engine, path, 'balanceOf', self.OTHER_ACCOUNT_2)
        self.assertEqual(balance_spender_before, balance_spender_after)
        self.assertEqual(balance_sender_before - transferred_amount,
                         balance_sender_after)
        self.assertEqual(balance_receiver_before + transferred_amount,
                         balance_receiver_after)

        # aux_contract_address and OTHER_SCRIPT_HASH allowance was reduced to 0
        result = self.run_smart_contract(
            engine,
            path,
            'allowance',
            aux_contract_address,
            self.OTHER_ACCOUNT_1,
            signer_accounts=[aux_contract_address],
            expected_result_type=bool)
        self.assertEqual(0, result)

        # this approve will succeed, because aux_contract_address have enough zNEO
        result = self.run_smart_contract(
            engine,
            path_aux_contract,
            'calling_approve',
            wrapped_neo_address,
            self.OTHER_ACCOUNT_1,
            allowed_amount,
            signer_accounts=[aux_contract_address],
            expected_result_type=bool)
        self.assertEqual(True, result)

        transferred_amount = allowed_amount - 4 * 10**8

        result = self.run_smart_contract(
            engine,
            path,
            'transfer_from',
            self.OTHER_ACCOUNT_1,
            aux_contract_address,
            self.OTHER_ACCOUNT_2,
            transferred_amount,
            None,
            signer_accounts=[self.OTHER_ACCOUNT_1],
            expected_result_type=bool)
        self.assertEqual(True, result)

        # aux_contract_address and OTHER_SCRIPT_HASH allowance was reduced to allowed_amount - transferred_amount
        result = self.run_smart_contract(
            engine,
            path,
            'allowance',
            aux_contract_address,
            self.OTHER_ACCOUNT_1,
            signer_accounts=[aux_contract_address],
            expected_result_type=bool)
        self.assertEqual(allowed_amount - transferred_amount, result)

        # should fail when any of the scripts' length is not 20
        with self.assertRaises(TestExecutionException,
                               msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path,
                                    'transfer_from', self.OWNER_SCRIPT_HASH,
                                    bytes(10), self.OTHER_ACCOUNT_1,
                                    allowed_amount, None)
        with self.assertRaises(TestExecutionException,
                               msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path, 'transfer_from', bytes(10),
                                    self.OTHER_ACCOUNT_1,
                                    self.OWNER_SCRIPT_HASH, allowed_amount,
                                    None)
        with self.assertRaises(TestExecutionException,
                               msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path, 'transfer_from',
                                    self.OTHER_ACCOUNT_1,
                                    self.OWNER_SCRIPT_HASH, bytes(10),
                                    allowed_amount, None)

        # should fail when the amount is less than 0
        with self.assertRaises(TestExecutionException,
                               msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path, 'transfer_from',
                                    self.OTHER_ACCOUNT_1,
                                    self.OWNER_SCRIPT_HASH,
                                    self.OTHER_ACCOUNT_2, -10, None)

    @unittest.skip(
        'Examples need to be changed to test with the latest Neo version')
    def test_wrapped_neo_onPayment(self):
        path = self.get_contract_path('wrapped_neo.py')
        engine = TestEngine()
        engine.add_contract(path.replace('.py', '.nef'))

        output, manifest = self.compile_and_save(path)
        wrapped_neo_address = hash160(output)
        aux_contract_address = bytes(range(20))

        minted_amount = 10 * 10**8
        # deploying wrapped_neo smart contract
        result = self.run_smart_contract(
            engine,
            path,
            'deploy',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        engine.add_neo(aux_contract_address, minted_amount)

        # the smart contract will abort if some address other than NEO calls the onPayment method
        with self.assertRaises(TestExecutionException,
                               msg=self.ABORTED_CONTRACT_MSG):
            self.run_smart_contract(engine,
                                    path,
                                    'onNEP17Payment',
                                    aux_contract_address,
                                    minted_amount,
                                    None,
                                    signer_accounts=[aux_contract_address])

        neo_wrapped_before = self.run_smart_contract(engine, NEO_SCRIPT,
                                                     'balanceOf',
                                                     wrapped_neo_address)
        neo_aux_before = self.run_smart_contract(engine, NEO_SCRIPT,
                                                 'balanceOf',
                                                 aux_contract_address)
        zneo_aux_before = self.run_smart_contract(engine, path, 'balanceOf',
                                                  aux_contract_address)
        # transferring NEO to the wrapped_neo_address will mint them
        result = self.run_smart_contract(
            engine,
            NEO_SCRIPT,
            'transfer',
            aux_contract_address,
            wrapped_neo_address,
            minted_amount,
            None,
            signer_accounts=[aux_contract_address],
            expected_result_type=bool)
        self.assertEqual(True, result)

        transfer_events = engine.get_events('Transfer')
        self.assertEqual(2, len(transfer_events))
        self.assertEqual(3, len(transfer_events[0].arguments))

        sender, receiver, amount = transfer_events[0].arguments
        if isinstance(sender, str):
            sender = String(sender).to_bytes()
        if isinstance(receiver, str):
            receiver = String(receiver).to_bytes()
        self.assertEqual(aux_contract_address, sender)
        self.assertEqual(wrapped_neo_address, receiver)
        self.assertEqual(minted_amount, amount)

        self.assertEqual(3, len(transfer_events[1].arguments))

        sender, receiver, amount = transfer_events[1].arguments
        if isinstance(sender, str):
            sender = String(sender).to_bytes()
        if isinstance(receiver, str):
            receiver = String(receiver).to_bytes()
        self.assertEqual(None, sender)
        self.assertEqual(aux_contract_address, receiver)
        self.assertEqual(minted_amount, amount)

        # balance after burning
        neo_wrapped_after = self.run_smart_contract(engine, NEO_SCRIPT,
                                                    'balanceOf',
                                                    wrapped_neo_address)
        neo_aux_after = self.run_smart_contract(engine, NEO_SCRIPT,
                                                'balanceOf',
                                                aux_contract_address)
        zneo_aux_after = self.run_smart_contract(engine, path, 'balanceOf',
                                                 aux_contract_address)
        self.assertEqual(neo_wrapped_before + minted_amount, neo_wrapped_after)
        self.assertEqual(neo_aux_before - minted_amount, neo_aux_after)
        self.assertEqual(zneo_aux_before + minted_amount, zneo_aux_after)
Exemple #16
0
class TestHTLCTemplate(BoaTest):

    default_folder: str = 'examples'

    OWNER_SCRIPT_HASH = bytes(20)
    OTHER_ACCOUNT_1 = to_script_hash(b'NiNmXL8FjEUEs1nfX9uHFBNaenxDHJtmuB')
    OTHER_ACCOUNT_2 = bytes(range(20))

    def test_HTLC_compile(self):
        path = self.get_contract_path('HTLC.py')
        Boa3.compile(path)

    def test_HTLC_deploy(self):
        path = self.get_contract_path('HTLC.py')
        engine = TestEngine()

        # deploying the smart contract
        result = self.run_smart_contract(
            engine,
            path,
            'deploy',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        # deploy can not occur more than once
        result = self.run_smart_contract(
            engine,
            path,
            'deploy',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(False, result)

    def test_HTLC_atomic_swap(self):
        path = self.get_contract_path('HTLC.py')
        engine = TestEngine()

        # can not atomic_swap() without deploying first
        result = self.run_smart_contract(
            engine,
            path,
            'atomic_swap',
            self.OWNER_SCRIPT_HASH,
            NEO,
            10 * 10**8,
            self.OTHER_ACCOUNT_1,
            GAS,
            10000 * 10**8,
            hash160(String('unit test').to_bytes()),
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(False, result)

        # deploying contract
        result = self.run_smart_contract(
            engine,
            path,
            'deploy',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        # starting atomic swap by using the atomic_swap method
        result = self.run_smart_contract(
            engine,
            path,
            'atomic_swap',
            self.OWNER_SCRIPT_HASH,
            NEO,
            10 * 10**8,
            self.OTHER_ACCOUNT_1,
            GAS,
            10000 * 10**8,
            hash160(String('unit test').to_bytes()),
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

    def test_HTLC_onPayment(self):
        path = self.get_contract_path('HTLC.py')
        engine = TestEngine()
        example_contract = self.get_contract_path(
            'test_native/example_contract_for_htlc.py')
        transferred_amount_neo = 10 * 10**8
        transferred_amount_gas = 10000 * 10**8

        output, manifest = self.compile_and_save(example_contract)
        contract_address1 = bytes(range(20))
        contract_address2 = hash160(output)

        output, manifest = self.compile_and_save(path)
        htlc_address = hash160(output)

        engine.add_neo(contract_address1, transferred_amount_neo)
        engine.add_gas(contract_address2, transferred_amount_gas)

        # deploying contract
        result = self.run_smart_contract(
            engine,
            path,
            'deploy',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        # starting atomic swap
        result = self.run_smart_contract(
            engine,
            path,
            'atomic_swap',
            contract_address1,
            NEO,
            transferred_amount_neo,
            contract_address2,
            GAS,
            transferred_amount_gas,
            hash160(String('unit test').to_bytes()),
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        # TODO: Test if onPayment is successful when update the TestEngine to make Neo/Gas transfers

    def test_HTLC_withdraw(self):
        path = self.get_contract_path('HTLC.py')
        engine = TestEngine()
        example_contract = self.get_contract_path(
            'test_native/example_contract_for_htlc.py')
        transferred_amount_neo = 10 * 10**8
        transferred_amount_gas = 10000 * 10**8

        output, manifest = self.compile_and_save(example_contract)
        contract_address1 = bytes(range(20))
        contract_address2 = hash160(output)

        output, manifest = self.compile_and_save(path)
        htlc_address = hash160(output)

        engine.add_neo(contract_address1, transferred_amount_neo)
        engine.add_gas(contract_address2, transferred_amount_gas)

        # deploying smart contract
        result = self.run_smart_contract(
            engine,
            path,
            'deploy',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        # starting atomic swap by using the atomic_swap method
        result = self.run_smart_contract(
            engine,
            path,
            'atomic_swap',
            contract_address1,
            NEO,
            transferred_amount_neo,
            contract_address2,
            GAS,
            transferred_amount_gas,
            hash160(String('unit test').to_bytes()),
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        # won't be able to withdraw, because no one transferred cryptocurrency to the smart contract
        result = self.run_smart_contract(
            engine,
            path,
            'withdraw',
            'unit test',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(False, result)

        # TODO: Test if the withdraw is successful when update the TestEngine to make Neo/Gas transfers

    def test_HTLC_refund(self):
        path = self.get_contract_path('HTLC.py')
        engine = TestEngine()
        example_contract = self.get_contract_path(
            'test_native/example_contract_for_htlc.py')
        transferred_amount_neo = 10 * 10**8
        transferred_amount_gas = 10000 * 10**8

        output, manifest = self.compile_and_save(example_contract)
        contract_address1 = bytes(range(20))
        contract_address2 = hash160(output)

        output, manifest = self.compile_and_save(path)
        htlc_address = hash160(output)

        engine.add_neo(contract_address1, transferred_amount_neo)
        engine.add_gas(contract_address2, transferred_amount_gas)

        result = self.run_smart_contract(
            engine,
            path,
            'deploy',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        result = self.run_smart_contract(
            engine,
            path,
            'atomic_swap',
            contract_address1,
            NEO,
            transferred_amount_neo,
            contract_address2,
            GAS,
            transferred_amount_gas,
            hash160(String('unit test').to_bytes()),
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        # won't be able to refund, because not enough time has passed
        result = self.run_smart_contract(
            engine,
            path,
            'refund',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(False, result)

        # this simulates a new block in the blockchain
        # get_time only changes value when a new block enters the blockchain
        engine.increase_block()
        # will be able to refund, because enough time has passed
        result = self.run_smart_contract(
            engine,
            path,
            'refund',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        # no one transferred cryptocurrency to the contract, so no one was refunded and no Transfer occurred
        transfer_events = engine.get_events('Transfer')
        self.assertEqual(0, len(transfer_events))
Exemple #17
0
class TestNEP17Template(BoaTest):

    default_folder: str = 'examples'

    OWNER_SCRIPT_HASH = bytes(20)
    OTHER_ACCOUNT_1 = to_script_hash(b'NiNmXL8FjEUEs1nfX9uHFBNaenxDHJtmuB')
    OTHER_ACCOUNT_2 = bytes(range(20))

    def test_nep17_compile(self):
        path = self.get_contract_path('NEP17.py')
        Boa3.compile(path)

    def test_nep17_deploy(self):
        path = self.get_contract_path('NEP17.py')
        engine = TestEngine()

        # needs the owner signature
        result = self.run_smart_contract(engine,
                                         path,
                                         method='deploy',
                                         expected_result_type=bool)
        self.assertEqual(False, result)

        # should return false if the signature isn't from the owner
        result = self.run_smart_contract(
            engine,
            path,
            'deploy',
            signer_accounts=[self.OTHER_ACCOUNT_1],
            expected_result_type=bool)
        self.assertEqual(False, result)

        result = self.run_smart_contract(
            engine,
            path,
            'deploy',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        # must always return false after first execution
        result = self.run_smart_contract(
            engine,
            path,
            'deploy',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(False, result)

    def test_nep17_symbol(self):
        path = self.get_contract_path('NEP17.py')
        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'symbol')
        self.assertEqual('NEP17', result)

    def test_nep17_decimals(self):
        path = self.get_contract_path('NEP17.py')
        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'decimals')
        self.assertEqual(8, result)

    def test_nep17_total_supply(self):
        total_supply = 10_000_000 * 10**8

        path = self.get_contract_path('NEP17.py')
        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'totalSupply')
        self.assertEqual(0, result)
        result = self.run_smart_contract(
            engine,
            path,
            'deploy',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)
        result = self.run_smart_contract(engine, path, 'totalSupply')
        self.assertEqual(total_supply, result)

    def test_nep17_total_balance_of(self):
        total_supply = 10_000_000 * 10**8

        path = self.get_contract_path('NEP17.py')
        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'balanceOf',
                                         self.OWNER_SCRIPT_HASH)
        self.assertEqual(0, result)

        result = self.run_smart_contract(
            engine,
            path,
            'deploy',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        result = self.run_smart_contract(engine, path, 'balanceOf',
                                         self.OWNER_SCRIPT_HASH)
        self.assertEqual(total_supply, result)

        # should fail when the script length is not 20
        with self.assertRaises(TestExecutionException,
                               msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path, 'balanceOf', bytes(10))
        with self.assertRaises(TestExecutionException,
                               msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path, 'balanceOf', bytes(30))

    def test_nep17_total_transfer(self):
        transferred_amount = 10 * 10**8  # 10 tokens

        path = self.get_contract_path('NEP17.py')
        engine = TestEngine()

        # should fail before running deploy
        result = self.run_smart_contract(engine,
                                         path,
                                         'transfer',
                                         self.OWNER_SCRIPT_HASH,
                                         self.OTHER_ACCOUNT_1,
                                         transferred_amount,
                                         "",
                                         expected_result_type=bool)
        self.assertEqual(False, result)

        result = self.run_smart_contract(
            engine,
            path,
            'deploy',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        # should fail if the sender doesn't sign
        result = self.run_smart_contract(engine,
                                         path,
                                         'transfer',
                                         self.OWNER_SCRIPT_HASH,
                                         self.OTHER_ACCOUNT_1,
                                         transferred_amount,
                                         "",
                                         expected_result_type=bool)
        self.assertEqual(False, result)

        # should fail if the sender doesn't have enough balance
        result = self.run_smart_contract(
            engine,
            path,
            'transfer',
            self.OTHER_ACCOUNT_1,
            self.OWNER_SCRIPT_HASH,
            transferred_amount,
            "",
            signer_accounts=[self.OTHER_ACCOUNT_1],
            expected_result_type=bool)
        self.assertEqual(False, result)

        # should fail when any of the scripts' length is not 20
        with self.assertRaises(TestExecutionException,
                               msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path,
                                    'transfer', self.OWNER_SCRIPT_HASH,
                                    bytes(10), transferred_amount, "")
        with self.assertRaises(TestExecutionException,
                               msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path, 'transfer', bytes(10),
                                    self.OTHER_ACCOUNT_1, transferred_amount,
                                    "")

        # should fail when the amount is less than 0
        with self.assertRaises(TestExecutionException,
                               msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path, 'transfer',
                                    self.OTHER_ACCOUNT_1,
                                    self.OWNER_SCRIPT_HASH, -10, "")

        # fire the transfer event when transferring to yourself
        balance_before = self.run_smart_contract(engine, path, 'balanceOf',
                                                 self.OWNER_SCRIPT_HASH)
        result = self.run_smart_contract(
            engine,
            path,
            'transfer',
            self.OWNER_SCRIPT_HASH,
            self.OWNER_SCRIPT_HASH,
            transferred_amount,
            "",
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)
        transfer_events = engine.get_events('Transfer')
        self.assertEqual(1, len(transfer_events))
        self.assertEqual(3, len(transfer_events[0].arguments))

        sender, receiver, amount = transfer_events[0].arguments
        if isinstance(sender, str):
            sender = String(sender).to_bytes()
        if isinstance(receiver, str):
            receiver = String(receiver).to_bytes()
        self.assertEqual(self.OWNER_SCRIPT_HASH, sender)
        self.assertEqual(self.OWNER_SCRIPT_HASH, receiver)
        self.assertEqual(transferred_amount, amount)

        # transferring to yourself doesn't change the balance
        balance_after = self.run_smart_contract(engine, path, 'balanceOf',
                                                self.OWNER_SCRIPT_HASH)
        self.assertEqual(balance_before, balance_after)

        # does fire the transfer event
        balance_sender_before = self.run_smart_contract(
            engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH)
        balance_receiver_before = self.run_smart_contract(
            engine, path, 'balanceOf', self.OTHER_ACCOUNT_1)
        result = self.run_smart_contract(
            engine,
            path,
            'transfer',
            self.OWNER_SCRIPT_HASH,
            self.OTHER_ACCOUNT_1,
            transferred_amount,
            "",
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)
        transfer_events = engine.get_events('Transfer')
        self.assertEqual(1, len(transfer_events))
        self.assertEqual(3, len(transfer_events[0].arguments))

        sender, receiver, amount = transfer_events[0].arguments
        if isinstance(sender, str):
            sender = String(sender).to_bytes()
        if isinstance(receiver, str):
            receiver = String(receiver).to_bytes()
        self.assertEqual(self.OWNER_SCRIPT_HASH, sender)
        self.assertEqual(self.OTHER_ACCOUNT_1, receiver)
        self.assertEqual(transferred_amount, amount)

        # transferring to someone other than yourself does change the balance
        balance_sender_after = self.run_smart_contract(engine, path,
                                                       'balanceOf',
                                                       self.OWNER_SCRIPT_HASH)
        balance_receiver_after = self.run_smart_contract(
            engine, path, 'balanceOf', self.OTHER_ACCOUNT_1)
        self.assertEqual(balance_sender_before - transferred_amount,
                         balance_sender_after)
        self.assertEqual(balance_receiver_before + transferred_amount,
                         balance_receiver_after)

    def test_nep17_onPayment(self):
        transferred_amount = 10 * 10**8  # 10 tokens

        path = self.get_contract_path('NEP17.py')
        engine = TestEngine()

        engine.add_contract(path.replace('.py', '.nef'))

        output, manifest = self.compile_and_save(path)
        nep17_address = hash160(output)

        test_address = bytes(range(20))

        result = self.run_smart_contract(
            engine,
            path,
            'deploy',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        engine.add_neo(test_address, transferred_amount)

        # fire the Transfer event if sender is NEO when transferring to NEP17 script hash
        neo_balance_sender_before = self.run_smart_contract(
            engine, NEO_SCRIPT, 'balanceOf', test_address)
        neo_balance_nep17_before = self.run_smart_contract(
            engine, NEO_SCRIPT, 'balanceOf', nep17_address)
        nep17_balance_sender_before = self.run_smart_contract(
            engine, path, 'balanceOf', test_address)

        # TODO: Test if the onPayment method is successful when update the TestEngine to make Neo/Gas transfers

    def test_nep17_verify(self):
        path = self.get_contract_path('NEP17.py')
        engine = TestEngine()

        # should fail without signature
        result = self.run_smart_contract(engine,
                                         path,
                                         'verify',
                                         expected_result_type=bool)
        self.assertEqual(False, result)

        # should fail if not signed by the owner
        result = self.run_smart_contract(
            engine,
            path,
            'verify',
            signer_accounts=[self.OTHER_ACCOUNT_1],
            expected_result_type=bool)
        self.assertEqual(False, result)

        result = self.run_smart_contract(
            engine,
            path,
            'verify',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)
def Main() -> bytes:
    return to_script_hash(b'42')
Exemple #19
0
class GhostTest(BoaTest):
    p = Path(__file__)
    GHOST_ROOT = str(p.parents[1])
    PRJ_ROOT = str(p.parents[2])

    CONTRACT_PATH_JSON = GHOST_ROOT+ '/contracts/NEP11/GhostMarket.NFT.manifest.json'
    CONTRACT_PATH_NEF = GHOST_ROOT + '/contracts/NEP11/GhostMarket.NFT.nef'
    CONTRACT_PATH_PY = GHOST_ROOT + '/contracts/NEP11/GhostMarket.NFT.py'
    BOA_PATH = PRJ_ROOT + '/neo3-boa/boa3'
    OWNER_SCRIPT_HASH = UInt160(to_script_hash(b'NZcuGiwRu1QscpmCyxj5XwQBUf6sk7dJJN'))
    OTHER_ACCOUNT_1 = UInt160(to_script_hash(b'NiNmXL8FjEUEs1nfX9uHFBNaenxDHJtmuB'))
    OTHER_ACCOUNT_2 = bytes(range(20))
    TOKEN_META = bytes('{ "name": "GHOST", "description": "A ghost shows up", "image": "{some image URI}", "tokenURI": "{some URI}" }', 'utf-8')
    LOCK_CONTENT = bytes('lockedContent', 'utf-8')
    ROYALTIES = bytes('[{"address": "someaddress", "value": 20}, {"address": "someaddress2", "value": 30}]', 'utf-8')

    def build_contract(self, preprocess=False):
        print('contract path: ' + self.CONTRACT_PATH_PY)
        if preprocess:
            import os
            old = os.getcwd()
            os.chdir(self.GHOST_ROOT)
            file = self.GHOST_ROOT + '/compile.py'
            os.system(file)
            os.chdir(old)
        else:
            output, manifest = self.compile_and_save(self.CONTRACT_PATH_PY)

    def deploy_contract(self, engine):
        engine.add_contract(self.CONTRACT_PATH_NEF.replace('.py', '.nef'))
        result = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, '_deploy', None, False,
                                         signer_accounts=[self.OWNER_SCRIPT_HASH],
                                         expected_result_type=bool)
        self.assertEqual(VoidType, result)

    def prepare_testengine(self, preprocess=False) -> TestEngine:
        self.build_contract(preprocess)
        root_folder = self.BOA_PATH
        engine = TestEngine(root_folder)
        engine.reset_engine()
        self.deploy_contract(engine)
        return engine

    def print_notif(self, notifications):
        print('\n=========================== NOTIFICATIONS START ===========================\n')
        for notif in notifications:
            print(f"{str(notif.name)}: {str(notif.arguments)}")
        print('\n=========================== NOTIFICATIONS END ===========================\n')

    def test_ghost_compile(self):
        self.build_contract()

    def test_ghost_symbol(self):
        engine = self.prepare_testengine()
        result = engine.run(self.CONTRACT_PATH_NEF, 'symbol', reset_engine=True)
        self.print_notif(engine.notifications)

        assert isinstance(result, str)
        assert result == 'GHOST'

    def test_ghost_decimals(self):
        engine = self.prepare_testengine()
        result = engine.run(self.CONTRACT_PATH_NEF, 'decimals', reset_engine=True)
        self.print_notif(engine.notifications)

        assert isinstance(result, int)
        assert result == 0

    def test_ghost_total_supply(self):
        engine = self.prepare_testengine()
        result = engine.run(self.CONTRACT_PATH_NEF, 'totalSupply', reset_engine=True)
        self.print_notif(engine.notifications)

        assert isinstance(result, int)
        assert result == 0

    def test_ghost_deploy(self):
        engine = self.prepare_testengine()
        # prepare_testengine already deploys the contract and verifies it's successfully deployed

        # must always return false after first execution
        with self.assertRaises(TestExecutionException, msg=self.ABORTED_CONTRACT_MSG):
            result = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, '_deploy', None, False,
                                             signer_accounts=[self.OWNER_SCRIPT_HASH],
                                         expected_result_type=bool)
        self.print_notif(engine.notifications)

    def test_ghost_update(self):
        engine = self.prepare_testengine()

        # updating ghost smart contract
        file_script = open(self.CONTRACT_PATH_NEF, 'rb')
        script = file_script.read()
        #print(script)
        file_script.close()

        file_manifest = open(self.CONTRACT_PATH_JSON, 'rb')
        manifest = file_manifest.read()
        #print(manifest)
        file_manifest.close()

        result = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'update', 
                                         script, manifest,
                                         signer_accounts=[self.OWNER_SCRIPT_HASH],
                                         expected_result_type=bool)
        self.assertEqual(VoidType, result)

    def test_ghost_destroy(self):
        engine = self.prepare_testengine()

        # destroy contract
        result = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'destroy',
                                         signer_accounts=[self.OWNER_SCRIPT_HASH],
                                         expected_result_type=bool)

        # should not exist anymore
        result = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'symbol')
        # self.assertNotEqual('GHOST', result)

        self.print_notif(engine.notifications)

    def test_ghost_verify(self):
        engine = self.prepare_testengine()

        # should fail because account does not have enough for fees
        with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'verify', self.OTHER_ACCOUNT_1)

        self.print_notif(engine.notifications)

    def test_ghost_authorize(self):
        engine = self.prepare_testengine()
        self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'setAuthorizedAddress', 
                self.OTHER_ACCOUNT_1, True,
                signer_accounts=[self.OWNER_SCRIPT_HASH],
                expected_result_type=bool)
        auth_events = engine.get_events('Authorized')

        # check if the event was triggered and the address was authorized
        self.assertEqual(0, auth_events[0].arguments[1])
        self.assertEqual(1, auth_events[0].arguments[2])

        # now deauthorize the address
        self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'setAuthorizedAddress', 
                self.OTHER_ACCOUNT_1, False,
                signer_accounts=[self.OWNER_SCRIPT_HASH],
                expected_result_type=bool)
        auth_events = engine.get_events('Authorized')
        # check if the event was triggered and the address was authorized
        self.assertEqual(0, auth_events[1].arguments[1])
        self.assertEqual(0, auth_events[1].arguments[2])

    def test_ghost_whitelist(self):
        engine = self.prepare_testengine()
        self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'setWhitelistedAddress', 
                self.OTHER_ACCOUNT_1, True,
                signer_accounts=[self.OWNER_SCRIPT_HASH],
                expected_result_type=bool)
        auth_events = engine.get_events('Authorized')

        # check if the event was triggered and the address was authorized
        self.assertEqual(1, auth_events[0].arguments[1])
        self.assertEqual(1, auth_events[0].arguments[2])

        # now deauthorize the address
        self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'setWhitelistedAddress', 
                self.OTHER_ACCOUNT_1, False,
                signer_accounts=[self.OWNER_SCRIPT_HASH],
                expected_result_type=bool)
        auth_events = engine.get_events('Authorized')
        # check if the event was triggered and the address was authorized
        self.assertEqual(1, auth_events[1].arguments[1])
        self.assertEqual(0, auth_events[1].arguments[2])

    def test_ghost_pause(self):
        engine = self.prepare_testengine()
        engine.add_contract(self.CONTRACT_PATH_NEF.replace('.py', '.nef'))
        aux_path = self.get_contract_path('test_native', 'auxiliary_contract.py')
        output, manifest = self.compile_and_save(self.CONTRACT_PATH_NEF.replace('.nef', '.py'))
        ghost_address = hash160(output)
        print(to_hex_str(ghost_address))
        output, manifest = self.compile_and_save(aux_path)
        aux_address = hash160(output)
        print(to_hex_str(aux_address))

        # when deploying, the contract will mint tokens to the owner
        deploy_event = engine.get_events('Deployed')
        self.assertEqual(1, len(deploy_event))
        self.assertEqual(2, len(deploy_event[0].arguments))

        # add some gas for fees
        add_amount = 10 * 10 ** 8
        engine.add_gas(aux_address, add_amount)

        # pause contract
        fee = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'updatePause', True,
                signer_accounts=[self.OWNER_SCRIPT_HASH],
                expected_result_type=int)

        # should fail because contract is paused
        with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG):
            token = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'mint', 
                    aux_address, self.TOKEN_META, self.LOCK_CONTENT, self.ROYALTIES, None,
                    signer_accounts=[aux_address],
                    expected_result_type=bytes)

        # unpause contract
        fee = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'updatePause', False,
                signer_accounts=[self.OWNER_SCRIPT_HASH],
                expected_result_type=int)

        # mint
        token = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'mint', 
            aux_address, self.TOKEN_META, self.LOCK_CONTENT, self.ROYALTIES, None,
            signer_accounts=[aux_address],
            expected_result_type=bytes)
        self.print_notif(engine.notifications)

    def test_ghost_mint(self):
        engine = self.prepare_testengine()
        engine.add_contract(self.CONTRACT_PATH_NEF.replace('.py', '.nef'))
        aux_path = self.get_contract_path('test_native', 'auxiliary_contract.py')
        output, manifest = self.compile_and_save(self.CONTRACT_PATH_NEF.replace('.nef', '.py'))
        ghost_address = hash160(output)
        print(to_hex_str(ghost_address))
        output, manifest = self.compile_and_save(aux_path)
        aux_address = hash160(output)
        print(to_hex_str(aux_address))

        # when deploying, the contract will mint tokens to the owner
        deploy_event = engine.get_events('Deployed')
        self.assertEqual(1, len(deploy_event))
        self.assertEqual(2, len(deploy_event[0].arguments))

        # should fail because account does not have enough for fees
        with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'mint', 
                # aux_address, self.TOKEN_META, self.LOCK_CONTENT, self.ROYALTIES, None,
                aux_address, bytes(0), bytes(0), bytes(0), None,
                signer_accounts=[aux_address],
                expected_result_type=bytes)

        # add some gas for fees
        add_amount = 10 * 10 ** 8
        engine.add_gas(aux_address, add_amount)

        # should succeed now that account has enough fees
        token = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'mint', 
                aux_address, self.TOKEN_META, self.LOCK_CONTENT, self.ROYALTIES, None,
                signer_accounts=[aux_address],
                expected_result_type=bytes)

        print("get props now: ")
        properties = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'properties', token, expected_result_type=bytes)
        print("props: " + str(properties))
        royalties = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'getRoyalties', token, expected_result_type=bytes)
        print("royalties: " + str(royalties))

        print('non existing props:')
        with self.assertRaises(TestExecutionException, msg='An unhandled exception was thrown. Unable to parse metadata'):
            properties = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'properties',
                    bytes('thisisanonexistingtoken', 'utf-8'), expected_result_type=bytes)
        print("props: " + str(properties))

        # check balances after
        ghost_amount_after = self.run_smart_contract(engine, GAS_SCRIPT, 'balanceOf', ghost_address)
        gas_aux_after = self.run_smart_contract(engine, GAS_SCRIPT, 'balanceOf', aux_address)
        print("ghost gas amount: " + str(ghost_amount_after))
        print("aux gas amount: " + str(gas_aux_after))
        ghost_balance_after = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'balanceOf', aux_address)
        print("balance nft: " + str(ghost_balance_after))
        ghost_supply_after = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'totalSupply')
        print("supply nft: " + str(ghost_supply_after))
        self.assertEqual(1, ghost_supply_after)
        self.print_notif(engine.notifications)

    def test_ghost_gas_cost(self):
        engine = self.prepare_testengine()
        engine.add_contract(self.CONTRACT_PATH_NEF.replace('.py', '.nef'))
        aux_path = self.get_contract_path('test_native', 'auxiliary_contract.py')
        output, manifest = self.compile_and_save(self.CONTRACT_PATH_NEF.replace('.nef', '.py'))
        ghost_address = hash160(output)
        print(to_hex_str(ghost_address))
        output, manifest = self.compile_and_save(aux_path)
        aux_address = hash160(output)
        print(to_hex_str(aux_address))

        # add some gas for fees
        add_amount = 10 * 10 ** 8
        engine.add_gas(aux_address, add_amount)

        # mint token with no meta, no lock content, no royalties
        token = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'mint', 
            aux_address, bytes(1), bytes(0), bytes(0), None,
            signer_accounts=[aux_address],
            expected_result_type=bytes)

        gasConsumed = str(int(engine.gas_consumed) / 10 ** 8)
        print("token with no meta, no lock content, no royalties: " + gasConsumed + " GAS")

        # mint token with meta, no lock content, no royalties
        token = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'mint', 
            aux_address, self.TOKEN_META, bytes(0), bytes(0), None,
            signer_accounts=[aux_address],
            expected_result_type=bytes)

        gasConsumed = str(int(engine.gas_consumed) / 10 ** 8)
        print("token with meta, no lock content, no royalties: " + gasConsumed + " GAS")

        # mint token with meta, lock content, no royalties
        token = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'mint', 
            aux_address, self.TOKEN_META, self.LOCK_CONTENT, bytes(0), None,
            signer_accounts=[aux_address],
            expected_result_type=bytes)

        gasConsumed = str(int(engine.gas_consumed) / 10 ** 8)
        print("token with meta, lock content, no royalties: " + gasConsumed + " GAS")

        # mint token with meta, no lock content, royalties
        token = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'mint', 
            aux_address, self.TOKEN_META, bytes(0), self.ROYALTIES, None,
            signer_accounts=[aux_address],
            expected_result_type=bytes)

        gasConsumed = str(int(engine.gas_consumed) / 10 ** 8)
        print("token with meta, no lock content, royalties: " + gasConsumed + " GAS")

        # mint token with meta, lock content, royalties
        token = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'mint', 
            aux_address, self.TOKEN_META, self.LOCK_CONTENT, self.ROYALTIES, None,
            signer_accounts=[aux_address],
            expected_result_type=bytes)

        gasConsumed = str(int(engine.gas_consumed) / 10 ** 8)
        print("token with meta, lock content, royalties: " + gasConsumed + " GAS")

        tokenMeta = bytes('{ "name": "GHOST3", "description": "A ghost shows up", "image": "{some image URI}", "name": "GHOST3", "description": "A ghost shows up", "image": "{some image URI}", "name": "GHOST3", "description": "A ghost shows up", "image": "{some image URI}", "name": "GHOST3", "description": "A ghost shows up", "image": "{some image URI}", "tokenURI": "{some URI}" }', 'utf-8')

        lockedContent = bytes('123456789101234567891012345678910123456789101234567891012345678910123456789101234567891012345678910123456789101234567891012345678910123456789101234567891012345678910123456789101234567891012345678910', 'utf-8')

        royalties = bytes('[{"address": "someaddress", "value": 20}, {"address": "someaddress2", "value": 30},{"address": "someaddress", "value": 20}, {"address": "someaddress2", "value": 30},{"address": "someaddress", "value": 20}, {"address": "someaddress2", "value": 30}]', 'utf-8')

        # mint high end token
        token = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'mint', 
            aux_address, tokenMeta, lockedContent, royalties, None,
            signer_accounts=[aux_address],
            expected_result_type=bytes)
            
        gasConsumed = str(int(engine.gas_consumed) / 10 ** 8)
        print("token with heavy meta, heavy lock content, heavy royalties: " + gasConsumed + " GAS")

        # get locked content
        content = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'getLockedContent', token,
                signer_accounts=[aux_address],
                expected_result_type=bytes)
            
        gasConsumed = str(int(engine.gas_consumed) / 10 ** 8)
        print("get locked content: " + gasConsumed + " GAS")

        # burn token
        burn = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'burn', token,
            signer_accounts=[aux_address],
            expected_result_type=bool)

        gasConsumed = str(int(engine.gas_consumed) / 10 ** 8)
        print("burn: " + gasConsumed + " GAS")

    def test_ghost_multi_mint(self):
        engine = self.prepare_testengine()
        engine.add_contract(self.CONTRACT_PATH_NEF.replace('.py', '.nef'))
        aux_path = self.get_contract_path('test_native', 'auxiliary_contract.py')
        output, manifest = self.compile_and_save(self.CONTRACT_PATH_NEF.replace('.nef', '.py'))
        ghost_address = hash160(output)
        print(to_hex_str(ghost_address))
        output, manifest = self.compile_and_save(aux_path)
        aux_address = hash160(output)
        print(to_hex_str(aux_address))

        # when deploying, the contract will mint tokens to the owner
        deploy_event = engine.get_events('Deployed')
        self.assertEqual(1, len(deploy_event))
        self.assertEqual(2, len(deploy_event[0].arguments))

        # add some gas for fees
        add_amount = 10 * 10 ** 8
        engine.add_gas(aux_address, add_amount)

        # define custom meta & lock & royalties for multi
        tokenMeta = [
                bytes('{ "name": "GHOST", "description": "A ghost shows up", "image": "{some image URI}", "tokenURI": "{some URI}" }', 'utf-8'),
                bytes('{ "name": "GHOST2", "description": "A ghost shows up", "image": "{some image URI}", "tokenURI": "{some URI}" }', 'utf-8'),
                bytes('{ "name": "GHOST3", "description": "A ghost shows up", "image": "{some image URI}", "tokenURI": "{some URI}" }', 'utf-8')
            ]

        lockedContent = [
                bytes('123', 'utf-8'),
                bytes('456', 'utf-8'),
                bytes('789', 'utf-8'),
            ]

        royalties = [
                bytes('[{"address": "someaddress", "value": 20}, {"address": "someaddress2", "value": 30}]', 'utf-8'),
                bytes('[{"address": "someaddress3", "value": 20}, {"address": "someaddress4", "value": 30}]', 'utf-8'),
                bytes('[{"address": "someaddress5", "value": 20}, {"address": "someaddress6", "value": 30}]', 'utf-8'),
            ]

        # check tokens iterator before
        ghost_tokens_before = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'tokens', expected_result_type=InteropInterface)
        self.assertEqual(InteropInterface, ghost_tokens_before)

        # multiMint
        result = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'multiMint', 
                aux_address, tokenMeta, lockedContent, royalties, None,
                signer_accounts=[aux_address],
                expected_result_type=list)
        print("result: " + str(result))

        # check tokens iterator after
        ghost_tokens_after = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'tokens', expected_result_type=InteropInterface)
        print("tokens after: " + str(ghost_tokens_after))
        
        # check balances after
        ghost_balance_after = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'balanceOf', aux_address)
        self.assertEqual(3, ghost_balance_after)
        ghost_supply_after = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'totalSupply')
        self.assertEqual(3, ghost_supply_after)
        self.print_notif(engine.notifications)

    def test_ghost_transfer(self):
        engine = self.prepare_testengine()
        engine.add_contract(self.CONTRACT_PATH_NEF.replace('.py', '.nef'))
        aux_path = self.get_contract_path('test_native', 'auxiliary_contract.py')
        output, manifest = self.compile_and_save(self.CONTRACT_PATH_NEF.replace('.nef', '.py'))
        ghost_address = hash160(output)
        print(to_hex_str(ghost_address))
        output, manifest = self.compile_and_save(aux_path)
        aux_address = hash160(output)
        print(to_hex_str(aux_address))

        # when deploying, the contract will mint tokens to the owner
        deploy_event = engine.get_events('Deployed')
        self.assertEqual(1, len(deploy_event))
        self.assertEqual(2, len(deploy_event[0].arguments))

        # add some gas for fees
        add_amount = 10 * 10 ** 8
        engine.add_gas(aux_address, add_amount)

        # mint
        token = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'mint', 
                aux_address, self.TOKEN_META, self.LOCK_CONTENT, self.ROYALTIES, None,
                signer_accounts=[aux_address],
                expected_result_type=bytes)
        properties = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'properties', token)
        print("props: " + str(properties))

        # check balances after
        ghost_amount_after = self.run_smart_contract(engine, GAS_SCRIPT, 'balanceOf', ghost_address)
        gas_aux_after = self.run_smart_contract(engine, GAS_SCRIPT, 'balanceOf', aux_address)
        print("ghost gas amount: " + str(ghost_amount_after))
        print("aux gas amount: " + str(gas_aux_after))
        ghost_balance_after = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'balanceOf', aux_address)
        print("balance nft: " + str(ghost_balance_after))
        ghost_supply_after = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'totalSupply')
        print("supply nft: " + str(ghost_supply_after))
        self.assertEqual(1, ghost_supply_after)

        # check owner before
        ghost_owner_of_before = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'ownerOf', token)
        print("owner of before: " + str(ghost_owner_of_before))

        # transfer
        result = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'transfer', 
                self.OTHER_ACCOUNT_1, token, None,
                signer_accounts=[aux_address],
                expected_result_type=bool)
        self.assertEqual(True, result)

        # check owner after
        ghost_owner_of_after = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'ownerOf', token)
        print("owner of after: " + str(ghost_owner_of_after))
        self.assertEqual(ghost_owner_of_after, self.OTHER_ACCOUNT_1)

        # check balances after
        ghost_balance_after_transfer = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'balanceOf', aux_address)
        ghost_supply_after_transfer = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'totalSupply')
        print("balance nft after transfer: " + str(ghost_balance_after_transfer))
        self.assertEqual(0, ghost_balance_after_transfer)
        self.assertEqual(1, ghost_supply_after_transfer)

        # try to transfer non existing token id
        with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG):
            result = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'transfer', 
                    self.OTHER_ACCOUNT_1, bytes('thisisanonexistingtoken', 'utf-8'), None,
                    signer_accounts=[aux_address],
                    expected_result_type=bool)

        self.print_notif(engine.notifications)

    def test_ghost_burn(self):
        engine = self.prepare_testengine()
        engine.add_contract(self.CONTRACT_PATH_NEF.replace('.py', '.nef'))
        aux_path = self.get_contract_path('test_native', 'auxiliary_contract.py')
        output, manifest = self.compile_and_save(self.CONTRACT_PATH_NEF.replace('.nef', '.py'))
        ghost_address = hash160(output)
        print(to_hex_str(ghost_address))
        output, manifest = self.compile_and_save(aux_path)
        aux_address = hash160(output)
        print(to_hex_str(aux_address))

        # when deploying, the contract will mint tokens to the owner
        deploy_event = engine.get_events('Deployed')
        self.assertEqual(1, len(deploy_event))
        self.assertEqual(2, len(deploy_event[0].arguments))

        # add some gas for fees
        add_amount = 10 * 10 ** 8
        engine.add_gas(aux_address, add_amount)

        # mint
        token = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'mint', 
                aux_address, self.TOKEN_META, self.LOCK_CONTENT, self.ROYALTIES, None,
                signer_accounts=[aux_address],
                expected_result_type=bytes)

        # burn
        burn = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'burn', token,
                signer_accounts=[aux_address],
                expected_result_type=bool)
        print("props: " + str(burn))

        # check balances after
        ghost_balance_after = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'balanceOf', aux_address)
        self.assertEqual(0, ghost_balance_after)
        ghost_supply_after = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'totalSupply')
        self.assertEqual(0, ghost_supply_after)
        self.print_notif(engine.notifications)


    def test_ghost_multi_burn(self):
        engine = self.prepare_testengine()
        engine.add_contract(self.CONTRACT_PATH_NEF.replace('.py', '.nef'))
        aux_path = self.get_contract_path('test_native', 'auxiliary_contract.py')
        output, manifest = self.compile_and_save(self.CONTRACT_PATH_NEF.replace('.nef', '.py'))
        ghost_address = hash160(output)
        print(to_hex_str(ghost_address))
        output, manifest = self.compile_and_save(aux_path)
        aux_address = hash160(output)
        print(to_hex_str(aux_address))

        deploy_event = engine.get_events('Deployed')
        self.assertEqual(1, len(deploy_event))
        self.assertEqual(2, len(deploy_event[0].arguments))

        # add some gas for fees
        add_amount = 10 * 10 ** 8
        engine.add_gas(aux_address, add_amount)

        # define custom meta & lock & royalties for multi
        tokenMeta = [
                bytes('{ "name": "GHOST", "description": "A ghost shows up", "image": "{some image URI}", "tokenURI": "{some URI}" }', 'utf-8'),
                bytes('{ "name": "GHOST2", "description": "A ghost shows up", "image": "{some image URI}", "tokenURI": "{some URI}" }', 'utf-8'),
                bytes('{ "name": "GHOST3", "description": "A ghost shows up", "image": "{some image URI}", "tokenURI": "{some URI}" }', 'utf-8')
            ]

        lockedContent = [
                bytes('123', 'utf-8'),
                bytes('456', 'utf-8'),
                bytes('789', 'utf-8'),
            ]

        royalties = [
                bytes('[{"address": "someaddress", "value": 20}, {"address": "someaddress2", "value": 30}]', 'utf-8'),
                bytes('[{"address": "someaddress3", "value": 20}, {"address": "someaddress4", "value": 30}]', 'utf-8'),
                bytes('[{"address": "someaddress5", "value": 20}, {"address": "someaddress6", "value": 30}]', 'utf-8'),
            ]

        # multiMint
        result = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'multiMint', 
                aux_address, tokenMeta, lockedContent, royalties, None,
                signer_accounts=[aux_address],
                expected_result_type=list)

        # check balances after
        ghost_balance_after = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'balanceOf', aux_address)
        self.assertEqual(3, ghost_balance_after)
        ghost_supply_after = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'totalSupply')
        self.assertEqual(3, ghost_supply_after)

        # multiBurn
        burn = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'multiBurn', result,
                signer_accounts=[aux_address],
                expected_result_type=list)
        print("burned: " + str(burn))

        # check balances after
        ghost_balance_after = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'balanceOf', aux_address)
        self.assertEqual(0, ghost_balance_after)
        ghost_supply_after = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'totalSupply')
        self.assertEqual(0, ghost_supply_after)
        self.print_notif(engine.notifications)

    def test_ghost_onNEP11Payment(self):
        engine = self.prepare_testengine()
        engine.add_contract(self.CONTRACT_PATH_NEF.replace('.py', '.nef'))
        aux_path = self.get_contract_path('test_native', 'auxiliary_contract.py')
        output, manifest = self.compile_and_save(self.CONTRACT_PATH_NEF.replace('.nef', '.py'))
        ghost_address = hash160(output)
        print(to_hex_str(ghost_address))
        output, manifest = self.compile_and_save(aux_path)
        aux_address = hash160(output)
        print(to_hex_str(aux_address))

        # add some gas for fees
        add_amount = 10 * 10 ** 8
        engine.add_gas(self.OTHER_ACCOUNT_1, add_amount)

        # mint
        token = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'mint', 
            self.OTHER_ACCOUNT_1, self.TOKEN_META, self.LOCK_CONTENT, self.ROYALTIES, None,
            signer_accounts=[self.OTHER_ACCOUNT_1],
            expected_result_type=bytes)

        # the smart contract will abort if any address calls the NEP11 onPayment method
        with self.assertRaises(TestExecutionException, msg=self.ABORTED_CONTRACT_MSG):
            result = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'onNEP11Payment', 
                self.OTHER_ACCOUNT_1, 1, token, None,
                signer_accounts=[self.OTHER_ACCOUNT_1],
                expected_result_type=bool)

    def test_ghost_onNEP17Payment(self):
        engine = self.prepare_testengine()
        engine.add_contract(self.CONTRACT_PATH_NEF.replace('.py', '.nef'))
        aux_path = self.get_contract_path('test_native', 'auxiliary_contract.py')
        output, manifest = self.compile_and_save(self.CONTRACT_PATH_NEF.replace('.nef', '.py'))
        ghost_address = hash160(output)
        print(to_hex_str(ghost_address))
        output, manifest = self.compile_and_save(aux_path)
        aux_address = hash160(output)
        print(to_hex_str(aux_address))

        # when deploying, the contract will mint tokens to the owner
        deploy_event = engine.get_events('Deployed')
        self.assertEqual(1, len(deploy_event))
        self.assertEqual(2, len(deploy_event[0].arguments))

        # add some gas for fees
        add_amount = 10 * 10 ** 8
        engine.add_gas(aux_address, add_amount)

        # the smart contract will abort if some address other than GAS calls the NEP17 onPayment method
        with self.assertRaises(TestExecutionException, msg=self.ABORTED_CONTRACT_MSG):
            self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'onNEP17Payment', aux_address, add_amount, None,
                                    signer_accounts=[aux_address])

    def test_ghost_mint_fee(self):
        engine = self.prepare_testengine()
        engine.add_contract(self.CONTRACT_PATH_NEF.replace('.py', '.nef'))
        output, manifest = self.compile_and_save(self.CONTRACT_PATH_NEF.replace('.nef', '.py'))
        ghost_address = hash160(output)

        # when deploying, the contract will mint tokens to the owner
        deploy_event = engine.get_events('Deployed')
        self.assertEqual(1, len(deploy_event))
        self.assertEqual(2, len(deploy_event[0].arguments))

        # add some gas for fees
        add_amount = 10 * 10 ** 8
        engine.add_gas(self.OTHER_ACCOUNT_1, add_amount/2)
        engine.add_gas(self.OWNER_SCRIPT_HASH, add_amount/2)

        # setMintFee
        fee = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'setMintFee', 1000,
                signer_accounts=[self.OWNER_SCRIPT_HASH],
                expected_result_type=int)

        # getMintFee should return the updated fee
        fee_event = engine.get_events('MintFeeUpdated')
        updated_fee = fee_event[0].arguments[1]
        self.assertEqual(updated_fee, 1000)

        # getMintFee should return the updated fee
        fee2 = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'getMintFee', expected_result_type=int)
        self.assertEqual(fee2, updated_fee)

        # fails because account not whitelisted
        with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'setMintFee', 1,
                                    signer_accounts=[self.OTHER_ACCOUNT_1],
                                    expected_result_type=int)

        # fees should be the same since it failed
        fee2 = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'getMintFee', expected_result_type=int)
        self.assertEqual(fee2, updated_fee)
        self.print_notif(engine.notifications)

    def test_ghost_fee_balance(self):
        engine = self.prepare_testengine()
        engine.add_contract(self.CONTRACT_PATH_NEF.replace('.py', '.nef'))
        output, manifest = self.compile_and_save(self.CONTRACT_PATH_NEF.replace('.nef', '.py'))
        ghost_address = hash160(output)

        # when deploying, the contract will mint tokens to the owner
        deploy_event = engine.get_events('Deployed')
        self.assertEqual(1, len(deploy_event))
        self.assertEqual(2, len(deploy_event[0].arguments))

        # add some gas for fees
        add_amount = 10 * 10 ** 8
        engine.add_gas(self.OTHER_ACCOUNT_1, add_amount)

        # check initial balance is 0
        balance = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'getFeeBalance',
                signer_accounts=[self.OWNER_SCRIPT_HASH],
                expected_result_type=int)
        self.assertEqual(0, balance)

        # mint + balanceOf
        token = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'mint', 
                self.OTHER_ACCOUNT_1, self.TOKEN_META, self.LOCK_CONTENT, self.ROYALTIES, None,
                signer_accounts=[self.OTHER_ACCOUNT_1],
                expected_result_type=bytes)
        balance_after = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'getFeeBalance',
                signer_accounts=[self.OWNER_SCRIPT_HASH],
                expected_result_type=int)
        initial_fee  = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'getMintFee', expected_result_type=int)

        # should have new balance
        self.assertEqual(initial_fee, balance_after)

        # set mint fee to 200000 + mint + getFeeBalance
        fee = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'setMintFee', 200000,
                signer_accounts=[self.OWNER_SCRIPT_HASH],
                expected_result_type=int)
        token = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'mint', 
                self.OTHER_ACCOUNT_1, self.TOKEN_META, self.LOCK_CONTENT, self.ROYALTIES, None,
                signer_accounts=[self.OTHER_ACCOUNT_1],
                expected_result_type=bytes)
        balance_after_updated = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'getFeeBalance',
                signer_accounts=[self.OWNER_SCRIPT_HASH],
                expected_result_type=int)
        
        # should have new balance
        self.assertEqual(balance_after_updated, balance_after + 200000)

        # withdraw fee
        success = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'withdrawFee', self.OWNER_SCRIPT_HASH,
                signer_accounts=[self.OWNER_SCRIPT_HASH],
                expected_result_type=int)
        self.assertEqual(True, success)

        # check balances after
        ghost_balance_after = self.run_smart_contract(engine, GAS_SCRIPT, 'balanceOf', ghost_address)
        self.assertEqual(0, ghost_balance_after)
        owner_balance = self.run_smart_contract(engine, GAS_SCRIPT, 'balanceOf', self.OWNER_SCRIPT_HASH)
        self.assertEqual(initial_fee + 200000, owner_balance)
        self.print_notif(engine.notifications)

        
    def test_ghost_locked_content(self):
        engine = self.prepare_testengine()
        engine.add_contract(self.CONTRACT_PATH_NEF.replace('.py', '.nef'))
        output, manifest = self.compile_and_save(self.CONTRACT_PATH_NEF.replace('.nef', '.py'))
        ghost_address = hash160(output)

        # when deploying, the contract will mint tokens to the owner
        deploy_event = engine.get_events('Deployed')
        self.assertEqual(1, len(deploy_event))
        self.assertEqual(2, len(deploy_event[0].arguments))

        # add some gas for fees
        add_amount = 10 * 10 ** 8
        engine.add_gas(self.OTHER_ACCOUNT_1, add_amount)

        # check if enough balance
        balance = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'getFeeBalance',
                signer_accounts=[self.OWNER_SCRIPT_HASH],
                expected_result_type=int)
        self.assertEqual(0, balance)

        # mint + getLockedContentViewCount
        token = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'mint', 
                self.OTHER_ACCOUNT_1, self.TOKEN_META, self.LOCK_CONTENT, self.ROYALTIES, None,
                signer_accounts=[self.OTHER_ACCOUNT_1],
                expected_result_type=bytes)
        views = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'getLockedContentViewCount', token,
                expected_result_type=int)

        # should have 0 views
        self.assertEqual(0, views)

        # getLockedContent
        content = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'getLockedContent', token,
                signer_accounts=[self.OTHER_ACCOUNT_1],
                expected_result_type=bytes)
        self.assertEqual(b'lockedContent', content)

        # getLockedContentViewCount should have 1 view
        views = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'getLockedContentViewCount', token,
                expected_result_type=int)
        print("views: " + str(views))
        self.assertEqual(1, views)

        # reset views and test getLockedContentViewCount with 100 views
        views = 0
        for i in range(0, 100):
            views += self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'getLockedContentViewCount', token,
                    expected_result_type=int)
        self.assertEqual(100, views)
        self.print_notif(engine.notifications)
Exemple #20
0
class TestNEP11Template(BoaTest):
    default_folder: str = 'examples'

    OTHER_ACCOUNT_1 = to_script_hash(b'NiNmXL8FjEUEs1nfX9uHFBNaenxDHJtmuB')

    def test_nep11_compile(self):
        path = self.get_contract_path('nep11_non_divisible.py')
        output, manifest = self.compile_and_save(path)

        self.assertIn('supportedstandards', manifest)
        self.assertIsInstance(manifest['supportedstandards'], list)
        self.assertGreater(len(manifest['supportedstandards']), 0)
        self.assertIn('NEP-11', manifest['supportedstandards'])

    def test_nep11_symbol(self):
        path = self.get_contract_path('nep11_non_divisible.py')
        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'symbol')
        self.assertEqual('NEP11', result)

    def test_nep11_decimals(self):
        path = self.get_contract_path('nep11_non_divisible.py')
        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'decimals')
        self.assertEqual(0, result)

    def test_nep11_total_supply(self):
        # smart contract deploys with zero tokens minted
        total_supply = 0

        path = self.get_contract_path('nep11_non_divisible.py')
        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'totalSupply')
        self.assertEqual(total_supply, result)

    def test_nep11_mint(self):
        path = self.get_contract_path('nep11_non_divisible.py')
        engine = TestEngine()

        self.run_smart_contract(engine, path, 'symbol')
        nep11_address = engine.executed_script_hash.to_array()

        aux_path = self.get_contract_path('examples/auxiliary_contracts',
                                          'auxiliary_contract.py')
        self.run_smart_contract(engine, aux_path, 'get_name')
        aux_address = engine.executed_script_hash.to_array()

        engine = TestEngine()
        engine.add_contract(path.replace('.py', '.nef'))

        # can't call the mint function directly
        with self.assertRaises(TestExecutionException):
            self.run_smart_contract(engine, path, 'mint', aux_address, 100)

        gas_used = 2 * 10**8
        engine.add_gas(aux_address, gas_used)

        # transferring GAS to the nep11 will mint some tokens
        result = self.run_smart_contract(engine,
                                         aux_path,
                                         'calling_transfer',
                                         constants.GAS_SCRIPT,
                                         aux_address,
                                         nep11_address,
                                         gas_used,
                                         None,
                                         signer_accounts=[aux_address])
        self.assertEqual(True, result)

    def test_nep11_total_balance_of(self):
        path = self.get_contract_path('nep11_non_divisible.py')
        engine = TestEngine()

        self.run_smart_contract(engine, path, 'symbol')
        nep11_address = engine.executed_script_hash.to_array()

        aux_path = self.get_contract_path('examples/auxiliary_contracts',
                                          'auxiliary_contract.py')
        self.run_smart_contract(engine, aux_path, 'get_name')
        aux_address = engine.executed_script_hash.to_array()

        engine = TestEngine()
        engine.add_contract(path.replace('.py', '.nef'))

        # every account starts with zero tokens
        result = self.run_smart_contract(engine, path, 'balanceOf',
                                         aux_address)
        self.assertEqual(0, result)

        gas_used = 2 * 10**8
        engine.add_gas(aux_address, gas_used)

        # transferring GAS to the nep11 will mint some tokens
        result = self.run_smart_contract(engine,
                                         aux_path,
                                         'calling_transfer',
                                         constants.GAS_SCRIPT,
                                         aux_address,
                                         nep11_address,
                                         gas_used,
                                         None,
                                         signer_accounts=[aux_address])
        self.assertEqual(True, result)

        # after minting 1 token, the amount of tokens should increment by 1
        result = self.run_smart_contract(engine, path, 'balanceOf',
                                         aux_address)
        self.assertEqual(1, result)

        gas_used = 6 * 10**8
        engine.add_gas(aux_address, gas_used)

        # minting another 3 nfts
        result = self.run_smart_contract(engine,
                                         aux_path,
                                         'calling_transfer',
                                         constants.GAS_SCRIPT,
                                         aux_address,
                                         nep11_address,
                                         gas_used,
                                         None,
                                         signer_accounts=[aux_address])
        self.assertEqual(True, result)

        # checking if the amount is 4 now
        result = self.run_smart_contract(engine, path, 'balanceOf',
                                         aux_address)
        self.assertEqual(4, result)

        # should fail when the script length is not 20
        with self.assertRaises(TestExecutionException,
                               msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path, 'balanceOf', bytes(10))
        with self.assertRaises(TestExecutionException,
                               msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path, 'balanceOf', bytes(30))

    def test_nep11_total_tokens_of(self):
        pass

    def test_nep11_total_owner_of(self):
        pass

    def test_nep11_total_transfer(self):
        pass
Exemple #21
0
class TestNEP17Template(BoaTest):

    default_folder: str = 'examples'

    OWNER_SCRIPT_HASH = bytes(20)
    OTHER_ACCOUNT_1 = to_script_hash(b'NiNmXL8FjEUEs1nfX9uHFBNaenxDHJtmuB')
    OTHER_ACCOUNT_2 = bytes(range(20))

    def test_nep17_compile(self):
        path = self.get_contract_path('NEP17.py')
        Boa3.compile(path)

    def test_nep17_deploy(self):
        path = self.get_contract_path('NEP17.py')
        engine = TestEngine()

        # needs the owner signature
        result = self.run_smart_contract(engine,
                                         path,
                                         method='deploy',
                                         expected_result_type=bool)
        self.assertEqual(False, result)

        # should return false if the signature isn't from the owner
        result = self.run_smart_contract(
            engine,
            path,
            'deploy',
            signer_accounts=[self.OTHER_ACCOUNT_1],
            expected_result_type=bool)
        self.assertEqual(False, result)

        result = self.run_smart_contract(
            engine,
            path,
            'deploy',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        # must always return false after first execution
        result = self.run_smart_contract(
            engine,
            path,
            'deploy',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(False, result)

    def test_nep17_symbol(self):
        path = self.get_contract_path('NEP17.py')
        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'symbol')
        self.assertEqual('NEP17', result)

    def test_nep17_decimals(self):
        path = self.get_contract_path('NEP17.py')
        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'decimals')
        self.assertEqual(8, result)

    def test_nep17_total_supply(self):
        total_supply = 10_000_000 * 10**8

        path = self.get_contract_path('NEP17.py')
        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'totalSupply')
        self.assertEqual(0, result)
        result = self.run_smart_contract(
            engine,
            path,
            'deploy',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)
        result = self.run_smart_contract(engine, path, 'totalSupply')
        self.assertEqual(total_supply, result)

    def test_nep17_total_balance_of(self):
        total_supply = 10_000_000 * 10**8

        path = self.get_contract_path('NEP17.py')
        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'balanceOf',
                                         self.OWNER_SCRIPT_HASH)
        self.assertEqual(0, result)

        result = self.run_smart_contract(
            engine,
            path,
            'deploy',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        result = self.run_smart_contract(engine, path, 'balanceOf',
                                         self.OWNER_SCRIPT_HASH)
        self.assertEqual(total_supply, result)

        # should fail when the script length is not 20
        with self.assertRaises(TestExecutionException,
                               msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path, 'balanceOf', bytes(10))
        with self.assertRaises(TestExecutionException,
                               msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path, 'balanceOf', bytes(30))

    @unittest.skip(
        'Examples need to be changed to test with the latest Neo version')
    def test_nep17_total_transfer(self):
        transferred_amount = 10 * 10**8  # 10 tokens

        path = self.get_contract_path('NEP17.py')
        engine = TestEngine()

        # should fail before running deploy
        result = self.run_smart_contract(engine,
                                         path,
                                         'transfer',
                                         self.OWNER_SCRIPT_HASH,
                                         self.OTHER_ACCOUNT_1,
                                         transferred_amount,
                                         None,
                                         expected_result_type=bool)
        self.assertEqual(False, result)

        result = self.run_smart_contract(
            engine,
            path,
            'deploy',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        # should fail if the sender doesn't sign
        result = self.run_smart_contract(engine,
                                         path,
                                         'transfer',
                                         self.OWNER_SCRIPT_HASH,
                                         self.OTHER_ACCOUNT_1,
                                         transferred_amount,
                                         None,
                                         expected_result_type=bool)
        self.assertEqual(False, result)

        # should fail if the sender doesn't have enough balance
        result = self.run_smart_contract(
            engine,
            path,
            'transfer',
            self.OTHER_ACCOUNT_1,
            self.OWNER_SCRIPT_HASH,
            transferred_amount,
            None,
            signer_accounts=[self.OTHER_ACCOUNT_1],
            expected_result_type=bool)
        self.assertEqual(False, result)

        # should fail when any of the scripts' length is not 20
        with self.assertRaises(TestExecutionException,
                               msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path,
                                    'transfer', self.OWNER_SCRIPT_HASH,
                                    bytes(10), transferred_amount, "")
        with self.assertRaises(TestExecutionException,
                               msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path, 'transfer', bytes(10),
                                    self.OTHER_ACCOUNT_1, transferred_amount,
                                    "")

        # should fail when the amount is less than 0
        with self.assertRaises(TestExecutionException,
                               msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path, 'transfer',
                                    self.OTHER_ACCOUNT_1,
                                    self.OWNER_SCRIPT_HASH, -10, None)

        # fire the transfer event when transferring to yourself
        balance_before = self.run_smart_contract(engine, path, 'balanceOf',
                                                 self.OWNER_SCRIPT_HASH)
        result = self.run_smart_contract(
            engine,
            path,
            'transfer',
            self.OWNER_SCRIPT_HASH,
            self.OWNER_SCRIPT_HASH,
            transferred_amount,
            None,
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)
        transfer_events = engine.get_events('Transfer')
        self.assertEqual(1, len(transfer_events))
        self.assertEqual(3, len(transfer_events[0].arguments))

        sender, receiver, amount = transfer_events[0].arguments
        if isinstance(sender, str):
            sender = String(sender).to_bytes()
        if isinstance(receiver, str):
            receiver = String(receiver).to_bytes()
        self.assertEqual(self.OWNER_SCRIPT_HASH, sender)
        self.assertEqual(self.OWNER_SCRIPT_HASH, receiver)
        self.assertEqual(transferred_amount, amount)

        # transferring to yourself doesn't change the balance
        balance_after = self.run_smart_contract(engine, path, 'balanceOf',
                                                self.OWNER_SCRIPT_HASH)
        self.assertEqual(balance_before, balance_after)

        # does fire the transfer event
        balance_sender_before = self.run_smart_contract(
            engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH)
        balance_receiver_before = self.run_smart_contract(
            engine, path, 'balanceOf', self.OTHER_ACCOUNT_1)
        result = self.run_smart_contract(
            engine,
            path,
            'transfer',
            self.OWNER_SCRIPT_HASH,
            self.OTHER_ACCOUNT_1,
            transferred_amount,
            None,
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)
        transfer_events = engine.get_events('Transfer')
        self.assertEqual(1, len(transfer_events))
        self.assertEqual(3, len(transfer_events[0].arguments))

        sender, receiver, amount = transfer_events[0].arguments
        if isinstance(sender, str):
            sender = String(sender).to_bytes()
        if isinstance(receiver, str):
            receiver = String(receiver).to_bytes()
        self.assertEqual(self.OWNER_SCRIPT_HASH, sender)
        self.assertEqual(self.OTHER_ACCOUNT_1, receiver)
        self.assertEqual(transferred_amount, amount)

        # transferring to someone other than yourself does change the balance
        balance_sender_after = self.run_smart_contract(engine, path,
                                                       'balanceOf',
                                                       self.OWNER_SCRIPT_HASH)
        balance_receiver_after = self.run_smart_contract(
            engine, path, 'balanceOf', self.OTHER_ACCOUNT_1)
        self.assertEqual(balance_sender_before - transferred_amount,
                         balance_sender_after)
        self.assertEqual(balance_receiver_before + transferred_amount,
                         balance_receiver_after)

    @unittest.skip(
        'Examples need to be changed to test with the latest Neo version')
    def test_nep17_onPayment(self):
        transferred_amount = 10 * 10**8  # 10 tokens

        path = self.get_contract_path('NEP17.py')
        engine = TestEngine()

        engine.add_contract(path.replace('.py', '.nef'))

        output, manifest = self.compile_and_save(path)
        nep17_address = hash160(output)

        result = self.run_smart_contract(
            engine,
            path,
            'deploy',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        engine.add_neo(self.OWNER_SCRIPT_HASH, transferred_amount)
        engine.add_gas(self.OWNER_SCRIPT_HASH, transferred_amount)

        # transferring NEO to the smart contract
        # saving the balance before the transfer to be able to compare after it
        neo_balance_sender_before = self.run_smart_contract(
            engine, NEO_SCRIPT, 'balanceOf', self.OWNER_SCRIPT_HASH)
        neo_balance_nep17_before = self.run_smart_contract(
            engine, NEO_SCRIPT, 'balanceOf', nep17_address)
        nep17_balance_sender_before = self.run_smart_contract(
            engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH)

        result = self.run_smart_contract(
            engine,
            NEO_SCRIPT,
            'transfer',
            self.OWNER_SCRIPT_HASH,
            nep17_address,
            transferred_amount,
            None,
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)
        transfer_events = engine.get_events('Transfer')
        self.assertEqual(2, len(transfer_events))
        self.assertEqual(3, len(transfer_events[0].arguments))
        self.assertEqual(3, len(transfer_events[1].arguments))

        # this is the event NEO emitted
        sender, receiver, amount = transfer_events[0].arguments
        if isinstance(sender, str):
            sender = String(sender).to_bytes()
        if isinstance(receiver, str):
            receiver = String(receiver).to_bytes()
        self.assertEqual(self.OWNER_SCRIPT_HASH, sender)
        self.assertEqual(nep17_address, receiver)
        self.assertEqual(transferred_amount, amount)

        # this is the event NEP17 emitted
        sender, receiver, amount = transfer_events[1].arguments
        if isinstance(sender, str):
            sender = String(sender).to_bytes()
        if isinstance(receiver, str):
            receiver = String(receiver).to_bytes()
        self.assertEqual(None, sender)
        self.assertEqual(self.OWNER_SCRIPT_HASH, receiver)
        # transferred_amount is multiplied by 10, because this smart contract is minting the NEO received
        self.assertEqual(transferred_amount * 10, amount)

        # saving the balance after the transfer to compare it with the previous data
        neo_balance_sender_after = self.run_smart_contract(
            engine, NEO_SCRIPT, 'balanceOf', self.OWNER_SCRIPT_HASH)
        neo_balance_nep17_after = self.run_smart_contract(
            engine, NEO_SCRIPT, 'balanceOf', nep17_address)
        nep17_balance_sender_after = self.run_smart_contract(
            engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH)

        self.assertEqual(neo_balance_sender_before - transferred_amount,
                         neo_balance_sender_after)
        self.assertEqual(neo_balance_nep17_before + transferred_amount,
                         neo_balance_nep17_after)
        # transferred_amount is multiplied by 10, because this smart contract is minting the NEO received
        self.assertEqual(nep17_balance_sender_before + transferred_amount * 10,
                         nep17_balance_sender_after)

        # transferring GAS to the smart contract
        # saving the balance before the transfer to be able to compare after it
        gas_balance_sender_before = self.run_smart_contract(
            engine, GAS_SCRIPT, 'balanceOf', self.OWNER_SCRIPT_HASH)
        gas_balance_nep17_before = self.run_smart_contract(
            engine, GAS_SCRIPT, 'balanceOf', nep17_address)
        nep17_balance_sender_before = self.run_smart_contract(
            engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH)

        result = self.run_smart_contract(
            engine,
            GAS_SCRIPT,
            'transfer',
            self.OWNER_SCRIPT_HASH,
            nep17_address,
            transferred_amount,
            None,
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)
        transfer_events = engine.get_events('Transfer')
        self.assertEqual(2, len(transfer_events))
        self.assertEqual(3, len(transfer_events[0].arguments))
        self.assertEqual(3, len(transfer_events[1].arguments))

        # this is the event GAS emitted
        sender, receiver, amount = transfer_events[0].arguments
        if isinstance(sender, str):
            sender = String(sender).to_bytes()
        if isinstance(receiver, str):
            receiver = String(receiver).to_bytes()
        self.assertEqual(self.OWNER_SCRIPT_HASH, sender)
        self.assertEqual(nep17_address, receiver)
        self.assertEqual(transferred_amount, amount)

        # this is the event NEP17 emitted
        sender, receiver, amount = transfer_events[1].arguments
        if isinstance(sender, str):
            sender = String(sender).to_bytes()
        if isinstance(receiver, str):
            receiver = String(receiver).to_bytes()
        self.assertEqual(None, sender)
        self.assertEqual(self.OWNER_SCRIPT_HASH, receiver)
        # transferred_amount is multiplied by 2, because this smart contract is minting the GAS received
        self.assertEqual(transferred_amount * 2, amount)

        # saving the balance after the transfer to compare it with the previous data
        gas_balance_sender_after = self.run_smart_contract(
            engine, GAS_SCRIPT, 'balanceOf', self.OWNER_SCRIPT_HASH)
        gas_balance_nep17_after = self.run_smart_contract(
            engine, GAS_SCRIPT, 'balanceOf', nep17_address)
        nep17_balance_sender_after = self.run_smart_contract(
            engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH)

        self.assertEqual(gas_balance_sender_before - transferred_amount,
                         gas_balance_sender_after)
        self.assertEqual(gas_balance_nep17_before + transferred_amount,
                         gas_balance_nep17_after)
        # transferred_amount is multiplied by 2, because this smart contract is minting the GAS received
        self.assertEqual(nep17_balance_sender_before + transferred_amount * 2,
                         nep17_balance_sender_after)

        # trying to call onNEP17Transfer() will result in an abort if the one calling it is not NEO or GAS contracts
        with self.assertRaises(TestExecutionException,
                               msg=self.ABORTED_CONTRACT_MSG):
            self.run_smart_contract(engine, path, 'onNEP17Transfer',
                                    self.OWNER_SCRIPT_HASH, transferred_amount,
                                    None)

    def test_nep17_verify(self):
        path = self.get_contract_path('NEP17.py')
        engine = TestEngine()

        # should fail without signature
        result = self.run_smart_contract(engine,
                                         path,
                                         'verify',
                                         expected_result_type=bool)
        self.assertEqual(False, result)

        # should fail if not signed by the owner
        result = self.run_smart_contract(
            engine,
            path,
            'verify',
            signer_accounts=[self.OTHER_ACCOUNT_1],
            expected_result_type=bool)
        self.assertEqual(False, result)

        result = self.run_smart_contract(
            engine,
            path,
            'verify',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)
Exemple #22
0
class TestUpdateContractTemplate(BoaTest):
    default_folder: str = 'examples'

    OWNER_SCRIPT_HASH = bytes(20)
    OTHER_ACCOUNT_1 = to_script_hash(b'NiNmXL8FjEUEs1nfX9uHFBNaenxDHJtmuB')

    def test_update_contract_compile(self):
        path = self.get_contract_path('update_contract.py')
        path_new = self.get_contract_path('examples/auxiliary_contracts',
                                          'update_contract.py')
        Boa3.compile(path)
        Boa3.compile(path_new)

    def test_update_contract(self):
        path = self.get_contract_path('update_contract.py')
        path_new = self.get_contract_path('examples/auxiliary_contracts',
                                          'update_contract.py')
        self.get_output(path_new)

        new_nef, new_manifest = self.get_bytes_output(path_new)
        arg_manifest = String(json.dumps(new_manifest,
                                         separators=(',', ':'))).to_bytes()
        engine = TestEngine()

        # Saving user's balance before calling method to compare it later
        tokens_before = self.run_smart_contract(engine, path, 'balanceOf',
                                                self.OTHER_ACCOUNT_1)

        event_transfer = engine.get_events('Transfer')
        # Transfer emitted when deploying the smart contract
        self.assertEqual(1, len(event_transfer))

        # The bugged method is being called and the user is able to receive tokens for free
        result = self.run_smart_contract(engine, path, 'method',
                                         self.OTHER_ACCOUNT_1)
        self.assertIsVoid(result)

        event_transfer = engine.get_events('Transfer')
        self.assertEqual(2, len(event_transfer))
        # The amount of tokens will be higher after calling the method
        tokens_after = self.run_smart_contract(engine, path, 'balanceOf',
                                               self.OTHER_ACCOUNT_1)
        self.assertGreater(tokens_after, tokens_before)

        # The smart contract will be updated to fix the bug in the method
        result = self.run_smart_contract(
            engine,
            path,
            'update_sc',
            new_nef,
            arg_manifest,
            None,
            signer_accounts=[self.OWNER_SCRIPT_HASH])
        self.assertIsVoid(result)

        # An `Update` event will be emitted
        event_update = engine.get_events('Update')
        self.assertEqual(1, len(event_update))

        # Saving user's balance before calling method to compare it later
        tokens_before = self.run_smart_contract(engine, path, 'balanceOf',
                                                self.OTHER_ACCOUNT_1)

        # Now, when method is called, it won't mint new tokens to any user that called it
        result = self.run_smart_contract(engine, path, 'method',
                                         self.OTHER_ACCOUNT_1)
        self.assertIsVoid(result)

        # The amount of tokens now is the same before and after calling the method
        tokens_after = self.run_smart_contract(engine, path, 'balanceOf',
                                               self.OTHER_ACCOUNT_1)
        self.assertEqual(tokens_after, tokens_before)
Exemple #23
0
class TestTemplate(BoaTest):

    default_folder: str = 'examples'

    OWNER_SCRIPT_HASH = bytes(20)
    OTHER_ACCOUNT_1 = to_script_hash(b'NiNmXL8FjEUEs1nfX9uHFBNaenxDHJtmuB')
    OTHER_ACCOUNT_2 = bytes(range(20))

    def test_amm_compile(self):
        path = self.get_contract_path('amm.py')
        Boa3.compile(path)

    def test_amm_deploy(self):
        path = self.get_contract_path('amm.py')
        engine = TestEngine()

        # needs the owner signature
        result = self.run_smart_contract(engine, path, method='deploy',
                                         expected_result_type=bool)
        self.assertEqual(False, result)

        # should return false if the signature isn't from the owner
        result = self.run_smart_contract(engine, path, 'deploy',
                                         signer_accounts=[self.OTHER_ACCOUNT_1],
                                         expected_result_type=bool)
        self.assertEqual(False, result)

        result = self.run_smart_contract(engine, path, 'deploy',
                                         signer_accounts=[self.OWNER_SCRIPT_HASH],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        # must always return false after first execution
        result = self.run_smart_contract(engine, path, 'deploy',
                                         signer_accounts=[self.OWNER_SCRIPT_HASH],
                                         expected_result_type=bool)
        self.assertEqual(False, result)

    def test_amm_set_address(self):
        path = self.get_contract_path('amm.py')
        path_zneo = self.get_contract_path('wrapped_neo.py')
        path_zgas = self.get_contract_path('wrapped_gas.py')
        engine = TestEngine()

        engine.add_contract(path_zneo.replace('.py', '.nef'))
        engine.add_contract(path_zgas.replace('.py', '.nef'))

        output, manifest = self.compile_and_save(path_zneo)
        zneo_address = hash160(output)

        output, manifest = self.compile_and_save(path_zgas)
        zgas_address = hash160(output)

        # won't work because the contract must have been deployed before
        result = self.run_smart_contract(engine, path, 'set_address', zneo_address, zgas_address,
                                         signer_accounts=[self.OWNER_SCRIPT_HASH],
                                         expected_result_type=bool)
        self.assertEqual(False, result)

        result = self.run_smart_contract(engine, path, 'deploy',
                                         signer_accounts=[self.OWNER_SCRIPT_HASH],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        # won't work because it needs the owner signature
        result = self.run_smart_contract(engine, path, 'set_address', zneo_address, zgas_address,
                                         signer_accounts=[self.OTHER_ACCOUNT_1],
                                         expected_result_type=bool)
        self.assertEqual(False, result)

        # it will work now
        result = self.run_smart_contract(engine, path, 'set_address', zneo_address, zgas_address,
                                         signer_accounts=[self.OWNER_SCRIPT_HASH],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        # initialize will work once
        result = self.run_smart_contract(engine, path, 'set_address', zneo_address, zgas_address,
                                         signer_accounts=[self.OWNER_SCRIPT_HASH],
                                         expected_result_type=bool)
        self.assertEqual(False, result)

    def test_amm_symbol(self):
        path = self.get_contract_path('amm.py')
        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'symbol')
        self.assertEqual('AMM', result)

    def test_amm_decimals(self):
        path = self.get_contract_path('amm.py')
        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'decimals')
        self.assertEqual(8, result)

    def test_amm_total_supply(self):
        path = self.get_contract_path('amm.py')
        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'totalSupply')
        self.assertEqual(0, result)

    def test_amm_total_balance_of(self):
        path = self.get_contract_path('amm.py')
        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH)
        self.assertEqual(0, result)

        # should fail when the script length is not 20
        with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path, 'balanceOf', bytes(10))
        with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path, 'balanceOf', bytes(30))

    def test_amm_quote(self):
        path = self.get_contract_path('amm.py')
        engine = TestEngine()
        amount_zneo = 1 * 10 ** 8
        reserve_zneo = 100 * 10 ** 8
        reserve_zgas = 1100 * 10 ** 8
        result = self.run_smart_contract(engine, path, 'quote', amount_zneo, reserve_zneo, reserve_zgas)
        amount_zgas = amount_zneo * reserve_zgas // reserve_zneo
        self.assertEqual(amount_zgas, result)

    def test_amm_onNEP17Payment(self):
        transferred_amount = 10 * 10 ** 8

        path = self.get_contract_path('amm.py')
        path_aux = self.get_contract_path('examples/test_native', 'auxiliary_contract.py')
        path_zneo = self.get_contract_path('wrapped_neo.py')
        path_zgas = self.get_contract_path('wrapped_gas.py')
        engine = TestEngine()

        engine.add_contract(path.replace('.py', '.nef'))
        engine.add_contract(path_zneo.replace('.py', '.nef'))
        engine.add_contract(path_zgas.replace('.py', '.nef'))

        output, manifest = self.compile_and_save(path)
        amm_address = hash160(output)

        output, manifest = self.compile_and_save(path_aux)
        aux_address = hash160(output)

        output, manifest = self.compile_and_save(path_zneo)
        zneo_address = hash160(output)

        output, manifest = self.compile_and_save(path_zgas)
        zgas_address = hash160(output)

        result = self.run_smart_contract(engine, path, 'deploy',
                                         signer_accounts=[self.OWNER_SCRIPT_HASH],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        result = self.run_smart_contract(engine, path, 'set_address', zneo_address, zgas_address,
                                         signer_accounts=[self.OWNER_SCRIPT_HASH],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        # the smart contract will abort if some address other than zNEO or zGAS calls the onPayment method
        with self.assertRaises(TestExecutionException, msg=self.ABORTED_CONTRACT_MSG):
            self.run_smart_contract(engine, path, 'onNEP17Payment', aux_address, transferred_amount, None,
                                    signer_accounts=[aux_address])

        engine.add_neo(aux_address, transferred_amount)

        # adding the transferred_amount into the aux_address
        result = self.run_smart_contract(engine, path_aux, 'calling_transfer',
                                         NEO_SCRIPT, aux_address, zneo_address, transferred_amount, None,
                                         signer_accounts=[aux_address],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        # the AMM will accept this transaction, but there is no reason to send tokens directly to the smart contract.
        # to send tokens to the AMM you should use the add_liquidity function
        result = self.run_smart_contract(engine, path_aux, 'calling_transfer',
                                         zneo_address, aux_address, amm_address, transferred_amount, None,
                                         signer_accounts=[aux_address],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

    def test_amm_add_liquidity(self):
        transferred_amount_zneo = 10 * 10 ** 8
        transferred_amount_zgas = 110 * 10 ** 8

        path = self.get_contract_path('amm.py')
        path_zneo = self.get_contract_path('wrapped_neo.py')
        path_zgas = self.get_contract_path('wrapped_gas.py')
        path_aux = self.get_contract_path('examples/test_native', 'auxiliary_contract.py')
        engine = TestEngine()

        engine.add_contract(path.replace('.py', '.nef'))
        engine.add_contract(path_zneo.replace('.py', '.nef'))
        engine.add_contract(path_zgas.replace('.py', '.nef'))

        output, manifest = self.compile_and_save(path)
        amm_address = hash160(output)

        output, manifest = self.compile_and_save(path_zneo)
        zneo_address = hash160(output)

        output, manifest = self.compile_and_save(path_zgas)
        zgas_address = hash160(output)

        output, manifest = self.compile_and_save(path_aux)
        aux_address = hash160(output)

        result = self.run_smart_contract(engine, path, 'deploy',
                                         signer_accounts=[self.OWNER_SCRIPT_HASH],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        result = self.run_smart_contract(engine, path, 'set_address', zneo_address, zgas_address,
                                         signer_accounts=[self.OWNER_SCRIPT_HASH],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        engine.add_neo(aux_address, 10_000_000 * 10 ** 8)
        # minting zNEO to this auxiliary smart contract is needed, because the test engine has some limitations
        result = self.run_smart_contract(engine, path_aux, 'calling_transfer',
                                         NEO_SCRIPT, aux_address, zneo_address, 10_000_000 * 10 ** 8, None,
                                         signer_accounts=[aux_address],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        engine.add_gas(aux_address, 10_000_000 * 10 ** 8)
        # minting zGAS to this auxiliary smart contract is needed, because the test engine has some limitations
        result = self.run_smart_contract(engine, path_aux, 'calling_transfer',
                                         GAS_SCRIPT, aux_address, zgas_address, 10_000_000 * 10 ** 8, None,
                                         signer_accounts=[aux_address],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        # won't work, because the user did not allow the amm to transfer zNEO and zGAS
        with self.assertRaises(TestExecutionException, msg=self.ABORTED_CONTRACT_MSG):
            self.run_smart_contract(engine, path, 'add_liquidity', transferred_amount_zneo, transferred_amount_zgas, 0,
                                    0, aux_address,
                                    signer_accounts=[aux_address])

        # approving the AMM contract, so that it will be able to transfer zNEO from test_address
        result = self.run_smart_contract(engine, path_aux, 'calling_approve',
                                         zneo_address, amm_address, transferred_amount_zneo,
                                         signer_accounts=[aux_address],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        # approving the AMM contract, so that it will be able to transfer zGAS from test_address
        result = self.run_smart_contract(engine, path_aux, 'calling_approve',
                                         zgas_address, amm_address, transferred_amount_zgas,
                                         signer_accounts=[aux_address],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        # saving data to demonstrate that the value will change later
        total_supply_before = self.run_smart_contract(engine, path, 'totalSupply')
        balance_user_amm_before = self.run_smart_contract(engine, path, 'balanceOf', aux_address)
        reserves_before = self.run_smart_contract(engine, path, 'get_reserves')
        balance_user_zneo_before = self.run_smart_contract(engine, path_zneo, 'balanceOf', aux_address)
        balance_user_zgas_before = self.run_smart_contract(engine, path_zgas, 'balanceOf', aux_address)
        balance_amm_zneo_before = self.run_smart_contract(engine, path_zneo, 'balanceOf', amm_address)
        balance_amm_zgas_before = self.run_smart_contract(engine, path_zgas, 'balanceOf', amm_address)
        # adding liquidity to the pool will give you AMM tokens in return
        result = self.run_smart_contract(engine, path, 'add_liquidity',
                                         transferred_amount_zneo, transferred_amount_zgas, 0, 0, aux_address,
                                         signer_accounts=[aux_address])
        import math
        liquidity = int(math.sqrt(transferred_amount_zneo * transferred_amount_zgas))
        self.assertEqual(3, len(result))
        self.assertEqual(transferred_amount_zneo, result[0])
        self.assertEqual(transferred_amount_zgas, result[1])
        self.assertEqual(liquidity, result[2])

        transfer_events = engine.get_events('Transfer', origin=amm_address)
        self.assertEqual(1, len(transfer_events))
        self.assertEqual(3, len(transfer_events[0].arguments))

        sender, receiver, amount = transfer_events[0].arguments
        if isinstance(sender, str):
            sender = String(sender).to_bytes()
        if isinstance(receiver, str):
            receiver = String(receiver).to_bytes()
        self.assertEqual(None, sender)
        self.assertEqual(aux_address, receiver)
        self.assertEqual(liquidity, amount)

        sync_events = engine.get_events('Sync', origin=amm_address)
        self.assertEqual(1, len(sync_events))
        self.assertEqual(2, len(sync_events[0].arguments))

        balance_zneo, balance_zgas = sync_events[0].arguments
        self.assertEqual(transferred_amount_zneo, balance_zneo)
        self.assertEqual(transferred_amount_zgas, balance_zgas)

        mint_events = engine.get_events('Mint', origin=amm_address)
        self.assertEqual(1, len(mint_events))
        self.assertEqual(3, len(mint_events[0].arguments))

        address, amount_zneo, amount_zgas = mint_events[0].arguments
        if isinstance(address, str):
            address = String(address).to_bytes()
        self.assertEqual(aux_address, address)
        self.assertEqual(transferred_amount_zneo, amount_zneo)
        self.assertEqual(transferred_amount_zgas, amount_zgas)

        # data that will be compared with the previously saved data
        total_supply_after = self.run_smart_contract(engine, path, 'totalSupply')
        balance_user_amm_after = self.run_smart_contract(engine, path, 'balanceOf', aux_address)
        reserves_after = self.run_smart_contract(engine, path, 'get_reserves')
        balance_user_zneo_after = self.run_smart_contract(engine, path_zneo, 'balanceOf', aux_address)
        balance_user_zgas_after = self.run_smart_contract(engine, path_zgas, 'balanceOf', aux_address)
        balance_amm_zneo_after = self.run_smart_contract(engine, path_zneo, 'balanceOf', amm_address)
        balance_amm_zgas_after = self.run_smart_contract(engine, path_zgas, 'balanceOf', amm_address)

        self.assertEqual(total_supply_before + liquidity, total_supply_after)
        self.assertEqual(balance_user_amm_before + liquidity, balance_user_amm_after)
        self.assertEqual(reserves_before[0] + transferred_amount_zneo, reserves_after[0])
        self.assertEqual(reserves_before[1] + transferred_amount_zgas, reserves_after[1])
        self.assertEqual(balance_user_zneo_before - transferred_amount_zneo, balance_user_zneo_after)
        self.assertEqual(balance_user_zgas_before - transferred_amount_zgas, balance_user_zgas_after)
        self.assertEqual(reserves_before[0], balance_amm_zneo_before)
        self.assertEqual(reserves_before[1], balance_amm_zgas_before)
        self.assertEqual(reserves_after[0], balance_amm_zneo_after)
        self.assertEqual(reserves_after[1], balance_amm_zgas_after)

        transferred_amount_zneo = 2 * 10 ** 8
        transferred_amount_zgas = 23 * 10 ** 8

        # approving the AMM contract, so that it will be able to transfer zNEO from test_address
        result = self.run_smart_contract(engine, path_aux, 'calling_approve',
                                         zneo_address, amm_address, transferred_amount_zneo,
                                         signer_accounts=[aux_address],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        # approving the AMM contract, so that it will be able to transfer zGAS from test_address
        result = self.run_smart_contract(engine, path_aux, 'calling_approve',
                                         zgas_address, amm_address, transferred_amount_zgas,
                                         signer_accounts=[aux_address],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        # saving data to demonstrate that the value will change later
        total_supply_before = self.run_smart_contract(engine, path, 'totalSupply')
        balance_user_before = self.run_smart_contract(engine, path, 'balanceOf', aux_address)
        reserves_before = self.run_smart_contract(engine, path, 'get_reserves')
        balance_user_zneo_before = self.run_smart_contract(engine, path_zneo, 'balanceOf', aux_address)
        balance_user_zgas_before = self.run_smart_contract(engine, path_zgas, 'balanceOf', aux_address)
        balance_amm_zneo_before = self.run_smart_contract(engine, path_zneo, 'balanceOf', amm_address)
        balance_amm_zgas_before = self.run_smart_contract(engine, path_zgas, 'balanceOf', amm_address)
        # adding liquidity to the pool will give you AMM tokens in return
        result = self.run_smart_contract(engine, path, 'add_liquidity',
                                         transferred_amount_zneo, transferred_amount_zgas, 0, 0, aux_address,
                                         signer_accounts=[aux_address])
        # zGAS will be quoted to keep the same ratio between zNEO and zGAS, the current ratio is 1 NEO to 11 GAS,
        # therefore, if 2 NEO are being added to the AMM, 22 GAS will be added instead of 23
        transferred_amount_zgas_quoted = transferred_amount_zneo * reserves_before[1] // reserves_before[0]
        # since there are tokens in the pool already, liquidity will be calculated as follows
        liquidity = min(transferred_amount_zneo * total_supply_before // reserves_before[0],
                        transferred_amount_zgas_quoted * total_supply_before // reserves_before[1])
        self.assertEqual(3, len(result))
        self.assertEqual(transferred_amount_zneo, result[0])
        self.assertEqual(transferred_amount_zgas_quoted, result[1])
        self.assertEqual(liquidity, result[2])

        transfer_events = engine.get_events('Transfer', origin=amm_address)
        self.assertEqual(2, len(transfer_events))
        self.assertEqual(3, len(transfer_events[1].arguments))

        sender, receiver, amount = transfer_events[1].arguments
        if isinstance(sender, str):
            sender = String(sender).to_bytes()
        if isinstance(receiver, str):
            receiver = String(receiver).to_bytes()
        self.assertEqual(None, sender)
        self.assertEqual(aux_address, receiver)
        self.assertEqual(liquidity, amount)

        sync_events = engine.get_events('Sync', origin=amm_address)
        self.assertEqual(2, len(sync_events))
        self.assertEqual(2, len(sync_events[1].arguments))

        balance_zneo, balance_zgas = sync_events[1].arguments
        self.assertEqual(reserves_before[0] + transferred_amount_zneo, balance_zneo)
        self.assertEqual(reserves_before[1] + transferred_amount_zgas_quoted, balance_zgas)

        mint_events = engine.get_events('Mint', origin=amm_address)
        self.assertEqual(2, len(mint_events))
        self.assertEqual(3, len(mint_events[1].arguments))

        address, amount_zneo, amount_zgas = mint_events[1].arguments
        if isinstance(address, str):
            address = String(address).to_bytes()
        self.assertEqual(aux_address, address)
        self.assertEqual(transferred_amount_zneo, amount_zneo)
        self.assertEqual(transferred_amount_zgas_quoted, amount_zgas)

        # data that will be compared with the previously saved data
        total_supply_after = self.run_smart_contract(engine, path, 'totalSupply')
        balance_user_after = self.run_smart_contract(engine, path, 'balanceOf', aux_address)
        reserves_after = self.run_smart_contract(engine, path, 'get_reserves')
        balance_user_zneo_after = self.run_smart_contract(engine, path_zneo, 'balanceOf', aux_address)
        balance_user_zgas_after = self.run_smart_contract(engine, path_zgas, 'balanceOf', aux_address)
        balance_amm_zneo_after = self.run_smart_contract(engine, path_zneo, 'balanceOf', amm_address)
        balance_amm_zgas_after = self.run_smart_contract(engine, path_zgas, 'balanceOf', amm_address)

        self.assertEqual(total_supply_before + liquidity, total_supply_after)
        self.assertEqual(balance_user_before + liquidity, balance_user_after)
        self.assertEqual(reserves_before[0] + transferred_amount_zneo, reserves_after[0])
        self.assertEqual(reserves_before[1] + transferred_amount_zgas_quoted, reserves_after[1])
        self.assertEqual(balance_user_zneo_before - transferred_amount_zneo, balance_user_zneo_after)
        self.assertEqual(balance_user_zgas_before - transferred_amount_zgas_quoted, balance_user_zgas_after)
        self.assertEqual(reserves_before[0], balance_amm_zneo_before)
        self.assertEqual(reserves_before[1], balance_amm_zgas_before)
        self.assertEqual(reserves_after[0], balance_amm_zneo_after)
        self.assertEqual(reserves_after[1], balance_amm_zgas_after)

    def test_amm_remove_liquidity(self):
        transferred_amount_zneo = 10 * 10 ** 8
        transferred_amount_zgas = 110 * 10 ** 8

        path = self.get_contract_path('amm.py')
        path_zneo = self.get_contract_path('wrapped_neo.py')
        path_zgas = self.get_contract_path('wrapped_gas.py')
        path_aux = self.get_contract_path('examples/test_native', 'auxiliary_contract.py')
        engine = TestEngine()

        engine.add_contract(path.replace('.py', '.nef'))
        engine.add_contract(path_zneo.replace('.py', '.nef'))
        engine.add_contract(path_zgas.replace('.py', '.nef'))

        output, manifest = self.compile_and_save(path)
        amm_address = hash160(output)

        output, manifest = self.compile_and_save(path_zneo)
        zneo_address = hash160(output)

        output, manifest = self.compile_and_save(path_zgas)
        zgas_address = hash160(output)

        output, manifest = self.compile_and_save(path_aux)
        aux_address = hash160(output)

        result = self.run_smart_contract(engine, path, 'deploy',
                                         signer_accounts=[self.OWNER_SCRIPT_HASH],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        result = self.run_smart_contract(engine, path, 'set_address', zneo_address, zgas_address,
                                         signer_accounts=[self.OWNER_SCRIPT_HASH],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        # can't remove liquidity, because the user doesn't have any
        with self.assertRaises(TestExecutionException, msg=self.ABORTED_CONTRACT_MSG):
            self.run_smart_contract(engine, path, 'remove_liquidity', 10000, 0, 0, aux_address,
                                    signer_accounts=[self.OWNER_SCRIPT_HASH])

        # deploying the wrapped_neo smart contract will give 10_000_000 zNEOs to the OWNER
        result = self.run_smart_contract(engine, path_zneo, 'deploy',
                                         signer_accounts=[self.OWNER_SCRIPT_HASH],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        # transferring zNEO to this auxiliary smart contract is needed, because the test engine has some limitations
        result = self.run_smart_contract(engine, path_zneo, 'transfer', self.OWNER_SCRIPT_HASH, aux_address,
                                         10_000_000 * 10 ** 8, None,
                                         signer_accounts=[self.OWNER_SCRIPT_HASH],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        # deploying the wrapped_gas smart contract will give 10_000_000 zGASs to the OWNER
        result = self.run_smart_contract(engine, path_zgas, 'deploy',
                                         signer_accounts=[self.OWNER_SCRIPT_HASH],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        # transferring zGAS to this auxiliary smart contract is needed, because the test engine has some limitations
        result = self.run_smart_contract(engine, path_zgas, 'transfer', self.OWNER_SCRIPT_HASH, aux_address,
                                         10_000_000 * 10 ** 8, None,
                                         signer_accounts=[self.OWNER_SCRIPT_HASH],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        # approving the AMM contract, so that it will be able to transfer zNEO from test_address
        result = self.run_smart_contract(engine, path_aux, 'calling_approve',
                                         zneo_address, amm_address, transferred_amount_zneo,
                                         signer_accounts=[aux_address],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        # approving the AMM contract, so that it will be able to transfer zGAS from test_address
        result = self.run_smart_contract(engine, path_aux, 'calling_approve',
                                         zgas_address, amm_address, transferred_amount_zgas,
                                         signer_accounts=[aux_address],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        # adding liquidity to the pool will give you AMM tokens in return
        result = self.run_smart_contract(engine, path, 'add_liquidity',
                                         transferred_amount_zneo, transferred_amount_zgas, 0, 0, aux_address,
                                         signer_accounts=[aux_address])
        import math
        liquidity = int(math.sqrt(transferred_amount_zneo * transferred_amount_zgas))
        self.assertEqual(3, len(result))
        self.assertEqual(transferred_amount_zneo, result[0])
        self.assertEqual(transferred_amount_zgas, result[1])
        self.assertEqual(liquidity, result[2])

        # saving data to demonstrate that the value will change later
        total_supply_before = self.run_smart_contract(engine, path, 'totalSupply')
        balance_user_before = self.run_smart_contract(engine, path, 'balanceOf', aux_address)
        reserves_before = self.run_smart_contract(engine, path, 'get_reserves')
        balance_user_zneo_before = self.run_smart_contract(engine, path_zneo, 'balanceOf', aux_address)
        balance_user_zgas_before = self.run_smart_contract(engine, path_zgas, 'balanceOf', aux_address)
        balance_amm_zneo_before = self.run_smart_contract(engine, path_zneo, 'balanceOf', amm_address)
        balance_amm_zgas_before = self.run_smart_contract(engine, path_zgas, 'balanceOf', amm_address)
        # removing liquidity from the pool will return the equivalent zNEO and zGAS that were used to fund the pool
        result = self.run_smart_contract(engine, path, 'remove_liquidity', liquidity, 0, 0, aux_address,
                                         signer_accounts=[aux_address])
        self.assertEqual(2, len(result))
        self.assertEqual(transferred_amount_zneo, result[0])
        self.assertEqual(transferred_amount_zgas, result[1])

        transfer_events = engine.get_events('Transfer', origin=amm_address)
        # add_liquidity sent a Transfer event and remove_liquidity sent another
        self.assertEqual(2, len(transfer_events))
        self.assertEqual(3, len(transfer_events[1].arguments))

        sender, receiver, amount = transfer_events[1].arguments
        if isinstance(sender, str):
            sender = String(sender).to_bytes()
        if isinstance(receiver, str):
            receiver = String(receiver).to_bytes()
        self.assertEqual(aux_address, sender)
        self.assertEqual(None, receiver)
        self.assertEqual(liquidity, amount)

        sync_events = engine.get_events('Sync', origin=amm_address)
        self.assertEqual(2, len(sync_events))
        self.assertEqual(2, len(sync_events[1].arguments))

        balance_zneo, balance_zgas = sync_events[1].arguments
        self.assertEqual(reserves_before[0] - transferred_amount_zneo, balance_zneo)
        self.assertEqual(reserves_before[1] - transferred_amount_zgas, balance_zgas)

        burn_events = engine.get_events('Burn', origin=amm_address)
        self.assertEqual(1, len(burn_events))
        self.assertEqual(3, len(burn_events[0].arguments))

        address, amount_zneo, amount_zgas = burn_events[0].arguments
        if isinstance(address, str):
            address = String(address).to_bytes()
        self.assertEqual(aux_address, address)
        self.assertEqual(transferred_amount_zneo, amount_zneo)
        self.assertEqual(transferred_amount_zgas, amount_zgas)

        # data that will be compared with the previously saved data
        total_supply_after = self.run_smart_contract(engine, path, 'totalSupply')
        balance_user_after = self.run_smart_contract(engine, path, 'balanceOf', aux_address)
        reserves_after = self.run_smart_contract(engine, path, 'get_reserves')
        balance_user_zneo_after = self.run_smart_contract(engine, path_zneo, 'balanceOf', aux_address)
        balance_user_zgas_after = self.run_smart_contract(engine, path_zgas, 'balanceOf', aux_address)
        balance_amm_zneo_after = self.run_smart_contract(engine, path_zneo, 'balanceOf', amm_address)
        balance_amm_zgas_after = self.run_smart_contract(engine, path_zgas, 'balanceOf', amm_address)

        self.assertEqual(total_supply_before - liquidity, total_supply_after)
        self.assertEqual(balance_user_before - liquidity, balance_user_after)
        self.assertEqual(reserves_before[0] - transferred_amount_zneo, reserves_after[0])
        self.assertEqual(reserves_before[1] - transferred_amount_zgas, reserves_after[1])
        self.assertEqual(balance_user_zneo_before + transferred_amount_zneo, balance_user_zneo_after)
        self.assertEqual(balance_user_zgas_before + transferred_amount_zgas, balance_user_zgas_after)
        self.assertEqual(reserves_before[0], balance_amm_zneo_before)
        self.assertEqual(reserves_before[1], balance_amm_zgas_before)
        self.assertEqual(reserves_after[0], balance_amm_zneo_after)
        self.assertEqual(reserves_after[1], balance_amm_zgas_after)

    def test_amm_swap_zneo_to_zgas(self):
        transferred_amount_zneo = 10 * 10 ** 8
        transferred_amount_zgas = 110 * 10 ** 8

        path = self.get_contract_path('amm.py')
        path_zneo = self.get_contract_path('wrapped_neo.py')
        path_zgas = self.get_contract_path('wrapped_gas.py')
        path_aux = self.get_contract_path('examples/test_native', 'auxiliary_contract.py')
        engine = TestEngine()

        engine.add_contract(path.replace('.py', '.nef'))
        engine.add_contract(path_zneo.replace('.py', '.nef'))
        engine.add_contract(path_zgas.replace('.py', '.nef'))

        output, manifest = self.compile_and_save(path)
        amm_address = hash160(output)

        output, manifest = self.compile_and_save(path_zneo)
        zneo_address = hash160(output)

        output, manifest = self.compile_and_save(path_zgas)
        zgas_address = hash160(output)

        output, manifest = self.compile_and_save(path_aux)
        aux_address = hash160(output)

        result = self.run_smart_contract(engine, path, 'deploy',
                                         signer_accounts=[self.OWNER_SCRIPT_HASH],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        result = self.run_smart_contract(engine, path, 'set_address', zneo_address, zgas_address,
                                         signer_accounts=[self.OWNER_SCRIPT_HASH],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        # deploying the wrapped_neo smart contract will give 10_000_000 zNEOs to the OWNER
        result = self.run_smart_contract(engine, path_zneo, 'deploy',
                                         signer_accounts=[self.OWNER_SCRIPT_HASH],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        # transferring zNEO to this auxiliary smart contract is needed, because the test engine has some limitations
        result = self.run_smart_contract(engine, path_zneo, 'transfer', self.OWNER_SCRIPT_HASH, aux_address,
                                         10_000_000 * 10 ** 8, None,
                                         signer_accounts=[self.OWNER_SCRIPT_HASH],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        # deploying the wrapped_gas smart contract will give 10_000_000 zGASs to the OWNER
        result = self.run_smart_contract(engine, path_zgas, 'deploy',
                                         signer_accounts=[self.OWNER_SCRIPT_HASH],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        # transferring zGAS to this auxiliary smart contract is needed, because the test engine has some limitations
        result = self.run_smart_contract(engine, path_zgas, 'transfer', self.OWNER_SCRIPT_HASH, aux_address,
                                         10_000_000 * 10 ** 8, None,
                                         signer_accounts=[self.OWNER_SCRIPT_HASH],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        # approving the AMM contract, so that it will be able to transfer zNEO from test_address
        result = self.run_smart_contract(engine, path_aux, 'calling_approve',
                                         zneo_address, amm_address, transferred_amount_zneo,
                                         signer_accounts=[aux_address],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        # approving the AMM contract, so that it will be able to transfer zGAS from test_address
        result = self.run_smart_contract(engine, path_aux, 'calling_approve',
                                         zgas_address, amm_address, transferred_amount_zgas,
                                         signer_accounts=[aux_address],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        # adding liquidity to the pool will give you AMM tokens in return
        result = self.run_smart_contract(engine, path, 'add_liquidity',
                                         transferred_amount_zneo, transferred_amount_zgas, 0, 0, aux_address,
                                         signer_accounts=[aux_address])
        import math
        liquidity = int(math.sqrt(transferred_amount_zneo * transferred_amount_zgas))
        self.assertEqual(3, len(result))
        self.assertEqual(transferred_amount_zneo, result[0])
        self.assertEqual(transferred_amount_zgas, result[1])
        self.assertEqual(liquidity, result[2])

        swapped_zneo = 1 * 10 ** 8
        # won't work, because user did not enough zNEO tokens
        with self.assertRaises(TestExecutionException, msg=self.ABORTED_CONTRACT_MSG):
            self.run_smart_contract(engine, path, 'swap_tokens',
                                    swapped_zneo, 0, zneo_address, aux_address,
                                    signer_accounts=[aux_address])

        # approving the AMM contract, so that it will be able to transfer zNEO from test_address
        result = self.run_smart_contract(engine, path_aux, 'calling_approve',
                                         zneo_address, amm_address, swapped_zneo,
                                         signer_accounts=[aux_address],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        # saving data to demonstrate that the value will change later
        total_supply_before = self.run_smart_contract(engine, path, 'totalSupply')
        reserves_before = self.run_smart_contract(engine, path, 'get_reserves')
        balance_user_zneo_before = self.run_smart_contract(engine, path_zneo, 'balanceOf', aux_address)
        balance_user_zgas_before = self.run_smart_contract(engine, path_zgas, 'balanceOf', aux_address)
        balance_amm_zneo_before = self.run_smart_contract(engine, path_zneo, 'balanceOf', amm_address)
        balance_amm_zgas_before = self.run_smart_contract(engine, path_zgas, 'balanceOf', amm_address)
        # swapping zneo for zgas
        result = self.run_smart_contract(engine, path, 'swap_tokens',
                                         swapped_zneo, 0, zneo_address, aux_address,
                                         signer_accounts=[aux_address], rollback_on_fault=False)
        # there is a 0.3% fee when doing a swap
        swapped_zneo_with_fee = swapped_zneo * (1000 - 3)
        swapped_zgas = swapped_zneo_with_fee * reserves_before[1] // (reserves_before[0] * 1000 + swapped_zneo_with_fee)
        self.assertEqual(swapped_zgas, result)

        # add_liquidity sent a Sync before
        transfer_events = engine.get_events('Sync')
        self.assertEqual(2, len(transfer_events))
        self.assertEqual(2, len(transfer_events[1].arguments))

        balance_zneo, balance_zgas = transfer_events[1].arguments
        self.assertEqual(reserves_before[0] + swapped_zneo, balance_zneo)
        self.assertEqual(reserves_before[1] - swapped_zgas, balance_zgas)

        transfer_events = engine.get_events('Swap')
        self.assertEqual(1, len(transfer_events))
        self.assertEqual(5, len(transfer_events[0].arguments))

        address, amount_zneo_in, amount_zgas_in, amount_zneo_out, amount_zgas_out = transfer_events[0].arguments
        if isinstance(address, str):
            address = String(address).to_bytes()
        self.assertEqual(aux_address, address)
        self.assertEqual(swapped_zneo, amount_zneo_in)
        self.assertEqual(0, amount_zgas_in)
        self.assertEqual(0, amount_zneo_out)
        self.assertEqual(swapped_zgas, amount_zgas_out)

        # data that will be compared with the previously saved data
        total_supply_after = self.run_smart_contract(engine, path, 'totalSupply')
        reserves_after = self.run_smart_contract(engine, path, 'get_reserves')
        balance_user_zneo_after = self.run_smart_contract(engine, path_zneo, 'balanceOf', aux_address)
        balance_user_zgas_after = self.run_smart_contract(engine, path_zgas, 'balanceOf', aux_address)
        balance_amm_zneo_after = self.run_smart_contract(engine, path_zneo, 'balanceOf', amm_address)
        balance_amm_zgas_after = self.run_smart_contract(engine, path_zgas, 'balanceOf', amm_address)

        self.assertEqual(total_supply_before, total_supply_after)
        self.assertEqual(reserves_before[0] + swapped_zneo, reserves_after[0])
        self.assertEqual(reserves_before[1] - swapped_zgas, reserves_after[1])
        self.assertEqual(balance_user_zneo_before - swapped_zneo, balance_user_zneo_after)
        self.assertEqual(balance_user_zgas_before + swapped_zgas, balance_user_zgas_after)
        self.assertEqual(reserves_before[0], balance_amm_zneo_before)
        self.assertEqual(reserves_before[1], balance_amm_zgas_before)
        self.assertEqual(reserves_after[0], balance_amm_zneo_after)
        self.assertEqual(reserves_after[1], balance_amm_zgas_after)
        self.assertEqual(reserves_before[0] + swapped_zneo, reserves_after[0])
        self.assertEqual(reserves_before[1] - swapped_zgas, reserves_after[1])

    def test_amm_swap_zgas_to_zneo(self):
        transferred_amount_zneo = 10 * 10 ** 8
        transferred_amount_zgas = 110 * 10 ** 8

        path = self.get_contract_path('amm.py')
        path_zneo = self.get_contract_path('wrapped_neo.py')
        path_zgas = self.get_contract_path('wrapped_gas.py')
        path_aux = self.get_contract_path('examples/test_native', 'auxiliary_contract.py')
        engine = TestEngine()

        engine.add_contract(path.replace('.py', '.nef'))
        engine.add_contract(path_zneo.replace('.py', '.nef'))
        engine.add_contract(path_zgas.replace('.py', '.nef'))

        output, manifest = self.compile_and_save(path)
        amm_address = hash160(output)

        output, manifest = self.compile_and_save(path_zneo)
        zneo_address = hash160(output)

        output, manifest = self.compile_and_save(path_zgas)
        zgas_address = hash160(output)

        output, manifest = self.compile_and_save(path_aux)
        aux_address = hash160(output)

        result = self.run_smart_contract(engine, path, 'deploy',
                                         signer_accounts=[self.OWNER_SCRIPT_HASH],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        result = self.run_smart_contract(engine, path, 'set_address', zneo_address, zgas_address,
                                         signer_accounts=[self.OWNER_SCRIPT_HASH],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        # deploying the wrapped_neo smart contract will give 10_000_000 zNEOs to the OWNER
        result = self.run_smart_contract(engine, path_zneo, 'deploy',
                                         signer_accounts=[self.OWNER_SCRIPT_HASH],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        # transferring zNEO to this auxiliary smart contract is needed, because the test engine has some limitations
        result = self.run_smart_contract(engine, path_zneo, 'transfer', self.OWNER_SCRIPT_HASH, aux_address,
                                         10_000_000 * 10 ** 8, None,
                                         signer_accounts=[self.OWNER_SCRIPT_HASH],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        # deploying the wrapped_gas smart contract will give 10_000_000 zGASs to the OWNER
        result = self.run_smart_contract(engine, path_zgas, 'deploy',
                                         signer_accounts=[self.OWNER_SCRIPT_HASH],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        # transferring zGAS to this auxiliary smart contract is needed, because the test engine has some limitations
        result = self.run_smart_contract(engine, path_zgas, 'transfer', self.OWNER_SCRIPT_HASH, aux_address,
                                         10_000_000 * 10 ** 8, None,
                                         signer_accounts=[self.OWNER_SCRIPT_HASH],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        # approving the AMM contract, so that it will be able to transfer zNEO from test_address
        result = self.run_smart_contract(engine, path_aux, 'calling_approve',
                                         zneo_address, amm_address, transferred_amount_zneo,
                                         signer_accounts=[aux_address],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        # approving the AMM contract, so that it will be able to transfer zGAS from test_address
        result = self.run_smart_contract(engine, path_aux, 'calling_approve',
                                         zgas_address, amm_address, transferred_amount_zgas,
                                         signer_accounts=[aux_address],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        # adding liquidity to the pool will give you AMM tokens in return
        result = self.run_smart_contract(engine, path, 'add_liquidity',
                                         transferred_amount_zneo, transferred_amount_zgas, 0, 0, aux_address,
                                         signer_accounts=[aux_address])
        import math
        liquidity = int(math.sqrt(transferred_amount_zneo * transferred_amount_zgas))
        self.assertEqual(3, len(result))
        self.assertEqual(transferred_amount_zneo, result[0])
        self.assertEqual(transferred_amount_zgas, result[1])
        self.assertEqual(liquidity, result[2])

        swapped_zgas = 11 * 10 ** 8
        # won't work, because user did not enough zNEO tokens
        with self.assertRaises(TestExecutionException, msg=self.ABORTED_CONTRACT_MSG):
            self.run_smart_contract(engine, path, 'swap_tokens',
                                    swapped_zgas, 0, zgas_address, aux_address,
                                    signer_accounts=[aux_address])

        # approving the AMM contract, so that it will be able to transfer zNEO from test_address
        result = self.run_smart_contract(engine, path_aux, 'calling_approve',
                                         zgas_address, amm_address, swapped_zgas,
                                         signer_accounts=[aux_address],
                                         expected_result_type=bool)
        self.assertEqual(True, result)

        # saving data to demonstrate that the value will change later
        total_supply_before = self.run_smart_contract(engine, path, 'totalSupply')
        reserves_before = self.run_smart_contract(engine, path, 'get_reserves')
        balance_user_zneo_before = self.run_smart_contract(engine, path_zneo, 'balanceOf', aux_address)
        balance_user_zgas_before = self.run_smart_contract(engine, path_zgas, 'balanceOf', aux_address)
        balance_amm_zneo_before = self.run_smart_contract(engine, path_zneo, 'balanceOf', amm_address)
        balance_amm_zgas_before = self.run_smart_contract(engine, path_zgas, 'balanceOf', amm_address)
        # swapping zgas for zneo
        result = self.run_smart_contract(engine, path, 'swap_tokens',
                                         swapped_zgas, 0, zgas_address, aux_address,
                                         signer_accounts=[aux_address])
        # there is a 0.3% fee when doing a swap
        swapped_zgas_with_fee = swapped_zgas * (1000 - 3)
        swapped_zneo = swapped_zgas_with_fee * reserves_before[0] // (reserves_before[1] * 1000 + swapped_zgas_with_fee)
        self.assertEqual(swapped_zneo, result)

        # add_liquidity sent a Sync before
        transfer_events = engine.get_events('Sync')
        self.assertEqual(2, len(transfer_events))
        self.assertEqual(2, len(transfer_events[1].arguments))

        balance_zneo, balance_zgas = transfer_events[1].arguments
        self.assertEqual(reserves_before[0] - swapped_zneo, balance_zneo)
        self.assertEqual(reserves_before[1] + swapped_zgas, balance_zgas)

        transfer_events = engine.get_events('Swap')
        self.assertEqual(1, len(transfer_events))
        self.assertEqual(5, len(transfer_events[0].arguments))

        address, amount_zneo_in, amount_zgas_in, amount_zneo_out, amount_zgas_out = transfer_events[0].arguments
        if isinstance(address, str):
            address = String(address).to_bytes()
        self.assertEqual(aux_address, address)
        self.assertEqual(0, amount_zneo_in)
        self.assertEqual(swapped_zgas, amount_zgas_in)
        self.assertEqual(swapped_zneo, amount_zneo_out)
        self.assertEqual(0, amount_zgas_out)

        # data that will be compared with the previously saved data
        total_supply_after = self.run_smart_contract(engine, path, 'totalSupply')
        reserves_after = self.run_smart_contract(engine, path, 'get_reserves')
        balance_user_zneo_after = self.run_smart_contract(engine, path_zneo, 'balanceOf', aux_address)
        balance_user_zgas_after = self.run_smart_contract(engine, path_zgas, 'balanceOf', aux_address)
        balance_amm_zneo_after = self.run_smart_contract(engine, path_zneo, 'balanceOf', amm_address)
        balance_amm_zgas_after = self.run_smart_contract(engine, path_zgas, 'balanceOf', amm_address)

        self.assertEqual(total_supply_before, total_supply_after)
        self.assertEqual(reserves_before[0] - swapped_zneo, reserves_after[0])
        self.assertEqual(reserves_before[1] + swapped_zgas, reserves_after[1])
        self.assertEqual(balance_user_zneo_before + swapped_zneo, balance_user_zneo_after)
        self.assertEqual(balance_user_zgas_before - swapped_zgas, balance_user_zgas_after)
        self.assertEqual(reserves_before[0], balance_amm_zneo_before)
        self.assertEqual(reserves_before[1], balance_amm_zgas_before)
        self.assertEqual(reserves_after[0], balance_amm_zneo_after)
        self.assertEqual(reserves_after[1], balance_amm_zgas_after)
        self.assertEqual(reserves_before[0] - swapped_zneo, reserves_after[0])
        self.assertEqual(reserves_before[1] + swapped_zgas, reserves_after[1])
Exemple #24
0
class TestTemplate(BoaTest):
    default_folder: str = 'examples'

    OWNER_SCRIPT_HASH = bytes(20)
    OTHER_ACCOUNT_1 = to_script_hash(b'NiNmXL8FjEUEs1nfX9uHFBNaenxDHJtmuB')
    OTHER_ACCOUNT_2 = bytes(range(20))

    KYC_WHITELIST_PREFIX = b'KYCWhitelistApproved'

    def test_ico_compile(self):
        path = self.get_contract_path('ico.py')
        Boa3.compile(path)

    def test_ico_verify(self):
        path = self.get_contract_path('ico.py')
        engine = TestEngine()

        result = self.run_smart_contract(
            engine, path, 'verify', signer_accounts=[self.OTHER_ACCOUNT_1])
        self.assertEqual(False, result)

        result = self.run_smart_contract(
            engine, path, 'verify', signer_accounts=[self.OWNER_SCRIPT_HASH])
        self.assertEqual(True, result)

    def test_ico_total_supply(self):
        path = self.get_contract_path('ico.py')
        engine = TestEngine()
        total_supply = 10_000_000 * 10**8

        result = self.run_smart_contract(
            engine,
            path,
            'totalSupply',
            signer_accounts=[self.OWNER_SCRIPT_HASH])
        self.assertEqual(total_supply, result)

    def test_ico_symbol(self):
        path = self.get_contract_path('ico.py')
        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'symbol')
        self.assertEqual('ICO', result)

    def test_ico_decimals(self):
        path = self.get_contract_path('ico.py')
        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'decimals')
        self.assertEqual(8, result)

    def test_ico_total_balance_of(self):
        total_supply = 10_000_000 * 10**8

        path = self.get_contract_path('ico.py')
        engine = TestEngine()

        result = self.run_smart_contract(engine, path, 'balanceOf',
                                         self.OWNER_SCRIPT_HASH)
        self.assertEqual(total_supply, result)

        # should fail when the script length is not 20
        with self.assertRaises(TestExecutionException,
                               msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path, 'balanceOf', bytes(10))
        with self.assertRaises(TestExecutionException,
                               msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path, 'balanceOf', bytes(30))

    def test_ico_kyc_register(self):
        path = self.get_contract_path('ico.py')
        engine = TestEngine()

        # don't include if not signed by the administrator
        result = self.run_smart_contract(
            engine, path, 'kyc_register',
            [self.OWNER_SCRIPT_HASH, bytes(22)])
        self.assertEqual(0, result)

        # don't include script hashes with size different than 20
        result = self.run_smart_contract(
            engine,
            path,
            'kyc_register', [bytes(40), self.OWNER_SCRIPT_HASH,
                             bytes(12)],
            signer_accounts=[self.OWNER_SCRIPT_HASH])
        self.assertEqual(1, result)
        storage_value = engine.storage_get(
            self.KYC_WHITELIST_PREFIX + self.OWNER_SCRIPT_HASH, path)
        self.assertIsNotNone(storage_value)

        # script hashes already registered are returned as well
        result = self.run_smart_contract(
            engine,
            path,
            'kyc_register', [self.OWNER_SCRIPT_HASH, self.OTHER_ACCOUNT_1],
            signer_accounts=[self.OWNER_SCRIPT_HASH])
        self.assertEqual(2, result)
        storage_value = engine.storage_get(
            self.KYC_WHITELIST_PREFIX + self.OTHER_ACCOUNT_1, path)
        self.assertIsNotNone(storage_value)

    def test_ico_kyc_remove(self):
        path = self.get_contract_path('ico.py')
        engine = TestEngine()

        # don't remove if not signed by the administrator
        result = self.run_smart_contract(
            engine, path, 'kyc_remove',
            [self.OWNER_SCRIPT_HASH, bytes(22)])
        self.assertEqual(0, result)

        # script hashes that weren't registered are returned as well
        self.assertTrue(self.KYC_WHITELIST_PREFIX +
                        self.OTHER_ACCOUNT_1 not in engine.storage)
        result = self.run_smart_contract(
            engine,
            path,
            'kyc_remove', [self.OTHER_ACCOUNT_1],
            signer_accounts=[self.OWNER_SCRIPT_HASH])
        self.assertEqual(1, result)
        self.assertTrue(self.KYC_WHITELIST_PREFIX +
                        self.OTHER_ACCOUNT_1 not in engine.storage)

        # don't include script hashes with size different than 20
        result = self.run_smart_contract(
            engine,
            path,
            'kyc_remove', [bytes(40), self.OWNER_SCRIPT_HASH,
                           bytes(12)],
            signer_accounts=[self.OWNER_SCRIPT_HASH])
        self.assertEqual(1, result)

    def test_ico_approve(self):
        path = self.get_contract_path('ico.py')
        engine = TestEngine()

        approved_amount = 100 * 10**8

        # should fail when any of the scripts' length is not 20
        with self.assertRaises(TestExecutionException,
                               msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine,
                                    path, 'approve', self.OWNER_SCRIPT_HASH,
                                    bytes(10), approved_amount)
        with self.assertRaises(TestExecutionException,
                               msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path, 'approve', bytes(10),
                                    self.OTHER_ACCOUNT_1, approved_amount)

        # should fail when the amount is less than 0
        with self.assertRaises(TestExecutionException,
                               msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path, 'approve',
                                    self.OTHER_ACCOUNT_1,
                                    self.OWNER_SCRIPT_HASH, -10)

        # should fail if the origin doesn't sign
        result = self.run_smart_contract(engine, path, 'approve',
                                         self.OWNER_SCRIPT_HASH,
                                         self.OTHER_ACCOUNT_1, approved_amount)
        self.assertEqual(False, result)

        # should fail if origin and target are the same
        result = self.run_smart_contract(
            engine,
            path,
            'approve',
            self.OWNER_SCRIPT_HASH,
            self.OWNER_SCRIPT_HASH,
            approved_amount,
            signer_accounts=[self.OWNER_SCRIPT_HASH])
        self.assertEqual(False, result)

        # should fail if any of the addresses is not included in the kyc
        result = self.run_smart_contract(
            engine,
            path,
            'approve',
            self.OWNER_SCRIPT_HASH,
            self.OTHER_ACCOUNT_1,
            approved_amount,
            signer_accounts=[self.OWNER_SCRIPT_HASH])
        self.assertEqual(False, result)

        result = self.run_smart_contract(
            engine,
            path,
            'kyc_register', [self.OWNER_SCRIPT_HASH, self.OTHER_ACCOUNT_1],
            signer_accounts=[self.OWNER_SCRIPT_HASH])
        self.assertEqual(2, result)

        result = self.run_smart_contract(
            engine,
            path,
            'approve',
            self.OWNER_SCRIPT_HASH,
            self.OTHER_ACCOUNT_1,
            approved_amount,
            signer_accounts=[self.OWNER_SCRIPT_HASH])
        self.assertEqual(True, result)

    def test_ico_allowance(self):
        path = self.get_contract_path('ico.py')
        engine = TestEngine()

        approved_amount = 100 * 10**8

        result = self.run_smart_contract(engine, path, 'allowance',
                                         self.OWNER_SCRIPT_HASH,
                                         self.OTHER_ACCOUNT_1)
        self.assertEqual(0, result)

        result = self.run_smart_contract(
            engine,
            path,
            'kyc_register', [self.OWNER_SCRIPT_HASH, self.OTHER_ACCOUNT_1],
            signer_accounts=[self.OWNER_SCRIPT_HASH])
        self.assertEqual(2, result)

        result = self.run_smart_contract(
            engine,
            path,
            'approve',
            self.OWNER_SCRIPT_HASH,
            self.OTHER_ACCOUNT_1,
            approved_amount,
            signer_accounts=[self.OWNER_SCRIPT_HASH])
        self.assertEqual(True, result)

        result = self.run_smart_contract(engine, path, 'allowance',
                                         self.OWNER_SCRIPT_HASH,
                                         self.OTHER_ACCOUNT_1)
        self.assertEqual(approved_amount, result)

    def test_ico_transfer_from(self):
        path = self.get_contract_path('ico.py')
        engine = TestEngine()

        transferred_amount = 100 * 10**8

        # should fail when any of the scripts' length is not 20
        with self.assertRaises(TestExecutionException,
                               msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path,
                                    'transferFrom', self.OWNER_SCRIPT_HASH,
                                    bytes(10), self.OTHER_ACCOUNT_2,
                                    transferred_amount, None)
        with self.assertRaises(TestExecutionException,
                               msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path, 'transferFrom', bytes(10),
                                    self.OTHER_ACCOUNT_1, self.OTHER_ACCOUNT_2,
                                    transferred_amount, None)
        with self.assertRaises(TestExecutionException,
                               msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path, 'transferFrom',
                                    self.OWNER_SCRIPT_HASH,
                                    self.OTHER_ACCOUNT_1, bytes(30),
                                    transferred_amount, None)

        # should fail when the amount is less than 0
        with self.assertRaises(TestExecutionException,
                               msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path, 'transferFrom',
                                    self.OWNER_SCRIPT_HASH,
                                    self.OTHER_ACCOUNT_1, self.OTHER_ACCOUNT_2,
                                    -10, None)

        # should fail if the sender doesn't sign
        result = self.run_smart_contract(engine, path, 'transferFrom',
                                         self.OWNER_SCRIPT_HASH,
                                         self.OTHER_ACCOUNT_1,
                                         self.OTHER_ACCOUNT_2,
                                         transferred_amount, None)
        self.assertEqual(False, result)

        # should fail if the allowed amount is less than the given amount
        result = self.run_smart_contract(
            engine,
            path,
            'transferFrom',
            self.OWNER_SCRIPT_HASH,
            self.OTHER_ACCOUNT_1,
            self.OTHER_ACCOUNT_2,
            transferred_amount,
            None,
            signer_accounts=[self.OTHER_ACCOUNT_1])
        self.assertEqual(False, result)

        result = self.run_smart_contract(
            engine,
            path,
            'kyc_register', [self.OWNER_SCRIPT_HASH, self.OTHER_ACCOUNT_1],
            signer_accounts=[self.OWNER_SCRIPT_HASH])
        self.assertEqual(2, result)

        result = self.run_smart_contract(
            engine,
            path,
            'approve',
            self.OWNER_SCRIPT_HASH,
            self.OTHER_ACCOUNT_1,
            transferred_amount * 2,
            signer_accounts=[self.OWNER_SCRIPT_HASH])
        self.assertEqual(True, result)

        # doesn't fire the transfer event when transferring to yourself or amount is zero
        balance_before = self.run_smart_contract(engine, path, 'balanceOf',
                                                 self.OWNER_SCRIPT_HASH)
        result = self.run_smart_contract(
            engine,
            path,
            'transferFrom',
            self.OWNER_SCRIPT_HASH,
            self.OTHER_ACCOUNT_1,
            self.OWNER_SCRIPT_HASH,
            transferred_amount,
            None,
            signer_accounts=[self.OTHER_ACCOUNT_1])
        self.assertEqual(True, result)
        self.assertEqual(0, len(engine.get_events('transfer')))
        balance_after = self.run_smart_contract(engine, path, 'balanceOf',
                                                self.OWNER_SCRIPT_HASH)
        self.assertEqual(balance_after, balance_before)

        balance_before = self.run_smart_contract(engine, path, 'balanceOf',
                                                 self.OTHER_ACCOUNT_1)
        result = self.run_smart_contract(
            engine,
            path,
            'transferFrom',
            self.OWNER_SCRIPT_HASH,
            self.OTHER_ACCOUNT_1,
            self.OTHER_ACCOUNT_1,
            transferred_amount,
            None,
            signer_accounts=[self.OTHER_ACCOUNT_1])
        self.assertEqual(True, result)
        self.assertEqual(0, len(engine.get_events('transfer')))
        balance_after = self.run_smart_contract(engine, path, 'balanceOf',
                                                self.OTHER_ACCOUNT_1)
        self.assertEqual(balance_after, balance_before)

        result = self.run_smart_contract(
            engine,
            path,
            'transferFrom',
            self.OWNER_SCRIPT_HASH,
            self.OTHER_ACCOUNT_1,
            self.OTHER_ACCOUNT_2,
            0,
            None,
            signer_accounts=[self.OTHER_ACCOUNT_1])
        self.assertEqual(True, result)
        self.assertEqual(0, len(engine.get_events('transfer')))

        balance_originator_before = self.run_smart_contract(
            engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH)
        balance_sender_before = self.run_smart_contract(
            engine, path, 'balanceOf', self.OTHER_ACCOUNT_1)
        balance_receiver_before = self.run_smart_contract(
            engine, path, 'balanceOf', self.OTHER_ACCOUNT_2)
        result = self.run_smart_contract(
            engine,
            path,
            'transferFrom',
            self.OWNER_SCRIPT_HASH,
            self.OTHER_ACCOUNT_1,
            self.OTHER_ACCOUNT_2,
            transferred_amount,
            None,
            signer_accounts=[self.OTHER_ACCOUNT_1])
        self.assertEqual(False, result)

        balance_originator_after = self.run_smart_contract(
            engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH)
        self.assertEqual(balance_originator_before, balance_originator_after)
        balance_sender_after = self.run_smart_contract(engine, path,
                                                       'balanceOf',
                                                       self.OTHER_ACCOUNT_1)
        self.assertEqual(balance_sender_before, balance_sender_after)
        balance_receiver_after = self.run_smart_contract(
            engine, path, 'balanceOf', self.OTHER_ACCOUNT_2)
        self.assertEqual(balance_receiver_before, balance_receiver_after)

    def test_ico_mint(self):
        path = self.get_contract_path('ico.py')
        engine = TestEngine()

        # should fail if amount is a negative number
        with self.assertRaises(TestExecutionException,
                               msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path, 'mint', -10 * 10**8)

        minted_amount = 10_000 * 10**8
        # should fail if not signed by the administrator
        result = self.run_smart_contract(engine, path, 'mint', minted_amount)
        self.assertEqual(False, result)

        total_supply_before = self.run_smart_contract(engine, path,
                                                      'totalSupply')
        owner_balance_before = self.run_smart_contract(engine, path,
                                                       'balanceOf',
                                                       self.OWNER_SCRIPT_HASH)

        result = self.run_smart_contract(
            engine,
            path,
            'mint',
            minted_amount,
            signer_accounts=[self.OWNER_SCRIPT_HASH])
        self.assertEqual(True, result)

        total_supply_after = self.run_smart_contract(engine, path,
                                                     'totalSupply')
        self.assertEqual(total_supply_before + minted_amount,
                         total_supply_after)
        owner_balance_after = self.run_smart_contract(engine, path,
                                                      'balanceOf',
                                                      self.OWNER_SCRIPT_HASH)
        self.assertEqual(owner_balance_before + minted_amount,
                         owner_balance_after)

    def test_ico_refund(self):
        path = self.get_contract_path('ico.py')
        engine = TestEngine()
        transferred_amount = 10_000

        # should fail script hash length is not 20
        with self.assertRaises(TestExecutionException,
                               msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path, 'refund', bytes(10),
                                    transferred_amount, transferred_amount)

        # should fail no amount is a positive number
        with self.assertRaises(TestExecutionException,
                               msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path, 'refund',
                                    self.OWNER_SCRIPT_HASH, 0, 0)

        # should fail if not signed by the owner
        result = self.run_smart_contract(engine, path, 'refund',
                                         self.OWNER_SCRIPT_HASH,
                                         transferred_amount,
                                         transferred_amount)
        self.assertEqual(False, result)
Exemple #25
0
 def test_script_hash(self):
     script = self.test_script
     nef = self.create_test_nef(script)
     self.assertEqual(len(nef.script_hash), 20)
     self.assertEqual(nef.script_hash, to_script_hash(script))
Exemple #26
0
class TestTemplate(BoaTest):
    default_folder: str = 'examples'

    OWNER_SCRIPT_HASH = bytes(20)
    OTHER_ACCOUNT_1 = to_script_hash(b'NiNmXL8FjEUEs1nfX9uHFBNaenxDHJtmuB')

    def test_nep5_compile(self):
        path = self.get_contract_path('nep5.py')
        Boa3.compile(path)

    def test_nep5_name(self):
        path = self.get_contract_path('nep5.py')
        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'name')
        self.assertEqual('NEP5 Standard', result)

    def test_nep5_symbol(self):
        path = self.get_contract_path('nep5.py')
        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'symbol')
        self.assertEqual('NEP5', result)

    def test_nep5_decimals(self):
        path = self.get_contract_path('nep5.py')
        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'decimals')
        self.assertEqual(8, result)

    def test_nep5_total_supply(self):
        total_supply = 10_000_000 * 10**8

        path = self.get_contract_path('nep5.py')
        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'totalSupply')
        self.assertEqual(total_supply, result)

    def test_nep5_total_balance_of(self):
        total_supply = 10_000_000 * 10**8

        path = self.get_contract_path('nep5.py')
        engine = TestEngine()

        result = self.run_smart_contract(engine, path, 'balanceOf',
                                         self.OWNER_SCRIPT_HASH)
        self.assertEqual(total_supply, result)

        # should fail when the script length is not 20
        with self.assertRaises(TestExecutionException,
                               msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path, 'balanceOf', bytes(10))
        with self.assertRaises(TestExecutionException,
                               msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path, 'balanceOf', bytes(30))

    def test_nep5_total_transfer(self):
        transferred_amount = 10 * 10**8  # 10 tokens

        path = self.get_contract_path('nep5.py')
        engine = TestEngine()

        # should fail if the sender doesn't sign
        result = self.run_smart_contract(engine, path, 'transfer',
                                         self.OWNER_SCRIPT_HASH,
                                         self.OTHER_ACCOUNT_1,
                                         transferred_amount)
        self.assertEqual(False, result)

        # other account doesn't have enough balance
        result = self.run_smart_contract(
            engine,
            path,
            'transfer',
            self.OTHER_ACCOUNT_1,
            self.OWNER_SCRIPT_HASH,
            transferred_amount,
            signer_accounts=[self.OTHER_ACCOUNT_1])
        self.assertEqual(False, result)

        # should fail when any of the scripts' length is not 20
        with self.assertRaises(TestExecutionException,
                               msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path,
                                    'transfer', self.OWNER_SCRIPT_HASH,
                                    bytes(10), transferred_amount)
        with self.assertRaises(TestExecutionException,
                               msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path, 'transfer', bytes(10),
                                    self.OTHER_ACCOUNT_1, transferred_amount)

        # should fail when the amount is less than 0
        with self.assertRaises(TestExecutionException,
                               msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path, 'transfer',
                                    self.OTHER_ACCOUNT_1,
                                    self.OWNER_SCRIPT_HASH, -10)

        # doesn't fire the transfer event when transferring to yourself
        balance_before = self.run_smart_contract(engine, path, 'balanceOf',
                                                 self.OWNER_SCRIPT_HASH)
        result = self.run_smart_contract(
            engine,
            path,
            'transfer',
            self.OWNER_SCRIPT_HASH,
            self.OWNER_SCRIPT_HASH,
            transferred_amount,
            signer_accounts=[self.OWNER_SCRIPT_HASH])
        self.assertEqual(True, result)
        transfer_events = engine.get_events('transfer')
        # there is one transfer event thanks to the deploy
        self.assertEqual(1, len(transfer_events))

        # transferring to yourself doesn't change the balance
        balance_after = self.run_smart_contract(engine, path, 'balanceOf',
                                                self.OWNER_SCRIPT_HASH)
        self.assertEqual(balance_before, balance_after)

        # doesn't fire the transfer event when transferring to yourself
        balance_sender_before = self.run_smart_contract(
            engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH)
        balance_receiver_before = self.run_smart_contract(
            engine, path, 'balanceOf', self.OTHER_ACCOUNT_1)
        result = self.run_smart_contract(
            engine,
            path,
            'transfer',
            self.OWNER_SCRIPT_HASH,
            self.OTHER_ACCOUNT_1,
            transferred_amount,
            signer_accounts=[self.OWNER_SCRIPT_HASH])
        self.assertEqual(True, result)
        transfer_events = engine.get_events('transfer')
        self.assertEqual(2, len(transfer_events))
        self.assertEqual(3, len(transfer_events[1].arguments))

        sender, receiver, amount = transfer_events[1].arguments
        if isinstance(sender, str):
            sender = String(sender).to_bytes()
        if isinstance(receiver, str):
            receiver = String(sender).to_bytes()
        self.assertEqual(self.OWNER_SCRIPT_HASH, sender)
        self.assertEqual(self.OTHER_ACCOUNT_1, receiver)
        self.assertEqual(transferred_amount, amount)

        # transferring to yourself doesn't change the balance
        balance_sender_after = self.run_smart_contract(engine, path,
                                                       'balanceOf',
                                                       self.OWNER_SCRIPT_HASH)
        balance_receiver_after = self.run_smart_contract(
            engine, path, 'balanceOf', self.OTHER_ACCOUNT_1)
        self.assertEqual(balance_sender_before - transferred_amount,
                         balance_sender_after)
        self.assertEqual(balance_receiver_before + transferred_amount,
                         balance_receiver_after)

    def test_nep5_verify(self):
        path = self.get_contract_path('nep5.py')
        engine = TestEngine()

        # should fail without signature
        result = self.run_smart_contract(engine, path, 'verify')
        self.assertEqual(False, result)

        # should fail if not signed by the owner
        result = self.run_smart_contract(
            engine, path, 'verify', signer_accounts=[self.OTHER_ACCOUNT_1])
        self.assertEqual(False, result)

        result = self.run_smart_contract(
            engine, path, 'verify', signer_accounts=[self.OWNER_SCRIPT_HASH])
        self.assertEqual(True, result)
Exemple #27
0
class TestNEP17Template(BoaTest):
    default_folder: str = 'examples'

    OWNER_SCRIPT_HASH = bytes(20)
    OTHER_ACCOUNT_1 = to_script_hash(b'NiNmXL8FjEUEs1nfX9uHFBNaenxDHJtmuB')
    OTHER_ACCOUNT_2 = bytes(range(20))

    def test_nep17_compile(self):
        path = self.get_contract_path('nep17.py')
        output, manifest = self.compile_and_save(path)

        self.assertIn('supportedstandards', manifest)
        self.assertIsInstance(manifest['supportedstandards'], list)
        self.assertGreater(len(manifest['supportedstandards']), 0)
        self.assertIn('NEP-17', manifest['supportedstandards'])

    def test_nep17_symbol(self):
        path = self.get_contract_path('nep17.py')
        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'symbol')
        self.assertEqual('NEP17', result)

    def test_nep17_decimals(self):
        path = self.get_contract_path('nep17.py')
        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'decimals')
        self.assertEqual(8, result)

    def test_nep17_total_supply(self):
        total_supply = 10_000_000 * 10 ** 8

        path = self.get_contract_path('nep17.py')
        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'totalSupply')
        self.assertEqual(total_supply, result)

    def test_nep17_total_balance_of(self):
        total_supply = 10_000_000 * 10 ** 8

        path = self.get_contract_path('nep17.py')
        engine = TestEngine()

        result = self.run_smart_contract(engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH)
        self.assertEqual(total_supply, result)

        # should fail when the script length is not 20
        with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path, 'balanceOf', bytes(10))
        with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path, 'balanceOf', bytes(30))

    def test_nep17_total_transfer(self):
        transferred_amount = 10 * 10 ** 8  # 10 tokens

        path = self.get_contract_path('nep17.py')
        engine = TestEngine()

        # should fail if the sender doesn't sign
        result = self.run_smart_contract(engine, path, 'transfer',
                                         self.OWNER_SCRIPT_HASH, self.OTHER_ACCOUNT_1, transferred_amount, None)
        self.assertEqual(False, result)

        # should fail if the sender doesn't have enough balance
        result = self.run_smart_contract(engine, path, 'transfer',
                                         self.OTHER_ACCOUNT_1, self.OWNER_SCRIPT_HASH, transferred_amount, None,
                                         signer_accounts=[self.OTHER_ACCOUNT_1])
        self.assertEqual(False, result)

        # should fail when any of the scripts' length is not 20
        with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path, 'transfer',
                                    self.OWNER_SCRIPT_HASH, bytes(10), transferred_amount, "")
        with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path, 'transfer',
                                    bytes(10), self.OTHER_ACCOUNT_1, transferred_amount, "")

        # should fail when the amount is less than 0
        with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG):
            self.run_smart_contract(engine, path, 'transfer',
                                    self.OTHER_ACCOUNT_1, self.OWNER_SCRIPT_HASH, -10, None)

        # fire the transfer event when transferring to yourself
        balance_before = self.run_smart_contract(engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH)
        result = self.run_smart_contract(engine, path, 'transfer',
                                         self.OWNER_SCRIPT_HASH, self.OWNER_SCRIPT_HASH, transferred_amount, None,
                                         signer_accounts=[self.OWNER_SCRIPT_HASH])
        self.assertEqual(True, result)
        transfer_events = engine.get_events('Transfer')
        self.assertEqual(2, len(transfer_events))
        self.assertEqual(3, len(transfer_events[1].arguments))

        sender, receiver, amount = transfer_events[1].arguments
        if isinstance(sender, str):
            sender = String(sender).to_bytes()
        if isinstance(receiver, str):
            receiver = String(receiver).to_bytes()
        self.assertEqual(self.OWNER_SCRIPT_HASH, sender)
        self.assertEqual(self.OWNER_SCRIPT_HASH, receiver)
        self.assertEqual(transferred_amount, amount)

        # transferring to yourself doesn't change the balance
        balance_after = self.run_smart_contract(engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH)
        self.assertEqual(balance_before, balance_after)

        # does fire the transfer event
        balance_sender_before = self.run_smart_contract(engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH)
        balance_receiver_before = self.run_smart_contract(engine, path, 'balanceOf', self.OTHER_ACCOUNT_1)
        result = self.run_smart_contract(engine, path, 'transfer',
                                         self.OWNER_SCRIPT_HASH, self.OTHER_ACCOUNT_1, transferred_amount, None,
                                         signer_accounts=[self.OWNER_SCRIPT_HASH])
        self.assertEqual(True, result)
        transfer_events = engine.get_events('Transfer')
        self.assertEqual(3, len(transfer_events))
        self.assertEqual(3, len(transfer_events[2].arguments))

        sender, receiver, amount = transfer_events[2].arguments
        if isinstance(sender, str):
            sender = String(sender).to_bytes()
        if isinstance(receiver, str):
            receiver = String(receiver).to_bytes()
        self.assertEqual(self.OWNER_SCRIPT_HASH, sender)
        self.assertEqual(self.OTHER_ACCOUNT_1, receiver)
        self.assertEqual(transferred_amount, amount)

        # transferring to someone other than yourself does change the balance
        balance_sender_after = self.run_smart_contract(engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH)
        balance_receiver_after = self.run_smart_contract(engine, path, 'balanceOf', self.OTHER_ACCOUNT_1)
        self.assertEqual(balance_sender_before - transferred_amount, balance_sender_after)
        self.assertEqual(balance_receiver_before + transferred_amount, balance_receiver_after)

    def test_nep17_on_nep17_payment(self):
        transferred_amount = 10 * 10 ** 8  # 10 tokens

        path = self.get_contract_path('nep17.py')
        engine = TestEngine()

        self.run_smart_contract(engine, path, 'symbol')
        nep17_address = engine.executed_script_hash.to_array()

        aux_path = self.get_contract_path('examples/auxiliary_contracts', 'auxiliary_contract.py')
        self.run_smart_contract(engine, aux_path, 'get_name')
        aux_address = engine.executed_script_hash.to_array()

        engine = TestEngine()
        engine.add_contract(path.replace('.py', '.nef'))

        engine.add_neo(aux_address, transferred_amount)
        engine.add_gas(aux_address, transferred_amount)

        # transferring NEO to the smart contract
        # saving the balance before the transfer to be able to compare after it
        neo_balance_sender_before = self.run_smart_contract(engine, constants.NEO_SCRIPT, 'balanceOf', aux_address)
        neo_balance_nep17_before = self.run_smart_contract(engine, constants.NEO_SCRIPT, 'balanceOf', nep17_address)
        nep17_balance_sender_before = self.run_smart_contract(engine, path, 'balanceOf', aux_address)

        result = self.run_smart_contract(engine, aux_path, 'calling_transfer', constants.NEO_SCRIPT,
                                         aux_address, nep17_address, transferred_amount, None,
                                         signer_accounts=[aux_address])
        self.assertEqual(True, result)
        transfer_events = engine.get_events('Transfer')
        self.assertEqual(4, len(transfer_events))
        neo_transfer_event = transfer_events[1]
        transfer_event = transfer_events[2]
        self.assertEqual(3, len(neo_transfer_event.arguments))
        self.assertEqual(3, len(transfer_event.arguments))

        # this is the event NEO emitted
        sender, receiver, amount = neo_transfer_event.arguments
        if isinstance(sender, str):
            sender = String(sender).to_bytes()
        if isinstance(receiver, str):
            receiver = String(receiver).to_bytes()
        self.assertEqual(aux_address, sender)
        self.assertEqual(nep17_address, receiver)
        self.assertEqual(transferred_amount, amount)

        # this is the event NEP17 emitted
        sender, receiver, amount = transfer_event.arguments
        if isinstance(sender, str):
            sender = String(sender).to_bytes()
        if isinstance(receiver, str):
            receiver = String(receiver).to_bytes()
        self.assertEqual(None, sender)
        self.assertEqual(aux_address, receiver)
        # transferred_amount is multiplied by 10, because this smart contract is minting the NEO received
        self.assertEqual(transferred_amount * 10, amount)

        # saving the balance after the transfer to compare it with the previous data
        neo_balance_sender_after = self.run_smart_contract(engine, constants.NEO_SCRIPT, 'balanceOf', aux_address)
        neo_balance_nep17_after = self.run_smart_contract(engine, constants.NEO_SCRIPT, 'balanceOf', nep17_address)
        nep17_balance_sender_after = self.run_smart_contract(engine, path, 'balanceOf', aux_address)

        self.assertEqual(neo_balance_sender_before - transferred_amount, neo_balance_sender_after)
        self.assertEqual(neo_balance_nep17_before + transferred_amount, neo_balance_nep17_after)
        # transferred_amount is multiplied by 10, because this smart contract is minting the NEO received
        self.assertEqual(nep17_balance_sender_before + transferred_amount * 10, nep17_balance_sender_after)

        # transferring GAS to the smart contract
        # saving the balance before the transfer to be able to compare after it
        gas_balance_sender_before = self.run_smart_contract(engine, constants.GAS_SCRIPT, 'balanceOf', aux_address)
        gas_balance_nep17_before = self.run_smart_contract(engine, constants.GAS_SCRIPT, 'balanceOf', nep17_address)
        nep17_balance_sender_before = self.run_smart_contract(engine, path, 'balanceOf', aux_address)

        result = self.run_smart_contract(engine, aux_path, 'calling_transfer', constants.GAS_SCRIPT,
                                         aux_address, nep17_address, transferred_amount, None,
                                         signer_accounts=[aux_address])
        self.assertEqual(True, result)
        transfer_events = engine.get_events('Transfer')
        self.assertEqual(6, len(transfer_events))
        gas_transfer_event = transfer_events[4]
        transfer_event = transfer_events[5]
        self.assertEqual(3, len(gas_transfer_event.arguments))
        self.assertEqual(3, len(transfer_event.arguments))

        # this is the event GAS emitted
        sender, receiver, amount = gas_transfer_event.arguments
        if isinstance(sender, str):
            sender = String(sender).to_bytes()
        if isinstance(receiver, str):
            receiver = String(receiver).to_bytes()
        self.assertEqual(aux_address, sender)
        self.assertEqual(nep17_address, receiver)
        self.assertEqual(transferred_amount, amount)

        # this is the event NEP17 emitted
        sender, receiver, amount = transfer_event.arguments
        if isinstance(sender, str):
            sender = String(sender).to_bytes()
        if isinstance(receiver, str):
            receiver = String(receiver).to_bytes()
        self.assertEqual(None, sender)
        self.assertEqual(aux_address, receiver)
        # transferred_amount is multiplied by 2, because this smart contract is minting the GAS received
        self.assertEqual(transferred_amount * 2, amount)

        # saving the balance after the transfer to compare it with the previous data
        gas_balance_sender_after = self.run_smart_contract(engine, constants.GAS_SCRIPT, 'balanceOf', aux_address)
        gas_balance_nep17_after = self.run_smart_contract(engine, constants.GAS_SCRIPT, 'balanceOf', nep17_address)
        nep17_balance_sender_after = self.run_smart_contract(engine, path, 'balanceOf', aux_address)

        self.assertEqual(gas_balance_sender_before - transferred_amount, gas_balance_sender_after)
        self.assertEqual(gas_balance_nep17_before + transferred_amount, gas_balance_nep17_after)
        # transferred_amount is multiplied by 2, because this smart contract is minting the GAS received
        self.assertEqual(nep17_balance_sender_before + transferred_amount * 2, nep17_balance_sender_after)

        # trying to call onNEP17Transfer() will result in an abort if the one calling it is not NEO or GAS contracts
        with self.assertRaises(TestExecutionException, msg=self.ABORTED_CONTRACT_MSG):
            self.run_smart_contract(engine, path, 'onNEP17Transfer',
                                    self.OWNER_SCRIPT_HASH, transferred_amount, None)

    def test_nep17_verify(self):
        path = self.get_contract_path('nep17.py')
        engine = TestEngine()

        # should fail without signature
        result = self.run_smart_contract(engine, path, 'verify')
        self.assertEqual(False, result)

        # should fail if not signed by the owner
        result = self.run_smart_contract(engine, path, 'verify',
                                         signer_accounts=[self.OTHER_ACCOUNT_1])
        self.assertEqual(False, result)

        result = self.run_smart_contract(engine, path, 'verify',
                                         signer_accounts=[self.OWNER_SCRIPT_HASH])
        self.assertEqual(True, result)