def do_address(ctx: Context, prim, args, annots): top = ctx.pop1() assert_stack_type(top, Contract) res = Address.new(top.get_address()) if top.name: annots.append(f'@{top.name}.address') ctx.push(res, annots=annots)
def do_commit(ctx: Context, prim, args, annots): debug, ctx.debug = ctx.debug, False output = ctx.pop1() assert_stack_type(output, Pair) operations = output.get_element(0) assert_stack_type(operations, List) assert operations.val_type() == Operation, f'expected list of operations' s_type_expr = ctx.get('storage') assert s_type_expr, f'storage type is not initialized' storage = output.get_element(1) assert_expr_equal(s_type_expr, storage.type_expr) storage, big_map_diff = ctx.big_maps.diff(storage) ctx.big_maps.commit(big_map_diff) res = Pair.new(operations, storage) ctx.push(res) ctx.debug = debug return {'kind': 'output', 'operations': operations, 'storage': storage, 'big_map_diff': big_map_diff}
def do_left(ctx: Context, prim, args, annots): top = ctx.pop1() if prim == 'LEFT': res = Or.left(r_type_expr=args[0], item=top) else: res = Or.right(l_type_expr=args[0], item=top) ctx.push(res, annots=annots)
def do_create_contract(ctx: Context, prim, args, annots): assert len(args[0]) == 3, 'expected { parameter ; storage ; code }' parameter_type, storage_type, code = args[0] delegate, amount, storage = ctx.pop3() assert_stack_type(amount, Mutez) decrease_balance(ctx, amount) assert_stack_type(delegate, Option) assert_equal_types(storage_type, storage.type_expr) originated_address = Address.new(ctx.dummy_gen.get_fresh_address()) content = { 'kind': 'origination', 'source': ctx.dummy_gen.self, 'balance': str(int(amount)), 'script': { 'storage': storage.val_expr, 'code': code }, 'originated_contract': str(originated_address) } if not delegate.is_none(): content['delegate'] = str(delegate.get_some()) orig = Operation.new(content) ctx.push(originated_address) ctx.push(orig)
def do_mem(ctx: Context, prim, args, annots): key, container = ctx.pop2() assert_stack_type(container, [Set, Map, BigMap]) if type(container) == BigMap: res = Bool(ctx.big_maps.contains(container, key)) else: res = Bool(key in container) ctx.push(res, annots=annots)
def do_is_nat(ctx: Context, prim, args, annots): top = ctx.pop1() assert_stack_type(top, Int) if int(top) >= 0: res = Option.some(Nat(int(top))) else: res = Option.none(Nat().type_expr) ctx.push(res, annots=annots)
def do_lsl(ctx: Context, prim, args, annots): a, b = ctx.pop2() assert_stack_type(a, Nat) assert_stack_type(b, Nat) assert int(b) < 257, f'shift overflow {int(b)}, should not exceed 256' handlers = {'LSL': lambda x: x[0] << x[1], 'LSR': lambda x: x[0] >> x[1]} res = Nat(handlers[prim]((int(a), int(b)))) ctx.push(res, annots=annots)
def do_sha(ctx: Context, prim, args, annots): top = ctx.pop1() assert_stack_type(top, Bytes) handlers = { 'SHA256': lambda x: sha256(x).digest(), 'SHA512': lambda x: sha512(x).digest(), } res = Bytes(handlers[prim](bytes(top))) ctx.push(res, annots=annots)
def do_or_xor(ctx: Context, prim, args, annots): a, b = ctx.pop2() val_type, res_type = dispatch_type_map(a, b, { (Bool, Bool): (bool, Bool), (Nat, Nat): (int, Nat), }) handlers = {'OR': lambda x: x[0] | x[1], 'XOR': lambda x: x[0] ^ x[1]} res = res_type(handlers[prim]((val_type(a), val_type(b)))) ctx.push(res, annots=annots)
def do_if_left(ctx: Context, prim, args, annots): assert_no_annots(prim, annots) top = ctx.pop1() assert_stack_type(top, Option) if top.is_none(): do_interpret(ctx, args[0]) else: ctx.push(top.get_some()) do_interpret(ctx, args[1])
def do_slice(ctx: Context, prim, args, annots): offset, length, s = ctx.pop3() assert_stack_type(s, [String, Bytes]) offset, length = int(offset), int(length) if len(s) > 0 and offset + length <= len(s): res = Option.some(s[offset:offset+length]) else: res = Option.none(type(s)().type_expr) ctx.push(res, annots=annots)
def do_exec(ctx: Context, prim, args, annots): param, lmbda = ctx.pop2() assert_stack_type(lmbda, Lambda) lmbda.assert_param_type(param) lmbda_ctx = ctx.spawn(stack=[param]) do_interpret(lmbda_ctx, lmbda.code) ret = lmbda_ctx.pop1() lmbda.assert_ret_type(ret) assert len(lmbda_ctx) == 0, f'lambda stack is not empty {lmbda_ctx}' ctx.push(ret, annots=annots)
def do_loop_left(ctx: Context, prim, args, annots): assert_no_annots(prim, annots) while True: top = ctx.pop1() assert_stack_type(top, Or) ctx.push(top.get_some()) if top.is_left(): do_interpret(ctx, args[0]) else: break
def do_not(ctx: Context, prim, args, annots): top = ctx.pop1() assert_stack_type(top, [Nat, Int, Bool]) if type(top) in [Nat, Int]: res = Int(~int(top)) elif type(top) == Bool: res = Bool(not bool(top)) else: assert False ctx.push(res, annots=annots)
def do_now(ctx: Context, prim, args, annots): res = ctx.get('NOW') if not res: network = ctx.get('NETWORK') if network: now = pytezos.using(network).now() else: now = int(datetime.utcnow().timestamp()) res = Timestamp(now) ctx.push(res, annots=['@now'])
def do_self(ctx: Context, prim, args, annots): p_type_expr = ctx.get('parameter') assert p_type_expr, f'parameter type is not initialized' entry_annot = next((a for a in annots if a[0] == '%'), '%default') ctx.print(f'use {entry_annot}') p_type_expr, _ = get_entry_expr(p_type_expr, entry_annot) res = Contract.new(ctx.dummy_gen.self + entry_annot, type_expr=p_type_expr) ctx.push(res, annots=['@self'])
def do_map(ctx: Context, prim, args, annots): container = ctx.pop1() assert_stack_type(container, [List, Map]) if type(container) == List: items = list() for item in container: ctx.push(item) do_interpret(ctx, args[0]) ret = ctx.pop1() items.append(ret) elif type(container) == Map: items = list() for key, val in container: ctx.push(Pair.new(key, val)) do_interpret(ctx, args[0]) ret = ctx.pop1() items.append((key, ret)) else: assert False if len(items) == 0: res = container else: res = type(container).new(items) ctx.push(res, annots=annots)
def do_if_cons(ctx: Context, prim, args, annots): assert_no_annots(prim, annots) top = ctx.pop1() assert_stack_type(top, List) if len(top) > 0: head, tail = top.cut_head() ctx.push(tail) ctx.push(head) do_interpret(ctx, args[0]) else: do_interpret(ctx, args[1])
def do_set_delegate(ctx: Context, prim, args, annots): delegate = ctx.pop1() assert_stack_type(delegate, Option) content = { 'kind': 'delegation', 'source': ctx.dummy_gen.self, 'delegate': None if delegate.is_none() else str(delegate.get_some()) } res = Operation.new(content) ctx.push(res)
def do_and(ctx: Context, prim, args, annots): a, b = ctx.pop2() val_type, res_type = dispatch_type_map( a, b, { (Bool, Bool): (bool, Bool), (Nat, Nat): (int, Nat), (Int, Nat): (int, Nat), (Nat, Int): (int, Nat) }) res = res_type(val_type(a) & val_type(b)) ctx.push(res, annots=annots)
def do_unpack(ctx: Context, prim, args, annots): top = ctx.pop1() assert_stack_type(top, Bytes) try: val_expr = unpack(data=bytes(top), type_expr=args[0]) item = StackItem.parse(val_expr=val_expr, type_expr=args[0]) res = Option.some(item) except Exception as e: ctx.print(f'failed: {e}') res = Option.none(args[0]) ctx.push(res, annots=annots)
def do_mul(ctx: Context, prim, args, annots): a, b = ctx.pop2() res_type = dispatch_type_map( a, b, { (Nat, Nat): Nat, (Nat, Int): Int, (Int, Nat): Int, (Int, Int): Int, (Mutez, Nat): Mutez, (Nat, Mutez): Mutez }) res = res_type(int(a) * int(b)) ctx.push(res, annots=annots)
def do_check_sig(ctx: Context, prim, args, annots): pk, sig, msg = ctx.pop3() assert_stack_type(pk, Key) assert_stack_type(sig, Signature) assert_stack_type(msg, Bytes) key = crypto.Key.from_encoded_key(str(pk)) try: key.verify(signature=str(sig), message=bytes(msg)) except: res = Bool(False) else: res = Bool(True) ctx.push(res, annots=annots)
def do_eq(ctx: Context, prim, args, annots): top = ctx.pop1() assert_stack_type(top, Int) handlers = { 'EQ': lambda x: x == 0, 'GE': lambda x: x >= 0, 'GT': lambda x: x > 0, 'LE': lambda x: x <= 0, 'LT': lambda x: x < 0, 'NEQ': lambda x: x != 0 } res = Bool(handlers[prim](int(top))) ctx.push(res, annots=annots)
def do_patch(ctx: Context, prim, args, annots): key, _ = parse_prim_expr(args[0]) assert key in patch_prim, f'expected one of {", ".join(patch_prim)}, got {args[0]}' if key in ['AMOUNT', 'BALANCE']: res = Mutez(get_int(args[1])) elif key == 'NOW': res = Timestamp(get_int(args[1])) elif key in ['SOURCE', 'SENDER']: res = Address.new(get_string(args[1])) elif key == 'CHAIN_ID': res = ChainID(get_string(args[1])) else: assert False ctx.set(key, res)
def do_map(ctx: Context, prim, args, annots): assert_no_annots(prim, annots) container = ctx.pop1() inferred_annots = [f'@{container.name}.elt'] if container.name else None if type(container) in [List, Set]: for item in container: ctx.push(item, annots=inferred_annots) do_interpret(ctx, args[0]) elif type(container) == Map: for key, val in container: ctx.push(Pair.new(key, val), annots=inferred_annots) do_interpret(ctx, args[0]) else: assert False, f'unexpected type {type(container)}'
def do_add(ctx: Context, prim, args, annots): a, b = ctx.pop2() res_type = dispatch_type_map( a, b, { (Nat, Nat): Nat, (Nat, Int): Int, (Int, Nat): Int, (Int, Int): Int, (Timestamp, Int): Timestamp, (Int, Timestamp): Timestamp, (Mutez, Mutez): Mutez }) res = res_type(int(a) + int(b)) ctx.push(res, annots=annots)
def do_contract(ctx: Context, prim, args, annots): top = ctx.pop1() assert_stack_type(top, Address) entry_annot = next((a for a in annots if a[0] == '%'), '%default') contract = Contract.new(str(top) + entry_annot, type_expr=args[0]) if check_contract(ctx, address=str(top), entry_annot=entry_annot, type_expr=args[0]): res = Option.some(contract) else: res = Option.none(contract.type_expr) if top.name: annots.append(f'@{top.name}.contract') ctx.push(res, annots=[a for a in annots if a[0] != '%'])
def do_include(ctx: Context, prim, args, annots): path = get_string(args[0]) if isfile(path): code = Contract.from_file(path).code else: parts = path.split(':') network = parts[0] if len(parts) > 1 else ctx.get('NETWORK', 'mainnet') address = parts[1] if len(parts) > 1 else parts[0] assert is_kt(address), f'expected filename or KT address (with network), got {path}' script = Interop().using(network).shell.contracts[address].script() code = script['code'] ctx.set('STORAGE', script['storage']) do_interpret(ctx, code)
def do_now(ctx: Context, prim, args, annots): res = ctx.get('NOW') if res is None: network = ctx.get('NETWORK') if network: interop = Interop().using(network) constants = interop.shell.block.context.constants() # cached ts = interop.shell.head.header()['timestamp'] dt = datetime.strptime(ts, '%Y-%m-%dT%H:%M:%SZ') first_delay = constants['time_between_blocks'][0] return int((dt - datetime(1970, 1, 1)).total_seconds()) + int(first_delay) else: now = int(datetime.utcnow().timestamp()) res = Timestamp(now) ctx.push(res, annots=['@now'])