diff --git a/tests/parser/functions/test_convert_to_bool.py b/tests/parser/functions/test_convert_to_bool.py index fe09aab1e5..4ad05015bf 100644 --- a/tests/parser/functions/test_convert_to_bool.py +++ b/tests/parser/functions/test_convert_to_bool.py @@ -193,3 +193,30 @@ def foo() -> bool: lambda: get_contract_with_gas_estimation(code), TypeMismatchException ) + + +def test_convert_from_address(w3, get_contract_with_gas_estimation): + code = """ +@public +def test_address_to_bool(val: address) -> bool: + temp: bool = convert(val, bool) + return temp + +@public +def test_literal_zero_address() -> bool: + return convert(ZERO_ADDRESS, bool) + +@public +def test_sender() -> bool: + return convert(msg.sender, bool) + """ + + a = w3.eth.accounts[0] + c = get_contract_with_gas_estimation(code) + + assert c.test_address_to_bool((b'\x00' * 19) + (b'\x01')) is True + assert c.test_address_to_bool(a) is True + assert c.test_address_to_bool(b'\x00' * 20) is False + + assert c.test_literal_zero_address() is False + assert c.test_sender() is True diff --git a/tests/parser/functions/test_convert_to_decimal.py b/tests/parser/functions/test_convert_to_decimal.py index d1b690f5d1..1864b9d135 100644 --- a/tests/parser/functions/test_convert_to_decimal.py +++ b/tests/parser/functions/test_convert_to_decimal.py @@ -169,3 +169,43 @@ def foobar() -> decimal: lambda: get_contract_with_gas_estimation(code), TypeMismatchException ) + + +def test_convert_from_address(get_contract_with_gas_estimation): + code = """ +stor: address + +@public +def conv(param: address) -> decimal: + return convert(param, decimal) + +@public +def conv_zero_literal() -> decimal: + return convert(ZERO_ADDRESS, decimal) + +@public +def conv_zero_stor() -> decimal: + self.stor = ZERO_ADDRESS + return convert(self.stor, decimal) + +@public +def conv_neg1_literal() -> decimal: + return convert(0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF, decimal) + +@public +def conv_neg1_stor() -> decimal: + self.stor = 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF + return convert(self.stor, decimal) + """ + + c = get_contract_with_gas_estimation(code) + assert c.conv(b"\x00" * 20) == 0.0 + assert c.conv_zero_literal() == 0.0 + assert c.conv_zero_stor() == 0.0 + + assert c.conv(b"\xff" * 20) == -1.0 + assert c.conv_neg1_literal() == -1.0 + assert c.conv_neg1_stor() == -1.0 + + assert c.conv((b"\x00" * 19) + b"\x01") == 1.0 + assert c.conv((b"\x00" * 18) + b"\x01\x00") == 256.0 diff --git a/tests/parser/functions/test_convert_to_int128.py b/tests/parser/functions/test_convert_to_int128.py index 67dafb8ed6..e83583d204 100644 --- a/tests/parser/functions/test_convert_to_int128.py +++ b/tests/parser/functions/test_convert_to_int128.py @@ -2,6 +2,9 @@ InvalidLiteralException, TypeMismatchException, ) +from vyper.utils import ( + SizeLimits, +) def test_convert_to_int128_units(get_contract, assert_tx_failed): @@ -204,16 +207,6 @@ def test1(): assert_tx_failed(lambda: c.test1()) -def test_convert_from_address(assert_compile_failed, get_contract_with_gas_estimation): - code = """ -@public -def test2(): - x: int128 = convert(msg.sender, int128) - """ - - assert_compile_failed(lambda: get_contract_with_gas_estimation(code), Exception) - - def test_convert_out_of_range_literal(assert_compile_failed, get_contract_with_gas_estimation): code = """ @public @@ -292,3 +285,107 @@ def foo() -> int128: lambda: get_contract_with_gas_estimation(code), InvalidLiteralException ) + + +def test_convert_from_address(w3, get_contract): + code = """ +stor: address + +@public +def testCompiles(): + x: int128 = convert(msg.sender, int128) + +@public +def conv_neg1_stor() -> int128: + self.stor = 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF + return convert(self.stor, int128) + +@public +def conv_neg1_literal() -> int128: + return convert(0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF, int128) + +@public +def conv_neg1_stor_alt() -> int128: + self.stor = 0x00000000fFFFffffffFfFfFFffFfFffFFFfFffff + return convert(self.stor, int128) + +@public +def conv_neg1_literal_alt() -> int128: + return convert(0x00000000fFFFffffffFfFfFFffFfFffFFFfFffff, int128) + +@public +def conv_min_stor() -> int128: + self.stor = 0x0000000080000000000000000000000000000000 + return convert(self.stor, int128) + +@public +def conv_min_literal() -> int128: + return convert(0x0000000080000000000000000000000000000000, int128) + +@public +def conv_min_stor_alt() -> int128: + self.stor = 0x1234567880000000000000000000000000000000 + return convert(self.stor, int128) + +@public +def conv_min_literal_alt() -> int128: + return convert(0x1234567880000000000000000000000000000000, int128) + +@public +def conv_zero_stor() -> int128: + self.stor = ZERO_ADDRESS + return convert(self.stor, int128) + +@public +def conv_zero_literal() -> int128: + return convert(ZERO_ADDRESS, int128) + +@public +def conv_zero_stor_alt() -> int128: + self.stor = 0xffFFfFFf00000000000000000000000000000000 + return convert(self.stor, int128) + +@public +def conv_zero_literal_alt() -> int128: + return convert(0xffFFfFFf00000000000000000000000000000000, int128) + +@public +def conv_max_stor() -> int128: + self.stor = 0xFffffFff7FFFFFFfFffFffFfFFffFffFFfFfffFF + return convert(self.stor, int128) + +@public +def conv_max_literal() -> int128: + return convert(0xFffffFff7FFFFFFfFffFffFfFFffFffFFfFfffFF, int128) + +@public +def conv_max_stor_alt() -> int128: + self.stor = 0x000000007FfFFffffFFFFfffffffFffFfFffffFF + return convert(self.stor, int128) + +@public +def conv_max_literal_alt() -> int128: + return convert(0x000000007FfFFffffFFFFfffffffFffFfFffffFF, int128) + """ + + c = get_contract(code) + + assert c.conv_neg1_stor() == -1 + assert c.conv_neg1_literal() == -1 + assert c.conv_neg1_stor_alt() == -1 + assert c.conv_neg1_literal_alt() == -1 + + assert c.conv_min_stor() == SizeLimits.MINNUM + assert c.conv_min_literal() == SizeLimits.MINNUM + assert c.conv_min_stor_alt() == SizeLimits.MINNUM + assert c.conv_min_literal_alt() == SizeLimits.MINNUM + + assert c.conv_zero_stor() == 0 + assert c.conv_zero_literal() == 0 + assert c.conv_zero_stor_alt() == 0 + assert c.conv_zero_literal_alt() == 0 + + assert c.conv_max_stor() == SizeLimits.MAXNUM + assert c.conv_max_literal() == SizeLimits.MAXNUM + assert c.conv_max_stor_alt() == SizeLimits.MAXNUM + assert c.conv_max_literal_alt() == SizeLimits.MAXNUM diff --git a/tests/parser/functions/test_convert_to_uint256.py b/tests/parser/functions/test_convert_to_uint256.py index e2541f9f2d..f5c4e23533 100644 --- a/tests/parser/functions/test_convert_to_uint256.py +++ b/tests/parser/functions/test_convert_to_uint256.py @@ -112,6 +112,24 @@ def conv2() -> uint256: @public def conv3() -> uint256: return convert(0x744d70FDBE2Ba4CF95131626614a1763DF805B9E, uint256) + +@public +def conv_max_stor() -> uint256: + self.stor_a = 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF + return convert(self.stor_a, uint256) + +@public +def conv_max_literal() -> uint256: + return convert(0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF, uint256) + +@public +def conv_min_stor() -> uint256: + self.stor_a = ZERO_ADDRESS + return convert(self.stor_a, uint256) + +@public +def conv_min_literal() -> uint256: + return convert(ZERO_ADDRESS, uint256) """ c = get_contract(code) @@ -119,6 +137,10 @@ def conv3() -> uint256: assert c.conv1(a) == int(a, 0) assert c.conv2() == 663969929716095361663590611662499625636445838238 assert c.conv3() == 663969929716095361663590611662499625636445838238 + assert c.conv_max_stor() == (2**160) - 1 + assert c.conv_max_literal() == (2**160) - 1 + assert c.conv_min_stor() == 0 + assert c.conv_min_literal() == 0 def test_convert_from_bool(get_contract_with_gas_estimation): diff --git a/vyper/types/convert.py b/vyper/types/convert.py index fc7e5c591b..9b48968aa2 100644 --- a/vyper/types/convert.py +++ b/vyper/types/convert.py @@ -28,7 +28,7 @@ ) -@signature(('decimal', 'int128', 'uint256', 'bytes32', 'bytes'), '*') +@signature(('decimal', 'int128', 'uint256', 'address', 'bytes32', 'bytes'), '*') def to_bool(expr, args, kwargs, context): in_arg = args[0] input_type, _ = get_type(in_arg) @@ -57,7 +57,8 @@ def to_bool(expr, args, kwargs, context): ) -@signature(('num_literal', 'bool', 'decimal', 'uint256', 'bytes32', 'bytes', 'string'), '*') +@signature(('num_literal', 'bool', 'decimal', 'uint256', 'address', + 'bytes32', 'bytes', 'string'), '*') def to_int128(expr, args, kwargs, context): in_arg = args[0] input_type, _ = get_type(in_arg) @@ -105,6 +106,21 @@ def to_int128(expr, args, kwargs, context): pos=getpos(expr) ) + elif input_type == 'address': + return LLLnode.from_list( + [ + 'signextend', + 15, + [ + 'and', + in_arg, + (SizeLimits.ADDRSIZE - 1) + ], + ], + typ=BaseType('int128', _unit), + pos=getpos(expr) + ) + elif input_type in ('string', 'bytes'): if in_arg.typ.maxlen > 32: raise TypeMismatchException( @@ -221,7 +237,7 @@ def to_uint256(expr, args, kwargs, context): raise InvalidLiteralException("Invalid input for uint256: %r" % in_arg, expr) -@signature(('bool', 'int128', 'uint256', 'bytes32', 'bytes'), '*') +@signature(('bool', 'int128', 'uint256', 'bytes32', 'bytes', 'address'), '*') def to_decimal(expr, args, kwargs, context): in_arg = args[0] input_type, _ = get_type(in_arg) @@ -267,6 +283,25 @@ def to_decimal(expr, args, kwargs, context): pos=getpos(expr) ) + elif input_type == 'address': + return LLLnode.from_list( + [ + 'mul', + [ + 'signextend', + 15, + [ + 'and', + in_arg, + (SizeLimits.ADDRSIZE - 1) + ], + ], + DECIMAL_DIVISOR + ], + typ=BaseType('decimal', _unit, _positional), + pos=getpos(expr) + ) + elif input_type == 'bytes32': if in_arg.typ.is_literal: if not SizeLimits.in_bounds('int128', (in_arg.value * DECIMAL_DIVISOR)):