Repository: vyperlang/vyper

Issue:
Cannot convert from address to num256
* vyper Version: 0.0.3 (commit 4d33dc4140f7d0c339876afb6af7b417bd0ed8e0)
* pyethereum Version: 2.3.0
* OS: osx & linux
* Python Version (python --version):
Python 3.6.3
* Environment (output of `pip freeze`):
```asn1crypto==0.24.0
attrs==17.4.0
bumpversion==0.5.3
certifi==2018.1.18
cffi==1.11.4
chardet==3.0.4
coincurve==7.1.0
coverage==4.5.1
cytoolz==0.9.0
ethereum==2.3.0
ethereum-abi-utils==0.4.7
ethereum-serpent==2.0.7
ethereum-utils==0.6.2
future==0.16.0
idna==2.6
Jinja2==2.10
MarkupSafe==1.0
numpy==1.14.0
pbkdf2==1.3
pluggy==0.6.0
py==1.5.2
py-ecc==1.4.2
pycparser==2.18
pycryptodome==3.4.11
pyethash==0.1.27
pylru==1.0.9
pysha3==1.0.2
pytest==3.4.0
pytest-cov==2.5.1
pytest-runner==4.0
PyYAML==3.12
repoze.lru==0.7
requests==2.18.4
rlp==0.6.0
scrypt==0.8.6
six==1.11.0
toolz==0.9.0
urllib3==1.22
vyper==0.0.3
web3==3.13.4
```
### What's your issue about?

The new `convert(x, 'num256')` function doesn't accept an `x` of type address.
It's possible to work around this by doing `convert(convert(my_address, 'bytes32'), 'num256')`

This seems unnecessarily cumbersome. It would be nice if a direct conversion were possible.

### How can it be fixed?

I suspect that this line is the culprit:
https://github.com/ethereum/vyper/blob/4d33dc4140f7d0c339876afb6af7b417bd0ed8e0/vyper/types/convert.py#L37

#### Cute Animal Picture
![valentine](https://i.pinimg.com/736x/8c/87/f1/8c87f181412dd85b618ffa21da105ed3.jpg)



Discussion:
What use cases do you envision for this conversion?
My particular use case stores an address in an array of num256s. Other use cases I can think of involve performing any kind of arithmetic on addresses.

More importantly, the `convert(addr, 'num256')` syntax is unambiguous and the conversion is safe with no information being lost in the process. Therefore, I believe that we shouldn't forbid the programmer from performing it.
A single address in an array of `num256`? An address is 20 bytes whereas `num256` is 32, why do you need the array? If you're storing multiple addresses in an array, you can just do so with an array of addresses.

Why would you want to arithmatic on an address?

These are not use cases that were considered when designing the address type, and I'm still not seeing the utility. It's not a matter of "can we do it?" but "why?"
@fubuloubu 

In Solidity, I've used addresses converted to integers combined with blockhash to generate pseudo-random numbers that are deterministic based on user address. I wouldn't say it should be super high priority, but it's potentially useful and something I might want to use again. 
Hmm, that's actually interesting because you can't front-run it since msg.sender is not a controllable environment variable...

Definitely a corner case, but it would be interesting to see an example of that for my own purposes.

Resolving patch:
diff --git a/vyper/types/convert.py b/vyper/types/convert.py
--- a/vyper/types/convert.py
+++ b/vyper/types/convert.py
@@ -38,21 +38,24 @@ def to_int128(expr, args, kwargs, context):
         return byte_array_to_num(in_node, expr, 'int128')
 
 
-@signature(('num_literal', 'int128', 'bytes32'), 'str_literal')
+@signature(('num_literal', 'int128', 'bytes32', 'address'), 'str_literal')
 def to_uint256(expr, args, kwargs, context):
     in_node = args[0]
-    typ, len = get_type(in_node)
-    if isinstance(in_node, int):
+    input_type, len = get_type(in_node)
 
+    if isinstance(in_node, int):
         if not SizeLimits.in_bounds('uint256', in_node):
             raise InvalidLiteralException("Number out of range: {}".format(in_node))
-        _unit = in_node.typ.unit if typ == 'int128' else None
+        _unit = in_node.typ.unit if input_type == 'int128' else None
         return LLLnode.from_list(in_node, typ=BaseType('uint256', _unit), pos=getpos(expr))
-    elif isinstance(in_node, LLLnode) and typ in ('int128', 'num_literal'):
-        _unit = in_node.typ.unit if typ == 'int128' else None
+
+    elif isinstance(in_node, LLLnode) and input_type in ('int128', 'num_literal'):
+        _unit = in_node.typ.unit if input_type == 'int128' else None
         return LLLnode.from_list(['clampge', in_node, 0], typ=BaseType('uint256', _unit), pos=getpos(expr))
-    elif isinstance(in_node, LLLnode) and typ in ('bytes32'):
+
+    elif isinstance(in_node, LLLnode) and input_type in ('bytes32', 'address'):
         return LLLnode(value=in_node.value, args=in_node.args, typ=BaseType('uint256'), pos=getpos(expr))
+
     else:
         raise InvalidLiteralException("Invalid input for uint256: %r" % in_node, expr)
 


Test patch:
diff --git a/tests/parser/functions/test_convert.py b/tests/parser/functions/test_convert.py
--- a/tests/parser/functions/test_convert.py
+++ b/tests/parser/functions/test_convert.py
@@ -215,3 +215,29 @@ def test2() -> decimal(meter):
     c = get_contract(code)
     assert c.test() == Decimal('5001')
     assert c.test2() == Decimal('1234')
+
+
+def test_convert_address_to_uint256(w3, get_contract):
+    a = w3.eth.accounts[0]
+    code = """
+stor_a: address
+
+@public
+def conv1(a: address) -> uint256:
+    return convert(a, 'uint256')
+
+@public
+def conv2() -> uint256:
+    self.stor_a = 0x744d70FDBE2Ba4CF95131626614a1763DF805B9E
+    return convert(self.stor_a, 'uint256')
+
+@public
+def conv3() -> uint256:
+    return convert(0x744d70FDBE2Ba4CF95131626614a1763DF805B9E, 'uint256')
+    """
+
+    c = get_contract(code)
+
+    assert c.conv1(a) == int(a, 0)
+    assert c.conv2() == 663969929716095361663590611662499625636445838238
+    assert c.conv3() == 663969929716095361663590611662499625636445838238