Skip to content

Commit 212ce80

Browse files
committed
feat: add Result Callback guide and update sidebar links
1 parent c8e4e65 commit 212ce80

File tree

3 files changed

+161
-330
lines changed

3 files changed

+161
-330
lines changed

.vitepress/sidebar.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,10 @@ export function getSidebar() {
165165
text: 'End-to-end Encryption',
166166
link: '/guides/build-iapp/advanced/protect-the-result',
167167
},
168+
{
169+
text: 'Result Callback',
170+
link: '/guides/build-iapp/advanced/result-callback',
171+
},
168172
{
169173
text: 'Access Confidential Assets',
170174
link: '/guides/build-iapp/advanced/access-confidential-assets',
@@ -545,10 +549,6 @@ export function getSidebar() {
545549
text: 'Pay Per Task Model',
546550
link: '/protocol/pay-per-task',
547551
},
548-
{
549-
text: 'Oracle',
550-
link: '/protocol/oracle',
551-
},
552552
{
553553
text: 'Workers & Workerpools',
554554
collapsed: false,
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
---
2+
title: Result Callback Guide
3+
description: Practical guide to using the iExec Result Callback mechanism to push an off-chain task result (iApp) directly into a smart contract—Oracles, automation, triggers, proofs, and more.
4+
---
5+
6+
# Result Callback
7+
8+
This guide explains how to securely push an iExec task result into a smart contract using the “callback” mechanism.
9+
Oracles are only **one** of the possible use cases.
10+
11+
## When to Use a Callback
12+
13+
Use a callback whenever a smart contract should:
14+
15+
- Consume off-chain computed data (API aggregation, ML inference, analytics) and store it on-chain
16+
- React on-chain to an execution outcome (conditional trigger, state transition)
17+
- Store a timestamped record (price feed, score, KPI, proof hash) on-chain
18+
- Act as a logic bridge between external systems and on-chain logic
19+
20+
## 🧩 High-Level Flow
21+
22+
1. A requester executes an iApp on iExec.
23+
2. The iApp writes in the file `${IEXEC_OUT}/computed.json` under the filed `callback-data`.
24+
3. iExec decentralized Protocol trigger corresponding on-chain contract based on `callback-data` field.
25+
4. Your smart contract (receiver) pulls, verifies, and ingests it.
26+
27+
## 🗂️ computed.json Expected Format
28+
29+
Minimal example:
30+
31+
```json
32+
{
33+
"callback-data": "0x...(ABI-encoded bytes)",
34+
"deterministic-output-path": "result.bin",
35+
"status": "success",
36+
"metadata": {
37+
"source": "coingecko",
38+
"pair": "BTC-USD",
39+
"ts": 1731412345
40+
}
41+
}
42+
```
43+
44+
Required key:
45+
46+
- `callback-data`: ABI-encoded payload (hex string) – you control the schema
47+
48+
Best practices:
49+
50+
- Encode with `abi.encode(...)`
51+
- Include an internal timestamp (anti-replay)
52+
- Use a stable struct (avoid free-form JSON inside the bytes)
53+
54+
## 🧪 Example iApp
55+
56+
```bash
57+
# Inside the container
58+
node app.js "$PAIR" "$PRECISION"
59+
```
60+
61+
```js
62+
import fs from 'node:fs';
63+
import Web3 from 'web3';
64+
const web3 = new Web3();
65+
66+
async function main() {
67+
const [pair = 'BTC-USD', precision = '9'] = process.argv.slice(2);
68+
const price = await fetchPrice(pair); // Your logic
69+
const scaled = BigInt(Math.round(price * 10 ** Number(precision)));
70+
71+
const now = Math.floor(Date.now() / 1000);
72+
const abiPayload = web3.eth.abi.encodeParameters(
73+
['uint256','string','uint256'],
74+
[now, `${pair}-${precision}`, scaled.toString()]
75+
);
76+
77+
fs.writeFileSync(
78+
process.env.IEXEC_OUT + '/computed.json',
79+
JSON.stringify({
80+
'callback-data': abiPayload,
81+
metadata: { pair, precision, now, source: 'demo' }
82+
})
83+
);
84+
}
85+
86+
main().catch(() => process.exit(1));
87+
```
88+
89+
## 🧩 Base Contract (Generic Receiver)
90+
91+
```solidity
92+
interface IIexecProxy {
93+
struct Task {
94+
uint256 status;
95+
bytes resultsCallback; // raw callback-data bytes
96+
// ...existing fields...
97+
}
98+
function viewTask(bytes32 _id) external view returns (Task memory);
99+
}
100+
101+
abstract contract IExecCallbackReceiver {
102+
IIexecProxy public immutable iexec;
103+
constructor(address _iexec) { iexec = IIexecProxy(_iexec); }
104+
105+
function _getCallback(bytes32 taskid) internal view returns (bytes memory) {
106+
IIexecProxy.Task memory t = iexec.viewTask(taskid);
107+
require(t.status == 3, "task-not-completed"); // Example: 3 = COMPLETED
108+
return t.resultsCallback;
109+
}
110+
}
111+
```
112+
113+
## 🧾 Specialized Receiver (Price Feed)
114+
115+
```solidity
116+
contract PriceFeed is IExecCallbackReceiver {
117+
struct FeedValue {
118+
uint256 date;
119+
uint256 value;
120+
string key;
121+
}
122+
123+
mapping(bytes32 => FeedValue) public feeds;
124+
event FeedUpdate(bytes32 indexed id, uint256 date, uint256 value, string key);
125+
126+
constructor(address _iexec) IExecCallbackReceiver(_iexec) {}
127+
128+
function ingest(bytes32 taskid) external {
129+
bytes memory payload = _getCallback(taskid);
130+
(uint256 date, string memory pairPrecision, uint256 scaled) =
131+
abi.decode(payload, (uint256,string,uint256));
132+
bytes32 id = keccak256(bytes(pairPrecision));
133+
require(date > feeds[id].date, "stale");
134+
feeds[id] = FeedValue(date, scaled, pairPrecision);
135+
emit FeedUpdate(id, date, scaled, pairPrecision);
136+
}
137+
138+
function latest(string calldata pairPrecision)
139+
external
140+
view
141+
returns (FeedValue memory)
142+
{
143+
return feeds[keccak256(bytes(pairPrecision))];
144+
}
145+
}
146+
```
147+
148+
## 🔄 Other Use Cases
149+
150+
| Use Case | Description |
151+
|----------|-------------|
152+
| Price oracle | Multi-source API aggregation |
153+
| Reputation / scoring | Off-chain ML / analytics pushed on-chain |
154+
| Audit hash | Security scan or verification artifact |
155+
| Automation | Workflow step completion signal |
156+
| Dynamic parameters | Adjust rates / thresholds / quorums |
157+
| Logical bridge | Sync external (IoT / legacy) state |

0 commit comments

Comments
 (0)