diff --git a/gitlab-pages/docs/advanced/interop.md b/gitlab-pages/docs/advanced/interop.md
new file mode 100644
index 000000000..736efc8f8
--- /dev/null
+++ b/gitlab-pages/docs/advanced/interop.md
@@ -0,0 +1,730 @@
+---
+id: interop
+title: Interop
+---
+
+import Syntax from '@theme/Syntax';
+
+LIGO can work together with other smart contract languages on Tezos. However
+data structures might have different representations in Michelson and not
+correctly match the standard LIGO types.
+
+## Michelson types and annotations
+Michelson types consist of `or`'s and `pair`'s, combined with field annotations.
+Field annotations add contraints on a Michelson type, for example a pair of
+`(pair (int %foo) (string %bar))` will only work with the exact equivalence or
+the same type without the field annotations.
+
+To clarify:
+
+```michelson
+(pair (int %foo) (string %bar))
+````
+
+works with
+
+```michelson
+(pair (int %foo) (string %bar))
+```
+
+works with
+
+```michelson
+(pair int string)
+```
+
+works not with
+
+```michelson
+(pair (int %bar) (string %foo))
+```
+
+works not with
+
+```michelson
+(pair (string %bar) (int %foo))
+```
+
+:::info
+In the case of annotated entrypoints - the annotated `or` tree directly under
+`parameter` in a contract - you should annotations, as otherwise it would
+become unclear which entrypoint you are referring to.
+:::
+
+## Entrypoints and annotations
+It's possible for a contract to have multiple entrypoints, which translates in
+LIGO to a `parameter` with a variant type as shown here:
+
+
+
+```pascaligo
+type storage is int
+
+type parameter is
+ | Left of int
+ | Right of int
+
+function main (const p: parameter; const x: storage): (list(operation) * storage) is
+ ((nil: list(operation)), case p of
+ | Left(i) -> x - i
+ | Right(i) -> x + i
+ end)
+```
+
+
+
+
+```cameligo
+type storage = int
+
+type parameter =
+ | Left of int
+ | Right of int
+
+let main ((p, x): (parameter * storage)): (operation list * storage) =
+ (([]: operation list), (match p with
+ | Left i -> x - i
+ | Right i -> x + i
+ ))
+
+```
+
+
+
+
+```reasonligo
+type storage = int
+
+type parameter =
+ | Left(int)
+ | Right(int)
+
+let main = ((p, x): (parameter, storage)): (list(operation), storage) => {
+ ([]: list(operation), (switch(p) {
+ | Left(i) => x - i
+ | Right(i) => x + i
+ }))
+};
+
+```
+
+
+
+This contract can be called by another contract, like this one:
+
+
+
+
+```pascaligo group=get_entrypoint_opt
+type storage is int
+
+type parameter is int
+
+type x is Left of int
+
+function main (const p: parameter; const s: storage): (list(operation) * storage) is block {
+ const contract: contract(x) =
+ case (Tezos.get_entrypoint_opt("%left", ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx":address)): option(contract(x))) of
+ | Some (c) -> c
+ | None -> (failwith("not a correct contract") : contract(x))
+ end;
+
+ const result: (list(operation) * storage) = ((list [Tezos.transaction(Left(2), 2mutez, contract)]: list(operation)), s)
+} with result
+```
+
+
+
+
+
+
+```cameligo group=get_entrypoint_opt
+type storage = int
+
+type parameter = int
+
+type x = Left of int
+
+let main (p, s: parameter * storage): operation list * storage = (
+ let contract: x contract =
+ match ((Tezos.get_entrypoint_opt "%left" ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address)): x contract option) with
+ | Some c -> c
+ | None -> (failwith "contract does not match": x contract)
+ in
+ (([
+ Tezos.transaction (Left 2) 2mutez contract;
+ ]: operation list), s)
+)
+```
+
+
+
+
+
+```reasonligo group=get_entrypoint_opt
+type storage = int;
+
+type parameter = int;
+
+type x = Left(int);
+
+let main = ((p, s): (parameter, storage)): (list(operation), storage) => {
+ let contract: contract(x) =
+ switch (Tezos.get_entrypoint_opt("%left", ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address)): option(contract(x))) {
+ | Some c => c
+ | None => (failwith ("contract does not match"): contract(x))
+ };
+ ([
+ Tezos.transaction(Left(2), 2mutez, contract)
+ ]: list(operation), s);
+};
+```
+
+
+
+Notice how we directly use the `%left` entrypoint without mentioning the
+`%right` entrypoint. This is done with the help of annotations. Without
+annotations it wouldn't be clear what our `int` would be referring to.
+
+This currently only works for `or`'s or variant types in LIGO.
+
+## Interop with Michelson
+To interop with existing Michelson code or for compatibility with certain
+development tooling, LIGO has two special interop types: `michelson_or` and
+`michelson_pair`. These types give the flexibility to model the exact Michelson
+output, including field annotations.
+
+Take for example the following Michelson type that we want to interop with:
+
+```michelson
+(or
+ (unit %z)
+ (or %other
+ (unit %y)
+ (pair %other
+ (string %x)
+ (pair %other
+ (int %w)
+ (nat %v)))))
+```
+
+To reproduce this type we can use the following LIGO code:
+
+
+
+```pascaligo
+type w_and_v is michelson_pair(int, "w", nat, "v")
+type x_and is michelson_pair(string, "x", w_and_v, "other")
+type y_or is michelson_or(unit, "y", x_and, "other")
+type z_or is michelson_or(unit, "z", y_or, "other")
+```
+
+
+
+
+```cameligo
+type w_and_v = (int, "w", nat, "v") michelson_pair
+type x_and = (string, "x", w_and_v, "other") michelson_pair
+type y_or = (unit, "y", x_and, "other") michelson_or
+type z_or = (unit, "z", y_or, "other") michelson_or
+```
+
+
+
+
+```reasonligo
+type w_and_v = michelson_pair(int, "w", nat, "v")
+type x_and = michelson_pair(string, "x", w_and_v, "other")
+type y_or = michelson_or(unit, "y", x_and, "other")
+type z_or = michelson_or(unit, "z", y_or, "other")
+```
+
+
+
+If you don't want to have an annotation, you need to provide an empty string.
+
+:::info
+Alternatively, if annotations are not important you can also use plain tuples
+for pair's instead. Plain tuples don't have any annotations.
+:::
+
+To use variables of type `michelson_or` you have to use `M_left` and `M_right`.
+`M_left` picks the left `or` case while `M_right` picks the right `or` case.
+For `michelson_pair` you need to use tuples.
+
+
+
+```pascaligo
+const z: z_or = (M_left (unit) : z_or);
+
+const y_1: y_or = (M_left (unit): y_or);
+const y: z_or = (M_right (y_1) : z_or);
+
+const x_pair: x_and = ("foo", (2, 3n));
+const x_1: y_or = (M_right (x_pair): y_or);
+const x: z_or = (M_right (y_1) : z_or);
+```
+
+
+
+
+```cameligo
+let z: z_or = (M_left (unit) : z_or)
+
+let y_1: y_or = (M_left (unit): y_or)
+let y: z_or = (M_right (y_1) : z_or)
+
+let x_pair: x_and = ("foo", (2, 3n))
+let x_1: y_or = (M_right (x_pair): y_or)
+let x: z_or = (M_right (y_1) : z_or)
+```
+
+
+
+
+```reasonligo
+let z: z_or = (M_left (unit) : z_or)
+
+let y_1: y_or = (M_left (unit): y_or)
+let y: z_or = (M_right (y_1) : z_or)
+
+let x_pair: x_and = ("foo", (2, 3n))
+let x_1: y_or = (M_right (x_pair): y_or)
+let x: z_or = (M_right (y_1) : z_or)
+```
+
+
+
+## Helper functions
+Converting between different LIGO types and data structures can happen in two
+ways. The first way is to use the provided layout conversion functions, and the
+second way is to handle the layout conversion manually.
+
+:::info
+In both cases it will increase the size of the smart contract and the
+conversion will happen when running the smart contract.
+:::
+
+### Converting left combed Michelson data structures
+Here's an example of a left combed Michelson data structure using pairs:
+
+```michelson
+ (pair %other
+ (pair %other
+ (string %s)
+ (int %w)
+ )
+ (nat %v)
+ )
+```
+
+Which could respond with the following record type:
+
+
+
+```pascaligo
+type l_record is record [
+ s: string;
+ w: int;
+ v: nat
+]
+```
+
+
+
+
+```cameligo
+type l_record = {
+ s: string;
+ w: int;
+ v: nat
+}
+```
+
+
+
+
+```reasonligo
+type l_record = {
+ s: string,
+ w: int,
+ v: nat
+}
+```
+
+
+
+If we want to convert from the Michelson type to our record type and vice
+versa, we can use the following code:
+
+
+
+```pascaligo
+type michelson is michelson_pair_left_comb(l_record)
+
+function of_michelson (const f: michelson) : l_record is
+ block {
+ const p: l_record = Layout.convert_from_left_comb(f)
+ }
+ with p
+
+function to_michelson (const f: l_record) : michelson is
+ block {
+ const p: michelson = Layout.convert_to_left_comb ((f: l_record))
+ }
+ with p
+```
+
+
+
+
+```cameligo
+type michelson = l_record michelson_pair_left_comb
+
+let of_michelson (f: michelson) : l_record =
+ let p: l_record = Layout.convert_from_left_comb f in
+ p
+
+let to_michelson (f: l_record) : michelson =
+ let p = Layout.convert_to_left_comb (f: l_record) in
+ p
+```
+
+
+
+
+```reasonligo
+type michelson = michelson_pair_left_comb(l_record);
+
+let of_michelson = (f: michelson) : l_record => {
+ let p: l_record = Layout.convert_from_left_comb(f);
+ p
+};
+
+let to_michelson = (f: l_record) : michelson => {
+ let p = Layout.convert_to_left_comb(f: l_record);
+ p
+}
+
+```
+
+
+
+In the case of a left combed Michelson `or` data structure, that you want to
+translate to a variant, you can use the `michelson_or_left_comb` type.
+
+For example:
+
+
+
+```pascaligo
+type vari is
+| Foo of int
+| Bar of nat
+| Other of bool
+
+type r is michelson_or_left_comb(vari)
+```
+
+
+
+
+```cameligo
+type vari =
+| Foo of int
+| Bar of nat
+| Other of bool
+
+type r = vari michelson_or_left_comb
+```
+
+
+
+
+```reasonligo
+type vari =
+| Foo(int)
+| Bar(nat)
+| Other(bool)
+
+type r = michelson_or_left_comb(vari)
+```
+
+
+
+And then use these types in `Layout.convert_from_left_comb` or
+`Layout.convert_to_left_comb`, similar to the `pair`s example above, like this:
+
+
+
+```pascaligo
+function of_michelson_or (const f: r) : vari is
+ block {
+ const p: vari = Layout.convert_from_left_comb(f)
+ }
+ with p
+
+function to_michelson_or (const f: vari) : r is
+ block {
+ const p: r = Layout.convert_to_left_comb((f: vari))
+ }
+ with p
+```
+
+
+
+
+```cameligo
+let of_michelson_or (f: r) : vari =
+ let p: vari = Layout.convert_from_left_comb f in
+ p
+
+let to_michelson_or (f: vari) : r =
+ let p = Layout.convert_to_left_comb (f: vari) in
+ p
+```
+
+
+
+
+```reasonligo
+let of_michelson_or = (f: r) : vari => {
+ let p: vari = Layout.convert_from_left_comb(f);
+ p
+};
+
+let to_michelson_or = (f: vari) : r => {
+ let p = Layout.convert_to_left_comb(f: vari);
+ p
+}
+
+```
+
+
+
+### Converting right combed Michelson data structures
+
+In the case of right combed data structures, like:
+
+```michelson
+ (pair %other
+ (string %s)
+ (pair %other
+ (int %w)
+ (nat %v)
+ )
+ )
+```
+
+you can almost use the same code as that for the left combed data structures,
+but with `michelson_or_right_comb`, `michelson_pair_right_comb`,
+`Layout.convert_from_right_comb`, and `Layout.convert_to_left_comb`
+respectively.
+
+### Manual data structure conversion
+If you want to get your hands dirty, it's also possible to do manual data
+structure conversion.
+
+The following code can be used as inspiration:
+
+
+
+```pascaligo group=helper_functions
+type z_to_v is
+| Z
+| Y
+| X
+| W
+| V
+
+type w_or_v is michelson_or(unit, "w", unit, "v")
+type x_or is michelson_or(unit, "x", w_or_v, "other")
+type y_or is michelson_or(unit, "y", x_or, "other")
+type z_or is michelson_or(unit, "z", y_or, "other")
+
+type test is record [
+ z: string;
+ y: int;
+ x: string;
+ w: bool;
+ v: int;
+]
+
+function make_concrete_sum (const r: z_to_v) : z_or is block {
+ const z: z_or = (M_left (unit) : z_or);
+
+ const y_1: y_or = (M_left (unit): y_or);
+ const y: z_or = (M_right (y_1) : z_or);
+
+ const x_2: x_or = (M_left (unit): x_or);
+ const x_1: y_or = (M_right (x_2): y_or);
+ const x: z_or = (M_right (x_1) : z_or);
+
+ const w_3: w_or_v = (M_left (unit): w_or_v);
+ const w_2: x_or = (M_right (w_3): x_or);
+ const w_1: y_or = (M_right (w_2): y_or);
+ const w: z_or = (M_right (w_1) : z_or);
+
+ const v_3: w_or_v = (M_right (unit): w_or_v);
+ const v_2: x_or = (M_right (v_3): x_or);
+ const v_1: y_or = (M_right (v_2): y_or);
+ const v: z_or = (M_right (v_1) : z_or);
+}
+ with (case r of
+ | Z -> z
+ | Y -> y
+ | X -> x
+ | W -> w
+ | V -> v
+ end)
+
+
+function make_concrete_record (const r: test) : (string * int * string * bool * int) is
+ (r.z, r.y, r.x, r.w, r.v)
+
+function make_abstract_sum (const z_or: z_or) : z_to_v is
+ (case z_or of
+ | M_left (n) -> Z
+ | M_right (y_or) ->
+ (case y_or of
+ | M_left (n) -> Y
+ | M_right (x_or) ->
+ (case x_or of
+ | M_left (n) -> X
+ | M_right (w_or) ->
+ (case (w_or) of
+ | M_left (n) -> W
+ | M_right (n) -> V
+ end)
+ end)
+ end)
+ end)
+
+function make_abstract_record (const z: string; const y: int; const x: string; const w: bool; const v: int) : test is
+ record [ z = z; y = y; x = x; w = w; v = v ]
+
+```
+
+
+
+
+
+
+```cameligo group=helper_functions
+type z_to_v =
+| Z
+| Y
+| X
+| W
+| V
+
+type w_or_v = (unit, "w", unit, "v") michelson_or
+type x_or = (unit, "x", w_or_v, "other") michelson_or
+type y_or = (unit, "y", x_or, "other") michelson_or
+type z_or = (unit, "z", y_or, "other") michelson_or
+
+type test = {
+ z: string;
+ y: int;
+ x: string;
+ w: bool;
+ v: int;
+}
+
+let make_concrete_sum (r: z_to_v) : z_or =
+ match r with
+ | Z -> (M_left (unit) : z_or)
+ | Y -> (M_right (M_left (unit): y_or) : z_or )
+ | X -> (M_right (M_right (M_left (unit): x_or): y_or) : z_or )
+ | W -> (M_right (M_right (M_right (M_left (unit): w_or_v): x_or): y_or) : z_or )
+ | V -> (M_right (M_right (M_right (M_right (unit): w_or_v): x_or): y_or) : z_or )
+
+let make_concrete_record (r: test) : (string * int * string * bool * int) =
+ (r.z, r.y, r.x, r.w, r.v)
+
+let make_abstract_sum (z_or: z_or) : z_to_v =
+ match z_or with
+ | M_left n -> Z
+ | M_right y_or ->
+ (match y_or with
+ | M_left n -> Y
+ | M_right x_or -> (
+ match x_or with
+ | M_left n -> X
+ | M_right w_or -> (
+ match w_or with
+ | M_left n -> W
+ | M_right n -> V)))
+
+
+let make_abstract_record (z: string) (y: int) (x: string) (w: bool) (v: int) : test =
+ { z = z; y = y; x = x; w = w; v = v }
+
+```
+
+
+
+
+
+```reasonligo group=helper_functions
+type z_to_v =
+| Z
+| Y
+| X
+| W
+| V
+
+type w_or_v = michelson_or(unit, "w", unit, "v")
+type x_or = michelson_or(unit, "x", w_or_v, "other")
+type y_or = michelson_or(unit, "y", x_or, "other")
+type z_or = michelson_or(unit, "z", y_or, "other")
+
+type test = {
+ z: string,
+ y: int,
+ x: string,
+ w: bool,
+ v: int
+}
+
+let make_concrete_sum = (r: z_to_v) : z_or =>
+ switch(r){
+ | Z => (M_left (unit) : z_or)
+ | Y => (M_right (M_left (unit): y_or) : z_or )
+ | X => (M_right (M_right (M_left (unit): x_or): y_or) : z_or )
+ | W => (M_right (M_right (M_right (M_left (unit): w_or_v): x_or): y_or) : z_or )
+ | V => (M_right (M_right (M_right (M_right (unit): w_or_v): x_or): y_or) : z_or )
+ }
+
+let make_concrete_record = (r: test) : (string, int, string, bool, int) =>
+ (r.z, r.y, r.x, r.w, r.v)
+
+let make_abstract_sum = (z_or: z_or) : z_to_v =>
+ switch (z_or) {
+ | M_left n => Z
+ | M_right y_or => (
+ switch (y_or) {
+ | M_left n => Y
+ | M_right x_or => (
+ switch (x_or) {
+ | M_left n => X
+ | M_right w_or => (
+ switch (w_or) {
+ | M_left n => W
+ | M_right n => V
+ })
+ })
+ })
+ }
+
+
+let make_abstract_record = (z: string, y: int, x: string, w: bool, v: int) : test =>
+ { z : z, y, x, w, v }
+
+```
+
+
+
+## Amendment
+With the upcoming 007 amendment to Tezos this will change though, and also
+`pair`'s can be ordered differently.
\ No newline at end of file
diff --git a/gitlab-pages/website/sidebars.json b/gitlab-pages/website/sidebars.json
index 2d32e898b..7aef10a0e 100644
--- a/gitlab-pages/website/sidebars.json
+++ b/gitlab-pages/website/sidebars.json
@@ -19,8 +19,9 @@
"advanced/entrypoints-contracts",
"advanced/include",
"advanced/first-contract",
- "advanced/michelson-and-ligo",
- "advanced/inline"
+ "advanced/michelson-and-ligo",
+ "advanced/inline",
+ "advanced/interop"
],
"Reference": [
"api/cli-commands",
diff --git a/src/test/md_file_tests.ml b/src/test/md_file_tests.ml
index 3ceb8c3a6..57ad2d8b2 100644
--- a/src/test/md_file_tests.ml
+++ b/src/test/md_file_tests.ml
@@ -123,6 +123,7 @@ let md_files = [
"/gitlab-pages/docs/advanced/entrypoints-contracts.md";
"/gitlab-pages/docs/advanced/timestamps-addresses.md";
"/gitlab-pages/docs/advanced/inline.md";
+ "/gitlab-pages/docs/advanced/interop.md";
"/gitlab-pages/docs/api/cli-commands.md";
"/gitlab-pages/docs/api/cheat-sheet.md";
"/gitlab-pages/docs/reference/toplevel.md";