Ejemplo n.º 1
0
def num256_mod(expr, args, kwargs, context):
    return LLLnode.from_list(['mod', args[0], args[1]],
                             typ=BaseType('num256'),
                             pos=getpos(expr))
Ejemplo n.º 2
0
def as_num128(expr, args, kwargs, context):
    return LLLnode.from_list(
        ['clamp', ['mload', MemoryPositions.MINNUM], args[0], ['mload', MemoryPositions.MAXNUM]], typ=BaseType("num"), pos=getpos(expr)
    )
Ejemplo n.º 3
0
        numstring, num, den = get_number_as_fraction(expr.args[0], context)
        if denomination % den:
            raise InvalidLiteralException(
                "Too many decimal places: %s" % numstring, expr.args[0])
        sub = num * denomination // den
    elif args[0].typ.typ == 'num':
        sub = ['mul', args[0], denomination]
    else:
        sub = ['div', ['mul', args[0], denomination], DECIMAL_DIVISOR]
    return LLLnode.from_list(sub,
                             typ=BaseType('num', {'wei': 1}),
                             location=None,
                             pos=getpos(expr))


zero_value = LLLnode.from_list(0, typ=BaseType('num', {'wei': 1}))


@signature('address',
           'bytes',
           outsize='num_literal',
           gas='num',
           value=Optional('num', zero_value))
def raw_call(expr, args, kwargs, context):
    to, data = args
    gas, value, outsize = kwargs['gas'], kwargs['value'], kwargs['outsize']
    if context.is_constant:
        raise ConstancyViolationException(
            "Cannot make calls from a constant function", expr)
    if value != zero_value:
        enforce_units(value.typ, get_keyword(expr, 'value'),
Ejemplo n.º 4
0
def avo(arg, ind):
    return unwrap_location(
        add_variable_offset(arg, LLLnode.from_list(ind, 'num')))
Ejemplo n.º 5
0
def _RLPlist(expr, args, kwargs, context):
    # Second argument must be a list of types
    if not isinstance(args[1], ast.List):
        raise TypeMismatchException(
            "Expecting list of types for second argument", args[1])
    if len(args[1].elts) == 0:
        raise TypeMismatchException("RLP list must have at least one item",
                                    expr)
    if len(args[1].elts) > 32:
        raise TypeMismatchException("RLP list must have at most 32 items",
                                    expr)
    # Get the output format
    _format = []
    for arg in args[1].elts:
        if isinstance(arg, ast.Name) and arg.id == "bytes":
            subtyp = ByteArrayType(args[0].typ.maxlen)
        else:
            subtyp = parse_type(arg, 'memory')
            if not isinstance(subtyp, BaseType):
                raise TypeMismatchException(
                    "RLP lists only accept BaseTypes and byte arrays", arg)
            if not is_base_type(
                    subtyp, ('num', 'num256', 'bytes32', 'address', 'bool')):
                raise TypeMismatchException(
                    "Unsupported base type: %s" % subtyp.typ, arg)
        _format.append(subtyp)
    output_type = TupleType(_format)
    output_placeholder_type = ByteArrayType(
        (2 * len(_format) + 1 + get_size_of_type(output_type)) * 32)
    output_placeholder = context.new_placeholder(output_placeholder_type)
    output_node = LLLnode.from_list(output_placeholder,
                                    typ=output_placeholder_type,
                                    location='memory')
    # Create a decoder for each element in the tuple
    decoder = []
    for i, typ in enumerate(_format):
        # Decoder for bytes32
        if is_base_type(typ, 'bytes32'):
            decoder.append(
                LLLnode.from_list(
                    [
                        'seq',
                        [
                            'assert',
                            [
                                'eq',
                                [
                                    'mload',
                                    [
                                        'add', output_node,
                                        [
                                            'mload',
                                            ['add', output_node, 32 * i]
                                        ]
                                    ]
                                ], 32
                            ]
                        ],
                        [
                            'mload',
                            [
                                'add', 32,
                                [
                                    'add', output_node,
                                    ['mload', ['add', output_node, 32 * i]]
                                ]
                            ]
                        ]
                    ],
                    typ,
                    annotation='getting and checking bytes32 item'))
        # Decoder for address
        elif is_base_type(typ, 'address'):
            decoder.append(
                LLLnode.from_list(
                    [
                        'seq',
                        [
                            'assert',
                            [
                                'eq',
                                [
                                    'mload',
                                    [
                                        'add', output_node,
                                        [
                                            'mload',
                                            ['add', output_node, 32 * i]
                                        ]
                                    ]
                                ], 20
                            ]
                        ],
                        [
                            'mod',
                            [
                                'mload',
                                [
                                    'add', 20,
                                    [
                                        'add', output_node,
                                        [
                                            'mload',
                                            ['add', output_node, 32 * i]
                                        ]
                                    ]
                                ]
                            ], ['mload', MemoryPositions.ADDRSIZE]
                        ]
                    ],
                    typ,
                    annotation='getting and checking address item'))
        # Decoder for bytes
        elif isinstance(typ, ByteArrayType):
            decoder.append(
                LLLnode.from_list([
                    'add', output_node,
                    ['mload', ['add', output_node, 32 * i]]
                ],
                                  typ,
                                  location='memory',
                                  annotation='getting byte array'))
        # Decoder for num and num256
        elif is_base_type(typ, ('num', 'num256')):
            bytez = LLLnode.from_list(
                ['add', output_node, ['mload', ['add', output_node, 32 * i]]],
                typ,
                location='memory',
                annotation='getting and checking %s' % typ.typ)
            decoder.append(byte_array_to_num(bytez, expr, typ.typ))
        # Decoder for bools
        elif is_base_type(typ, ('bool')):
            # This is basically a really clever way to test for a length-prefixed one or zero. We take the 32 bytes
            # starting one byte *after* the start of the length declaration; this includes the last 31 bytes of the
            # length and the first byte of the value. 0 corresponds to length 0, first byte 0, and 257 corresponds
            # to length 1, first byte \x01
            decoder.append(
                LLLnode.from_list([
                    'with', '_ans',
                    [
                        'mload',
                        [
                            'add', 1,
                            [
                                'add', output_node,
                                ['mload', ['add', output_node, 32 * i]]
                            ]
                        ]
                    ],
                    [
                        'seq',
                        [
                            'assert',
                            ['or', ['eq', '_ans', 0], ['eq', '_ans', 257]]
                        ], ['div', '_ans', 257]
                    ]
                ],
                                  typ,
                                  annotation='getting and checking bool'))
        else:
            raise Exception("Type not yet supported")
    # Copy the input data to memory
    if args[0].location == "memory":
        variable_pointer = args[0]
    elif args[0].location == "storage":
        placeholder = context.new_placeholder(args[0].typ)
        placeholder_node = LLLnode.from_list(placeholder,
                                             typ=args[0].typ,
                                             location='memory')
        copier = make_byte_array_copier(
            placeholder_node,
            LLLnode.from_list('_ptr',
                              typ=args[0].typ,
                              location=args[0].location))
        variable_pointer = [
            'with', '_ptr', args[0], ['seq', copier, placeholder_node]
        ]
    else:
        raise Exception("Location not yet supported")
    # Decode the input data
    initial_setter = LLLnode.from_list([
        'seq',
        [
            'with', '_sub', variable_pointer,
            [
                'pop',
                [
                    'call', 1500 + 400 * len(_format) + 10 * len(args),
                    LLLnode.from_list(RLP_DECODER_ADDRESS,
                                      annotation='RLP decoder'), 0,
                    ['add', '_sub', 32], ['mload', '_sub'], output_node,
                    64 * len(_format) + 32 + 32 * get_size_of_type(output_type)
                ]
            ]
        ], ['assert', ['eq', ['mload', output_node], 32 * len(_format) + 32]]
    ],
                                       typ=None)
    # Shove the input data decoder in front of the first variable decoder
    decoder[0] = LLLnode.from_list(['seq', initial_setter, decoder[0]],
                                   typ=decoder[0].typ,
                                   location=decoder[0].location)
    return LLLnode.from_list(["multi"] + decoder,
                             typ=output_type,
                             location='memory',
                             pos=getpos(expr))
Ejemplo n.º 6
0
def as_unitless_number(expr, args, kwargs, context):
    return LLLnode(value=args[0].value,
                   args=args[0].args,
                   typ=BaseType(args[0].typ.typ, {}),
                   pos=getpos(expr))
Ejemplo n.º 7
0
def concat(expr, context):
    args = [Expr(arg, context).lll_node for arg in expr.args]
    if len(args) < 2:
        raise StructureException("Concat expects at least two arguments", expr)
    for expr_arg, arg in zip(expr.args, args):
        if not isinstance(arg.typ, ByteArrayType) and not is_base_type(
                arg.typ, 'bytes32') and not is_base_type(arg.typ, 'method_id'):
            raise TypeMismatchException(
                "Concat expects byte arrays or bytes32 objects", expr_arg)
    # Maximum length of the output
    total_maxlen = sum([
        arg.typ.maxlen if isinstance(arg.typ, ByteArrayType) else 32
        for arg in args
    ])
    # Node representing the position of the output in memory
    placeholder = context.new_placeholder(ByteArrayType(total_maxlen))
    # Object representing the output
    seq = []
    # For each argument we are concatenating...
    for arg in args:
        # Start pasting into a position the starts at zero, and keeps
        # incrementing as we concatenate arguments
        placeholder_node = LLLnode.from_list(['add', placeholder, '_poz'],
                                             typ=ByteArrayType(total_maxlen),
                                             location='memory')
        placeholder_node_plus_32 = LLLnode.from_list(
            ['add', ['add', placeholder, '_poz'], 32],
            typ=ByteArrayType(total_maxlen),
            location='memory')
        if isinstance(arg.typ, ByteArrayType):
            # Ignore empty strings
            if arg.typ.maxlen == 0:
                continue
            # Get the length of the current argument
            if arg.location == "memory":
                length = LLLnode.from_list(['mload', '_arg'],
                                           typ=BaseType('num'))
                argstart = LLLnode.from_list(['add', '_arg', 32],
                                             typ=arg.typ,
                                             location=arg.location)
            elif arg.location == "storage":
                length = LLLnode.from_list(['sload', ['sha3_32', '_arg']],
                                           typ=BaseType('num'))
                argstart = LLLnode.from_list(['add', ['sha3_32', '_arg'], 1],
                                             typ=arg.typ,
                                             location=arg.location)
            # Make a copier to copy over data from that argyument
            seq.append([
                'with',
                '_arg',
                arg,
                [
                    'seq',
                    make_byte_slice_copier(placeholder_node_plus_32, argstart,
                                           length, arg.typ.maxlen),
                    # Change the position to start at the correct
                    # place to paste the next value
                    ['set', '_poz', ['add', '_poz', length]]
                ]
            ])
        elif isinstance(arg.typ, BaseType) and arg.typ.typ == "method_id":
            seq.append([
                'seq',
                ['mstore', ['add', placeholder_node, 32], arg.value * 2**224],
                ['set', '_poz', ['add', '_poz', 4]]
            ])
        else:
            seq.append([
                'seq',
                [
                    'mstore', ['add', placeholder_node, 32],
                    unwrap_location(arg)
                ], ['set', '_poz', ['add', '_poz', 32]]
            ])
    # The position, after all arguments are processing, equals the total
    # length. Paste this in to make the output a proper bytearray
    seq.append(['mstore', placeholder, '_poz'])
    # Memory location of the output
    seq.append(placeholder)
    return LLLnode.from_list(['with', '_poz', 0, ['seq'] + seq],
                             typ=ByteArrayType(total_maxlen),
                             location='memory',
                             pos=getpos(expr))
Ejemplo n.º 8
0
def num256_mul(expr, args, kwargs, context):
    return LLLnode.from_list(['seq',
                                # Checks that: a == 0 || a / b == b
                                ['assert', ['or', ['iszero', args[0]],
                                ['eq', ['div', ['mul', args[0], args[1]], args[0]], args[1]]]],
                                ['mul', args[0], args[1]]], typ=BaseType('num256'), pos=getpos(expr))
Ejemplo n.º 9
0
def num256_div(expr, args, kwargs, context):
    return LLLnode.from_list(['seq',
                                # Checks that:  b != 0
                                ['assert', args[1]],
                                ['div', args[0], args[1]]], typ=BaseType('num256'), pos=getpos(expr))
Ejemplo n.º 10
0
def num256_add(expr, args, kwargs, context):
    return LLLnode.from_list(['seq',
                                # Checks that: a + b > a
                                ['assert', ['or', ['iszero', args[1]], ['gt', ['add', args[0], args[1]], args[0]]]],
                                ['add', args[0], args[1]]], typ=BaseType('num256'), pos=getpos(expr))
Ejemplo n.º 11
0
def num256_sub(expr, args, kwargs, context):
    return LLLnode.from_list(['seq',
                                # Checks that: a >= b
                                ['assert', ['ge', args[0], args[1]]],
                                ['sub', args[0], args[1]]], typ=BaseType('num256'), pos=getpos(expr))
Ejemplo n.º 12
0
def blockhash(expr, args, kwargs, contact):
    return LLLnode.from_list(['blockhash', ['uclamplt', ['clampge', args[0], ['sub', ['number'], 256]], 'number']],
                             typ=BaseType('bytes32'), pos=getpos(expr))
Ejemplo n.º 13
0
def selfdestruct(expr, args, kwargs, context):
    if context.is_constant:
        raise ConstancyViolationException("Cannot %s inside a constant function!" % expr.func.id, expr.func)
    return LLLnode.from_list(['selfdestruct', args[0]], typ=None, pos=getpos(expr))
Ejemplo n.º 14
0
def send(expr, args, kwargs, context):
    to, value = args
    if context.is_constant:
        raise ConstancyViolationException("Cannot send ether inside a constant function!", expr)
    enforce_units(value.typ, expr.args[1], BaseType('num', {'wei': 1}))
    return LLLnode.from_list(['assert', ['call', 0, to, value, 0, 0, 0, 0]], typ=None, pos=getpos(expr))
Ejemplo n.º 15
0
def num256_le(expr, args, kwargs, context):
    return LLLnode.from_list(['le', args[0], args[1]],
                             typ=BaseType('bool'),
                             pos=getpos(expr))
Ejemplo n.º 16
0
def num256_exp(expr, args, kwargs, context):
    return LLLnode.from_list(['seq',
                                ['assert', ['or', ['or', ['eq', args[1], 1], ['iszero', args[1]]],
                                ['lt', args[0], ['exp', args[0], args[1]]]]],
                                ['exp', args[0], args[1]]], typ=BaseType('num256'), pos=getpos(expr))
Ejemplo n.º 17
0
def floor(expr, args, kwargs, context):
    return LLLnode.from_list(['sdiv', args[0], DECIMAL_DIVISOR],
                             typ=BaseType('num', args[0].typ.unit,
                                          args[0].typ.positional),
                             pos=getpos(expr))
Ejemplo n.º 18
0
def num256_mulmod(expr, args, kwargs, context):
    return LLLnode.from_list(['seq',
                                ['assert', ['or', ['iszero', args[0]],
                                ['eq', ['div', ['mul', args[0], args[1]], args[0]], args[1]]]],
                                ['mulmod', args[0], args[1], args[2]]], typ=BaseType('num256'), pos=getpos(expr))
Ejemplo n.º 19
0
def as_bytes32(expr, args, kwargs, context):
    return LLLnode(value=args[0].value,
                   args=args[0].args,
                   typ=BaseType('bytes32'),
                   pos=getpos(expr))
Ejemplo n.º 20
0
 def lll_compiler(lll):
     lll = optimizer.optimize(LLLnode.from_list(lll))
     byte_code = compile_lll.assembly_to_evm(
         compile_lll.compile_to_assembly(lll))
     t.s.tx(to=b'', data=byte_code)
Ejemplo n.º 21
0
def method_id(expr, args, kwargs, context):
    method_id = fourbytes_to_int(sha3(args[0])[:4])
    return LLLnode(method_id, typ=BaseType('method_id'), pos=getpos(expr))
Ejemplo n.º 22
0
def optimize(node):
    argz = [optimize(arg) for arg in node.args]
    if node.value in arith and int_at(argz, 0) and int_at(argz, 1):
        left, right = get_int_at(argz, 0), get_int_at(argz, 1)
        calcer, symb = arith[node.value]
        new_value = calcer(left, right)
        if argz[0].annotation and argz[1].annotation:
            annotation = argz[0].annotation + symb + argz[1].annotation
        elif argz[0].annotation or argz[1].annotation:
            annotation = (argz[0].annotation or str(left)) + symb + (
                argz[1].annotation or str(right))
        else:
            annotation = ''
        return LLLnode(new_value, [], node.typ, None, node.pos, annotation)
    elif node.value == "add" and int_at(
            argz, 0) and argz[1].value == "add" and int_at(argz[1].args, 0):
        calcer, symb = arith[node.value]
        if argz[0].annotation and argz[1].args[0].annotation:
            annotation = argz[0].annotation + symb + argz[1].args[0].annotation
        elif argz[0].annotation or argz[1].args[0].annotation:
            annotation = (argz[0].annotation or str(argz[0].value)) + symb + (
                argz[1].args[0].annotation or str(argz[1].args[0].value))
        else:
            annotation = ''
        return LLLnode("add", [
            LLLnode(argz[0].value + argz[1].args[0].value,
                    annotation=annotation), argz[1].args[1]
        ], node.typ, None, node.annotation)
    elif node.value == "add" and get_int_at(argz, 0) == 0:
        return LLLnode(argz[1].value, argz[1].args, node.typ, node.location,
                       node.pos, argz[1].annotation)
    elif node.value == "add" and get_int_at(argz, 1) == 0:
        return LLLnode(argz[0].value, argz[0].args, node.typ, node.location,
                       node.pos, argz[0].annotation)
    elif node.value == "clamp" and int_at(argz, 0) and int_at(
            argz, 1) and int_at(argz, 2):
        if get_int_at(argz, 0, True) > get_int_at(argz, 1, True):
            raise Exception("Clamp always fails")
        elif get_int_at(argz, 1, True) > get_int_at(argz, 2, True):
            raise Exception("Clamp always fails")
        else:
            return argz[1]
    elif node.value == "clamp" and int_at(argz, 0) and int_at(argz, 1):
        if get_int_at(argz, 0, True) > get_int_at(argz, 1, True):
            raise Exception("Clamp always fails")
        else:
            return LLLnode("clample", [argz[1], argz[2]], node.typ,
                           node.location, node.pos, node.annotation)
    elif node.value == "clamp_nonzero" and int_at(argz, 0):
        if get_int_at(argz, 0) != 0:
            return LLLnode(argz[0].value, [], node.typ, node.location,
                           node.pos, node.annotation)
        else:
            raise Exception("Clamp always fails")
    # Turns out this is actually not such a good optimization after all
    elif node.value == "with" and int_at(
            argz, 1) and not search_for_set(argz[2], argz[0].value) and False:
        o = replace_with_value(argz[2], argz[0].value, argz[1].value)
        return o
    elif node.value == "seq":
        o = []
        for arg in argz:
            if arg.value == "seq":
                o.extend(arg.args)
            elif arg.value != "pass":
                o.append(arg)
        return LLLnode(node.value,
                       o,
                       node.typ,
                       node.location,
                       node.pos,
                       node.annotation,
                       add_gas_estimate=node.add_gas_estimate)
    elif hasattr(node, 'total_gas'):
        o = LLLnode(node.value, argz, node.typ, node.location, node.pos,
                    node.annotation)
        o.total_gas = node.total_gas - node.gas + o.gas
        o.func_name = node.func_name
        return o
    else:
        return LLLnode(node.value, argz, node.typ, node.location, node.pos,
                       node.annotation)
Ejemplo n.º 23
0
def extract32(expr, args, kwargs, context):
    sub, index = args
    ret_type = kwargs['type']
    # Get length and specific element
    if sub.location == "memory":
        lengetter = LLLnode.from_list(['mload', '_sub'], typ=BaseType('num'))
        elementgetter = lambda index: LLLnode.from_list(
            ['mload', ['add', '_sub', ['add', 32, ['mul', 32, index]]]],
            typ=BaseType('num'))
    elif sub.location == "storage":
        lengetter = LLLnode.from_list(['sload', ['sha3_32', '_sub']],
                                      typ=BaseType('num'))
        elementgetter = lambda index: LLLnode.from_list(
            ['sload', ['add', ['sha3_32', '_sub'], ['add', 1, index]]],
            typ=BaseType('num'))
    # Special case: index known to be a multiple of 32
    if isinstance(index.value, int) and not index.value % 32:
        o = LLLnode.from_list([
            'with', '_sub', sub,
            elementgetter(
                ['div', ['clamp', 0, index, ['sub', lengetter, 32]], 32])
        ],
                              typ=BaseType(ret_type),
                              annotation='extracting 32 bytes')
    # General case
    else:
        o = LLLnode.from_list([
            'with', '_sub', sub,
            [
                'with', '_len', lengetter,
                [
                    'with', '_index', ['clamp', 0, index, ['sub', '_len', 32]],
                    [
                        'with', '_mi32', ['mod', '_index', 32],
                        [
                            'with', '_di32', ['div', '_index', 32],
                            [
                                'if', '_mi32',
                                [
                                    'add',
                                    [
                                        'mul',
                                        elementgetter('_di32'),
                                        ['exp', 256, '_mi32']
                                    ],
                                    [
                                        'div',
                                        elementgetter(['add', '_di32', 1]),
                                        ['exp', 256, ['sub', 32, '_mi32']]
                                    ]
                                ],
                                elementgetter('_di32')
                            ]
                        ]
                    ]
                ]
            ]
        ],
                              typ=BaseType(ret_type),
                              pos=getpos(expr),
                              annotation='extracting 32 bytes')
    if ret_type == 'num128':
        return LLLnode.from_list([
            'clamp', ['mload', MemoryPositions.MINNUM], o,
            ['mload', MemoryPositions.MAXNUM]
        ],
                                 typ=BaseType("num"),
                                 pos=getpos(expr))
    elif ret_type == 'address':
        return LLLnode.from_list(
            ['uclamplt', o, ['mload', MemoryPositions.ADDRSIZE]],
            typ=BaseType(ret_type),
            pos=getpos(expr))
    else:
        return o
    simple_factory_contract_bytecode,
)
from tests.core.contract_fixtures.PAYGAS_contract import (
    simple_forwarder_contract_lll_code,
    PAYGAS_contract_normal_lll_code,
    PAYGAS_contract_triggered_twice_lll_code,
)
from tests.core.contract_fixtures.nonce_tracking_contract import (
    nonce_tracking_lll_code,
    no_nonce_tracking_lll_code,
)

DIR = os.path.dirname(__file__)

simple_transfer_contract_bytecode = assembly_to_evm(
    compile_to_assembly(LLLnode.from_list(simple_transfer_contract_lll_code)))

CREATE2_contract_bytecode = assembly_to_evm(
    compile_to_assembly(LLLnode.from_list(CREATE2_contract_lll_code)))

CREATE2_json = {
    "simple_transfer_contract": {
        "bytecode":
        encode_hex(simple_transfer_contract_bytecode),
        "address":
        encode_hex(
            generate_CREATE2_contract_address(
                b'', simple_transfer_contract_bytecode)),
    },
    "CREATE2_contract": {
        "bytecode":
Ejemplo n.º 25
0
def bitwise_or(expr, args, kwargs, context):
    return LLLnode.from_list(['or', args[0], args[1]],
                             typ=BaseType('num256'),
                             pos=getpos(expr))
Ejemplo n.º 26
0
rlp_decoder_lll = LLLnode.from_list([
    'seq',
    [
        'return',
        [0],
        [
            'lll',
            [
                'seq',
                ['mstore', position_index, 0],
                ['mstore', data_pos, 0],
                ['mstore', c, call_data_char(0)],
                ['mstore', i, 0],
                ['mstore', position_offset, 0],
                ['assert', ['ge', ['mload', c], 192]],  # Must be a list
                [
                    'if',
                    ['lt', ['mload', c], 248],  # if c < 248:
                    [
                        'seq',
                        [
                            'assert',
                            ['eq', ['calldatasize'],
                             sub(['mload', c], 191)]
                        ],  # assert ~calldatasize() == (c - 191)
                        ['mstore', i, 1]  # i = 1
                    ],
                    [
                        'seq',
                        [
                            'assert',
                            [
                                'eq', ['calldatasize'],
                                add(
                                    sub(['mload', c], 246),
                                    call_data_bytes_as_int(
                                        1, sub(['mload', c], 247)))
                            ]
                        ],  # assert ~calldatasize() == (c - 246) + calldatabytes_as_int(1, c - 247)
                        ['mstore', i, sub(['mload', c], 246)]  # i = c - 246
                    ],
                ],
                # Main loop
                # Here, we simultaneously build up data in two places:
                # (i) starting from memory index 64, a list of 32-byte numbers
                #     representing the start positions of each value
                # (ii) starting from memory index 1088, the values, in format
                #     <length as 32 byte int> <value>, packed one after the other
                [
                    'repeat', MemoryPositions.FREE_LOOP_INDEX, 1, 100,
                    [
                        'seq',
                        ['if', ['ge', ['mload', i], 'calldatasize'], 'break'],
                        ['mstore', c,
                         call_data_char(['mload', i])],
                        [
                            'mstore',
                            add(positions,
                                ['mul', ['mload', position_index], 32]),
                            ['mload', data_pos]
                        ],
                        [
                            'mstore', position_index,
                            add(['mload', position_index], 1)
                        ],
                        [
                            'if', ['lt', ['mload', c], 128],
                            [
                                'seq',
                                ['mstore',
                                 add(data, ['mload', data_pos]), 1],
                                [
                                    'calldatacopy',
                                    add(data + 32, ['mload', data_pos]),
                                    ['mload', i], 1
                                ], ['mstore', i,
                                    add(['mload', i], 1)],
                                [
                                    'mstore', data_pos,
                                    add(['mload', data_pos], 33)
                                ]
                            ],
                            [
                                'if', ['lt', ['mload', c], 184],
                                [
                                    'seq',
                                    [
                                        'mstore',
                                        add(data, ['mload', data_pos]),
                                        sub(['mload', c], 128)
                                    ],
                                    [
                                        'calldatacopy',
                                        add(data + 32, ['mload', data_pos]),
                                        add(['mload', i], 1),
                                        sub(['mload', c], 128)
                                    ],
                                    [
                                        'if', ['eq', ['mload', c], 129],
                                        [
                                            'assert',
                                            [
                                                'ge',
                                                call_data_char(
                                                    add(['mload', i], 1)), 128
                                            ]
                                        ]
                                    ],
                                    [
                                        'mstore', i,
                                        add(['mload', i], sub(['mload', c],
                                                              127))
                                    ],
                                    [
                                        'mstore', data_pos,
                                        add(['mload', data_pos],
                                            sub(['mload', c], 96))
                                    ]
                                ],
                                [
                                    'if', ['lt', ['mload', c], 192],
                                    [
                                        'seq',
                                        [
                                            'mstore', L,
                                            call_data_bytes_as_int(
                                                add(['mload', i], 1),
                                                sub(['mload', c], 183))
                                        ],
                                        [
                                            'assert',
                                            [
                                                'mul',
                                                call_data_char(
                                                    add(['mload', i], 1)),
                                                ['ge', ['mload', L], 56]
                                            ]
                                        ],
                                        [
                                            'mstore',
                                            add(data, ['mload', data_pos]),
                                            ['mload', L]
                                        ],
                                        [
                                            'calldatacopy',
                                            add(data + 32,
                                                ['mload', data_pos]),
                                            add(['mload', i],
                                                sub(['mload', c], 182)),
                                            ['mload', L]
                                        ],
                                        [
                                            'mstore', i,
                                            add(
                                                add(['mload', i],
                                                    sub(['mload', c], 182)),
                                                ['mload', L])
                                        ],
                                        [
                                            'mstore', data_pos,
                                            add(['mload', data_pos],
                                                add(['mload', L], 32))
                                        ]
                                    ], ['invalid']
                                ]
                            ]
                        ],
                    ]
                ],
                ['assert', ['le', ['mload', position_index], 31]],
                [
                    'mstore', position_offset,
                    add(['mul', ['mload', position_index], 32], 32)
                ],
                ['mstore', i, sub(['mload', position_offset], 32)],
                [
                    'repeat',
                    MemoryPositions.FREE_LOOP_INDEX,
                    1,
                    100,
                    [
                        'seq',
                        ['if', ['slt', ['mload', i], 0], 'break'],
                        [
                            'mstore',
                            add(sub(data, ['mload', position_offset]),
                                ['mload', i]),
                            add(['mload',
                                 add(positions, ['mload', i])],
                                ['mload', position_offset])
                        ],
                        # ~mstore(data - positionOffset + i, ~mload(positions + i) + positionOffset)
                        ['mstore', i, sub(['mload', i], 32)],
                    ]
                ],
                [
                    'mstore',
                    sub(data, 32),
                    add(['mload', position_offset], ['mload', data_pos])
                ],
                [
                    'return',
                    sub(data, ['mload', position_offset]),
                    add(['mload', position_offset], ['mload', data_pos])
                ]
            ],
            [0]
        ]
    ]
])