def test_script_hash_variable_with_builtin(self): from boa3.neo3.contracts import CallFlags call_flag = Integer(CallFlags.ALL).to_byte_array(signed=True, min_length=1) twenty = Integer(20).to_byte_array() base58_identifier = String(Interop.Base58Decode.method_name).to_bytes() expected_output = ( Opcode.INITSLOT + b'\x00\x01' + Opcode.LDARG0 + Opcode.DUP + Opcode.SIZE + Opcode.JMPIFNOT + Integer(47).to_byte_array(min_length=1) + Opcode.DUP + Opcode.ISTYPE + Type.str.stack_item + Opcode.JMPIF + Integer(4).to_byte_array(min_length=1) + Opcode.CONVERT + Type.str.stack_item + Opcode.PUSH1 + Opcode.PACK + Opcode.PUSHDATA1 + Integer(len(base58_identifier)).to_byte_array(min_length=1) + base58_identifier + Opcode.PUSHDATA1 + Integer(len(STD_LIB_SCRIPT)).to_byte_array(min_length=1) + STD_LIB_SCRIPT + Opcode.PUSHDATA1 + Integer(len(call_flag)).to_byte_array(min_length=1) + call_flag + Opcode.ROT + Opcode.ROT + Opcode.SYSCALL + Interop.CallContract.interop_method_hash + Opcode.DUP + Opcode.SIZE + Opcode.PUSHDATA1 + Integer(len(twenty)).to_byte_array(min_length=1) + twenty + Opcode.CONVERT + Type.int.stack_item + Opcode.JMPGT + Integer(8).to_byte_array(min_length=1) + Opcode.DUP + Opcode.SIZE + Opcode.DEC + Opcode.RIGHT + Opcode.JMP + Integer(9).to_byte_array(min_length=1) + Opcode.PUSH1 + Opcode.PUSHDATA1 + Integer(len(twenty)).to_byte_array(min_length=1) + twenty + Opcode.CONVERT + Type.int.stack_item + Opcode.SUBSTR + Opcode.CONVERT + Type.bytes.stack_item + Opcode.RET) path = self.get_contract_path('ScriptHashVariableBuiltinCall.py') output = Boa3.compile(path) self.assertEqual(expected_output, output) from boa3.neo import to_script_hash from base58 import b58encode engine = TestEngine() script_hash = to_script_hash('123') result = self.run_smart_contract(engine, path, 'Main', '123', expected_result_type=bytes) self.assertEqual(script_hash, result) value = b58encode('123') if isinstance(value, int): value = Integer(value).to_byte_array() script_hash = to_script_hash(value) result = self.run_smart_contract(engine, path, 'Main', value, expected_result_type=bytes) self.assertEqual(script_hash, result)
def test_bytes_script_hash(self): from boa3.neo import cryptography, to_script_hash input = b'\x01\x02\x03' expected_output = cryptography.hash160(input) output = to_script_hash(input) self.assertEqual(expected_output, output)
def test_string_script_hash(self): from boa3.neo import cryptography, to_script_hash input = String('123').to_bytes() expected_output = cryptography.hash160(input) output = to_script_hash(input) self.assertEqual(expected_output, output)
def test_integer_script_hash(self): from boa3.neo import cryptography, to_script_hash input = Integer(123).to_byte_array() expected_output = cryptography.hash160(input) output = to_script_hash(input) self.assertEqual(expected_output, output)
def test_string_script_hash(self): import base58 from boa3.neo import to_script_hash input = String('123').to_bytes() expected_output = base58.b58decode(input)[1:] output = to_script_hash(input) self.assertEqual(expected_output, output)
def test_script_hash_variable_with_builtin(self): path = self.get_contract_path('ScriptHashVariableBuiltinCall.py') from boa3.neo import to_script_hash from base58 import b58encode engine = TestEngine() script_hash = to_script_hash('123') result = self.run_smart_contract(engine, path, 'Main', '123', expected_result_type=bytes) self.assertEqual(script_hash, result) value = b58encode('123') if isinstance(value, int): value = Integer(value).to_byte_array() script_hash = to_script_hash(value) result = self.run_smart_contract(engine, path, 'Main', value, expected_result_type=bytes) self.assertEqual(script_hash, result)
def test_script_hash_str_with_builtin(self): from boa3.neo import to_script_hash script_hash = to_script_hash(String('123').to_bytes()) path = self.get_contract_path('ScriptHashStrBuiltinCall.py') output = Boa3.compile(path) engine = TestEngine() result = self.run_smart_contract(engine, path, 'Main') self.assertEqual(script_hash, result)
def test_script_hash_int_with_builtin(self): from boa3.neo import to_script_hash script_hash = to_script_hash(Integer(123).to_byte_array()) path = self.get_contract_path('ScriptHashIntBuiltinCall.py') output = Boa3.compile(path) engine = TestEngine() result = self.run_smart_contract(engine, path, 'Main') self.assertEqual(script_hash, result)
def test_script_hash_str(self): from boa3.neo import to_script_hash script_hash = to_script_hash(String('123').to_bytes()) path = self.get_contract_path('ScriptHashStr.py') output = Boa3.compile(path) engine = TestEngine() result = self.run_smart_contract(engine, path, 'Main', expected_result_type=bytes) self.assertEqual(script_hash, result)
def test_address_script_hash(self): from base58 import b58decode from boa3.neo import cryptography, to_script_hash input = String('Nd7eAuHsKvvzHzSPyuJQALcYCcUrcwvm5W').to_bytes() expected_output = b58decode(input)[1:21] wrong_output = cryptography.hash160(input) output = to_script_hash(input) self.assertNotEqual(wrong_output, output) self.assertEqual(expected_output, output)
def test_check_witness_imported_as(self): path = self.get_contract_path('CheckWitnessImportedAs.py') account = to_script_hash(b'NiNmXL8FjEUEs1nfX9uHFBNaenxDHJtmuB') engine = TestEngine() result = self.run_smart_contract(engine, path, 'Main', account) self.assertEqual(False, result) engine.add_signer_account(account) result = self.run_smart_contract(engine, path, 'Main', account) self.assertEqual(True, result)
def visit_Call(self, call: ast.Call) -> ast.AST: """ Visitor of a function call node :param call: the python ast function call node """ if isinstance(call.func, ast.Attribute): from boa3.model.builtin.builtin import Builtin if call.func.attr == Builtin.ScriptHash.identifier: from boa3.constants import SYS_VERSION_INFO from boa3.model.type.type import Type types = { Type.int.identifier: int, Type.str.identifier: str, Type.bytes.identifier: bytes } literal: tuple = ((ast.Constant, ) if SYS_VERSION_INFO >= (3, 8) else (ast.Num, ast.Str, ast.Bytes)) if isinstance(call.func.value, literal) and len( call.args) == 0: value = ast.literal_eval(call.func.value) if not isinstance(value, tuple(types.values())): return call elif (isinstance(call.func.value, ast.Name) # checks if is the name of a type and call.func.value.id in types # and if the arguments is from the same type and len(call.args) == 1 and isinstance(call.args[0], literal)): value = ast.literal_eval(call.args[0]) if not isinstance(value, (types[call.func.value.id], )): return call else: return call from boa3.neo import to_script_hash # value must be bytes if isinstance(value, int): from boa3.neo.vm.type.Integer import Integer value = Integer(value).to_byte_array() elif isinstance(value, str): from boa3.neo.vm.type.String import String value = String(value).to_bytes() return self.parse_to_node(str(to_script_hash(value)), call) return call
def test_script_hash_variable(self): path = self.get_contract_path('ScriptHashVariable.py') engine = TestEngine() with self.assertRaises(TestExecutionException): self.run_smart_contract(engine, path, 'Main', 123) from boa3.neo import to_script_hash from base58 import b58encode value = b58encode(Integer(123).to_byte_array()) if isinstance(value, int): value = Integer(value).to_byte_array() script_hash = to_script_hash(value) result = self.run_smart_contract(engine, path, 'Main', value, expected_result_type=bytes) self.assertEqual(script_hash, result)
class TestHTLCTemplate(BoaTest): default_folder: str = 'examples' OWNER_SCRIPT_HASH = bytes(20) OTHER_ACCOUNT_1 = to_script_hash(b'NiNmXL8FjEUEs1nfX9uHFBNaenxDHJtmuB') OTHER_ACCOUNT_2 = bytes(range(20)) def test_HTLC_compile(self): path = self.get_contract_path('HTLC.py') Boa3.compile(path) def test_HTLC_deploy(self): path = self.get_contract_path('HTLC.py') engine = TestEngine() # deploying the smart contract result = self.run_smart_contract( engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # deploy can not occur more than once result = self.run_smart_contract( engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(False, result) def test_HTLC_atomic_swap(self): path = self.get_contract_path('HTLC.py') engine = TestEngine() # can not atomic_swap() without deploying first result = self.run_smart_contract( engine, path, 'atomic_swap', self.OWNER_SCRIPT_HASH, NEO_SCRIPT, 10 * 10**8, self.OTHER_ACCOUNT_1, GAS_SCRIPT, 10000 * 10**8, hash160(String('unit test').to_bytes()), signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(False, result) # deploying contract result = self.run_smart_contract( engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # starting atomic swap by using the atomic_swap method result = self.run_smart_contract( engine, path, 'atomic_swap', self.OWNER_SCRIPT_HASH, NEO_SCRIPT, 10 * 10**8, self.OTHER_ACCOUNT_1, GAS_SCRIPT, 10000 * 10**8, hash160(String('unit test').to_bytes()), signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) def test_HTLC_onNEP17Payment(self): path = self.get_contract_path('HTLC.py') engine = TestEngine() transferred_amount_neo = 10 * 10**8 transferred_amount_gas = 10000 * 10**8 output, manifest = self.compile_and_save(path) htlc_address = hash160(output) aux_path = self.get_contract_path('examples/test_native', 'auxiliary_contract.py') output, manifest = self.compile_and_save(aux_path) aux_address = hash160(output) aux_path2 = self.get_contract_path('examples/test_native', 'auxiliary_contract_2.py') output, manifest = self.compile_and_save(aux_path2) aux_address2 = hash160(output) engine.add_neo(aux_address, transferred_amount_neo) engine.add_gas(aux_address2, transferred_amount_gas) # deploying contract result = self.run_smart_contract( engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # starting atomic swap result = self.run_smart_contract( engine, path, 'atomic_swap', aux_address, NEO_SCRIPT, transferred_amount_neo, aux_address2, GAS_SCRIPT, transferred_amount_gas, hash160(String('unit test').to_bytes()), signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # transfer wil be aborted at onPayment if the transfer is not valid with self.assertRaises(TestExecutionException, msg=self.ABORTED_CONTRACT_MSG): self.run_smart_contract(engine, aux_path, 'calling_transfer', NEO_SCRIPT, aux_address, htlc_address, transferred_amount_neo - 100, None, signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) # since the transfer was aborted, it was not registered in the events transfer_events = engine.get_events('Transfer') self.assertEqual(0, len(transfer_events)) # saving the balance to compare after the transfer balance_neo_sender_before = self.run_smart_contract( engine, NEO_SCRIPT, 'balanceOf', aux_address) balance_neo_receiver_before = self.run_smart_contract( engine, NEO_SCRIPT, 'balanceOf', htlc_address) # this transfer will be accepted result = self.run_smart_contract(engine, aux_path, 'calling_transfer', NEO_SCRIPT, aux_address, htlc_address, transferred_amount_neo, None, signer_accounts=[aux_address], expected_result_type=bool) self.assertEqual(True, result) # transfer was accepted so it was registered transfer_events = engine.get_events('Transfer') self.assertEqual(1, len(transfer_events)) self.assertEqual(3, len(transfer_events[0].arguments)) sender, receiver, amount = transfer_events[0].arguments if isinstance(sender, str): sender = String(sender).to_bytes() if isinstance(receiver, str): receiver = String(receiver).to_bytes() self.assertEqual(aux_address, sender) self.assertEqual(htlc_address, receiver) self.assertEqual(transferred_amount_neo, amount) # saving the balance after to compare with the balance before the transfer balance_neo_sender_after = self.run_smart_contract( engine, NEO_SCRIPT, 'balanceOf', aux_address) balance_neo_receiver_after = self.run_smart_contract( engine, NEO_SCRIPT, 'balanceOf', htlc_address) self.assertEqual(balance_neo_sender_before - transferred_amount_neo, balance_neo_sender_after) self.assertEqual(balance_neo_receiver_before + transferred_amount_neo, balance_neo_receiver_after) # transfer won't be accepted, because amount is wrong with self.assertRaises(TestExecutionException, msg=self.ABORTED_CONTRACT_MSG): self.run_smart_contract(engine, aux_path2, 'calling_transfer', GAS_SCRIPT, aux_address2, htlc_address, transferred_amount_gas - 100, None, signer_accounts=[aux_address2], expected_result_type=bool) transfer_events = engine.get_events('Transfer') # the NEO transfer self.assertEqual(1, len(transfer_events)) # saving the balance to compare after the transfer balance_gas_sender_before = self.run_smart_contract( engine, GAS_SCRIPT, 'balanceOf', aux_address2) balance_gas_receiver_before = self.run_smart_contract( engine, GAS_SCRIPT, 'balanceOf', htlc_address) # this transfer will be accepted result = self.run_smart_contract(engine, aux_path2, 'calling_transfer', GAS_SCRIPT, aux_address2, htlc_address, transferred_amount_gas, None, signer_accounts=[aux_address2], expected_result_type=bool) self.assertEqual(True, result) # the transfer was accepted so it was registered transfer_events = engine.get_events('Transfer') self.assertEqual(2, len(transfer_events)) self.assertEqual(3, len(transfer_events[1].arguments)) sender, receiver, amount = transfer_events[1].arguments if isinstance(sender, str): sender = String(sender).to_bytes() if isinstance(receiver, str): receiver = String(receiver).to_bytes() self.assertEqual(aux_address2, sender) self.assertEqual(htlc_address, receiver) self.assertEqual(transferred_amount_gas, amount) # saving the balance after to compare with the balance before the transfer balance_gas_sender_after = self.run_smart_contract( engine, GAS_SCRIPT, 'balanceOf', aux_address2) balance_gas_receiver_after = self.run_smart_contract( engine, GAS_SCRIPT, 'balanceOf', htlc_address) self.assertEqual(balance_gas_sender_before - transferred_amount_gas, balance_gas_sender_after) self.assertEqual(balance_gas_receiver_before + transferred_amount_gas, balance_gas_receiver_after) def test_HTLC_withdraw(self): path = self.get_contract_path('HTLC.py') engine = TestEngine() transferred_amount_neo = 10 * 10**8 transferred_amount_gas = 10000 * 10**8 output, manifest = self.compile_and_save(path) htlc_address = hash160(output) aux_path = self.get_contract_path('examples/test_native', 'auxiliary_contract.py') output, manifest = self.compile_and_save(aux_path) aux_address = hash160(output) aux_path2 = self.get_contract_path('examples/test_native', 'auxiliary_contract_2.py') output, manifest = self.compile_and_save(aux_path2) aux_address2 = hash160(output) engine.add_neo(aux_address, transferred_amount_neo) engine.add_gas(aux_address2, transferred_amount_gas) # deploying smart contract result = self.run_smart_contract( engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # saving the balance to compare after the withdraw balance_neo_person_a_before = self.run_smart_contract( engine, NEO_SCRIPT, 'balanceOf', aux_address) balance_neo_person_b_before = self.run_smart_contract( engine, NEO_SCRIPT, 'balanceOf', aux_address2) balance_neo_htlc_before = self.run_smart_contract( engine, NEO_SCRIPT, 'balanceOf', htlc_address) balance_gas_person_a_before = self.run_smart_contract( engine, GAS_SCRIPT, 'balanceOf', aux_address) balance_gas_person_b_before = self.run_smart_contract( engine, GAS_SCRIPT, 'balanceOf', aux_address2) balance_gas_htlc_before = self.run_smart_contract( engine, GAS_SCRIPT, 'balanceOf', htlc_address) # starting atomic swap by using the atomic_swap method result = self.run_smart_contract( engine, path, 'atomic_swap', aux_address, NEO_SCRIPT, transferred_amount_neo, aux_address2, GAS_SCRIPT, transferred_amount_gas, hash160(String('unit test').to_bytes()), signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # won't be able to withdraw, because no one transferred cryptocurrency to the smart contract result = self.run_smart_contract(engine, path, 'withdraw', 'unit test', signer_accounts=[aux_address], expected_result_type=bool) self.assertEqual(False, result) result = self.run_smart_contract(engine, aux_path, 'calling_transfer', NEO_SCRIPT, aux_address, htlc_address, transferred_amount_neo, None, signer_accounts=[aux_address], expected_result_type=bool) self.assertEqual(True, result) transfer_events = engine.get_events('Transfer') self.assertEqual(1, len(transfer_events)) result = self.run_smart_contract(engine, aux_path2, 'calling_transfer', GAS_SCRIPT, aux_address2, htlc_address, transferred_amount_gas, None, signer_accounts=[aux_address2], expected_result_type=bool) self.assertEqual(True, result) transfer_events = engine.get_events('Transfer') self.assertEqual(2, len(transfer_events)) # the withdraw will fail, because the secret is wrong result = self.run_smart_contract(engine, path, 'withdraw', 'wrong one', signer_accounts=[aux_address], expected_result_type=bool) self.assertEqual(False, result) # the withdraw will occur result = self.run_smart_contract( engine, path, 'withdraw', 'unit test', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # the transfer were accepted so they were registered transfer_events = engine.get_events('Transfer') self.assertEqual(4, len(transfer_events)) self.assertEqual(3, len(transfer_events[2].arguments)) sender, receiver, amount = transfer_events[2].arguments if isinstance(sender, str): sender = String(sender).to_bytes() if isinstance(receiver, str): receiver = String(receiver).to_bytes() self.assertEqual(htlc_address, sender) self.assertEqual(aux_address, receiver) self.assertEqual(transferred_amount_gas, amount) self.assertEqual(3, len(transfer_events[3].arguments)) sender, receiver, amount = transfer_events[3].arguments if isinstance(sender, str): sender = String(sender).to_bytes() if isinstance(receiver, str): receiver = String(receiver).to_bytes() self.assertEqual(htlc_address, sender) self.assertEqual(aux_address2, receiver) self.assertEqual(transferred_amount_neo, amount) # saving the balance after to compare with the balance before the transfer balance_neo_person_a_after = self.run_smart_contract( engine, NEO_SCRIPT, 'balanceOf', aux_address) balance_neo_person_b_after = self.run_smart_contract( engine, NEO_SCRIPT, 'balanceOf', aux_address2) balance_neo_htlc_after = self.run_smart_contract( engine, NEO_SCRIPT, 'balanceOf', htlc_address) balance_gas_person_a_after = self.run_smart_contract( engine, GAS_SCRIPT, 'balanceOf', aux_address) balance_gas_person_b_after = self.run_smart_contract( engine, GAS_SCRIPT, 'balanceOf', aux_address2) balance_gas_htlc_after = self.run_smart_contract( engine, GAS_SCRIPT, 'balanceOf', htlc_address) self.assertEqual(balance_neo_person_a_before - transferred_amount_neo, balance_neo_person_a_after) self.assertEqual(balance_neo_person_b_before + transferred_amount_neo, balance_neo_person_b_after) self.assertEqual(balance_neo_htlc_before, balance_neo_htlc_after) self.assertEqual(balance_gas_person_a_before + transferred_amount_gas, balance_gas_person_a_after) self.assertEqual(balance_gas_person_b_before - transferred_amount_gas, balance_gas_person_b_after) self.assertEqual(balance_gas_htlc_before, balance_gas_htlc_after) def test_HTLC_refund(self): path = self.get_contract_path('HTLC.py') engine = TestEngine() transferred_amount_neo = 10 * 10**8 transferred_amount_gas = 10000 * 10**8 output, manifest = self.compile_and_save(path) htlc_address = hash160(output) aux_path = self.get_contract_path('examples/test_native', 'auxiliary_contract.py') output, manifest = self.compile_and_save(aux_path) aux_address = hash160(output) aux_path2 = self.get_contract_path('examples/test_native', 'auxiliary_contract_2.py') output, manifest = self.compile_and_save(aux_path2) aux_address2 = hash160(output) engine.add_neo(aux_address, transferred_amount_neo) engine.add_gas(aux_address2, transferred_amount_gas) result = self.run_smart_contract( engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) result = self.run_smart_contract( engine, path, 'atomic_swap', aux_address, NEO_SCRIPT, transferred_amount_neo, aux_address2, GAS_SCRIPT, transferred_amount_gas, hash160(String('unit test').to_bytes()), signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # won't be able to refund, because not enough time has passed result = self.run_smart_contract( engine, path, 'refund', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(False, result) # this simulates a new block in the blockchain # get_time only changes value when a new block enters the blockchain engine.increase_block() # will be able to refund, because enough time has passed result = self.run_smart_contract(engine, path, 'refund', signer_accounts=[aux_address], expected_result_type=bool) self.assertEqual(True, result) transfer_events: List[Notification] = [] # no one transferred cryptocurrency to the contract, so no one was refunded and no Transfer occurred # removing possible GAS minting from the List for k in engine.get_events('Transfer'): if k.arguments[0] is not None: transfer_events.append(k) self.assertEqual(0, len(transfer_events)) # starting atomic swap by using the atomic_swap method result = self.run_smart_contract( engine, path, 'atomic_swap', aux_address, NEO_SCRIPT, transferred_amount_neo, aux_address2, GAS_SCRIPT, transferred_amount_gas, hash160(String('unit test').to_bytes()), signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) result = self.run_smart_contract(engine, aux_path, 'calling_transfer', NEO_SCRIPT, aux_address, htlc_address, transferred_amount_neo, None, signer_accounts=[aux_address], expected_result_type=bool) self.assertEqual(True, result) for k in engine.get_events('Transfer'): if k.arguments[0] is not None: transfer_events.append(k) self.assertEqual(1, len(transfer_events)) self.assertEqual(3, len(transfer_events[0].arguments)) engine.increase_block() # will be able to refund, because enough time has passed result = self.run_smart_contract(engine, path, 'refund', signer_accounts=[aux_address], expected_result_type=bool) self.assertEqual(True, result) # OWNER transferred cryptocurrency to the contract, so only he will be refunded transfer_events = [] # removing possible GAS minting from the List for k in engine.get_events('Transfer'): if k.arguments[0] is not None: transfer_events.append(k) self.assertEqual(2, len(transfer_events)) self.assertEqual(3, len(transfer_events[1].arguments)) # HTLC returning the tokens sender, receiver, amount = transfer_events[1].arguments if isinstance(sender, str): sender = String(sender).to_bytes() if isinstance(receiver, str): receiver = String(receiver).to_bytes() self.assertEqual(htlc_address, sender) self.assertEqual(aux_address, receiver) self.assertEqual(transferred_amount_neo, amount) result = self.run_smart_contract( engine, path, 'atomic_swap', aux_address, NEO_SCRIPT, transferred_amount_neo, aux_address2, GAS_SCRIPT, transferred_amount_gas, hash160(String('unit test').to_bytes()), signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) result = self.run_smart_contract(engine, aux_path, 'calling_transfer', NEO_SCRIPT, aux_address, htlc_address, transferred_amount_neo, None, signer_accounts=[aux_address], expected_result_type=bool) self.assertEqual(True, result) transfer_events = [] for k in engine.get_events('Transfer'): if k.arguments[0] is not None: transfer_events.append(k) self.assertEqual(3, len(transfer_events)) self.assertEqual(3, len(transfer_events[2].arguments)) result = self.run_smart_contract(engine, aux_path2, 'calling_transfer', GAS_SCRIPT, aux_address2, htlc_address, transferred_amount_gas, None, signer_accounts=[aux_address2], expected_result_type=bool) self.assertEqual(True, result) transfer_events = [] for k in engine.get_events('Transfer'): if k.arguments[0] is not None: transfer_events.append(k) self.assertEqual(4, len(transfer_events)) self.assertEqual(3, len(transfer_events[3].arguments)) engine.increase_block() # will be able to refund, because enough time has passed result = self.run_smart_contract(engine, path, 'refund', signer_accounts=[aux_address], expected_result_type=bool) self.assertEqual(True, result) # OWNER and OTHER_ACCOUNT transferred cryptocurrency to the contract, so they both will be refunded transfer_events = [] # removing possible GAS minting from the List for k in engine.get_events('Transfer'): if k.arguments[0] is not None: transfer_events.append(k) self.assertEqual(6, len(transfer_events)) self.assertEqual(3, len(transfer_events[4].arguments)) self.assertEqual(3, len(transfer_events[5].arguments)) sender, receiver, amount = transfer_events[4].arguments if isinstance(sender, str): sender = String(sender).to_bytes() if isinstance(receiver, str): receiver = String(receiver).to_bytes() self.assertEqual(htlc_address, sender) self.assertEqual(aux_address, receiver) self.assertEqual(transferred_amount_neo, amount) sender, receiver, amount = transfer_events[5].arguments if isinstance(sender, str): sender = String(sender).to_bytes() if isinstance(receiver, str): receiver = String(receiver).to_bytes() self.assertEqual(htlc_address, sender) self.assertEqual(aux_address2, receiver) self.assertEqual(transferred_amount_gas, amount)
class TestTemplate(BoaTest): default_folder: str = 'examples' OWNER_SCRIPT_HASH = bytes(20) OTHER_ACCOUNT_1 = to_script_hash(b'NiNmXL8FjEUEs1nfX9uHFBNaenxDHJtmuB') OTHER_ACCOUNT_2 = bytes(range(20)) def test_wrapped_neo_compile(self): path = self.get_contract_path('wrapped_neo.py') Boa3.compile(path) def test_wrapped_neo_deploy(self): path = self.get_contract_path('wrapped_neo.py') engine = TestEngine() # needs the owner signature result = self.run_smart_contract(engine, path, method='deploy', expected_result_type=bool) self.assertEqual(False, result) # should return false if the signature isn't from the owner result = self.run_smart_contract( engine, path, 'deploy', signer_accounts=[self.OTHER_ACCOUNT_1], expected_result_type=bool) self.assertEqual(False, result) result = self.run_smart_contract( engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # must always return false after first execution result = self.run_smart_contract( engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(False, result) def test_wrapped_neo_symbol(self): path = self.get_contract_path('wrapped_neo.py') engine = TestEngine() result = self.run_smart_contract(engine, path, 'symbol') self.assertEqual('zNEO', result) def test_wrapped_neo_decimals(self): path = self.get_contract_path('wrapped_neo.py') engine = TestEngine() result = self.run_smart_contract(engine, path, 'decimals') self.assertEqual(8, result) def test_wrapped_neo_total_supply(self): total_supply = 10_000_000 * 10**8 path = self.get_contract_path('wrapped_neo.py') engine = TestEngine() result = self.run_smart_contract(engine, path, 'totalSupply') self.assertEqual(0, result) result = self.run_smart_contract( engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) result = self.run_smart_contract(engine, path, 'totalSupply') self.assertEqual(total_supply, result) def test_wrapped_neo_total_balance_of(self): total_supply = 10_000_000 * 10**8 path = self.get_contract_path('wrapped_neo.py') engine = TestEngine() result = self.run_smart_contract(engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) self.assertEqual(0, result) result = self.run_smart_contract( engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) result = self.run_smart_contract(engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) self.assertEqual(total_supply, result) # should fail when the script length is not 20 with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'balanceOf', bytes(10)) with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'balanceOf', bytes(30)) @unittest.skip( 'Examples need to be changed to test with the latest Neo version') def test_wrapped_neo_total_transfer(self): transferred_amount = 10 * 10**8 # 10 tokens path = self.get_contract_path('wrapped_neo.py') engine = TestEngine() # should fail before running deploy result = self.run_smart_contract(engine, path, 'transfer', self.OWNER_SCRIPT_HASH, self.OTHER_ACCOUNT_1, transferred_amount, "", expected_result_type=bool) self.assertEqual(False, result) result = self.run_smart_contract( engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # should fail if the sender doesn't sign result = self.run_smart_contract(engine, path, 'transfer', self.OWNER_SCRIPT_HASH, self.OTHER_ACCOUNT_1, transferred_amount, "", expected_result_type=bool) self.assertEqual(False, result) # should fail if the sender doesn't have enough balance result = self.run_smart_contract( engine, path, 'transfer', self.OTHER_ACCOUNT_1, self.OWNER_SCRIPT_HASH, transferred_amount, "", signer_accounts=[self.OTHER_ACCOUNT_1], expected_result_type=bool) self.assertEqual(False, result) # should fail when any of the scripts' length is not 20 with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'transfer', self.OWNER_SCRIPT_HASH, bytes(10), transferred_amount, "") with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'transfer', bytes(10), self.OTHER_ACCOUNT_1, transferred_amount, "") # should fail when the amount is less than 0 with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'transfer', self.OTHER_ACCOUNT_1, self.OWNER_SCRIPT_HASH, -10, "") # fire the transfer event when transferring to yourself balance_before = self.run_smart_contract(engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) result = self.run_smart_contract( engine, path, 'transfer', self.OWNER_SCRIPT_HASH, self.OWNER_SCRIPT_HASH, transferred_amount, "", signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) transfer_events = engine.get_events('Transfer') self.assertEqual(1, len(transfer_events)) self.assertEqual(3, len(transfer_events[0].arguments)) sender, receiver, amount = transfer_events[0].arguments if isinstance(sender, str): sender = String(sender).to_bytes() if isinstance(receiver, str): receiver = String(receiver).to_bytes() self.assertEqual(self.OWNER_SCRIPT_HASH, sender) self.assertEqual(self.OWNER_SCRIPT_HASH, receiver) self.assertEqual(transferred_amount, amount) # transferring to yourself doesn't change the balance balance_after = self.run_smart_contract(engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) self.assertEqual(balance_before, balance_after) # does fire the transfer event when transferring to someone other than yourself balance_sender_before = self.run_smart_contract( engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) balance_receiver_before = self.run_smart_contract( engine, path, 'balanceOf', self.OTHER_ACCOUNT_1) result = self.run_smart_contract( engine, path, 'transfer', self.OWNER_SCRIPT_HASH, self.OTHER_ACCOUNT_1, transferred_amount, "", signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) transfer_events = engine.get_events('Transfer') self.assertEqual(1, len(transfer_events)) self.assertEqual(3, len(transfer_events[0].arguments)) sender, receiver, amount = transfer_events[0].arguments if isinstance(sender, str): sender = String(sender).to_bytes() if isinstance(receiver, str): receiver = String(receiver).to_bytes() self.assertEqual(self.OWNER_SCRIPT_HASH, sender) self.assertEqual(self.OTHER_ACCOUNT_1, receiver) self.assertEqual(transferred_amount, amount) # transferring to someone other than yourself does change the balance balance_sender_after = self.run_smart_contract(engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) balance_receiver_after = self.run_smart_contract( engine, path, 'balanceOf', self.OTHER_ACCOUNT_1) self.assertEqual(balance_sender_before - transferred_amount, balance_sender_after) self.assertEqual(balance_receiver_before + transferred_amount, balance_receiver_after) def test_wrapped_neo_verify(self): path = self.get_contract_path('wrapped_neo.py') engine = TestEngine() # should fail without signature result = self.run_smart_contract(engine, path, 'verify', expected_result_type=bool) self.assertEqual(False, result) # should fail if not signed by the owner result = self.run_smart_contract( engine, path, 'verify', signer_accounts=[self.OTHER_ACCOUNT_1], expected_result_type=bool) self.assertEqual(False, result) result = self.run_smart_contract( engine, path, 'verify', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) @unittest.skip( 'Examples need to be changed to test with the latest Neo version') def test_wrapped_neo_burn(self): path = self.get_contract_path('wrapped_neo.py') engine = TestEngine() output, manifest = self.compile_and_save(path) wrapped_neo_address = hash160(output) engine.add_neo(wrapped_neo_address, 10_000_000 * 10**8) burned_amount = 100 * 10**8 # deploying this smart contract will give 10m total supply * 10^8 zNEOs to OWNER result = self.run_smart_contract( engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # burning zNEO will end up giving NEO to the one who burned it neo_wrapped_before = self.run_smart_contract(engine, NEO_SCRIPT, 'balanceOf', wrapped_neo_address) neo_owner_before = self.run_smart_contract(engine, NEO_SCRIPT, 'balanceOf', self.OWNER_SCRIPT_HASH) zneo_owner_before = self.run_smart_contract(engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) # in this case, NEO will be given to the OWNER_SCRIPT_HASH result = self.run_smart_contract( engine, path, 'burn', self.OWNER_SCRIPT_HASH, burned_amount, signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertIsVoid(result) transfer_events = engine.get_events('Transfer') self.assertEqual(2, len(transfer_events)) self.assertEqual(3, len(transfer_events[0].arguments)) sender, receiver, amount = transfer_events[0].arguments if isinstance(sender, str): sender = String(sender).to_bytes() if isinstance(receiver, str): receiver = String(receiver).to_bytes() self.assertEqual(self.OWNER_SCRIPT_HASH, sender) self.assertEqual(None, receiver) self.assertEqual(burned_amount, amount) self.assertEqual(3, len(transfer_events[1].arguments)) sender, receiver, amount = transfer_events[1].arguments if isinstance(sender, str): sender = String(sender).to_bytes() if isinstance(receiver, str): receiver = String(receiver).to_bytes() self.assertEqual(wrapped_neo_address, sender) self.assertEqual(self.OWNER_SCRIPT_HASH, receiver) self.assertEqual(burned_amount, amount) # balance after burning neo_wrapped_after = self.run_smart_contract(engine, NEO_SCRIPT, 'balanceOf', wrapped_neo_address) neo_owner_after = self.run_smart_contract(engine, NEO_SCRIPT, 'balanceOf', self.OWNER_SCRIPT_HASH) zneo_owner_after = self.run_smart_contract(engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) self.assertEqual(neo_wrapped_before - burned_amount, neo_wrapped_after) self.assertEqual(neo_owner_before + burned_amount, neo_owner_after) self.assertEqual(zneo_owner_before - burned_amount, zneo_owner_after) # should fail when the script length is not 20 with self.assertRaises(TestExecutionException, msg=self.ABORTED_CONTRACT_MSG): self.run_smart_contract(engine, path, 'burn', bytes(15), burned_amount, signer_accounts=[self.OWNER_SCRIPT_HASH]) # or amount is less than 0 with self.assertRaises(TestExecutionException, msg=self.ABORTED_CONTRACT_MSG): self.run_smart_contract(engine, path, 'burn', self.OWNER_SCRIPT_HASH, -1, signer_accounts=[self.OWNER_SCRIPT_HASH]) def test_wrapped_neo_approve(self): path = self.get_contract_path('wrapped_neo.py') path_aux_contract = self.get_contract_path( 'examples/test_native', 'example_contract_for_wrapped_tokens.py') engine = TestEngine() engine.add_contract(path.replace('.py', '.nef')) output, manifest = self.compile_and_save(path) wrapped_neo_address = hash160(output) output, manifest = self.compile_and_save(path_aux_contract) aux_contract_address = hash160(output) allowed_amount = 10 * 10**8 # this approve will fail, because aux_contract_address doesn't have enough zNEO result = self.run_smart_contract( engine, path_aux_contract, 'calling_approve', wrapped_neo_address, self.OTHER_ACCOUNT_1, allowed_amount, signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(False, result) # deploying this smart contract will give 10m total supply * 10^8 zNEOs to OWNER result = self.run_smart_contract( engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # OWNER will give zNEO to aux_contract_address so that it can approve result = self.run_smart_contract( engine, path, 'transfer', self.OWNER_SCRIPT_HASH, aux_contract_address, allowed_amount, None, signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # this approve will succeed, because aux_contract_address have enough zNEO result = self.run_smart_contract( engine, path_aux_contract, 'calling_approve', wrapped_neo_address, self.OTHER_ACCOUNT_1, allowed_amount, signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # approved fired an event approval_events = engine.get_events('Approval') self.assertEqual(1, len(approval_events)) owner, spender, amount = approval_events[0].arguments if isinstance(owner, str): sender = String(owner).to_bytes() if isinstance(spender, str): receiver = String(spender).to_bytes() self.assertEqual(aux_contract_address, owner) self.assertEqual(self.OTHER_ACCOUNT_1, spender) self.assertEqual(allowed_amount, amount) def test_wrapped_neo_allowance(self): path = self.get_contract_path('wrapped_neo.py') path_aux_contract = self.get_contract_path( 'examples/test_native', 'example_contract_for_wrapped_tokens.py') engine = TestEngine() engine.add_contract(path.replace('.py', '.nef')) output, manifest = self.compile_and_save(path) wrapped_neo_address = hash160(output) output, manifest = self.compile_and_save(path_aux_contract) aux_contract_address = hash160(output) allowed_amount = 10 * 10**8 # aux_contract_address did not approve OTHER_SCRIPT_HASH result = self.run_smart_contract( engine, path, 'allowance', aux_contract_address, self.OTHER_ACCOUNT_1, signer_accounts=[aux_contract_address], expected_result_type=bool) self.assertEqual(0, result) # deploying smart contract result = self.run_smart_contract( engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # OWNER will give zNEO to aux_contract_address so that it can approve result = self.run_smart_contract( engine, path, 'transfer', self.OWNER_SCRIPT_HASH, aux_contract_address, allowed_amount, None, signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # this approve will succeed, because aux_contract_address have enough zNEO result = self.run_smart_contract( engine, path_aux_contract, 'calling_approve', wrapped_neo_address, self.OTHER_ACCOUNT_1, allowed_amount, signer_accounts=[aux_contract_address], expected_result_type=bool) self.assertEqual(True, result) # aux_contract_address allowed OTHER_SCRIPT_HASH to spend transferred_amount of zNEO result = self.run_smart_contract( engine, path, 'allowance', aux_contract_address, self.OTHER_ACCOUNT_1, signer_accounts=[aux_contract_address]) self.assertEqual(allowed_amount, result) @unittest.skip( 'Examples need to be changed to test with the latest Neo version') def test_wrapped_neo_transfer_from(self): path = self.get_contract_path('wrapped_neo.py') path_aux_contract = self.get_contract_path( 'examples/test_native', 'example_contract_for_wrapped_tokens.py') engine = TestEngine() engine.add_contract(path.replace('.py', '.nef')) output, manifest = self.compile_and_save(path) wrapped_neo_address = hash160(output) output, manifest = self.compile_and_save(path_aux_contract) aux_contract_address = hash160(output) allowed_amount = 10 * 10**8 # deploying smart contract result = self.run_smart_contract( engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # OWNER will give zNEO to aux_contract_address so that it can approve another contracts result = self.run_smart_contract( engine, path, 'transfer', self.OWNER_SCRIPT_HASH, aux_contract_address, 10_000_000 * 10**8, None, signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # this approve will succeed, because aux_contract_address have enough zNEO result = self.run_smart_contract( engine, path_aux_contract, 'calling_approve', wrapped_neo_address, self.OTHER_ACCOUNT_1, allowed_amount, signer_accounts=[aux_contract_address], expected_result_type=bool) self.assertEqual(True, result) transferred_amount = allowed_amount # this transfer will fail, # because OTHER_SCRIPT_HASH is not allowed to transfer more than aux_contract_address approved result = self.run_smart_contract( engine, path, 'transfer_from', self.OTHER_ACCOUNT_1, aux_contract_address, self.OTHER_ACCOUNT_2, transferred_amount + 1 * 10**8, None, signer_accounts=[self.OTHER_ACCOUNT_1], expected_result_type=bool) self.assertEqual(False, result) transfer_events = engine.get_events('Transfer') self.assertEqual(0, len(transfer_events)) # this transfer will succeed and will fire the Transfer event balance_spender_before = self.run_smart_contract( engine, path, 'balanceOf', self.OTHER_ACCOUNT_1) balance_sender_before = self.run_smart_contract( engine, path, 'balanceOf', aux_contract_address) balance_receiver_before = self.run_smart_contract( engine, path, 'balanceOf', self.OTHER_ACCOUNT_2) result = self.run_smart_contract( engine, path, 'transfer_from', self.OTHER_ACCOUNT_1, aux_contract_address, self.OTHER_ACCOUNT_2, transferred_amount, None, signer_accounts=[self.OTHER_ACCOUNT_1], expected_result_type=bool) self.assertEqual(True, result) transfer_events = engine.get_events('Transfer') self.assertEqual(1, len(transfer_events)) self.assertEqual(3, len(transfer_events[0].arguments)) sender, receiver, amount = transfer_events[0].arguments if isinstance(sender, str): sender = String(sender).to_bytes() if isinstance(receiver, str): receiver = String(receiver).to_bytes() self.assertEqual(aux_contract_address, sender) self.assertEqual(self.OTHER_ACCOUNT_2, receiver) self.assertEqual(transferred_amount, amount) # transferring changed the balance balance_spender_after = self.run_smart_contract( engine, path, 'balanceOf', self.OTHER_ACCOUNT_1) balance_sender_after = self.run_smart_contract(engine, path, 'balanceOf', aux_contract_address) balance_receiver_after = self.run_smart_contract( engine, path, 'balanceOf', self.OTHER_ACCOUNT_2) self.assertEqual(balance_spender_before, balance_spender_after) self.assertEqual(balance_sender_before - transferred_amount, balance_sender_after) self.assertEqual(balance_receiver_before + transferred_amount, balance_receiver_after) # aux_contract_address and OTHER_SCRIPT_HASH allowance was reduced to 0 result = self.run_smart_contract( engine, path, 'allowance', aux_contract_address, self.OTHER_ACCOUNT_1, signer_accounts=[aux_contract_address], expected_result_type=bool) self.assertEqual(0, result) # this approve will succeed, because aux_contract_address have enough zNEO result = self.run_smart_contract( engine, path_aux_contract, 'calling_approve', wrapped_neo_address, self.OTHER_ACCOUNT_1, allowed_amount, signer_accounts=[aux_contract_address], expected_result_type=bool) self.assertEqual(True, result) transferred_amount = allowed_amount - 4 * 10**8 result = self.run_smart_contract( engine, path, 'transfer_from', self.OTHER_ACCOUNT_1, aux_contract_address, self.OTHER_ACCOUNT_2, transferred_amount, None, signer_accounts=[self.OTHER_ACCOUNT_1], expected_result_type=bool) self.assertEqual(True, result) # aux_contract_address and OTHER_SCRIPT_HASH allowance was reduced to allowed_amount - transferred_amount result = self.run_smart_contract( engine, path, 'allowance', aux_contract_address, self.OTHER_ACCOUNT_1, signer_accounts=[aux_contract_address], expected_result_type=bool) self.assertEqual(allowed_amount - transferred_amount, result) # should fail when any of the scripts' length is not 20 with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'transfer_from', self.OWNER_SCRIPT_HASH, bytes(10), self.OTHER_ACCOUNT_1, allowed_amount, None) with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'transfer_from', bytes(10), self.OTHER_ACCOUNT_1, self.OWNER_SCRIPT_HASH, allowed_amount, None) with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'transfer_from', self.OTHER_ACCOUNT_1, self.OWNER_SCRIPT_HASH, bytes(10), allowed_amount, None) # should fail when the amount is less than 0 with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'transfer_from', self.OTHER_ACCOUNT_1, self.OWNER_SCRIPT_HASH, self.OTHER_ACCOUNT_2, -10, None) @unittest.skip( 'Examples need to be changed to test with the latest Neo version') def test_wrapped_neo_onPayment(self): path = self.get_contract_path('wrapped_neo.py') engine = TestEngine() engine.add_contract(path.replace('.py', '.nef')) output, manifest = self.compile_and_save(path) wrapped_neo_address = hash160(output) aux_contract_address = bytes(range(20)) minted_amount = 10 * 10**8 # deploying wrapped_neo smart contract result = self.run_smart_contract( engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) engine.add_neo(aux_contract_address, minted_amount) # the smart contract will abort if some address other than NEO calls the onPayment method with self.assertRaises(TestExecutionException, msg=self.ABORTED_CONTRACT_MSG): self.run_smart_contract(engine, path, 'onNEP17Payment', aux_contract_address, minted_amount, None, signer_accounts=[aux_contract_address]) neo_wrapped_before = self.run_smart_contract(engine, NEO_SCRIPT, 'balanceOf', wrapped_neo_address) neo_aux_before = self.run_smart_contract(engine, NEO_SCRIPT, 'balanceOf', aux_contract_address) zneo_aux_before = self.run_smart_contract(engine, path, 'balanceOf', aux_contract_address) # transferring NEO to the wrapped_neo_address will mint them result = self.run_smart_contract( engine, NEO_SCRIPT, 'transfer', aux_contract_address, wrapped_neo_address, minted_amount, None, signer_accounts=[aux_contract_address], expected_result_type=bool) self.assertEqual(True, result) transfer_events = engine.get_events('Transfer') self.assertEqual(2, len(transfer_events)) self.assertEqual(3, len(transfer_events[0].arguments)) sender, receiver, amount = transfer_events[0].arguments if isinstance(sender, str): sender = String(sender).to_bytes() if isinstance(receiver, str): receiver = String(receiver).to_bytes() self.assertEqual(aux_contract_address, sender) self.assertEqual(wrapped_neo_address, receiver) self.assertEqual(minted_amount, amount) self.assertEqual(3, len(transfer_events[1].arguments)) sender, receiver, amount = transfer_events[1].arguments if isinstance(sender, str): sender = String(sender).to_bytes() if isinstance(receiver, str): receiver = String(receiver).to_bytes() self.assertEqual(None, sender) self.assertEqual(aux_contract_address, receiver) self.assertEqual(minted_amount, amount) # balance after burning neo_wrapped_after = self.run_smart_contract(engine, NEO_SCRIPT, 'balanceOf', wrapped_neo_address) neo_aux_after = self.run_smart_contract(engine, NEO_SCRIPT, 'balanceOf', aux_contract_address) zneo_aux_after = self.run_smart_contract(engine, path, 'balanceOf', aux_contract_address) self.assertEqual(neo_wrapped_before + minted_amount, neo_wrapped_after) self.assertEqual(neo_aux_before - minted_amount, neo_aux_after) self.assertEqual(zneo_aux_before + minted_amount, zneo_aux_after)
class TestHTLCTemplate(BoaTest): default_folder: str = 'examples' OWNER_SCRIPT_HASH = bytes(20) OTHER_ACCOUNT_1 = to_script_hash(b'NiNmXL8FjEUEs1nfX9uHFBNaenxDHJtmuB') OTHER_ACCOUNT_2 = bytes(range(20)) def test_HTLC_compile(self): path = self.get_contract_path('HTLC.py') Boa3.compile(path) def test_HTLC_deploy(self): path = self.get_contract_path('HTLC.py') engine = TestEngine() # deploying the smart contract result = self.run_smart_contract( engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # deploy can not occur more than once result = self.run_smart_contract( engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(False, result) def test_HTLC_atomic_swap(self): path = self.get_contract_path('HTLC.py') engine = TestEngine() # can not atomic_swap() without deploying first result = self.run_smart_contract( engine, path, 'atomic_swap', self.OWNER_SCRIPT_HASH, NEO, 10 * 10**8, self.OTHER_ACCOUNT_1, GAS, 10000 * 10**8, hash160(String('unit test').to_bytes()), signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(False, result) # deploying contract result = self.run_smart_contract( engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # starting atomic swap by using the atomic_swap method result = self.run_smart_contract( engine, path, 'atomic_swap', self.OWNER_SCRIPT_HASH, NEO, 10 * 10**8, self.OTHER_ACCOUNT_1, GAS, 10000 * 10**8, hash160(String('unit test').to_bytes()), signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) def test_HTLC_onPayment(self): path = self.get_contract_path('HTLC.py') engine = TestEngine() example_contract = self.get_contract_path( 'test_native/example_contract_for_htlc.py') transferred_amount_neo = 10 * 10**8 transferred_amount_gas = 10000 * 10**8 output, manifest = self.compile_and_save(example_contract) contract_address1 = bytes(range(20)) contract_address2 = hash160(output) output, manifest = self.compile_and_save(path) htlc_address = hash160(output) engine.add_neo(contract_address1, transferred_amount_neo) engine.add_gas(contract_address2, transferred_amount_gas) # deploying contract result = self.run_smart_contract( engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # starting atomic swap result = self.run_smart_contract( engine, path, 'atomic_swap', contract_address1, NEO, transferred_amount_neo, contract_address2, GAS, transferred_amount_gas, hash160(String('unit test').to_bytes()), signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # TODO: Test if onPayment is successful when update the TestEngine to make Neo/Gas transfers def test_HTLC_withdraw(self): path = self.get_contract_path('HTLC.py') engine = TestEngine() example_contract = self.get_contract_path( 'test_native/example_contract_for_htlc.py') transferred_amount_neo = 10 * 10**8 transferred_amount_gas = 10000 * 10**8 output, manifest = self.compile_and_save(example_contract) contract_address1 = bytes(range(20)) contract_address2 = hash160(output) output, manifest = self.compile_and_save(path) htlc_address = hash160(output) engine.add_neo(contract_address1, transferred_amount_neo) engine.add_gas(contract_address2, transferred_amount_gas) # deploying smart contract result = self.run_smart_contract( engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # starting atomic swap by using the atomic_swap method result = self.run_smart_contract( engine, path, 'atomic_swap', contract_address1, NEO, transferred_amount_neo, contract_address2, GAS, transferred_amount_gas, hash160(String('unit test').to_bytes()), signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # won't be able to withdraw, because no one transferred cryptocurrency to the smart contract result = self.run_smart_contract( engine, path, 'withdraw', 'unit test', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(False, result) # TODO: Test if the withdraw is successful when update the TestEngine to make Neo/Gas transfers def test_HTLC_refund(self): path = self.get_contract_path('HTLC.py') engine = TestEngine() example_contract = self.get_contract_path( 'test_native/example_contract_for_htlc.py') transferred_amount_neo = 10 * 10**8 transferred_amount_gas = 10000 * 10**8 output, manifest = self.compile_and_save(example_contract) contract_address1 = bytes(range(20)) contract_address2 = hash160(output) output, manifest = self.compile_and_save(path) htlc_address = hash160(output) engine.add_neo(contract_address1, transferred_amount_neo) engine.add_gas(contract_address2, transferred_amount_gas) result = self.run_smart_contract( engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) result = self.run_smart_contract( engine, path, 'atomic_swap', contract_address1, NEO, transferred_amount_neo, contract_address2, GAS, transferred_amount_gas, hash160(String('unit test').to_bytes()), signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # won't be able to refund, because not enough time has passed result = self.run_smart_contract( engine, path, 'refund', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(False, result) # this simulates a new block in the blockchain # get_time only changes value when a new block enters the blockchain engine.increase_block() # will be able to refund, because enough time has passed result = self.run_smart_contract( engine, path, 'refund', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # no one transferred cryptocurrency to the contract, so no one was refunded and no Transfer occurred transfer_events = engine.get_events('Transfer') self.assertEqual(0, len(transfer_events))
class TestNEP17Template(BoaTest): default_folder: str = 'examples' OWNER_SCRIPT_HASH = bytes(20) OTHER_ACCOUNT_1 = to_script_hash(b'NiNmXL8FjEUEs1nfX9uHFBNaenxDHJtmuB') OTHER_ACCOUNT_2 = bytes(range(20)) def test_nep17_compile(self): path = self.get_contract_path('NEP17.py') Boa3.compile(path) def test_nep17_deploy(self): path = self.get_contract_path('NEP17.py') engine = TestEngine() # needs the owner signature result = self.run_smart_contract(engine, path, method='deploy', expected_result_type=bool) self.assertEqual(False, result) # should return false if the signature isn't from the owner result = self.run_smart_contract( engine, path, 'deploy', signer_accounts=[self.OTHER_ACCOUNT_1], expected_result_type=bool) self.assertEqual(False, result) result = self.run_smart_contract( engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # must always return false after first execution result = self.run_smart_contract( engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(False, result) def test_nep17_symbol(self): path = self.get_contract_path('NEP17.py') engine = TestEngine() result = self.run_smart_contract(engine, path, 'symbol') self.assertEqual('NEP17', result) def test_nep17_decimals(self): path = self.get_contract_path('NEP17.py') engine = TestEngine() result = self.run_smart_contract(engine, path, 'decimals') self.assertEqual(8, result) def test_nep17_total_supply(self): total_supply = 10_000_000 * 10**8 path = self.get_contract_path('NEP17.py') engine = TestEngine() result = self.run_smart_contract(engine, path, 'totalSupply') self.assertEqual(0, result) result = self.run_smart_contract( engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) result = self.run_smart_contract(engine, path, 'totalSupply') self.assertEqual(total_supply, result) def test_nep17_total_balance_of(self): total_supply = 10_000_000 * 10**8 path = self.get_contract_path('NEP17.py') engine = TestEngine() result = self.run_smart_contract(engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) self.assertEqual(0, result) result = self.run_smart_contract( engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) result = self.run_smart_contract(engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) self.assertEqual(total_supply, result) # should fail when the script length is not 20 with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'balanceOf', bytes(10)) with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'balanceOf', bytes(30)) def test_nep17_total_transfer(self): transferred_amount = 10 * 10**8 # 10 tokens path = self.get_contract_path('NEP17.py') engine = TestEngine() # should fail before running deploy result = self.run_smart_contract(engine, path, 'transfer', self.OWNER_SCRIPT_HASH, self.OTHER_ACCOUNT_1, transferred_amount, "", expected_result_type=bool) self.assertEqual(False, result) result = self.run_smart_contract( engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # should fail if the sender doesn't sign result = self.run_smart_contract(engine, path, 'transfer', self.OWNER_SCRIPT_HASH, self.OTHER_ACCOUNT_1, transferred_amount, "", expected_result_type=bool) self.assertEqual(False, result) # should fail if the sender doesn't have enough balance result = self.run_smart_contract( engine, path, 'transfer', self.OTHER_ACCOUNT_1, self.OWNER_SCRIPT_HASH, transferred_amount, "", signer_accounts=[self.OTHER_ACCOUNT_1], expected_result_type=bool) self.assertEqual(False, result) # should fail when any of the scripts' length is not 20 with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'transfer', self.OWNER_SCRIPT_HASH, bytes(10), transferred_amount, "") with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'transfer', bytes(10), self.OTHER_ACCOUNT_1, transferred_amount, "") # should fail when the amount is less than 0 with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'transfer', self.OTHER_ACCOUNT_1, self.OWNER_SCRIPT_HASH, -10, "") # fire the transfer event when transferring to yourself balance_before = self.run_smart_contract(engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) result = self.run_smart_contract( engine, path, 'transfer', self.OWNER_SCRIPT_HASH, self.OWNER_SCRIPT_HASH, transferred_amount, "", signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) transfer_events = engine.get_events('Transfer') self.assertEqual(1, len(transfer_events)) self.assertEqual(3, len(transfer_events[0].arguments)) sender, receiver, amount = transfer_events[0].arguments if isinstance(sender, str): sender = String(sender).to_bytes() if isinstance(receiver, str): receiver = String(receiver).to_bytes() self.assertEqual(self.OWNER_SCRIPT_HASH, sender) self.assertEqual(self.OWNER_SCRIPT_HASH, receiver) self.assertEqual(transferred_amount, amount) # transferring to yourself doesn't change the balance balance_after = self.run_smart_contract(engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) self.assertEqual(balance_before, balance_after) # does fire the transfer event balance_sender_before = self.run_smart_contract( engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) balance_receiver_before = self.run_smart_contract( engine, path, 'balanceOf', self.OTHER_ACCOUNT_1) result = self.run_smart_contract( engine, path, 'transfer', self.OWNER_SCRIPT_HASH, self.OTHER_ACCOUNT_1, transferred_amount, "", signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) transfer_events = engine.get_events('Transfer') self.assertEqual(1, len(transfer_events)) self.assertEqual(3, len(transfer_events[0].arguments)) sender, receiver, amount = transfer_events[0].arguments if isinstance(sender, str): sender = String(sender).to_bytes() if isinstance(receiver, str): receiver = String(receiver).to_bytes() self.assertEqual(self.OWNER_SCRIPT_HASH, sender) self.assertEqual(self.OTHER_ACCOUNT_1, receiver) self.assertEqual(transferred_amount, amount) # transferring to someone other than yourself does change the balance balance_sender_after = self.run_smart_contract(engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) balance_receiver_after = self.run_smart_contract( engine, path, 'balanceOf', self.OTHER_ACCOUNT_1) self.assertEqual(balance_sender_before - transferred_amount, balance_sender_after) self.assertEqual(balance_receiver_before + transferred_amount, balance_receiver_after) def test_nep17_onPayment(self): transferred_amount = 10 * 10**8 # 10 tokens path = self.get_contract_path('NEP17.py') engine = TestEngine() engine.add_contract(path.replace('.py', '.nef')) output, manifest = self.compile_and_save(path) nep17_address = hash160(output) test_address = bytes(range(20)) result = self.run_smart_contract( engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) engine.add_neo(test_address, transferred_amount) # fire the Transfer event if sender is NEO when transferring to NEP17 script hash neo_balance_sender_before = self.run_smart_contract( engine, NEO_SCRIPT, 'balanceOf', test_address) neo_balance_nep17_before = self.run_smart_contract( engine, NEO_SCRIPT, 'balanceOf', nep17_address) nep17_balance_sender_before = self.run_smart_contract( engine, path, 'balanceOf', test_address) # TODO: Test if the onPayment method is successful when update the TestEngine to make Neo/Gas transfers def test_nep17_verify(self): path = self.get_contract_path('NEP17.py') engine = TestEngine() # should fail without signature result = self.run_smart_contract(engine, path, 'verify', expected_result_type=bool) self.assertEqual(False, result) # should fail if not signed by the owner result = self.run_smart_contract( engine, path, 'verify', signer_accounts=[self.OTHER_ACCOUNT_1], expected_result_type=bool) self.assertEqual(False, result) result = self.run_smart_contract( engine, path, 'verify', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result)
def Main() -> bytes: return to_script_hash(b'42')
class GhostTest(BoaTest): p = Path(__file__) GHOST_ROOT = str(p.parents[1]) PRJ_ROOT = str(p.parents[2]) CONTRACT_PATH_JSON = GHOST_ROOT+ '/contracts/NEP11/GhostMarket.NFT.manifest.json' CONTRACT_PATH_NEF = GHOST_ROOT + '/contracts/NEP11/GhostMarket.NFT.nef' CONTRACT_PATH_PY = GHOST_ROOT + '/contracts/NEP11/GhostMarket.NFT.py' BOA_PATH = PRJ_ROOT + '/neo3-boa/boa3' OWNER_SCRIPT_HASH = UInt160(to_script_hash(b'NZcuGiwRu1QscpmCyxj5XwQBUf6sk7dJJN')) OTHER_ACCOUNT_1 = UInt160(to_script_hash(b'NiNmXL8FjEUEs1nfX9uHFBNaenxDHJtmuB')) OTHER_ACCOUNT_2 = bytes(range(20)) TOKEN_META = bytes('{ "name": "GHOST", "description": "A ghost shows up", "image": "{some image URI}", "tokenURI": "{some URI}" }', 'utf-8') LOCK_CONTENT = bytes('lockedContent', 'utf-8') ROYALTIES = bytes('[{"address": "someaddress", "value": 20}, {"address": "someaddress2", "value": 30}]', 'utf-8') def build_contract(self, preprocess=False): print('contract path: ' + self.CONTRACT_PATH_PY) if preprocess: import os old = os.getcwd() os.chdir(self.GHOST_ROOT) file = self.GHOST_ROOT + '/compile.py' os.system(file) os.chdir(old) else: output, manifest = self.compile_and_save(self.CONTRACT_PATH_PY) def deploy_contract(self, engine): engine.add_contract(self.CONTRACT_PATH_NEF.replace('.py', '.nef')) result = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, '_deploy', None, False, signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(VoidType, result) def prepare_testengine(self, preprocess=False) -> TestEngine: self.build_contract(preprocess) root_folder = self.BOA_PATH engine = TestEngine(root_folder) engine.reset_engine() self.deploy_contract(engine) return engine def print_notif(self, notifications): print('\n=========================== NOTIFICATIONS START ===========================\n') for notif in notifications: print(f"{str(notif.name)}: {str(notif.arguments)}") print('\n=========================== NOTIFICATIONS END ===========================\n') def test_ghost_compile(self): self.build_contract() def test_ghost_symbol(self): engine = self.prepare_testengine() result = engine.run(self.CONTRACT_PATH_NEF, 'symbol', reset_engine=True) self.print_notif(engine.notifications) assert isinstance(result, str) assert result == 'GHOST' def test_ghost_decimals(self): engine = self.prepare_testengine() result = engine.run(self.CONTRACT_PATH_NEF, 'decimals', reset_engine=True) self.print_notif(engine.notifications) assert isinstance(result, int) assert result == 0 def test_ghost_total_supply(self): engine = self.prepare_testengine() result = engine.run(self.CONTRACT_PATH_NEF, 'totalSupply', reset_engine=True) self.print_notif(engine.notifications) assert isinstance(result, int) assert result == 0 def test_ghost_deploy(self): engine = self.prepare_testengine() # prepare_testengine already deploys the contract and verifies it's successfully deployed # must always return false after first execution with self.assertRaises(TestExecutionException, msg=self.ABORTED_CONTRACT_MSG): result = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, '_deploy', None, False, signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.print_notif(engine.notifications) def test_ghost_update(self): engine = self.prepare_testengine() # updating ghost smart contract file_script = open(self.CONTRACT_PATH_NEF, 'rb') script = file_script.read() #print(script) file_script.close() file_manifest = open(self.CONTRACT_PATH_JSON, 'rb') manifest = file_manifest.read() #print(manifest) file_manifest.close() result = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'update', script, manifest, signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(VoidType, result) def test_ghost_destroy(self): engine = self.prepare_testengine() # destroy contract result = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'destroy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) # should not exist anymore result = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'symbol') # self.assertNotEqual('GHOST', result) self.print_notif(engine.notifications) def test_ghost_verify(self): engine = self.prepare_testengine() # should fail because account does not have enough for fees with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'verify', self.OTHER_ACCOUNT_1) self.print_notif(engine.notifications) def test_ghost_authorize(self): engine = self.prepare_testengine() self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'setAuthorizedAddress', self.OTHER_ACCOUNT_1, True, signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) auth_events = engine.get_events('Authorized') # check if the event was triggered and the address was authorized self.assertEqual(0, auth_events[0].arguments[1]) self.assertEqual(1, auth_events[0].arguments[2]) # now deauthorize the address self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'setAuthorizedAddress', self.OTHER_ACCOUNT_1, False, signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) auth_events = engine.get_events('Authorized') # check if the event was triggered and the address was authorized self.assertEqual(0, auth_events[1].arguments[1]) self.assertEqual(0, auth_events[1].arguments[2]) def test_ghost_whitelist(self): engine = self.prepare_testengine() self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'setWhitelistedAddress', self.OTHER_ACCOUNT_1, True, signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) auth_events = engine.get_events('Authorized') # check if the event was triggered and the address was authorized self.assertEqual(1, auth_events[0].arguments[1]) self.assertEqual(1, auth_events[0].arguments[2]) # now deauthorize the address self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'setWhitelistedAddress', self.OTHER_ACCOUNT_1, False, signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) auth_events = engine.get_events('Authorized') # check if the event was triggered and the address was authorized self.assertEqual(1, auth_events[1].arguments[1]) self.assertEqual(0, auth_events[1].arguments[2]) def test_ghost_pause(self): engine = self.prepare_testengine() engine.add_contract(self.CONTRACT_PATH_NEF.replace('.py', '.nef')) aux_path = self.get_contract_path('test_native', 'auxiliary_contract.py') output, manifest = self.compile_and_save(self.CONTRACT_PATH_NEF.replace('.nef', '.py')) ghost_address = hash160(output) print(to_hex_str(ghost_address)) output, manifest = self.compile_and_save(aux_path) aux_address = hash160(output) print(to_hex_str(aux_address)) # when deploying, the contract will mint tokens to the owner deploy_event = engine.get_events('Deployed') self.assertEqual(1, len(deploy_event)) self.assertEqual(2, len(deploy_event[0].arguments)) # add some gas for fees add_amount = 10 * 10 ** 8 engine.add_gas(aux_address, add_amount) # pause contract fee = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'updatePause', True, signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=int) # should fail because contract is paused with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): token = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'mint', aux_address, self.TOKEN_META, self.LOCK_CONTENT, self.ROYALTIES, None, signer_accounts=[aux_address], expected_result_type=bytes) # unpause contract fee = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'updatePause', False, signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=int) # mint token = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'mint', aux_address, self.TOKEN_META, self.LOCK_CONTENT, self.ROYALTIES, None, signer_accounts=[aux_address], expected_result_type=bytes) self.print_notif(engine.notifications) def test_ghost_mint(self): engine = self.prepare_testengine() engine.add_contract(self.CONTRACT_PATH_NEF.replace('.py', '.nef')) aux_path = self.get_contract_path('test_native', 'auxiliary_contract.py') output, manifest = self.compile_and_save(self.CONTRACT_PATH_NEF.replace('.nef', '.py')) ghost_address = hash160(output) print(to_hex_str(ghost_address)) output, manifest = self.compile_and_save(aux_path) aux_address = hash160(output) print(to_hex_str(aux_address)) # when deploying, the contract will mint tokens to the owner deploy_event = engine.get_events('Deployed') self.assertEqual(1, len(deploy_event)) self.assertEqual(2, len(deploy_event[0].arguments)) # should fail because account does not have enough for fees with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'mint', # aux_address, self.TOKEN_META, self.LOCK_CONTENT, self.ROYALTIES, None, aux_address, bytes(0), bytes(0), bytes(0), None, signer_accounts=[aux_address], expected_result_type=bytes) # add some gas for fees add_amount = 10 * 10 ** 8 engine.add_gas(aux_address, add_amount) # should succeed now that account has enough fees token = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'mint', aux_address, self.TOKEN_META, self.LOCK_CONTENT, self.ROYALTIES, None, signer_accounts=[aux_address], expected_result_type=bytes) print("get props now: ") properties = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'properties', token, expected_result_type=bytes) print("props: " + str(properties)) royalties = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'getRoyalties', token, expected_result_type=bytes) print("royalties: " + str(royalties)) print('non existing props:') with self.assertRaises(TestExecutionException, msg='An unhandled exception was thrown. Unable to parse metadata'): properties = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'properties', bytes('thisisanonexistingtoken', 'utf-8'), expected_result_type=bytes) print("props: " + str(properties)) # check balances after ghost_amount_after = self.run_smart_contract(engine, GAS_SCRIPT, 'balanceOf', ghost_address) gas_aux_after = self.run_smart_contract(engine, GAS_SCRIPT, 'balanceOf', aux_address) print("ghost gas amount: " + str(ghost_amount_after)) print("aux gas amount: " + str(gas_aux_after)) ghost_balance_after = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'balanceOf', aux_address) print("balance nft: " + str(ghost_balance_after)) ghost_supply_after = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'totalSupply') print("supply nft: " + str(ghost_supply_after)) self.assertEqual(1, ghost_supply_after) self.print_notif(engine.notifications) def test_ghost_gas_cost(self): engine = self.prepare_testengine() engine.add_contract(self.CONTRACT_PATH_NEF.replace('.py', '.nef')) aux_path = self.get_contract_path('test_native', 'auxiliary_contract.py') output, manifest = self.compile_and_save(self.CONTRACT_PATH_NEF.replace('.nef', '.py')) ghost_address = hash160(output) print(to_hex_str(ghost_address)) output, manifest = self.compile_and_save(aux_path) aux_address = hash160(output) print(to_hex_str(aux_address)) # add some gas for fees add_amount = 10 * 10 ** 8 engine.add_gas(aux_address, add_amount) # mint token with no meta, no lock content, no royalties token = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'mint', aux_address, bytes(1), bytes(0), bytes(0), None, signer_accounts=[aux_address], expected_result_type=bytes) gasConsumed = str(int(engine.gas_consumed) / 10 ** 8) print("token with no meta, no lock content, no royalties: " + gasConsumed + " GAS") # mint token with meta, no lock content, no royalties token = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'mint', aux_address, self.TOKEN_META, bytes(0), bytes(0), None, signer_accounts=[aux_address], expected_result_type=bytes) gasConsumed = str(int(engine.gas_consumed) / 10 ** 8) print("token with meta, no lock content, no royalties: " + gasConsumed + " GAS") # mint token with meta, lock content, no royalties token = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'mint', aux_address, self.TOKEN_META, self.LOCK_CONTENT, bytes(0), None, signer_accounts=[aux_address], expected_result_type=bytes) gasConsumed = str(int(engine.gas_consumed) / 10 ** 8) print("token with meta, lock content, no royalties: " + gasConsumed + " GAS") # mint token with meta, no lock content, royalties token = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'mint', aux_address, self.TOKEN_META, bytes(0), self.ROYALTIES, None, signer_accounts=[aux_address], expected_result_type=bytes) gasConsumed = str(int(engine.gas_consumed) / 10 ** 8) print("token with meta, no lock content, royalties: " + gasConsumed + " GAS") # mint token with meta, lock content, royalties token = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'mint', aux_address, self.TOKEN_META, self.LOCK_CONTENT, self.ROYALTIES, None, signer_accounts=[aux_address], expected_result_type=bytes) gasConsumed = str(int(engine.gas_consumed) / 10 ** 8) print("token with meta, lock content, royalties: " + gasConsumed + " GAS") tokenMeta = bytes('{ "name": "GHOST3", "description": "A ghost shows up", "image": "{some image URI}", "name": "GHOST3", "description": "A ghost shows up", "image": "{some image URI}", "name": "GHOST3", "description": "A ghost shows up", "image": "{some image URI}", "name": "GHOST3", "description": "A ghost shows up", "image": "{some image URI}", "tokenURI": "{some URI}" }', 'utf-8') lockedContent = bytes('123456789101234567891012345678910123456789101234567891012345678910123456789101234567891012345678910123456789101234567891012345678910123456789101234567891012345678910123456789101234567891012345678910', 'utf-8') royalties = bytes('[{"address": "someaddress", "value": 20}, {"address": "someaddress2", "value": 30},{"address": "someaddress", "value": 20}, {"address": "someaddress2", "value": 30},{"address": "someaddress", "value": 20}, {"address": "someaddress2", "value": 30}]', 'utf-8') # mint high end token token = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'mint', aux_address, tokenMeta, lockedContent, royalties, None, signer_accounts=[aux_address], expected_result_type=bytes) gasConsumed = str(int(engine.gas_consumed) / 10 ** 8) print("token with heavy meta, heavy lock content, heavy royalties: " + gasConsumed + " GAS") # get locked content content = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'getLockedContent', token, signer_accounts=[aux_address], expected_result_type=bytes) gasConsumed = str(int(engine.gas_consumed) / 10 ** 8) print("get locked content: " + gasConsumed + " GAS") # burn token burn = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'burn', token, signer_accounts=[aux_address], expected_result_type=bool) gasConsumed = str(int(engine.gas_consumed) / 10 ** 8) print("burn: " + gasConsumed + " GAS") def test_ghost_multi_mint(self): engine = self.prepare_testengine() engine.add_contract(self.CONTRACT_PATH_NEF.replace('.py', '.nef')) aux_path = self.get_contract_path('test_native', 'auxiliary_contract.py') output, manifest = self.compile_and_save(self.CONTRACT_PATH_NEF.replace('.nef', '.py')) ghost_address = hash160(output) print(to_hex_str(ghost_address)) output, manifest = self.compile_and_save(aux_path) aux_address = hash160(output) print(to_hex_str(aux_address)) # when deploying, the contract will mint tokens to the owner deploy_event = engine.get_events('Deployed') self.assertEqual(1, len(deploy_event)) self.assertEqual(2, len(deploy_event[0].arguments)) # add some gas for fees add_amount = 10 * 10 ** 8 engine.add_gas(aux_address, add_amount) # define custom meta & lock & royalties for multi tokenMeta = [ bytes('{ "name": "GHOST", "description": "A ghost shows up", "image": "{some image URI}", "tokenURI": "{some URI}" }', 'utf-8'), bytes('{ "name": "GHOST2", "description": "A ghost shows up", "image": "{some image URI}", "tokenURI": "{some URI}" }', 'utf-8'), bytes('{ "name": "GHOST3", "description": "A ghost shows up", "image": "{some image URI}", "tokenURI": "{some URI}" }', 'utf-8') ] lockedContent = [ bytes('123', 'utf-8'), bytes('456', 'utf-8'), bytes('789', 'utf-8'), ] royalties = [ bytes('[{"address": "someaddress", "value": 20}, {"address": "someaddress2", "value": 30}]', 'utf-8'), bytes('[{"address": "someaddress3", "value": 20}, {"address": "someaddress4", "value": 30}]', 'utf-8'), bytes('[{"address": "someaddress5", "value": 20}, {"address": "someaddress6", "value": 30}]', 'utf-8'), ] # check tokens iterator before ghost_tokens_before = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'tokens', expected_result_type=InteropInterface) self.assertEqual(InteropInterface, ghost_tokens_before) # multiMint result = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'multiMint', aux_address, tokenMeta, lockedContent, royalties, None, signer_accounts=[aux_address], expected_result_type=list) print("result: " + str(result)) # check tokens iterator after ghost_tokens_after = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'tokens', expected_result_type=InteropInterface) print("tokens after: " + str(ghost_tokens_after)) # check balances after ghost_balance_after = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'balanceOf', aux_address) self.assertEqual(3, ghost_balance_after) ghost_supply_after = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'totalSupply') self.assertEqual(3, ghost_supply_after) self.print_notif(engine.notifications) def test_ghost_transfer(self): engine = self.prepare_testengine() engine.add_contract(self.CONTRACT_PATH_NEF.replace('.py', '.nef')) aux_path = self.get_contract_path('test_native', 'auxiliary_contract.py') output, manifest = self.compile_and_save(self.CONTRACT_PATH_NEF.replace('.nef', '.py')) ghost_address = hash160(output) print(to_hex_str(ghost_address)) output, manifest = self.compile_and_save(aux_path) aux_address = hash160(output) print(to_hex_str(aux_address)) # when deploying, the contract will mint tokens to the owner deploy_event = engine.get_events('Deployed') self.assertEqual(1, len(deploy_event)) self.assertEqual(2, len(deploy_event[0].arguments)) # add some gas for fees add_amount = 10 * 10 ** 8 engine.add_gas(aux_address, add_amount) # mint token = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'mint', aux_address, self.TOKEN_META, self.LOCK_CONTENT, self.ROYALTIES, None, signer_accounts=[aux_address], expected_result_type=bytes) properties = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'properties', token) print("props: " + str(properties)) # check balances after ghost_amount_after = self.run_smart_contract(engine, GAS_SCRIPT, 'balanceOf', ghost_address) gas_aux_after = self.run_smart_contract(engine, GAS_SCRIPT, 'balanceOf', aux_address) print("ghost gas amount: " + str(ghost_amount_after)) print("aux gas amount: " + str(gas_aux_after)) ghost_balance_after = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'balanceOf', aux_address) print("balance nft: " + str(ghost_balance_after)) ghost_supply_after = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'totalSupply') print("supply nft: " + str(ghost_supply_after)) self.assertEqual(1, ghost_supply_after) # check owner before ghost_owner_of_before = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'ownerOf', token) print("owner of before: " + str(ghost_owner_of_before)) # transfer result = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'transfer', self.OTHER_ACCOUNT_1, token, None, signer_accounts=[aux_address], expected_result_type=bool) self.assertEqual(True, result) # check owner after ghost_owner_of_after = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'ownerOf', token) print("owner of after: " + str(ghost_owner_of_after)) self.assertEqual(ghost_owner_of_after, self.OTHER_ACCOUNT_1) # check balances after ghost_balance_after_transfer = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'balanceOf', aux_address) ghost_supply_after_transfer = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'totalSupply') print("balance nft after transfer: " + str(ghost_balance_after_transfer)) self.assertEqual(0, ghost_balance_after_transfer) self.assertEqual(1, ghost_supply_after_transfer) # try to transfer non existing token id with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): result = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'transfer', self.OTHER_ACCOUNT_1, bytes('thisisanonexistingtoken', 'utf-8'), None, signer_accounts=[aux_address], expected_result_type=bool) self.print_notif(engine.notifications) def test_ghost_burn(self): engine = self.prepare_testengine() engine.add_contract(self.CONTRACT_PATH_NEF.replace('.py', '.nef')) aux_path = self.get_contract_path('test_native', 'auxiliary_contract.py') output, manifest = self.compile_and_save(self.CONTRACT_PATH_NEF.replace('.nef', '.py')) ghost_address = hash160(output) print(to_hex_str(ghost_address)) output, manifest = self.compile_and_save(aux_path) aux_address = hash160(output) print(to_hex_str(aux_address)) # when deploying, the contract will mint tokens to the owner deploy_event = engine.get_events('Deployed') self.assertEqual(1, len(deploy_event)) self.assertEqual(2, len(deploy_event[0].arguments)) # add some gas for fees add_amount = 10 * 10 ** 8 engine.add_gas(aux_address, add_amount) # mint token = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'mint', aux_address, self.TOKEN_META, self.LOCK_CONTENT, self.ROYALTIES, None, signer_accounts=[aux_address], expected_result_type=bytes) # burn burn = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'burn', token, signer_accounts=[aux_address], expected_result_type=bool) print("props: " + str(burn)) # check balances after ghost_balance_after = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'balanceOf', aux_address) self.assertEqual(0, ghost_balance_after) ghost_supply_after = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'totalSupply') self.assertEqual(0, ghost_supply_after) self.print_notif(engine.notifications) def test_ghost_multi_burn(self): engine = self.prepare_testengine() engine.add_contract(self.CONTRACT_PATH_NEF.replace('.py', '.nef')) aux_path = self.get_contract_path('test_native', 'auxiliary_contract.py') output, manifest = self.compile_and_save(self.CONTRACT_PATH_NEF.replace('.nef', '.py')) ghost_address = hash160(output) print(to_hex_str(ghost_address)) output, manifest = self.compile_and_save(aux_path) aux_address = hash160(output) print(to_hex_str(aux_address)) deploy_event = engine.get_events('Deployed') self.assertEqual(1, len(deploy_event)) self.assertEqual(2, len(deploy_event[0].arguments)) # add some gas for fees add_amount = 10 * 10 ** 8 engine.add_gas(aux_address, add_amount) # define custom meta & lock & royalties for multi tokenMeta = [ bytes('{ "name": "GHOST", "description": "A ghost shows up", "image": "{some image URI}", "tokenURI": "{some URI}" }', 'utf-8'), bytes('{ "name": "GHOST2", "description": "A ghost shows up", "image": "{some image URI}", "tokenURI": "{some URI}" }', 'utf-8'), bytes('{ "name": "GHOST3", "description": "A ghost shows up", "image": "{some image URI}", "tokenURI": "{some URI}" }', 'utf-8') ] lockedContent = [ bytes('123', 'utf-8'), bytes('456', 'utf-8'), bytes('789', 'utf-8'), ] royalties = [ bytes('[{"address": "someaddress", "value": 20}, {"address": "someaddress2", "value": 30}]', 'utf-8'), bytes('[{"address": "someaddress3", "value": 20}, {"address": "someaddress4", "value": 30}]', 'utf-8'), bytes('[{"address": "someaddress5", "value": 20}, {"address": "someaddress6", "value": 30}]', 'utf-8'), ] # multiMint result = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'multiMint', aux_address, tokenMeta, lockedContent, royalties, None, signer_accounts=[aux_address], expected_result_type=list) # check balances after ghost_balance_after = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'balanceOf', aux_address) self.assertEqual(3, ghost_balance_after) ghost_supply_after = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'totalSupply') self.assertEqual(3, ghost_supply_after) # multiBurn burn = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'multiBurn', result, signer_accounts=[aux_address], expected_result_type=list) print("burned: " + str(burn)) # check balances after ghost_balance_after = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'balanceOf', aux_address) self.assertEqual(0, ghost_balance_after) ghost_supply_after = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'totalSupply') self.assertEqual(0, ghost_supply_after) self.print_notif(engine.notifications) def test_ghost_onNEP11Payment(self): engine = self.prepare_testengine() engine.add_contract(self.CONTRACT_PATH_NEF.replace('.py', '.nef')) aux_path = self.get_contract_path('test_native', 'auxiliary_contract.py') output, manifest = self.compile_and_save(self.CONTRACT_PATH_NEF.replace('.nef', '.py')) ghost_address = hash160(output) print(to_hex_str(ghost_address)) output, manifest = self.compile_and_save(aux_path) aux_address = hash160(output) print(to_hex_str(aux_address)) # add some gas for fees add_amount = 10 * 10 ** 8 engine.add_gas(self.OTHER_ACCOUNT_1, add_amount) # mint token = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'mint', self.OTHER_ACCOUNT_1, self.TOKEN_META, self.LOCK_CONTENT, self.ROYALTIES, None, signer_accounts=[self.OTHER_ACCOUNT_1], expected_result_type=bytes) # the smart contract will abort if any address calls the NEP11 onPayment method with self.assertRaises(TestExecutionException, msg=self.ABORTED_CONTRACT_MSG): result = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'onNEP11Payment', self.OTHER_ACCOUNT_1, 1, token, None, signer_accounts=[self.OTHER_ACCOUNT_1], expected_result_type=bool) def test_ghost_onNEP17Payment(self): engine = self.prepare_testengine() engine.add_contract(self.CONTRACT_PATH_NEF.replace('.py', '.nef')) aux_path = self.get_contract_path('test_native', 'auxiliary_contract.py') output, manifest = self.compile_and_save(self.CONTRACT_PATH_NEF.replace('.nef', '.py')) ghost_address = hash160(output) print(to_hex_str(ghost_address)) output, manifest = self.compile_and_save(aux_path) aux_address = hash160(output) print(to_hex_str(aux_address)) # when deploying, the contract will mint tokens to the owner deploy_event = engine.get_events('Deployed') self.assertEqual(1, len(deploy_event)) self.assertEqual(2, len(deploy_event[0].arguments)) # add some gas for fees add_amount = 10 * 10 ** 8 engine.add_gas(aux_address, add_amount) # the smart contract will abort if some address other than GAS calls the NEP17 onPayment method with self.assertRaises(TestExecutionException, msg=self.ABORTED_CONTRACT_MSG): self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'onNEP17Payment', aux_address, add_amount, None, signer_accounts=[aux_address]) def test_ghost_mint_fee(self): engine = self.prepare_testengine() engine.add_contract(self.CONTRACT_PATH_NEF.replace('.py', '.nef')) output, manifest = self.compile_and_save(self.CONTRACT_PATH_NEF.replace('.nef', '.py')) ghost_address = hash160(output) # when deploying, the contract will mint tokens to the owner deploy_event = engine.get_events('Deployed') self.assertEqual(1, len(deploy_event)) self.assertEqual(2, len(deploy_event[0].arguments)) # add some gas for fees add_amount = 10 * 10 ** 8 engine.add_gas(self.OTHER_ACCOUNT_1, add_amount/2) engine.add_gas(self.OWNER_SCRIPT_HASH, add_amount/2) # setMintFee fee = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'setMintFee', 1000, signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=int) # getMintFee should return the updated fee fee_event = engine.get_events('MintFeeUpdated') updated_fee = fee_event[0].arguments[1] self.assertEqual(updated_fee, 1000) # getMintFee should return the updated fee fee2 = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'getMintFee', expected_result_type=int) self.assertEqual(fee2, updated_fee) # fails because account not whitelisted with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'setMintFee', 1, signer_accounts=[self.OTHER_ACCOUNT_1], expected_result_type=int) # fees should be the same since it failed fee2 = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'getMintFee', expected_result_type=int) self.assertEqual(fee2, updated_fee) self.print_notif(engine.notifications) def test_ghost_fee_balance(self): engine = self.prepare_testengine() engine.add_contract(self.CONTRACT_PATH_NEF.replace('.py', '.nef')) output, manifest = self.compile_and_save(self.CONTRACT_PATH_NEF.replace('.nef', '.py')) ghost_address = hash160(output) # when deploying, the contract will mint tokens to the owner deploy_event = engine.get_events('Deployed') self.assertEqual(1, len(deploy_event)) self.assertEqual(2, len(deploy_event[0].arguments)) # add some gas for fees add_amount = 10 * 10 ** 8 engine.add_gas(self.OTHER_ACCOUNT_1, add_amount) # check initial balance is 0 balance = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'getFeeBalance', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=int) self.assertEqual(0, balance) # mint + balanceOf token = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'mint', self.OTHER_ACCOUNT_1, self.TOKEN_META, self.LOCK_CONTENT, self.ROYALTIES, None, signer_accounts=[self.OTHER_ACCOUNT_1], expected_result_type=bytes) balance_after = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'getFeeBalance', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=int) initial_fee = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'getMintFee', expected_result_type=int) # should have new balance self.assertEqual(initial_fee, balance_after) # set mint fee to 200000 + mint + getFeeBalance fee = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'setMintFee', 200000, signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=int) token = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'mint', self.OTHER_ACCOUNT_1, self.TOKEN_META, self.LOCK_CONTENT, self.ROYALTIES, None, signer_accounts=[self.OTHER_ACCOUNT_1], expected_result_type=bytes) balance_after_updated = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'getFeeBalance', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=int) # should have new balance self.assertEqual(balance_after_updated, balance_after + 200000) # withdraw fee success = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'withdrawFee', self.OWNER_SCRIPT_HASH, signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=int) self.assertEqual(True, success) # check balances after ghost_balance_after = self.run_smart_contract(engine, GAS_SCRIPT, 'balanceOf', ghost_address) self.assertEqual(0, ghost_balance_after) owner_balance = self.run_smart_contract(engine, GAS_SCRIPT, 'balanceOf', self.OWNER_SCRIPT_HASH) self.assertEqual(initial_fee + 200000, owner_balance) self.print_notif(engine.notifications) def test_ghost_locked_content(self): engine = self.prepare_testengine() engine.add_contract(self.CONTRACT_PATH_NEF.replace('.py', '.nef')) output, manifest = self.compile_and_save(self.CONTRACT_PATH_NEF.replace('.nef', '.py')) ghost_address = hash160(output) # when deploying, the contract will mint tokens to the owner deploy_event = engine.get_events('Deployed') self.assertEqual(1, len(deploy_event)) self.assertEqual(2, len(deploy_event[0].arguments)) # add some gas for fees add_amount = 10 * 10 ** 8 engine.add_gas(self.OTHER_ACCOUNT_1, add_amount) # check if enough balance balance = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'getFeeBalance', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=int) self.assertEqual(0, balance) # mint + getLockedContentViewCount token = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'mint', self.OTHER_ACCOUNT_1, self.TOKEN_META, self.LOCK_CONTENT, self.ROYALTIES, None, signer_accounts=[self.OTHER_ACCOUNT_1], expected_result_type=bytes) views = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'getLockedContentViewCount', token, expected_result_type=int) # should have 0 views self.assertEqual(0, views) # getLockedContent content = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'getLockedContent', token, signer_accounts=[self.OTHER_ACCOUNT_1], expected_result_type=bytes) self.assertEqual(b'lockedContent', content) # getLockedContentViewCount should have 1 view views = self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'getLockedContentViewCount', token, expected_result_type=int) print("views: " + str(views)) self.assertEqual(1, views) # reset views and test getLockedContentViewCount with 100 views views = 0 for i in range(0, 100): views += self.run_smart_contract(engine, self.CONTRACT_PATH_NEF, 'getLockedContentViewCount', token, expected_result_type=int) self.assertEqual(100, views) self.print_notif(engine.notifications)
class TestNEP11Template(BoaTest): default_folder: str = 'examples' OTHER_ACCOUNT_1 = to_script_hash(b'NiNmXL8FjEUEs1nfX9uHFBNaenxDHJtmuB') def test_nep11_compile(self): path = self.get_contract_path('nep11_non_divisible.py') output, manifest = self.compile_and_save(path) self.assertIn('supportedstandards', manifest) self.assertIsInstance(manifest['supportedstandards'], list) self.assertGreater(len(manifest['supportedstandards']), 0) self.assertIn('NEP-11', manifest['supportedstandards']) def test_nep11_symbol(self): path = self.get_contract_path('nep11_non_divisible.py') engine = TestEngine() result = self.run_smart_contract(engine, path, 'symbol') self.assertEqual('NEP11', result) def test_nep11_decimals(self): path = self.get_contract_path('nep11_non_divisible.py') engine = TestEngine() result = self.run_smart_contract(engine, path, 'decimals') self.assertEqual(0, result) def test_nep11_total_supply(self): # smart contract deploys with zero tokens minted total_supply = 0 path = self.get_contract_path('nep11_non_divisible.py') engine = TestEngine() result = self.run_smart_contract(engine, path, 'totalSupply') self.assertEqual(total_supply, result) def test_nep11_mint(self): path = self.get_contract_path('nep11_non_divisible.py') engine = TestEngine() self.run_smart_contract(engine, path, 'symbol') nep11_address = engine.executed_script_hash.to_array() aux_path = self.get_contract_path('examples/auxiliary_contracts', 'auxiliary_contract.py') self.run_smart_contract(engine, aux_path, 'get_name') aux_address = engine.executed_script_hash.to_array() engine = TestEngine() engine.add_contract(path.replace('.py', '.nef')) # can't call the mint function directly with self.assertRaises(TestExecutionException): self.run_smart_contract(engine, path, 'mint', aux_address, 100) gas_used = 2 * 10**8 engine.add_gas(aux_address, gas_used) # transferring GAS to the nep11 will mint some tokens result = self.run_smart_contract(engine, aux_path, 'calling_transfer', constants.GAS_SCRIPT, aux_address, nep11_address, gas_used, None, signer_accounts=[aux_address]) self.assertEqual(True, result) def test_nep11_total_balance_of(self): path = self.get_contract_path('nep11_non_divisible.py') engine = TestEngine() self.run_smart_contract(engine, path, 'symbol') nep11_address = engine.executed_script_hash.to_array() aux_path = self.get_contract_path('examples/auxiliary_contracts', 'auxiliary_contract.py') self.run_smart_contract(engine, aux_path, 'get_name') aux_address = engine.executed_script_hash.to_array() engine = TestEngine() engine.add_contract(path.replace('.py', '.nef')) # every account starts with zero tokens result = self.run_smart_contract(engine, path, 'balanceOf', aux_address) self.assertEqual(0, result) gas_used = 2 * 10**8 engine.add_gas(aux_address, gas_used) # transferring GAS to the nep11 will mint some tokens result = self.run_smart_contract(engine, aux_path, 'calling_transfer', constants.GAS_SCRIPT, aux_address, nep11_address, gas_used, None, signer_accounts=[aux_address]) self.assertEqual(True, result) # after minting 1 token, the amount of tokens should increment by 1 result = self.run_smart_contract(engine, path, 'balanceOf', aux_address) self.assertEqual(1, result) gas_used = 6 * 10**8 engine.add_gas(aux_address, gas_used) # minting another 3 nfts result = self.run_smart_contract(engine, aux_path, 'calling_transfer', constants.GAS_SCRIPT, aux_address, nep11_address, gas_used, None, signer_accounts=[aux_address]) self.assertEqual(True, result) # checking if the amount is 4 now result = self.run_smart_contract(engine, path, 'balanceOf', aux_address) self.assertEqual(4, result) # should fail when the script length is not 20 with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'balanceOf', bytes(10)) with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'balanceOf', bytes(30)) def test_nep11_total_tokens_of(self): pass def test_nep11_total_owner_of(self): pass def test_nep11_total_transfer(self): pass
class TestNEP17Template(BoaTest): default_folder: str = 'examples' OWNER_SCRIPT_HASH = bytes(20) OTHER_ACCOUNT_1 = to_script_hash(b'NiNmXL8FjEUEs1nfX9uHFBNaenxDHJtmuB') OTHER_ACCOUNT_2 = bytes(range(20)) def test_nep17_compile(self): path = self.get_contract_path('NEP17.py') Boa3.compile(path) def test_nep17_deploy(self): path = self.get_contract_path('NEP17.py') engine = TestEngine() # needs the owner signature result = self.run_smart_contract(engine, path, method='deploy', expected_result_type=bool) self.assertEqual(False, result) # should return false if the signature isn't from the owner result = self.run_smart_contract( engine, path, 'deploy', signer_accounts=[self.OTHER_ACCOUNT_1], expected_result_type=bool) self.assertEqual(False, result) result = self.run_smart_contract( engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # must always return false after first execution result = self.run_smart_contract( engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(False, result) def test_nep17_symbol(self): path = self.get_contract_path('NEP17.py') engine = TestEngine() result = self.run_smart_contract(engine, path, 'symbol') self.assertEqual('NEP17', result) def test_nep17_decimals(self): path = self.get_contract_path('NEP17.py') engine = TestEngine() result = self.run_smart_contract(engine, path, 'decimals') self.assertEqual(8, result) def test_nep17_total_supply(self): total_supply = 10_000_000 * 10**8 path = self.get_contract_path('NEP17.py') engine = TestEngine() result = self.run_smart_contract(engine, path, 'totalSupply') self.assertEqual(0, result) result = self.run_smart_contract( engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) result = self.run_smart_contract(engine, path, 'totalSupply') self.assertEqual(total_supply, result) def test_nep17_total_balance_of(self): total_supply = 10_000_000 * 10**8 path = self.get_contract_path('NEP17.py') engine = TestEngine() result = self.run_smart_contract(engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) self.assertEqual(0, result) result = self.run_smart_contract( engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) result = self.run_smart_contract(engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) self.assertEqual(total_supply, result) # should fail when the script length is not 20 with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'balanceOf', bytes(10)) with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'balanceOf', bytes(30)) @unittest.skip( 'Examples need to be changed to test with the latest Neo version') def test_nep17_total_transfer(self): transferred_amount = 10 * 10**8 # 10 tokens path = self.get_contract_path('NEP17.py') engine = TestEngine() # should fail before running deploy result = self.run_smart_contract(engine, path, 'transfer', self.OWNER_SCRIPT_HASH, self.OTHER_ACCOUNT_1, transferred_amount, None, expected_result_type=bool) self.assertEqual(False, result) result = self.run_smart_contract( engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # should fail if the sender doesn't sign result = self.run_smart_contract(engine, path, 'transfer', self.OWNER_SCRIPT_HASH, self.OTHER_ACCOUNT_1, transferred_amount, None, expected_result_type=bool) self.assertEqual(False, result) # should fail if the sender doesn't have enough balance result = self.run_smart_contract( engine, path, 'transfer', self.OTHER_ACCOUNT_1, self.OWNER_SCRIPT_HASH, transferred_amount, None, signer_accounts=[self.OTHER_ACCOUNT_1], expected_result_type=bool) self.assertEqual(False, result) # should fail when any of the scripts' length is not 20 with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'transfer', self.OWNER_SCRIPT_HASH, bytes(10), transferred_amount, "") with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'transfer', bytes(10), self.OTHER_ACCOUNT_1, transferred_amount, "") # should fail when the amount is less than 0 with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'transfer', self.OTHER_ACCOUNT_1, self.OWNER_SCRIPT_HASH, -10, None) # fire the transfer event when transferring to yourself balance_before = self.run_smart_contract(engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) result = self.run_smart_contract( engine, path, 'transfer', self.OWNER_SCRIPT_HASH, self.OWNER_SCRIPT_HASH, transferred_amount, None, signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) transfer_events = engine.get_events('Transfer') self.assertEqual(1, len(transfer_events)) self.assertEqual(3, len(transfer_events[0].arguments)) sender, receiver, amount = transfer_events[0].arguments if isinstance(sender, str): sender = String(sender).to_bytes() if isinstance(receiver, str): receiver = String(receiver).to_bytes() self.assertEqual(self.OWNER_SCRIPT_HASH, sender) self.assertEqual(self.OWNER_SCRIPT_HASH, receiver) self.assertEqual(transferred_amount, amount) # transferring to yourself doesn't change the balance balance_after = self.run_smart_contract(engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) self.assertEqual(balance_before, balance_after) # does fire the transfer event balance_sender_before = self.run_smart_contract( engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) balance_receiver_before = self.run_smart_contract( engine, path, 'balanceOf', self.OTHER_ACCOUNT_1) result = self.run_smart_contract( engine, path, 'transfer', self.OWNER_SCRIPT_HASH, self.OTHER_ACCOUNT_1, transferred_amount, None, signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) transfer_events = engine.get_events('Transfer') self.assertEqual(1, len(transfer_events)) self.assertEqual(3, len(transfer_events[0].arguments)) sender, receiver, amount = transfer_events[0].arguments if isinstance(sender, str): sender = String(sender).to_bytes() if isinstance(receiver, str): receiver = String(receiver).to_bytes() self.assertEqual(self.OWNER_SCRIPT_HASH, sender) self.assertEqual(self.OTHER_ACCOUNT_1, receiver) self.assertEqual(transferred_amount, amount) # transferring to someone other than yourself does change the balance balance_sender_after = self.run_smart_contract(engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) balance_receiver_after = self.run_smart_contract( engine, path, 'balanceOf', self.OTHER_ACCOUNT_1) self.assertEqual(balance_sender_before - transferred_amount, balance_sender_after) self.assertEqual(balance_receiver_before + transferred_amount, balance_receiver_after) @unittest.skip( 'Examples need to be changed to test with the latest Neo version') def test_nep17_onPayment(self): transferred_amount = 10 * 10**8 # 10 tokens path = self.get_contract_path('NEP17.py') engine = TestEngine() engine.add_contract(path.replace('.py', '.nef')) output, manifest = self.compile_and_save(path) nep17_address = hash160(output) result = self.run_smart_contract( engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) engine.add_neo(self.OWNER_SCRIPT_HASH, transferred_amount) engine.add_gas(self.OWNER_SCRIPT_HASH, transferred_amount) # transferring NEO to the smart contract # saving the balance before the transfer to be able to compare after it neo_balance_sender_before = self.run_smart_contract( engine, NEO_SCRIPT, 'balanceOf', self.OWNER_SCRIPT_HASH) neo_balance_nep17_before = self.run_smart_contract( engine, NEO_SCRIPT, 'balanceOf', nep17_address) nep17_balance_sender_before = self.run_smart_contract( engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) result = self.run_smart_contract( engine, NEO_SCRIPT, 'transfer', self.OWNER_SCRIPT_HASH, nep17_address, transferred_amount, None, signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) transfer_events = engine.get_events('Transfer') self.assertEqual(2, len(transfer_events)) self.assertEqual(3, len(transfer_events[0].arguments)) self.assertEqual(3, len(transfer_events[1].arguments)) # this is the event NEO emitted sender, receiver, amount = transfer_events[0].arguments if isinstance(sender, str): sender = String(sender).to_bytes() if isinstance(receiver, str): receiver = String(receiver).to_bytes() self.assertEqual(self.OWNER_SCRIPT_HASH, sender) self.assertEqual(nep17_address, receiver) self.assertEqual(transferred_amount, amount) # this is the event NEP17 emitted sender, receiver, amount = transfer_events[1].arguments if isinstance(sender, str): sender = String(sender).to_bytes() if isinstance(receiver, str): receiver = String(receiver).to_bytes() self.assertEqual(None, sender) self.assertEqual(self.OWNER_SCRIPT_HASH, receiver) # transferred_amount is multiplied by 10, because this smart contract is minting the NEO received self.assertEqual(transferred_amount * 10, amount) # saving the balance after the transfer to compare it with the previous data neo_balance_sender_after = self.run_smart_contract( engine, NEO_SCRIPT, 'balanceOf', self.OWNER_SCRIPT_HASH) neo_balance_nep17_after = self.run_smart_contract( engine, NEO_SCRIPT, 'balanceOf', nep17_address) nep17_balance_sender_after = self.run_smart_contract( engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) self.assertEqual(neo_balance_sender_before - transferred_amount, neo_balance_sender_after) self.assertEqual(neo_balance_nep17_before + transferred_amount, neo_balance_nep17_after) # transferred_amount is multiplied by 10, because this smart contract is minting the NEO received self.assertEqual(nep17_balance_sender_before + transferred_amount * 10, nep17_balance_sender_after) # transferring GAS to the smart contract # saving the balance before the transfer to be able to compare after it gas_balance_sender_before = self.run_smart_contract( engine, GAS_SCRIPT, 'balanceOf', self.OWNER_SCRIPT_HASH) gas_balance_nep17_before = self.run_smart_contract( engine, GAS_SCRIPT, 'balanceOf', nep17_address) nep17_balance_sender_before = self.run_smart_contract( engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) result = self.run_smart_contract( engine, GAS_SCRIPT, 'transfer', self.OWNER_SCRIPT_HASH, nep17_address, transferred_amount, None, signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) transfer_events = engine.get_events('Transfer') self.assertEqual(2, len(transfer_events)) self.assertEqual(3, len(transfer_events[0].arguments)) self.assertEqual(3, len(transfer_events[1].arguments)) # this is the event GAS emitted sender, receiver, amount = transfer_events[0].arguments if isinstance(sender, str): sender = String(sender).to_bytes() if isinstance(receiver, str): receiver = String(receiver).to_bytes() self.assertEqual(self.OWNER_SCRIPT_HASH, sender) self.assertEqual(nep17_address, receiver) self.assertEqual(transferred_amount, amount) # this is the event NEP17 emitted sender, receiver, amount = transfer_events[1].arguments if isinstance(sender, str): sender = String(sender).to_bytes() if isinstance(receiver, str): receiver = String(receiver).to_bytes() self.assertEqual(None, sender) self.assertEqual(self.OWNER_SCRIPT_HASH, receiver) # transferred_amount is multiplied by 2, because this smart contract is minting the GAS received self.assertEqual(transferred_amount * 2, amount) # saving the balance after the transfer to compare it with the previous data gas_balance_sender_after = self.run_smart_contract( engine, GAS_SCRIPT, 'balanceOf', self.OWNER_SCRIPT_HASH) gas_balance_nep17_after = self.run_smart_contract( engine, GAS_SCRIPT, 'balanceOf', nep17_address) nep17_balance_sender_after = self.run_smart_contract( engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) self.assertEqual(gas_balance_sender_before - transferred_amount, gas_balance_sender_after) self.assertEqual(gas_balance_nep17_before + transferred_amount, gas_balance_nep17_after) # transferred_amount is multiplied by 2, because this smart contract is minting the GAS received self.assertEqual(nep17_balance_sender_before + transferred_amount * 2, nep17_balance_sender_after) # trying to call onNEP17Transfer() will result in an abort if the one calling it is not NEO or GAS contracts with self.assertRaises(TestExecutionException, msg=self.ABORTED_CONTRACT_MSG): self.run_smart_contract(engine, path, 'onNEP17Transfer', self.OWNER_SCRIPT_HASH, transferred_amount, None) def test_nep17_verify(self): path = self.get_contract_path('NEP17.py') engine = TestEngine() # should fail without signature result = self.run_smart_contract(engine, path, 'verify', expected_result_type=bool) self.assertEqual(False, result) # should fail if not signed by the owner result = self.run_smart_contract( engine, path, 'verify', signer_accounts=[self.OTHER_ACCOUNT_1], expected_result_type=bool) self.assertEqual(False, result) result = self.run_smart_contract( engine, path, 'verify', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result)
class TestUpdateContractTemplate(BoaTest): default_folder: str = 'examples' OWNER_SCRIPT_HASH = bytes(20) OTHER_ACCOUNT_1 = to_script_hash(b'NiNmXL8FjEUEs1nfX9uHFBNaenxDHJtmuB') def test_update_contract_compile(self): path = self.get_contract_path('update_contract.py') path_new = self.get_contract_path('examples/auxiliary_contracts', 'update_contract.py') Boa3.compile(path) Boa3.compile(path_new) def test_update_contract(self): path = self.get_contract_path('update_contract.py') path_new = self.get_contract_path('examples/auxiliary_contracts', 'update_contract.py') self.get_output(path_new) new_nef, new_manifest = self.get_bytes_output(path_new) arg_manifest = String(json.dumps(new_manifest, separators=(',', ':'))).to_bytes() engine = TestEngine() # Saving user's balance before calling method to compare it later tokens_before = self.run_smart_contract(engine, path, 'balanceOf', self.OTHER_ACCOUNT_1) event_transfer = engine.get_events('Transfer') # Transfer emitted when deploying the smart contract self.assertEqual(1, len(event_transfer)) # The bugged method is being called and the user is able to receive tokens for free result = self.run_smart_contract(engine, path, 'method', self.OTHER_ACCOUNT_1) self.assertIsVoid(result) event_transfer = engine.get_events('Transfer') self.assertEqual(2, len(event_transfer)) # The amount of tokens will be higher after calling the method tokens_after = self.run_smart_contract(engine, path, 'balanceOf', self.OTHER_ACCOUNT_1) self.assertGreater(tokens_after, tokens_before) # The smart contract will be updated to fix the bug in the method result = self.run_smart_contract( engine, path, 'update_sc', new_nef, arg_manifest, None, signer_accounts=[self.OWNER_SCRIPT_HASH]) self.assertIsVoid(result) # An `Update` event will be emitted event_update = engine.get_events('Update') self.assertEqual(1, len(event_update)) # Saving user's balance before calling method to compare it later tokens_before = self.run_smart_contract(engine, path, 'balanceOf', self.OTHER_ACCOUNT_1) # Now, when method is called, it won't mint new tokens to any user that called it result = self.run_smart_contract(engine, path, 'method', self.OTHER_ACCOUNT_1) self.assertIsVoid(result) # The amount of tokens now is the same before and after calling the method tokens_after = self.run_smart_contract(engine, path, 'balanceOf', self.OTHER_ACCOUNT_1) self.assertEqual(tokens_after, tokens_before)
class TestTemplate(BoaTest): default_folder: str = 'examples' OWNER_SCRIPT_HASH = bytes(20) OTHER_ACCOUNT_1 = to_script_hash(b'NiNmXL8FjEUEs1nfX9uHFBNaenxDHJtmuB') OTHER_ACCOUNT_2 = bytes(range(20)) def test_amm_compile(self): path = self.get_contract_path('amm.py') Boa3.compile(path) def test_amm_deploy(self): path = self.get_contract_path('amm.py') engine = TestEngine() # needs the owner signature result = self.run_smart_contract(engine, path, method='deploy', expected_result_type=bool) self.assertEqual(False, result) # should return false if the signature isn't from the owner result = self.run_smart_contract(engine, path, 'deploy', signer_accounts=[self.OTHER_ACCOUNT_1], expected_result_type=bool) self.assertEqual(False, result) result = self.run_smart_contract(engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # must always return false after first execution result = self.run_smart_contract(engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(False, result) def test_amm_set_address(self): path = self.get_contract_path('amm.py') path_zneo = self.get_contract_path('wrapped_neo.py') path_zgas = self.get_contract_path('wrapped_gas.py') engine = TestEngine() engine.add_contract(path_zneo.replace('.py', '.nef')) engine.add_contract(path_zgas.replace('.py', '.nef')) output, manifest = self.compile_and_save(path_zneo) zneo_address = hash160(output) output, manifest = self.compile_and_save(path_zgas) zgas_address = hash160(output) # won't work because the contract must have been deployed before result = self.run_smart_contract(engine, path, 'set_address', zneo_address, zgas_address, signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(False, result) result = self.run_smart_contract(engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # won't work because it needs the owner signature result = self.run_smart_contract(engine, path, 'set_address', zneo_address, zgas_address, signer_accounts=[self.OTHER_ACCOUNT_1], expected_result_type=bool) self.assertEqual(False, result) # it will work now result = self.run_smart_contract(engine, path, 'set_address', zneo_address, zgas_address, signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # initialize will work once result = self.run_smart_contract(engine, path, 'set_address', zneo_address, zgas_address, signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(False, result) def test_amm_symbol(self): path = self.get_contract_path('amm.py') engine = TestEngine() result = self.run_smart_contract(engine, path, 'symbol') self.assertEqual('AMM', result) def test_amm_decimals(self): path = self.get_contract_path('amm.py') engine = TestEngine() result = self.run_smart_contract(engine, path, 'decimals') self.assertEqual(8, result) def test_amm_total_supply(self): path = self.get_contract_path('amm.py') engine = TestEngine() result = self.run_smart_contract(engine, path, 'totalSupply') self.assertEqual(0, result) def test_amm_total_balance_of(self): path = self.get_contract_path('amm.py') engine = TestEngine() result = self.run_smart_contract(engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) self.assertEqual(0, result) # should fail when the script length is not 20 with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'balanceOf', bytes(10)) with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'balanceOf', bytes(30)) def test_amm_quote(self): path = self.get_contract_path('amm.py') engine = TestEngine() amount_zneo = 1 * 10 ** 8 reserve_zneo = 100 * 10 ** 8 reserve_zgas = 1100 * 10 ** 8 result = self.run_smart_contract(engine, path, 'quote', amount_zneo, reserve_zneo, reserve_zgas) amount_zgas = amount_zneo * reserve_zgas // reserve_zneo self.assertEqual(amount_zgas, result) def test_amm_onNEP17Payment(self): transferred_amount = 10 * 10 ** 8 path = self.get_contract_path('amm.py') path_aux = self.get_contract_path('examples/test_native', 'auxiliary_contract.py') path_zneo = self.get_contract_path('wrapped_neo.py') path_zgas = self.get_contract_path('wrapped_gas.py') engine = TestEngine() engine.add_contract(path.replace('.py', '.nef')) engine.add_contract(path_zneo.replace('.py', '.nef')) engine.add_contract(path_zgas.replace('.py', '.nef')) output, manifest = self.compile_and_save(path) amm_address = hash160(output) output, manifest = self.compile_and_save(path_aux) aux_address = hash160(output) output, manifest = self.compile_and_save(path_zneo) zneo_address = hash160(output) output, manifest = self.compile_and_save(path_zgas) zgas_address = hash160(output) result = self.run_smart_contract(engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) result = self.run_smart_contract(engine, path, 'set_address', zneo_address, zgas_address, signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # the smart contract will abort if some address other than zNEO or zGAS calls the onPayment method with self.assertRaises(TestExecutionException, msg=self.ABORTED_CONTRACT_MSG): self.run_smart_contract(engine, path, 'onNEP17Payment', aux_address, transferred_amount, None, signer_accounts=[aux_address]) engine.add_neo(aux_address, transferred_amount) # adding the transferred_amount into the aux_address result = self.run_smart_contract(engine, path_aux, 'calling_transfer', NEO_SCRIPT, aux_address, zneo_address, transferred_amount, None, signer_accounts=[aux_address], expected_result_type=bool) self.assertEqual(True, result) # the AMM will accept this transaction, but there is no reason to send tokens directly to the smart contract. # to send tokens to the AMM you should use the add_liquidity function result = self.run_smart_contract(engine, path_aux, 'calling_transfer', zneo_address, aux_address, amm_address, transferred_amount, None, signer_accounts=[aux_address], expected_result_type=bool) self.assertEqual(True, result) def test_amm_add_liquidity(self): transferred_amount_zneo = 10 * 10 ** 8 transferred_amount_zgas = 110 * 10 ** 8 path = self.get_contract_path('amm.py') path_zneo = self.get_contract_path('wrapped_neo.py') path_zgas = self.get_contract_path('wrapped_gas.py') path_aux = self.get_contract_path('examples/test_native', 'auxiliary_contract.py') engine = TestEngine() engine.add_contract(path.replace('.py', '.nef')) engine.add_contract(path_zneo.replace('.py', '.nef')) engine.add_contract(path_zgas.replace('.py', '.nef')) output, manifest = self.compile_and_save(path) amm_address = hash160(output) output, manifest = self.compile_and_save(path_zneo) zneo_address = hash160(output) output, manifest = self.compile_and_save(path_zgas) zgas_address = hash160(output) output, manifest = self.compile_and_save(path_aux) aux_address = hash160(output) result = self.run_smart_contract(engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) result = self.run_smart_contract(engine, path, 'set_address', zneo_address, zgas_address, signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) engine.add_neo(aux_address, 10_000_000 * 10 ** 8) # minting zNEO to this auxiliary smart contract is needed, because the test engine has some limitations result = self.run_smart_contract(engine, path_aux, 'calling_transfer', NEO_SCRIPT, aux_address, zneo_address, 10_000_000 * 10 ** 8, None, signer_accounts=[aux_address], expected_result_type=bool) self.assertEqual(True, result) engine.add_gas(aux_address, 10_000_000 * 10 ** 8) # minting zGAS to this auxiliary smart contract is needed, because the test engine has some limitations result = self.run_smart_contract(engine, path_aux, 'calling_transfer', GAS_SCRIPT, aux_address, zgas_address, 10_000_000 * 10 ** 8, None, signer_accounts=[aux_address], expected_result_type=bool) self.assertEqual(True, result) # won't work, because the user did not allow the amm to transfer zNEO and zGAS with self.assertRaises(TestExecutionException, msg=self.ABORTED_CONTRACT_MSG): self.run_smart_contract(engine, path, 'add_liquidity', transferred_amount_zneo, transferred_amount_zgas, 0, 0, aux_address, signer_accounts=[aux_address]) # approving the AMM contract, so that it will be able to transfer zNEO from test_address result = self.run_smart_contract(engine, path_aux, 'calling_approve', zneo_address, amm_address, transferred_amount_zneo, signer_accounts=[aux_address], expected_result_type=bool) self.assertEqual(True, result) # approving the AMM contract, so that it will be able to transfer zGAS from test_address result = self.run_smart_contract(engine, path_aux, 'calling_approve', zgas_address, amm_address, transferred_amount_zgas, signer_accounts=[aux_address], expected_result_type=bool) self.assertEqual(True, result) # saving data to demonstrate that the value will change later total_supply_before = self.run_smart_contract(engine, path, 'totalSupply') balance_user_amm_before = self.run_smart_contract(engine, path, 'balanceOf', aux_address) reserves_before = self.run_smart_contract(engine, path, 'get_reserves') balance_user_zneo_before = self.run_smart_contract(engine, path_zneo, 'balanceOf', aux_address) balance_user_zgas_before = self.run_smart_contract(engine, path_zgas, 'balanceOf', aux_address) balance_amm_zneo_before = self.run_smart_contract(engine, path_zneo, 'balanceOf', amm_address) balance_amm_zgas_before = self.run_smart_contract(engine, path_zgas, 'balanceOf', amm_address) # adding liquidity to the pool will give you AMM tokens in return result = self.run_smart_contract(engine, path, 'add_liquidity', transferred_amount_zneo, transferred_amount_zgas, 0, 0, aux_address, signer_accounts=[aux_address]) import math liquidity = int(math.sqrt(transferred_amount_zneo * transferred_amount_zgas)) self.assertEqual(3, len(result)) self.assertEqual(transferred_amount_zneo, result[0]) self.assertEqual(transferred_amount_zgas, result[1]) self.assertEqual(liquidity, result[2]) transfer_events = engine.get_events('Transfer', origin=amm_address) self.assertEqual(1, len(transfer_events)) self.assertEqual(3, len(transfer_events[0].arguments)) sender, receiver, amount = transfer_events[0].arguments if isinstance(sender, str): sender = String(sender).to_bytes() if isinstance(receiver, str): receiver = String(receiver).to_bytes() self.assertEqual(None, sender) self.assertEqual(aux_address, receiver) self.assertEqual(liquidity, amount) sync_events = engine.get_events('Sync', origin=amm_address) self.assertEqual(1, len(sync_events)) self.assertEqual(2, len(sync_events[0].arguments)) balance_zneo, balance_zgas = sync_events[0].arguments self.assertEqual(transferred_amount_zneo, balance_zneo) self.assertEqual(transferred_amount_zgas, balance_zgas) mint_events = engine.get_events('Mint', origin=amm_address) self.assertEqual(1, len(mint_events)) self.assertEqual(3, len(mint_events[0].arguments)) address, amount_zneo, amount_zgas = mint_events[0].arguments if isinstance(address, str): address = String(address).to_bytes() self.assertEqual(aux_address, address) self.assertEqual(transferred_amount_zneo, amount_zneo) self.assertEqual(transferred_amount_zgas, amount_zgas) # data that will be compared with the previously saved data total_supply_after = self.run_smart_contract(engine, path, 'totalSupply') balance_user_amm_after = self.run_smart_contract(engine, path, 'balanceOf', aux_address) reserves_after = self.run_smart_contract(engine, path, 'get_reserves') balance_user_zneo_after = self.run_smart_contract(engine, path_zneo, 'balanceOf', aux_address) balance_user_zgas_after = self.run_smart_contract(engine, path_zgas, 'balanceOf', aux_address) balance_amm_zneo_after = self.run_smart_contract(engine, path_zneo, 'balanceOf', amm_address) balance_amm_zgas_after = self.run_smart_contract(engine, path_zgas, 'balanceOf', amm_address) self.assertEqual(total_supply_before + liquidity, total_supply_after) self.assertEqual(balance_user_amm_before + liquidity, balance_user_amm_after) self.assertEqual(reserves_before[0] + transferred_amount_zneo, reserves_after[0]) self.assertEqual(reserves_before[1] + transferred_amount_zgas, reserves_after[1]) self.assertEqual(balance_user_zneo_before - transferred_amount_zneo, balance_user_zneo_after) self.assertEqual(balance_user_zgas_before - transferred_amount_zgas, balance_user_zgas_after) self.assertEqual(reserves_before[0], balance_amm_zneo_before) self.assertEqual(reserves_before[1], balance_amm_zgas_before) self.assertEqual(reserves_after[0], balance_amm_zneo_after) self.assertEqual(reserves_after[1], balance_amm_zgas_after) transferred_amount_zneo = 2 * 10 ** 8 transferred_amount_zgas = 23 * 10 ** 8 # approving the AMM contract, so that it will be able to transfer zNEO from test_address result = self.run_smart_contract(engine, path_aux, 'calling_approve', zneo_address, amm_address, transferred_amount_zneo, signer_accounts=[aux_address], expected_result_type=bool) self.assertEqual(True, result) # approving the AMM contract, so that it will be able to transfer zGAS from test_address result = self.run_smart_contract(engine, path_aux, 'calling_approve', zgas_address, amm_address, transferred_amount_zgas, signer_accounts=[aux_address], expected_result_type=bool) self.assertEqual(True, result) # saving data to demonstrate that the value will change later total_supply_before = self.run_smart_contract(engine, path, 'totalSupply') balance_user_before = self.run_smart_contract(engine, path, 'balanceOf', aux_address) reserves_before = self.run_smart_contract(engine, path, 'get_reserves') balance_user_zneo_before = self.run_smart_contract(engine, path_zneo, 'balanceOf', aux_address) balance_user_zgas_before = self.run_smart_contract(engine, path_zgas, 'balanceOf', aux_address) balance_amm_zneo_before = self.run_smart_contract(engine, path_zneo, 'balanceOf', amm_address) balance_amm_zgas_before = self.run_smart_contract(engine, path_zgas, 'balanceOf', amm_address) # adding liquidity to the pool will give you AMM tokens in return result = self.run_smart_contract(engine, path, 'add_liquidity', transferred_amount_zneo, transferred_amount_zgas, 0, 0, aux_address, signer_accounts=[aux_address]) # zGAS will be quoted to keep the same ratio between zNEO and zGAS, the current ratio is 1 NEO to 11 GAS, # therefore, if 2 NEO are being added to the AMM, 22 GAS will be added instead of 23 transferred_amount_zgas_quoted = transferred_amount_zneo * reserves_before[1] // reserves_before[0] # since there are tokens in the pool already, liquidity will be calculated as follows liquidity = min(transferred_amount_zneo * total_supply_before // reserves_before[0], transferred_amount_zgas_quoted * total_supply_before // reserves_before[1]) self.assertEqual(3, len(result)) self.assertEqual(transferred_amount_zneo, result[0]) self.assertEqual(transferred_amount_zgas_quoted, result[1]) self.assertEqual(liquidity, result[2]) transfer_events = engine.get_events('Transfer', origin=amm_address) self.assertEqual(2, len(transfer_events)) self.assertEqual(3, len(transfer_events[1].arguments)) sender, receiver, amount = transfer_events[1].arguments if isinstance(sender, str): sender = String(sender).to_bytes() if isinstance(receiver, str): receiver = String(receiver).to_bytes() self.assertEqual(None, sender) self.assertEqual(aux_address, receiver) self.assertEqual(liquidity, amount) sync_events = engine.get_events('Sync', origin=amm_address) self.assertEqual(2, len(sync_events)) self.assertEqual(2, len(sync_events[1].arguments)) balance_zneo, balance_zgas = sync_events[1].arguments self.assertEqual(reserves_before[0] + transferred_amount_zneo, balance_zneo) self.assertEqual(reserves_before[1] + transferred_amount_zgas_quoted, balance_zgas) mint_events = engine.get_events('Mint', origin=amm_address) self.assertEqual(2, len(mint_events)) self.assertEqual(3, len(mint_events[1].arguments)) address, amount_zneo, amount_zgas = mint_events[1].arguments if isinstance(address, str): address = String(address).to_bytes() self.assertEqual(aux_address, address) self.assertEqual(transferred_amount_zneo, amount_zneo) self.assertEqual(transferred_amount_zgas_quoted, amount_zgas) # data that will be compared with the previously saved data total_supply_after = self.run_smart_contract(engine, path, 'totalSupply') balance_user_after = self.run_smart_contract(engine, path, 'balanceOf', aux_address) reserves_after = self.run_smart_contract(engine, path, 'get_reserves') balance_user_zneo_after = self.run_smart_contract(engine, path_zneo, 'balanceOf', aux_address) balance_user_zgas_after = self.run_smart_contract(engine, path_zgas, 'balanceOf', aux_address) balance_amm_zneo_after = self.run_smart_contract(engine, path_zneo, 'balanceOf', amm_address) balance_amm_zgas_after = self.run_smart_contract(engine, path_zgas, 'balanceOf', amm_address) self.assertEqual(total_supply_before + liquidity, total_supply_after) self.assertEqual(balance_user_before + liquidity, balance_user_after) self.assertEqual(reserves_before[0] + transferred_amount_zneo, reserves_after[0]) self.assertEqual(reserves_before[1] + transferred_amount_zgas_quoted, reserves_after[1]) self.assertEqual(balance_user_zneo_before - transferred_amount_zneo, balance_user_zneo_after) self.assertEqual(balance_user_zgas_before - transferred_amount_zgas_quoted, balance_user_zgas_after) self.assertEqual(reserves_before[0], balance_amm_zneo_before) self.assertEqual(reserves_before[1], balance_amm_zgas_before) self.assertEqual(reserves_after[0], balance_amm_zneo_after) self.assertEqual(reserves_after[1], balance_amm_zgas_after) def test_amm_remove_liquidity(self): transferred_amount_zneo = 10 * 10 ** 8 transferred_amount_zgas = 110 * 10 ** 8 path = self.get_contract_path('amm.py') path_zneo = self.get_contract_path('wrapped_neo.py') path_zgas = self.get_contract_path('wrapped_gas.py') path_aux = self.get_contract_path('examples/test_native', 'auxiliary_contract.py') engine = TestEngine() engine.add_contract(path.replace('.py', '.nef')) engine.add_contract(path_zneo.replace('.py', '.nef')) engine.add_contract(path_zgas.replace('.py', '.nef')) output, manifest = self.compile_and_save(path) amm_address = hash160(output) output, manifest = self.compile_and_save(path_zneo) zneo_address = hash160(output) output, manifest = self.compile_and_save(path_zgas) zgas_address = hash160(output) output, manifest = self.compile_and_save(path_aux) aux_address = hash160(output) result = self.run_smart_contract(engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) result = self.run_smart_contract(engine, path, 'set_address', zneo_address, zgas_address, signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # can't remove liquidity, because the user doesn't have any with self.assertRaises(TestExecutionException, msg=self.ABORTED_CONTRACT_MSG): self.run_smart_contract(engine, path, 'remove_liquidity', 10000, 0, 0, aux_address, signer_accounts=[self.OWNER_SCRIPT_HASH]) # deploying the wrapped_neo smart contract will give 10_000_000 zNEOs to the OWNER result = self.run_smart_contract(engine, path_zneo, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # transferring zNEO to this auxiliary smart contract is needed, because the test engine has some limitations result = self.run_smart_contract(engine, path_zneo, 'transfer', self.OWNER_SCRIPT_HASH, aux_address, 10_000_000 * 10 ** 8, None, signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # deploying the wrapped_gas smart contract will give 10_000_000 zGASs to the OWNER result = self.run_smart_contract(engine, path_zgas, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # transferring zGAS to this auxiliary smart contract is needed, because the test engine has some limitations result = self.run_smart_contract(engine, path_zgas, 'transfer', self.OWNER_SCRIPT_HASH, aux_address, 10_000_000 * 10 ** 8, None, signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # approving the AMM contract, so that it will be able to transfer zNEO from test_address result = self.run_smart_contract(engine, path_aux, 'calling_approve', zneo_address, amm_address, transferred_amount_zneo, signer_accounts=[aux_address], expected_result_type=bool) self.assertEqual(True, result) # approving the AMM contract, so that it will be able to transfer zGAS from test_address result = self.run_smart_contract(engine, path_aux, 'calling_approve', zgas_address, amm_address, transferred_amount_zgas, signer_accounts=[aux_address], expected_result_type=bool) self.assertEqual(True, result) # adding liquidity to the pool will give you AMM tokens in return result = self.run_smart_contract(engine, path, 'add_liquidity', transferred_amount_zneo, transferred_amount_zgas, 0, 0, aux_address, signer_accounts=[aux_address]) import math liquidity = int(math.sqrt(transferred_amount_zneo * transferred_amount_zgas)) self.assertEqual(3, len(result)) self.assertEqual(transferred_amount_zneo, result[0]) self.assertEqual(transferred_amount_zgas, result[1]) self.assertEqual(liquidity, result[2]) # saving data to demonstrate that the value will change later total_supply_before = self.run_smart_contract(engine, path, 'totalSupply') balance_user_before = self.run_smart_contract(engine, path, 'balanceOf', aux_address) reserves_before = self.run_smart_contract(engine, path, 'get_reserves') balance_user_zneo_before = self.run_smart_contract(engine, path_zneo, 'balanceOf', aux_address) balance_user_zgas_before = self.run_smart_contract(engine, path_zgas, 'balanceOf', aux_address) balance_amm_zneo_before = self.run_smart_contract(engine, path_zneo, 'balanceOf', amm_address) balance_amm_zgas_before = self.run_smart_contract(engine, path_zgas, 'balanceOf', amm_address) # removing liquidity from the pool will return the equivalent zNEO and zGAS that were used to fund the pool result = self.run_smart_contract(engine, path, 'remove_liquidity', liquidity, 0, 0, aux_address, signer_accounts=[aux_address]) self.assertEqual(2, len(result)) self.assertEqual(transferred_amount_zneo, result[0]) self.assertEqual(transferred_amount_zgas, result[1]) transfer_events = engine.get_events('Transfer', origin=amm_address) # add_liquidity sent a Transfer event and remove_liquidity sent another self.assertEqual(2, len(transfer_events)) self.assertEqual(3, len(transfer_events[1].arguments)) sender, receiver, amount = transfer_events[1].arguments if isinstance(sender, str): sender = String(sender).to_bytes() if isinstance(receiver, str): receiver = String(receiver).to_bytes() self.assertEqual(aux_address, sender) self.assertEqual(None, receiver) self.assertEqual(liquidity, amount) sync_events = engine.get_events('Sync', origin=amm_address) self.assertEqual(2, len(sync_events)) self.assertEqual(2, len(sync_events[1].arguments)) balance_zneo, balance_zgas = sync_events[1].arguments self.assertEqual(reserves_before[0] - transferred_amount_zneo, balance_zneo) self.assertEqual(reserves_before[1] - transferred_amount_zgas, balance_zgas) burn_events = engine.get_events('Burn', origin=amm_address) self.assertEqual(1, len(burn_events)) self.assertEqual(3, len(burn_events[0].arguments)) address, amount_zneo, amount_zgas = burn_events[0].arguments if isinstance(address, str): address = String(address).to_bytes() self.assertEqual(aux_address, address) self.assertEqual(transferred_amount_zneo, amount_zneo) self.assertEqual(transferred_amount_zgas, amount_zgas) # data that will be compared with the previously saved data total_supply_after = self.run_smart_contract(engine, path, 'totalSupply') balance_user_after = self.run_smart_contract(engine, path, 'balanceOf', aux_address) reserves_after = self.run_smart_contract(engine, path, 'get_reserves') balance_user_zneo_after = self.run_smart_contract(engine, path_zneo, 'balanceOf', aux_address) balance_user_zgas_after = self.run_smart_contract(engine, path_zgas, 'balanceOf', aux_address) balance_amm_zneo_after = self.run_smart_contract(engine, path_zneo, 'balanceOf', amm_address) balance_amm_zgas_after = self.run_smart_contract(engine, path_zgas, 'balanceOf', amm_address) self.assertEqual(total_supply_before - liquidity, total_supply_after) self.assertEqual(balance_user_before - liquidity, balance_user_after) self.assertEqual(reserves_before[0] - transferred_amount_zneo, reserves_after[0]) self.assertEqual(reserves_before[1] - transferred_amount_zgas, reserves_after[1]) self.assertEqual(balance_user_zneo_before + transferred_amount_zneo, balance_user_zneo_after) self.assertEqual(balance_user_zgas_before + transferred_amount_zgas, balance_user_zgas_after) self.assertEqual(reserves_before[0], balance_amm_zneo_before) self.assertEqual(reserves_before[1], balance_amm_zgas_before) self.assertEqual(reserves_after[0], balance_amm_zneo_after) self.assertEqual(reserves_after[1], balance_amm_zgas_after) def test_amm_swap_zneo_to_zgas(self): transferred_amount_zneo = 10 * 10 ** 8 transferred_amount_zgas = 110 * 10 ** 8 path = self.get_contract_path('amm.py') path_zneo = self.get_contract_path('wrapped_neo.py') path_zgas = self.get_contract_path('wrapped_gas.py') path_aux = self.get_contract_path('examples/test_native', 'auxiliary_contract.py') engine = TestEngine() engine.add_contract(path.replace('.py', '.nef')) engine.add_contract(path_zneo.replace('.py', '.nef')) engine.add_contract(path_zgas.replace('.py', '.nef')) output, manifest = self.compile_and_save(path) amm_address = hash160(output) output, manifest = self.compile_and_save(path_zneo) zneo_address = hash160(output) output, manifest = self.compile_and_save(path_zgas) zgas_address = hash160(output) output, manifest = self.compile_and_save(path_aux) aux_address = hash160(output) result = self.run_smart_contract(engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) result = self.run_smart_contract(engine, path, 'set_address', zneo_address, zgas_address, signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # deploying the wrapped_neo smart contract will give 10_000_000 zNEOs to the OWNER result = self.run_smart_contract(engine, path_zneo, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # transferring zNEO to this auxiliary smart contract is needed, because the test engine has some limitations result = self.run_smart_contract(engine, path_zneo, 'transfer', self.OWNER_SCRIPT_HASH, aux_address, 10_000_000 * 10 ** 8, None, signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # deploying the wrapped_gas smart contract will give 10_000_000 zGASs to the OWNER result = self.run_smart_contract(engine, path_zgas, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # transferring zGAS to this auxiliary smart contract is needed, because the test engine has some limitations result = self.run_smart_contract(engine, path_zgas, 'transfer', self.OWNER_SCRIPT_HASH, aux_address, 10_000_000 * 10 ** 8, None, signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # approving the AMM contract, so that it will be able to transfer zNEO from test_address result = self.run_smart_contract(engine, path_aux, 'calling_approve', zneo_address, amm_address, transferred_amount_zneo, signer_accounts=[aux_address], expected_result_type=bool) self.assertEqual(True, result) # approving the AMM contract, so that it will be able to transfer zGAS from test_address result = self.run_smart_contract(engine, path_aux, 'calling_approve', zgas_address, amm_address, transferred_amount_zgas, signer_accounts=[aux_address], expected_result_type=bool) self.assertEqual(True, result) # adding liquidity to the pool will give you AMM tokens in return result = self.run_smart_contract(engine, path, 'add_liquidity', transferred_amount_zneo, transferred_amount_zgas, 0, 0, aux_address, signer_accounts=[aux_address]) import math liquidity = int(math.sqrt(transferred_amount_zneo * transferred_amount_zgas)) self.assertEqual(3, len(result)) self.assertEqual(transferred_amount_zneo, result[0]) self.assertEqual(transferred_amount_zgas, result[1]) self.assertEqual(liquidity, result[2]) swapped_zneo = 1 * 10 ** 8 # won't work, because user did not enough zNEO tokens with self.assertRaises(TestExecutionException, msg=self.ABORTED_CONTRACT_MSG): self.run_smart_contract(engine, path, 'swap_tokens', swapped_zneo, 0, zneo_address, aux_address, signer_accounts=[aux_address]) # approving the AMM contract, so that it will be able to transfer zNEO from test_address result = self.run_smart_contract(engine, path_aux, 'calling_approve', zneo_address, amm_address, swapped_zneo, signer_accounts=[aux_address], expected_result_type=bool) self.assertEqual(True, result) # saving data to demonstrate that the value will change later total_supply_before = self.run_smart_contract(engine, path, 'totalSupply') reserves_before = self.run_smart_contract(engine, path, 'get_reserves') balance_user_zneo_before = self.run_smart_contract(engine, path_zneo, 'balanceOf', aux_address) balance_user_zgas_before = self.run_smart_contract(engine, path_zgas, 'balanceOf', aux_address) balance_amm_zneo_before = self.run_smart_contract(engine, path_zneo, 'balanceOf', amm_address) balance_amm_zgas_before = self.run_smart_contract(engine, path_zgas, 'balanceOf', amm_address) # swapping zneo for zgas result = self.run_smart_contract(engine, path, 'swap_tokens', swapped_zneo, 0, zneo_address, aux_address, signer_accounts=[aux_address], rollback_on_fault=False) # there is a 0.3% fee when doing a swap swapped_zneo_with_fee = swapped_zneo * (1000 - 3) swapped_zgas = swapped_zneo_with_fee * reserves_before[1] // (reserves_before[0] * 1000 + swapped_zneo_with_fee) self.assertEqual(swapped_zgas, result) # add_liquidity sent a Sync before transfer_events = engine.get_events('Sync') self.assertEqual(2, len(transfer_events)) self.assertEqual(2, len(transfer_events[1].arguments)) balance_zneo, balance_zgas = transfer_events[1].arguments self.assertEqual(reserves_before[0] + swapped_zneo, balance_zneo) self.assertEqual(reserves_before[1] - swapped_zgas, balance_zgas) transfer_events = engine.get_events('Swap') self.assertEqual(1, len(transfer_events)) self.assertEqual(5, len(transfer_events[0].arguments)) address, amount_zneo_in, amount_zgas_in, amount_zneo_out, amount_zgas_out = transfer_events[0].arguments if isinstance(address, str): address = String(address).to_bytes() self.assertEqual(aux_address, address) self.assertEqual(swapped_zneo, amount_zneo_in) self.assertEqual(0, amount_zgas_in) self.assertEqual(0, amount_zneo_out) self.assertEqual(swapped_zgas, amount_zgas_out) # data that will be compared with the previously saved data total_supply_after = self.run_smart_contract(engine, path, 'totalSupply') reserves_after = self.run_smart_contract(engine, path, 'get_reserves') balance_user_zneo_after = self.run_smart_contract(engine, path_zneo, 'balanceOf', aux_address) balance_user_zgas_after = self.run_smart_contract(engine, path_zgas, 'balanceOf', aux_address) balance_amm_zneo_after = self.run_smart_contract(engine, path_zneo, 'balanceOf', amm_address) balance_amm_zgas_after = self.run_smart_contract(engine, path_zgas, 'balanceOf', amm_address) self.assertEqual(total_supply_before, total_supply_after) self.assertEqual(reserves_before[0] + swapped_zneo, reserves_after[0]) self.assertEqual(reserves_before[1] - swapped_zgas, reserves_after[1]) self.assertEqual(balance_user_zneo_before - swapped_zneo, balance_user_zneo_after) self.assertEqual(balance_user_zgas_before + swapped_zgas, balance_user_zgas_after) self.assertEqual(reserves_before[0], balance_amm_zneo_before) self.assertEqual(reserves_before[1], balance_amm_zgas_before) self.assertEqual(reserves_after[0], balance_amm_zneo_after) self.assertEqual(reserves_after[1], balance_amm_zgas_after) self.assertEqual(reserves_before[0] + swapped_zneo, reserves_after[0]) self.assertEqual(reserves_before[1] - swapped_zgas, reserves_after[1]) def test_amm_swap_zgas_to_zneo(self): transferred_amount_zneo = 10 * 10 ** 8 transferred_amount_zgas = 110 * 10 ** 8 path = self.get_contract_path('amm.py') path_zneo = self.get_contract_path('wrapped_neo.py') path_zgas = self.get_contract_path('wrapped_gas.py') path_aux = self.get_contract_path('examples/test_native', 'auxiliary_contract.py') engine = TestEngine() engine.add_contract(path.replace('.py', '.nef')) engine.add_contract(path_zneo.replace('.py', '.nef')) engine.add_contract(path_zgas.replace('.py', '.nef')) output, manifest = self.compile_and_save(path) amm_address = hash160(output) output, manifest = self.compile_and_save(path_zneo) zneo_address = hash160(output) output, manifest = self.compile_and_save(path_zgas) zgas_address = hash160(output) output, manifest = self.compile_and_save(path_aux) aux_address = hash160(output) result = self.run_smart_contract(engine, path, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) result = self.run_smart_contract(engine, path, 'set_address', zneo_address, zgas_address, signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # deploying the wrapped_neo smart contract will give 10_000_000 zNEOs to the OWNER result = self.run_smart_contract(engine, path_zneo, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # transferring zNEO to this auxiliary smart contract is needed, because the test engine has some limitations result = self.run_smart_contract(engine, path_zneo, 'transfer', self.OWNER_SCRIPT_HASH, aux_address, 10_000_000 * 10 ** 8, None, signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # deploying the wrapped_gas smart contract will give 10_000_000 zGASs to the OWNER result = self.run_smart_contract(engine, path_zgas, 'deploy', signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # transferring zGAS to this auxiliary smart contract is needed, because the test engine has some limitations result = self.run_smart_contract(engine, path_zgas, 'transfer', self.OWNER_SCRIPT_HASH, aux_address, 10_000_000 * 10 ** 8, None, signer_accounts=[self.OWNER_SCRIPT_HASH], expected_result_type=bool) self.assertEqual(True, result) # approving the AMM contract, so that it will be able to transfer zNEO from test_address result = self.run_smart_contract(engine, path_aux, 'calling_approve', zneo_address, amm_address, transferred_amount_zneo, signer_accounts=[aux_address], expected_result_type=bool) self.assertEqual(True, result) # approving the AMM contract, so that it will be able to transfer zGAS from test_address result = self.run_smart_contract(engine, path_aux, 'calling_approve', zgas_address, amm_address, transferred_amount_zgas, signer_accounts=[aux_address], expected_result_type=bool) self.assertEqual(True, result) # adding liquidity to the pool will give you AMM tokens in return result = self.run_smart_contract(engine, path, 'add_liquidity', transferred_amount_zneo, transferred_amount_zgas, 0, 0, aux_address, signer_accounts=[aux_address]) import math liquidity = int(math.sqrt(transferred_amount_zneo * transferred_amount_zgas)) self.assertEqual(3, len(result)) self.assertEqual(transferred_amount_zneo, result[0]) self.assertEqual(transferred_amount_zgas, result[1]) self.assertEqual(liquidity, result[2]) swapped_zgas = 11 * 10 ** 8 # won't work, because user did not enough zNEO tokens with self.assertRaises(TestExecutionException, msg=self.ABORTED_CONTRACT_MSG): self.run_smart_contract(engine, path, 'swap_tokens', swapped_zgas, 0, zgas_address, aux_address, signer_accounts=[aux_address]) # approving the AMM contract, so that it will be able to transfer zNEO from test_address result = self.run_smart_contract(engine, path_aux, 'calling_approve', zgas_address, amm_address, swapped_zgas, signer_accounts=[aux_address], expected_result_type=bool) self.assertEqual(True, result) # saving data to demonstrate that the value will change later total_supply_before = self.run_smart_contract(engine, path, 'totalSupply') reserves_before = self.run_smart_contract(engine, path, 'get_reserves') balance_user_zneo_before = self.run_smart_contract(engine, path_zneo, 'balanceOf', aux_address) balance_user_zgas_before = self.run_smart_contract(engine, path_zgas, 'balanceOf', aux_address) balance_amm_zneo_before = self.run_smart_contract(engine, path_zneo, 'balanceOf', amm_address) balance_amm_zgas_before = self.run_smart_contract(engine, path_zgas, 'balanceOf', amm_address) # swapping zgas for zneo result = self.run_smart_contract(engine, path, 'swap_tokens', swapped_zgas, 0, zgas_address, aux_address, signer_accounts=[aux_address]) # there is a 0.3% fee when doing a swap swapped_zgas_with_fee = swapped_zgas * (1000 - 3) swapped_zneo = swapped_zgas_with_fee * reserves_before[0] // (reserves_before[1] * 1000 + swapped_zgas_with_fee) self.assertEqual(swapped_zneo, result) # add_liquidity sent a Sync before transfer_events = engine.get_events('Sync') self.assertEqual(2, len(transfer_events)) self.assertEqual(2, len(transfer_events[1].arguments)) balance_zneo, balance_zgas = transfer_events[1].arguments self.assertEqual(reserves_before[0] - swapped_zneo, balance_zneo) self.assertEqual(reserves_before[1] + swapped_zgas, balance_zgas) transfer_events = engine.get_events('Swap') self.assertEqual(1, len(transfer_events)) self.assertEqual(5, len(transfer_events[0].arguments)) address, amount_zneo_in, amount_zgas_in, amount_zneo_out, amount_zgas_out = transfer_events[0].arguments if isinstance(address, str): address = String(address).to_bytes() self.assertEqual(aux_address, address) self.assertEqual(0, amount_zneo_in) self.assertEqual(swapped_zgas, amount_zgas_in) self.assertEqual(swapped_zneo, amount_zneo_out) self.assertEqual(0, amount_zgas_out) # data that will be compared with the previously saved data total_supply_after = self.run_smart_contract(engine, path, 'totalSupply') reserves_after = self.run_smart_contract(engine, path, 'get_reserves') balance_user_zneo_after = self.run_smart_contract(engine, path_zneo, 'balanceOf', aux_address) balance_user_zgas_after = self.run_smart_contract(engine, path_zgas, 'balanceOf', aux_address) balance_amm_zneo_after = self.run_smart_contract(engine, path_zneo, 'balanceOf', amm_address) balance_amm_zgas_after = self.run_smart_contract(engine, path_zgas, 'balanceOf', amm_address) self.assertEqual(total_supply_before, total_supply_after) self.assertEqual(reserves_before[0] - swapped_zneo, reserves_after[0]) self.assertEqual(reserves_before[1] + swapped_zgas, reserves_after[1]) self.assertEqual(balance_user_zneo_before + swapped_zneo, balance_user_zneo_after) self.assertEqual(balance_user_zgas_before - swapped_zgas, balance_user_zgas_after) self.assertEqual(reserves_before[0], balance_amm_zneo_before) self.assertEqual(reserves_before[1], balance_amm_zgas_before) self.assertEqual(reserves_after[0], balance_amm_zneo_after) self.assertEqual(reserves_after[1], balance_amm_zgas_after) self.assertEqual(reserves_before[0] - swapped_zneo, reserves_after[0]) self.assertEqual(reserves_before[1] + swapped_zgas, reserves_after[1])
class TestTemplate(BoaTest): default_folder: str = 'examples' OWNER_SCRIPT_HASH = bytes(20) OTHER_ACCOUNT_1 = to_script_hash(b'NiNmXL8FjEUEs1nfX9uHFBNaenxDHJtmuB') OTHER_ACCOUNT_2 = bytes(range(20)) KYC_WHITELIST_PREFIX = b'KYCWhitelistApproved' def test_ico_compile(self): path = self.get_contract_path('ico.py') Boa3.compile(path) def test_ico_verify(self): path = self.get_contract_path('ico.py') engine = TestEngine() result = self.run_smart_contract( engine, path, 'verify', signer_accounts=[self.OTHER_ACCOUNT_1]) self.assertEqual(False, result) result = self.run_smart_contract( engine, path, 'verify', signer_accounts=[self.OWNER_SCRIPT_HASH]) self.assertEqual(True, result) def test_ico_total_supply(self): path = self.get_contract_path('ico.py') engine = TestEngine() total_supply = 10_000_000 * 10**8 result = self.run_smart_contract( engine, path, 'totalSupply', signer_accounts=[self.OWNER_SCRIPT_HASH]) self.assertEqual(total_supply, result) def test_ico_symbol(self): path = self.get_contract_path('ico.py') engine = TestEngine() result = self.run_smart_contract(engine, path, 'symbol') self.assertEqual('ICO', result) def test_ico_decimals(self): path = self.get_contract_path('ico.py') engine = TestEngine() result = self.run_smart_contract(engine, path, 'decimals') self.assertEqual(8, result) def test_ico_total_balance_of(self): total_supply = 10_000_000 * 10**8 path = self.get_contract_path('ico.py') engine = TestEngine() result = self.run_smart_contract(engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) self.assertEqual(total_supply, result) # should fail when the script length is not 20 with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'balanceOf', bytes(10)) with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'balanceOf', bytes(30)) def test_ico_kyc_register(self): path = self.get_contract_path('ico.py') engine = TestEngine() # don't include if not signed by the administrator result = self.run_smart_contract( engine, path, 'kyc_register', [self.OWNER_SCRIPT_HASH, bytes(22)]) self.assertEqual(0, result) # don't include script hashes with size different than 20 result = self.run_smart_contract( engine, path, 'kyc_register', [bytes(40), self.OWNER_SCRIPT_HASH, bytes(12)], signer_accounts=[self.OWNER_SCRIPT_HASH]) self.assertEqual(1, result) storage_value = engine.storage_get( self.KYC_WHITELIST_PREFIX + self.OWNER_SCRIPT_HASH, path) self.assertIsNotNone(storage_value) # script hashes already registered are returned as well result = self.run_smart_contract( engine, path, 'kyc_register', [self.OWNER_SCRIPT_HASH, self.OTHER_ACCOUNT_1], signer_accounts=[self.OWNER_SCRIPT_HASH]) self.assertEqual(2, result) storage_value = engine.storage_get( self.KYC_WHITELIST_PREFIX + self.OTHER_ACCOUNT_1, path) self.assertIsNotNone(storage_value) def test_ico_kyc_remove(self): path = self.get_contract_path('ico.py') engine = TestEngine() # don't remove if not signed by the administrator result = self.run_smart_contract( engine, path, 'kyc_remove', [self.OWNER_SCRIPT_HASH, bytes(22)]) self.assertEqual(0, result) # script hashes that weren't registered are returned as well self.assertTrue(self.KYC_WHITELIST_PREFIX + self.OTHER_ACCOUNT_1 not in engine.storage) result = self.run_smart_contract( engine, path, 'kyc_remove', [self.OTHER_ACCOUNT_1], signer_accounts=[self.OWNER_SCRIPT_HASH]) self.assertEqual(1, result) self.assertTrue(self.KYC_WHITELIST_PREFIX + self.OTHER_ACCOUNT_1 not in engine.storage) # don't include script hashes with size different than 20 result = self.run_smart_contract( engine, path, 'kyc_remove', [bytes(40), self.OWNER_SCRIPT_HASH, bytes(12)], signer_accounts=[self.OWNER_SCRIPT_HASH]) self.assertEqual(1, result) def test_ico_approve(self): path = self.get_contract_path('ico.py') engine = TestEngine() approved_amount = 100 * 10**8 # should fail when any of the scripts' length is not 20 with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'approve', self.OWNER_SCRIPT_HASH, bytes(10), approved_amount) with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'approve', bytes(10), self.OTHER_ACCOUNT_1, approved_amount) # should fail when the amount is less than 0 with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'approve', self.OTHER_ACCOUNT_1, self.OWNER_SCRIPT_HASH, -10) # should fail if the origin doesn't sign result = self.run_smart_contract(engine, path, 'approve', self.OWNER_SCRIPT_HASH, self.OTHER_ACCOUNT_1, approved_amount) self.assertEqual(False, result) # should fail if origin and target are the same result = self.run_smart_contract( engine, path, 'approve', self.OWNER_SCRIPT_HASH, self.OWNER_SCRIPT_HASH, approved_amount, signer_accounts=[self.OWNER_SCRIPT_HASH]) self.assertEqual(False, result) # should fail if any of the addresses is not included in the kyc result = self.run_smart_contract( engine, path, 'approve', self.OWNER_SCRIPT_HASH, self.OTHER_ACCOUNT_1, approved_amount, signer_accounts=[self.OWNER_SCRIPT_HASH]) self.assertEqual(False, result) result = self.run_smart_contract( engine, path, 'kyc_register', [self.OWNER_SCRIPT_HASH, self.OTHER_ACCOUNT_1], signer_accounts=[self.OWNER_SCRIPT_HASH]) self.assertEqual(2, result) result = self.run_smart_contract( engine, path, 'approve', self.OWNER_SCRIPT_HASH, self.OTHER_ACCOUNT_1, approved_amount, signer_accounts=[self.OWNER_SCRIPT_HASH]) self.assertEqual(True, result) def test_ico_allowance(self): path = self.get_contract_path('ico.py') engine = TestEngine() approved_amount = 100 * 10**8 result = self.run_smart_contract(engine, path, 'allowance', self.OWNER_SCRIPT_HASH, self.OTHER_ACCOUNT_1) self.assertEqual(0, result) result = self.run_smart_contract( engine, path, 'kyc_register', [self.OWNER_SCRIPT_HASH, self.OTHER_ACCOUNT_1], signer_accounts=[self.OWNER_SCRIPT_HASH]) self.assertEqual(2, result) result = self.run_smart_contract( engine, path, 'approve', self.OWNER_SCRIPT_HASH, self.OTHER_ACCOUNT_1, approved_amount, signer_accounts=[self.OWNER_SCRIPT_HASH]) self.assertEqual(True, result) result = self.run_smart_contract(engine, path, 'allowance', self.OWNER_SCRIPT_HASH, self.OTHER_ACCOUNT_1) self.assertEqual(approved_amount, result) def test_ico_transfer_from(self): path = self.get_contract_path('ico.py') engine = TestEngine() transferred_amount = 100 * 10**8 # should fail when any of the scripts' length is not 20 with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'transferFrom', self.OWNER_SCRIPT_HASH, bytes(10), self.OTHER_ACCOUNT_2, transferred_amount, None) with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'transferFrom', bytes(10), self.OTHER_ACCOUNT_1, self.OTHER_ACCOUNT_2, transferred_amount, None) with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'transferFrom', self.OWNER_SCRIPT_HASH, self.OTHER_ACCOUNT_1, bytes(30), transferred_amount, None) # should fail when the amount is less than 0 with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'transferFrom', self.OWNER_SCRIPT_HASH, self.OTHER_ACCOUNT_1, self.OTHER_ACCOUNT_2, -10, None) # should fail if the sender doesn't sign result = self.run_smart_contract(engine, path, 'transferFrom', self.OWNER_SCRIPT_HASH, self.OTHER_ACCOUNT_1, self.OTHER_ACCOUNT_2, transferred_amount, None) self.assertEqual(False, result) # should fail if the allowed amount is less than the given amount result = self.run_smart_contract( engine, path, 'transferFrom', self.OWNER_SCRIPT_HASH, self.OTHER_ACCOUNT_1, self.OTHER_ACCOUNT_2, transferred_amount, None, signer_accounts=[self.OTHER_ACCOUNT_1]) self.assertEqual(False, result) result = self.run_smart_contract( engine, path, 'kyc_register', [self.OWNER_SCRIPT_HASH, self.OTHER_ACCOUNT_1], signer_accounts=[self.OWNER_SCRIPT_HASH]) self.assertEqual(2, result) result = self.run_smart_contract( engine, path, 'approve', self.OWNER_SCRIPT_HASH, self.OTHER_ACCOUNT_1, transferred_amount * 2, signer_accounts=[self.OWNER_SCRIPT_HASH]) self.assertEqual(True, result) # doesn't fire the transfer event when transferring to yourself or amount is zero balance_before = self.run_smart_contract(engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) result = self.run_smart_contract( engine, path, 'transferFrom', self.OWNER_SCRIPT_HASH, self.OTHER_ACCOUNT_1, self.OWNER_SCRIPT_HASH, transferred_amount, None, signer_accounts=[self.OTHER_ACCOUNT_1]) self.assertEqual(True, result) self.assertEqual(0, len(engine.get_events('transfer'))) balance_after = self.run_smart_contract(engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) self.assertEqual(balance_after, balance_before) balance_before = self.run_smart_contract(engine, path, 'balanceOf', self.OTHER_ACCOUNT_1) result = self.run_smart_contract( engine, path, 'transferFrom', self.OWNER_SCRIPT_HASH, self.OTHER_ACCOUNT_1, self.OTHER_ACCOUNT_1, transferred_amount, None, signer_accounts=[self.OTHER_ACCOUNT_1]) self.assertEqual(True, result) self.assertEqual(0, len(engine.get_events('transfer'))) balance_after = self.run_smart_contract(engine, path, 'balanceOf', self.OTHER_ACCOUNT_1) self.assertEqual(balance_after, balance_before) result = self.run_smart_contract( engine, path, 'transferFrom', self.OWNER_SCRIPT_HASH, self.OTHER_ACCOUNT_1, self.OTHER_ACCOUNT_2, 0, None, signer_accounts=[self.OTHER_ACCOUNT_1]) self.assertEqual(True, result) self.assertEqual(0, len(engine.get_events('transfer'))) balance_originator_before = self.run_smart_contract( engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) balance_sender_before = self.run_smart_contract( engine, path, 'balanceOf', self.OTHER_ACCOUNT_1) balance_receiver_before = self.run_smart_contract( engine, path, 'balanceOf', self.OTHER_ACCOUNT_2) result = self.run_smart_contract( engine, path, 'transferFrom', self.OWNER_SCRIPT_HASH, self.OTHER_ACCOUNT_1, self.OTHER_ACCOUNT_2, transferred_amount, None, signer_accounts=[self.OTHER_ACCOUNT_1]) self.assertEqual(False, result) balance_originator_after = self.run_smart_contract( engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) self.assertEqual(balance_originator_before, balance_originator_after) balance_sender_after = self.run_smart_contract(engine, path, 'balanceOf', self.OTHER_ACCOUNT_1) self.assertEqual(balance_sender_before, balance_sender_after) balance_receiver_after = self.run_smart_contract( engine, path, 'balanceOf', self.OTHER_ACCOUNT_2) self.assertEqual(balance_receiver_before, balance_receiver_after) def test_ico_mint(self): path = self.get_contract_path('ico.py') engine = TestEngine() # should fail if amount is a negative number with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'mint', -10 * 10**8) minted_amount = 10_000 * 10**8 # should fail if not signed by the administrator result = self.run_smart_contract(engine, path, 'mint', minted_amount) self.assertEqual(False, result) total_supply_before = self.run_smart_contract(engine, path, 'totalSupply') owner_balance_before = self.run_smart_contract(engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) result = self.run_smart_contract( engine, path, 'mint', minted_amount, signer_accounts=[self.OWNER_SCRIPT_HASH]) self.assertEqual(True, result) total_supply_after = self.run_smart_contract(engine, path, 'totalSupply') self.assertEqual(total_supply_before + minted_amount, total_supply_after) owner_balance_after = self.run_smart_contract(engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) self.assertEqual(owner_balance_before + minted_amount, owner_balance_after) def test_ico_refund(self): path = self.get_contract_path('ico.py') engine = TestEngine() transferred_amount = 10_000 # should fail script hash length is not 20 with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'refund', bytes(10), transferred_amount, transferred_amount) # should fail no amount is a positive number with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'refund', self.OWNER_SCRIPT_HASH, 0, 0) # should fail if not signed by the owner result = self.run_smart_contract(engine, path, 'refund', self.OWNER_SCRIPT_HASH, transferred_amount, transferred_amount) self.assertEqual(False, result)
def test_script_hash(self): script = self.test_script nef = self.create_test_nef(script) self.assertEqual(len(nef.script_hash), 20) self.assertEqual(nef.script_hash, to_script_hash(script))
class TestTemplate(BoaTest): default_folder: str = 'examples' OWNER_SCRIPT_HASH = bytes(20) OTHER_ACCOUNT_1 = to_script_hash(b'NiNmXL8FjEUEs1nfX9uHFBNaenxDHJtmuB') def test_nep5_compile(self): path = self.get_contract_path('nep5.py') Boa3.compile(path) def test_nep5_name(self): path = self.get_contract_path('nep5.py') engine = TestEngine() result = self.run_smart_contract(engine, path, 'name') self.assertEqual('NEP5 Standard', result) def test_nep5_symbol(self): path = self.get_contract_path('nep5.py') engine = TestEngine() result = self.run_smart_contract(engine, path, 'symbol') self.assertEqual('NEP5', result) def test_nep5_decimals(self): path = self.get_contract_path('nep5.py') engine = TestEngine() result = self.run_smart_contract(engine, path, 'decimals') self.assertEqual(8, result) def test_nep5_total_supply(self): total_supply = 10_000_000 * 10**8 path = self.get_contract_path('nep5.py') engine = TestEngine() result = self.run_smart_contract(engine, path, 'totalSupply') self.assertEqual(total_supply, result) def test_nep5_total_balance_of(self): total_supply = 10_000_000 * 10**8 path = self.get_contract_path('nep5.py') engine = TestEngine() result = self.run_smart_contract(engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) self.assertEqual(total_supply, result) # should fail when the script length is not 20 with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'balanceOf', bytes(10)) with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'balanceOf', bytes(30)) def test_nep5_total_transfer(self): transferred_amount = 10 * 10**8 # 10 tokens path = self.get_contract_path('nep5.py') engine = TestEngine() # should fail if the sender doesn't sign result = self.run_smart_contract(engine, path, 'transfer', self.OWNER_SCRIPT_HASH, self.OTHER_ACCOUNT_1, transferred_amount) self.assertEqual(False, result) # other account doesn't have enough balance result = self.run_smart_contract( engine, path, 'transfer', self.OTHER_ACCOUNT_1, self.OWNER_SCRIPT_HASH, transferred_amount, signer_accounts=[self.OTHER_ACCOUNT_1]) self.assertEqual(False, result) # should fail when any of the scripts' length is not 20 with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'transfer', self.OWNER_SCRIPT_HASH, bytes(10), transferred_amount) with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'transfer', bytes(10), self.OTHER_ACCOUNT_1, transferred_amount) # should fail when the amount is less than 0 with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'transfer', self.OTHER_ACCOUNT_1, self.OWNER_SCRIPT_HASH, -10) # doesn't fire the transfer event when transferring to yourself balance_before = self.run_smart_contract(engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) result = self.run_smart_contract( engine, path, 'transfer', self.OWNER_SCRIPT_HASH, self.OWNER_SCRIPT_HASH, transferred_amount, signer_accounts=[self.OWNER_SCRIPT_HASH]) self.assertEqual(True, result) transfer_events = engine.get_events('transfer') # there is one transfer event thanks to the deploy self.assertEqual(1, len(transfer_events)) # transferring to yourself doesn't change the balance balance_after = self.run_smart_contract(engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) self.assertEqual(balance_before, balance_after) # doesn't fire the transfer event when transferring to yourself balance_sender_before = self.run_smart_contract( engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) balance_receiver_before = self.run_smart_contract( engine, path, 'balanceOf', self.OTHER_ACCOUNT_1) result = self.run_smart_contract( engine, path, 'transfer', self.OWNER_SCRIPT_HASH, self.OTHER_ACCOUNT_1, transferred_amount, signer_accounts=[self.OWNER_SCRIPT_HASH]) self.assertEqual(True, result) transfer_events = engine.get_events('transfer') self.assertEqual(2, len(transfer_events)) self.assertEqual(3, len(transfer_events[1].arguments)) sender, receiver, amount = transfer_events[1].arguments if isinstance(sender, str): sender = String(sender).to_bytes() if isinstance(receiver, str): receiver = String(sender).to_bytes() self.assertEqual(self.OWNER_SCRIPT_HASH, sender) self.assertEqual(self.OTHER_ACCOUNT_1, receiver) self.assertEqual(transferred_amount, amount) # transferring to yourself doesn't change the balance balance_sender_after = self.run_smart_contract(engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) balance_receiver_after = self.run_smart_contract( engine, path, 'balanceOf', self.OTHER_ACCOUNT_1) self.assertEqual(balance_sender_before - transferred_amount, balance_sender_after) self.assertEqual(balance_receiver_before + transferred_amount, balance_receiver_after) def test_nep5_verify(self): path = self.get_contract_path('nep5.py') engine = TestEngine() # should fail without signature result = self.run_smart_contract(engine, path, 'verify') self.assertEqual(False, result) # should fail if not signed by the owner result = self.run_smart_contract( engine, path, 'verify', signer_accounts=[self.OTHER_ACCOUNT_1]) self.assertEqual(False, result) result = self.run_smart_contract( engine, path, 'verify', signer_accounts=[self.OWNER_SCRIPT_HASH]) self.assertEqual(True, result)
class TestNEP17Template(BoaTest): default_folder: str = 'examples' OWNER_SCRIPT_HASH = bytes(20) OTHER_ACCOUNT_1 = to_script_hash(b'NiNmXL8FjEUEs1nfX9uHFBNaenxDHJtmuB') OTHER_ACCOUNT_2 = bytes(range(20)) def test_nep17_compile(self): path = self.get_contract_path('nep17.py') output, manifest = self.compile_and_save(path) self.assertIn('supportedstandards', manifest) self.assertIsInstance(manifest['supportedstandards'], list) self.assertGreater(len(manifest['supportedstandards']), 0) self.assertIn('NEP-17', manifest['supportedstandards']) def test_nep17_symbol(self): path = self.get_contract_path('nep17.py') engine = TestEngine() result = self.run_smart_contract(engine, path, 'symbol') self.assertEqual('NEP17', result) def test_nep17_decimals(self): path = self.get_contract_path('nep17.py') engine = TestEngine() result = self.run_smart_contract(engine, path, 'decimals') self.assertEqual(8, result) def test_nep17_total_supply(self): total_supply = 10_000_000 * 10 ** 8 path = self.get_contract_path('nep17.py') engine = TestEngine() result = self.run_smart_contract(engine, path, 'totalSupply') self.assertEqual(total_supply, result) def test_nep17_total_balance_of(self): total_supply = 10_000_000 * 10 ** 8 path = self.get_contract_path('nep17.py') engine = TestEngine() result = self.run_smart_contract(engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) self.assertEqual(total_supply, result) # should fail when the script length is not 20 with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'balanceOf', bytes(10)) with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'balanceOf', bytes(30)) def test_nep17_total_transfer(self): transferred_amount = 10 * 10 ** 8 # 10 tokens path = self.get_contract_path('nep17.py') engine = TestEngine() # should fail if the sender doesn't sign result = self.run_smart_contract(engine, path, 'transfer', self.OWNER_SCRIPT_HASH, self.OTHER_ACCOUNT_1, transferred_amount, None) self.assertEqual(False, result) # should fail if the sender doesn't have enough balance result = self.run_smart_contract(engine, path, 'transfer', self.OTHER_ACCOUNT_1, self.OWNER_SCRIPT_HASH, transferred_amount, None, signer_accounts=[self.OTHER_ACCOUNT_1]) self.assertEqual(False, result) # should fail when any of the scripts' length is not 20 with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'transfer', self.OWNER_SCRIPT_HASH, bytes(10), transferred_amount, "") with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'transfer', bytes(10), self.OTHER_ACCOUNT_1, transferred_amount, "") # should fail when the amount is less than 0 with self.assertRaises(TestExecutionException, msg=self.ASSERT_RESULTED_FALSE_MSG): self.run_smart_contract(engine, path, 'transfer', self.OTHER_ACCOUNT_1, self.OWNER_SCRIPT_HASH, -10, None) # fire the transfer event when transferring to yourself balance_before = self.run_smart_contract(engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) result = self.run_smart_contract(engine, path, 'transfer', self.OWNER_SCRIPT_HASH, self.OWNER_SCRIPT_HASH, transferred_amount, None, signer_accounts=[self.OWNER_SCRIPT_HASH]) self.assertEqual(True, result) transfer_events = engine.get_events('Transfer') self.assertEqual(2, len(transfer_events)) self.assertEqual(3, len(transfer_events[1].arguments)) sender, receiver, amount = transfer_events[1].arguments if isinstance(sender, str): sender = String(sender).to_bytes() if isinstance(receiver, str): receiver = String(receiver).to_bytes() self.assertEqual(self.OWNER_SCRIPT_HASH, sender) self.assertEqual(self.OWNER_SCRIPT_HASH, receiver) self.assertEqual(transferred_amount, amount) # transferring to yourself doesn't change the balance balance_after = self.run_smart_contract(engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) self.assertEqual(balance_before, balance_after) # does fire the transfer event balance_sender_before = self.run_smart_contract(engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) balance_receiver_before = self.run_smart_contract(engine, path, 'balanceOf', self.OTHER_ACCOUNT_1) result = self.run_smart_contract(engine, path, 'transfer', self.OWNER_SCRIPT_HASH, self.OTHER_ACCOUNT_1, transferred_amount, None, signer_accounts=[self.OWNER_SCRIPT_HASH]) self.assertEqual(True, result) transfer_events = engine.get_events('Transfer') self.assertEqual(3, len(transfer_events)) self.assertEqual(3, len(transfer_events[2].arguments)) sender, receiver, amount = transfer_events[2].arguments if isinstance(sender, str): sender = String(sender).to_bytes() if isinstance(receiver, str): receiver = String(receiver).to_bytes() self.assertEqual(self.OWNER_SCRIPT_HASH, sender) self.assertEqual(self.OTHER_ACCOUNT_1, receiver) self.assertEqual(transferred_amount, amount) # transferring to someone other than yourself does change the balance balance_sender_after = self.run_smart_contract(engine, path, 'balanceOf', self.OWNER_SCRIPT_HASH) balance_receiver_after = self.run_smart_contract(engine, path, 'balanceOf', self.OTHER_ACCOUNT_1) self.assertEqual(balance_sender_before - transferred_amount, balance_sender_after) self.assertEqual(balance_receiver_before + transferred_amount, balance_receiver_after) def test_nep17_on_nep17_payment(self): transferred_amount = 10 * 10 ** 8 # 10 tokens path = self.get_contract_path('nep17.py') engine = TestEngine() self.run_smart_contract(engine, path, 'symbol') nep17_address = engine.executed_script_hash.to_array() aux_path = self.get_contract_path('examples/auxiliary_contracts', 'auxiliary_contract.py') self.run_smart_contract(engine, aux_path, 'get_name') aux_address = engine.executed_script_hash.to_array() engine = TestEngine() engine.add_contract(path.replace('.py', '.nef')) engine.add_neo(aux_address, transferred_amount) engine.add_gas(aux_address, transferred_amount) # transferring NEO to the smart contract # saving the balance before the transfer to be able to compare after it neo_balance_sender_before = self.run_smart_contract(engine, constants.NEO_SCRIPT, 'balanceOf', aux_address) neo_balance_nep17_before = self.run_smart_contract(engine, constants.NEO_SCRIPT, 'balanceOf', nep17_address) nep17_balance_sender_before = self.run_smart_contract(engine, path, 'balanceOf', aux_address) result = self.run_smart_contract(engine, aux_path, 'calling_transfer', constants.NEO_SCRIPT, aux_address, nep17_address, transferred_amount, None, signer_accounts=[aux_address]) self.assertEqual(True, result) transfer_events = engine.get_events('Transfer') self.assertEqual(4, len(transfer_events)) neo_transfer_event = transfer_events[1] transfer_event = transfer_events[2] self.assertEqual(3, len(neo_transfer_event.arguments)) self.assertEqual(3, len(transfer_event.arguments)) # this is the event NEO emitted sender, receiver, amount = neo_transfer_event.arguments if isinstance(sender, str): sender = String(sender).to_bytes() if isinstance(receiver, str): receiver = String(receiver).to_bytes() self.assertEqual(aux_address, sender) self.assertEqual(nep17_address, receiver) self.assertEqual(transferred_amount, amount) # this is the event NEP17 emitted sender, receiver, amount = transfer_event.arguments if isinstance(sender, str): sender = String(sender).to_bytes() if isinstance(receiver, str): receiver = String(receiver).to_bytes() self.assertEqual(None, sender) self.assertEqual(aux_address, receiver) # transferred_amount is multiplied by 10, because this smart contract is minting the NEO received self.assertEqual(transferred_amount * 10, amount) # saving the balance after the transfer to compare it with the previous data neo_balance_sender_after = self.run_smart_contract(engine, constants.NEO_SCRIPT, 'balanceOf', aux_address) neo_balance_nep17_after = self.run_smart_contract(engine, constants.NEO_SCRIPT, 'balanceOf', nep17_address) nep17_balance_sender_after = self.run_smart_contract(engine, path, 'balanceOf', aux_address) self.assertEqual(neo_balance_sender_before - transferred_amount, neo_balance_sender_after) self.assertEqual(neo_balance_nep17_before + transferred_amount, neo_balance_nep17_after) # transferred_amount is multiplied by 10, because this smart contract is minting the NEO received self.assertEqual(nep17_balance_sender_before + transferred_amount * 10, nep17_balance_sender_after) # transferring GAS to the smart contract # saving the balance before the transfer to be able to compare after it gas_balance_sender_before = self.run_smart_contract(engine, constants.GAS_SCRIPT, 'balanceOf', aux_address) gas_balance_nep17_before = self.run_smart_contract(engine, constants.GAS_SCRIPT, 'balanceOf', nep17_address) nep17_balance_sender_before = self.run_smart_contract(engine, path, 'balanceOf', aux_address) result = self.run_smart_contract(engine, aux_path, 'calling_transfer', constants.GAS_SCRIPT, aux_address, nep17_address, transferred_amount, None, signer_accounts=[aux_address]) self.assertEqual(True, result) transfer_events = engine.get_events('Transfer') self.assertEqual(6, len(transfer_events)) gas_transfer_event = transfer_events[4] transfer_event = transfer_events[5] self.assertEqual(3, len(gas_transfer_event.arguments)) self.assertEqual(3, len(transfer_event.arguments)) # this is the event GAS emitted sender, receiver, amount = gas_transfer_event.arguments if isinstance(sender, str): sender = String(sender).to_bytes() if isinstance(receiver, str): receiver = String(receiver).to_bytes() self.assertEqual(aux_address, sender) self.assertEqual(nep17_address, receiver) self.assertEqual(transferred_amount, amount) # this is the event NEP17 emitted sender, receiver, amount = transfer_event.arguments if isinstance(sender, str): sender = String(sender).to_bytes() if isinstance(receiver, str): receiver = String(receiver).to_bytes() self.assertEqual(None, sender) self.assertEqual(aux_address, receiver) # transferred_amount is multiplied by 2, because this smart contract is minting the GAS received self.assertEqual(transferred_amount * 2, amount) # saving the balance after the transfer to compare it with the previous data gas_balance_sender_after = self.run_smart_contract(engine, constants.GAS_SCRIPT, 'balanceOf', aux_address) gas_balance_nep17_after = self.run_smart_contract(engine, constants.GAS_SCRIPT, 'balanceOf', nep17_address) nep17_balance_sender_after = self.run_smart_contract(engine, path, 'balanceOf', aux_address) self.assertEqual(gas_balance_sender_before - transferred_amount, gas_balance_sender_after) self.assertEqual(gas_balance_nep17_before + transferred_amount, gas_balance_nep17_after) # transferred_amount is multiplied by 2, because this smart contract is minting the GAS received self.assertEqual(nep17_balance_sender_before + transferred_amount * 2, nep17_balance_sender_after) # trying to call onNEP17Transfer() will result in an abort if the one calling it is not NEO or GAS contracts with self.assertRaises(TestExecutionException, msg=self.ABORTED_CONTRACT_MSG): self.run_smart_contract(engine, path, 'onNEP17Transfer', self.OWNER_SCRIPT_HASH, transferred_amount, None) def test_nep17_verify(self): path = self.get_contract_path('nep17.py') engine = TestEngine() # should fail without signature result = self.run_smart_contract(engine, path, 'verify') self.assertEqual(False, result) # should fail if not signed by the owner result = self.run_smart_contract(engine, path, 'verify', signer_accounts=[self.OTHER_ACCOUNT_1]) self.assertEqual(False, result) result = self.run_smart_contract(engine, path, 'verify', signer_accounts=[self.OWNER_SCRIPT_HASH]) self.assertEqual(True, result)