def test_external_contract_calls_with_public_globals(): contract_1 = """ lucky: public(num) @public def __init__(_lucky: num): self.lucky = _lucky """ lucky_number = 7 c = get_contract(contract_1, args=[lucky_number]) contract_2 = """ class Foo(): def get_lucky() -> num: pass @public def bar(arg1: address) -> num: return Foo(arg1).get_lucky() """ c2 = get_contract(contract_2) assert c2.bar(c.address) == lucky_number print( 'Successfully executed an external contract call with public globals')
def test_address_can_returned_from_contract_type(t): contract_1 = """ @public def bar() -> num: return 1 """ contract_2 = """ class Bar(): def bar() -> num: pass bar_contract: public(Bar) @public def foo(contract_address: contract(Bar)) -> num: self.bar_contract = contract_address @public def get_bar() -> num: return self.bar_contract.bar() """ c1 = get_contract(contract_1) c2 = get_contract(contract_2) c2.foo(c1.address) assert u.remove_0x_head(c2.get_bar_contract()) == c1.address.hex() assert c2.get_bar() == 1
def test_invalid_external_contract_call_to_the_same_contract(assert_tx_failed): contract_1 = """ @public def bar() -> num: return 1 """ contract_2 = """ class Bar(): def bar() -> num: pass @public def bar() -> num: return 1 @public def _stmt(x: address): Bar(x).bar() @public def _expr(x: address) -> num: return Bar(x).bar() """ c1 = get_contract(contract_1) c2 = get_contract(contract_2) c2._stmt(c1.address) c2._expr(c1.address) assert_tx_failed(lambda: c2._stmt(c2.address)) assert_tx_failed(lambda: c2._expr(c2.address))
def test_external_contract_calls_with_multiple_contracts(): contract_1 = """ lucky: public(num) def __init__(_lucky: num): self.lucky = _lucky """ lucky_number = 7 c = get_contract(contract_1, args=[lucky_number]) contract_2 = """ class Foo(): def get_lucky() -> num: pass magic_number: public(num) def __init__(arg1: address): self.magic_number = Foo(arg1).get_lucky() """ c2 = get_contract(contract_2, args=[c.address]) contract_3 = """ class Bar(): def get_magic_number() -> num: pass best_number: public(num) def __init__(arg1: address): self.best_number = Bar(arg1).get_magic_number() """ c3 = get_contract(contract_3, args=[c2.address]) assert c3.get_best_number() == lucky_number print('Successfully executed a multiple external contract calls')
def test_complicated_external_contract_calls(): contract_1 = """ lucky: public(num) def __init__(_lucky: num): self.lucky = _lucky def foo() -> num: return self.lucky def array() -> bytes <= 3: return 'dog' """ lucky_number = 7 c = get_contract(contract_1, args=[lucky_number]) contract_2 = """ class Foo(): def foo() -> num: pass def array() -> bytes <= 3: pass def bar(arg1: address) -> num: return Foo(arg1).foo() """ c2 = get_contract(contract_2) assert c2.bar(c.address) == lucky_number print('Successfully executed a complicated external contract call')
def test_external_contract_can_be_changed_based_on_address(): contract_1 = """ lucky: public(num) def set_lucky(_lucky: num): self.lucky = _lucky """ lucky_number_1 = 7 c = get_contract(contract_1) contract_2 = """ lucky: public(num) def set_lucky(_lucky: num): self.lucky = _lucky """ lucky_number_2 = 3 c2 = get_contract(contract_1) contract_3 = """ class Foo(): def set_lucky(_lucky: num): pass def set_lucky(arg1: address, arg2: num): Foo(arg1).set_lucky(arg2) """ c3 = get_contract(contract_3) c3.set_lucky(c.address, lucky_number_1) c3.set_lucky(c2.address, lucky_number_2) assert c.get_lucky() == lucky_number_1 assert c2.get_lucky() == lucky_number_2 print('Successfully executed multiple external contract calls to different contracts based on address')
def test_external_contract_call_state_change(): contract_1 = """ lucky: public(num) @public def set_lucky(_lucky: num): self.lucky = _lucky """ lucky_number = 7 c = get_contract(contract_1) contract_2 = """ class Foo(): def set_lucky(_lucky: num): pass @public def set_lucky(arg1: address, arg2: num): Foo(arg1).set_lucky(arg2) """ c2 = get_contract(contract_2) assert c.get_lucky() == 0 c2.set_lucky(c.address, lucky_number) assert c.get_lucky() == lucky_number print('Successfully executed an external contract call state change')
def test_event_logging_cannot_have_more_than_three_topics(): loggy_code = """ MyLog: __log__({arg1: indexed(bytes <= 3), arg2: indexed(bytes <= 4), arg3: indexed(address), arg4: indexed(num)}) def foo(): log.MyLog('bar', 'home', self) """ with pytest.raises(VariableDeclarationException): get_contract(loggy_code)
def test_mismatched_byte_length(): code = """ mapped_bytes: num[bytes <= 34] @public def set(k: bytes <= 35, v: num): self.mapped_bytes[k] = v """ with pytest.raises(TypeMismatchException): get_contract(code)
def test_altering_list_within_for_loop(): code = """ def data() -> num: s = [1, 2, 3, 4, 5, 6] count = 0 for i in s: s[count] = 1 # this should not be allowed. if i >= 3: return i count += 1 return -1 """ with pytest.raises(StructureException): get_contract(code)
def test_logging_the_same_event_multiple_times_with_topics(): loggy_code = """ MyLog: __log__({arg1: indexed(num), arg2: indexed(address)}) def foo(): log.MyLog(1, self) log.MyLog(1, self) def bar(): log.MyLog(1, self) log.MyLog(1, self) """ c = get_contract(loggy_code) c.foo() c.bar() logs = s.head_state.receipts[-1].logs[-1] event_id = u.bytes_to_int(u.sha3(bytes('MyLog(int128,address)', 'utf-8'))) # Event id is always the first topic assert logs.topics[0] == event_id # Event id is calculated correctly assert c.translator.event_data[event_id] # Event abi is created correctly assert c.translator.event_data[event_id] == {'types': ['int128','address'], 'name': 'MyLog', 'names': ['arg1','arg2'], 'indexed': [True,True], 'anonymous': False} # Event is decoded correctly assert c.translator.decode_event(logs.topics, logs.data) == {'_event_type': b'MyLog', 'arg1': 1, 'arg2': '0x' + c.address.hex()}
def test_basic_for_list_storage_address(): code = """ addresses: address[3] def set(i: num, val: address): self.addresses[i] = val def ret(i: num) -> address: return self.addresses[i] def iterate_return_second() -> address: count = 0 for i in self.addresses: count += 1 if count == 2: return i """ c = get_contract(code) c.set(0, '0x82A978B3f5962A5b0957d9ee9eEf472EE55B42F1') c.set(1, '0x7d577a597B2742b498Cb5Cf0C26cDCD726d39E6e') c.set(2, '0xDCEceAF3fc5C0a63d195d69b1A90011B7B19650D') assert c.ret(1) == c.iterate_return_second( ) == "0x7d577a597b2742b498cb5cf0c26cdcd726d39e6e"
def test_selfcall_code_4(): selfcall_code_4 = """ def summy(x: num, y: num) -> num: return x + y def catty(x: bytes <= 5, y: bytes <= 5) -> bytes <= 10: return concat(x, y) def slicey1(x: bytes <= 10, y: num) -> bytes <= 10: return slice(x, start=0, len=y) def slicey2(y: num, x: bytes <= 10) -> bytes <= 10: return slice(x, start=0, len=y) def returnten() -> num: return self.summy(3, 7) def return_mongoose() -> bytes <= 10: return self.catty("mon", "goose") def return_goose() -> bytes <= 10: return self.slicey1("goosedog", 5) def return_goose2() -> bytes <= 10: return self.slicey2(5, "goosedog") """ c = get_contract(selfcall_code_4) assert c.returnten() == 10 assert c.return_mongoose() == b"mongoose" assert c.return_goose() == b"goose" assert c.return_goose2() == b"goose" print("Passed multi-argument self-call test")
def test_event_logging_with_multiple_logs_topics_and_data(): loggy_code = """ MyLog: __log__({arg1: indexed(num), arg2: bytes <= 3}) YourLog: __log__({arg1: indexed(address), arg2: bytes <= 5}) def foo(): log.MyLog(1, 'bar') log.YourLog(self, 'house') """ c = get_contract(loggy_code) c.foo() logs1 = s.head_state.receipts[-1].logs[-2] logs2 = s.head_state.receipts[-1].logs[-1] event_id1 = u.bytes_to_int(u.sha3(bytes('MyLog(int128,bytes3)', 'utf-8'))) event_id2 = u.bytes_to_int(u.sha3(bytes('YourLog(address,bytes5)', 'utf-8'))) # Event id is always the first topic assert logs1.topics[0] == event_id1 assert logs2.topics[0] == event_id2 # Event ids are calculated correctly assert c.translator.event_data[event_id1] assert c.translator.event_data[event_id2] # Event abi is created correctly assert c.translator.event_data[event_id1] == {'types': ['int128','bytes3'], 'name': 'MyLog', 'names': ['arg1','arg2'], 'indexed': [True, False], 'anonymous': False} assert c.translator.event_data[event_id2] == {'types': ['address','bytes5'], 'name': 'YourLog', 'names': ['arg1','arg2'], 'indexed': [True, False], 'anonymous': False} # Event is decoded correctly assert c.translator.decode_event(logs1.topics, logs1.data) == {'arg1': 1, 'arg2': b'bar', '_event_type': b'MyLog'} assert c.translator.decode_event(logs2.topics, logs2.data) == {'arg1': '0x' + c.address.hex(), 'arg2': b'house', '_event_type': b'YourLog'}
def erc20_caller(erc20): erc20_caller_code = """ token_address: address(ERC20) @public def __init__(token_addr: address): self.token_address = token_addr @public def symbol() -> bytes32: return self.token_address.symbol() @public def balanceOf(_owner: address) -> num256: return self.token_address.balanceOf(_owner) @public def totalSupply() -> num256: return self.token_address.totalSupply() @public def transfer(_to: address, _value: num256) -> bool: return self.token_address.transfer(_to, _value) @public def transferFrom(_from: address, _to: address, _value: num(num256)) -> bool: return self.token_address.transferFrom(_from, _to, _value) @public def allowance(_owner: address, _spender: address) -> num256: return self.token_address.allowance(_owner, _spender) """ return get_contract(erc20_caller_code, args=[erc20.address])
def test_logging_with_input_bytes(bytes_helper): loggy_code = """ MyLog: __log__({arg1: indexed(bytes <= 4), arg2: indexed(bytes <= 29), arg3: bytes<=31}) def foo(arg1: bytes <= 29, arg2: bytes <= 31): log.MyLog('bar', arg1, arg2) """ c = get_contract(loggy_code) c.foo('bar', 'foo') logs = s.head_state.receipts[-1].logs[-1] event_id = u.bytes_to_int( u.sha3(bytes('MyLog(bytes4,bytes29,bytes31)', 'utf-8'))) # # Event id is always the first topic assert logs.topics[0] == event_id # # Event id is calculated correctly assert c.translator.event_data[event_id] # # Event abi is created correctly assert c.translator.event_data[event_id] == { 'types': ['bytes4', 'bytes29', 'bytes31'], 'name': 'MyLog', 'names': ['arg1', 'arg2', 'arg3'], 'indexed': [True, True, False], 'anonymous': False } # Event is decoded correctly assert c.translator.decode_event(logs.topics, logs.data) == { 'arg1': b'bar\x00', 'arg2': bytes_helper('bar', 29), 'arg3': bytes_helper('foo', 31), '_event_type': b'MyLog' }
def test_invalid_contract_reference_call(assert_tx_failed): contract = """ def bar(arg1: address, arg2: num) -> num: return Foo(arg1).foo(arg2) """ t.s = t.Chain() assert_tx_failed(t, lambda: get_contract(contract), exception = VariableDeclarationException)
def test_string_literal_code(): string_literal_code = """ def foo() -> bytes <= 5: return "horse" def bar() -> bytes <= 10: return concat("b", "a", "d", "m", "i", "", "nton") def baz() -> bytes <= 40: return concat("0123456789012345678901234567890", "12") def baz2() -> bytes <= 40: return concat("01234567890123456789012345678901", "12") def baz3() -> bytes <= 40: return concat("0123456789012345678901234567890", "1") def baz4() -> bytes <= 100: return concat("01234567890123456789012345678901234567890123456789", "01234567890123456789012345678901234567890123456789") """ c = get_contract(string_literal_code) assert c.foo() == b"horse" assert c.bar() == b"badminton" assert c.baz() == b"012345678901234567890123456789012" assert c.baz2() == b"0123456789012345678901234567890112" assert c.baz3() == b"01234567890123456789012345678901" assert c.baz4() == b"0123456789" * 10 print("Passed string literal test")
def test_loggy_code(): loggy_code = """ s: bytes <= 100 def foo(): raw_log([], "moo") def goo(): raw_log([0x1234567812345678123456781234567812345678123456781234567812345678], "moo2") def hoo(): self.s = "moo3" raw_log([], self.s) def ioo(inp: bytes <= 100): raw_log([], inp) """ c = get_contract(loggy_code) c.foo() assert s.head_state.receipts[-1].logs[0].data == b'moo' c.goo() assert s.head_state.receipts[-1].logs[0].data == b'moo2' assert s.head_state.receipts[-1].logs[0].topics == [0x1234567812345678123456781234567812345678123456781234567812345678] c.hoo() assert s.head_state.receipts[-1].logs[0].data == b'moo3' c.ioo(b"moo4") assert s.head_state.receipts[-1].logs[0].data == b'moo4' print("Passed raw log tests")
def test_bytes_to_num_code(): bytes_to_num_code = """ def foo(x: bytes <= 32) -> num: return bytes_to_num(x) """ c = get_contract(bytes_to_num_code) assert c.foo(b"") == 0 try: c.foo(b"\x00") success = True except: success = False assert not success assert c.foo(b"\x01") == 1 try: c.foo(b"\x00\x01") success = True except: success = False assert not success assert c.foo(b"\x01\x00") == 256 assert c.foo(b"\x01\x00\x00\x00\x01") == 4294967297 assert c.foo(b"\xff" * 32) == -1 try: c.foo(b"\x80" + b"\xff" * 31) success = True except: success = False try: c.foo(b"\x01" * 33) success = True except: success = False print('Passed bytes_to_num tests')
def test_logging_fails_after_a_global_declaration(assert_tx_failed): loggy_code = """ age: num MyLog: __log__({arg1: bytes <= 3}) """ t.s = s assert_tx_failed(t, lambda: get_contract(loggy_code), StructureException)
def test_basic_for_list_storage_decimal(): code = """ readings: decimal[3] def set(i: num, val: decimal): self.readings[i] = val def ret(i: num) -> decimal: return self.readings[i] def i_return(break_count: num) -> decimal: count = 0 for i in self.readings: if count == break_count: return i count += 1 """ c = get_contract(code) c.set(0, 0.0001) c.set(1, 1.1) c.set(2, 2.2) assert c.ret(2) == c.i_return(2) == 2.2 assert c.ret(1) == c.i_return(1) == 1.1 assert c.ret(0) == c.i_return(0) == 0.0001
def test_logging_fails_with_when_log_is_undeclared(assert_tx_failed): loggy_code = """ def foo(): log.MyLog() """ t.s = s assert_tx_failed(t, lambda: get_contract(loggy_code), VariableDeclarationException)
def test_num256_mod(assert_tx_failed): num256_code = """ def _num256_mod(x: num256, y: num256) -> num256: return num256_mod(x, y) def _num256_addmod(x: num256, y: num256, z: num256) -> num256: return num256_addmod(x, y, z) def _num256_mulmod(x: num256, y: num256, z: num256) -> num256: return num256_mulmod(x, y, z) """ c = get_contract(num256_code) t.s = s assert c._num256_mod(3, 2) == 1 assert c._num256_mod(34, 32) == 2 assert c._num256_addmod(1, 2, 2) == 1 assert c._num256_addmod(32, 2, 32) == 2 assert c._num256_addmod((2**256) - 1, 0, 2) == 1 assert_tx_failed(t, lambda: c._num256_addmod((2**256) - 1, 1, 1)) assert c._num256_mulmod(3, 1, 2) == 1 assert c._num256_mulmod(200, 3, 601) == 600 assert c._num256_mulmod(2**255, 1, 3) == 2 assert_tx_failed(t, lambda: c._num256_mulmod(2**255, 2, 1))
def test_num256_to_num_casting(assert_tx_failed): code = """ def _num256_to_num(x: num(num256)) -> num: return x def _num256_to_num_call(x: num256) -> num: return self._num256_to_num(x) def built_in_conversion(x: num256) -> num: return as_num128(x) """ c = get_contract(code) # Ensure uint256 function signature. assert c.translator.function_data['_num256_to_num']['encode_types'] == [ 'uint256' ] assert c._num256_to_num(1) == 1 assert c._num256_to_num((2**127) - 1) == 2**127 - 1 t.s = s assert_tx_failed(t, lambda: c._num256_to_num((2**128)) == 0) assert c._num256_to_num_call(1) == 1 # Check that casting matches manual conversion assert c._num256_to_num_call(2**127 - 1) == c.built_in_conversion(2**127 - 1) # Pass in negative int. assert_tx_failed(t, lambda: c._num256_to_num(-1) != -1, ValueOutOfBounds) # Make sure it can't be coherced into a negative number. assert_tx_failed(t, lambda: c._num256_to_num_call(2**127))
def test_composite_setter_test(): composite_setter_test = """ mom: {a: {c: num}[3], b:num} qoq: {c: num} def foo() -> num: self.mom = {a: [{c: 1}, {c: 2}, {c: 3}], b: 4} non = {c: 5} self.mom.a[0] = non non = {c: 6} self.mom.a[2] = non return self.mom.a[0].c + self.mom.a[1].c * 10 + self.mom.a[2].c * 100 + self.mom.b * 1000 def fop() -> num: popp = {a: [{c: 1}, {c: 2}, {c: 3}], b: 4} self.qoq = {c: 5} popp.a[0] = self.qoq self.qoq = {c: 6} popp.a[2] = self.qoq return popp.a[0].c + popp.a[1].c * 10 + popp.a[2].c * 100 + popp.b * 1000 def foq() -> num: popp = {a: [{c: 1}, {c: 2}, {c: 3}], b: 4} popp.a[0] = None popp.a[2] = None return popp.a[0].c + popp.a[1].c * 10 + popp.a[2].c * 100 + popp.b * 1000 """ c = get_contract(composite_setter_test) assert c.foo() == 4625 assert c.fop() == 4625 assert c.foq() == 4020 print('Passed composite struct test')
def test_logging_fails_with_over_three_topics(assert_tx_failed): loggy_code = """ MyLog: __log__({arg1: indexed(num), arg2: indexed(num), arg3: indexed(num), arg4: indexed(num)}) def __init__(): log.MyLog(1, 2, 3, 4) """ t.s = s assert_tx_failed(t, lambda: get_contract(loggy_code), VariableDeclarationException)
def test_list_output_tester_code(): list_output_tester_code = """ z: num[2] def foo() -> num[2]: return [3, 5] def goo() -> num[2]: x = [3, 5] return x def hoo() -> num[2]: self.z = [3, 5] return self.z def joo() -> num[2]: self.z = [3, 5] x = self.z return x def koo() -> num[2][2]: return [[1,2],[3,4]] def loo() -> num[2][2]: x = [[1,2],[3,4]] return x def moo() -> num[2][2]: x = [1,2] return [x,[3,4]] def noo(inp: num[2]) -> num[2]: return inp def poo(inp: num[2][2]) -> num[2][2]: return inp def qoo(inp: num[2]) -> num[2][2]: return [inp,[3,4]] def roo(inp: num[2]) -> decimal[2][2]: return [inp,[3,4]] """ c = get_contract(list_output_tester_code) assert c.foo() == [3, 5] assert c.goo() == [3, 5] assert c.hoo() == [3, 5] assert c.joo() == [3, 5] assert c.koo() == [[1, 2], [3, 4]] assert c.loo() == [[1, 2], [3, 4]] assert c.moo() == [[1, 2], [3, 4]] assert c.noo([3, 5]) == [3, 5] assert c.poo([[1, 2], [3, 4]]) == [[1, 2], [3, 4]] assert c.qoo([1, 2]) == [[1, 2], [3, 4]] assert c.roo([1, 2]) == [[1.0, 2.0], [3.0, 4.0]] print("Passed list output tests")
def test_external_contract_calls_with_bytes(): contract_1 = """ def array() -> bytes <= 3: return 'dog' """ c = get_contract(contract_1) contract_2 = """ class Foo(): def array() -> bytes <= 3: pass def get_array(arg1: address) -> bytes <= 3: return Foo(arg1).array() """ c2 = get_contract(contract_2) assert c2.get_array(c.address) == b'dog'
def test_logging_fails_after_a_function_declaration(assert_tx_failed): loggy_code = """ def foo(): pass MyLog: __log__({arg1: bytes <= 3}) """ t.s = s assert_tx_failed(t, lambda: get_contract(loggy_code), StructureException)