(* Generated by coq-of-rust *)
Require Import CoqOfRust.CoqOfRust.

Module instructions.
  Module contract.
    Module call_helpers.
      (*
      pub fn get_memory_input_and_out_ranges(
          interpreter: &mut Interpreter,
      ) -> Option<(Bytes, Range<usize>)> {
          pop_ret!(interpreter, in_offset, in_len, out_offset, out_len, None);
      
          let in_range = resize_memory_and_return_range(interpreter, in_offset, in_len)?;
      
          let mut input = Bytes::new();
          if !in_range.is_empty() {
              input = Bytes::copy_from_slice(interpreter.shared_memory.slice_range(in_range));
          }
      
          let ret_range = resize_memory_and_return_range(interpreter, out_offset, out_len)?;
          Some((input, ret_range))
      }
      *)
      Definition get_memory_input_and_out_ranges
          (ε : list Value.t)
          (τ : list Ty.t)
          (α : list Value.t)
          : M :=
        match ε, τ, α with
        | [], [], [ interpreter ] =>
          ltac:(M.monadic
            (let interpreter := M.alloc (| interpreter |) in
            M.catch_return (|
              ltac:(M.monadic
                (M.read (|
                  let~ _ :=
                    M.match_operator (|
                      M.alloc (| Value.Tuple [] |),
                      [
                        fun γ =>
                          ltac:(M.monadic
                            (let γ :=
                              M.use
                                (M.alloc (|
                                  BinOp.lt (|
                                    M.call_closure (|
                                      M.get_associated_function (|
                                        Ty.path "revm_interpreter::interpreter::stack::Stack",
                                        "len",
                                        []
                                      |),
                                      [
                                        M.SubPointer.get_struct_record_field (|
                                          M.read (| interpreter |),
                                          "revm_interpreter::interpreter::Interpreter",
                                          "stack"
                                        |)
                                      ]
                                    |),
                                    Value.Integer IntegerKind.Usize 4
                                  |)
                                |)) in
                            let _ :=
                              M.is_constant_or_break_match (| M.read (| γ |), Value.Bool true |) in
                            M.alloc (|
                              M.never_to_any (|
                                M.read (|
                                  let~ _ :=
                                    M.write (|
                                      M.SubPointer.get_struct_record_field (|
                                        M.read (| interpreter |),
                                        "revm_interpreter::interpreter::Interpreter",
                                        "instruction_result"
                                      |),
                                      Value.StructTuple
                                        "revm_interpreter::instruction_result::InstructionResult::StackUnderflow"
                                        []
                                    |) in
                                  M.return_ (| Value.StructTuple "core::option::Option::None" [] |)
                                |)
                              |)
                            |)));
                        fun γ => ltac:(M.monadic (M.alloc (| Value.Tuple [] |)))
                      ]
                    |) in
                  M.match_operator (|
                    M.alloc (|
                      M.call_closure (|
                        M.get_associated_function (|
                          Ty.path "revm_interpreter::interpreter::stack::Stack",
                          "pop4_unsafe",
                          []
                        |),
                        [
                          M.SubPointer.get_struct_record_field (|
                            M.read (| interpreter |),
                            "revm_interpreter::interpreter::Interpreter",
                            "stack"
                          |)
                        ]
                      |)
                    |),
                    [
                      fun γ =>
                        ltac:(M.monadic
                          (let γ0_0 := M.SubPointer.get_tuple_field (| γ, 0 |) in
                          let γ0_1 := M.SubPointer.get_tuple_field (| γ, 1 |) in
                          let γ0_2 := M.SubPointer.get_tuple_field (| γ, 2 |) in
                          let γ0_3 := M.SubPointer.get_tuple_field (| γ, 3 |) in
                          let in_offset := M.copy (| γ0_0 |) in
                          let in_len := M.copy (| γ0_1 |) in
                          let out_offset := M.copy (| γ0_2 |) in
                          let out_len := M.copy (| γ0_3 |) in
                          let~ in_range :=
                            M.copy (|
                              M.match_operator (|
                                M.alloc (|
                                  M.call_closure (|
                                    M.get_trait_method (|
                                      "core::ops::try_trait::Try",
                                      Ty.apply
                                        (Ty.path "core::option::Option")
                                        []
                                        [
                                          Ty.apply
                                            (Ty.path "core::ops::range::Range")
                                            []
                                            [ Ty.path "usize" ]
                                        ],
                                      [],
                                      "branch",
                                      []
                                    |),
                                    [
                                      M.call_closure (|
                                        M.get_function (|
                                          "revm_interpreter::instructions::contract::call_helpers::resize_memory_and_return_range",
                                          []
                                        |),
                                        [
                                          M.read (| interpreter |);
                                          M.read (| in_offset |);
                                          M.read (| in_len |)
                                        ]
                                      |)
                                    ]
                                  |)
                                |),
                                [
                                  fun γ =>
                                    ltac:(M.monadic
                                      (let γ0_0 :=
                                        M.SubPointer.get_struct_tuple_field (|
                                          γ,
                                          "core::ops::control_flow::ControlFlow::Break",
                                          0
                                        |) in
                                      let residual := M.copy (| γ0_0 |) in
                                      M.alloc (|
                                        M.never_to_any (|
                                          M.read (|
                                            M.return_ (|
                                              M.call_closure (|
                                                M.get_trait_method (|
                                                  "core::ops::try_trait::FromResidual",
                                                  Ty.apply
                                                    (Ty.path "core::option::Option")
                                                    []
                                                    [
                                                      Ty.tuple
                                                        [
                                                          Ty.path "alloy_primitives::bytes_::Bytes";
                                                          Ty.apply
                                                            (Ty.path "core::ops::range::Range")
                                                            []
                                                            [ Ty.path "usize" ]
                                                        ]
                                                    ],
                                                  [
                                                    Ty.apply
                                                      (Ty.path "core::option::Option")
                                                      []
                                                      [ Ty.path "core::convert::Infallible" ]
                                                  ],
                                                  "from_residual",
                                                  []
                                                |),
                                                [ M.read (| residual |) ]
                                              |)
                                            |)
                                          |)
                                        |)
                                      |)));
                                  fun γ =>
                                    ltac:(M.monadic
                                      (let γ0_0 :=
                                        M.SubPointer.get_struct_tuple_field (|
                                          γ,
                                          "core::ops::control_flow::ControlFlow::Continue",
                                          0
                                        |) in
                                      let val := M.copy (| γ0_0 |) in
                                      val))
                                ]
                              |)
                            |) in
                          let~ input :=
                            M.alloc (|
                              M.call_closure (|
                                M.get_associated_function (|
                                  Ty.path "alloy_primitives::bytes_::Bytes",
                                  "new",
                                  []
                                |),
                                []
                              |)
                            |) in
                          let~ _ :=
                            M.match_operator (|
                              M.alloc (| Value.Tuple [] |),
                              [
                                fun γ =>
                                  ltac:(M.monadic
                                    (let γ :=
                                      M.use
                                        (M.alloc (|
                                          UnOp.not (|
                                            M.call_closure (|
                                              M.get_associated_function (|
                                                Ty.apply
                                                  (Ty.path "core::ops::range::Range")
                                                  []
                                                  [ Ty.path "usize" ],
                                                "is_empty",
                                                []
                                              |),
                                              [ in_range ]
                                            |)
                                          |)
                                        |)) in
                                    let _ :=
                                      M.is_constant_or_break_match (|
                                        M.read (| γ |),
                                        Value.Bool true
                                      |) in
                                    let~ _ :=
                                      M.write (|
                                        input,
                                        M.call_closure (|
                                          M.get_associated_function (|
                                            Ty.path "alloy_primitives::bytes_::Bytes",
                                            "copy_from_slice",
                                            []
                                          |),
                                          [
                                            M.call_closure (|
                                              M.get_associated_function (|
                                                Ty.path
                                                  "revm_interpreter::interpreter::shared_memory::SharedMemory",
                                                "slice_range",
                                                []
                                              |),
                                              [
                                                M.SubPointer.get_struct_record_field (|
                                                  M.read (| interpreter |),
                                                  "revm_interpreter::interpreter::Interpreter",
                                                  "shared_memory"
                                                |);
                                                M.read (| in_range |)
                                              ]
                                            |)
                                          ]
                                        |)
                                      |) in
                                    M.alloc (| Value.Tuple [] |)));
                                fun γ => ltac:(M.monadic (M.alloc (| Value.Tuple [] |)))
                              ]
                            |) in
                          let~ ret_range :=
                            M.copy (|
                              M.match_operator (|
                                M.alloc (|
                                  M.call_closure (|
                                    M.get_trait_method (|
                                      "core::ops::try_trait::Try",
                                      Ty.apply
                                        (Ty.path "core::option::Option")
                                        []
                                        [
                                          Ty.apply
                                            (Ty.path "core::ops::range::Range")
                                            []
                                            [ Ty.path "usize" ]
                                        ],
                                      [],
                                      "branch",
                                      []
                                    |),
                                    [
                                      M.call_closure (|
                                        M.get_function (|
                                          "revm_interpreter::instructions::contract::call_helpers::resize_memory_and_return_range",
                                          []
                                        |),
                                        [
                                          M.read (| interpreter |);
                                          M.read (| out_offset |);
                                          M.read (| out_len |)
                                        ]
                                      |)
                                    ]
                                  |)
                                |),
                                [
                                  fun γ =>
                                    ltac:(M.monadic
                                      (let γ0_0 :=
                                        M.SubPointer.get_struct_tuple_field (|
                                          γ,
                                          "core::ops::control_flow::ControlFlow::Break",
                                          0
                                        |) in
                                      let residual := M.copy (| γ0_0 |) in
                                      M.alloc (|
                                        M.never_to_any (|
                                          M.read (|
                                            M.return_ (|
                                              M.call_closure (|
                                                M.get_trait_method (|
                                                  "core::ops::try_trait::FromResidual",
                                                  Ty.apply
                                                    (Ty.path "core::option::Option")
                                                    []
                                                    [
                                                      Ty.tuple
                                                        [
                                                          Ty.path "alloy_primitives::bytes_::Bytes";
                                                          Ty.apply
                                                            (Ty.path "core::ops::range::Range")
                                                            []
                                                            [ Ty.path "usize" ]
                                                        ]
                                                    ],
                                                  [
                                                    Ty.apply
                                                      (Ty.path "core::option::Option")
                                                      []
                                                      [ Ty.path "core::convert::Infallible" ]
                                                  ],
                                                  "from_residual",
                                                  []
                                                |),
                                                [ M.read (| residual |) ]
                                              |)
                                            |)
                                          |)
                                        |)
                                      |)));
                                  fun γ =>
                                    ltac:(M.monadic
                                      (let γ0_0 :=
                                        M.SubPointer.get_struct_tuple_field (|
                                          γ,
                                          "core::ops::control_flow::ControlFlow::Continue",
                                          0
                                        |) in
                                      let val := M.copy (| γ0_0 |) in
                                      val))
                                ]
                              |)
                            |) in
                          M.alloc (|
                            Value.StructTuple
                              "core::option::Option::Some"
                              [ Value.Tuple [ M.read (| input |); M.read (| ret_range |) ] ]
                          |)))
                    ]
                  |)
                |)))
            |)))
        | _, _, _ => M.impossible "wrong number of arguments"
        end.
      
      Axiom Function_get_memory_input_and_out_ranges :
        M.IsFunction
          "revm_interpreter::instructions::contract::call_helpers::get_memory_input_and_out_ranges"
          get_memory_input_and_out_ranges.
      
      (*
      pub fn resize_memory_and_return_range(
          interpreter: &mut Interpreter,
          offset: U256,
          len: U256,
      ) -> Option<Range<usize>> {
          let len = as_usize_or_fail_ret!(interpreter, len, None);
          let offset = if len != 0 {
              let offset = as_usize_or_fail_ret!(interpreter, offset, None);
              resize_memory!(interpreter, offset, len, None);
              offset
          } else {
              usize::MAX //unrealistic value so we are sure it is not used
          };
          Some(offset..offset + len)
      }
      *)
      Definition resize_memory_and_return_range
          (ε : list Value.t)
          (τ : list Ty.t)
          (α : list Value.t)
          : M :=
        match ε, τ, α with
        | [], [], [ interpreter; offset; len ] =>
          ltac:(M.monadic
            (let interpreter := M.alloc (| interpreter |) in
            let offset := M.alloc (| offset |) in
            let len := M.alloc (| len |) in
            M.catch_return (|
              ltac:(M.monadic
                (M.read (|
                  let~ len :=
                    M.copy (|
                      let~ x :=
                        M.alloc (|
                          M.call_closure (|
                            M.get_associated_function (|
                              Ty.apply
                                (Ty.path "ruint::Uint")
                                [
                                  Value.Integer IntegerKind.Usize 256;
                                  Value.Integer IntegerKind.Usize 4
                                ]
                                [],
                              "as_limbs",
                              []
                            |),
                            [ len ]
                          |)
                        |) in
                      let~ _ :=
                        M.match_operator (|
                          M.alloc (| Value.Tuple [] |),
                          [
                            fun γ =>
                              ltac:(M.monadic
                                (let γ :=
                                  M.use
                                    (M.alloc (|
                                      LogicalOp.or (|
                                        LogicalOp.or (|
                                          BinOp.ne (|
                                            M.read (|
                                              M.SubPointer.get_array_field (|
                                                M.read (| x |),
                                                M.alloc (| Value.Integer IntegerKind.Usize 1 |)
                                              |)
                                            |),
                                            Value.Integer IntegerKind.U64 0
                                          |),
                                          ltac:(M.monadic
                                            (BinOp.ne (|
                                              M.read (|
                                                M.SubPointer.get_array_field (|
                                                  M.read (| x |),
                                                  M.alloc (| Value.Integer IntegerKind.Usize 2 |)
                                                |)
                                              |),
                                              Value.Integer IntegerKind.U64 0
                                            |)))
                                        |),
                                        ltac:(M.monadic
                                          (BinOp.ne (|
                                            M.read (|
                                              M.SubPointer.get_array_field (|
                                                M.read (| x |),
                                                M.alloc (| Value.Integer IntegerKind.Usize 3 |)
                                              |)
                                            |),
                                            Value.Integer IntegerKind.U64 0
                                          |)))
                                      |)
                                    |)) in
                                let _ :=
                                  M.is_constant_or_break_match (|
                                    M.read (| γ |),
                                    Value.Bool true
                                  |) in
                                M.alloc (|
                                  M.never_to_any (|
                                    M.read (|
                                      let~ _ :=
                                        M.write (|
                                          M.SubPointer.get_struct_record_field (|
                                            M.read (| interpreter |),
                                            "revm_interpreter::interpreter::Interpreter",
                                            "instruction_result"
                                          |),
                                          Value.StructTuple
                                            "revm_interpreter::instruction_result::InstructionResult::InvalidOperandOOG"
                                            []
                                        |) in
                                      M.return_ (|
                                        Value.StructTuple "core::option::Option::None" []
                                      |)
                                    |)
                                  |)
                                |)));
                            fun γ => ltac:(M.monadic (M.alloc (| Value.Tuple [] |)))
                          ]
                        |) in
                      M.match_operator (|
                        M.alloc (|
                          M.call_closure (|
                            M.get_trait_method (|
                              "core::convert::TryFrom",
                              Ty.path "usize",
                              [ Ty.path "u64" ],
                              "try_from",
                              []
                            |),
                            [
                              M.read (|
                                M.SubPointer.get_array_field (|
                                  M.read (| x |),
                                  M.alloc (| Value.Integer IntegerKind.Usize 0 |)
                                |)
                              |)
                            ]
                          |)
                        |),
                        [
                          fun γ =>
                            ltac:(M.monadic
                              (let γ0_0 :=
                                M.SubPointer.get_struct_tuple_field (|
                                  γ,
                                  "core::result::Result::Ok",
                                  0
                                |) in
                              let val := M.copy (| γ0_0 |) in
                              val))
                        ]
                      |)
                    |) in
                  let~ offset :=
                    M.copy (|
                      M.match_operator (|
                        M.alloc (| Value.Tuple [] |),
                        [
                          fun γ =>
                            ltac:(M.monadic
                              (let γ :=
                                M.use
                                  (M.alloc (|
                                    BinOp.ne (|
                                      M.read (| len |),
                                      Value.Integer IntegerKind.Usize 0
                                    |)
                                  |)) in
                              let _ :=
                                M.is_constant_or_break_match (|
                                  M.read (| γ |),
                                  Value.Bool true
                                |) in
                              let~ offset :=
                                M.copy (|
                                  let~ x :=
                                    M.alloc (|
                                      M.call_closure (|
                                        M.get_associated_function (|
                                          Ty.apply
                                            (Ty.path "ruint::Uint")
                                            [
                                              Value.Integer IntegerKind.Usize 256;
                                              Value.Integer IntegerKind.Usize 4
                                            ]
                                            [],
                                          "as_limbs",
                                          []
                                        |),
                                        [ offset ]
                                      |)
                                    |) in
                                  let~ _ :=
                                    M.match_operator (|
                                      M.alloc (| Value.Tuple [] |),
                                      [
                                        fun γ =>
                                          ltac:(M.monadic
                                            (let γ :=
                                              M.use
                                                (M.alloc (|
                                                  LogicalOp.or (|
                                                    LogicalOp.or (|
                                                      BinOp.ne (|
                                                        M.read (|
                                                          M.SubPointer.get_array_field (|
                                                            M.read (| x |),
                                                            M.alloc (|
                                                              Value.Integer IntegerKind.Usize 1
                                                            |)
                                                          |)
                                                        |),
                                                        Value.Integer IntegerKind.U64 0
                                                      |),
                                                      ltac:(M.monadic
                                                        (BinOp.ne (|
                                                          M.read (|
                                                            M.SubPointer.get_array_field (|
                                                              M.read (| x |),
                                                              M.alloc (|
                                                                Value.Integer IntegerKind.Usize 2
                                                              |)
                                                            |)
                                                          |),
                                                          Value.Integer IntegerKind.U64 0
                                                        |)))
                                                    |),
                                                    ltac:(M.monadic
                                                      (BinOp.ne (|
                                                        M.read (|
                                                          M.SubPointer.get_array_field (|
                                                            M.read (| x |),
                                                            M.alloc (|
                                                              Value.Integer IntegerKind.Usize 3
                                                            |)
                                                          |)
                                                        |),
                                                        Value.Integer IntegerKind.U64 0
                                                      |)))
                                                  |)
                                                |)) in
                                            let _ :=
                                              M.is_constant_or_break_match (|
                                                M.read (| γ |),
                                                Value.Bool true
                                              |) in
                                            M.alloc (|
                                              M.never_to_any (|
                                                M.read (|
                                                  let~ _ :=
                                                    M.write (|
                                                      M.SubPointer.get_struct_record_field (|
                                                        M.read (| interpreter |),
                                                        "revm_interpreter::interpreter::Interpreter",
                                                        "instruction_result"
                                                      |),
                                                      Value.StructTuple
                                                        "revm_interpreter::instruction_result::InstructionResult::InvalidOperandOOG"
                                                        []
                                                    |) in
                                                  M.return_ (|
                                                    Value.StructTuple
                                                      "core::option::Option::None"
                                                      []
                                                  |)
                                                |)
                                              |)
                                            |)));
                                        fun γ => ltac:(M.monadic (M.alloc (| Value.Tuple [] |)))
                                      ]
                                    |) in
                                  M.match_operator (|
                                    M.alloc (|
                                      M.call_closure (|
                                        M.get_trait_method (|
                                          "core::convert::TryFrom",
                                          Ty.path "usize",
                                          [ Ty.path "u64" ],
                                          "try_from",
                                          []
                                        |),
                                        [
                                          M.read (|
                                            M.SubPointer.get_array_field (|
                                              M.read (| x |),
                                              M.alloc (| Value.Integer IntegerKind.Usize 0 |)
                                            |)
                                          |)
                                        ]
                                      |)
                                    |),
                                    [
                                      fun γ =>
                                        ltac:(M.monadic
                                          (let γ0_0 :=
                                            M.SubPointer.get_struct_tuple_field (|
                                              γ,
                                              "core::result::Result::Ok",
                                              0
                                            |) in
                                          let val := M.copy (| γ0_0 |) in
                                          val))
                                    ]
                                  |)
                                |) in
                              let~ new_size :=
                                M.alloc (|
                                  M.call_closure (|
                                    M.get_associated_function (|
                                      Ty.path "usize",
                                      "saturating_add",
                                      []
                                    |),
                                    [ M.read (| offset |); M.read (| len |) ]
                                  |)
                                |) in
                              let~ _ :=
                                M.match_operator (|
                                  M.alloc (| Value.Tuple [] |),
                                  [
                                    fun γ =>
                                      ltac:(M.monadic
                                        (let γ :=
                                          M.use
                                            (M.alloc (|
                                              BinOp.gt (|
                                                M.read (| new_size |),
                                                M.call_closure (|
                                                  M.get_associated_function (|
                                                    Ty.path
                                                      "revm_interpreter::interpreter::shared_memory::SharedMemory",
                                                    "len",
                                                    []
                                                  |),
                                                  [
                                                    M.SubPointer.get_struct_record_field (|
                                                      M.read (| interpreter |),
                                                      "revm_interpreter::interpreter::Interpreter",
                                                      "shared_memory"
                                                    |)
                                                  ]
                                                |)
                                              |)
                                            |)) in
                                        let _ :=
                                          M.is_constant_or_break_match (|
                                            M.read (| γ |),
                                            Value.Bool true
                                          |) in
                                        M.match_operator (|
                                          M.alloc (| Value.Tuple [] |),
                                          [
                                            fun γ =>
                                              ltac:(M.monadic
                                                (let γ :=
                                                  M.use
                                                    (M.alloc (|
                                                      UnOp.not (|
                                                        M.call_closure (|
                                                          M.get_function (|
                                                            "revm_interpreter::interpreter::resize_memory",
                                                            []
                                                          |),
                                                          [
                                                            M.SubPointer.get_struct_record_field (|
                                                              M.read (| interpreter |),
                                                              "revm_interpreter::interpreter::Interpreter",
                                                              "shared_memory"
                                                            |);
                                                            M.SubPointer.get_struct_record_field (|
                                                              M.read (| interpreter |),
                                                              "revm_interpreter::interpreter::Interpreter",
                                                              "gas"
                                                            |);
                                                            M.read (| new_size |)
                                                          ]
                                                        |)
                                                      |)
                                                    |)) in
                                                let _ :=
                                                  M.is_constant_or_break_match (|
                                                    M.read (| γ |),
                                                    Value.Bool true
                                                  |) in
                                                M.alloc (|
                                                  M.never_to_any (|
                                                    M.read (|
                                                      let~ _ :=
                                                        M.write (|
                                                          M.SubPointer.get_struct_record_field (|
                                                            M.read (| interpreter |),
                                                            "revm_interpreter::interpreter::Interpreter",
                                                            "instruction_result"
                                                          |),
                                                          Value.StructTuple
                                                            "revm_interpreter::instruction_result::InstructionResult::MemoryOOG"
                                                            []
                                                        |) in
                                                      M.return_ (|
                                                        Value.StructTuple
                                                          "core::option::Option::None"
                                                          []
                                                      |)
                                                    |)
                                                  |)
                                                |)));
                                            fun γ => ltac:(M.monadic (M.alloc (| Value.Tuple [] |)))
                                          ]
                                        |)));
                                    fun γ => ltac:(M.monadic (M.alloc (| Value.Tuple [] |)))
                                  ]
                                |) in
                              offset));
                          fun γ => ltac:(M.monadic (M.get_constant (| "core::num::MAX" |)))
                        ]
                      |)
                    |) in
                  M.alloc (|
                    Value.StructTuple
                      "core::option::Option::Some"
                      [
                        Value.StructRecord
                          "core::ops::range::Range"
                          [
                            ("start", M.read (| offset |));
                            ("end_", BinOp.Wrap.add (| M.read (| offset |), M.read (| len |) |))
                          ]
                      ]
                  |)
                |)))
            |)))
        | _, _, _ => M.impossible "wrong number of arguments"
        end.
      
      Axiom Function_resize_memory_and_return_range :
        M.IsFunction
          "revm_interpreter::instructions::contract::call_helpers::resize_memory_and_return_range"
          resize_memory_and_return_range.
      
      (*
      pub fn calc_call_gas<H: Host + ?Sized, SPEC: Spec>(
          interpreter: &mut Interpreter,
          is_cold: bool,
          has_transfer: bool,
          new_account_accounting: bool,
          local_gas_limit: u64,
      ) -> Option<u64> {
          let call_cost = gas::call_cost(SPEC::SPEC_ID, has_transfer, is_cold, new_account_accounting);
      
          gas!(interpreter, call_cost, None);
      
          // EIP-150: Gas cost changes for IO-heavy operations
          let gas_limit = if SPEC::enabled(TANGERINE) {
              let gas = interpreter.gas().remaining();
              // take l64 part of gas_limit
              min(gas - gas / 64, local_gas_limit)
          } else {
              local_gas_limit
          };
      
          Some(gas_limit)
      }
      *)
      Definition calc_call_gas (ε : list Value.t) (τ : list Ty.t) (α : list Value.t) : M :=
        match ε, τ, α with
        | [],
            [ H; SPEC ],
            [ interpreter; is_cold; has_transfer; new_account_accounting; local_gas_limit ] =>
          ltac:(M.monadic
            (let interpreter := M.alloc (| interpreter |) in
            let is_cold := M.alloc (| is_cold |) in
            let has_transfer := M.alloc (| has_transfer |) in
            let new_account_accounting := M.alloc (| new_account_accounting |) in
            let local_gas_limit := M.alloc (| local_gas_limit |) in
            M.catch_return (|
              ltac:(M.monadic
                (M.read (|
                  let~ call_cost :=
                    M.alloc (|
                      M.call_closure (|
                        M.get_function (| "revm_interpreter::gas::calc::call_cost", [] |),
                        [
                          M.read (|
                            M.get_constant (| "revm_primitives::specification::Spec::SPEC_ID" |)
                          |);
                          M.read (| has_transfer |);
                          M.read (| is_cold |);
                          M.read (| new_account_accounting |)
                        ]
                      |)
                    |) in
                  let~ _ :=
                    M.match_operator (|
                      M.alloc (| Value.Tuple [] |),
                      [
                        fun γ =>
                          ltac:(M.monadic
                            (let γ :=
                              M.use
                                (M.alloc (|
                                  UnOp.not (|
                                    M.call_closure (|
                                      M.get_associated_function (|
                                        Ty.path "revm_interpreter::gas::Gas",
                                        "record_cost",
                                        []
                                      |),
                                      [
                                        M.SubPointer.get_struct_record_field (|
                                          M.read (| interpreter |),
                                          "revm_interpreter::interpreter::Interpreter",
                                          "gas"
                                        |);
                                        M.read (| call_cost |)
                                      ]
                                    |)
                                  |)
                                |)) in
                            let _ :=
                              M.is_constant_or_break_match (| M.read (| γ |), Value.Bool true |) in
                            M.alloc (|
                              M.never_to_any (|
                                M.read (|
                                  let~ _ :=
                                    M.write (|
                                      M.SubPointer.get_struct_record_field (|
                                        M.read (| interpreter |),
                                        "revm_interpreter::interpreter::Interpreter",
                                        "instruction_result"
                                      |),
                                      Value.StructTuple
                                        "revm_interpreter::instruction_result::InstructionResult::OutOfGas"
                                        []
                                    |) in
                                  M.return_ (| Value.StructTuple "core::option::Option::None" [] |)
                                |)
                              |)
                            |)));
                        fun γ => ltac:(M.monadic (M.alloc (| Value.Tuple [] |)))
                      ]
                    |) in
                  let~ gas_limit :=
                    M.copy (|
                      M.match_operator (|
                        M.alloc (| Value.Tuple [] |),
                        [
                          fun γ =>
                            ltac:(M.monadic
                              (let γ :=
                                M.use
                                  (M.alloc (|
                                    M.call_closure (|
                                      M.get_trait_method (|
                                        "revm_primitives::specification::Spec",
                                        SPEC,
                                        [],
                                        "enabled",
                                        []
                                      |),
                                      [
                                        Value.StructTuple
                                          "revm_primitives::specification::SpecId::TANGERINE"
                                          []
                                      ]
                                    |)
                                  |)) in
                              let _ :=
                                M.is_constant_or_break_match (|
                                  M.read (| γ |),
                                  Value.Bool true
                                |) in
                              let~ gas :=
                                M.alloc (|
                                  M.call_closure (|
                                    M.get_associated_function (|
                                      Ty.path "revm_interpreter::gas::Gas",
                                      "remaining",
                                      []
                                    |),
                                    [
                                      M.call_closure (|
                                        M.get_associated_function (|
                                          Ty.path "revm_interpreter::interpreter::Interpreter",
                                          "gas",
                                          []
                                        |),
                                        [ M.read (| interpreter |) ]
                                      |)
                                    ]
                                  |)
                                |) in
                              M.alloc (|
                                M.call_closure (|
                                  M.get_function (| "core::cmp::min", [ Ty.path "u64" ] |),
                                  [
                                    BinOp.Wrap.sub (|
                                      M.read (| gas |),
                                      BinOp.Wrap.div (|
                                        M.read (| gas |),
                                        Value.Integer IntegerKind.U64 64
                                      |)
                                    |);
                                    M.read (| local_gas_limit |)
                                  ]
                                |)
                              |)));
                          fun γ => ltac:(M.monadic local_gas_limit)
                        ]
                      |)
                    |) in
                  M.alloc (|
                    Value.StructTuple "core::option::Option::Some" [ M.read (| gas_limit |) ]
                  |)
                |)))
            |)))
        | _, _, _ => M.impossible "wrong number of arguments"
        end.
      
      Axiom Function_calc_call_gas :
        M.IsFunction
          "revm_interpreter::instructions::contract::call_helpers::calc_call_gas"
          calc_call_gas.
    End call_helpers.
  End contract.
End instructions.
