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

# It's gonna be Legen... wait for it...

> dary! Legendary! NEAR protocol is getting updated with the ability to yield and resume computations

***Guille** · May 30, 2024*

*dary! Legendary! NEAR protocol is getting updated with the ability to yield and resume computations*

<img src="https://mintcdn.com/neardocs/RuYMAM7eln2T5AA7/assets/blog/legendary.jpg?fit=max&auto=format&n=RuYMAM7eln2T5AA7&q=85&s=3081f77f82b67bc2e9e62aef99e128c6" alt="waiting on a loop" width="798" height="347" data-path="assets/blog/legendary.jpg" />

<Tip>
  We now have an [example of how to use `yield` and `resume`](https://github.com/near-examples/yield-resume) in your contracts. Check it out!

  There is also a new documentation page on [Yield and Resume](/smart-contracts/anatomy/yield-resume) that explains how to use this feature
</Tip>

## The problem of waiting

Currently, smart contracts have no way to wait for an external event to happen. This can be a problem when the contract relies on an external service to provide a result.

We encountered this issue while implementing [Chain Signatures](/chain-abstraction/chain-signatures), which work by requiring an external service to provide a signature.

Until now, the only workaround has been to make the contract call itself in a loop, checking on each iteration if the result is ready. Each call delays the result by one block (\~1 second), allowing the contract to wait almost a minute before running out of gas.

<img src="https://mintcdn.com/neardocs/RuYMAM7eln2T5AA7/assets/blog/contract-wait-loop.png?fit=max&auto=format&n=RuYMAM7eln2T5AA7&q=85&s=f1d081876c12063519ed86d8153f7da6" alt="waiting on a loop" width="1346" height="842" data-path="assets/blog/contract-wait-loop.png" />

*Until now, contracts had to wait by calling themselves until a external service replies... more often than not the contract will run out of gas waiting*

While this method works, it's far from ideal. It wastes a lot of gas on looping and - more often than not - runs out of gas, forcing the user to retry the transaction.

## Yield and Resume

Starting from version `1.40` of the protocol, developers can **delay the execution** of a function until certain conditions are met (e.g. an external service provides a result).

This way, instead of the contract calling itself on a loop waiting, the contract can simply **yield** calling the function that gives the result. When an external response is provided, the contract will **resume** and return the result.

<img src="https://mintcdn.com/neardocs/RuYMAM7eln2T5AA7/assets/blog/contract-wait-yield.png?fit=max&auto=format&n=RuYMAM7eln2T5AA7&q=85&s=479a2ff37d1f82874a73dc0ed955294f" alt="waiting on a yield" width="1355" height="842" data-path="assets/blog/contract-wait-yield.png" />

*Contracts can now yield the execution of a function until an external service signals that the result is ready*

### What is exactly being yielded?

It is important to notice that the contract is not **halting** or **blocking** its ability to execute, nor **halting in the middle of a function** to later resume it.

In the same way that a function can return a promise to call another contract, now a function can return a **yield** to call another function.

Indeed, the contract is not halting, but simply **delaying the execution of a callback** until an external agent signals that it is ok to resume.

If the contract does not trigger a resume after 200 blocks - around 4 minutes - the yielded function will resume receiving a "timeout error" as input.

<Warning>
  People can keep calling functions on the contract between a `yield`/`resume`, and the function that creates the `yield` can be called multiple times.

  The state **can change** between the `yield` and the `resume`, since people can keep interacting with the contract.

  Moreover, since the function used to signal is public, developers must make sure to guard it properly to avoid unwanted calls. This can be done by simply checking the caller of the function.
</Warning>

### How does it change for the user?

Between the `yield` and `resume` the user will simply be waiting to receive the result. But, in contrast with waiting on a loop, the user will not pay GAS just for having the contract waiting!

## How I can use yield/resume in my contract?

While we have not created any official `yield/resume` example, you can refer to [Saketh Are's example](https://github.com/near/near-sdk-rs/pull/1133/files), who has been working on the `yield/resume` implementation.

The basic idea is that the SDK now exposes two functions:

* A `yield(function_to_yield)` that returns a `yield_ID` which identifies the yield
* A `resume(yield_ID)` that signals which instance of `function_to_yield` can now execute

#### Simplified Example

```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
// const DATA_ID_REGISTER: u64 = 0;

pub fn request_weather(&mut self, city: String) {
    let index = self.next_available_request_index;
    self.next_available_request_index += 1;

    let yield_promise = env::promise_yield_create(
        "callback_return_result",
        &serde_json::to_vec(&(index,)).unwrap(),
        SIGN_ON_FINISH_CALL_GAS,
        GasWeight(0),
        DATA_ID_REGISTER,
    );

    // Store the request, so an external service can easily fetch it
    // This is optional, as an indexer could simply observe it in the receipts
    let data_id: CryptoHash =
        env::read_register(DATA_ID_REGISTER).expect("").try_into().expect("");
    self.requests.insert(&index, WeatherRequest{&data_id, &city});

    // The return will be the result of "callback_return_result" (defined below)
    env::promise_return(yield_promise);
}

/// Called by external participants to submit a response
pub fn respond(&mut self, data_id: String, weather: String) {
    let mut data_id_buf = [0u8; 32];
    hex::decode_to_slice(data_id, &mut data_id_buf).expect("");
    let data_id = data_id_buf;

    // check that caller is allowed to respond, weather is valid, etc.
    // ...

    log!("submitting response {} for data id {:?}", &weather, &data_id);
    env::promise_yield_resume(&data_id, &serde_json::to_vec(&weather).unwrap());
}

/// Callback receiving the external data (or a PromiseError in case of timeout)
pub fn callback_return_result(
    &mut self,
    request_index: u64,
    #[callback_result] weather: Result<String, PromiseError>,
) -> String {
    // Clean up the local state
    self.requests.remove(&request_index);

    match weather {
        Ok(weather) => "weather received: ".to_owned() + &weather,
        Err(_) => "request timed out".to_string(),
    }
}
```

## Conclusion

The ability to `yield` and `resume` computations is a big step forward for the NEAR protocol, as it enables developers to create contracts that rely on external services.

Currently, the feature is only **available on testnet**, and we are looking for feedback on how to improve it.

We expect to have a more user-friendly way to use `yield` and `resume` in the future, so stay tuned!
