# How to Use External Contract Calls in Sway: ABI and Proxy Patterns Explained

> Master external contract calls in Sway using ABI and proxy patterns. Explore typed calls and run_external for efficient bytecode execution and interaction with Fuel smart contracts.

- Repository: [Fuel Labs/sway](https://github.com/FuelLabs/sway)
- Tags: tutorial
- Published: 2026-03-04

---

**External contract calls in Sway are implemented through ABI-based typed calls for standard interactions or `run_external` for proxy patterns that execute external bytecode within the caller's storage context.**

Sway, the smart contract language for the Fuel blockchain, provides two distinct mechanisms for external contract calls. According to the FuelLabs/sway source code, developers can use ABI-based calls for type-safe cross-contract communication or `run_external` for upgradeable proxies that require shared storage contexts.

## ABI-Based External Contract Calls

The standard method for external contract calls in Sway uses Application Binary Interface (ABI) definitions. This approach, documented in [`docs/book/src/blockchain-development/calling_contracts.md`](https://github.com/FuelLabs/sway/blob/main/docs/book/src/blockchain-development/calling_contracts.md), provides compile-time type safety and generates Fuel VM `CALL` instructions with isolated storage contexts.

### Setting Up Contract Dependencies

To call an external contract, first declare it as a dependency in your [`Forc.toml`](https://github.com/FuelLabs/sway/blob/main/Forc.toml):

```toml
[contract-dependencies]
contract_a = { path = "../contract_a" }

```

When you build with `forc`, it automatically generates the ABI trait from the dependency's interface.

### Implementing the Call

Import the generated ABI and create an instance using the target `ContractId`:

```sway
use contract_a::ContractA;

const CONTRACT_ID = 0x79fa8779bed2f36c3581d01c79df8da45eee09fac1fd76a5a656e16326317ef0;

fn make_call() {
    let target = abi(ContractA, CONTRACT_ID);
    let result = target.receive(true, 3);
}

```

The compiler translates `target.receive()` into a Fuel VM `CALL` instruction that forwards gas and assets while isolating the callee's storage context. The call respects the **Checks-Effects-Interactions (CEI)** pattern, with compiler warnings for storage writes following external calls.

## Using run_external for Proxy and Upgradeable Contracts

For scenarios requiring shared storage contexts, such as upgradeable proxies, Sway provides `run_external` in `sway-lib-std/src/execution.sw`.

### How run_external Works

Unlike ABI calls, `run_external` loads the target contract's bytecode and executes it within the caller's storage context. The function signature in the standard library shows it never returns (`!`), effectively replacing the current execution context:

```sway
pub fn run_external(target: ContractId) -> !;

```

This mirrors low-level `jmp_mem` semantics and enables proxy patterns where the implementation contract manipulates the proxy's storage directly.

### Upgradeable Proxy Example

The `examples/upgradeable_proxy/proxy/src/main.sw` demonstrates a complete implementation:

```sway
contract;

use std::execution::run_external;

abi Proxy {
    #[storage(write)]
    fn set_target_contract(id: ContractId);
    #[storage(read)]
    fn double_input(_value: u64) -> u64;
}

#[namespace(my_storage_namespace)]
storage {
    target_contract: Option<ContractId> = None,
}

impl Proxy for Contract {
    #[storage(write)]
    fn set_target_contract(id: ContractId) {
        storage.target_contract.write(Some(id));
    }

    #[storage(read)]
    fn double_input(_value: u64) -> u64 {
        let target = storage.target_contract.read().unwrap();
        run_external(target)
    }
}

```

The corresponding implementation in `examples/upgradeable_proxy/implementation/src/main.sw` writes to the proxy's storage:

```sway
contract;

abi Implementation {
    #[storage(write)]
    fn double_input(value: u64) -> u64;
}

storage {
    value: u64 = 0,
}

impl Implementation for Contract {
    #[storage(write)]
    fn double_input(value: u64) -> u64 {
        let new_value = value * 2;
        storage.value.write(new_value);
        new_value
    }
}

```

When the proxy's `double_input` is called, `run_external` transfers execution to the implementation contract, which doubles the input and writes the result into the proxy's `value` field.

## Testing External Contract Calls

Unit tests in Sway can invoke external contracts by declaring them as dependencies. The test harness automatically injects a `CONTRACT_ID` constant:

```sway
#[test]
fn test_external_call() {
    let external = abi(ExternalContract, CONTRACT_ID);
    let result = external.do_something {}();
    assert(result);
}

```

This pattern is documented in [`docs/book/src/testing/unit-testing.md`](https://github.com/FuelLabs/sway/blob/main/docs/book/src/testing/unit-testing.md).

## Summary

- **ABI-based calls** provide type-safe external contract calls in Sway using generated traits and the `abi()` constructor, compiling to Fuel VM `CALL` instructions with isolated storage contexts.
- **`run_external`** enables proxy and upgradeable patterns by loading external bytecode into the caller's storage context, implemented in `sway-lib-std/src/execution.sw`.
- Both methods support the **Checks-Effects-Interactions (CEI)** pattern, with compiler warnings for storage writes following external calls.
- **Unit tests** can invoke external contracts using the `CONTRACT_ID` constant injected by the test harness.

## Frequently Asked Questions

### What is the difference between ABI calls and run_external in Sway?

ABI calls require the external contract's interface definition and create an isolated execution context where the callee's storage is separate from the caller's. In contrast, `run_external` loads the target contract's bytecode and executes it within the caller's storage context, making it suitable for proxy patterns where the implementation must manipulate the proxy's state directly.

### How do I handle storage when using run_external for upgradeable contracts?

When using `run_external`, the target contract operates on the proxy's storage context rather than its own. You should namespace your storage in the proxy using the `#[namespace(...)]` attribute to avoid collisions, and ensure the implementation contract's storage layout remains compatible across upgrades since it will be writing directly to the proxy's storage slots.

### Can I call external contracts from unit tests in Sway?

Yes, unit tests can call external contracts by adding them as `contract-dependencies` in your [`Forc.toml`](https://github.com/FuelLabs/sway/blob/main/Forc.toml). The test harness automatically injects a `CONTRACT_ID` constant that you can use with the `abi()` constructor to create a typed interface to the external contract within your test functions.

### What file contains the run_external implementation in the Sway standard library?

The `run_external` function is implemented in `sway-lib-std/src/execution.sw` within the FuelLabs/sway repository. This file contains the low-level function definition that loads external contract bytecode and transfers execution context without returning.