def number(self): orignum = get_original_if_0_prefixed(self.expr, self.context) if orignum is None and isinstance(self.expr.n, int): # Literal becomes int128 if (SizeLimits.MINNUM <= self.expr.n <= SizeLimits.MAXNUM): return LLLnode.from_list(self.expr.n, typ=BaseType('int128', None, is_literal=True), pos=getpos(self.expr)) # Literal is large enough, becomes uint256. elif 0 <= self.expr.n <= SizeLimits.MAX_UINT256: return LLLnode.from_list(self.expr.n, typ=BaseType('uint256', None, is_literal=True), pos=getpos(self.expr)) else: raise InvalidLiteralException("Number out of range: " + str(self.expr.n), self.expr) elif isinstance(self.expr.n, float): numstring, num, den = get_number_as_fraction(self.expr, self.context) if not (SizeLimits.MINNUM * den < num < SizeLimits.MAXNUM * den): raise InvalidLiteralException("Number out of range: " + numstring, self.expr) if DECIMAL_DIVISOR % den: raise InvalidLiteralException("Too many decimal places: " + numstring, self.expr) return LLLnode.from_list(num * DECIMAL_DIVISOR // den, typ=BaseType('decimal', None), pos=getpos(self.expr)) # Binary literal. elif orignum[:2] == '0b': str_val = orignum[2:] total_bits = len(orignum[2:]) total_bits = total_bits if total_bits % 8 == 0 else total_bits + 8 - (total_bits % 8) # ceil8 to get byte length. if total_bits != len(orignum[2:]): # add necessary zero padding. pad_len = total_bits - len(orignum[2:]) str_val = pad_len * '0' + str_val byte_len = int(total_bits / 8) placeholder = self.context.new_placeholder(ByteArrayType(byte_len)) seq = [] seq.append(['mstore', placeholder, byte_len]) for i in range(0, total_bits, 256): section = str_val[i:i + 256] int_val = int(section, 2) << (256 - len(section)) # bytes are right padded. seq.append( ['mstore', ['add', placeholder, i + 32], int_val]) return LLLnode.from_list(['seq'] + seq + [placeholder], typ=ByteArrayType(byte_len), location='memory', pos=getpos(self.expr), annotation='Create ByteArray (Binary literal): %s' % str_val) elif len(orignum) == 42: if checksum_encode(orignum) != orignum: raise InvalidLiteralException("Address checksum mismatch. If you are sure this is the " "right address, the correct checksummed form is: " + checksum_encode(orignum), self.expr) return LLLnode.from_list(self.expr.n, typ=BaseType('address', is_literal=True), pos=getpos(self.expr)) elif len(orignum) == 66: return LLLnode.from_list(self.expr.n, typ=BaseType('bytes32', is_literal=True), pos=getpos(self.expr)) else: raise InvalidLiteralException("Cannot read 0x value with length %d. Expecting 42 (address incl 0x) or 66 (bytes32 incl 0x)" % len(orignum), self.expr)
def number(self): orignum = get_original_if_0_prefixed(self.expr, self.context) if orignum is None and isinstance(self.expr.n, int): # Literal (mostly likely) becomes int128 if SizeLimits.in_bounds('int128', self.expr.n) or self.expr.n < 0: return LLLnode.from_list(self.expr.n, typ=BaseType('int128', unit={}, is_literal=True), pos=getpos(self.expr)) # Literal is large enough (mostly likely) becomes uint256. else: return LLLnode.from_list(self.expr.n, typ=BaseType('uint256', unit={}, is_literal=True), pos=getpos(self.expr)) elif isinstance(self.expr.n, float): numstring, num, den = get_number_as_fraction(self.expr, self.context) # if not SizeLimits.in_bounds('decimal', num // den): # if not SizeLimits.MINDECIMAL * den <= num <= SizeLimits.MAXDECIMAL * den: if not (SizeLimits.MINNUM * den < num < SizeLimits.MAXNUM * den): raise InvalidLiteralException("Number out of range: " + numstring, self.expr) if DECIMAL_DIVISOR % den: raise InvalidLiteralException("Too many decimal places: " + numstring, self.expr) return LLLnode.from_list(num * DECIMAL_DIVISOR // den, typ=BaseType('decimal', unit=None), pos=getpos(self.expr)) # Binary literal. elif orignum[:2] == '0b': str_val = orignum[2:] total_bits = len(orignum[2:]) total_bits = total_bits if total_bits % 8 == 0 else total_bits + 8 - (total_bits % 8) # ceil8 to get byte length. if len(orignum[2:]) != total_bits: # Support only full formed bit definitions. raise InvalidLiteralException("Bit notation requires a multiple of 8 bits / 1 byte. {} bit(s) are missing.".format(total_bits - len(orignum[2:])), self.expr) byte_len = int(total_bits / 8) placeholder = self.context.new_placeholder(ByteArrayType(byte_len)) seq = [] seq.append(['mstore', placeholder, byte_len]) for i in range(0, total_bits, 256): section = str_val[i:i + 256] int_val = int(section, 2) << (256 - len(section)) # bytes are right padded. seq.append( ['mstore', ['add', placeholder, i + 32], int_val]) return LLLnode.from_list(['seq'] + seq + [placeholder], typ=ByteArrayType(byte_len), location='memory', pos=getpos(self.expr), annotation='Create ByteArray (Binary literal): %s' % str_val) elif len(orignum) == 42: if checksum_encode(orignum) != orignum: raise InvalidLiteralException("""Address checksum mismatch. If you are sure this is the right address, the correct checksummed form is: %s""" % checksum_encode(orignum), self.expr) return LLLnode.from_list(self.expr.n, typ=BaseType('address', is_literal=True), pos=getpos(self.expr)) elif len(orignum) == 66: return LLLnode.from_list(self.expr.n, typ=BaseType('bytes32', is_literal=True), pos=getpos(self.expr)) else: raise InvalidLiteralException("Cannot read 0x value with length %d. Expecting 42 (address incl 0x) or 66 (bytes32 incl 0x)" % len(orignum), self.expr)
def hexstring(self): orignum = self.expr.node_source_code if len(orignum) == 42: if checksum_encode(orignum) != orignum: raise InvalidLiteralException( "Address checksum mismatch. If you are sure this is the " f"right address, the correct checksummed form is: {checksum_encode(orignum)}", self.expr ) return LLLnode.from_list( self.expr.n, typ=BaseType('address', is_literal=True), pos=getpos(self.expr), ) elif len(orignum) == 66: return LLLnode.from_list( self.expr.n, typ=BaseType('bytes32', is_literal=True), pos=getpos(self.expr), ) else: raise InvalidLiteralException( f"Cannot read 0x value with length {len(orignum)}. Expecting 42 (address " "incl 0x) or 66 (bytes32 incl 0x)", self.expr )
def from_literal(cls, node: vy_ast.Constant) -> AddressDefinition: super().from_literal(node) addr = node.value if len(addr) != 42: raise InvalidLiteral("Invalid literal for type 'address'", node) if checksum_encode(addr) != addr: # this should have been caught in `vyper.ast.nodes.Hex.validate` raise CompilerPanic("Address checksum mismatch") return AddressDefinition()
def validate(self): if len(self.value) % 2: raise InvalidLiteral("Hex notation requires an even number of digits", self) if len(self.value) == 42 and checksum_encode(self.value) != self.value: raise InvalidLiteral( "Address checksum mismatch. If you are sure this is the right " f"address, the correct checksummed form is: {checksum_encode(self.value)}", self, )
def _py_convert(val, i_typ, o_typ): """ Perform conversion on the Python representation of a Vyper value. Returns None if the conversion is invalid (i.e., would revert in Vyper) """ i_detail = _parse_type(i_typ) o_detail = _parse_type(o_typ) if i_detail.type_class == "int" and o_detail.type_class == "int": if not SizeLimits.in_bounds(o_typ, val): return None return val if i_typ == "decimal" and o_typ in INTEGER_TYPES: return _convert_decimal_to_int(val, o_typ) if i_detail.type_class in ("bool", "int") and o_typ == "decimal": # Note: Decimal(True) == Decimal("1") return _convert_int_to_decimal(val, o_typ) val_bits = _to_bits(val, i_typ) if i_detail.type_class in ("Bytes", "String"): val_bits = val_bits[32:] if _padding_direction(i_typ) != _padding_direction(o_typ): # subtle! the padding conversion follows the bytes argument if i_detail.type_class in ("bytes", "Bytes"): n = i_detail.type_bytes padding_byte = None else: # output type is bytes n = o_detail.type_bytes padding_byte = b"\x00" val_bits = _padconvert(val_bits, _padding_direction(o_typ), n, padding_byte) if getattr(o_detail.info, "is_signed", False) and i_detail.type_class == "bytes": n_bits = i_detail.type_bytes * 8 val_bits = _signextend(val_bits, n_bits) try: if o_typ == "bool": return _from_bits(val_bits, "uint256") != 0 ret = _from_bits(val_bits, o_typ) if o_typ == "address": return checksum_encode(ret) return ret except _OutOfBounds: return None
def from_literal(cls, node: vy_ast.Constant) -> AddressDefinition: super().from_literal(node) addr = node.value if len(addr) != 42: raise InvalidLiteral("Invalid literal for type 'address'", node) if checksum_encode(addr) != addr: raise InvalidLiteral( "Address checksum mismatch. If you are sure this is the right " f"address, the correct checksummed form is: {checksum_encode(addr)}", node, ) return AddressDefinition()
def number(self): orignum = get_original_if_0x_prefixed(self.expr, self.context) if orignum is None and isinstance(self.expr.n, int): if not (SizeLimits.MINNUM <= self.expr.n <= SizeLimits.MAXNUM): raise InvalidLiteralException( "Number out of range: " + str(self.expr.n), self.expr) return LLLnode.from_list(self.expr.n, typ=BaseType('int128', None), pos=getpos(self.expr)) elif isinstance(self.expr.n, float): numstring, num, den = get_number_as_fraction( self.expr, self.context) if not (SizeLimits.MINNUM * den < num < SizeLimits.MAXNUM * den): raise InvalidLiteralException( "Number out of range: " + numstring, self.expr) if DECIMAL_DIVISOR % den: raise InvalidLiteralException( "Too many decimal places: " + numstring, self.expr) return LLLnode.from_list(num * DECIMAL_DIVISOR // den, typ=BaseType('decimal', None), pos=getpos(self.expr)) elif len(orignum) == 42: if checksum_encode(orignum) != orignum: raise InvalidLiteralException( "Address checksum mismatch. If you are sure this is the " "right address, the correct checksummed form is: " + checksum_encode(orignum), self.expr) return LLLnode.from_list(self.expr.n, typ=BaseType('address'), pos=getpos(self.expr)) elif len(orignum) == 66: return LLLnode.from_list(self.expr.n, typ=BaseType('bytes32'), pos=getpos(self.expr)) else: raise InvalidLiteralException( "Cannot read 0x value with length %d. Expecting 42 (address incl 0x) or 66 (bytes32 incl 0x)" % len(orignum), self.expr)
def parse_Hex(self): orignum = self.expr.value if len(orignum) == 42 and checksum_encode(orignum) == orignum: return LLLnode.from_list( int(self.expr.value, 16), typ=BaseType("address", is_literal=True), pos=getpos(self.expr), ) elif len(orignum) == 66: return LLLnode.from_list( int(self.expr.value, 16), typ=BaseType("bytes32", is_literal=True), pos=getpos(self.expr), )
def test_uint256_clamping(get_contract, assert_tx_failed): test_fails = 2**160 test_passing = test_fails - 1 test_bytes_to_address = """ @external def foo(x: uint256) -> address: return convert(x, address) """ c = get_contract(test_bytes_to_address) assert_tx_failed(lambda: c.foo(test_fails)) assert c.foo(test_passing) == checksum_encode("0x" + "ff" * 20)
def test_bytes32_clamping(get_contract, assert_tx_failed): test_passing = (b"\xff" * 20).rjust(32, b"\x00") test_fails = (b"\x01" + b"\xff" * 20).rjust(32, b"\x00") test_bytes_to_address = """ @external def foo(x: bytes32) -> address: return convert(x, address) """ c = get_contract(test_bytes_to_address) assert_tx_failed(lambda: c.foo(test_fails)) assert c.foo(test_passing) == checksum_encode("0x" + "ff" * 20)
def test_create_minimal_proxy_to_create(get_contract): code = """ main: address @external def test() -> address: self.main = create_minimal_proxy_to(self) return self.main """ c = get_contract(code) address_bits = int(c.address, 16) nonce = 1 rlp_encoded = rlp.encode([address_bits, nonce]) expected_create_address = keccak256(rlp_encoded)[12:].rjust(20, b"\x00") assert c.test() == checksum_encode("0x" + expected_create_address.hex())
def parse_Hex(self): hexstr = self.expr.value if len(hexstr) == 42: # sanity check typechecker did its job assert checksum_encode(hexstr) == hexstr typ = BaseType("address") # TODO allow non-checksum encoded bytes20 return IRnode.from_list(int(self.expr.value, 16), typ=typ) else: n_bytes = (len(hexstr) - 2) // 2 # e.g. "0x1234" is 2 bytes # TODO: typ = new_type_to_old_type(self.expr._metadata["type"]) # assert n_bytes == typ._bytes_info.m # bytes_m types are left padded with zeros val = int(hexstr, 16) << 8 * (32 - n_bytes) typ = BaseType(f"bytes{n_bytes}", is_literal=True) typ.is_literal = True return IRnode.from_list(val, typ=typ)