Repository: vyperlang/vyper

Issue:
VIP: Add constants for max in min values
## Preamble

    VIP: #843
    Title: Constants for max in min values
    Author: Jacques Wagener
    Type: Standard Track
    Status: Draft
    Created: <date created on, in ISO 8601 (yyyy-mm-dd) format>
    Requires (*optional): <VIP number(s)>
    Replaces (*optional): <VIP number(s)>


## Simple Summary
Add 6 commonly used constants.

## Abstract
Adding some commonly used constants will improve the experience of porting over existing solidity contracts.

## Motivation
In most cases one should not actually have to use MIN/MAX constants when programming vyper. But there seem to be legacy cases were it's necessary (when MAX values are used for flags).

## Specification
Because we store the min max values for clamps in any case. Just mload the necessary values as appropriate.

```
ZERO_ADDRESS = 0x0000000000000000000000000000000000000000
MAX_INT128 = 2**127 - 1
MIN_INT128 = -2**127
MAX_DECIMAL = (2**127 - 1) * DECIMAL_DIVISOR
MIN_DECIMAL = (-2**127) * DECIMAL_DIVISOR
MAX_UINT256 = 2**256 - 1
```

## Backwards Compatibility
Forward compatible, as no old annotations will be altered.

## Copyright
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/)


Discussion:

Resolving patch:
diff --git a/vyper/parser/expr.py b/vyper/parser/expr.py
--- a/vyper/parser/expr.py
+++ b/vyper/parser/expr.py
@@ -154,11 +154,22 @@ def constants(self):
 
     # Variable names
     def variables(self):
+        constants = {
+            'ZERO_ADDRESS': LLLnode.from_list([0], typ=BaseType('address', None, is_literal=True), pos=getpos(self.expr)),
+            'MAX_INT128': LLLnode.from_list(['mload', MemoryPositions.MAXNUM], typ=BaseType('int128', None, is_literal=True), pos=getpos(self.expr)),
+            'MIN_INT128': LLLnode.from_list(['mload', MemoryPositions.MINNUM], typ=BaseType('int128', None, is_literal=True), pos=getpos(self.expr)),
+            'MAX_DECIMAL': LLLnode.from_list(['mload', MemoryPositions.MAXDECIMAL], typ=BaseType('decimal', None, is_literal=True), pos=getpos(self.expr)),
+            'MIN_DECIMAL': LLLnode.from_list(['mload', MemoryPositions.MINDECIMAL], typ=BaseType('decimal', None, is_literal=True), pos=getpos(self.expr)),
+            'MAX_UINT256': LLLnode.from_list([2**256 - 1], typ=BaseType('uint256', None, is_literal=True), pos=getpos(self.expr)),
+        }
+
         if self.expr.id == 'self':
             return LLLnode.from_list(['address'], typ='address', pos=getpos(self.expr))
-        if self.expr.id in self.context.vars:
+        elif self.expr.id in self.context.vars:
             var = self.context.vars[self.expr.id]
             return LLLnode.from_list(var.pos, typ=var.typ, location='memory', pos=getpos(self.expr), annotation=self.expr.id, mutable=var.mutable)
+        elif self.expr.id in constants:
+            return constants[self.expr.id]
         else:
             raise VariableDeclarationException("Undeclared variable: " + self.expr.id, self.expr)
 


Test patch:
diff --git a/tests/parser/types/numbers/test_constants.py b/tests/parser/types/numbers/test_constants.py
new file mode 100644
--- /dev/null
+++ b/tests/parser/types/numbers/test_constants.py
@@ -0,0 +1,46 @@
+from decimal import Decimal
+
+
+def test_builtin_constants(get_contract_with_gas_estimation):
+    code = """
+@public
+def test_zaddress(a: address) -> bool:
+    return a == ZERO_ADDRESS
+
+
+@public
+def test_int128(a: int128) -> (bool, bool):
+    return a == MAX_INT128, a == MIN_INT128
+
+
+@public
+def test_decimal(a: decimal) -> (bool, bool):
+    return a == MAX_DECIMAL, a == MIN_DECIMAL
+
+
+@public
+def test_uint256(a: uint256) -> bool:
+    return a == MAX_UINT256
+
+
+@public
+def test_arithmetic(a: int128) -> int128:
+    return MAX_INT128 - a
+    """
+
+    c = get_contract_with_gas_estimation(code)
+
+    assert c.test_zaddress("0x0000000000000000000000000000000000000000") is True
+    assert c.test_zaddress("0x0000000000000000000000000000000000000012") is False
+
+    assert c.test_int128(2**127 - 1) == [True, False]
+    assert c.test_int128(-2**127) == [False, True]
+    assert c.test_int128(0) == [False, False]
+
+    assert c.test_decimal(Decimal(2**127 - 1)) == [True, False]
+    assert c.test_decimal(Decimal('-170141183460469231731687303715884105728')) == [False, True]
+    assert c.test_decimal(Decimal('0.1')) == [False, False]
+
+    assert c.test_uint256(2**256 - 1) is True
+
+    assert c.test_arithmetic(5000) == 2**127 - 1 - 5000