Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
212ce80
feat: add Result Callback guide and update sidebar links
Le-Caignec Sep 15, 2025
b1ecd0a
refactor: streamline Result Callback guide and enhance clarity in imp…
Le-Caignec Sep 15, 2025
e3aee48
refactor: enhance clarity and update examples in Result Callback guide
Le-Caignec Sep 15, 2025
a44d059
refactor: improve clarity and formatting in Result Callback guide
Le-Caignec Sep 15, 2025
eb1e100
refactor: update command examples to use placeholder for chain name i…
Le-Caignec Sep 15, 2025
da8b29a
refactor: clarify and streamline the Result Callback guide for better…
Le-Caignec Sep 15, 2025
83f9929
refactor: add naming conventions for input parameters and enhance cal…
Le-Caignec Sep 15, 2025
cd2e0a1
refactor: add gas limit information and ensure callback logic adheres…
Le-Caignec Sep 16, 2025
76133c0
Update src/guides/build-iapp/advanced/result-callback.md
Le-Caignec Sep 18, 2025
d0722d6
Update src/guides/build-iapp/advanced/result-callback.md
Le-Caignec Sep 18, 2025
4688133
Update src/guides/build-iapp/advanced/result-callback.md
Le-Caignec Sep 18, 2025
998d4dc
Update src/guides/build-iapp/advanced/result-callback.md
Le-Caignec Sep 18, 2025
50246da
Update src/guides/build-iapp/advanced/result-callback.md
Le-Caignec Sep 18, 2025
5325468
Update src/guides/build-iapp/advanced/result-callback.md
Le-Caignec Sep 18, 2025
f26d075
refactor: reorganize callback contract implementation and clarify gas…
Le-Caignec Sep 18, 2025
aec3b16
Merge branch 'feature/result-callback' of https://github.com/iExecBlo…
Le-Caignec Sep 18, 2025
240e37f
style: standardize section titles and improve consistency in the resu…
Le-Caignec Sep 18, 2025
d1a88fb
refactor: remove redundant parameter `protectedDataAddress` from nami…
Le-Caignec Sep 18, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .vitepress/sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,10 @@ export function getSidebar() {
text: 'End-to-end Encryption',
link: '/guides/build-iapp/advanced/protect-the-result',
},
{
text: 'Result Callback',
link: '/guides/build-iapp/advanced/result-callback',
},
{
text: 'Access Confidential Assets',
link: '/guides/build-iapp/advanced/access-confidential-assets',
Expand Down Expand Up @@ -545,10 +549,6 @@ export function getSidebar() {
text: 'Pay Per Task Model',
link: '/protocol/pay-per-task',
},
{
text: 'Oracle',
link: '/protocol/oracle',
},
{
text: 'Workers & Workerpools',
collapsed: false,
Expand Down
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,25 @@ We welcome contributions to improve the iExec documentation!
📖 **For detailed contribution guidelines, component usage, and best practices,
please see our [CONTRIBUTING.md](CONTRIBUTING.md) guide.**

### Some conventions

In order to keep the documentation consistent, we have some naming conventions
for input parameters:

- `protectedData`: '0x123abc...',
- `authorizedApp`: '0x456def...',
- `authorizedUser`: '0x789cba...',
- `userAddress`: '0x789cba...',
- `appWhitelist`: '0xba46d6...',
- `owner`: '0xa0c15e...',
- `newOwner`: '0xc5e9f4...',
- `voucherOwner`: '0x5714eB...',
- `renterAddress`: '0x246bdf...'
- `subscriberAddress`: '0x246bdf...'
- `workerpool`: '0xa5de76...'
- `taskId`: '0x7ac398...'
- `smartContractAddress`: '0x8e5bB6...'

### Quick Contribution Steps

1. **Fork** this repository
Expand Down
16 changes: 8 additions & 8 deletions src/guides/build-iapp/advanced/build-your-first-sgx-iapp.md
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ You can check your deployed apps with their index, let's check your last
deployed app:

```bash twoslash
iexec app show --chain arbitrum-mainnet
iexec app show --chain {{chainName}}
```

## Run the iApp
Expand All @@ -420,20 +420,20 @@ At any time you can:
- view your balance

```bash twoslash
iexec account show --chain arbitrum-mainnet
iexec account show --chain {{chainName}}
```

- deposit RLC from your wallet to your iExec Account

```bash twoslash
iexec account deposit --chain arbitrum-mainnet <amount>
iexec account deposit --chain {{chainName}} <amount>
```

- withdraw RLC from your iExec account to your wallet \(only stake can be
withdrawn\)

```bash twoslash
iexec account withdraw --chain arbitrum-mainnet <amount>
iexec account withdraw --chain {{chainName}} <amount>
```

:::
Expand Down Expand Up @@ -478,13 +478,13 @@ is a 32Bytes hexadecimal string\).
Download the result of your task

```bash twoslash
iexec task show --chain arbitrum-mainnet <taskid> --download my-result
iexec task show --chain {{chainName}} <taskid> --download my-result
```

You can get your taskid with the command:

```bash twoslash
iexec deal show --chain arbitrum-mainnet <dealid>
iexec deal show --chain {{chainName}} <dealid>
```

::: info
Expand Down Expand Up @@ -526,7 +526,7 @@ The conditions to use an app are defined in the **apporder**.
Publish a new apporder for your application.

```bash twoslash
iexec app publish --chain arbitrum-mainnet
iexec app publish --chain {{chainName}}
```

::: info
Expand All @@ -545,7 +545,7 @@ conditions defined in apporder.
You can check the published apporders for your app

```bash twoslash
iexec orderbook app --chain arbitrum-mainnet <your app address>
iexec orderbook app --chain {{chainName}} <your app address>
```

Congratulation you just created a decentralized application! Anyone can now
Expand Down
184 changes: 184 additions & 0 deletions src/guides/build-iapp/advanced/result-callback.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
---
title: Result callback guide
description:
Use the iExec result callback feature to have the protocol invoke a function
on your smart contract at the end of a task execution.
---

# Result callback

This guide explains how to trigger a callback function at the end of a
successful task on your smart contract.

Use a callback when your smart contract should:

- Ingest off-chain computed data (API aggregation, ML inference, analytics) and
persist it
- React to an execution outcome (conditional trigger, state transition)

Check notice on line 17 in src/guides/build-iapp/advanced/result-callback.md

View workflow job for this annotation

GitHub Actions / vale

[vale] src/guides/build-iapp/advanced/result-callback.md#L17

[Google.Parens] Use parentheses judiciously.
Raw output
{"message": "[Google.Parens] Use parentheses judiciously.", "location": {"path": "src/guides/build-iapp/advanced/result-callback.md", "range": {"start": {"line": 17, "column": 33}}}, "severity": "INFO"}
- Store a timestamped record (price feed, score, KPI, proof hash)

Check notice on line 18 in src/guides/build-iapp/advanced/result-callback.md

View workflow job for this annotation

GitHub Actions / vale

[vale] src/guides/build-iapp/advanced/result-callback.md#L18

[Google.Parens] Use parentheses judiciously.
Raw output
{"message": "[Google.Parens] Use parentheses judiciously.", "location": {"path": "src/guides/build-iapp/advanced/result-callback.md", "range": {"start": {"line": 18, "column": 30}}}, "severity": "INFO"}
- Bridge logic between external systems and on-chain state

## 🧩 High-level flow

1. A requester deploys the smart contract that should receive the callback data.
2. The requester executes an iApp and specifies the callback address.
3. The iApp writes `${IEXEC_OUT}/computed.json` with a `callback-data` field
(ABI‑encoded bytes you crafted).

Check notice on line 26 in src/guides/build-iapp/advanced/result-callback.md

View workflow job for this annotation

GitHub Actions / vale

[vale] src/guides/build-iapp/advanced/result-callback.md#L26

[Google.Parens] Use parentheses judiciously.
Raw output
{"message": "[Google.Parens] Use parentheses judiciously.", "location": {"path": "src/guides/build-iapp/advanced/result-callback.md", "range": {"start": {"line": 26, "column": 4}}}, "severity": "INFO"}
4. After the task completes and is validated, the iExec protocol invokes your

Check notice on line 27 in src/guides/build-iapp/advanced/result-callback.md

View workflow job for this annotation

GitHub Actions / vale

[vale] src/guides/build-iapp/advanced/result-callback.md#L27

[Google.Passive] In general, use active voice instead of passive voice ('is validated').
Raw output
{"message": "[Google.Passive] In general, use active voice instead of passive voice ('is validated').", "location": {"path": "src/guides/build-iapp/advanced/result-callback.md", "range": {"start": {"line": 27, "column": 33}}}, "severity": "INFO"}
contract’s `receiveResult(bytes32,bytes)`.
5. Your contract decodes and processes those bytes if callback data have been
provided.

## Step-by-step implementation

### Step 1: Implement the callback contract

Your contract must expose the function `receiveResult(bytes32,bytes)`
[ERC1154](https://github.com/iExecBlockchainComputing/iexec-solidity/blob/master/contracts/ERC1154/IERC1154.sol).
The protocol calls it with:

- `_callID`: This parameter represents the `taskId`, passed as the first
argument
- `callback`: exactly the bytes you encoded as `callback-data`

Decode using the same tuple. (Optional) Add protections: authorized caller check

Check notice on line 44 in src/guides/build-iapp/advanced/result-callback.md

View workflow job for this annotation

GitHub Actions / vale

[vale] src/guides/build-iapp/advanced/result-callback.md#L44

[Google.Parens] Use parentheses judiciously.
Raw output
{"message": "[Google.Parens] Use parentheses judiciously.", "location": {"path": "src/guides/build-iapp/advanced/result-callback.md", "range": {"start": {"line": 44, "column": 30}}}, "severity": "INFO"}
(iExec hub / proxy), replay guard, bounds checks.

```solidity
contract IExecCallbackReceiver {
// Your business logic here ...

// ERC1154 - Callback processing
function receiveResult(bytes32 _callID, bytes memory callback) external {
// Parse results
(uint256 timestamp, string memory pairAndPrecision, uint256 scaledValue) =
abi.decode(callback, (uint256, string, uint256));
}
}
```

::: tip Important

The callback transaction is subject to a gas limit of {{ gasLimit }}.

Check failure on line 62 in src/guides/build-iapp/advanced/result-callback.md

View workflow job for this annotation

GitHub Actions / vale

[vale] src/guides/build-iapp/advanced/result-callback.md#L62

[Vale.Spelling] Did you really mean 'gasLimit'?
Raw output
{"message": "[Vale.Spelling] Did you really mean 'gasLimit'?", "location": {"path": "src/guides/build-iapp/advanced/result-callback.md", "range": {"start": {"line": 62, "column": 58}}}, "severity": "ERROR"}
Ensure your callback logic fits within this limit to avoid out-of-gas errors.

:::

### Step 2: Prepare the callback payload in the iApp

You only need to write `computed.json` containing the key `callback-data`.
That value must be the ABI‑encoded bytes your contract knows how to decode.
Example tuple schema we'll use:

Check warning on line 71 in src/guides/build-iapp/advanced/result-callback.md

View workflow job for this annotation

GitHub Actions / vale

[vale] src/guides/build-iapp/advanced/result-callback.md#L71

[Google.We] Try to avoid using first-person plural like 'we'.
Raw output
{"message": "[Google.We] Try to avoid using first-person plural like 'we'.", "location": {"path": "src/guides/build-iapp/advanced/result-callback.md", "range": {"start": {"line": 71, "column": 22}}}, "severity": "WARNING"}
`(uint256 timestamp, string pairAndPrecision, uint256 scaledValue)`.

```ts twoslash
import { writeFileSync } from 'node:fs';
import { AbiCoder } from 'ethers';

const timestamp = Math.floor(Date.now() / 1000);
const pair = 'BTC-USD';
const scaled = '9';
// ---cut---

async function main() {
// Your business logic here ...

const abiCoder = new AbiCoder();
const abiPayload = abiCoder.encode(
['uint256', 'string', 'uint256'],
[timestamp, pair, scaled]
);

writeFileSync(
`${process.env.IEXEC_OUT}/computed.json`,
JSON.stringify({
'callback-data': abiPayload,
})
);
}
```

### Step 3: Run the iApp with a callback

When creating the request order, set the `callback` field to your callback
contract address.
After completion, the protocol calls your contract, passing the `callback-data`
bytes.

First install the iExec SDK if you have not already (see

Check notice on line 108 in src/guides/build-iapp/advanced/result-callback.md

View workflow job for this annotation

GitHub Actions / vale

[vale] src/guides/build-iapp/advanced/result-callback.md#L108

[Google.Contractions] Use 'haven't' instead of 'have not'.
Raw output
{"message": "[Google.Contractions] Use 'haven't' instead of 'have not'.", "location": {"path": "src/guides/build-iapp/advanced/result-callback.md", "range": {"start": {"line": 108, "column": 36}}}, "severity": "INFO"}
[Getting Started](/guides/use-iapp/getting-started)).

```ts twoslash
import { IExec, utils } from 'iexec';

const ethProvider = utils.getSignerFromPrivateKey(
'chain', // blockchain node URL
'PRIVATE_KEY'
);
const iexec = new IExec({
ethProvider,
});
// ---cut---
// Basic arguments
const requestorderToSign = await iexec.order.createRequestorder({
app: '0x456def...',
category: 0,
appmaxprice: 10,
workerpool: '0xa5de76...',
callback: '0x8e5bB6...', // Callback contract address
});
const requestOrder = await iexec.order.signRequestorder(requestorderToSign);

// Fetch app orders
const appOrders = await iexec.orderbook.fetchAppOrderbook(
'0x456def...' // Filter by specific app
);
if (appOrders.orders.length === 0) {
throw new Error('No app orders found for the specified app');
}

// Fetch workerpool orders
const workerpoolOrders = await iexec.orderbook.fetchWorkerpoolOrderbook({
workerpool: '0xa5de76...', // Filter by specific workerpool
});
if (workerpoolOrders.orders.length === 0) {
throw new Error('No workerpool orders found for the specified workerpool');
}

// Execute the task
const taskId = await iexec.order.matchOrders({
requestorder: requestOrder,
apporder: appOrders.orders[0].order,
workerpoolorder: workerpoolOrders.orders[0].order,
});
```

## 🔄 Other use cases

| Use Case | Description |
| -------------------- | ---------------------------------------- |
| Price oracle | Multi-source API aggregation |
| Reputation / scoring | Off-chain ML / analytics pushed on-chain |
| Audit hash | Security scan or verification artifact |
| Automation | Workflow step completion signal |
| Dynamic parameters | Adjust rates / thresholds / quorums |
| Logical bridge | Sync external (IoT / legacy) state |

Check notice on line 165 in src/guides/build-iapp/advanced/result-callback.md

View workflow job for this annotation

GitHub Actions / vale

[vale] src/guides/build-iapp/advanced/result-callback.md#L165

[Google.Parens] Use parentheses judiciously.
Raw output
{"message": "[Google.Parens] Use parentheses judiciously.", "location": {"path": "src/guides/build-iapp/advanced/result-callback.md", "range": {"start": {"line": 165, "column": 40}}}, "severity": "INFO"}

<script setup>
import { computed } from 'vue';
import useUserStore from '@/stores/useUser.store';
import { getChainById } from '@/utils/chain.utils';

// Get current chain info
const userStore = useUserStore();
const selectedChain = computed(() => userStore.getCurrentChainId());
const chainData = computed(() => getChainById(selectedChain.value));
const chainName = computed(() => chainData.value.chainName);

const gasLimit = computed(() => {
const chainId = selectedChain.value;
if (chainId === 42161) return '100,000'; // Arbitrum One
if (chainId === 134) return '200,000'; // Bellecour
return '100,000'; // default
});
</script>
Loading