> ## Documentation Index
> Fetch the complete documentation index at: https://docs.li.fi/llms.txt
> Use this file to discover all available pages before exploring further.

# References

> The three ref scopes the compiler understands, the reserved prefixes, and how SDK handles become refs.

> Now that you know what's being passed (resources, handles), this page covers the dotpath grammar that wires them together.

A **ref** is a dotpath string wrapped in `{ "$ref": "…" }`. Refs let a `Call` bind one of its input ports to a value produced elsewhere in the Flow: a declared input, a previous call's output, or a runtime context value.

The grammar recognises **three** scopes and reserves a handful of prefixes to avoid ambiguity.

## The three ref scopes

### 1. `input.<name>`

References a flow-level input declared in `flow.inputs`.

```json theme={"system"}
{ "$ref": "input.amountIn" }
```

Parses to `{ scope: "input", port: "amountIn" }`.

### 2. `context.<key>`

References a runtime context value. Only two keys are currently recognised:

| Key                | Meaning                                                             |
| ------------------ | ------------------------------------------------------------------- |
| `sender`           | The transaction signer's `address`.                                 |
| `executionAddress` | The predicted execution proxy address where the compiled flow runs. |

```json theme={"system"}
{ "$ref": "context.sender" }
```

Parses to `{ scope: "context", key: "sender" }`. Any other key under `context.*` is rejected.

### 3. `<nodeId>.<port>`

Any ref whose prefix is *not* `input` or `context` is treated as a reference to another call's output port. The `<nodeId>` is the **user-defined id** you passed when you added the node (e.g. `builder.lifi.swap('swap', …)` produces refs of the form `swap.<port>`).

```json theme={"system"}
{ "$ref": "swap.amountOut" }
```

Parses to `{ scope: "output", node: "swap", port: "amountOut" }`.

## Reserved prefixes

Three prefixes are reserved and cannot be used as node ids: `input`, `context`, and `literal`. Flow validation rejects a node whose `id` matches any of them.

`literal` is **not** a ref scope; it is reserved to keep the grammar unambiguous. Literal *values* are expressed through a separate mechanism, a `LiteralBinding`, which lives alongside refs in a node's `bind` record:

```json theme={"system"}
{
  "bind": {
    "amount": { "kind": "uint256", "value": "1000000000000000000" }
  }
}
```

## How SDK handles become refs

Partner code usually does not construct refs directly. The SDK gives you **handles** (typed JavaScript values returned by the builder), and converts them to refs when it serialises calls.

Handles come in three flavours:

* **`InputHandle`.** Returned by `builder.inputs.<name>`. Serialises to `input.<name>`.
* **`ResourceInputHandle`.** A subtype of `InputHandle` for resource inputs, carrying the resource declaration.
* **`OutputHandle`.** Returned by an op call. `builder.lifi.swap('swap', …).amountOut` serialises to `swap.amountOut` (where `swap` is the user-defined node id you passed as the first argument).

The conversion is automatic. You pass handles into `bind` and the SDK produces the right `$ref` string. Context refs are exposed through `builder.context`:

* `builder.context.sender` → `{ $ref: "context.sender" }`
* `builder.context.executionAddress` → `{ $ref: "context.executionAddress" }`

## Raw refs (escape hatch)

When you need to reference an output of a call you created through `builder.untypedOp(...)`, or a path the typed API does not cover, use `raw.ref<T>(path)` to get a typed `TypedRef` accepted by a `Bindable<T>` slot:

```ts theme={"system"}
import { raw } from '@lifi/composer-sdk';

builder.untypedOp('custom', 'some.op', {
  bind: { x: { $ref: 'input.token' } },
  config: {},
});

builder.core.asResource('wrapped', {
  bind: { handle: raw.ref<'uint256'>('custom.result') },
  config: { resource: /* ... */ },
});
```

`raw.ref` does no runtime validation; the caller is responsible for choosing the right type parameter.

## Summary

* Three scopes exist: `input.<name>`, `context.<sender|executionAddress>`, `<nodeId>.<port>`.
* `<name>` and `<nodeId>` are user-defined: you pick them when you author the flow.
* `literal` is a *reserved prefix*, not a ref scope. Literal values use `LiteralBinding`, not a ref.
* SDK handles convert to refs automatically. You almost never write ref strings by hand.
* Use `raw.ref<T>(path)` only when the typed API cannot express the ref you need.

> Once a Flow is wired, you POST it to `/compose`. The next page, [Execution Model](/composer/composer-api/concepts/execution-model), covers the pipeline.
