Exemplo n.º 1
0
    def storage_delete(self, key: Union[str, bytes]):
        if isinstance(key, str):
            key = String(key).to_bytes()

        if key in self._storage:
            self._storage.pop(key)
Exemplo n.º 2
0
    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

        self.run_smart_contract(engine, path, 'refund')
        htlc_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()

        aux_path2 = self.get_contract_path('examples/auxiliary_contracts',
                                           'auxiliary_contract_2.py')
        self.run_smart_contract(engine, aux_path2, 'get_name')
        aux_address2 = engine.executed_script_hash.to_array()

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

        # saving the balance to compare after the withdraw
        balance_neo_person_a_before = self.run_smart_contract(
            engine, constants.NEO_SCRIPT, 'balanceOf', aux_address)
        balance_neo_person_b_before = self.run_smart_contract(
            engine, constants.NEO_SCRIPT, 'balanceOf', aux_address2)
        balance_neo_htlc_before = self.run_smart_contract(
            engine, constants.NEO_SCRIPT, 'balanceOf', htlc_address)
        balance_gas_person_a_before = self.run_smart_contract(
            engine, constants.GAS_SCRIPT, 'balanceOf', aux_address)
        balance_gas_person_b_before = self.run_smart_contract(
            engine, constants.GAS_SCRIPT, 'balanceOf', aux_address2)
        balance_gas_htlc_before = self.run_smart_contract(
            engine, constants.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,
            constants.NEO_SCRIPT,
            transferred_amount_neo,
            aux_address2,
            constants.GAS_SCRIPT,
            transferred_amount_gas,
            hash160(String('unit test').to_bytes()),
            signer_accounts=[self.OWNER_SCRIPT_HASH])
        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])
        self.assertEqual(False, result)

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

        result = self.run_smart_contract(engine,
                                         aux_path2,
                                         'calling_transfer',
                                         constants.GAS_SCRIPT,
                                         aux_address2,
                                         htlc_address,
                                         transferred_amount_gas,
                                         None,
                                         signer_accounts=[aux_address2])
        self.assertEqual(True, result)
        transfer_events = engine.get_events('Transfer', constants.GAS_SCRIPT)
        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])
        self.assertEqual(False, result)

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

        # the transfer were accepted so they were registered
        transfer_events = engine.get_events('Transfer',
                                            origin=constants.GAS_SCRIPT)
        self.assertGreaterEqual(len(transfer_events), 1)
        gas_transfer_event = transfer_events[-1]
        self.assertEqual(3, len(gas_transfer_event.arguments))

        transfer_events = engine.get_events('Transfer', constants.NEO_SCRIPT)
        self.assertGreaterEqual(len(transfer_events), 1)
        neo_transfer_event = transfer_events[-1]
        self.assertEqual(3, len(neo_transfer_event.arguments))

        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(htlc_address, sender)
        self.assertEqual(aux_address, receiver)
        self.assertEqual(transferred_amount_gas, amount)

        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(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
        minted_gas_per_neo_transfer = int(transferred_amount_neo * 0.5)
        balance_neo_person_a_after = self.run_smart_contract(
            engine, constants.NEO_SCRIPT, 'balanceOf', aux_address)
        balance_neo_person_b_after = self.run_smart_contract(
            engine, constants.NEO_SCRIPT, 'balanceOf', aux_address2)
        balance_neo_htlc_after = self.run_smart_contract(
            engine, constants.NEO_SCRIPT, 'balanceOf', htlc_address)
        balance_gas_person_a_after = self.run_smart_contract(
            engine, constants.GAS_SCRIPT, 'balanceOf', aux_address)
        balance_gas_person_b_after = self.run_smart_contract(
            engine, constants.GAS_SCRIPT, 'balanceOf', aux_address2)
        balance_gas_htlc_after = self.run_smart_contract(
            engine, constants.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 +
            minted_gas_per_neo_transfer, 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)
Exemplo n.º 3
0
class TestException(BoaTest):

    EXCEPTION_EMPTY_MESSAGE = String(Builtin.Exception.default_message).to_bytes()

    def test_raise_exception_empty_message(self):
        expected_output = (
            Opcode.INITSLOT     # function signature
            + b'\x00'
            + b'\x01'
            + Opcode.LDARG0     # if arg0 < 0
            + Opcode.PUSH0
            + Opcode.LT
            + Opcode.JMPIFNOT
            + Integer(14).to_byte_array(signed=True, min_length=1)
            + Opcode.PUSHDATA1      # raise Exception
            + Integer(len(self.EXCEPTION_EMPTY_MESSAGE)).to_byte_array(signed=True, min_length=1)
            + self.EXCEPTION_EMPTY_MESSAGE
            + Opcode.THROW
            + Opcode.PUSHNULL
            + Opcode.RET
        )

        path = '%s/boa3_test/test_sc/exception_test/RaiseExceptionEmptyMessage.py' % self.dirname
        output = Boa3.compile(path)
        self.assertEqual(expected_output, output)

        engine = TestEngine(self.dirname)
        self.run_smart_contract(engine, path, 'test_raise', 10)

        with self.assertRaises(TestExecutionException, msg=self.EXCEPTION_EMPTY_MESSAGE):
            self.run_smart_contract(engine, path, 'test_raise', -10)

    def test_raise_exception_with_message(self):
        exception_message = String('raised an exception').to_bytes()
        expected_output = (
            Opcode.INITSLOT     # function signature
            + b'\x00'
            + b'\x01'
            + Opcode.LDARG0     # if arg0 < 0
            + Opcode.PUSH0
            + Opcode.LT
            + Opcode.JMPIFNOT
            + Integer(24).to_byte_array(signed=True, min_length=1)
            + Opcode.PUSHDATA1      # raise Exception('raised an exception')
            + Integer(len(exception_message)).to_byte_array(signed=True, min_length=1)
            + exception_message
            + Opcode.THROW
            + Opcode.PUSHNULL
            + Opcode.RET
        )

        path = '%s/boa3_test/test_sc/exception_test/RaiseExceptionWithMessage.py' % self.dirname
        output = Boa3.compile(path)
        self.assertEqual(expected_output, output)

        engine = TestEngine(self.dirname)
        self.run_smart_contract(engine, path, 'test_raise', 10)

        with self.assertRaises(TestExecutionException, msg=self.EXCEPTION_EMPTY_MESSAGE):
            self.run_smart_contract(engine, path, 'test_raise', -10)

    def test_raise_exception_without_call(self):
        expected_output = (
            Opcode.INITSLOT     # function signature
            + b'\x00'
            + b'\x01'
            + Opcode.LDARG0     # if arg0 < 0
            + Opcode.PUSH0
            + Opcode.LT
            + Opcode.JMPIFNOT
            + Integer(14).to_byte_array(signed=True, min_length=1)
            + Opcode.PUSHDATA1      # raise Exception
            + Integer(len(self.EXCEPTION_EMPTY_MESSAGE)).to_byte_array(signed=True, min_length=1)
            + self.EXCEPTION_EMPTY_MESSAGE
            + Opcode.THROW
            + Opcode.PUSHNULL
            + Opcode.RET
        )

        path = '%s/boa3_test/test_sc/exception_test/RaiseExceptionWithoutCall.py' % self.dirname
        output = Boa3.compile(path)
        self.assertEqual(expected_output, output)

        engine = TestEngine(self.dirname)
        self.run_smart_contract(engine, path, 'test_raise', 10)

        with self.assertRaises(TestExecutionException, msg=self.EXCEPTION_EMPTY_MESSAGE):
            self.run_smart_contract(engine, path, 'test_raise', -10)

    def test_raise_variable_exception(self):
        expected_output = (
            Opcode.INITSLOT     # function signature
            + b'\x01'
            + b'\x01'
            + Opcode.PUSHDATA1  # x = Exception
            + Integer(len(self.EXCEPTION_EMPTY_MESSAGE)).to_byte_array(signed=True, min_length=1)
            + self.EXCEPTION_EMPTY_MESSAGE
            + Opcode.STLOC0
            + Opcode.LDARG0     # if arg0 < 0
            + Opcode.PUSH0
            + Opcode.LT
            + Opcode.JMPIFNOT
            + Integer(4).to_byte_array(signed=True, min_length=1)
            + Opcode.LDLOC0         # raise x
            + Opcode.THROW
            + Opcode.PUSHNULL
            + Opcode.RET
        )

        path = '%s/boa3_test/test_sc/exception_test/RaiseVariableException.py' % self.dirname
        output = Boa3.compile(path)
        self.assertEqual(expected_output, output)

        engine = TestEngine(self.dirname)
        self.run_smart_contract(engine, path, 'test_raise', 10)

        with self.assertRaises(TestExecutionException, msg=self.EXCEPTION_EMPTY_MESSAGE):
            self.run_smart_contract(engine, path, 'test_raise', -10)

    def test_raise_exception_variable_message(self):
        message = 'raised an exception'
        exception_message = String(message).to_bytes()
        expected_output = (
            Opcode.INITSLOT     # function signature
            + b'\x01'
            + b'\x01'
            + Opcode.PUSHDATA1  # x = 'raised an exception'
            + Integer(len(exception_message)).to_byte_array(signed=True, min_length=1)
            + exception_message
            + Opcode.STLOC0
            + Opcode.LDARG0     # if arg0 < 0
            + Opcode.PUSH0
            + Opcode.LT
            + Opcode.JMPIFNOT
            + Integer(24).to_byte_array(signed=True, min_length=1)
            + Opcode.PUSHDATA1      # raise Exception(x)
            + Integer(len(exception_message)).to_byte_array(signed=True, min_length=1)
            + exception_message
            + Opcode.THROW
            + Opcode.PUSHNULL
            + Opcode.RET
        )

        path = '%s/boa3_test/test_sc/exception_test/RaiseExceptionVariableMessage.py' % self.dirname
        output = Boa3.compile(path)
        self.assertEqual(expected_output, output)

        engine = TestEngine(self.dirname)
        self.run_smart_contract(engine, path, 'test_raise', 10)

        with self.assertRaises(TestExecutionException, msg=message):
            self.run_smart_contract(engine, path, 'test_raise', -10)

    def test_raise_specific_exception(self):
        expected_output = (
            Opcode.INITSLOT     # function signature
            + b'\x00'
            + b'\x01'
            + Opcode.LDARG0     # if arg0 < 0
            + Opcode.PUSH0
            + Opcode.LT
            + Opcode.JMPIFNOT
            + Integer(14).to_byte_array(signed=True, min_length=1)
            + Opcode.PUSHDATA1      # raise ValueError
            + Integer(len(self.EXCEPTION_EMPTY_MESSAGE)).to_byte_array(signed=True, min_length=1)
            + self.EXCEPTION_EMPTY_MESSAGE
            + Opcode.THROW
            + Opcode.PUSHNULL
            + Opcode.RET
        )

        path = '%s/boa3_test/test_sc/exception_test/RaiseSpecificException.py' % self.dirname
        output = Boa3.compile(path)
        self.assertEqual(expected_output, output)

        engine = TestEngine(self.dirname)
        self.run_smart_contract(engine, path, 'test_raise', 10)

        with self.assertRaises(TestExecutionException, msg=self.EXCEPTION_EMPTY_MESSAGE):
            self.run_smart_contract(engine, path, 'test_raise', -10)

    def test_raise_mismatched_type(self):
        path = '%s/boa3_test/test_sc/exception_test/RaiseMismatchedType.py' % self.dirname
        self.assertCompilerLogs(MismatchedTypes, path)

    def test_try_except_without_exception(self):
        expected_output = (
            Opcode.INITSLOT     # function signature
            + b'\x01'
            + b'\x01'
            + Opcode.TRY        # try:
            + Integer(7).to_byte_array(signed=True, min_length=1)  # jmp to exception
            + Integer(0).to_byte_array(signed=True, min_length=1)  # jmp to finally if exists
            + Opcode.LDARG0         # x = arg
            + Opcode.STLOC0
            + Opcode.JMP        # except:
            + Integer(5).to_byte_array(signed=True, min_length=1)
            + Opcode.DROP
            + Opcode.PUSH0          # x = 0
            + Opcode.STLOC0
            + Opcode.ENDTRY
            + Integer(2).to_byte_array(signed=True, min_length=1)
            + Opcode.LDLOC0     # return x
            + Opcode.RET
        )

        path = '%s/boa3_test/test_sc/exception_test/TryExceptWithoutException.py' % self.dirname
        output = Boa3.compile(path)
        self.assertEqual(expected_output, output)

        engine = TestEngine(self.dirname)
        result = self.run_smart_contract(engine, path, 'test_try_except', 10)
        self.assertEqual(10, result)
        result = self.run_smart_contract(engine, path, 'test_try_except', -110)
        self.assertEqual(-110, result)

    def test_try_except_base_exception(self):
        expected_output = (
            Opcode.INITSLOT     # function signature
            + b'\x01'
            + b'\x01'
            + Opcode.TRY        # try:
            + Integer(7).to_byte_array(signed=True, min_length=1)  # jmp to exception
            + Integer(0).to_byte_array(signed=True, min_length=1)  # jmp to finally if exists
            + Opcode.LDARG0         # x = arg
            + Opcode.STLOC0
            + Opcode.JMP        # except BaseException:
            + Integer(5).to_byte_array(signed=True, min_length=1)
            + Opcode.DROP
            + Opcode.PUSH0          # x = 0
            + Opcode.STLOC0
            + Opcode.ENDTRY
            + Integer(2).to_byte_array(signed=True, min_length=1)
            + Opcode.LDLOC0     # return x
            + Opcode.RET
        )

        path = '%s/boa3_test/test_sc/exception_test/TryExceptBaseException.py' % self.dirname
        output = Boa3.compile(path)
        self.assertEqual(expected_output, output)

        engine = TestEngine(self.dirname)
        result = self.run_smart_contract(engine, path, 'test_try_except', 10)
        self.assertEqual(10, result)
        result = self.run_smart_contract(engine, path, 'test_try_except', -110)
        self.assertEqual(-110, result)

    def test_try_except_specific_exception(self):
        expected_output = (
            Opcode.INITSLOT     # function signature
            + b'\x01'
            + b'\x01'
            + Opcode.TRY        # try:
            + Integer(7).to_byte_array(signed=True, min_length=1)  # jmp to exception
            + Integer(0).to_byte_array(signed=True, min_length=1)  # jmp to finally if exists
            + Opcode.LDARG0         # x = arg
            + Opcode.STLOC0
            + Opcode.JMP        # except ValueError:
            + Integer(5).to_byte_array(signed=True, min_length=1)
            + Opcode.DROP
            + Opcode.PUSH0          # x = 0
            + Opcode.STLOC0
            + Opcode.ENDTRY
            + Integer(2).to_byte_array(signed=True, min_length=1)
            + Opcode.LDLOC0     # return x
            + Opcode.RET
        )

        path = '%s/boa3_test/test_sc/exception_test/TryExceptSpecificException.py' % self.dirname
        output = self.assertCompilerLogs(UsingSpecificException, path)
        self.assertEqual(expected_output, output)

        engine = TestEngine(self.dirname)
        result = self.run_smart_contract(engine, path, 'test_try_except', 10)
        self.assertEqual(10, result)
        result = self.run_smart_contract(engine, path, 'test_try_except', -110)
        self.assertEqual(-110, result)

    def test_try_except_with_name(self):
        path = '%s/boa3_test/test_sc/exception_test/TryExceptWithName.py' % self.dirname
        self.assertCompilerLogs(NotSupportedOperation, path)

    def test_try_except_finally(self):
        expected_output = (
            Opcode.INITSLOT     # function signature
            + b'\x01'
            + b'\x01'
            + Opcode.LDARG0
            + Opcode.PUSH4
            + Opcode.DIV
            + Opcode.STLOC0
            + Opcode.TRY        # try:
            + Integer(9).to_byte_array(signed=True, min_length=1)   # jmp to exception
            + Integer(15).to_byte_array(signed=True, min_length=1)  # jmp to finally if exists
            + Opcode.LDLOC0         # x += arg
            + Opcode.LDARG0
            + Opcode.ADD
            + Opcode.STLOC0
            + Opcode.JMP        # except ValueError:
            + Integer(6).to_byte_array(signed=True, min_length=1)
            + Opcode.DROP
            + Opcode.LDLOC0         # x = -x
            + Opcode.NEGATE
            + Opcode.STLOC0
            + Opcode.ENDTRY
            + Integer(7).to_byte_array(signed=True, min_length=1)
            + Opcode.LDLOC0     # finally
            + Opcode.PUSH2          # x *= 2
            + Opcode.MUL
            + Opcode.STLOC0
            + Opcode.ENDFINALLY
            + Opcode.LDLOC0     # return x
            + Opcode.RET
        )

        path = '%s/boa3_test/test_sc/exception_test/TryExceptFinally.py' % self.dirname
        output = Boa3.compile(path)
        self.assertEqual(expected_output, output)

        engine = TestEngine(self.dirname)
        result = self.run_smart_contract(engine, path, 'test_try_except', 10)
        self.assertEqual(24, result)
        result = self.run_smart_contract(engine, path, 'test_try_except', -110)
        self.assertEqual(-274, result)
Exemplo n.º 4
0
    def run(self, contract_id: Union[str, UInt160], method: str, *arguments: Any, reset_engine: bool = False,
            rollback_on_fault: bool = True) -> Any:
        import json
        import subprocess

        if isinstance(contract_id, str) and contract_id not in self.contracts:
            self.add_contract(contract_id)

        # build an UInt160 value if the contract_id is not a path
        if isinstance(contract_id, bytes) and not isinstance(contract_id, UInt160):
            contract_id = UInt160(contract_id)

        test_engine_args = self.to_json(contract_id, method, *arguments)
        param_json = json.dumps(test_engine_args, separators=(',', ':'))

        try:
            process = subprocess.Popen(['dotnet', self._test_engine_path, param_json],
                                       stdout=subprocess.PIPE,
                                       stderr=subprocess.STDOUT,
                                       text=True)
        except BaseException:
            json_path = '{0}/test-engine-test.json'.format(path.curdir)
            with open(json_path, 'wb+') as json_file:
                json_file.write(String(param_json).to_bytes())
                json_file.close()

            process = subprocess.Popen(['dotnet', self._test_engine_path, json_path],
                                       stdout=subprocess.PIPE,
                                       stderr=subprocess.STDOUT,
                                       text=True)

        stdout, stderr = process.communicate()

        if reset_engine:
            self.reset_engine()
        else:
            self.reset_state()

        stdout = stdout.splitlines()[-1]

        try:
            result = json.loads(stdout)

            self._error_message = result['error'] if 'error' in result else None

            if 'vmstate' in result:
                self._vm_state = VMState.get_vm_state(result['vmstate'])

            if 'executedscripthash' in result:
                self._executed_script_hash = UInt160.from_string(result['executedscripthash'])

            if 'gasconsumed' in result:
                self._gas_consumed = int(result['gasconsumed'])

            if 'resultstack' in result:
                if isinstance(result['resultstack'], list):
                    self._result_stack = [stack_item_from_json(value) for value in result['resultstack']]
                else:
                    self._result_stack = [stack_item_from_json(result['resultstack'])]

            if self._vm_state is VMState.HALT or not rollback_on_fault:
                if 'notifications' in result:
                    json_storage = result['notifications']
                    if not isinstance(json_storage, list):
                        json_storage = [json_storage]

                    notifications = []
                    for n in json_storage:
                        new = Notification.from_json(n)
                        if new is not None:
                            notifications.append(new)
                    self._notifications.extend(notifications)

                if 'storage' in result:
                    json_storage = result['storage']
                    self._storage = Storage.from_json(json_storage)

                    for contract in self._contract_paths.copy():
                        if (not isinstance(contract, TestContract)
                                or contract.script_hash is None
                                or not self._storage.has_contract(contract.script_hash)):
                            self.remove_contract(contract.path)

                if 'currentblock' in result:
                    current_block = Block.from_json(result['currentblock'])

                    existing_block = next((block for block in self._blocks if block.index == current_block.index), None)
                    if existing_block is not None:
                        self._blocks.remove(existing_block)
                    self._blocks.append(current_block)

                if 'transaction' in result and self._vm_state is VMState.HALT:
                    block = self.current_block
                    if block is None:
                        block = self.increase_block(self.height)

                    tx = Transaction.from_json(result['transaction'])
                    block.add_transaction(tx)

        except BaseException as e:
            self._error_message = str(e)

        # TODO: convert the result to the return type of the function in the manifest
        return self._result_stack[-1] if len(self._result_stack) > 0 else VoidType
Exemplo n.º 5
0
    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])
Exemplo n.º 6
0
    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)
Exemplo n.º 7
0
    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)

        engine.add_neo(self.OWNER_SCRIPT_HASH, transferred_amount_neo)
        engine.add_gas(self.OTHER_ACCOUNT_1, 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',
            self.OWNER_SCRIPT_HASH,
            NEO_SCRIPT,
            transferred_amount_neo,
            self.OTHER_ACCOUNT_1,
            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,
                                    NEO_SCRIPT,
                                    'transfer',
                                    self.OWNER_SCRIPT_HASH,
                                    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', self.OWNER_SCRIPT_HASH)
        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,
            NEO_SCRIPT,
            'transfer',
            self.OWNER_SCRIPT_HASH,
            htlc_address,
            transferred_amount_neo,
            None,
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            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(self.OWNER_SCRIPT_HASH, 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', self.OWNER_SCRIPT_HASH)
        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,
                                    GAS_SCRIPT,
                                    'transfer',
                                    self.OTHER_ACCOUNT_1,
                                    htlc_address,
                                    transferred_amount_gas - 100,
                                    None,
                                    signer_accounts=[self.OTHER_ACCOUNT_1],
                                    expected_result_type=bool)

        transfer_events = engine.get_events('Transfer')
        self.assertEqual(0, len(transfer_events))

        # saving the balance to compare after the transfer
        balance_gas_sender_before = self.run_smart_contract(
            engine, GAS_SCRIPT, 'balanceOf', self.OTHER_ACCOUNT_1)
        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,
            GAS_SCRIPT,
            'transfer',
            self.OTHER_ACCOUNT_1,
            htlc_address,
            transferred_amount_gas,
            None,
            signer_accounts=[self.OTHER_ACCOUNT_1],
            expected_result_type=bool)
        self.assertEqual(True, result)

        # the 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(self.OTHER_ACCOUNT_1, 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', self.OTHER_ACCOUNT_1)
        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)
Exemplo n.º 8
0
    def opcode(self) -> List[Tuple[Opcode, bytes]]:
        from boa3.compiler.codegenerator import get_bytes_count

        jmp_place_holder = (Opcode.JMP, b'\x01')
        message = String("x not in sequence").to_bytes()

        # receives: end, start, x, sequence
        verify_negative_index = [  # verifies if index in a negative value
            (Opcode.DUP, b''),
            (Opcode.PUSHM1, b''),
            jmp_place_holder  # if index >= 0, jump to verify_big_end or verify_big_start
        ]

        fix_negative_end = [  # gets the correspondent positive value of end
            (Opcode.PUSH3, b''),
            (Opcode.PICK, b''),
            (Opcode.SIZE, b''),
            (Opcode.ADD, b''),
            (Opcode.INC, b''),  # end = end + len(sequence) + 1
            (Opcode.DUP, b''),
            (Opcode.PUSHM1, b''),
            jmp_place_holder  # if end is not negative anymore, start verifying start
        ]

        fix_still_negative_index = [  # if index is still negative, consider it 0 then
            (Opcode.DROP, b''),
            (Opcode.PUSH0, b''),  # end = 0
        ]

        jmp_fix_negative_index = Opcode.get_jump_and_data(
            Opcode.JMPGT,
            get_bytes_count(fix_negative_end + fix_still_negative_index), True)
        verify_negative_index[-1] = jmp_fix_negative_index

        verify_big_end = [  # verify if end is bigger then len(sequence)
            (Opcode.DUP, b''),
            (Opcode.PUSH4, b''),
            (Opcode.PICK, b''),
            (Opcode.SIZE, b''),
            jmp_place_holder  # if end <= len(sequence), start verifying start
        ]

        fix_big_end = [  # consider end as len(sequence)
            (Opcode.DROP, b''),
            (Opcode.PUSH2, b''),
            (Opcode.PICK, b''),
            (Opcode.SIZE, b''),  # end = len(sequence)
        ]

        jmp_other_verifies = Opcode.get_jump_and_data(
            Opcode.JMPGT,
            get_bytes_count(fix_still_negative_index + verify_big_end +
                            fix_big_end), True)
        fix_negative_end[-1] = jmp_other_verifies

        jmp_fix_big_index = Opcode.get_jump_and_data(
            Opcode.JMPLE, get_bytes_count(fix_big_end), True)
        verify_big_end[-1] = jmp_fix_big_index

        verify_and_fix_end = [  # collection of Opcodes regarding verifying and fixing end index
            (Opcode.REVERSE4, b''),
        ]
        verify_and_fix_end.extend(verify_negative_index)
        verify_and_fix_end.extend(fix_negative_end)
        verify_and_fix_end.extend(fix_still_negative_index)
        verify_and_fix_end.extend(verify_big_end)
        verify_and_fix_end.extend(fix_big_end)

        verify_and_fix_start = [  # collection of Opcodes regarding verifying and fixing start index
            (Opcode.SWAP, b'')
        ]
        verify_and_fix_start.extend(verify_negative_index)
        verify_and_fix_start.extend(fix_negative_end)
        verify_and_fix_start.extend(fix_still_negative_index)
        verify_and_fix_start.extend(verify_big_end)
        verify_and_fix_start.extend(fix_big_end)

        verify_while = [  # verify if already went through all items on the sequence[start:end]
            (Opcode.OVER, b''),  # index = start
            (Opcode.OVER, b''),
            jmp_place_holder  # if index <= start, jump to not_inside_sequence
        ]

        compare_item = [  # verifies if x is in sequence
            (Opcode.PUSH3, b''),
            (Opcode.PICK, b''),
            (Opcode.OVER, b''),
            (Opcode.PICKITEM, b''),
            (Opcode.PUSH3, b''),
            (Opcode.PICK, b''),
            (Opcode.NUMEQUAL, b''),  # found_x = sequence[index] == x
            jmp_place_holder  # if found_x, jump to return_index
        ]

        not_found = [  # increments index and goes back to verify again
            (Opcode.INC, b''),  # index++
            # jump to verify_while
        ]

        jmp_back_to_verify = Opcode.get_jump_and_data(
            Opcode.JMP,
            -get_bytes_count(verify_while + compare_item + not_found), True)
        not_found.append(jmp_back_to_verify)

        jmp_to_error = Opcode.get_jump_and_data(
            Opcode.JMPLE, get_bytes_count(compare_item + not_found), True)
        verify_while[-1] = jmp_to_error

        not_inside_sequence = [  # send error message saying that x is not in sequence
            (Opcode.PUSHDATA1,
             Integer(len(message)).to_byte_array(signed=True, min_length=1) +
             message),
            (Opcode.THROW, b''),
        ]

        jmp_to_return_index = Opcode.get_jump_and_data(
            Opcode.JMPIF, get_bytes_count(not_found + not_inside_sequence),
            True)
        compare_item[-1] = jmp_to_return_index

        return_index = [  # removes all values in the stack but the index
            (Opcode.NIP, b''),
            (Opcode.NIP, b''),
            (Opcode.NIP, b''),
        ]

        return (verify_and_fix_end + verify_and_fix_start + verify_while +
                compare_item + not_found + not_inside_sequence + return_index)
Exemplo n.º 9
0
    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)

        engine.add_neo(self.OWNER_SCRIPT_HASH, transferred_amount_neo)
        engine.add_gas(self.OTHER_ACCOUNT_1, 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', self.OWNER_SCRIPT_HASH)
        balance_neo_person_b_before = self.run_smart_contract(
            engine, NEO_SCRIPT, 'balanceOf', self.OTHER_ACCOUNT_1)
        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', self.OWNER_SCRIPT_HASH)
        balance_gas_person_b_before = self.run_smart_contract(
            engine, GAS_SCRIPT, 'balanceOf', self.OTHER_ACCOUNT_1)
        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',
            self.OWNER_SCRIPT_HASH,
            NEO_SCRIPT,
            transferred_amount_neo,
            self.OTHER_ACCOUNT_1,
            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=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(False, result)

        result = self.run_smart_contract(
            engine,
            NEO_SCRIPT,
            'transfer',
            self.OWNER_SCRIPT_HASH,
            htlc_address,
            transferred_amount_neo,
            None,
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        result = self.run_smart_contract(
            engine,
            GAS_SCRIPT,
            'transfer',
            self.OTHER_ACCOUNT_1,
            htlc_address,
            transferred_amount_gas,
            None,
            signer_accounts=[self.OTHER_ACCOUNT_1],
            expected_result_type=bool)
        self.assertEqual(True, result)

        # the withdraw will fail, because the secret is wrong
        result = self.run_smart_contract(
            engine,
            path,
            'withdraw',
            'wrong one',
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            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(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(htlc_address, sender)
        self.assertEqual(self.OWNER_SCRIPT_HASH, receiver)
        self.assertEqual(transferred_amount_gas, 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(htlc_address, sender)
        self.assertEqual(self.OTHER_ACCOUNT_1, 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', self.OWNER_SCRIPT_HASH)
        balance_neo_person_b_after = self.run_smart_contract(
            engine, NEO_SCRIPT, 'balanceOf', self.OTHER_ACCOUNT_1)
        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', self.OWNER_SCRIPT_HASH)
        balance_gas_person_b_after = self.run_smart_contract(
            engine, GAS_SCRIPT, 'balanceOf', self.OTHER_ACCOUNT_1)
        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)
Exemplo n.º 10
0
    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)

        engine.add_neo(self.OWNER_SCRIPT_HASH, transferred_amount_neo)
        engine.add_gas(self.OTHER_ACCOUNT_1, 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',
            self.OWNER_SCRIPT_HASH,
            NEO_SCRIPT,
            transferred_amount_neo,
            self.OTHER_ACCOUNT_1,
            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=[self.OWNER_SCRIPT_HASH],
            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',
            self.OWNER_SCRIPT_HASH,
            NEO_SCRIPT,
            transferred_amount_neo,
            self.OTHER_ACCOUNT_1,
            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,
            NEO_SCRIPT,
            'transfer',
            self.OWNER_SCRIPT_HASH,
            htlc_address,
            transferred_amount_neo,
            None,
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        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)

        # 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(1, len(transfer_events))
        self.assertEqual(3, len(transfer_events[0].arguments))

        # HTLC returning the tokens
        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(htlc_address, sender)
        self.assertEqual(self.OWNER_SCRIPT_HASH, receiver)
        self.assertEqual(transferred_amount_neo, amount)

        result = self.run_smart_contract(
            engine,
            path,
            'atomic_swap',
            self.OWNER_SCRIPT_HASH,
            NEO_SCRIPT,
            transferred_amount_neo,
            self.OTHER_ACCOUNT_1,
            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,
            NEO_SCRIPT,
            'transfer',
            self.OWNER_SCRIPT_HASH,
            htlc_address,
            transferred_amount_neo,
            None,
            signer_accounts=[self.OWNER_SCRIPT_HASH],
            expected_result_type=bool)
        self.assertEqual(True, result)

        result = self.run_smart_contract(
            engine,
            GAS_SCRIPT,
            'transfer',
            self.OTHER_ACCOUNT_1,
            htlc_address,
            transferred_amount_gas,
            None,
            signer_accounts=[self.OTHER_ACCOUNT_1],
            expected_result_type=bool)
        self.assertEqual(True, result)

        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)

        # 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(2, len(transfer_events))
        self.assertEqual(3, len(transfer_events[0].arguments))
        self.assertEqual(3, len(transfer_events[1].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(htlc_address, sender)
        self.assertEqual(self.OWNER_SCRIPT_HASH, receiver)
        self.assertEqual(transferred_amount_neo, amount)

        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(self.OTHER_ACCOUNT_1, receiver)
        self.assertEqual(transferred_amount_gas, amount)
Exemplo n.º 11
0
    def run(self,
            nef_path: Union[str, UInt160],
            method: str,
            *arguments: Any,
            reset_engine: bool = False,
            rollback_on_fault: bool = True) -> Any:
        import json
        import subprocess

        if isinstance(nef_path, str) and nef_path not in self._contract_paths:
            self.add_contract(nef_path)

        test_engine_args = self.to_json(nef_path, method, *arguments)
        param_json = json.dumps(test_engine_args, separators=(',', ':'))

        try:
            process = subprocess.Popen(
                ['dotnet', self._test_engine_path, param_json],
                stdout=subprocess.PIPE,
                stderr=subprocess.STDOUT,
                text=True)
        except BaseException:
            json_path = '{0}/test-engine-test.json'.format(path.curdir)
            with open(json_path, 'wb+') as json_file:
                json_file.write(String(param_json).to_bytes())
                json_file.close()

            process = subprocess.Popen(
                ['dotnet', self._test_engine_path, json_path],
                stdout=subprocess.PIPE,
                stderr=subprocess.STDOUT,
                text=True)

        stdout, stderr = process.communicate()

        if reset_engine:
            self.reset_engine()
        else:
            self.reset_state()

        stdout = stdout.splitlines()[-1]

        try:
            result = json.loads(stdout)

            self._error_message = result['error'] if 'error' in result else None

            if 'vm_state' in result:
                self._vm_state = VMState.get_vm_state(result['vm_state'])

            if 'gasconsumed' in result:
                self._gas_consumed = result['gasconsumed']

            if 'result_stack' in result:
                if isinstance(result['result_stack'], list):
                    self._result_stack = [
                        stack_item_from_json(value)
                        for value in result['result_stack']
                    ]
                else:
                    self._result_stack = [
                        stack_item_from_json(result['result_stack'])
                    ]

            if self._vm_state is VMState.HALT or not rollback_on_fault:
                if 'notifications' in result:
                    json_storage = result['notifications']
                    if not isinstance(json_storage, list):
                        json_storage = [json_storage]

                    notifications = []
                    for n in json_storage:
                        new = Notification.from_json(n)
                        if new is not None:
                            notifications.append(new)
                    self._notifications.extend(notifications)

                if 'storage' in result:
                    json_storage = result['storage']
                    self._storage = Storage.from_json(json_storage)

                    index = self._get_contract_id(nef_path)
                    contract = self._contract_paths[index]
                    if contract.script_hash is not None and not self._storage.has_contract(
                            contract.script_hash):
                        self.remove_contract(nef_path)

                if 'blocks' in result:
                    blocks_json = result['blocks']
                    if not isinstance(blocks_json, list):
                        blocks_json = [blocks_json]

                    self._blocks = sorted(
                        [Block.from_json(js) for js in blocks_json],
                        key=lambda b: b.index)

                if 'transaction' in result and self._vm_state is VMState.HALT:
                    block = self.current_block
                    if block is None:
                        block = self.increase_block(self.height)

                    tx = Transaction.from_json(result['transaction'])
                    block.add_transaction(tx)

        except BaseException as e:
            self._error_message = str(e)

        # TODO: convert the result to the return type of the function in the manifest
        return self._result_stack[-1] if len(
            self._result_stack) > 0 else VoidType
Exemplo n.º 12
0
    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)
Exemplo n.º 13
0
 def _generate_invoke_file(self, invoke: NeoInvoke):
     test_engine_args = invoke.to_json()
     param_json = json.dumps(test_engine_args, separators=(',', ':'))
     with open(self._INVOKE_FILE, 'wb+') as json_file:
         json_file.write(String(param_json).to_bytes())
Exemplo n.º 14
0
    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

        self.run_smart_contract(engine, path, 'refund')
        htlc_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()

        aux_path2 = self.get_contract_path('examples/auxiliary_contracts',
                                           'auxiliary_contract_2.py')
        self.run_smart_contract(engine, aux_path2, 'get_name')
        aux_address2 = engine.executed_script_hash.to_array()

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

        result = self.run_smart_contract(
            engine,
            path,
            'atomic_swap',
            aux_address,
            constants.NEO_SCRIPT,
            transferred_amount_neo,
            aux_address2,
            constants.GAS_SCRIPT,
            transferred_amount_gas,
            hash160(String('unit test').to_bytes()),
            signer_accounts=[self.OWNER_SCRIPT_HASH])
        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])
        self.assertEqual(False, result)

        # this simulates a new block in the blockchain
        # 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])
        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,
            constants.NEO_SCRIPT,
            transferred_amount_neo,
            aux_address2,
            constants.GAS_SCRIPT,
            transferred_amount_gas,
            hash160(String('unit test').to_bytes()),
            signer_accounts=[self.OWNER_SCRIPT_HASH])
        self.assertEqual(True, result)

        result = self.run_smart_contract(engine,
                                         aux_path,
                                         'calling_transfer',
                                         constants.NEO_SCRIPT,
                                         aux_address,
                                         htlc_address,
                                         transferred_amount_neo,
                                         None,
                                         signer_accounts=[aux_address])
        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])
        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,
            constants.NEO_SCRIPT,
            transferred_amount_neo,
            aux_address2,
            constants.GAS_SCRIPT,
            transferred_amount_gas,
            hash160(String('unit test').to_bytes()),
            signer_accounts=[self.OWNER_SCRIPT_HASH])
        self.assertEqual(True, result)

        result = self.run_smart_contract(engine,
                                         aux_path,
                                         'calling_transfer',
                                         constants.NEO_SCRIPT,
                                         aux_address,
                                         htlc_address,
                                         transferred_amount_neo,
                                         None,
                                         signer_accounts=[aux_address])
        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',
                                         constants.GAS_SCRIPT,
                                         aux_address2,
                                         htlc_address,
                                         transferred_amount_gas,
                                         None,
                                         signer_accounts=[aux_address2])
        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])
        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)
Exemplo n.º 15
0
    def test_wrapped_neo_burn(self):
        path = self.get_contract_path('wrapped_neo.py')
        engine = TestEngine()

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

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

        # burning zNEO will end up giving NEO to the one who burned it
        neo_wrapped_before = self.run_smart_contract(engine,
                                                     constants.NEO_SCRIPT,
                                                     'balanceOf',
                                                     wrapped_neo_address)
        neo_owner_before = self.run_smart_contract(engine,
                                                   constants.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])
        self.assertIsVoid(result)

        transfer_events = engine.get_events('Transfer',
                                            origin=wrapped_neo_address)
        self.assertGreaterEqual(len(transfer_events), 1)
        wrapped_token_transfer_event = transfer_events[-1]
        self.assertEqual(3, len(wrapped_token_transfer_event.arguments))

        sender, receiver, amount = wrapped_token_transfer_event.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)

        transfer_events = engine.get_events('Transfer',
                                            origin=constants.NEO_SCRIPT)
        self.assertGreaterEqual(len(transfer_events), 1)
        neo_transfer_event = transfer_events[-1]
        self.assertEqual(3, len(neo_transfer_event.arguments))

        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(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,
                                                    constants.NEO_SCRIPT,
                                                    'balanceOf',
                                                    wrapped_neo_address)
        neo_owner_after = self.run_smart_contract(engine, constants.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])
Exemplo n.º 16
0
    def test_htlc_on_nep17_payment(self):
        path = self.get_contract_path('htlc.py')
        engine = TestEngine()
        transferred_amount_neo = 10 * 10**8
        transferred_amount_gas = 10000 * 10**8

        self.run_smart_contract(engine, path, 'refund')
        htlc_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()

        aux_path2 = self.get_contract_path('examples/auxiliary_contracts',
                                           'auxiliary_contract_2.py')
        self.run_smart_contract(engine, aux_path2, 'get_name')
        aux_address2 = engine.executed_script_hash.to_array()

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

        # starting atomic swap
        result = self.run_smart_contract(
            engine,
            path,
            'atomic_swap',
            aux_address,
            constants.NEO_SCRIPT,
            transferred_amount_neo,
            aux_address2,
            constants.GAS_SCRIPT,
            transferred_amount_gas,
            hash160(String('unit test').to_bytes()),
            signer_accounts=[self.OWNER_SCRIPT_HASH])
        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',
                                    constants.NEO_SCRIPT,
                                    aux_address,
                                    htlc_address,
                                    transferred_amount_neo - 100,
                                    None,
                                    signer_accounts=[self.OWNER_SCRIPT_HASH])

        # 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, constants.NEO_SCRIPT, 'balanceOf', aux_address)
        balance_neo_receiver_before = self.run_smart_contract(
            engine, constants.NEO_SCRIPT, 'balanceOf', htlc_address)

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

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

        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(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, constants.NEO_SCRIPT, 'balanceOf', aux_address)
        balance_neo_receiver_after = self.run_smart_contract(
            engine, constants.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',
                                    constants.GAS_SCRIPT,
                                    aux_address2,
                                    htlc_address,
                                    transferred_amount_gas - 100,
                                    None,
                                    signer_accounts=[aux_address2])

        transfer_events = engine.get_events('Transfer',
                                            origin=constants.NEO_SCRIPT)
        # 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, constants.GAS_SCRIPT, 'balanceOf', aux_address2)
        balance_gas_receiver_before = self.run_smart_contract(
            engine, constants.GAS_SCRIPT, 'balanceOf', htlc_address)

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

        # the transfer was accepted so it was registered
        transfer_events = engine.get_events('Transfer',
                                            origin=constants.GAS_SCRIPT)
        self.assertGreaterEqual(len(transfer_events), 1)
        gas_transfer_event = transfer_events[-1]
        self.assertEqual(3, len(gas_transfer_event.arguments))

        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_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, constants.GAS_SCRIPT, 'balanceOf', aux_address2)
        balance_gas_receiver_after = self.run_smart_contract(
            engine, constants.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)
Exemplo n.º 17
0
    def test_wrapped_neo_approve(self):
        path = self.get_contract_path('wrapped_neo.py')
        path_aux_contract = self.get_contract_path(
            'examples/auxiliary_contracts', 'auxiliary_contract.py')
        engine = TestEngine()

        self.run_smart_contract(engine, path, 'symbol')
        wrapped_neo_address = engine.executed_script_hash.to_array()
        self.run_smart_contract(engine, path_aux_contract, 'get_name')
        aux_contract_address = engine.executed_script_hash.to_array()

        engine = TestEngine()
        engine.add_contract(path.replace('.py', '.nef'))
        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])
        self.assertEqual(False, 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])
        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])
        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):
            owner = String(owner).to_bytes()
        if isinstance(spender, str):
            spender = String(spender).to_bytes()
        self.assertEqual(aux_contract_address, owner)
        self.assertEqual(self.OTHER_ACCOUNT_1, spender)
        self.assertEqual(allowed_amount, amount)
Exemplo n.º 18
0
class TestRange(BoaTest):

    default_folder: str = 'test_sc/range_test'

    RANGE_ERROR_MESSAGE = String('range() arg 3 must not be zero').to_bytes()

    def test_range_given_length(self):
        expected_output = (
            Opcode.INITSLOT + b'\x00' + b'\x01' + Opcode.PUSH1  # range(arg0)
            + Opcode.PUSH0 + Opcode.LDARG0 + Opcode.PUSH2 + Opcode.PICK +
            Opcode.SIGN + Opcode.JMPIF +
            Integer(5 + len(self.RANGE_ERROR_MESSAGE)).to_byte_array(
                signed=True, min_length=1) + Opcode.PUSHDATA1 +
            Integer(len(self.RANGE_ERROR_MESSAGE)).to_byte_array(
                signed=True, min_length=1) + self.RANGE_ERROR_MESSAGE +
            Opcode.THROW + Opcode.NEWARRAY0 + Opcode.REVERSE4 + Opcode.SWAP +
            Opcode.JMP + Integer(8).to_byte_array(signed=True, min_length=1) +
            Opcode.PUSH3 + Opcode.PICK + Opcode.OVER + Opcode.APPEND +
            Opcode.OVER + Opcode.ADD + Opcode.DUP + Opcode.PUSH3 +
            Opcode.PICK + Opcode.PUSH3 + Opcode.PICK + Opcode.SIGN +
            Opcode.PUSH0 + Opcode.JMPGT +
            Integer(5).to_byte_array(signed=True, min_length=1) + Opcode.GT +
            Opcode.JMP + Integer(3).to_byte_array(signed=True, min_length=1) +
            Opcode.LT + Opcode.JMPIF +
            Integer(-19).to_byte_array(signed=True, min_length=1) +
            Opcode.DROP + Opcode.DROP + Opcode.DROP + Opcode.RET  # return
        )

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

        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'range_example', 5)
        self.assertEqual([0, 1, 2, 3, 4], result)
        result = self.run_smart_contract(engine, path, 'range_example', 10)
        self.assertEqual([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], result)
        result = self.run_smart_contract(engine, path, 'range_example', 0)
        self.assertEqual([], result)

    def test_range_given_start(self):
        expected_output = (
            Opcode.INITSLOT + b'\x00' + b'\x02' +
            Opcode.PUSH1  # range(arg0, arg1)
            + Opcode.LDARG0 + Opcode.LDARG1 + Opcode.PUSH2 + Opcode.PICK +
            Opcode.SIGN + Opcode.JMPIF +
            Integer(5 + len(self.RANGE_ERROR_MESSAGE)).to_byte_array(
                signed=True, min_length=1) + Opcode.PUSHDATA1 +
            Integer(len(self.RANGE_ERROR_MESSAGE)).to_byte_array(
                signed=True, min_length=1) + self.RANGE_ERROR_MESSAGE +
            Opcode.THROW + Opcode.NEWARRAY0 + Opcode.REVERSE4 + Opcode.SWAP +
            Opcode.JMP + Integer(8).to_byte_array(signed=True, min_length=1) +
            Opcode.PUSH3 + Opcode.PICK + Opcode.OVER + Opcode.APPEND +
            Opcode.OVER + Opcode.ADD + Opcode.DUP + Opcode.PUSH3 +
            Opcode.PICK + Opcode.PUSH3 + Opcode.PICK + Opcode.SIGN +
            Opcode.PUSH0 + Opcode.JMPGT +
            Integer(5).to_byte_array(signed=True, min_length=1) + Opcode.GT +
            Opcode.JMP + Integer(3).to_byte_array(signed=True, min_length=1) +
            Opcode.LT + Opcode.JMPIF +
            Integer(-19).to_byte_array(signed=True, min_length=1) +
            Opcode.DROP + Opcode.DROP + Opcode.DROP + Opcode.RET  # return
        )

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

        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'range_example', 2, 6)
        self.assertEqual([2, 3, 4, 5], result)
        result = self.run_smart_contract(engine, path, 'range_example', -10, 0)
        self.assertEqual([-10, -9, -8, -7, -6, -5, -4, -3, -2, -1], result)

    def test_range_given_step(self):
        expected_output = (
            Opcode.INITSLOT + b'\x00' + b'\x03' +
            Opcode.LDARG2  # range(arg0, arg1, arg2)
            + Opcode.LDARG0 + Opcode.LDARG1 + Opcode.PUSH2 + Opcode.PICK +
            Opcode.SIGN + Opcode.JMPIF +
            Integer(5 + len(self.RANGE_ERROR_MESSAGE)).to_byte_array(
                signed=True, min_length=1) + Opcode.PUSHDATA1 +
            Integer(len(self.RANGE_ERROR_MESSAGE)).to_byte_array(
                signed=True, min_length=1) + self.RANGE_ERROR_MESSAGE +
            Opcode.THROW + Opcode.NEWARRAY0 + Opcode.REVERSE4 + Opcode.SWAP +
            Opcode.JMP + Integer(8).to_byte_array(signed=True, min_length=1) +
            Opcode.PUSH3 + Opcode.PICK + Opcode.OVER + Opcode.APPEND +
            Opcode.OVER + Opcode.ADD + Opcode.DUP + Opcode.PUSH3 +
            Opcode.PICK + Opcode.PUSH3 + Opcode.PICK + Opcode.SIGN +
            Opcode.PUSH0 + Opcode.JMPGT +
            Integer(5).to_byte_array(signed=True, min_length=1) + Opcode.GT +
            Opcode.JMP + Integer(3).to_byte_array(signed=True, min_length=1) +
            Opcode.LT + Opcode.JMPIF +
            Integer(-19).to_byte_array(signed=True, min_length=1) +
            Opcode.DROP + Opcode.DROP + Opcode.DROP + Opcode.RET  # return
        )

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

        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'range_example', 2, 10,
                                         3)
        self.assertEqual([2, 5, 8], result)
        result = self.run_smart_contract(engine, path, 'range_example', -2, 10,
                                         3)
        self.assertEqual([-2, 1, 4, 7], result)

    def test_range_parameter_mismatched_type(self):
        path = self.get_contract_path('RangeParameterMismatchedType.py')
        self.assertCompilerLogs(MismatchedTypes, path)

    def test_range_as_sequence(self):
        expected_output = (
            Opcode.INITSLOT + b'\x00' + b'\x02' +
            Opcode.PUSH1  # range(arg0, arg1)
            + Opcode.LDARG0 + Opcode.LDARG1 + Opcode.PUSH2 + Opcode.PICK +
            Opcode.SIGN + Opcode.JMPIF +
            Integer(5 + len(self.RANGE_ERROR_MESSAGE)).to_byte_array(
                signed=True, min_length=1) + Opcode.PUSHDATA1 +
            Integer(len(self.RANGE_ERROR_MESSAGE)).to_byte_array(
                signed=True, min_length=1) + self.RANGE_ERROR_MESSAGE +
            Opcode.THROW + Opcode.NEWARRAY0 + Opcode.REVERSE4 + Opcode.SWAP +
            Opcode.JMP + Integer(8).to_byte_array(signed=True, min_length=1) +
            Opcode.PUSH3 + Opcode.PICK + Opcode.OVER + Opcode.APPEND +
            Opcode.OVER + Opcode.ADD + Opcode.DUP + Opcode.PUSH3 +
            Opcode.PICK + Opcode.PUSH3 + Opcode.PICK + Opcode.SIGN +
            Opcode.PUSH0 + Opcode.JMPGT +
            Integer(5).to_byte_array(signed=True, min_length=1) + Opcode.GT +
            Opcode.JMP + Integer(3).to_byte_array(signed=True, min_length=1) +
            Opcode.LT + Opcode.JMPIF +
            Integer(-19).to_byte_array(signed=True, min_length=1) +
            Opcode.DROP + Opcode.DROP + Opcode.DROP + Opcode.RET  # return
        )

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

        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'range_example', 2, 6)
        self.assertEqual([2, 3, 4, 5], result)
        result = self.run_smart_contract(engine, path, 'range_example', -10, 0)
        self.assertEqual([-10, -9, -8, -7, -6, -5, -4, -3, -2, -1], result)

    def test_range_mismatched_type(self):
        path = self.get_contract_path('RangeMismatchedType.py')
        self.assertCompilerLogs(MismatchedTypes, path)

    def test_range_too_few_parameters(self):
        path = self.get_contract_path('RangeTooFewParameters.py')
        self.assertCompilerLogs(UnfilledArgument, path)

    def test_range_too_many_parameters(self):
        path = self.get_contract_path('RangeTooManyParameters.py')
        self.assertCompilerLogs(UnexpectedArgument, path)

    def test_range_get_value(self):
        expected_output = (
            Opcode.INITSLOT  # function signature
            + b'\x00' + b'\x01' + Opcode.LDARG0  # arg[0]
            + Opcode.PUSH0 + Opcode.DUP + Opcode.SIGN + Opcode.PUSHM1 +
            Opcode.JMPNE +
            Integer(5).to_byte_array(min_length=1, signed=True) + Opcode.OVER +
            Opcode.SIZE + Opcode.ADD + Opcode.PICKITEM + Opcode.RET  # return
        )

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

        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'Main', [1, 2, 3, 4])
        self.assertEqual(1, result)
        result = self.run_smart_contract(engine, path, 'Main', [5, 3, 2])
        self.assertEqual(5, result)

        with self.assertRaises(TestExecutionException,
                               msg=self.VALUE_IS_OUT_OF_RANGE_MSG):
            self.run_smart_contract(engine, path, 'Main', [])

    def test_range_set_value(self):
        path = self.get_contract_path('SetValue.py')
        self.assertCompilerLogs(UnresolvedOperation, path)

    def test_range_slicing(self):
        path = self.get_contract_path('RangeSlicingLiteralValues.py')

        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'Main')
        self.assertEqual([2], result)

    def test_range_slicing_start_larger_than_ending(self):
        path = self.get_contract_path('RangeSlicingStartLargerThanEnding.py')

        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'Main')
        self.assertEqual([], result)

    def test_range_slicing_with_variables(self):
        path = self.get_contract_path('RangeSlicingVariableValues.py')

        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'Main')
        self.assertEqual([2], result)

    def test_range_slicing_negative_start(self):
        expected_output = (
            Opcode.INITSLOT  # function signature
            + b'\x01' + b'\x00' + Opcode.PUSH1  # range(6)
            + Opcode.PUSH0 + Opcode.PUSH6 + Opcode.PUSH2 + Opcode.PICK +
            Opcode.SIGN + Opcode.JMPIF +
            Integer(5 + len(self.RANGE_ERROR_MESSAGE)).to_byte_array(
                signed=True, min_length=1) + Opcode.PUSHDATA1 +
            Integer(len(self.RANGE_ERROR_MESSAGE)).to_byte_array(
                signed=True, min_length=1) + self.RANGE_ERROR_MESSAGE +
            Opcode.THROW + Opcode.NEWARRAY0 + Opcode.REVERSE4 + Opcode.SWAP +
            Opcode.JMP + Integer(8).to_byte_array(signed=True, min_length=1) +
            Opcode.PUSH3 + Opcode.PICK + Opcode.OVER + Opcode.APPEND +
            Opcode.OVER + Opcode.ADD + Opcode.DUP + Opcode.PUSH3 +
            Opcode.PICK + Opcode.PUSH3 + Opcode.PICK + Opcode.SIGN +
            Opcode.PUSH0 + Opcode.JMPGT +
            Integer(5).to_byte_array(signed=True, min_length=1) + Opcode.GT +
            Opcode.JMP + Integer(3).to_byte_array(signed=True, min_length=1) +
            Opcode.LT + Opcode.JMPIF +
            Integer(-19).to_byte_array(signed=True, min_length=1) +
            Opcode.DROP + Opcode.DROP + Opcode.DROP + Opcode.STLOC0 +
            Opcode.LDLOC0  # return a[-4:]
            + Opcode.DUP + Opcode.SIZE  # slice end
            + Opcode.PUSH4 + Opcode.NEGATE + Opcode.DUP + Opcode.SIGN +
            Opcode.PUSHM1 + Opcode.JMPNE +
            Integer(6).to_byte_array(min_length=1, signed=True) +
            Opcode.PUSH2 + Opcode.PICK + Opcode.SIZE + Opcode.ADD +
            Opcode.SWAP  # get slice
            + Opcode.NEWARRAY0  # slice
            + Opcode.PUSH2 + Opcode.PICK  # index
            + Opcode.JMP  # while index < end
            + Integer(32).to_byte_array(min_length=1) +
            Opcode.DUP  # if index >= slice start
            + Opcode.PUSH4 + Opcode.PICK + Opcode.GE + Opcode.JMPIFNOT +
            Integer(25).to_byte_array(min_length=1) +
            Opcode.OVER  # slice.append(array[index])
            + Opcode.PUSH5 + Opcode.PICK + Opcode.PUSH2 + Opcode.PICK +
            Opcode.DUP + Opcode.SIGN + Opcode.PUSHM1 + Opcode.JMPNE +
            Integer(5).to_byte_array(min_length=1) + Opcode.OVER +
            Opcode.SIZE + Opcode.ADD + Opcode.PICKITEM + Opcode.OVER +
            Opcode.ISTYPE + Type.bytearray.stack_item + Opcode.JMPIFNOT +
            Integer(5).to_byte_array(signed=True, min_length=1) + Opcode.CAT +
            Opcode.JMP + Integer(5).to_byte_array(min_length=1) +
            Opcode.APPEND + Opcode.INC  # index += 1
            + Opcode.DUP + Opcode.PUSH3 + Opcode.PICK + Opcode.LT +
            Opcode.JMPIF  # end while index < slice end
            + Integer(-34).to_byte_array(min_length=1) + Opcode.DROP +
            Opcode.REVERSE4 + Opcode.DROP + Opcode.DROP + Opcode.DROP +
            Opcode.RET  # return
        )
        path = self.get_contract_path('RangeSlicingNegativeStart.py')
        output = Boa3.compile(path)
        self.assertEqual(expected_output, output)

        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'Main')
        self.assertEqual([2, 3, 4, 5], result)

    def test_range_slicing_negative_end(self):
        expected_output = (
            Opcode.INITSLOT  # function signature
            + b'\x01' + b'\x00' + Opcode.PUSH1  # range(6)
            + Opcode.PUSH0 + Opcode.PUSH6 + Opcode.PUSH2 + Opcode.PICK +
            Opcode.SIGN + Opcode.JMPIF +
            Integer(5 + len(self.RANGE_ERROR_MESSAGE)).to_byte_array(
                signed=True, min_length=1) + Opcode.PUSHDATA1 +
            Integer(len(self.RANGE_ERROR_MESSAGE)).to_byte_array(
                signed=True, min_length=1) + self.RANGE_ERROR_MESSAGE +
            Opcode.THROW + Opcode.NEWARRAY0 + Opcode.REVERSE4 + Opcode.SWAP +
            Opcode.JMP + Integer(8).to_byte_array(signed=True, min_length=1) +
            Opcode.PUSH3 + Opcode.PICK + Opcode.OVER + Opcode.APPEND +
            Opcode.OVER + Opcode.ADD + Opcode.DUP + Opcode.PUSH3 +
            Opcode.PICK + Opcode.PUSH3 + Opcode.PICK + Opcode.SIGN +
            Opcode.PUSH0 + Opcode.JMPGT +
            Integer(5).to_byte_array(signed=True, min_length=1) + Opcode.GT +
            Opcode.JMP + Integer(3).to_byte_array(signed=True, min_length=1) +
            Opcode.LT + Opcode.JMPIF +
            Integer(-19).to_byte_array(signed=True, min_length=1) +
            Opcode.DROP + Opcode.DROP + Opcode.DROP + Opcode.STLOC0 +
            Opcode.LDLOC0  # return a[:-4]
            + Opcode.PUSH4 + Opcode.NEGATE  # slice end
            + Opcode.DUP + Opcode.SIGN + Opcode.PUSHM1 + Opcode.JMPNE +
            Integer(5).to_byte_array(min_length=1, signed=True) + Opcode.OVER +
            Opcode.SIZE + Opcode.ADD + Opcode.PUSH0 + Opcode.SWAP +
            Opcode.NEWARRAY0  # slice
            + Opcode.PUSH2 + Opcode.PICK  # index
            + Opcode.JMP  # while index < end
            + Integer(32).to_byte_array(min_length=1) +
            Opcode.DUP  # if index >= slice start
            + Opcode.PUSH4 + Opcode.PICK + Opcode.GE + Opcode.JMPIFNOT +
            Integer(25).to_byte_array(min_length=1) +
            Opcode.OVER  # slice.append(array[index])
            + Opcode.PUSH5 + Opcode.PICK + Opcode.PUSH2 + Opcode.PICK +
            Opcode.DUP + Opcode.SIGN + Opcode.PUSHM1 + Opcode.JMPNE +
            Integer(5).to_byte_array(min_length=1) + Opcode.OVER +
            Opcode.SIZE + Opcode.ADD + Opcode.PICKITEM + Opcode.OVER +
            Opcode.ISTYPE + Type.bytearray.stack_item + Opcode.JMPIFNOT +
            Integer(5).to_byte_array(signed=True, min_length=1) + Opcode.CAT +
            Opcode.JMP + Integer(5).to_byte_array(min_length=1) +
            Opcode.APPEND + Opcode.INC  # index += 1
            + Opcode.DUP + Opcode.PUSH3 + Opcode.PICK + Opcode.LT +
            Opcode.JMPIF  # end while index < slice end
            + Integer(-34).to_byte_array(min_length=1) + Opcode.DROP +
            Opcode.REVERSE4 + Opcode.DROP + Opcode.DROP + Opcode.DROP +
            Opcode.RET  # return
        )
        path = self.get_contract_path('RangeSlicingNegativeEnd.py')
        output = Boa3.compile(path)
        self.assertEqual(expected_output, output)

        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'Main')
        self.assertEqual([0, 1], result)

    def test_range_slicing_start_omitted(self):
        expected_output = (
            Opcode.INITSLOT  # function signature
            + b'\x01' + b'\x00' + Opcode.PUSH1  # range(6)
            + Opcode.PUSH0 + Opcode.PUSH6 + Opcode.PUSH2 + Opcode.PICK +
            Opcode.SIGN + Opcode.JMPIF +
            Integer(5 + len(self.RANGE_ERROR_MESSAGE)).to_byte_array(
                signed=True, min_length=1) + Opcode.PUSHDATA1 +
            Integer(len(self.RANGE_ERROR_MESSAGE)).to_byte_array(
                signed=True, min_length=1) + self.RANGE_ERROR_MESSAGE +
            Opcode.THROW + Opcode.NEWARRAY0 + Opcode.REVERSE4 + Opcode.SWAP +
            Opcode.JMP + Integer(8).to_byte_array(signed=True, min_length=1) +
            Opcode.PUSH3 + Opcode.PICK + Opcode.OVER + Opcode.APPEND +
            Opcode.OVER + Opcode.ADD + Opcode.DUP + Opcode.PUSH3 +
            Opcode.PICK + Opcode.PUSH3 + Opcode.PICK + Opcode.SIGN +
            Opcode.PUSH0 + Opcode.JMPGT +
            Integer(5).to_byte_array(signed=True, min_length=1) + Opcode.GT +
            Opcode.JMP + Integer(3).to_byte_array(signed=True, min_length=1) +
            Opcode.LT + Opcode.JMPIF +
            Integer(-19).to_byte_array(signed=True, min_length=1) +
            Opcode.DROP + Opcode.DROP + Opcode.DROP + Opcode.STLOC0 +
            Opcode.LDLOC0  # return a[:3]
            + Opcode.PUSH3  # slice end
            + Opcode.DUP + Opcode.SIGN + Opcode.PUSHM1 + Opcode.JMPNE +
            Integer(5).to_byte_array(min_length=1, signed=True) + Opcode.OVER +
            Opcode.SIZE + Opcode.ADD + Opcode.PUSH0 + Opcode.SWAP +
            Opcode.NEWARRAY0  # slice
            + Opcode.PUSH2 + Opcode.PICK  # index
            + Opcode.JMP  # while index < end
            + Integer(32).to_byte_array(min_length=1) +
            Opcode.DUP  # if index >= slice start
            + Opcode.PUSH4 + Opcode.PICK + Opcode.GE + Opcode.JMPIFNOT +
            Integer(25).to_byte_array(min_length=1) +
            Opcode.OVER  # slice.append(array[index])
            + Opcode.PUSH5 + Opcode.PICK + Opcode.PUSH2 + Opcode.PICK +
            Opcode.DUP + Opcode.SIGN + Opcode.PUSHM1 + Opcode.JMPNE +
            Integer(5).to_byte_array(min_length=1) + Opcode.OVER +
            Opcode.SIZE + Opcode.ADD + Opcode.PICKITEM + Opcode.OVER +
            Opcode.ISTYPE + Type.bytearray.stack_item + Opcode.JMPIFNOT +
            Integer(5).to_byte_array(signed=True, min_length=1) + Opcode.CAT +
            Opcode.JMP + Integer(5).to_byte_array(min_length=1) +
            Opcode.APPEND + Opcode.INC  # index += 1
            + Opcode.DUP + Opcode.PUSH3 + Opcode.PICK + Opcode.LT +
            Opcode.JMPIF  # end while index < slice end
            + Integer(-34).to_byte_array(min_length=1) + Opcode.DROP +
            Opcode.REVERSE4 + Opcode.DROP + Opcode.DROP + Opcode.DROP +
            Opcode.RET  # return
        )
        path = self.get_contract_path('RangeSlicingStartOmitted.py')
        output = Boa3.compile(path)
        self.assertEqual(expected_output, output)

        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'Main')
        self.assertEqual([0, 1, 2], result)

    def test_range_slicing_omitted(self):
        expected_output = (
            Opcode.INITSLOT  # function signature
            + b'\x01' + b'\x00' + Opcode.PUSH1  # range(6)
            + Opcode.PUSH0 + Opcode.PUSH6 + Opcode.PUSH2 + Opcode.PICK +
            Opcode.SIGN + Opcode.JMPIF +
            Integer(5 + len(self.RANGE_ERROR_MESSAGE)).to_byte_array(
                signed=True, min_length=1) + Opcode.PUSHDATA1 +
            Integer(len(self.RANGE_ERROR_MESSAGE)).to_byte_array(
                signed=True, min_length=1) + self.RANGE_ERROR_MESSAGE +
            Opcode.THROW + Opcode.NEWARRAY0 + Opcode.REVERSE4 + Opcode.SWAP +
            Opcode.JMP + Integer(8).to_byte_array(signed=True, min_length=1) +
            Opcode.PUSH3 + Opcode.PICK + Opcode.OVER + Opcode.APPEND +
            Opcode.OVER + Opcode.ADD + Opcode.DUP + Opcode.PUSH3 +
            Opcode.PICK + Opcode.PUSH3 + Opcode.PICK + Opcode.SIGN +
            Opcode.PUSH0 + Opcode.JMPGT +
            Integer(5).to_byte_array(signed=True, min_length=1) + Opcode.GT +
            Opcode.JMP + Integer(3).to_byte_array(signed=True, min_length=1) +
            Opcode.LT + Opcode.JMPIF +
            Integer(-19).to_byte_array(signed=True, min_length=1) +
            Opcode.DROP + Opcode.DROP + Opcode.DROP + Opcode.STLOC0 +
            Opcode.LDLOC0  # return a[:]
            + Opcode.UNPACK + Opcode.PACK + Opcode.RET  # return
        )
        path = self.get_contract_path('RangeSlicingOmitted.py')
        output = Boa3.compile(path)
        self.assertEqual(expected_output, output)

        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'Main')
        self.assertEqual([0, 1, 2, 3, 4, 5], result)

    def test_range_slicing_end_omitted(self):
        path = self.get_contract_path('RangeSlicingEndOmitted.py')

        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'Main')
        self.assertEqual([2, 3, 4, 5], result)

    def test_range_slicing_omitted_stride(self):
        path = self.get_contract_path('RangeSlicingWithStride.py')
        self.assertCompilerLogs(InternalError, path)

    def test_range_slicing_omitted_with_stride(self):
        path = self.get_contract_path('RangeSlicingOmittedWithStride.py')
        self.assertCompilerLogs(InternalError, path)

    def test_boa2_range_test(self):
        path = self.get_contract_path('RangeBoa2Test.py')
        engine = TestEngine()
        result = self.run_smart_contract(engine, path, 'main')
        self.assertEqual(list(range(100, 120)), result)
Exemplo n.º 19
0
    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 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)
        wrapped_neo_address = engine.executed_script_hash.to_array()

        # 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])
        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])
        self.assertEqual(True, result)
        transfer_events = engine.get_events('Transfer',
                                            origin=wrapped_neo_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(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])
        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)
Exemplo n.º 20
0
    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)
Exemplo n.º 21
0
    def test_wrapped_neo_on_nep17_payment(self):
        path = self.get_contract_path('wrapped_neo.py')
        aux_path = self.get_contract_path('examples/auxiliary_contracts',
                                          'auxiliary_contract.py')
        engine = TestEngine()

        self.run_smart_contract(engine, path, 'symbol')
        wrapped_neo_address = engine.executed_script_hash.to_array()
        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'))
        minted_amount = 10 * 10**8
        engine.add_neo(aux_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_address,
                                    minted_amount,
                                    None,
                                    signer_accounts=[aux_address])

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

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

        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(wrapped_neo_address, receiver)
        self.assertEqual(minted_amount, amount)

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

        sender, receiver, amount = wrapped_token_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)
        self.assertEqual(minted_amount, amount)

        # balance after burning
        neo_wrapped_after = self.run_smart_contract(engine,
                                                    constants.NEO_SCRIPT,
                                                    'balanceOf',
                                                    wrapped_neo_address)
        neo_aux_after = self.run_smart_contract(engine, constants.NEO_SCRIPT,
                                                'balanceOf', aux_address)
        zneo_aux_after = self.run_smart_contract(engine, path, 'balanceOf',
                                                 aux_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)
Exemplo n.º 22
0
    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)
Exemplo n.º 23
0
    def storage_put(self, key: Union[str, bytes], value: Any):
        if isinstance(key, str):
            key = String(key).to_bytes()

        self._storage[key] = value
Exemplo n.º 24
0
    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)
        # when deploying, the contract will mint tokens to the owner
        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(None, sender)
        self.assertEqual(self.OWNER_SCRIPT_HASH, receiver)
        self.assertEqual(10_000_000 * 100_000_000, amount)

        # 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(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],
            expected_result_type=bool)
        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)
Exemplo n.º 25
0
    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)