From 3d9b5594a88c0f78705f1e2b0b64b3663076fa63 Mon Sep 17 00:00:00 2001 From: Le-Caignec Date: Mon, 18 Aug 2025 19:43:41 +0200 Subject: [PATCH 01/33] fix: Refactor documentation and code examples for iApp result handling - Updated links in debugging and inputs/outputs guides to reflect new result decryption guide. - Added new guide on downloading and decrypting iApp results, detailing the process and providing code examples. - Removed outdated debug mode option from access management guide. - Streamlined input handling sections in execution guides, consolidating command-line argument examples. - Enhanced getting started guide with clearer prerequisites and installation instructions. - Removed unnecessary debug-related code snippets from the DataProtector documentation. - Updated iApp generator documentation to clarify project modes and removed debug mode references. - Improved formatting and clarity in the getting started guide for the iApp generator. --- .vitepress/sidebar.ts | 4 +- src/get-started/helloWorld/3-buildIApp.md | 8 +- src/guides/build-iapp/build-&-deploy.md | 115 ++---- src/guides/build-iapp/debugging.md | 2 +- ...lts.md => download-and-decrypt-results.md} | 84 +---- src/guides/build-iapp/inputs-and-outputs.md | 4 +- src/guides/manage-data/manage-access.md | 21 -- .../use-iapp/add-inputs-to-execution.md | 224 +----------- .../use-iapp/different-ways-to-execute.md | 76 +--- src/guides/use-iapp/getting-started.md | 37 +- .../use-iapp/use-iapp-with-protected-data.md | 333 +----------------- src/modules/helloWorld/ProtectData.vue | 9 +- .../dataProtectorCore/protectData.md | 28 -- src/references/iapp-generator.md | 9 +- .../iapp-generator/building-your-iexec-app.md | 13 +- .../iapp-generator/getting-started.md | 26 +- 16 files changed, 89 insertions(+), 904 deletions(-) rename src/guides/build-iapp/{how-to-get-and-decrypt-results.md => download-and-decrypt-results.md} (76%) diff --git a/.vitepress/sidebar.ts b/.vitepress/sidebar.ts index af4a6d47..87e2e559 100644 --- a/.vitepress/sidebar.ts +++ b/.vitepress/sidebar.ts @@ -182,8 +182,8 @@ export function getSidebar() { link: '/guides/build-iapp/using-tdx', }, { - text: 'How to Get and Decrypt Results', - link: '/guides/build-iapp/how-to-get-and-decrypt-results', + text: 'Download and Decrypt Results', + link: '/guides/build-iapp/download-and-decrypt-results', }, { text: 'Debugging', diff --git a/src/get-started/helloWorld/3-buildIApp.md b/src/get-started/helloWorld/3-buildIApp.md index 554dd493..6ab83a99 100644 --- a/src/get-started/helloWorld/3-buildIApp.md +++ b/src/get-started/helloWorld/3-buildIApp.md @@ -489,7 +489,7 @@ const arbitrumSteps = [ }, { showAt: 13, - question: 'Pushed TEE image bob/hello-world:0.0.1-tee-scone-5.9.1-v16-debug-ce3a01d9c5d7 on dockerhub', + question: 'Pushed TEE image bob/hello-world:0.0.1-tee-scone-5.9.1-v16-ce3a01d9c5d7 on dockerhub', answer: '', showTyping: false, isComplete: true @@ -558,7 +558,7 @@ const bellecourSteps = [ }, { showAt: 12, - question: 'Pushed TEE image bob/hello-world:0.0.1-tee-scone-5.9.1-v16-debug-ce3a01d9c5d7 on dockerhub', + question: 'Pushed TEE image bob/hello-world:0.0.1-tee-scone-5.9.1-v16-ce3a01d9c5d7 on dockerhub', answer: '', showTyping: false, isComplete: true @@ -573,12 +573,12 @@ const bellecourSteps = [ ]; const arbitrumCompletionItems = [ - '└ Docker image: bob/hello-world:0.0.1-tee-scone-5.9.1-v16-debug-ce3a01d9c5d7', + '└ Docker image: bob/hello-world:0.0.1-tee-scone-5.9.1-v16-ce3a01d9c5d7', '└ iApp address: 0x1f80DCebc2EAAff0Db7156413C43B7e88D189923' ]; const bellecourCompletionItems = [ - '└ Docker image: bob/hello-world:0.0.1-tee-scone-5.9.1-v16-debug-ce3a01d9c5d7', + '└ Docker image: bob/hello-world:0.0.1-tee-scone-5.9.1-v16-ce3a01d9c5d7', '└ iApp address: 0x1f80DCebc2EAAff0Db7156413C43B7e88D189923' ]; diff --git a/src/guides/build-iapp/build-&-deploy.md b/src/guides/build-iapp/build-&-deploy.md index ac6a28dc..459bbe3e 100644 --- a/src/guides/build-iapp/build-&-deploy.md +++ b/src/guides/build-iapp/build-&-deploy.md @@ -30,10 +30,27 @@ iApp Generator handles all the low-level complexity for you. Before getting started, make sure you have the following installed: -- **Node.js** (version 18 or higher) - [Download here](https://nodejs.org/) -- **Docker** - [Download here](https://www.docker.com/get-started) -- **Docker Hub account** - [Sign up here](https://hub.docker.com/) (required for - deployment) +
+
+
+ 📦 Node.js v20+ +
+ Download → +
+
+
+ 🐳 Docker installed +
+ Download → +
+ +
+
+ 🐳 DockerHub Account +
+ Sign Up → +
+
## Installation @@ -220,88 +237,6 @@ specify your app version, and push both standard and TEE-compatible images: /> -## Real Examples - -Here are some real-world examples of iApp to help you understand how they work -in practice. - -### Email Notification iApp - -This iApp lets you send updates to your contacts without ever seeing their email -addresses, privacy is preserved by design. - -::: code-group - -```js [Node.js] -/* User runs: "Send updates to my contacts about my project" */ -const contacts = loadProtectedData(); // User's protected contact list -contacts.forEach((contact) => { - sendEmail(contact, projectUpdateMessage); -}); -// → Emails sent directly, you never see the addresses -``` - -```python [Python] -# User runs: "Send updates to my contacts about my project" -contacts = load_protecteddata() # User's protected contact list -for contact in contacts: - send_email(contact, project_update_message) -# → Emails sent directly, you never see the addresses -``` - -::: - -### Oracle Update iApp - -This iApp securely updates a price oracle using private trading data, ensuring -sensitive information stays confidential. - -::: code-group - -```js [Node.js] -// User runs: "Update price oracle with my private trading data" -const tradingData = loadProtectedData(); // User's protected trading history -const averagePrice = calculateWeightedAverage(tradingData); -updateOracleContract(averagePrice); -// → Oracle updated with real data, trading history stays private -``` - -```python [Python] -# User runs: "Update price oracle with my private trading data" -trading_data = load_protecteddata() # User's protected trading history -average_price = calculate_weighted_average(trading_data) -update_oracle_contract(average_price) -# → Oracle updated with real data, trading history stays private -``` - -::: - -### Automated Transactions iApp - -This iApp automates monthly payments using protected payment details, so -financial information remains private. - -::: code-group - -```js [Node.js] -// User runs: "Automate payments every month" -const paymentInfo = loadProtectedData(); // User's payment details -for (let month = 0; month < 12; month++) { - processPayment(paymentInfo); -} -// → Payments processed, payment details stay private -``` - -```python [Python] -# User runs: "Automate payments every month" -payment_info = load_protecteddata() # User's payment details -for month in range(12): - process_payment(payment_info) -# → Payments processed, payment details stay private -``` - -::: - diff --git a/src/guides/build-iapp/debugging.md b/src/guides/build-iapp/debugging.md index 17e9c5a2..aad98af2 100644 --- a/src/guides/build-iapp/debugging.md +++ b/src/guides/build-iapp/debugging.md @@ -171,5 +171,5 @@ Continue improving your iApp: - **[Inputs and Outputs](/guides/build-iapp/inputs-and-outputs)** - Handle data in TEE -- **[How to Get and Decrypt Results](/guides/build-iapp/how-to-get-and-decrypt-results)** - +- **[How to Get and Decrypt Results](/guides/build-iapp/download-and-decrypt-results)** - Retrieve results diff --git a/src/guides/build-iapp/how-to-get-and-decrypt-results.md b/src/guides/build-iapp/download-and-decrypt-results.md similarity index 76% rename from src/guides/build-iapp/how-to-get-and-decrypt-results.md rename to src/guides/build-iapp/download-and-decrypt-results.md index f56bef05..64bdc61e 100644 --- a/src/guides/build-iapp/how-to-get-and-decrypt-results.md +++ b/src/guides/build-iapp/download-and-decrypt-results.md @@ -3,7 +3,7 @@ title: How to Get and Decrypt Results description: Download and decrypt iApp execution results from completed tasks --- -# 📦 How to Get and Decrypt Results +# 📦 Download and Decrypt Results **When an iApp execution completes, you need to retrieve and decrypt the results.** This guide shows you how to download task results and decrypt them to @@ -40,36 +40,11 @@ Deal (agreement between parties) - 📁 **Results contain** all files from `IEXEC_OUT` directory - ⚡ **Available immediately** after task completion -## Downloading Results +## Download & Decrypt Results -### Using iExec SDK CLI - -**Get task information and download**: - -```bash -# Check task status and get result info -iexec task show - -# Download encrypted result -iexec task show --download my-result - -# Extract downloaded files -unzip my-result.zip -d my-result/ -ls my-result/ -``` - -**Get task ID from deal**: - -```bash -# If you only have the deal ID -iexec deal show - -# Lists all tasks in the deal with their IDs -``` - -### Using DataProtector SDK - -**Integrated download and decryption**: +DataProtector provides methods to download and decrypt results from completed +tasks. You can view the `taskId` in your +[iExec Explorer](https://explorer.iex.ec/). ```ts twoslash import { IExecDataProtectorCore, getWeb3Provider } from '@iexec/dataprotector'; @@ -77,7 +52,7 @@ import { IExecDataProtectorCore, getWeb3Provider } from '@iexec/dataprotector'; const web3Provider = getWeb3Provider('PRIVATE_KEY'); const dataProtectorCore = new IExecDataProtectorCore(web3Provider); // ---cut--- -// Get result from completed task +// Get result from a completed task const result = await dataProtectorCore.getResultFromCompletedTask({ taskId: '0x123abc...', // Your task ID }); @@ -85,51 +60,12 @@ const result = await dataProtectorCore.getResultFromCompletedTask({ console.log('Result downloaded and decrypted:', result); ``` -## Decrypting Results +::: tip Info -### Automatic Decryption with DataProtector - -**The easiest way** - decryption happens automatically: - -```ts twoslash -import { IExecDataProtectorCore, getWeb3Provider } from '@iexec/dataprotector'; +The `processProtectedData` method will create a task and automatically download +and decrypt the result. -const web3Provider = getWeb3Provider('PRIVATE_KEY'); -const dataProtectorCore = new IExecDataProtectorCore(web3Provider); -// ---cut--- -// Execute and get results in one flow -const processResponse = await dataProtectorCore.processProtectedData({ - protectedData: '0x123abc...', - app: '0x456def...', -}); - -console.log('Task ID:', processResponse.taskId); - -// Get decrypted result -const result = await dataProtectorCore.getResultFromCompletedTask({ - taskId: processResponse.taskId, -}); - -// Result is automatically decrypted ArrayBuffer -const resultText = new TextDecoder().decode(result.result); -console.log('Decrypted result:', resultText); -``` - -### Manual Decryption with CLI - -**If you downloaded manually**: - -```bash -# Download the encrypted result -iexec task show --download my-result - -# Decrypt using your wallet (must be the beneficiary) -iexec result decrypt my-result.zip --force - -# Extract decrypted files -unzip decrypted-result.zip -d final-result/ -cat final-result/result.txt -``` +::: ## Result File Structure diff --git a/src/guides/build-iapp/inputs-and-outputs.md b/src/guides/build-iapp/inputs-and-outputs.md index 1012a2e6..056476b7 100644 --- a/src/guides/build-iapp/inputs-and-outputs.md +++ b/src/guides/build-iapp/inputs-and-outputs.md @@ -618,7 +618,7 @@ save_report(report) Once your iApp completes execution, users can retrieve and decrypt the results: → **Learn how users get results**: Check our -[How to Get and Decrypt Results](/guides/build-iapp/how-to-get-and-decrypt-results) +[How to Get and Decrypt Results](/guides/build-iapp/download-and-decrypt-results) guide for the complete user workflow. ## What's Next? @@ -631,7 +631,7 @@ Continue building with these guides: Control who can use your iApp - **[Debugging Your iApp](/guides/build-iapp/debugging)** - Troubleshoot execution issues -- **[How to Get and Decrypt Results](/guides/build-iapp/how-to-get-and-decrypt-results)** - +- **[How to Get and Decrypt Results](/guides/build-iapp/download-and-decrypt-results)** - User-side result handling ### Technical Deep Dive diff --git a/src/guides/manage-data/manage-access.md b/src/guides/manage-data/manage-access.md index 7b37b486..8f2ecde1 100644 --- a/src/guides/manage-data/manage-access.md +++ b/src/guides/manage-data/manage-access.md @@ -79,27 +79,6 @@ for detailed formatting instructions. ::: -### Debug Mode Option - -Debug mode lets you test with debug iApp during development. As "debug" iApp -don't have the same security standards, we recommend using this mode only during -iApp development. - -```ts twoslash -import { IExecDataProtectorCore, getWeb3Provider } from '@iexec/dataprotector'; - -const web3Provider = getWeb3Provider('PRIVATE_KEY'); -const dataProtectorCore = new IExecDataProtectorCore(web3Provider); -// ---cut--- - -const protectedData = await dataProtectorCore.protectData({ - data: { - email: 'test@example.com', - }, - allowDebug: true, // [!code focus] -}); -``` - ## Grant Access By default, your protected data is private. To let others use it, you need to diff --git a/src/guides/use-iapp/add-inputs-to-execution.md b/src/guides/use-iapp/add-inputs-to-execution.md index eb6d321e..3d88eb68 100644 --- a/src/guides/use-iapp/add-inputs-to-execution.md +++ b/src/guides/use-iapp/add-inputs-to-execution.md @@ -20,74 +20,11 @@ iExec supports several types of inputs for iApp executions: 3. **Secrets**: Sensitive data like API keys stored securely 4. **Protected Data**: Encrypted data processed within the TEE -## Method 1: Adding Command-Line Arguments +## Adding Command-Line Arguments Command-line arguments are passed as a string to the iApp and are visible on the blockchain. -### Using SDK Library - -```ts twoslash -import { IExec, utils } from 'iexec'; - -const ethProvider = utils.getSignerFromPrivateKey( - 'bellecour', // 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...', // ENS address for iExec's debug workerpool - params: 'arg1 arg2 arg3', // Command-line arguments - // Other parameters have default values -}); -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, -}); -``` - -### Using SDK CLI - -```bash -# Basic arguments -iexec app run 0x456def... --protectedData 0x123abc... --args "arg1 arg2" - -# Complex arguments with spaces -iexec app run 0x456def... --protectedData 0x123abc... --args "--input-file data.csv --output-format json" - -# Arguments with quotes (escape properly) -iexec app run 0x456def... --protectedData 0x123abc... --args "--message \"Hello World\" --config '{\"key\": \"value\"}'" -``` - -### Using DataProtector - ```ts twoslash import { IExecDataProtectorCore, getWeb3Provider } from '@iexec/dataprotector'; @@ -102,79 +39,11 @@ const result = await dataProtectorCore.processProtectedData({ }); ``` -## Method 2: Adding Input Files +## Adding Input Files Input files are URLs to public files that the iApp can download during execution. -### Using SDK Library - -```ts twoslash -import { IExec, utils } from 'iexec'; - -const ethProvider = utils.getSignerFromPrivateKey( - 'bellecour', // blockchain node URL - 'PRIVATE_KEY' -); -const iexec = new IExec({ - ethProvider, -}); -// ---cut--- -// Single input file -const requestorderToSign = await iexec.order.createRequestorder({ - app: '0x456def...', - category: 0, // Required: category for the request - appmaxprice: 10, - workerpool: '0xa5de76...', // ENS address for iExec's debug workerpool - params: { - iexec_input_files: [ - 'https://example.com/config.json', - 'https://example.com/template.html', - 'https://example.com/data.csv', - ], - }, -}); -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, -}); -``` - -### Using SDK CLI - -```bash -# Single input file -iexec app run 0x456def... --protectedData 0x123abc... --inputFiles "https://example.com/config.json" - -# Multiple input files (comma-separated) -iexec app run 0x456def... --protectedData 0x123abc... --inputFiles "https://example.com/config.json,https://example.com/template.html" - -# Multiple input files (space-separated) -iexec app run 0x456def... --protectedData 0x123abc... --inputFiles "https://example.com/config.json" --inputFiles "https://example.com/template.html" -``` - -### Using DataProtector - ```ts twoslash import { IExecDataProtectorCore, getWeb3Provider } from '@iexec/dataprotector'; @@ -192,76 +61,11 @@ const result = await dataProtectorCore.processProtectedData({ }); ``` -## Method 3: Adding Secrets +## Adding Secrets Secrets are sensitive data like API keys, passwords, or tokens that are stored securely and made available to the iApp as environment variables. -### Using SDK Library - -```ts twoslash [Browser] -// @errors: 2345 2739 7053 2339 -import { IExec, utils } from 'iexec'; - -const ethProvider = utils.getSignerFromPrivateKey( - 'bellecour', // blockchain node URL - 'PRIVATE_KEY' -); -const iexec = new IExec({ - ethProvider, -}); -// ---cut--- -// Basic secrets -const requestorderToSign = await iexec.order.createRequestorder({ - app: '0x456def...', - category: 0, // Required: category for the request - appmaxprice: 10, - workerpool: '0xa5de76...', // ENS address for iExec's debug workerpool - params: { - iexec_secrets: { - 1: 'api-key-12345', - 2: 'database-password', - }, - }, -}); -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, -}); -``` - -### Using SDK CLI - -```bash -# Note: CLI doesn't support secrets directly for security reasons -# Use the SDK for secret management - -# Alternative: Use environment variables (less secure) -export IEXEC_SECRET_1="api-key-12345" -export IEXEC_SECRET_2="database-password" -iexec app run 0x456def... --protectedData 0x123abc... -``` - ### Using DataProtector ```ts twoslash @@ -281,7 +85,7 @@ const result = await dataProtectorCore.processProtectedData({ }); ``` -## Method 4: Specifying File Paths in Protected Data +## Specifying File Paths in Protected Data When working with protected data that contains multiple files, you can specify which file to process. @@ -308,26 +112,6 @@ const taskResult = await dataProtectorCore.getResultFromCompletedTask({ }); ``` -You can combine different types of inputs for complex executions. - -## How Secrets Work in iApp - -Inside the iApp, secrets are available as environment variables: - -```python -# Python iApp example -import os - -api_key = os.environ.get('IEXEC_SECRET_1') # 'api-key-12345' -db_password = os.environ.get('IEXEC_SECRET_2') # 'database-password' -``` - -```javascript -// JavaScript iApp example -const apiKey = process.env.IEXEC_SECRET_1; // 'api-key-12345' -const dbPassword = process.env.IEXEC_SECRET_2; // 'database-password' -``` - ## Next Steps Now that you understand how to add inputs to iApp executions: diff --git a/src/guides/use-iapp/different-ways-to-execute.md b/src/guides/use-iapp/different-ways-to-execute.md index bd9f25dc..eb549b19 100644 --- a/src/guides/use-iapp/different-ways-to-execute.md +++ b/src/guides/use-iapp/different-ways-to-execute.md @@ -9,75 +9,7 @@ There are multiple ways to execute iApp on the iExec network. This guide covers the basic execution methods. For advanced features like protected data, arguments, and input files, see the dedicated guides. -::: tip ENS Addresses - -**ENS (Ethereum Name Service)** is a naming system for Ethereum addresses that -allows you to use human-readable names instead of long hexadecimal addresses. -For example, instead of using `0x1234567890abcdef...`, you can use -`debug-v8-learn.main.pools.iexec.eth`. - -In the examples below, we use `debug-v8-learn.main.pools.iexec.eth` which is -iExec's official debug workerpool ENS address. This workerpool is specifically -designed for testing and development purposes on the Bellecour testnet. - -::: - -## Method 1: Using the iExec SDK Library - -The iExec SDK provides a modular JavaScript interface for executing iApp. - -```ts twoslash -import { IExec, utils } from 'iexec'; - -const ethProvider = utils.getSignerFromPrivateKey( - 'bellecour', // blockchain node URL - 'PRIVATE_KEY' -); -const iexec = new IExec({ - ethProvider, -}); -// ---cut--- -// Create & Sign a request order -const requestorderToSign = await iexec.order.createRequestorder({ - app: '0x456def...', // The iApp address - category: 0, -}); -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, -}); -``` - -## Method 2: Using the iExec CLI - -The iExec CLI is perfect for quick executions and automation scripts. - -```bash -# Execute an iApp -iexec app run 0x456def... -``` - -## Method 3: Using the iApp Generator CLI +## Using the iApp Generator CLI The iApp Generator CLI provides a streamlined way to execute iApp, especially for developers who have built their own iApp. @@ -99,12 +31,6 @@ iapp run 0x456def... iapp test ``` -## When to Use Each Method - -- **iExec Library**: For JavaScript applications and web3 integration -- **iExec CLI**: For quick testing and automation scripts -- **iApp Generator CLI**: For developers who have built their own iApp - ## Next Steps - Learn how to diff --git a/src/guides/use-iapp/getting-started.md b/src/guides/use-iapp/getting-started.md index c6be7e09..38a3a9ef 100644 --- a/src/guides/use-iapp/getting-started.md +++ b/src/guides/use-iapp/getting-started.md @@ -8,34 +8,33 @@ description: Learn the basics of finding and executing iApp on the iExec network Welcome to secure, privacy-preserving computation! This guide shows you how to use iApp on the iExec confidential computing network. -## Prerequisites +### Prerequisites -Before you begin, make sure you have: +Before getting started, ensure that you have the following installed on your +system: -- A Web3 wallet (MetaMask, WalletConnect, etc.) -- Some RLC tokens for paying computation fees (or access to free vouchers - through learning programs) - - [Learn about RLC tokens](/get-started/overview/rlc) and - [how to bridge them](/get-started/tooling-and-explorers/bridge) -- Basic understanding of blockchain transactions -- iExec SDK installed +\- [**Node.js**](https://nodejs.org/en/) version 18 or higher + +\- [**NPM**](https://docs.npmjs.com/) (Node.js package manager) + +### Installation ::: code-group ```sh [npm] -npm install -g iexec +npm install @iexec/dataprotector ``` ```sh [yarn] -yarn global add iexec +yarn add @iexec/dataprotector ``` ```sh [pnpm] -pnpm add -g iexec +pnpm add @iexec/dataprotector ``` ```sh [bun] -bun add -g iexec +bun add @iexec/dataprotector ``` ::: @@ -81,15 +80,3 @@ For step-by-step instructions, check out these guides: to provide data and parameters to iApp - **[How to Pay for Executions](/guides/use-iapp/how-to-pay-executions)** - Understanding costs and payment options - -## Quick Start - -Ready to jump in? Follow the execution guides for detailed instructions on how -to use iApp. - - diff --git a/src/guides/use-iapp/use-iapp-with-protected-data.md b/src/guides/use-iapp/use-iapp-with-protected-data.md index 2bdb23a0..fb597265 100644 --- a/src/guides/use-iapp/use-iapp-with-protected-data.md +++ b/src/guides/use-iapp/use-iapp-with-protected-data.md @@ -49,49 +49,6 @@ const { address: protectedDataAddress } = await dataProtectorCore.protectData({ }); ``` -### Protecting Different Data Types - -```ts twoslash -import { IExecDataProtectorCore, getWeb3Provider } from '@iexec/dataprotector'; - -const web3Provider = getWeb3Provider('PRIVATE_KEY'); -const dataProtectorCore = new IExecDataProtectorCore(web3Provider); -// ---cut--- -// Protect contact list for email applications -const { address: contactListAddress } = await dataProtectorCore.protectData({ - name: 'Email Contact List', - data: { - contacts: { - '0x123abc...': 'john@example.com', - '0x456def...': 'jane@example.com', - '0x789ghi...': 'bob@example.com', - }, - }, -}); - -// Protect trading data for oracle applications -const { address: tradingDataAddress } = await dataProtectorCore.protectData({ - name: 'Trading History', - data: { - trades: { - '2024-01-01': { price: 50000, volume: 100 }, - '2024-01-02': { price: 51000, volume: 150 }, - '2024-01-03': { price: 49000, volume: 200 }, - }, - }, -}); - -// Protect financial data for payment applications -const { address: paymentDataAddress } = await dataProtectorCore.protectData({ - name: 'Payment Information', - data: { - bankAccount: '1234567890', - routingNumber: '987654321', - accountHolder: 'John Doe', - }, -}); -``` - ## Step 2: Grant Access to iApp iApp need explicit authorization to access your protected data. @@ -134,8 +91,6 @@ const grantedAccessList = await dataProtectorCore.getGrantedAccess({ Once access is granted, you can execute the iApp with your protected data. -### Using DataProtector - ```ts twoslash import { IExecDataProtectorCore, getWeb3Provider } from '@iexec/dataprotector'; @@ -149,78 +104,11 @@ const result = await dataProtectorCore.processProtectedData({ }); ``` -### Using SDK Library - -```ts twoslash -import { IExec, utils } from 'iexec'; - -const ethProvider = utils.getSignerFromPrivateKey( - 'bellecour', // blockchain node URL - 'PRIVATE_KEY' -); -const iexec = new IExec({ - ethProvider, -}); -const protectedDataAddress = '0x123abc...'; -// ---cut--- -// Create & Sign a request order with protected data -const requestorderToSign = await iexec.order.createRequestorder({ - app: '0x456def...', // The iApp address - category: 0, - appmaxprice: 10, // Maximum price in nRLC - dataset: protectedDataAddress, // Protected data address - datasetmaxprice: 5, // Maximum price for dataset access - workerpool: '0xa5de76...', // ENS address for iExec's debug workerpool -}); -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 protected data orders -const datasetOrders = await iexec.orderbook.fetchDatasetOrderbook( - protectedDataAddress // Filter by specific dataset -); -if (datasetOrders.orders.length === 0) { - throw new Error( - 'No protectedData orders found for the specified protectedData' - ); -} - -// 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, - datasetorder: datasetOrders.orders[0].order, - workerpoolorder: workerpoolOrders.orders[0].order, -}); -``` - -### Using iExec CLI with Protected Data - -```bash -# Execute with protected data -iexec app run 0x456def... --dataset 0x123abc... -``` - ## Step 4: Retrieve Results -After execution completes, retrieve the results from the task. - -### Using DataProtector +This step is optional. Indeed, `processProtectedData` will automatically +download and decrypt the results for you. Nevertheless, if you want to retrieve +results from a completed task, you can do so as follows: ```ts twoslash import { IExecDataProtectorCore, getWeb3Provider } from '@iexec/dataprotector'; @@ -236,221 +124,6 @@ const taskResult = await dataProtectorCore.getResultFromCompletedTask({ }); ``` -### Using iExec CLI - -```bash -# Get the task ID from the execution result -TASK_ID="0x7ac398..." - -# Retrieve the result -iexec task show $TASK_ID - -# Retrieve a specific file from the result -iexec task show $TASK_ID --path "computed.json" -``` - -## Real-World Examples - -### Example 1: Data Analysis System - -```ts twoslash -import { IExecDataProtectorCore, getWeb3Provider } from '@iexec/dataprotector'; - -const web3Provider = getWeb3Provider('PRIVATE_KEY'); -const dataProtectorCore = new IExecDataProtectorCore(web3Provider); -// ---cut--- -// 1. Protect sensitive dataset -const { address: datasetAddress } = await dataProtectorCore.protectData({ - name: 'Customer Analytics Data', - data: { - customers: { - '0': { id: 1, purchases: 1500, category: 'premium' }, - '1': { id: 2, purchases: 800, category: 'standard' }, - '2': { id: 3, purchases: 2200, category: 'premium' }, - }, - }, -}); - -// 2. Grant access to analytics iApp -await dataProtectorCore.grantAccess({ - protectedData: datasetAddress, - authorizedApp: '0xanalytics...', // Analytics iApp address - authorizedUser: '0x789abc...', - pricePerAccess: 3, - numberOfAccess: 50, -}); - -// 3. Execute data analysis -const analysisResult = await dataProtectorCore.processProtectedData({ - protectedData: datasetAddress, - app: '0xanalytics...', - args: '--analyze-customer-segments --output-format json', - appMaxPrice: 10, -}); -``` - -### Example 2: Oracle Price Update - -```ts twoslash -import { IExecDataProtectorCore, getWeb3Provider } from '@iexec/dataprotector'; - -const web3Provider = getWeb3Provider('PRIVATE_KEY'); -const dataProtectorCore = new IExecDataProtectorCore(web3Provider); -// ---cut--- -// 1. Protect trading data -const { address: tradingDataAddress } = await dataProtectorCore.protectData({ - name: 'Trading Data', - data: { - trades: { - '2024-01-01': { price: 50000, volume: 100 }, - '2024-01-02': { price: 51000, volume: 150 }, - }, - }, -}); - -// 2. Grant access to oracle iApp -await dataProtectorCore.grantAccess({ - protectedData: tradingDataAddress, - authorizedApp: '0xoracle...', // Oracle iApp address - authorizedUser: '0x789abc...', - pricePerAccess: 5, - numberOfAccess: 100, -}); - -// 3. Execute oracle update -const oracleResult = await dataProtectorCore.processProtectedData({ - protectedData: tradingDataAddress, - app: '0xoracle...', - args: '--update-price-feed --asset ETH', - appMaxPrice: 10, -}); -``` - -### Example 3: Automated Payment Processing - -```ts twoslash -import { IExecDataProtectorCore, getWeb3Provider } from '@iexec/dataprotector'; - -const web3Provider = getWeb3Provider('PRIVATE_KEY'); -const dataProtectorCore = new IExecDataProtectorCore(web3Provider); -// ---cut--- -// 1. Protect payment data -const { address: paymentDataAddress } = await dataProtectorCore.protectData({ - name: 'Payment Data', - data: { - bankAccount: '1234567890', - routingNumber: '987654321', - accountHolder: 'John Doe', - monthlyAmount: 1000, - }, -}); - -// 2. Grant access to payment iApp -await dataProtectorCore.grantAccess({ - protectedData: paymentDataAddress, - authorizedApp: '0xpayment...', // Payment iApp address - authorizedUser: '0x789abc...', - pricePerAccess: 2, - numberOfAccess: 12, // Monthly payments -}); - -// 3. Execute payment processing -const paymentResult = await dataProtectorCore.processProtectedData({ - protectedData: paymentDataAddress, - app: '0xpayment...', - args: '--process-monthly-payment', - secrets: { - 1: 'bank-api-key', - }, - appMaxPrice: 8, -}); -``` - -## Best Practices - -### 1. Always Grant Access Before Execution - -```ts twoslash -import { IExecDataProtectorCore, getWeb3Provider } from '@iexec/dataprotector'; - -const web3Provider = getWeb3Provider('PRIVATE_KEY'); -const dataProtectorCore = new IExecDataProtectorCore(web3Provider); -const protectedDataAddress = '0x123abc...'; -// ---cut--- -// Grant access first -await dataProtectorCore.grantAccess({ - protectedData: protectedDataAddress, - authorizedApp: '0x456def...', - authorizedUser: '0x789abc...', - pricePerAccess: 5, - numberOfAccess: 10, -}); - -const result = await dataProtectorCore.processProtectedData({ - protectedData: protectedDataAddress, - app: '0x456def...', - appMaxPrice: 10, -}); -``` - -### 2. Monitor Access Usage - -```ts twoslash -import { IExecDataProtectorCore, getWeb3Provider } from '@iexec/dataprotector'; - -const web3Provider = getWeb3Provider('PRIVATE_KEY'); -const dataProtectorCore = new IExecDataProtectorCore(web3Provider); -// ---cut--- -// Check access usage regularly -const grantedAccess = await dataProtectorCore.getGrantedAccess({ - protectedData: '0x123abc...', - authorizedApp: '0x456def...', - authorizedUser: '0x789abc...', -}); - -console.log('Remaining access:', grantedAccess.count); -``` - -### 3. Use Appropriate Price Limits - -```ts twoslash -import { IExecDataProtectorCore, getWeb3Provider } from '@iexec/dataprotector'; - -const web3Provider = getWeb3Provider('PRIVATE_KEY'); -const dataProtectorCore = new IExecDataProtectorCore(web3Provider); -// ---cut--- -// Set reasonable price limits -const result = await dataProtectorCore.processProtectedData({ - protectedData: '0x123abc...', - app: '0x456def...', - appMaxPrice: 10, // Set appropriate limit -}); -``` - -### 4. Handle Results Properly - -```ts twoslash -import { IExecDataProtectorCore, getWeb3Provider } from '@iexec/dataprotector'; - -const web3Provider = getWeb3Provider('PRIVATE_KEY'); -const dataProtectorCore = new IExecDataProtectorCore(web3Provider); -// ---cut--- -// Store task ID and retrieve results later -const result = await dataProtectorCore.processProtectedData({ - protectedData: '0x123abc...', - app: '0x456def...', - appMaxPrice: 10, -}); - -// Store task ID for later retrieval -const taskId = result.taskId; - -// Later, retrieve the result -const taskResult = await dataProtectorCore.getResultFromCompletedTask({ - taskId: taskId, -}); -``` - ## Next Steps Now that you understand how to use iApp with protected data: diff --git a/src/modules/helloWorld/ProtectData.vue b/src/modules/helloWorld/ProtectData.vue index d442bb1d..8e6000c2 100644 --- a/src/modules/helloWorld/ProtectData.vue +++ b/src/modules/helloWorld/ProtectData.vue @@ -19,13 +19,7 @@

You will sign three things:

  1. A transaction to create the protected data
  2. -
  3. - A message signature to prove your identity to the production SMS -
  4. -
  5. - A message signature to prove your identity to the debug SMS (this - signature is only required during this Hello World tutorial) -
  6. +
  7. A message signature to prove your identity to the SMS
@@ -189,7 +183,6 @@ async function protectData() { secretText: contentToProtect.value, }, name: 'helloWorld', - allowDebug: true, }); console.log('createdProtectedData', createdProtectedData); diff --git a/src/references/dataProtector/dataProtectorCore/protectData.md b/src/references/dataProtector/dataProtectorCore/protectData.md index 973f233c..528f47fc 100644 --- a/src/references/dataProtector/dataProtectorCore/protectData.md +++ b/src/references/dataProtector/dataProtectorCore/protectData.md @@ -236,34 +236,6 @@ const protectedData = await dataProtectorCore.protectData({ }); ``` -### allowDebug - -**Type:** `boolean` -**Default:** `false` - -Allow using the protected data in TEE debug apps. - -```ts twoslash -import { IExecDataProtectorCore, getWeb3Provider } from '@iexec/dataprotector'; - -const web3Provider = getWeb3Provider('PRIVATE_KEY'); -const dataProtectorCore = new IExecDataProtectorCore(web3Provider); -// ---cut--- -const protectedData = await dataProtectorCore.protectData({ - name: 'myEmail', - data: { - email: 'example@gmail.com', - }, - allowDebug: true, // [!code focus] -}); -``` - -::: tip - -This param is for development only. - -::: - ### onStatusUpdate **Type:** `OnStatusUpdateFn` diff --git a/src/references/iapp-generator.md b/src/references/iapp-generator.md index c653c8b3..0b22b79a 100644 --- a/src/references/iapp-generator.md +++ b/src/references/iapp-generator.md @@ -17,13 +17,6 @@ confidential computing setup. **iApp Generator** builds confidential applications. Your code runs in Intel SGX/TDX secure enclaves where data stays private during processing. -### What you get - -- **Project scaffolding** - Complete setup, ready to deploy -- **Local testing** - Debug in simulation mode before going live -- **Simple deployment** - One command deploys to TEE workers -- **Data integration** - Works with encrypted datasets out of the box - ### What iApp Generator Provides - ✅ **Project scaffolding** - Complete iApp structure ready to deploy @@ -53,7 +46,7 @@ Once you've built your first iApp, level up with these practical guides: execution issues - **[App Access Control and Pricing](/guides/build-iapp/manage-access)** - Control who can use your iApp -- **[How to Get and Decrypt Results](/guides/build-iapp/how-to-get-and-decrypt-results)** - +- **[How to Get and Decrypt Results](/guides/build-iapp/download-and-decrypt-results)** - Retrieve and use outputs ### 3. **Explore Advanced Features** diff --git a/src/references/iapp-generator/building-your-iexec-app.md b/src/references/iapp-generator/building-your-iexec-app.md index f3314326..f8bdf98a 100644 --- a/src/references/iapp-generator/building-your-iexec-app.md +++ b/src/references/iapp-generator/building-your-iexec-app.md @@ -68,19 +68,10 @@ Follow the prompts to specify: - **Project name** – Creates a folder for your project files. - **Language** – Choose between JavaScript, Python, etc. -- **Project mode** – Choose Basic (Hello-World setup) or Advanced (full debug - capabilities). +- **Project mode** – Choose Basic (Hello-World setup) or Advanced mode. ### ⚙ Configure -::: info - -We are going to create and test our iApp locally. In **debug mode**, you can -quickly iterate and troubleshoot your code. Logs and output files are available -for debugging, helping you refine your app before moving to production. - -::: - You'll set up: - **Arguments (Args)** – Public parameters for your iApp. @@ -186,7 +177,7 @@ discontinuity. ### 🚀 Next Steps -Your iApp is now running in **debug mode** on iExec! +Your iApp is now running on iExec! Once your application is **stable** and **functional**, you can: diff --git a/src/references/iapp-generator/getting-started.md b/src/references/iapp-generator/getting-started.md index 6d381e56..9614cc5a 100644 --- a/src/references/iapp-generator/getting-started.md +++ b/src/references/iapp-generator/getting-started.md @@ -11,11 +11,27 @@ description: Before using the iApp Generator, make sure you have: -\- [**Node.js**](https://nodejs.org/en/) version 20 or higher - -\- **Docker / Docker hub account** - -\- **Docker Buildx** _(for macOS users, check AMD64 compatibility)_ +
+
+
+ 📦 Node.js v20+ +
+ Download → +
+
+
+ 🐳 Docker installed +
+ Download → +
+ +
+
+ 🐳 DockerHub Account +
+ Sign Up → +
+
::: tip 🔍 Verify Docker Compatibility From 7ca2d4bef65123fa7a6f7f9159dc7930cd5dfa88 Mon Sep 17 00:00:00 2001 From: Le-Caignec Date: Mon, 18 Aug 2025 19:50:29 +0200 Subject: [PATCH 02/33] chore: Remove outdated CLI examples and batch operation section from payment execution guide - Deleted sections on using CLI with RLC and vouchers, as well as the batch operations example to streamline the documentation. - Focused on enhancing clarity and relevance of payment methods in the guide. --- src/guides/use-iapp/how-to-pay-executions.md | 52 -------------------- 1 file changed, 52 deletions(-) diff --git a/src/guides/use-iapp/how-to-pay-executions.md b/src/guides/use-iapp/how-to-pay-executions.md index e3d0fcbe..a9d1cb79 100644 --- a/src/guides/use-iapp/how-to-pay-executions.md +++ b/src/guides/use-iapp/how-to-pay-executions.md @@ -73,19 +73,6 @@ const result = await dataProtectorCore.processProtectedData({ }); ``` -### Using CLI with RLC - -```bash -# Execute with RLC payment -iexec app run 0x456def... --protectedData 0xa0c15e... - -# Check your balance -iexec account show - -# Deposit RLC -iexec account deposit 100 -``` - ## Method 2: Paying with Vouchers Vouchers are pre-funded payment instruments that simplify the payment process @@ -150,16 +137,6 @@ be used in combination with `useVoucher: true`. ::: -#### CLI with Vouchers - -```bash -# Use your own voucher -iexec app run 0x456def... --protectedData 0xa0c15e... --useVoucher - -# Use someone else's voucher -iexec app run 0x456def... --protectedData 0xa0c15e... --useVoucher --voucherOwner 0x5714eB... -``` - ## Understanding Pricing ### Cost Components @@ -263,35 +240,6 @@ const result = await dataProtectorCore.processProtectedData({ }); ``` -### 4. Batch Operations - -Group multiple executions to optimize costs: - -```ts twoslash -import { IExecDataProtectorCore, getWeb3Provider } from '@iexec/dataprotector'; - -const web3Provider = getWeb3Provider('PRIVATE_KEY'); -const dataProtectorCore = new IExecDataProtectorCore(web3Provider); -// ---cut--- -// Execute multiple tasks efficiently -const tasks = [ - { protectedData: '0x123abc...', app: '0x456def...' }, - { protectedData: '0x124abc...', app: '0x456def...' }, -]; - -const results = await Promise.all( - tasks.map((task) => - dataProtectorCore.processProtectedData({ - ...task, - dataMaxPrice: 5, - appMaxPrice: 3, - workerpoolMaxPrice: 2, - useVoucher: true, - }) - ) -); -``` - ## Payment Troubleshooting ### Insufficient Balance From bee1b91f5a59101d826cdb391c350cd42d3368e0 Mon Sep 17 00:00:00 2001 From: Le-Caignec Date: Mon, 18 Aug 2025 22:59:32 +0200 Subject: [PATCH 03/33] refactor: Update iApp execution guides and remove outdated content - Renamed and reorganized sections in the sidebar for clarity, replacing 'Different Ways to Execute an iApp' with 'Run iApp' and 'Use iApp with Protected Data' with 'Run iApp with Inputs'. - Updated links in the 'Getting Started' guide to reflect the new structure. - Added new guides for 'Run an iApp' and 'Run iApp with Inputs', detailing execution methods and input handling. - Removed the outdated 'Use iApp with Protected Data' guide to streamline documentation. --- .vitepress/sidebar.ts | 12 +- README.md | 1 + .../use-iapp/add-inputs-to-execution.md | 124 ---- .../use-iapp/different-ways-to-execute.md | 40 -- src/guides/use-iapp/getting-started.md | 10 +- src/guides/use-iapp/how-to-pay-executions.md | 6 +- src/guides/use-iapp/run-iapp-with-inputs.md | 626 ++++++++++++++++++ src/guides/use-iapp/run-iapp.md | 256 +++++++ .../use-iapp/use-iapp-with-protected-data.md | 135 ---- 9 files changed, 893 insertions(+), 317 deletions(-) delete mode 100644 src/guides/use-iapp/add-inputs-to-execution.md delete mode 100644 src/guides/use-iapp/different-ways-to-execute.md create mode 100644 src/guides/use-iapp/run-iapp-with-inputs.md create mode 100644 src/guides/use-iapp/run-iapp.md delete mode 100644 src/guides/use-iapp/use-iapp-with-protected-data.md diff --git a/.vitepress/sidebar.ts b/.vitepress/sidebar.ts index 87e2e559..44e42851 100644 --- a/.vitepress/sidebar.ts +++ b/.vitepress/sidebar.ts @@ -241,16 +241,12 @@ export function getSidebar() { link: '/guides/use-iapp/getting-started', }, { - text: 'Different Ways to Execute an iApp', - link: '/guides/use-iapp/different-ways-to-execute', + text: 'Run iApp', + link: '/guides/use-iapp/run-iapp', }, { - text: 'Use iApp with Protected Data', - link: '/guides/use-iapp/use-iapp-with-protected-data', - }, - { - text: 'Add Inputs to the Execution', - link: '/guides/use-iapp/add-inputs-to-execution', + text: 'Run iApp with Inputs', + link: '/guides/use-iapp/run-iapp-with-inputs', }, { text: 'How to Pay the Executions', diff --git a/README.md b/README.md index 7fd53bf4..72e617d0 100644 --- a/README.md +++ b/README.md @@ -252,3 +252,4 @@ for input parameters: - Talk about ENS on Bellecour(it's not supported on arbitrum) - Rework Advanced iApp building guides. (from "old" protocol doc) - Rework src\get-started\protocol\oracle.md (transfer to guide or rewrite) +- Talk about iApp secret diff --git a/src/guides/use-iapp/add-inputs-to-execution.md b/src/guides/use-iapp/add-inputs-to-execution.md deleted file mode 100644 index 3d88eb68..00000000 --- a/src/guides/use-iapp/add-inputs-to-execution.md +++ /dev/null @@ -1,124 +0,0 @@ ---- -title: Add Inputs to iApp Execution -description: - Learn how to provide arguments, files, secrets, and other inputs to iApp - executions ---- - -# 📥 Add Inputs to iApp Execution - -iApp can accept various types of inputs to customize their behavior and provide -necessary data for processing. This guide covers all the different ways to add -inputs to your iApp executions using various iExec tools and SDK. - -## Types of Inputs - -iExec supports several types of inputs for iApp executions: - -1. **Arguments**: Command-line arguments passed to the application -2. **Input Files**: URLs to public files that the app can download -3. **Secrets**: Sensitive data like API keys stored securely -4. **Protected Data**: Encrypted data processed within the TEE - -## Adding Command-Line Arguments - -Command-line arguments are passed as a string to the iApp and are visible on the -blockchain. - -```ts twoslash -import { IExecDataProtectorCore, getWeb3Provider } from '@iexec/dataprotector'; - -const web3Provider = getWeb3Provider('PRIVATE_KEY'); -const dataProtectorCore = new IExecDataProtectorCore(web3Provider); -// ---cut--- -// Process protected data with arguments -const result = await dataProtectorCore.processProtectedData({ - protectedData: '0x123abc...', - app: '0x456def...', - args: '--input-path data/input.csv --output-format json --verbose', -}); -``` - -## Adding Input Files - -Input files are URLs to public files that the iApp can download during -execution. - -```ts twoslash -import { IExecDataProtectorCore, getWeb3Provider } from '@iexec/dataprotector'; - -const web3Provider = getWeb3Provider('PRIVATE_KEY'); -const dataProtectorCore = new IExecDataProtectorCore(web3Provider); -// ---cut--- -// Process protected data with input files -const result = await dataProtectorCore.processProtectedData({ - protectedData: '0x123abc...', - app: '0x456def...', - inputFiles: [ - 'https://raw.githubusercontent.com/user/repo/main/config.json', - 'https://example.com/public-data.csv', - ], -}); -``` - -## Adding Secrets - -Secrets are sensitive data like API keys, passwords, or tokens that are stored -securely and made available to the iApp as environment variables. - -### Using DataProtector - -```ts twoslash -import { IExecDataProtectorCore, getWeb3Provider } from '@iexec/dataprotector'; - -const web3Provider = getWeb3Provider('PRIVATE_KEY'); -const dataProtectorCore = new IExecDataProtectorCore(web3Provider); -// ---cut--- -// Process protected data with secrets -const result = await dataProtectorCore.processProtectedData({ - protectedData: '0x123abc...', - app: '0x456def...', - secrets: { - 1: 'openai-api-key', - 2: 'database-password', - }, -}); -``` - -## Specifying File Paths in Protected Data - -When working with protected data that contains multiple files, you can specify -which file to process. - -### Using DataProtector - -```ts twoslash -import { IExecDataProtectorCore, getWeb3Provider } from '@iexec/dataprotector'; - -const web3Provider = getWeb3Provider('PRIVATE_KEY'); -const dataProtectorCore = new IExecDataProtectorCore(web3Provider); -// ---cut--- -// Process protected data with specific path -const result = await dataProtectorCore.processProtectedData({ - protectedData: '0x123abc...', - app: '0x456def...', - path: 'data/input.csv', -}); - -// Get result with specific path -const taskResult = await dataProtectorCore.getResultFromCompletedTask({ - taskId: '0x7ac398...', - path: 'output/analysis.json', -}); -``` - -## Next Steps - -Now that you understand how to add inputs to iApp executions: - -- Learn about - [Using iApp with Protected Data](/guides/use-iapp/use-iapp-with-protected-data) -- Explore - [Different Ways to Execute](/guides/use-iapp/different-ways-to-execute) iApp -- Check out our - [How to Pay for Executions](/guides/use-iapp/how-to-pay-executions) guide diff --git a/src/guides/use-iapp/different-ways-to-execute.md b/src/guides/use-iapp/different-ways-to-execute.md deleted file mode 100644 index eb549b19..00000000 --- a/src/guides/use-iapp/different-ways-to-execute.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -title: Different Ways to Execute iApp -description: Learn about various methods for executing iApp on the iExec network ---- - -# ⚡ Different Ways to Execute iApp - -There are multiple ways to execute iApp on the iExec network. This guide covers -the basic execution methods. For advanced features like protected data, -arguments, and input files, see the dedicated guides. - -## Using the iApp Generator CLI - -The iApp Generator CLI provides a streamlined way to execute iApp, especially -for developers who have built their own iApp. - -> **Note**: For installation instructions, see the -> [iApp Generator Getting Started guide](/references/iapp-generator/getting-started). - -### Basic Execution - -```bash -# Execute a deployed iApp -iapp run 0x456def... -``` - -### Testing Before Execution - -```bash -# Test the iApp locally first -iapp test -``` - -## Next Steps - -- Learn how to - [use iApp with protected data](/guides/use-iapp/use-iapp-with-protected-data) -- Discover how to - [add inputs to execution](/guides/use-iapp/add-inputs-to-execution) -- Understand [how to pay for executions](/guides/use-iapp/how-to-pay-executions) diff --git a/src/guides/use-iapp/getting-started.md b/src/guides/use-iapp/getting-started.md index 38a3a9ef..050d08ab 100644 --- a/src/guides/use-iapp/getting-started.md +++ b/src/guides/use-iapp/getting-started.md @@ -72,11 +72,9 @@ section. For step-by-step instructions, check out these guides: -- **[Different Ways to Execute](/guides/use-iapp/different-ways-to-execute)** - - iExec CLI, lib, and other execution methods -- **[Use iApp with Protected Data](/guides/use-iapp/use-iapp-with-protected-data)** - - Working with sensitive data securely -- **[Add Inputs to Execution](/guides/use-iapp/add-inputs-to-execution)** - How - to provide data and parameters to iApp +- **[Run iApp](/guides/use-iapp/run-iapp)** - iExec CLI, lib, and other + execution methods +- **[Run iApp with Inputs](/guides/use-iapp/run-iapp-with-inputs)** - How to + provide data and parameters to iApp - **[How to Pay for Executions](/guides/use-iapp/how-to-pay-executions)** - Understanding costs and payment options diff --git a/src/guides/use-iapp/how-to-pay-executions.md b/src/guides/use-iapp/how-to-pay-executions.md index a9d1cb79..bba62495 100644 --- a/src/guides/use-iapp/how-to-pay-executions.md +++ b/src/guides/use-iapp/how-to-pay-executions.md @@ -438,10 +438,8 @@ const executeWithPaymentRetry = async (params: any, maxRetries = 3) => { Now that you understand payment methods: -- Learn about - [Adding Inputs to Execution](/guides/use-iapp/add-inputs-to-execution) -- Explore - [Using iApp with Protected Data](/guides/use-iapp/use-iapp-with-protected-data) +- Learn about [Run iApp with Inputs](/guides/use-iapp/run-iapp-with-inputs) +- Explore [Getting Started with iApp](/guides/use-iapp/getting-started) - Review the pricing information above for detailed cost analysis diff --git a/src/guides/use-iapp/run-iapp.md b/src/guides/use-iapp/run-iapp.md new file mode 100644 index 00000000..9534625f --- /dev/null +++ b/src/guides/use-iapp/run-iapp.md @@ -0,0 +1,256 @@ +--- +title: Run an iApp +description: + Learn about various methods for executing iApp on the iExec network, including + CLI and SDK approaches +--- + +# ⚡ Run an iApp + +There are multiple ways to execute an iApp on the iExec network. An iApp can be: + +- **Self-sufficient** - Basic execution without additional inputs +- **Data-dependent** - Requires protected data, secrets, input files, or + command-line arguments + +This guide covers the basic execution methods. For advanced features like +protected data, arguments, and input files, see the dedicated guides. + +## Using the iApp Generator CLI + +The iApp Generator CLI provides a streamlined way to execute iApp, especially +for developers who have built their own iApp. + +> **Note**: For installation instructions, see the +> [iApp Generator Getting Started guide](/references/iapp-generator/getting-started). + + + + + +## Next Steps + +- Discover how to + [run an iApp with inputs](/guides/use-iapp/run-iapp-with-inputs) +- Understand [how to pay for executions](/guides/use-iapp/how-to-pay-executions) + + diff --git a/src/guides/use-iapp/use-iapp-with-protected-data.md b/src/guides/use-iapp/use-iapp-with-protected-data.md deleted file mode 100644 index fb597265..00000000 --- a/src/guides/use-iapp/use-iapp-with-protected-data.md +++ /dev/null @@ -1,135 +0,0 @@ ---- -title: Use iApp with Protected Data -description: - Learn how to securely process protected data using iApp on the iExec network ---- - -# 🔒 Use iApp with Protected Data - -Protected data is the cornerstone of privacy-preserving computation on iExec. -This guide shows you how to use iApp with protected data, from granting access -to processing and retrieving results. - -## Understanding Protected Data and iApp - -Protected data is encrypted information that can only be processed by authorized -iApp within Trusted Execution Environments (TEEs). The data remains confidential -throughout the entire computation process. - -### The Workflow - -1. **Protect Your Data**: Encrypt sensitive information using the Data Protector -2. **Grant Access**: Authorize specific iApp to process your data -3. **Execute iApp**: Run the iApp with your protected data -4. **Retrieve Results**: Get the computation results while data remains private - -## Step 1: Protect Your Data - -Before using an iApp, you need to protect your sensitive data. - -### Basic Data Protection - -```ts twoslash -import { IExecDataProtectorCore, getWeb3Provider } from '@iexec/dataprotector'; - -const web3Provider = getWeb3Provider('PRIVATE_KEY'); -const dataProtectorCore = new IExecDataProtectorCore(web3Provider); -// ---cut--- -// Protect your data -const { address: protectedDataAddress } = await dataProtectorCore.protectData({ - name: 'My Sensitive Data', - data: { - email: 'user@example.com', - apiKey: 'secret-api-key-12345', - preferences: { - theme: 'dark', - notifications: true, - }, - }, -}); -``` - -## Step 2: Grant Access to iApp - -iApp need explicit authorization to access your protected data. - -### Grant Access to a Specific iApp - -```ts twoslash -import { IExecDataProtectorCore, getWeb3Provider } from '@iexec/dataprotector'; - -const web3Provider = getWeb3Provider('PRIVATE_KEY'); -const dataProtectorCore = new IExecDataProtectorCore(web3Provider); -// ---cut--- -// Grant access to an iApp -const grantedAccess = await dataProtectorCore.grantAccess({ - protectedData: '0x123abc...', - authorizedApp: '0x456def...', // The iApp address - authorizedUser: '0x789abc...', // Your wallet address - pricePerAccess: 5, // Price per access in nRLC - numberOfAccess: 10, // Number of allowed accesses -}); -``` - -### Check Granted Access - -```ts twoslash -import { IExecDataProtectorCore, getWeb3Provider } from '@iexec/dataprotector'; - -const web3Provider = getWeb3Provider('PRIVATE_KEY'); -const dataProtectorCore = new IExecDataProtectorCore(web3Provider); -// ---cut--- -// Check what access you've granted -const grantedAccessList = await dataProtectorCore.getGrantedAccess({ - protectedData: '0x123abc...', - authorizedApp: '0x456def...', - authorizedUser: '0x789abc...', -}); -``` - -## Step 3: Execute iApp with Protected Data - -Once access is granted, you can execute the iApp with your protected data. - -```ts twoslash -import { IExecDataProtectorCore, getWeb3Provider } from '@iexec/dataprotector'; - -const web3Provider = getWeb3Provider('PRIVATE_KEY'); -const dataProtectorCore = new IExecDataProtectorCore(web3Provider); -// ---cut--- -// Execute iApp with protected data -const result = await dataProtectorCore.processProtectedData({ - protectedData: '0x123abc...', - app: '0x456def...', // The iApp address -}); -``` - -## Step 4: Retrieve Results - -This step is optional. Indeed, `processProtectedData` will automatically -download and decrypt the results for you. Nevertheless, if you want to retrieve -results from a completed task, you can do so as follows: - -```ts twoslash -import { IExecDataProtectorCore, getWeb3Provider } from '@iexec/dataprotector'; - -const web3Provider = getWeb3Provider('PRIVATE_KEY'); -const dataProtectorCore = new IExecDataProtectorCore(web3Provider); -const taskId = '0x7ac398...'; - -// ---cut--- -// Retrieve the result -const taskResult = await dataProtectorCore.getResultFromCompletedTask({ - taskId: taskId, -}); -``` - -## Next Steps - -Now that you understand how to use iApp with protected data: - -- Learn about - [Different Ways to Execute](/guides/use-iapp/different-ways-to-execute) iApp -- Explore [How to Pay for Executions](/guides/use-iapp/how-to-pay-executions) -- Check out our - [Add Inputs to Execution](/guides/use-iapp/add-inputs-to-execution) guide From 1c8d83f786b44354a6c32e600587810d61f2662b Mon Sep 17 00:00:00 2001 From: Le-Caignec Date: Tue, 19 Aug 2025 08:18:31 +0200 Subject: [PATCH 04/33] refactor: Improve formatting and clarity in iApp execution guide - Enhanced readability by breaking long lines into multiple lines in the 'Choosing Between Toolkit' section. - Maintained the content integrity while improving the overall presentation of the guide. --- src/guides/use-iapp/run-iapp-with-inputs.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/guides/use-iapp/run-iapp-with-inputs.md b/src/guides/use-iapp/run-iapp-with-inputs.md index 15e886ff..f8a71fd5 100644 --- a/src/guides/use-iapp/run-iapp-with-inputs.md +++ b/src/guides/use-iapp/run-iapp-with-inputs.md @@ -14,9 +14,13 @@ DataProtector turnkey toolkit. ## Choosing Between Toolkit -**DataProtector SDK Toolkit**: Always requires protected data. Best for Node.js/frontend projects and production environments. Offers programmatic control, integration, error handling, and batch operations. +**DataProtector SDK Toolkit**: Always requires protected data. Best for +Node.js/frontend projects and production environments. Offers programmatic +control, integration, error handling, and batch operations. -**iApp Generator CLI Toolkit**: No protected data required to run an iApp. Perfect for testing, development, and quick prototyping. Provides immediate execution without coding. +**iApp Generator CLI Toolkit**: No protected data required to run an iApp. +Perfect for testing, development, and quick prototyping. Provides immediate +execution without coding. ## Possible of Inputs From 889b38267417c61879b12d2c3ff61512ba6b73fe Mon Sep 17 00:00:00 2001 From: Le-Caignec Date: Tue, 19 Aug 2025 11:08:44 +0200 Subject: [PATCH 05/33] docs: Enhance iApp execution guide with structured methods and code examples - Added a new section outlining when to use each execution method: iApp Generator CLI, iExec Library, and iExec CLI. - Introduced detailed code examples for using the iExec SDK Library and iExec CLI for executing iApps. - Improved overall organization and clarity of the guide to assist users in selecting the appropriate execution method. --- src/guides/use-iapp/run-iapp.md | 63 ++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/src/guides/use-iapp/run-iapp.md b/src/guides/use-iapp/run-iapp.md index 9534625f..6999435d 100644 --- a/src/guides/use-iapp/run-iapp.md +++ b/src/guides/use-iapp/run-iapp.md @@ -16,7 +16,13 @@ There are multiple ways to execute an iApp on the iExec network. An iApp can be: This guide covers the basic execution methods. For advanced features like protected data, arguments, and input files, see the dedicated guides. -## Using the iApp Generator CLI +## When to Use Each Method + +- **iApp Generator CLI**: For developers who have built their own iApp +- **iExec Library**: For JavaScript applications and web3 integration +- **iExec CLI**: For quick testing and automation scripts + +## Method 1: Using the iApp Generator CLI The iApp Generator CLI provides a streamlined way to execute iApp, especially for developers who have built their own iApp. @@ -50,6 +56,61 @@ for developers who have built their own iApp. /> +## Method 2: Using the iExec SDK Library + +The iExec SDK provides a modular JavaScript interface for executing iApp. + +```ts twoslash +import { IExec, utils } from 'iexec'; + +const ethProvider = utils.getSignerFromPrivateKey( + 'bellecour', // blockchain node URL + 'PRIVATE_KEY' +); +const iexec = new IExec({ + ethProvider, +}); +// ---cut--- +// Create & Sign a request order +const requestorderToSign = await iexec.order.createRequestorder({ + app: '0x456def...', // The iApp address + category: 0, +}); +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, +}); +``` + +## Method 3: Using the iExec CLI + +The iExec CLI is perfect for quick executions and automation scripts. + +```bash +# Execute an iApp +iexec app run 0x456def... +``` + ## Next Steps - Discover how to From 638787138509370ca72e8fce61186cedc566e51f Mon Sep 17 00:00:00 2001 From: Le-Caignec Date: Tue, 19 Aug 2025 11:35:57 +0200 Subject: [PATCH 06/33] docs: Update iApp guide titles for consistency and clarity --- src/guides/build-iapp/build-&-deploy.md | 2 +- src/guides/use-iapp/run-iapp.md | 10 ---------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/src/guides/build-iapp/build-&-deploy.md b/src/guides/build-iapp/build-&-deploy.md index 459bbe3e..db3d97ae 100644 --- a/src/guides/build-iapp/build-&-deploy.md +++ b/src/guides/build-iapp/build-&-deploy.md @@ -4,7 +4,7 @@ description: How to create a confidential iExec application and deploy it on iExec protocol --- -# Create and Deploy an iApp +# Build and Deploy an iApp iApp (iExec Applications) are decentralized applications that run on the iExec network. They use confidential computing to ensure data privacy and security diff --git a/src/guides/use-iapp/run-iapp.md b/src/guides/use-iapp/run-iapp.md index 6999435d..296a7e22 100644 --- a/src/guides/use-iapp/run-iapp.md +++ b/src/guides/use-iapp/run-iapp.md @@ -20,7 +20,6 @@ protected data, arguments, and input files, see the dedicated guides. - **iApp Generator CLI**: For developers who have built their own iApp - **iExec Library**: For JavaScript applications and web3 integration -- **iExec CLI**: For quick testing and automation scripts ## Method 1: Using the iApp Generator CLI @@ -102,15 +101,6 @@ const taskId = await iexec.order.matchOrders({ }); ``` -## Method 3: Using the iExec CLI - -The iExec CLI is perfect for quick executions and automation scripts. - -```bash -# Execute an iApp -iexec app run 0x456def... -``` - ## Next Steps - Discover how to From b9d6d4162df432b4b8f8dd633d19ef670f21b54f Mon Sep 17 00:00:00 2001 From: Le-Caignec Date: Tue, 19 Aug 2025 12:29:06 +0200 Subject: [PATCH 07/33] docs: Update iApp guides to reflect new testing and deployment structure - Renamed 'Build and Deploy' to 'Build and Test' in navigation and sidebar for consistency. - Added a new guide for 'Build and Test an iApp' detailing the creation and testing process. - Introduced a new guide for 'Deploy and Run an iApp' covering deployment methods and execution on the iExec network. - Updated links in existing documentation to align with the new guide structure. --- .vitepress/config.ts | 2 +- .vitepress/sidebar.ts | 8 +- src/get-started/overview/what-is-iexec.md | 2 +- .../{build-&-deploy.md => build-&-test.md} | 172 +------ src/guides/build-iapp/deploy-&-run.md | 454 ++++++++++++++++++ src/index.md | 2 +- 6 files changed, 469 insertions(+), 171 deletions(-) rename src/guides/build-iapp/{build-&-deploy.md => build-&-test.md} (63%) create mode 100644 src/guides/build-iapp/deploy-&-run.md diff --git a/.vitepress/config.ts b/.vitepress/config.ts index 8714f543..b893e811 100644 --- a/.vitepress/config.ts +++ b/.vitepress/config.ts @@ -101,7 +101,7 @@ export default withMermaid( // https://vitepress.dev/reference/default-theme-config nav: [ { text: 'Get Started', link: '/get-started/welcome' }, - { text: 'Guides', link: '/guides/build-iapp/build-&-deploy' }, + { text: 'Guides', link: '/guides/build-iapp/build-&-test' }, { text: 'References', link: '/references/dataProtector' }, { component: 'ChainSelector', diff --git a/.vitepress/sidebar.ts b/.vitepress/sidebar.ts index 44e42851..ee93d804 100644 --- a/.vitepress/sidebar.ts +++ b/.vitepress/sidebar.ts @@ -166,8 +166,12 @@ export function getSidebar() { text: 'BUILD YOUR iAPP', items: [ { - text: 'Build and Deploy', - link: '/guides/build-iapp/build-&-deploy', + text: 'Build and Test', + link: '/guides/build-iapp/build-&-test', + }, + { + text: 'Deploy and Run', + link: '/guides/build-iapp/deploy-&-run', }, { text: 'Manage Access', diff --git a/src/get-started/overview/what-is-iexec.md b/src/get-started/overview/what-is-iexec.md index bd416f56..a88710ee 100644 --- a/src/get-started/overview/what-is-iexec.md +++ b/src/get-started/overview/what-is-iexec.md @@ -10,7 +10,7 @@ description: iExec is a **decentralized confidential computing toolkit** that helps developers build privacy-preserving applications. -## The Protocol (Simple Version) +## SpeedRun The Protocol ### Step 1: Protect Data diff --git a/src/guides/build-iapp/build-&-deploy.md b/src/guides/build-iapp/build-&-test.md similarity index 63% rename from src/guides/build-iapp/build-&-deploy.md rename to src/guides/build-iapp/build-&-test.md index db3d97ae..2e96bb3c 100644 --- a/src/guides/build-iapp/build-&-deploy.md +++ b/src/guides/build-iapp/build-&-test.md @@ -4,7 +4,7 @@ description: How to create a confidential iExec application and deploy it on iExec protocol --- -# Build and Deploy an iApp +# Build and Test an iApp iApp (iExec Applications) are decentralized applications that run on the iExec network. They use confidential computing to ensure data privacy and security @@ -237,171 +237,11 @@ specify your app version, and push both standard and TEE-compatible images: /> - diff --git a/src/guides/build-iapp/deploy-&-run.md b/src/guides/build-iapp/deploy-&-run.md new file mode 100644 index 00000000..4367d151 --- /dev/null +++ b/src/guides/build-iapp/deploy-&-run.md @@ -0,0 +1,454 @@ +--- +title: Run an iApp +description: + Learn about various methods for executing iApp on the iExec network, including + CLI and SDK approaches +--- + +# Deploy and Run an iApp + +After your tests pass and the package is built, you can deploy your iApp to a +supported network. During deployment, you'll enter your DockerHub credentials, +specify your app version, and push both standard and TEE-compatible images: + + + + + +# ⚡ Run an iApp + +There are multiple ways to execute an iApp on the iExec network. An iApp can be: + +- **Self-sufficient** - Basic execution without additional inputs +- **Data-dependent** - Requires protected data, secrets, input files, or + command-line arguments + +This guide covers the basic execution methods. For advanced features like +protected data, arguments, and input files, see the dedicated guides. + +## Using the iApp Generator Toolkit + +The iApp Generator CLI provides a streamlined way to execute iApp, especially +for developers who have built their own iApp. + +> **Note**: For installation instructions, see the +> [iApp Generator Getting Started guide](/references/iapp-generator/getting-started). + + + + + +## Next Steps + +- Discover how to + [run an iApp with inputs](/guides/use-iapp/run-iapp-with-inputs) +- Understand [how to pay for executions](/guides/use-iapp/how-to-pay-executions) + + diff --git a/src/index.md b/src/index.md index dbd9dbb9..100648f1 100644 --- a/src/index.md +++ b/src/index.md @@ -31,7 +31,7 @@ features: details: iApp Generator builds confidential applications that run in secure TEEs. Custom confidentiality integration without managing infrastructure. - link: /guides/build-iapp/build-&-deploy + link: /guides/build-iapp/build-&-test - icon: ⚡ title: Use iApp details: From 0ce89134f33c93d309c6e8803756013084fc9f93 Mon Sep 17 00:00:00 2001 From: Le-Caignec Date: Tue, 19 Aug 2025 12:39:49 +0200 Subject: [PATCH 08/33] docs: Revise iApp deployment and execution guides for clarity and structure - Removed outdated deployment examples from the 'Build and Test' guide to streamline content. - Enhanced the 'Deploy and Run' guide with a clearer introduction and restructured sections for better flow. - Updated headings for consistency and improved readability throughout the documentation. --- src/guides/build-iapp/build-&-test.md | 32 --------------------------- src/guides/build-iapp/deploy-&-run.md | 11 +++++---- 2 files changed, 5 insertions(+), 38 deletions(-) diff --git a/src/guides/build-iapp/build-&-test.md b/src/guides/build-iapp/build-&-test.md index 2e96bb3c..8b05bf5e 100644 --- a/src/guides/build-iapp/build-&-test.md +++ b/src/guides/build-iapp/build-&-test.md @@ -205,38 +205,6 @@ The CLI will build a Docker image, run your app, and show you the results: :autoRestart="true" /> -## Deployment - -After your tests pass and the package is built, you can deploy your iApp to a -supported network. During deployment, you'll enter your DockerHub credentials, -specify your app version, and push both standard and TEE-compatible images: - - - - - ## Next Steps - When everything is ready diff --git a/src/guides/build-iapp/deploy-&-run.md b/src/guides/build-iapp/deploy-&-run.md index 4367d151..a18af1bc 100644 --- a/src/guides/build-iapp/deploy-&-run.md +++ b/src/guides/build-iapp/deploy-&-run.md @@ -7,6 +7,10 @@ description: # Deploy and Run an iApp +It's time to run your iApp! After building and testing, you'll need to deploy it to a supported network and then execute it. + +## Deploy your iApp + After your tests pass and the package is built, you can deploy your iApp to a supported network. During deployment, you'll enter your DockerHub credentials, specify your app version, and push both standard and TEE-compatible images: @@ -37,7 +41,7 @@ specify your app version, and push both standard and TEE-compatible images: /> -# ⚡ Run an iApp +## Run your iApp There are multiple ways to execute an iApp on the iExec network. An iApp can be: @@ -45,11 +49,6 @@ There are multiple ways to execute an iApp on the iExec network. An iApp can be: - **Data-dependent** - Requires protected data, secrets, input files, or command-line arguments -This guide covers the basic execution methods. For advanced features like -protected data, arguments, and input files, see the dedicated guides. - -## Using the iApp Generator Toolkit - The iApp Generator CLI provides a streamlined way to execute iApp, especially for developers who have built their own iApp. From 9e254399930ee33a806014e26d3d3f8f7370169c Mon Sep 17 00:00:00 2001 From: Le-Caignec Date: Tue, 19 Aug 2025 12:51:51 +0200 Subject: [PATCH 09/33] docs: Update iApp guides for improved clarity and consistency --- src/guides/build-iapp/build-&-test.md | 4 ++-- src/guides/build-iapp/deploy-&-run.md | 5 ++--- src/guides/build-iapp/manage-access.md | 6 +++--- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/guides/build-iapp/build-&-test.md b/src/guides/build-iapp/build-&-test.md index 8b05bf5e..37a2063d 100644 --- a/src/guides/build-iapp/build-&-test.md +++ b/src/guides/build-iapp/build-&-test.md @@ -1,7 +1,7 @@ --- -title: Create and Deploy an iApp +title: Build and Test an iApp description: - How to create a confidential iExec application and deploy it on iExec protocol + Learn how to build, test, and package your iExec application using the iApp Generator CLI tool --- # Build and Test an iApp diff --git a/src/guides/build-iapp/deploy-&-run.md b/src/guides/build-iapp/deploy-&-run.md index a18af1bc..f6ccfafe 100644 --- a/src/guides/build-iapp/deploy-&-run.md +++ b/src/guides/build-iapp/deploy-&-run.md @@ -1,8 +1,7 @@ --- -title: Run an iApp +title: Deploy and Run an iApp description: - Learn about various methods for executing iApp on the iExec network, including - CLI and SDK approaches + Deploy your iApp to supported networks and learn how to execute it using the iApp Generator CLI --- # Deploy and Run an iApp diff --git a/src/guides/build-iapp/manage-access.md b/src/guides/build-iapp/manage-access.md index a325c2a5..9d18e8c1 100644 --- a/src/guides/build-iapp/manage-access.md +++ b/src/guides/build-iapp/manage-access.md @@ -118,13 +118,13 @@ iexec wallet import ::: tip iApp Generator Users -If you used iApp Generator, you already have an `iexecconfig.json` file with a +If you used iApp Generator, you already have an `iapp.config.json` file with a generated private key. You can use this existing private key to initialize your wallet: ```bash -# Extract the private key from your `iexecconfig.json` -iexec wallet import +# Extract the private key from your `iapp.config.json` +iexec wallet import ``` ::: From d523212a4732b7079dd5686e177debd73ee43e58 Mon Sep 17 00:00:00 2001 From: Le-Caignec Date: Tue, 19 Aug 2025 13:11:00 +0200 Subject: [PATCH 10/33] docs: Enhance 'Deploy and Run' guide with deployment and run tracking details - Added sections explaining the creation of `deployments.json` and `runs.json` files for tracking deployments and runs on the iExec network. - Included JSON examples to illustrate the structure of the tracking files. - Updated next steps to guide users on managing access and debugging techniques. --- src/guides/build-iapp/deploy-&-run.md | 38 ++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/src/guides/build-iapp/deploy-&-run.md b/src/guides/build-iapp/deploy-&-run.md index f6ccfafe..fa0cd335 100644 --- a/src/guides/build-iapp/deploy-&-run.md +++ b/src/guides/build-iapp/deploy-&-run.md @@ -40,6 +40,22 @@ specify your app version, and push both standard and TEE-compatible images: /> +Now that your iApp has been deployed on the iExec protocol, you can navigate to the `cache` folder to see your deployments saved. A file named `deployments.json` in the folder corresponding to your target network will be created containing each deployment made on this network. These files will help you easily track each deployment per network. + +Here is an example: + +```json +[ + { + "sconifiedImage": "robiniexec/iapp:0.0.1-tee-scone-5.9.1-v16-debug-5aea8b4aa71d", + "appContractAddress": "0x9665136c599ec361C8eE627eC4F35A23fBa94897", + "owner": "0xbabE8270aC9857Af3aaC06877888F1939FbeC578", + "date": "2025-08-12T13:16:18.252Z" + }, + ... +] +``` + ## Run your iApp There are multiple ways to execute an iApp on the iExec network. An iApp can be: @@ -80,11 +96,27 @@ for developers who have built their own iApp. /> +Now that you have run your iApp on the iExec protocol, you can navigate to the `cache` folder to see your runs saved. A file named `runs.json` in the folder corresponding to your target network will be created containing each run made on this network. These files will help you easily track each run per network. Use the [iExec Explorer](/guides/tooling-and-explorers/iexec-explorer) to retrieve more data about your tasks. + +Here is an example: + +```json +[ + { + "iAppAddress": "0x9665136c599ec361C8eE627eC4F35A23fBa94897", + "dealid": "0x26d758de1be51697c33fa606cd0c5243082a6e675a4463b106d71fde2893280f", + "taskid": "0x1a58dd6018b30b022eb35be53ad9374eb630925458d14643a1dfd9c686b964d8", + "txHash": "0x6f14eac6933c609fb6d3e6b2bbd18c373c6dc99c7d7fd22036d5a20f847c5e42", + "date": "2025-08-18T18:30:03.711Z" + }, + ... +] +``` + ## Next Steps -- Discover how to - [run an iApp with inputs](/guides/use-iapp/run-iapp-with-inputs) -- Understand [how to pay for executions](/guides/use-iapp/how-to-pay-executions) +- Learn how to [manage access to your iApp](/guides/build-iapp/manage-access) +- Discover [debugging techniques](/guides/build-iapp/debugging) for troubleshooting diff --git a/src/guides/use-iapp/run-iapp-without-ProtectedData.md b/src/guides/use-iapp/run-iapp-without-ProtectedData.md new file mode 100644 index 00000000..7e93ce74 --- /dev/null +++ b/src/guides/use-iapp/run-iapp-without-ProtectedData.md @@ -0,0 +1,187 @@ +--- +title: Run iApp without ProtectedData +description: + Learn how to run iApp with basic inputs like command-line arguments, public files, and secrets using the iexec SDK +--- + +# 📥 Run iApp without a ProtectedData + +When an iApp requires additional data or parameters to function, you can provide +various types of inputs to customize its behavior and enable processing. This +guide covers all the different ways to run an iApp with inputs using the +DataProtector turnkey toolkit. + +## Possible Inputs + +iExec supports several types of inputs for iApp executions: + +1. **Arguments**: Command-line arguments passed to the application +2. **Input Files**: URLs to public files that the app can download +3. **Secrets**: Sensitive data like API keys stored securely + +## Adding Command-Line Arguments + +Command-line arguments are passed as a string to the iApp and are visible on the +blockchain. + +```ts twoslash +import { IExec, utils } from 'iexec'; + +const ethProvider = utils.getSignerFromPrivateKey( + 'bellecour', // 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...', // ENS address for iExec's debug workerpool + params: 'arg1 arg2 arg3', // Command-line arguments + // Other parameters have default values +}); +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, +}); +``` + +## Adding Input Files + +Input files are URLs to public files that the iApp can download during +execution. + +```ts twoslash +import { IExec, utils } from 'iexec'; + +const ethProvider = utils.getSignerFromPrivateKey( + 'bellecour', // blockchain node URL + 'PRIVATE_KEY' +); +const iexec = new IExec({ + ethProvider, +}); +// ---cut--- +// Single input file +const requestorderToSign = await iexec.order.createRequestorder({ + app: '0x456def...', + category: 0, // Required: category for the request + appmaxprice: 10, + workerpool: '0xa5de76...', // ENS address for iExec's debug workerpool + params: { + iexec_input_files: [ + 'https://example.com/config.json', + 'https://example.com/template.html', + 'https://example.com/data.csv', + ], + }, +}); +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, +}); +``` + +## Adding Secrets + +Secrets are sensitive data like API keys, passwords, or tokens that are stored +securely and made available to the iApp as environment variables. + +```ts twoslash [Browser] +// @errors: 2345 2739 7053 2339 +import { IExec, utils } from 'iexec'; + +const ethProvider = utils.getSignerFromPrivateKey( + 'bellecour', // blockchain node URL + 'PRIVATE_KEY' +); +const iexec = new IExec({ + ethProvider, +}); +// ---cut--- +// Basic secrets +const requestorderToSign = await iexec.order.createRequestorder({ + app: '0x456def...', + category: 0, // Required: category for the request + appmaxprice: 10, + workerpool: '0xa5de76...', // ENS address for iExec's debug workerpool + params: { + iexec_secrets: { + 1: 'api-key-12345', + 2: 'database-password', + }, + }, +}); +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, +}); +``` + +## Next Steps + +Now that you understand how to add inputs to iApp executions: diff --git a/src/guides/use-iapp/run-iapp.md b/src/guides/use-iapp/run-iapp.md deleted file mode 100644 index 296a7e22..00000000 --- a/src/guides/use-iapp/run-iapp.md +++ /dev/null @@ -1,307 +0,0 @@ ---- -title: Run an iApp -description: - Learn about various methods for executing iApp on the iExec network, including - CLI and SDK approaches ---- - -# ⚡ Run an iApp - -There are multiple ways to execute an iApp on the iExec network. An iApp can be: - -- **Self-sufficient** - Basic execution without additional inputs -- **Data-dependent** - Requires protected data, secrets, input files, or - command-line arguments - -This guide covers the basic execution methods. For advanced features like -protected data, arguments, and input files, see the dedicated guides. - -## When to Use Each Method - -- **iApp Generator CLI**: For developers who have built their own iApp -- **iExec Library**: For JavaScript applications and web3 integration - -## Method 1: Using the iApp Generator CLI - -The iApp Generator CLI provides a streamlined way to execute iApp, especially -for developers who have built their own iApp. - -> **Note**: For installation instructions, see the -> [iApp Generator Getting Started guide](/references/iapp-generator/getting-started). - - - - - -## Method 2: Using the iExec SDK Library - -The iExec SDK provides a modular JavaScript interface for executing iApp. - -```ts twoslash -import { IExec, utils } from 'iexec'; - -const ethProvider = utils.getSignerFromPrivateKey( - 'bellecour', // blockchain node URL - 'PRIVATE_KEY' -); -const iexec = new IExec({ - ethProvider, -}); -// ---cut--- -// Create & Sign a request order -const requestorderToSign = await iexec.order.createRequestorder({ - app: '0x456def...', // The iApp address - category: 0, -}); -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, -}); -``` - -## Next Steps - -- Discover how to - [run an iApp with inputs](/guides/use-iapp/run-iapp-with-inputs) -- Understand [how to pay for executions](/guides/use-iapp/how-to-pay-executions) - - From 1f58f63a65e5cc1d51abe6b4cc6b776378f79d1c Mon Sep 17 00:00:00 2001 From: Le-Caignec Date: Tue, 19 Aug 2025 14:30:00 +0200 Subject: [PATCH 12/33] docs: Update iApp guides for improved navigation and clarity --- .vitepress/sidebar.ts | 12 +- .../protocol/tee/intel-sgx-technology.md | 2 +- .../advanced/access-confidential-assets.md | 4 +- .../advanced/quick-start-for-developers.md | 1 - .../advanced/sgx-encrypted-dataset.md | 2 - .../build-iapp/advanced/your-first-app.md | 10 - src/guides/build-iapp/build-&-test.md | 2 +- src/guides/build-iapp/debugging.md | 2 +- src/guides/build-iapp/deploy-&-run.md | 4 +- .../download-and-decrypt-results.md | 250 ------------------ src/guides/build-iapp/inputs-and-outputs.md | 6 +- src/guides/use-iapp/getting-started.md | 13 +- src/guides/use-iapp/how-to-pay-executions.md | 3 +- .../use-iapp/run-iapp-with-ProtectedData.md | 3 +- .../run-iapp-without-ProtectedData.md | 3 +- src/references/iapp-generator.md | 6 +- 16 files changed, 28 insertions(+), 295 deletions(-) delete mode 100644 src/guides/build-iapp/download-and-decrypt-results.md diff --git a/.vitepress/sidebar.ts b/.vitepress/sidebar.ts index ee93d804..984ff8f8 100644 --- a/.vitepress/sidebar.ts +++ b/.vitepress/sidebar.ts @@ -185,10 +185,6 @@ export function getSidebar() { text: 'Using TDX', link: '/guides/build-iapp/using-tdx', }, - { - text: 'Download and Decrypt Results', - link: '/guides/build-iapp/download-and-decrypt-results', - }, { text: 'Debugging', link: '/guides/build-iapp/debugging', @@ -245,12 +241,12 @@ export function getSidebar() { link: '/guides/use-iapp/getting-started', }, { - text: 'Run iApp', - link: '/guides/use-iapp/run-iapp', + text: 'Run iApp without ProtectedData', + link: '/guides/use-iapp/run-iapp-without-ProtectedData', }, { - text: 'Run iApp with Inputs', - link: '/guides/use-iapp/run-iapp-with-inputs', + text: 'Run iApp with ProtectedData', + link: '/guides/use-iapp/run-iapp-with-ProtectedData', }, { text: 'How to Pay the Executions', diff --git a/src/get-started/protocol/tee/intel-sgx-technology.md b/src/get-started/protocol/tee/intel-sgx-technology.md index 62ab37ff..bd508f78 100644 --- a/src/get-started/protocol/tee/intel-sgx-technology.md +++ b/src/get-started/protocol/tee/intel-sgx-technology.md @@ -79,6 +79,6 @@ The environment you are about to use is a "develop" environment: - where configurations and secrets might be inspected (debug enclaves) When your developer discovery journey is complete, please reach the -[production section](/guides/build-iapp/build-&-deploy#go-to-production). +[production section](/guides/build-iapp/build-&-test#go-to-production). ::: diff --git a/src/guides/build-iapp/advanced/access-confidential-assets.md b/src/guides/build-iapp/advanced/access-confidential-assets.md index 7d705204..4a245b95 100644 --- a/src/guides/build-iapp/advanced/access-confidential-assets.md +++ b/src/guides/build-iapp/advanced/access-confidential-assets.md @@ -18,7 +18,7 @@ indeed whitelisted for it. The SMS currently supports 3 types of secrets: -1. [Application developer secret](/guides/build-iapp/build-&-deploy#application-developer-secret): +1. [Application developer secret](/guides/build-iapp/build-&-test#application-developer-secret): This secret is directly accessible from the application as an environment variable. It is owned by the developer of the application. It can be any kind of data (API key, private key, token, ..) as long as it respects the size @@ -58,6 +58,4 @@ graph TD You now understand how these three kinds of confidential assets work on iExec, you can go one step further by learning how to manipulate them: -- [Attach a secret to your app](/guides/build-iapp/build-&-deploy#application-developer-secret) -- [Access requester secrets](/guides/build-iapp/inputs-and-outputs#access-requester-secrets) - [Access a confidential dataset](sgx-encrypted-dataset.md) diff --git a/src/guides/build-iapp/advanced/quick-start-for-developers.md b/src/guides/build-iapp/advanced/quick-start-for-developers.md index 08a45b38..2c3564bf 100644 --- a/src/guides/build-iapp/advanced/quick-start-for-developers.md +++ b/src/guides/build-iapp/advanced/quick-start-for-developers.md @@ -344,4 +344,3 @@ You are now familiar with the following key iExec concepts for developers: Continue with these guides: - [Learn how to build your first application running on iExec](your-first-app.md) -- [Learn how to manage your apporders](/guides/build-iapp/build-&-deploy#manage-your-apporders) diff --git a/src/guides/build-iapp/advanced/sgx-encrypted-dataset.md b/src/guides/build-iapp/advanced/sgx-encrypted-dataset.md index eee484e9..c4e84288 100644 --- a/src/guides/build-iapp/advanced/sgx-encrypted-dataset.md +++ b/src/guides/build-iapp/advanced/sgx-encrypted-dataset.md @@ -363,6 +363,4 @@ an encrypted dataset in a Confidential Computing application. To go further, check out how to: -- [Attach a secret to your app](/guides/build-iapp/build-&-deploy#application-developer-secret) -- [Access requester secrets](/guides/build-iapp/inputs-and-outputs#access-requester-secrets) - [Protect the result](end-to-end-encryption.md) diff --git a/src/guides/build-iapp/advanced/your-first-app.md b/src/guides/build-iapp/advanced/your-first-app.md index 824b15bf..e3dd5a8e 100644 --- a/src/guides/build-iapp/advanced/your-first-app.md +++ b/src/guides/build-iapp/advanced/your-first-app.md @@ -413,13 +413,3 @@ iExec: - using docker to package your app with all its dependencies - testing an iExec app locally - publishing on dockerhub - -Resources: - -- A list of iExec applications with their Docker images can be found at - [https://github.com/iExecBlockchainComputing/iexec-apps](https://github.com/iExecBlockchainComputing/iexec-apps) - -Continue with these articles: - -- [Confidential app](/guides/build-iapp/build-&-deploy#confidential-app) -- [Learn how to manage your apporders](/guides/build-iapp/build-&-deploy#manage-your-apporders) diff --git a/src/guides/build-iapp/build-&-test.md b/src/guides/build-iapp/build-&-test.md index e61d1eb8..cec884c1 100644 --- a/src/guides/build-iapp/build-&-test.md +++ b/src/guides/build-iapp/build-&-test.md @@ -209,7 +209,7 @@ The CLI will build a Docker image, run your app, and show you the results: ## Next Steps - When everything is ready - [deploy and run your iApp](../use-iapp/run-iapp-with-inputs) + [deploy and run your iApp](../use-iapp/run-iapp-with-ProtectedData) diff --git a/src/guides/use-iapp/how-to-pay/how-to-pay-for-web3mail.md b/src/guides/use-iapp/how-to-pay/how-to-pay-for-web3mail.md deleted file mode 100644 index 599832b1..00000000 --- a/src/guides/use-iapp/how-to-pay/how-to-pay-for-web3mail.md +++ /dev/null @@ -1,160 +0,0 @@ ---- -title: How to Pay for Web3Mail -description: - Learn how to pay for Web3Mail's confidential computing power using vouchers - and RLC for secure, blockchain-based email communication. ---- - -# How to Pay for Web3Mail - -[Web3Mail](/references/web3mail) offers secure, blockchain-based communication -by encrypting emails and protecting user privacy. - -The `sendEmail` function uses iExec's protocol to encrypt and send messages, -ensuring secure and decentralized email exchanges. - -This guide shows how to pay for Web3Mail using **vouchers** and -****. - -## Using Vouchers for Web3Mail - -### Step 1: Obtain a Voucher - -- **Acquire Vouchers**: Obtain vouchers through the - [iExec Builder Dashboard](https://builder.iex.ec/). Note that the number of - Web3Mail executions and the expiration time of each voucher is restricted - based on its validity period. Refer to - [pricing documentation](https://www.iex.ec/voucher) for more information. -- **Support**: For specific limitations related to your voucher, please contact - iExec Support. - -### Step 2: Use the Builder Dashboard - - - Builder dashboard screenshot - - -The iExec Builder Dashboard manages vouchers and resources with an intuitive -interface for: - -- **Claiming Vouchers**: Builders can claim vouchers during the BUILD and EARN - stages. -- **Top-Up Vouchers**: Future updates will allow direct top-ups via the - dashboard. Currently, builders are redirected to Discord. -- **Checking Voucher Balance**: Track your voucher balance and usage history. - -🧙🏼 [Go here](https://builder.iex.ec/) - -### Step 3: Grant Allowance (If Necessary) - -Use `iexec.account.approve(voucherAddress)` to authorize the voucher smart -contract to debit your account if the voucher balance is insufficient. This -ensures that if the voucher alone doesn't cover the execution cost, the -remaining balance is automatically deducted from your account. - -For additional information on using for fallback payment in -Web3Mail, refer to the **Using with Web3Mail** section. - -### Step 4: Execute Web3Mail's SendEmail Function - -When using a voucher for payment, set the `useVoucher` parameter to `true`: - -```ts twoslash -import { IExecWeb3mail, getWeb3Provider } from '@iexec/web3mail'; - -const web3Provider = getWeb3Provider('PRIVATE_KEY'); -const web3mail = new IExecWeb3mail(web3Provider); -// ---cut--- -const sendEmail = await web3mail.sendEmail({ - protectedData: '0x123abc...', - emailSubject: 'My email subject', - emailContent: 'My email content', - useVoucher: true, // [!code focus] -}); -``` - -## Using for Web3Mail - -If you choose to use to cover the computational cost of Web3Mail -(or if you need to cover data access costs such as retrieving the recipient's -email address), follow these steps: - -### Install the iExec SDK - -To manage RLC tokens, developers must use the iExec SDK, which offers all the -necessary tools for interacting with the iExec platform. This includes -depositing, withdrawing, and checking balances of RLC and - -- In your JS/TS project, run `npm install iexec` -- Instantiate the iExec SDK (see the - [doc](https://github.com/iExecBlockchainComputing/iexec-sdk/blob/master/docs/README.md#quick-start)) - -```javascript -import { IExec } from 'iexec'; -// Connect to injected provider -const iexec = new IExec({ ethProvider: window.ethereum }); -``` - -### Purchase RLC - -Obtain RLC tokens from a supported cryptocurrency exchange. For detailed -information on how to buy RLC tokens, see our -[RLC Token guide](/get-started/overview/rlc) which covers all available DEX and -CEX options. - -For detailed instructions on how to bridge RLC tokens between networks, see our -[Bridge guide](/get-started/tooling-and-explorers/bridge) which covers all -supported networks and bridging methods. - -### Deposit - -Deposit the into your iExec account using the command: - -```javascript -iexec.account.deposit(RLC_amount); -``` - -This converts into sRLC, used as proof of funds for task -execution. - -### Check sRLC Balance - -Use the command below to check your balance: - -```javascript -iexec.account.show(); -``` - -### Execute sendEmail - -Set the `useVoucher` parameter to `false` when using Web3Mail's sendEmail -function to pay with : - -```ts twoslash -import { IExecWeb3mail, getWeb3Provider } from '@iexec/web3mail'; - -const web3Provider = getWeb3Provider('PRIVATE_KEY'); -const web3mail = new IExecWeb3mail(web3Provider); -// ---cut--- -const sendEmail = await web3mail.sendEmail({ - protectedData: '0x123abc...', - emailSubject: 'My email subject', - emailContent: 'My email content', - useVoucher: false, // [!code focus] -}); -``` - -### Withdraw sRLC (If Desired) - -Convert sRLC back to and withdraw to your wallet using: - -```javascript -iexec.account.withdraw(RLC_amount); -``` - - diff --git a/src/guides/use-iapp/how-to-pay/how-to-pay-for-web3telegram.md b/src/guides/use-iapp/how-to-pay/how-to-pay-for-web3telegram.md deleted file mode 100644 index e9a9d098..00000000 --- a/src/guides/use-iapp/how-to-pay/how-to-pay-for-web3telegram.md +++ /dev/null @@ -1,172 +0,0 @@ ---- -title: How to Pay for Web3Telegram -description: - Learn how to pay for Web3Telegram's confidential computing power using - vouchers and RLC for secure, blockchain-based email communication. ---- - -# How to Pay for Web3Telegram - -[Web3Telegram](/references/web3telegram) offers secure, blockchain-based -communication by encrypting messages and protecting user privacy. - -The `sendTelegram` function uses iExec's protocol to encrypt and send messages, -ensuring secure and decentralized email exchanges. - -This guide shows how to pay for Web3Telegram using **vouchers** and -****. - -## Using Vouchers for Web3Telegram - -### Step 1: Obtain a Voucher - -- **Acquire Vouchers**: Obtain vouchers through the - [iExec Builder Dashboard](https://builder.iex.ec/). Note that the number of - Web3Telegram executions and the expiration time of each voucher is restricted - based on its validity period. Refer to - [pricing documentation](https://www.iex.ec/voucher) for more information. -- **Support**: For specific limitations related to your voucher, please contact - iExec Support. - -### Step 2: Use the Builder Dashboard - - - Builder dashboard screenshot - - -The iExec Builder Dashboard manages vouchers and resources with an intuitive -interface for: - -- **Claiming Vouchers**: Builders can claim vouchers during the BUILD and EARN - stages. -- **Top-Up Vouchers**: Future updates will allow direct top-ups via the - dashboard. Currently, builders are redirected to Discord. -- **Checking Voucher Balance**: Track your voucher balance and usage history. - -🧙🏼 [Go here](https://builder.iex.ec/) - -### Step 3: Grant Allowance (If Necessary) - -Use `iexec.account.approve(voucherAddress)` to authorize the voucher smart -contract to debit your account if the voucher balance is insufficient. This -ensures that if the voucher alone doesn't cover the execution cost, the -remaining balance is automatically deducted from your account. - -For additional information on using for fallback payment in -Web3Telegram, refer to the **Using with Web3Telegram** section. - -### Step 4: Execute Web3Telegram's `sendTelegram` Function - -When using a voucher for payment, set the `useVoucher` parameter to `true`: - -```ts twoslash -import { IExecWeb3telegram, getWeb3Provider } from '@iexec/web3telegram'; - -const web3Provider = getWeb3Provider('PRIVATE_KEY'); -const web3telegram = new IExecWeb3telegram(web3Provider); -// ---cut--- - -const sendTelegram = await web3telegram.sendTelegram({ - protectedData: '0x123abc...', - telegramContent: 'My telegram message content', - senderName: 'Awesome project team', - label: 'some-custom-id', - workerpoolAddressOrEns: 'prod-v8-bellecour.main.pools.iexec.eth', - dataMaxPrice: 42, - appMaxPrice: 42, - workerpoolMaxPrice: 42, - useVoucher: true, // [!code focus] -}); -``` - -## Using for Web3Telegram - -If you choose to use to cover the computational cost of -Web3Telegram (or if you need to cover data access costs such as retrieving the -recipient's Chat Id), follow these steps: - -### Install the iExec SDK - -To manage RLC tokens, developers must use the iExec SDK, which offers all the -necessary tools for interacting with the iExec platform. This includes -depositing, withdrawing, and checking balances of RLC and - -- In your JS/TS project, run `npm install iexec` -- Instantiate the iExec SDK (see the - [doc](https://github.com/iExecBlockchainComputing/iexec-sdk/blob/master/docs/README.md#quick-start)) - -```javascript -import { IExec } from 'iexec'; -// Connect to injected provider -const iexec = new IExec({ ethProvider: window.ethereum }); -``` - -### Purchase RLC - -Obtain RLC tokens from a supported cryptocurrency exchange. For detailed -information on how to buy RLC tokens, see our -[RLC Token guide](/get-started/overview/rlc) which covers all available DEX and -CEX options. - -For detailed instructions on how to bridge RLC tokens between networks, see our -[Bridge guide](/get-started/tooling-and-explorers/bridge) which covers all -supported networks and bridging methods. - -### Deposit - -Deposit the into your iExec account using the command: - -```javascript -iexec.account.deposit(RLC_amount); -``` - -This converts into sRLC, used as proof of funds for task -execution. - -### Check sRLC Balance - -Use the command below to check your balance: - -```javascript -iexec.account.show(); -``` - -### Execute `sendTelegram` - -Set the `useVoucher` parameter to `false` when using Web3Telegram's sendTelegram -function to pay with : - -```ts twoslash -import { IExecWeb3telegram, getWeb3Provider } from '@iexec/web3telegram'; - -const web3Provider = getWeb3Provider('PRIVATE_KEY'); -const web3telegram = new IExecWeb3telegram(web3Provider); -// ---cut--- - -const sendTelegram = await web3telegram.sendTelegram({ - protectedData: '0x123abc...', - telegramContent: 'My telegram message content', - senderName: 'Awesome project team', - label: 'some-custom-id', - workerpoolAddressOrEns: 'prod-v8-bellecour.main.pools.iexec.eth', - dataMaxPrice: 42, - appMaxPrice: 42, - workerpoolMaxPrice: 42, - useVoucher: false, // [!code focus] -}); -``` - -### Withdraw sRLC (If Desired) - -Convert sRLC back to and withdraw to your wallet using: - -```javascript -iexec.account.withdraw(RLC_amount); -``` - - diff --git a/src/guides/use-iapp/how-to-pay/pricing-considerations.md b/src/guides/use-iapp/how-to-pay/pricing-considerations.md deleted file mode 100644 index 09587a20..00000000 --- a/src/guides/use-iapp/how-to-pay/pricing-considerations.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -title: Pricing Considerations -description: Pricing considerations ---- - -# Pricing Considerations - -This page is under development. - - diff --git a/src/guides/use-iapp/how-to-pay/voucher.md b/src/guides/use-iapp/how-to-pay/voucher.md deleted file mode 100644 index cf1c7822..00000000 --- a/src/guides/use-iapp/how-to-pay/voucher.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -title: Voucher Guide -description: Voucher Guide ---- - -# Voucher Guide - -This page is under development. - - diff --git a/src/guides/use-iapp/run-iapp-with-ProtectedData.md b/src/guides/use-iapp/run-iapp-with-ProtectedData.md index 7fa99f17..479f228c 100644 --- a/src/guides/use-iapp/run-iapp-with-ProtectedData.md +++ b/src/guides/use-iapp/run-iapp-with-ProtectedData.md @@ -113,10 +113,3 @@ const result = await dataProtectorCore.processProtectedData({ }, }); ``` - -## Next Steps - -Now that you understand how to add inputs to iApp executions: - -- Check out our - [How to Pay for Executions](/guides/use-iapp/how-to-pay-executions) guide diff --git a/src/guides/use-iapp/run-iapp-without-ProtectedData.md b/src/guides/use-iapp/run-iapp-without-ProtectedData.md index 4a569032..f568f619 100644 --- a/src/guides/use-iapp/run-iapp-without-ProtectedData.md +++ b/src/guides/use-iapp/run-iapp-without-ProtectedData.md @@ -176,7 +176,3 @@ const taskId = await iexec.order.matchOrders({ workerpoolorder: workerpoolOrders.orders[0].order, }); ``` - -## Next Steps - -Now that you understand how to add inputs to iApp executions: diff --git a/src/references/sdk.md b/src/references/sdk.md index 54ee6c83..f56f75db 100644 --- a/src/references/sdk.md +++ b/src/references/sdk.md @@ -9,8 +9,72 @@ The iExec SDK is a [CLI](#command-line-interface) and a [JS library](#javascripttypescript-library) that allows easy interactions with iExec decentralized marketplace in order to run off-chain computations. -iExec SDK is available on [npm](https://www.npmjs.com/package/iexec) and -[GitHub](https://github.com/iExecBlockchainComputing/iexec-sdk) +## Overview + +### Prerequisites + +Before getting started, ensure that you have the following installed on your +system: + +\- [**Node.js**](https://nodejs.org/en/) version 18 or higher + +\- [**NPM**](https://docs.npmjs.com/) (Node.js package manager) + +### Installation + +::: code-group + +```sh [npm] +npm install @iexec/dataprotector +``` + +```sh [yarn] +yarn add @iexec/dataprotector +``` + +```sh [pnpm] +pnpm add @iexec/dataprotector +``` + +```sh [bun] +bun add @iexec/dataprotector +``` + +::: + +### Instantiate SDK + +::: code-group + +```ts twoslash [Browser] +declare global { + interface Window { + ethereum: any; + } +} +// ---cut--- +import { IExec } from 'iexec'; + +// Connect to injected provider +const iexec = new IExec({ ethProvider: window.ethereum }); +``` + +```ts twoslash [NodeJS] +import { IExec, utils } from 'iexec'; + +const ethProvider = utils.getSignerFromPrivateKey( + 'http://localhost:8545', // blockchain node URL + 'YOUR_PRIVATE_KEY' +); +const iexec = new IExec({ + ethProvider, +}); +``` + +::: + +For comprehensive documentation and advanced usage examples, see the +[iExec SDK GitHub repository](https://github.com/iExecBlockchainComputing/iexec-sdk/blob/master/docs/README.md). ## Command Line Interface diff --git a/src/references/web3mail/methods/sendEmail.md b/src/references/web3mail/methods/sendEmail.md index 39d3cdfc..4eefbaa3 100644 --- a/src/references/web3mail/methods/sendEmail.md +++ b/src/references/web3mail/methods/sendEmail.md @@ -23,7 +23,7 @@ documentation for more details. For executing the `sendEmail` method with a voucher or , refer to the dedicated section in the documentation under -"[How to Pay for web3mail](/guides/use-iapp/how-to-pay/how-to-pay-for-web3mail)". +"[How to Pay for Executions](/guides/use-iapp/how-to-pay-executions.md)". ::: diff --git a/src/references/web3telegram/methods/sendTelegram.md b/src/references/web3telegram/methods/sendTelegram.md index c14135ac..6b9e1450 100644 --- a/src/references/web3telegram/methods/sendTelegram.md +++ b/src/references/web3telegram/methods/sendTelegram.md @@ -23,7 +23,7 @@ documentation for more details. For executing the `sendTelegram` method with a voucher or , refer to the dedicated section in the documentation under -"[How to Pay for web3telegram](/guides/use-iapp/how-to-pay/how-to-pay-for-web3telegram)". +"[How to Pay for Executions](/guides/use-iapp/how-to-pay-executions.md)". ::: From 1dd585384a0fbc28e16685135c09039f80cd4c39 Mon Sep 17 00:00:00 2001 From: Le-Caignec Date: Tue, 19 Aug 2025 20:30:42 +0200 Subject: [PATCH 17/33] refactor: remove TokenSymbol component and replace with RLC in documentation --- src/components/TokenSymbol.vue | 25 ------------------ .../protocol/worker/manage-access.md | 26 ++++++++----------- .../protocol/worker/quick-start.md | 17 +++++------- src/guides/build-iapp/manage-access.md | 12 +++------ src/guides/manage-data/manage-access.md | 3 +-- src/guides/use-iapp/how-to-pay-executions.md | 15 +++++------ src/guides/use-iapp/introduction.md | 11 +++----- .../dataProtectorCore/grantAccess.md | 3 +-- .../dataProtectorCore/processProtectedData.md | 9 +++---- src/references/dataProtector/types.md | 8 ++---- src/references/web3mail/methods/sendEmail.md | 13 +++++----- .../web3telegram/methods/sendTelegram.md | 13 +++++----- 12 files changed, 51 insertions(+), 104 deletions(-) delete mode 100644 src/components/TokenSymbol.vue diff --git a/src/components/TokenSymbol.vue b/src/components/TokenSymbol.vue deleted file mode 100644 index 5778577a..00000000 --- a/src/components/TokenSymbol.vue +++ /dev/null @@ -1,25 +0,0 @@ - - - diff --git a/src/get-started/protocol/worker/manage-access.md b/src/get-started/protocol/worker/manage-access.md index de601f30..ce4b59b6 100644 --- a/src/get-started/protocol/worker/manage-access.md +++ b/src/get-started/protocol/worker/manage-access.md @@ -41,17 +41,17 @@ iexec order init --workerpool Edit the `workerpoolorder` part in `iexec.json` to set the conditions to use your workerpool: -| key | description | -| ------------------- | ------------------------------------------------------------------------------------- | -| `workerpool` | workerpool address | -| `workerpoolprice` | price to charge the requester for each execution of the app (in nano ) | -| `volume` | number of authorized uses, each use decreases this number | -| `tag` | restrict usage to a specific runtime such as **Scone** or **Gramine** TEE frameworks | -| `category` | Order category, will define the deal `workClockTimeRef` and its deadlines | -| `trust` | Trust level of the execution, impacts the number of replicates | -| `apprestrict` | restrict the workerpool usage to a specific app (1) | -| `datasetrestrict` | restrict the workerpool usage to a specific dataset (1) | -| `requesterrestrict` | restrict the workerpool usage to a specific requester (1) | +| key | description | +| ------------------- | ------------------------------------------------------------------------------------ | +| `workerpool` | workerpool address | +| `workerpoolprice` | price to charge the requester for each execution of the app (in nano RLC) | +| `volume` | number of authorized uses, each use decreases this number | +| `tag` | restrict usage to a specific runtime such as **Scone** or **Gramine** TEE frameworks | +| `category` | Order category, will define the deal `workClockTimeRef` and its deadlines | +| `trust` | Trust level of the execution, impacts the number of replicates | +| `apprestrict` | restrict the workerpool usage to a specific app (1) | +| `datasetrestrict` | restrict the workerpool usage to a specific dataset (1) | +| `requesterrestrict` | restrict the workerpool usage to a specific requester (1) | 1. the restriction is disabled by default with 0x0000000000000000000000000000000000000000. @@ -106,7 +106,3 @@ cancel command. ```bash iexec order cancel --workerpool ``` - - diff --git a/src/get-started/protocol/worker/quick-start.md b/src/get-started/protocol/worker/quick-start.md index 340bde8e..df23dab5 100644 --- a/src/get-started/protocol/worker/quick-start.md +++ b/src/get-started/protocol/worker/quick-start.md @@ -14,13 +14,12 @@ The iExec Worker participates in a workerpool by computing tasks purchased by requesters on the iExec marketplace. The iExec Worker must connect to the iExec Core Scheduler of the workerpool to actively participate in the computation. -A worker will be rewarded with for every properly computed -tasks. +A worker will be rewarded with RLC for every properly computed tasks. Please note that: -- your wallet must be loaded with . Some must be - deposited to your iExec account in order to stake for incoming tasks. +- your wallet must be loaded with RLC. Some RLC must be deposited to your iExec + account in order to stake for incoming tasks. - your computer needs at least 2 CPUs. ## Start a worker @@ -34,18 +33,14 @@ configuration documentation of the For security reason, it is **highly recommended** to launch your worker in a virtual machine. -After loading some and depositing them to your iExec account, -you can start your worker. +After loading some RLC and depositing them to your iExec account, you can start +your worker. When the worker initialization process is complete, the worker will start and you will get: **Your worker is all set**. Your worker will now be able to -compute tasks from the iExec network to earn . +compute tasks from the iExec network to earn RLC. ## Wallet restriction An exclusive wallet must be associated to your worker. You need N wallets if you want N workers. - - diff --git a/src/guides/build-iapp/manage-access.md b/src/guides/build-iapp/manage-access.md index 9d18e8c1..df2dbe34 100644 --- a/src/guides/build-iapp/manage-access.md +++ b/src/guides/build-iapp/manage-access.md @@ -40,7 +40,7 @@ Here's the simplified process: 2. **You sign the order** with your wallet 3. **You publish the order** on the iExec marketplace 4. **Users can discover** and execute your iApp according to your conditions -5. **You automatically receive** payment in for each execution +5. **You automatically receive** payment in RLC for each execution ``` Deployed iApp + Signed App Order = Application accessible on iExec @@ -231,12 +231,12 @@ Here's the detailed description of each parameter: **Common values:** - `"0"` - Free -- `"1000000000"` - 1 per execution -- `"500000000"` - 0.5 per execution +- `"1000000000"` - 1 RLC per execution +- `"500000000"` - 0.5 RLC per execution ::: tip -1 = 1,000,000,000 nano (10^9) +1 RLC = 1,000,000,000 nano RLC (10^9) ::: @@ -301,7 +301,3 @@ Next steps: Complete CLI reference - **[Official Orders Documentation](https://protocol.docs.iex.ec/for-developers/advanced/manage-your-apporders)** - Protocol-level order management - - diff --git a/src/guides/manage-data/manage-access.md b/src/guides/manage-data/manage-access.md index 8f2ecde1..8c4a5d01 100644 --- a/src/guides/manage-data/manage-access.md +++ b/src/guides/manage-data/manage-access.md @@ -169,7 +169,7 @@ yourself! Set to `0` for free access, or specify a price to monetize your data automatically. -**Example**: `pricePerAccess: 1_000_000_000` = 1 per access +**Example**: `pricePerAccess: 1_000_000_000` = 1 RLC per access → **Want to learn more monetization capabilities?** See our detailed [Monetize Protected Data guide](/guides/manage-data/monetize-protected-data) @@ -211,5 +211,4 @@ steps: diff --git a/src/guides/use-iapp/how-to-pay-executions.md b/src/guides/use-iapp/how-to-pay-executions.md index fe215210..9d1b4ccf 100644 --- a/src/guides/use-iapp/how-to-pay-executions.md +++ b/src/guides/use-iapp/how-to-pay-executions.md @@ -14,7 +14,7 @@ and cost management strategies. iExec supports multiple payment methods for executing iApp: -1. **RLC Tokens**: Direct payment using tokens +1. **RLC Tokens**: Direct payment using RLC tokens 2. **Vouchers**: Pre-funded vouchers for simplified payment 3. **Mixed Payment**: Combination of RLC and vouchers @@ -103,8 +103,8 @@ balance is insufficient. This ensures that if the voucher alone doesn't cover the execution cost, the remaining balance is automatically deducted from your account. -For additional information on using for fallback payment in -Web3Mail, refer to the **Using with Web3Mail** section. +For additional information on using RLC for fallback payment in Web3Mail, refer +to the **Using RLC with Web3Mail** section. ### Step 4: Use Voucher @@ -161,10 +161,10 @@ const result = await dataProtectorCore.processProtectedData({ ::: tip -If your voucher doesn't have enough to cover the deal, the SDK -will automatically get the required amount to your iExec account. Ensure that -your voucher is authorized to access your iExec account and that your account -has sufficient funds for this transfer to proceed. +If your voucher doesn't have enough RLC to cover the deal, the SDK will +automatically get the required amount to your iExec account. Ensure that your +voucher is authorized to access your iExec account and that your account has +sufficient funds for this transfer to proceed. ::: @@ -239,7 +239,6 @@ Now that you understand payment methods: diff --git a/src/references/dataProtector/dataProtectorCore/grantAccess.md b/src/references/dataProtector/dataProtectorCore/grantAccess.md index 67462f07..adf54e0d 100644 --- a/src/references/dataProtector/dataProtectorCore/grantAccess.md +++ b/src/references/dataProtector/dataProtectorCore/grantAccess.md @@ -165,7 +165,7 @@ const grantedAccess = await dataProtectorCore.grantAccess({ ::: tip `pricePerAccess` is expressed in nano RLC (nRLC). nRLC is the smallest -subdivision of the token, 1 equals to 10^9 nRLC. +subdivision of the RLC token, 1 RLC equals to 10^9 nRLC. When provided, `pricePerAccess` must be a non-negative integer value. @@ -254,5 +254,4 @@ The result of this method confirms the new access grant. It consists of a JSON diff --git a/src/references/dataProtector/dataProtectorCore/processProtectedData.md b/src/references/dataProtector/dataProtectorCore/processProtectedData.md index a6c7316d..f1feb735 100644 --- a/src/references/dataProtector/dataProtectorCore/processProtectedData.md +++ b/src/references/dataProtector/dataProtectorCore/processProtectedData.md @@ -154,10 +154,10 @@ const processProtectedDataResponse = ::: tip -If your voucher doesn't have enough to cover the deal, the SDK -will automatically get the required amount to your iExec account. Ensure that -your voucher is authorized to access your iExec account and that your account -has sufficient funds for this transfer to proceed. +If your voucher doesn't have enough RLC to cover the deal, the SDK will +automatically get the required amount to your iExec account. Ensure that your +voucher is authorized to access your iExec account and that your account has +sufficient funds for this transfer to proceed. ::: @@ -501,5 +501,4 @@ processed during the task. import RequiredBadge from '@/components/RequiredBadge.vue' import OptionalBadge from '@/components/OptionalBadge.vue' import ChainNotSupportedBadge from '@/components/ChainNotSupportedBadge.vue' -import TokenSymbol from '@/components/TokenSymbol.vue' diff --git a/src/references/dataProtector/types.md b/src/references/dataProtector/types.md index e586d99a..eb5edd8d 100644 --- a/src/references/dataProtector/types.md +++ b/src/references/dataProtector/types.md @@ -17,8 +17,8 @@ Types in DataProtector. ### datasetprice: `string` -- Price (in n) to charge the user specified in - `requesterrestrict` for each use of this `protectedData` +- Price (in nRLC) to charge the user specified in `requesterrestrict` for each + use of this `protectedData` ### volume: `string` @@ -123,7 +123,3 @@ _Hash example:_ `0xc9c2d58fc01fe54149b7daf49a0026d4ab1fdd3d10fb7c76350790fff03fe You can read more about he iExec Explorer [here](https://protocol.docs.iex.ec/for-developers/toolbox/iexec-explorer). - - diff --git a/src/references/web3mail/methods/sendEmail.md b/src/references/web3mail/methods/sendEmail.md index 4eefbaa3..74fcc888 100644 --- a/src/references/web3mail/methods/sendEmail.md +++ b/src/references/web3mail/methods/sendEmail.md @@ -21,8 +21,8 @@ documentation for more details. ::: tip -For executing the `sendEmail` method with a voucher or , refer to -the dedicated section in the documentation under +For executing the `sendEmail` method with a voucher or RLC, refer to the +dedicated section in the documentation under "[How to Pay for Executions](/guides/use-iapp/how-to-pay-executions.md)". ::: @@ -136,10 +136,10 @@ const sendEmail = await web3mail.sendEmail({ ::: tip -If your voucher doesn't have enough to cover the deal, the SDK -will automatically get the required amount to your iExec account. Ensure that -your voucher is authorized to access your iExec account and that your account -has sufficient funds for this transfer to proceed. +If your voucher doesn't have enough RLC to cover the deal, the SDK will +automatically get the required amount to your iExec account. Ensure that your +voucher is authorized to access your iExec account and that your account has +sufficient funds for this transfer to proceed. ::: @@ -395,5 +395,4 @@ For any other errors, you'll get a `WorkflowError` error in the form of: import RequiredBadge from '@/components/RequiredBadge.vue' import OptionalBadge from '@/components/OptionalBadge.vue' import ChainNotSupportedBadge from '@/components/ChainNotSupportedBadge.vue' -import TokenSymbol from '@/components/TokenSymbol.vue' diff --git a/src/references/web3telegram/methods/sendTelegram.md b/src/references/web3telegram/methods/sendTelegram.md index 6b9e1450..f9a39731 100644 --- a/src/references/web3telegram/methods/sendTelegram.md +++ b/src/references/web3telegram/methods/sendTelegram.md @@ -21,8 +21,8 @@ documentation for more details. ::: tip -For executing the `sendTelegram` method with a voucher or , refer -to the dedicated section in the documentation under +For executing the `sendTelegram` method with a voucher or RLC, refer to the +dedicated section in the documentation under "[How to Pay for Executions](/guides/use-iapp/how-to-pay-executions.md)". ::: @@ -147,10 +147,10 @@ const sendTelegram = await web3telegram.sendTelegram({ ::: tip -If your voucher doesn't have enough to cover the deal, the SDK -will automatically get the required amount to your iExec account. Ensure that -your voucher is authorized to access your iExec account and that your account -has sufficient funds for this transfer to proceed. +If your voucher doesn't have enough RLC to cover the deal, the SDK will +automatically get the required amount to your iExec account. Ensure that your +voucher is authorized to access your iExec account and that your account has +sufficient funds for this transfer to proceed. ::: @@ -297,5 +297,4 @@ the status of the `sendTelegram` method by monitoring the task on the From 22c15b2a18c9f7c96b7ac72fab862010bf88827b Mon Sep 17 00:00:00 2001 From: Le-Caignec Date: Tue, 19 Aug 2025 20:38:17 +0200 Subject: [PATCH 18/33] docs: update sidebar text for consistency and clarity; add info about xRLC token --- .vitepress/sidebar.ts | 16 ++++++++-------- src/get-started/overview/rlc.md | 6 ++++++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/.vitepress/sidebar.ts b/.vitepress/sidebar.ts index 6bbfc610..ca52922e 100644 --- a/.vitepress/sidebar.ts +++ b/.vitepress/sidebar.ts @@ -8,7 +8,7 @@ export function getSidebar() { items: [ { text: '💡 Welcome', link: '/get-started/welcome' }, { - text: '🛠️ Toolkit', + text: 'Toolkit', link: '/get-started/toolkit', }, { @@ -39,15 +39,15 @@ export function getSidebar() { ], }, { - text: '🚀 Quick Start', + text: 'Quick Start', link: '/get-started/quick-start', }, { - text: '📋 Use Cases', + text: 'Use Cases', link: '/get-started/use-cases', }, { - text: '🤖 Develop with AI', + text: 'Develop with AI', link: '/get-started/develop-with-ai', }, ], @@ -72,7 +72,7 @@ export function getSidebar() { link: '/get-started/overview/workerpool', }, { - text: '🪙 RLC Token', + text: 'RLC Token', link: '/get-started/overview/rlc', }, ], @@ -233,11 +233,11 @@ export function getSidebar() { text: 'USE AN iAPP', items: [ { - text: '📝 Introduction', + text: 'Introduction', link: '/guides/use-iapp/introduction', }, { - text: '🚀 Getting Started', + text: 'Getting Started', link: '/guides/use-iapp/getting-started', }, { @@ -576,7 +576,7 @@ export function getSidebar() { ], }, { - text: '🔧 iExec SDK', + text: 'iExec SDK', link: '/references/sdk', }, { diff --git a/src/get-started/overview/rlc.md b/src/get-started/overview/rlc.md index 0b6177b1..18d10512 100644 --- a/src/get-started/overview/rlc.md +++ b/src/get-started/overview/rlc.md @@ -17,6 +17,12 @@ confidential computation requires RLC. Every piece of protected data consumed requires RLC. Every app execution requires RLC. The more builders use our tools, the more utility RLC gains in real applications. +::: tip Info + +On the iExec sidechain (Bellecour), the RLC token symbol becomes **xRLC**. xRLC is the native token of the Bellecour chain and is used for all transactions and payments on this network. + +::: + ## 🎯 Why RLC Matters **Stack adoption = token usage.** When developers build with iExec tools, RLC From 9f207843ae339582c8bfba8326e8d39ee8054b6f Mon Sep 17 00:00:00 2001 From: Le-Caignec Date: Tue, 19 Aug 2025 21:13:43 +0200 Subject: [PATCH 19/33] docs: update links to point to Arbitrum mainnet and clarify network selection in documentation --- .../tooling-and-explorers/iexec-explorer.md | 20 +++++++---- .../advanced/create-your-first-sgx-app.md | 35 ------------------- .../advanced/quick-start-for-developers.md | 5 +-- src/guides/use-iapp/how-to-pay-executions.md | 4 +-- .../dataProtectorCore/processProtectedData.md | 4 +-- src/references/glossary.md | 2 +- src/references/web3mail/methods/sendEmail.md | 2 +- .../web3telegram/methods/sendTelegram.md | 2 +- 8 files changed, 23 insertions(+), 51 deletions(-) diff --git a/src/get-started/tooling-and-explorers/iexec-explorer.md b/src/get-started/tooling-and-explorers/iexec-explorer.md index af44feb9..aa36c634 100644 --- a/src/get-started/tooling-and-explorers/iexec-explorer.md +++ b/src/get-started/tooling-and-explorers/iexec-explorer.md @@ -18,6 +18,12 @@ explore apps and protectedData—all in one powerful dashboard. caption="🔗 Explore the iExec Protocol" /> +::: tip + +Before searching or exploring, make sure to select your desired network. The Explorer displays data for the network you choose. + +::: + ## 🎯 What you Can Explore @@ -72,7 +78,7 @@ explore apps and protectedData—all in one powerful dashboard. @@ -98,7 +104,7 @@ explore apps and protectedData—all in one powerful dashboard. @@ -114,14 +120,14 @@ Browse and analyze all tasks across the iExec network: @@ -150,7 +156,7 @@ Browse and analyze all tasks across the iExec network: @@ -165,7 +171,7 @@ Explore the iExec application marketplace: @@ -182,7 +188,7 @@ Navigate the protected data landscape: diff --git a/src/guides/build-iapp/advanced/create-your-first-sgx-app.md b/src/guides/build-iapp/advanced/create-your-first-sgx-app.md index 161c84f2..8d3b70b8 100644 --- a/src/guides/build-iapp/advanced/create-your-first-sgx-app.md +++ b/src/guides/build-iapp/advanced/create-your-first-sgx-app.md @@ -65,41 +65,6 @@ touch sconify.sh chmod +x sconify.sh ``` -### Update chain json - -Make sure your `chain.json` content is as follows: - -```json -{ - "default": "bellecour", - "chains": { - "bellecour": { - "sms": { "scone": "https://sms.scone-debug.v8-bellecour.iex.ec" } - } - } -} -``` - -If you start from a new directory tree, you will need to replay the following -steps from [Build your first application](./your-first-app): - -- [Write the app](./your-first-app.md#write-the-app) Javascript or Python source - code in `src/` -- [Dockerize your app](./your-first-app.md#dockerize-your-app) -- [Push your app to Dockerhub](./your-first-app.md#push-your-app-to-dockerhub) - -As we mentioned earlier, the advantage of using **SCONE** is the ability to make -the application **Intel® SGX-enabled** without changing the source code. The -only thing we are going to do is rebuilding the app using the -Trusted-Execution-Environment tooling provided by **SCONE**. - -::: info - -SCONE provides TEE conversion tooling (Python, Java, ..) plus eventually TEE -base images for other languages (NodeJs). - -::: - ## Build the TEE docker image We will use the following script to wrap the sconification process, copy the diff --git a/src/guides/build-iapp/advanced/quick-start-for-developers.md b/src/guides/build-iapp/advanced/quick-start-for-developers.md index 2c3564bf..77124dd3 100644 --- a/src/guides/build-iapp/advanced/quick-start-for-developers.md +++ b/src/guides/build-iapp/advanced/quick-start-for-developers.md @@ -80,8 +80,9 @@ The iExec SDK creates the minimum configuration files: ::: -You can now connect to the blockchain. In the following steps, we will use the -[iExec sidechain (also called Bellecour)](/get-started/tooling-and-explorers/blockchain-explorer#bellecour) +You can now connect to the desired supported blockchain. In the following steps, we will use the chosen +blockchain to deploy and run your iExec app. See the +[supported blockchains](/get-started/tooling-and-explorers/blockchain-explorer) for a full list. You can now check your wallet content: diff --git a/src/guides/use-iapp/how-to-pay-executions.md b/src/guides/use-iapp/how-to-pay-executions.md index 9d1b4ccf..a099922b 100644 --- a/src/guides/use-iapp/how-to-pay-executions.md +++ b/src/guides/use-iapp/how-to-pay-executions.md @@ -28,7 +28,7 @@ your wallet to pay for executions. For detailed information on how to obtain RLC tokens, see our [RLC guide](/get-started/overview/rlc.md). -### Step 2: Transfer to iExec Sidechain +### Step 2: Stake RLC to Power Your iExec Tasks RLC tokens need to be staked on the iExec protocol to allow task payment. To do this, you should use the [iExec SDK](/references/sdk.md). @@ -49,7 +49,7 @@ const balance = await iexec.account.checkBalance('0xa0c15e...'); console.log('Nano RLC staked:', balance.stake.toString()); console.log('Nano RLC locked:', balance.locked.toString()); -// Deposit RLC to the sidechain +// Lock RLC in your account in the iExec protocol await iexec.account.deposit(1_000_000_000); // Deposit 1 RLC ``` diff --git a/src/references/dataProtector/dataProtectorCore/processProtectedData.md b/src/references/dataProtector/dataProtectorCore/processProtectedData.md index f1feb735..092694f3 100644 --- a/src/references/dataProtector/dataProtectorCore/processProtectedData.md +++ b/src/references/dataProtector/dataProtectorCore/processProtectedData.md @@ -464,8 +464,8 @@ Identifies the specific deal associated with this transaction. `string` A unique identifier associated with a task currently running on the iExec -Bellecour side chain. You can monitor task execution using the -[iExec blockchain explorer](https://explorer.iex.ec). +protocol. You can monitor task execution using the +[iExec blockchain explorer](https://explorer.iex.ec/arbitrum-mainnet). ::: tip diff --git a/src/references/glossary.md b/src/references/glossary.md index 9be08c24..160e92d6 100644 --- a/src/references/glossary.md +++ b/src/references/glossary.md @@ -22,7 +22,7 @@ iExec’s product sidechain. It is linked to Ethereum Mainnet with a bridge allowing for the transfer of assets between networks. It allows iExec to be used without paying Ethereum gas fees. -See “Sidechain and xRLC” for more information. +See "Sidechain" and "xRLC" for more information. ### Beneficiary diff --git a/src/references/web3mail/methods/sendEmail.md b/src/references/web3mail/methods/sendEmail.md index 74fcc888..875e5fb0 100644 --- a/src/references/web3mail/methods/sendEmail.md +++ b/src/references/web3mail/methods/sendEmail.md @@ -321,7 +321,7 @@ import { type SendEmailResponse } from '@iexec/web3mail'; This uniquely identifies the email task on the iExec side chain. You can view the status of the `sendEmail` method by monitoring the task on the -[iExec Explorer](https://explorer.iex.ec/bellecour). +[iExec Explorer](https://explorer.iex.ec/arbitrum-mainnet). ## Error Handling diff --git a/src/references/web3telegram/methods/sendTelegram.md b/src/references/web3telegram/methods/sendTelegram.md index f9a39731..cbed507d 100644 --- a/src/references/web3telegram/methods/sendTelegram.md +++ b/src/references/web3telegram/methods/sendTelegram.md @@ -292,7 +292,7 @@ import { type SendTelegramResponse } from '@iexec/web3telegram'; This uniquely identifies the telegram task on the iExec side chain. You can view the status of the `sendTelegram` method by monitoring the task on the -[iExec Explorer](https://explorer.iex.ec/bellecour). +[iExec Explorer](https://explorer.iex.ec/arbitrum-mainnet). From a6855def7f53c43c1d775ab8f18412f3dc9044b7 Mon Sep 17 00:00:00 2001 From: Le-Caignec Date: Thu, 21 Aug 2025 00:15:50 +0200 Subject: [PATCH 23/33] feat: update iExec Explorer links to use dynamic URL based on selected chain --- .../tooling-and-explorers/iexec-explorer.md | 26 +++++++++++++------ .../dataProtectorCore/processProtectedData.md | 20 +++++++++++--- src/references/web3mail/methods/sendEmail.md | 13 +++++++++- .../web3telegram/methods/sendTelegram.md | 13 +++++++++- src/utils/chain.utils.ts | 3 +++ 5 files changed, 62 insertions(+), 13 deletions(-) diff --git a/src/get-started/tooling-and-explorers/iexec-explorer.md b/src/get-started/tooling-and-explorers/iexec-explorer.md index 43b862d7..67875188 100644 --- a/src/get-started/tooling-and-explorers/iexec-explorer.md +++ b/src/get-started/tooling-and-explorers/iexec-explorer.md @@ -14,7 +14,7 @@ explore apps and protectedData—all in one powerful dashboard. @@ -79,7 +79,7 @@ Explorer displays data for the network you choose. @@ -105,7 +105,7 @@ Explorer displays data for the network you choose. @@ -121,14 +121,14 @@ Browse and analyze all tasks across the iExec network: @@ -157,7 +157,7 @@ Browse and analyze all tasks across the iExec network: @@ -172,7 +172,7 @@ Explore the iExec application marketplace: @@ -189,7 +189,7 @@ Navigate the protected data landscape: @@ -202,9 +202,19 @@ Explore the decentralized computing infrastructure: - **Usage Statistics**: Analyze workerpool utilization diff --git a/src/references/web3mail/methods/sendEmail.md b/src/references/web3mail/methods/sendEmail.md index 875e5fb0..0eff5c34 100644 --- a/src/references/web3mail/methods/sendEmail.md +++ b/src/references/web3mail/methods/sendEmail.md @@ -321,7 +321,8 @@ import { type SendEmailResponse } from '@iexec/web3mail'; This uniquely identifies the email task on the iExec side chain. You can view the status of the `sendEmail` method by monitoring the task on the -[iExec Explorer](https://explorer.iex.ec/arbitrum-mainnet). +iExec blockchain +explorer . ## Error Handling @@ -392,7 +393,17 @@ For any other errors, you'll get a `WorkflowError` error in the form of: ``` diff --git a/src/references/web3telegram/methods/sendTelegram.md b/src/references/web3telegram/methods/sendTelegram.md index cbed507d..9e75c8e7 100644 --- a/src/references/web3telegram/methods/sendTelegram.md +++ b/src/references/web3telegram/methods/sendTelegram.md @@ -292,9 +292,20 @@ import { type SendTelegramResponse } from '@iexec/web3telegram'; This uniquely identifies the telegram task on the iExec side chain. You can view the status of the `sendTelegram` method by monitoring the task on the -[iExec Explorer](https://explorer.iex.ec/arbitrum-mainnet). +iExec blockchain +explorer . diff --git a/src/utils/chain.utils.ts b/src/utils/chain.utils.ts index 491c4230..58f171fd 100644 --- a/src/utils/chain.utils.ts +++ b/src/utils/chain.utils.ts @@ -23,6 +23,7 @@ export interface Chain { url: string; }; }; + iexecExplorerUrl: string; } export function getSupportedChains(): Chain[] { @@ -34,6 +35,7 @@ export function getSupportedChains(): Chain[] { nativeCurrency: arbitrum.nativeCurrency, rpcUrls: arbitrum.rpcUrls, blockExplorers: arbitrum.blockExplorers, + iexecExplorerUrl: 'https://explorer.iex.ec/arbitrum-mainnet', }, { id: Number(bellecour.id), @@ -49,6 +51,7 @@ export function getSupportedChains(): Chain[] { 'https://blockscout-bellecour.iex.ec', }, }, + iexecExplorerUrl: 'https://explorer.iex.ec/bellecour', }, ]; } From 6b8161c2af8c839fa716b5948f5fd2fddf109832 Mon Sep 17 00:00:00 2001 From: Le-Caignec Date: Thu, 21 Aug 2025 09:54:51 +0200 Subject: [PATCH 24/33] refactor: update blockchain node URLs and remove deprecated workerpool references in documentation --- src/guides/use-iapp/how-to-pay-executions.md | 3 +- .../run-iapp-without-ProtectedData.md | 6 +-- .../advanced/advanced-configuration.md | 9 ++-- .../consume/consumeProtectedData.md | 8 ---- .../web3mail/advanced-configuration.md | 20 +++------ src/references/web3mail/methods/sendEmail.md | 11 +---- .../web3telegram/advanced-configuration.md | 21 ++++------ .../web3telegram/methods/fetchUserContacts.md | 2 +- .../web3telegram/methods/sendTelegram.md | 42 +++++++------------ 9 files changed, 39 insertions(+), 83 deletions(-) diff --git a/src/guides/use-iapp/how-to-pay-executions.md b/src/guides/use-iapp/how-to-pay-executions.md index bbeefe93..6ab24d15 100644 --- a/src/guides/use-iapp/how-to-pay-executions.md +++ b/src/guides/use-iapp/how-to-pay-executions.md @@ -37,7 +37,7 @@ this, you should use the [iExec SDK](/references/sdk.md). import { IExec, utils } from 'iexec'; const ethProvider = utils.getSignerFromPrivateKey( - 'bellecour', // blockchain node URL + 'chain', // blockchain node URL 'PRIVATE_KEY' ); const iexec = new IExec({ @@ -136,7 +136,6 @@ const sendTelegram = await web3telegram.sendTelegram({ telegramContent: 'My telegram message content', senderName: 'Awesome project team', label: 'some-custom-id', - workerpoolAddressOrEns: 'prod-v8-bellecour.main.pools.iexec.eth', dataMaxPrice: 42, appMaxPrice: 42, workerpoolMaxPrice: 42, diff --git a/src/guides/use-iapp/run-iapp-without-ProtectedData.md b/src/guides/use-iapp/run-iapp-without-ProtectedData.md index 0d008e98..0a05fd36 100644 --- a/src/guides/use-iapp/run-iapp-without-ProtectedData.md +++ b/src/guides/use-iapp/run-iapp-without-ProtectedData.md @@ -47,7 +47,7 @@ blockchain. import { IExec, utils } from 'iexec'; const ethProvider = utils.getSignerFromPrivateKey( - 'bellecour', // blockchain node URL + 'chain', // blockchain node URL 'PRIVATE_KEY' ); const iexec = new IExec({ @@ -98,7 +98,7 @@ execution. import { IExec, utils } from 'iexec'; const ethProvider = utils.getSignerFromPrivateKey( - 'bellecour', // blockchain node URL + 'chain', // blockchain node URL 'PRIVATE_KEY' ); const iexec = new IExec({ @@ -155,7 +155,7 @@ securely and made available to the iApp as environment variables. import { IExec, utils } from 'iexec'; const ethProvider = utils.getSignerFromPrivateKey( - 'bellecour', // blockchain node URL + 'chain', // blockchain node URL 'PRIVATE_KEY' ); const iexec = new IExec({ diff --git a/src/references/dataProtector/advanced/advanced-configuration.md b/src/references/dataProtector/advanced/advanced-configuration.md index b6cbcde9..780fc0e9 100644 --- a/src/references/dataProtector/advanced/advanced-configuration.md +++ b/src/references/dataProtector/advanced/advanced-configuration.md @@ -74,8 +74,7 @@ import { IExecDataProtector, getWeb3Provider } from '@iexec/dataprotector'; const web3Provider = getWeb3Provider('PRIVATE_KEY'); // ---cut--- const dataProtector = new IExecDataProtector(web3Provider, { - subgraphUrl: - 'https://thegraph-product.iex.ec/subgraphs/name/bellecour/dataprotector', // [!code focus] + subgraphUrl: 'subgraph-url', // [!code focus] }); ``` @@ -94,7 +93,7 @@ import { IExecDataProtector, getWeb3Provider } from '@iexec/dataprotector'; const web3Provider = getWeb3Provider('PRIVATE_KEY'); // ---cut--- const dataProtector = new IExecDataProtector(web3Provider, { - ipfsNode: 'https://ipfs-upload.v8-bellecour.iex.ec', // [!code focus] + ipfsNode: 'ipfs-node-url', // [!code focus] }); ``` @@ -114,7 +113,7 @@ import { IExecDataProtector, getWeb3Provider } from '@iexec/dataprotector'; const web3Provider = getWeb3Provider('PRIVATE_KEY'); // ---cut--- const dataProtector = new IExecDataProtector(web3Provider, { - ipfsGateway: 'https://ipfs-gateway.v8-bellecour.iex.ec', // [!code focus] + ipfsGateway: 'ipfs-gateway-url', // [!code focus] }); ``` @@ -130,7 +129,7 @@ import { IExecDataProtector, getWeb3Provider } from '@iexec/dataprotector'; const web3Provider = getWeb3Provider('PRIVATE_KEY'); // ---cut--- const dataProtector = new IExecDataProtector(web3Provider, { - iexecOptions: { smsURL: 'https://sms.scone-prod.v8-bellecour.iex.ec' }, // [!code focus] + iexecOptions: { smsURL: 'sms-url' }, // [!code focus] }); ``` diff --git a/src/references/dataProtector/dataProtectorSharing/consume/consumeProtectedData.md b/src/references/dataProtector/dataProtectorSharing/consume/consumeProtectedData.md index 53615b2f..4c0a0018 100644 --- a/src/references/dataProtector/dataProtectorSharing/consume/consumeProtectedData.md +++ b/src/references/dataProtector/dataProtectorSharing/consume/consumeProtectedData.md @@ -177,14 +177,6 @@ const consumeProtectedDataResult = }); ``` -::: tip - -iExec currently offers a production workerpool located at the Ethereum Name -Service (ENS) address `prod-v8-bellecour.main.pools.iexec.eth`. This is the -default workerpool for running confidential computations on the iExec platform. - -::: - ### maxPrice **Type:** `number` diff --git a/src/references/web3mail/advanced-configuration.md b/src/references/web3mail/advanced-configuration.md index 177b2205..0adbfa63 100644 --- a/src/references/web3mail/advanced-configuration.md +++ b/src/references/web3mail/advanced-configuration.md @@ -23,19 +23,13 @@ import { type Web3MailConfigOptions } from '@iexec/web3mail'; The Ethereum contract address or ENS (Ethereum Name Service) for the web3mail iApp. -If not provided, the default ENS `web3mail.apps.iexec.eth` pointing to the -latest version of the web3mail iApp provided by iExec will be used. - -You can find the corresponding iApp address with Bellecour explorer: -[https://explorer.iex.ec/bellecour/search/web3mail.apps.iexec.eth](https://explorer.iex.ec/bellecour/search/web3mail.apps.iexec.eth). - ```ts twoslash import { IExecWeb3mail, getWeb3Provider } from '@iexec/web3mail'; const web3Provider = getWeb3Provider('PRIVATE_KEY'); // ---cut--- const web3mail = new IExecWeb3mail(web3Provider, { - dappAddressOrENS: 'web3mail.apps.iexec.eth', // [!code focus] + dappAddressOrENS: '0x456def...', // [!code focus] }); ``` @@ -54,13 +48,10 @@ import { IExecWeb3mail, getWeb3Provider } from '@iexec/web3mail'; const web3Provider = getWeb3Provider('PRIVATE_KEY'); // ---cut--- const web3mail = new IExecWeb3mail(web3Provider, { - dappWhitelistAddress: '0x781482C39CcE25546583EaC4957Fb7Bf04C277D2', // [!code focus] + dappWhitelistAddress: '0x456def...', // [!code focus] }); ``` -See it in -[https://blockscout-bellecour.iex.ec/](https://blockscout-bellecour.iex.ec/address/0x781482C39CcE25546583EaC4957Fb7Bf04C277D2) - ### dataProtectorSubgraph The subgraph URL for querying data. @@ -74,8 +65,7 @@ import { IExecWeb3mail, getWeb3Provider } from '@iexec/web3mail'; const web3Provider = getWeb3Provider('PRIVATE_KEY'); // ---cut--- const web3mail = new IExecWeb3mail(web3Provider, { - dataProtectorSubgraph: - 'https://thegraph-product.iex.ec/subgraphs/name/bellecour/dataprotector', // [!code focus] + dataProtectorSubgraph: 'subgraph-url', // [!code focus] }); ``` @@ -92,7 +82,7 @@ import { IExecWeb3mail, getWeb3Provider } from '@iexec/web3mail'; const web3Provider = getWeb3Provider('PRIVATE_KEY'); // ---cut--- const web3mail = new IExecWeb3mail(web3Provider, { - ipfsNode: 'https://ipfs-upload.v8-bellecour.iex.ec', // [!code focus] + ipfsNode: 'ipfs-node-url', // [!code focus] }); ``` @@ -110,7 +100,7 @@ import { IExecWeb3mail, getWeb3Provider } from '@iexec/web3mail'; const web3Provider = getWeb3Provider('PRIVATE_KEY'); // ---cut--- const web3mail = new IExecWeb3mail(web3Provider, { - ipfsGateway: 'https://ipfs-gateway.v8-bellecour.iex.ec', // [!code focus] + ipfsGateway: 'ipfs-gateway-url', // [!code focus] }); ``` diff --git a/src/references/web3mail/methods/sendEmail.md b/src/references/web3mail/methods/sendEmail.md index 0eff5c34..53e2800f 100644 --- a/src/references/web3mail/methods/sendEmail.md +++ b/src/references/web3mail/methods/sendEmail.md @@ -216,7 +216,8 @@ const sendEmail = await web3mail.sendEmail({ ### workerpoolAddressOrEns **Type:** `workerpoolAddressOrEns` -**Default:** iExec's production workerpool +**Default:** `prod-v8-bellecour.main.pools.iexec.eth` (iExec's production +workerpool) Allows specifying the workerpool that will run the Web3Mail application. @@ -234,14 +235,6 @@ const sendEmail = await web3mail.sendEmail({ }); ``` -::: tip - -iExec currently offers a production workerpool located at the Ethereum Name -Service (ENS) address `prod-v8-bellecour.main.pools.iexec.eth`. This is the -default workerpool for running confidential computations on the iExec platform. - -::: - ### dataMaxPrice **Type:** `number` diff --git a/src/references/web3telegram/advanced-configuration.md b/src/references/web3telegram/advanced-configuration.md index b5229405..bef05dab 100644 --- a/src/references/web3telegram/advanced-configuration.md +++ b/src/references/web3telegram/advanced-configuration.md @@ -23,11 +23,8 @@ import { type Web3TelegramConfigOptions } from '@iexec/web3telegram'; The Ethereum contract address or ENS (Ethereum Name Service) for the web3telegram iApp. -If not provided, the default ENS `web3telegram.apps.iexec.eth` pointing to the -latest version of the web3telegram iApp provided by iExec will be used. - -You can find the corresponding iApp address with Bellecour explorer: -[https://explorer.iex.ec/bellecour/search/web3telegram.apps.iexec.eth](https://explorer.iex.ec/bellecour/search/web3telegram.apps.iexec.eth). +If not provided, the default ENS web3telegram iApp provided by iExec will be +used. ```ts twoslash import { IExecWeb3telegram, getWeb3Provider } from '@iexec/web3telegram'; @@ -35,7 +32,7 @@ import { IExecWeb3telegram, getWeb3Provider } from '@iexec/web3telegram'; const web3Provider = getWeb3Provider('PRIVATE_KEY'); // ---cut--- const web3telegram = new IExecWeb3telegram(web3Provider, { - dappAddressOrENS: 'web3telegram.apps.iexec.eth', // [!code focus] + dappAddressOrENS: '0x456def...', // [!code focus] }); ``` @@ -54,13 +51,10 @@ import { IExecWeb3telegram, getWeb3Provider } from '@iexec/web3telegram'; const web3Provider = getWeb3Provider('PRIVATE_KEY'); // ---cut--- const web3telegram = new IExecWeb3telegram(web3Provider, { - dappWhitelistAddress: '0x192C6f5AccE52c81Fcc2670f10611a3665AAA98F', // [!code focus] + dappWhitelistAddress: '0x456def...', // [!code focus] }); ``` -See it in -[https://blockscout-bellecour.iex.ec/](https://blockscout-bellecour.iex.ec/address/0x192C6f5AccE52c81Fcc2670f10611a3665AAA98F) - ### dataProtectorSubgraph The subgraph URL for querying data. @@ -74,8 +68,7 @@ import { IExecWeb3telegram, getWeb3Provider } from '@iexec/web3telegram'; const web3Provider = getWeb3Provider('PRIVATE_KEY'); // ---cut--- const web3telegram = new IExecWeb3telegram(web3Provider, { - dataProtectorSubgraph: - 'https://thegraph-product.iex.ec/subgraphs/name/bellecour/dataprotector', // [!code focus] + dataProtectorSubgraph: 'subgraph-url', // [!code focus] }); ``` @@ -92,7 +85,7 @@ import { IExecWeb3telegram, getWeb3Provider } from '@iexec/web3telegram'; const web3Provider = getWeb3Provider('PRIVATE_KEY'); // ---cut--- const web3telegram = new IExecWeb3telegram(web3Provider, { - ipfsNode: 'https://ipfs-upload.v8-bellecour.iex.ec', // [!code focus] + ipfsNode: 'ipfs-node-url', // [!code focus] }); ``` @@ -110,7 +103,7 @@ import { IExecWeb3telegram, getWeb3Provider } from '@iexec/web3telegram'; const web3Provider = getWeb3Provider('PRIVATE_KEY'); // ---cut--- const web3telegram = new IExecWeb3telegram(web3Provider, { - ipfsGateway: 'https://ipfs-gateway.v8-bellecour.iex.ec', // [!code focus] + ipfsGateway: 'ipfs-gateway-url', // [!code focus] }); ``` diff --git a/src/references/web3telegram/methods/fetchUserContacts.md b/src/references/web3telegram/methods/fetchUserContacts.md index 815514a3..582ef300 100644 --- a/src/references/web3telegram/methods/fetchUserContacts.md +++ b/src/references/web3telegram/methods/fetchUserContacts.md @@ -33,7 +33,7 @@ import { type FetchUserContactsParams } from '@iexec/web3telegram'; ### userAddress -`Address` +**Type:** `Address` The entity for which you wish to obtain the list of contacts. diff --git a/src/references/web3telegram/methods/sendTelegram.md b/src/references/web3telegram/methods/sendTelegram.md index 9e75c8e7..8637dbfb 100644 --- a/src/references/web3telegram/methods/sendTelegram.md +++ b/src/references/web3telegram/methods/sendTelegram.md @@ -41,7 +41,6 @@ const sendTelegram = await web3telegram.sendTelegram({ telegramContent: 'My telegram message content', senderName: 'Awesome project team', label: 'some-custom-id', - workerpoolAddressOrEns: 'prod-v8-bellecour.main.pools.iexec.eth', dataMaxPrice: 42, appMaxPrice: 42, workerpoolMaxPrice: 42, @@ -56,7 +55,7 @@ import { type SendTelegramParams } from '@iexec/web3telegram'; ### protectedData -`Address` +**Type:** `Address` The address of the `protectedData` holding the contact's telegram chat ID. @@ -76,7 +75,7 @@ const sendTelegram = await web3telegram.sendTelegram({ ### senderName -`string` +**Type:** `string` The name of the telegram message sender. @@ -96,9 +95,7 @@ const sendTelegram = await web3telegram.sendTelegram({ ### telegramContent -`string` - -_maximum size_: 512 kb +**Type:**`string` **Maximum siz:** `512 kb` The telegram message content that needs to be sent. The content is limited to 512 kb in size. Telegram content is encrypted and stored in IPFS. @@ -119,7 +116,8 @@ const sendTelegram = await web3telegram.sendTelegram({ ### useVoucher -**Type:** `boolean` +**Type:** `boolean` + **Default:** `false` This optional param allows you to pay for the deal using your voucher. Make sure @@ -137,7 +135,6 @@ const sendTelegram = await web3telegram.sendTelegram({ telegramContent: 'My telegram message content', senderName: 'Awesome project team', label: 'some-custom-id', - workerpoolAddressOrEns: 'prod-v8-bellecour.main.pools.iexec.eth', dataMaxPrice: 42, appMaxPrice: 42, workerpoolMaxPrice: 42, @@ -156,7 +153,7 @@ sufficient funds for this transfer to proceed. ### label -`string | undefined` +**Type:** `string | undefined` Allows adding a custom public label. The Web3telegram tool writes this onchain as `iexec_args` in the deal params. @@ -178,9 +175,10 @@ const sendTelegram = await web3telegram.sendTelegram({ ### workerpoolAddressOrEns -`workerpoolAddressOrEns | undefined` +**Type:** `workerpoolAddressOrEns | undefined` -_default_: iExec's production workerpool +**Default:** `prod-v8-bellecour.main.pools.iexec.eth` (iExec's production +workerpool) Allows specifying the workerpool that will run the Web3Telegram application. @@ -199,19 +197,11 @@ const sendTelegram = await web3telegram.sendTelegram({ }); ``` -::: tip - -iExec currently offers a production workerpool located at the Ethereum Name -Service (ENS) address `prod-v8-bellecour.main.pools.iexec.eth`. This is the -default workerpool for running confidential computations on the iExec platform. - -::: - ### dataMaxPrice -`number | undefined` +**Type:** `number | undefined` -_default_: `0` +**Default:** `0` Allows specifying the maximum amount (in nRLC) you are willing to pay the telegram chat ID owner for using their data. The owner of the protected chat ID @@ -234,9 +224,9 @@ const sendTelegram = await web3telegram.sendTelegram({ ### appMaxPrice -`number | undefined` +**Type:** `number | undefined` -_default_: `0` +**Default:** `0` Allows specifying the maximum amount (in nRLC) you are willing to pay the Web3telegram app provider (iExec) for using the Web3telegram application. @@ -258,9 +248,9 @@ const sendTelegram = await web3telegram.sendTelegram({ ### workerpoolMaxPrice -`number | undefined` +**Type:** `number | undefined` -_default_: `0` +**Default:** `0` Allows specifying the maximum amount you want to pay the workerpool provider for using their infrastructure to run the web3telegram app in nRLC. @@ -288,7 +278,7 @@ import { type SendTelegramResponse } from '@iexec/web3telegram'; ### taskId -`Addess` +**Type:** `Address` This uniquely identifies the telegram task on the iExec side chain. You can view the status of the `sendTelegram` method by monitoring the task on the From f85de929b7f3c25f9e4387ebd912939e874cd55e Mon Sep 17 00:00:00 2001 From: Le-Caignec Date: Thu, 21 Aug 2025 12:51:50 +0200 Subject: [PATCH 25/33] refactor: streamline advanced iApp documentation and remove deprecated sections - Removed outdated references and sections from the advanced iApp guides, including the overview and SGX encrypted dataset. - Updated sidebar to reflect the changes in the advanced section. - Enhanced documentation with dynamic chain name integration for commands. - Removed unused image assets and improved clarity in examples. --- .vitepress/sidebar.ts | 10 +- src/assets/explorer-dataset-example.png | Bin 113104 -> 0 bytes .../advanced/access-confidential-assets.md | 15 +- .../advanced/create-your-first-sgx-app.md | 24 +- .../advanced/create-your-first-tdx-app.md | 6 +- .../advanced/end-to-end-encryption.md | 28 +- src/guides/build-iapp/advanced/overview.md | 32 -- .../advanced/quick-start-for-developers.md | 69 ++-- .../advanced/sgx-encrypted-dataset.md | 365 ------------------ .../build-iapp/advanced/your-first-app.md | 35 +- src/guides/build-iapp/manage-access.md | 26 +- .../dataProtector/advanced/apps-whitelist.md | 3 - .../dataProtectorCore/processProtectedData.md | 14 +- .../dataProtectorCore/protectData.md | 19 +- .../consume/consumeProtectedData.md | 16 +- src/references/web3mail/methods/sendEmail.md | 6 +- .../web3telegram/methods/sendTelegram.md | 6 +- src/utils/chain.utils.ts | 9 + 18 files changed, 175 insertions(+), 508 deletions(-) delete mode 100644 src/assets/explorer-dataset-example.png delete mode 100644 src/guides/build-iapp/advanced/overview.md delete mode 100644 src/guides/build-iapp/advanced/sgx-encrypted-dataset.md diff --git a/.vitepress/sidebar.ts b/.vitepress/sidebar.ts index 698c955a..9f814918 100644 --- a/.vitepress/sidebar.ts +++ b/.vitepress/sidebar.ts @@ -202,10 +202,6 @@ export function getSidebar() { text: 'Advanced', collapsed: true, items: [ - { - text: 'Overview', - link: '/guides/build-iapp/advanced/overview', - }, { text: 'Quick Start for Developers', link: '/guides/build-iapp/advanced/quick-start-for-developers', @@ -215,17 +211,13 @@ export function getSidebar() { link: '/guides/build-iapp/advanced/your-first-app', }, { - text: 'Build your first SGX app (SCONE)', + text: 'Build your first SGX app', link: '/guides/build-iapp/advanced/create-your-first-sgx-app', }, { text: 'End-to-end Encryption', link: '/guides/build-iapp/advanced/end-to-end-encryption', }, - { - text: 'SGX Encrypted Dataset', - link: '/guides/build-iapp/advanced/sgx-encrypted-dataset', - }, { text: 'Access Confidential Assets', link: '/guides/build-iapp/advanced/access-confidential-assets', diff --git a/src/assets/explorer-dataset-example.png b/src/assets/explorer-dataset-example.png deleted file mode 100644 index 8041b03d45ba85e9fd362dc54b7a737071202f74..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 113104 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
XB7sr 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 P-O5TTNmPix`}{uu?7cD* diff --git a/src/guides/build-iapp/advanced/access-confidential-assets.md b/src/guides/build-iapp/advanced/access-confidential-assets.md index 4a245b95..a3462ebc 100644 --- a/src/guides/build-iapp/advanced/access-confidential-assets.md +++ b/src/guides/build-iapp/advanced/access-confidential-assets.md @@ -31,13 +31,10 @@ The SMS currently supports 3 types of secrets: is not linked to any application. When a requester buys a task, the requester can declare which secrets can be accessed by the application. Doing so, a single requester secret can be shared with multiple applications. -3. [Dataset secret](sgx-encrypted-dataset.md): A dataset secret is not directly - accessible from the application but its decrypted content is. If a dataset is - requested and authorized to be used in it, its content will be automatically - decrypted in the application enclave. To monetize such a dataset on iExec, - the original dataset must be encrypted using the iExec SDK, its encrypted - counterpart must be publicly available and its encryption key pushed into the - SMS. +3. [Protected Data secret](/guides/manage-data/manage-access): A protected data + secret is not directly accessible from the application but its decrypted + content is. If a Protected Data is requested and authorized to be used in it, + its content will be automatically decrypted in the application enclave. Here is a general overview of how confidential assets are used on iExec: @@ -45,7 +42,7 @@ Here is a general overview of how confidential assets are used on iExec: graph TD Req[Requester] -->|1.a. Push secret| SMS[SMS] AppDev[Application developer] -->|1.b. Push secret| SMS - DatasetOwn[Dataset owner] -->|1.c. Push secret| SMS + ProtectedDataOwn[ProtectedData owner] -->|1.c. Push secret| SMS Req --> |2 . Buy task| Chain Chain[Blockchain] --> |3 . Notify task to compute| Worker[Worker/Workerpool] Worker --> |4 . Launch TEE application| App[TEE application] @@ -58,4 +55,4 @@ graph TD You now understand how these three kinds of confidential assets work on iExec, you can go one step further by learning how to manipulate them: -- [Access a confidential dataset](sgx-encrypted-dataset.md) +- [Access to a Protected Data](guides/build-iapp/inputs-and-outputs) diff --git a/src/guides/build-iapp/advanced/create-your-first-sgx-app.md b/src/guides/build-iapp/advanced/create-your-first-sgx-app.md index ece4ac3a..65e4da71 100644 --- a/src/guides/build-iapp/advanced/create-your-first-sgx-app.md +++ b/src/guides/build-iapp/advanced/create-your-first-sgx-app.md @@ -225,8 +225,8 @@ docker run --rm -e SCONE_HASH=1 /tee-scone-hello-world:1.0.0-de Deploy the app with the standard command: -```bash -iexec app deploy +```bash twoslash +iexec app deploy --chain {{chainName}} ``` ### Run the TEE app @@ -239,8 +239,8 @@ a debug workerpool, use the debug workerpool You are now ready to run the app -```bash -iexec app run --tag tee,scone --workerpool debug-v8-learn.main.pools.iexec.eth --watch +```bash twoslash +iexec app run --chain {{chainName}} --tag tee,scone --workerpool debug-v8-learn.main.pools.iexec.eth --watch ``` ::: info @@ -248,9 +248,6 @@ iexec app run --tag tee,scone --workerpool debug-v8-learn.main.pools.iexec.eth - You noticed we used `debug-v8-learn.main.pools.iexec.eth` instead of an ethereum address, this is an ENS name. -The [ENS (Ethereum Name Service)](https://ens.domains/) protocol enables -associating decentralized naming to ethereum addresses. - ::: ::: info @@ -269,3 +266,16 @@ may need to use some confidential data to get the full potential of the - [Access confidential assets from your app](access-confidential-assets.md) - [Protect the result](end-to-end-encryption.md) + + diff --git a/src/guides/build-iapp/advanced/create-your-first-tdx-app.md b/src/guides/build-iapp/advanced/create-your-first-tdx-app.md index 92040ca7..7025944c 100644 --- a/src/guides/build-iapp/advanced/create-your-first-tdx-app.md +++ b/src/guides/build-iapp/advanced/create-your-first-tdx-app.md @@ -1,4 +1,4 @@ -# 🛡️ Build Intel TDX App (Experimental) +# 🛡️ Build Intel TDX App (Experimental) In this tutorial, you will learn how to build and run a Confidential Computing application with Intel TDX technology using both traditional deployment and the @@ -309,3 +309,7 @@ EXPERIMENTAL_TDX_APP=true iapp run in TDX - **[Advanced iApp Building](/guides/build-iapp/advanced/overview)** - Advanced development techniques + + diff --git a/src/guides/build-iapp/advanced/end-to-end-encryption.md b/src/guides/build-iapp/advanced/end-to-end-encryption.md index 5f7f19bb..a8831fe9 100644 --- a/src/guides/build-iapp/advanced/end-to-end-encryption.md +++ b/src/guides/build-iapp/advanced/end-to-end-encryption.md @@ -64,21 +64,22 @@ private key in the file `<0x-your-wallet-address>_key`. Now, push the public key to the SMS: -```bash -iexec result push-encryption-key --tee-framework scone +```bash twoslash +iexec result push-encryption-key --tee-framework --chain {{chainName}} scone ``` And check it using: -```bash -iexec result check-encryption-key --tee-framework scone +```bash twoslash +iexec result check-encryption-key --tee-framework --chain {{chainName}} scone ``` Now to see that in action, you'd need to trigger a task and specify yourself as the beneficiary in the command: -```bash +```bash twoslash iexec app run <0x-your-app-address> \ + --chain {{chainName}} --workerpool debug-v8-learn.main.pools.iexec.eth \ --tag tee,scone \ --encrypt-result \ @@ -87,8 +88,8 @@ iexec app run <0x-your-app-address> \ Wait for the task to be `COMPLETED` and download the result: -```bash -iexec task show <0x-your-task-id> --download +```bash twoslash +iexec task show --chain {{chainName}} <0x-your-task-id> --download ``` If you extract the obtained zip and try to read the content of the file @@ -134,3 +135,16 @@ the dataset, and the result. You can go to the advanced section and learn more about managing orders on the iExec to effectively monetize your applications and datasets. + + diff --git a/src/guides/build-iapp/advanced/overview.md b/src/guides/build-iapp/advanced/overview.md deleted file mode 100644 index 995a5319..00000000 --- a/src/guides/build-iapp/advanced/overview.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -title: Advanced iApp Building -description: - Legacy, low-level guides for building confidential iApp (Docker, SGX, TDX, - SCONE/Gramine, E2E encryption) ---- - -# ⚙️ Advanced iApp Building - -::: warning Important - -This section contains legacy, low-level material. Please note: - -- Terminology and some concepts may have changed in the current documentation. -- These topics are intentionally advanced and can be complex to understand. -- In most cases, you should not need to dive into this section — we’ve - simplified and streamlined recommended paths elsewhere in the docs. - -If you believe you truly need these advanced flows or you’re unsure which path -to take, please contact our support so we can understand your use case and help -you efficiently: [Join our Discord](https://discord.gg/9h25DQFSCU). - -::: - -- **[Quick Start for Developers](./quick-start-for-developers)** -- **[Build your first application](./your-first-app)** -- **[Intel SGX Technology](/get-started/protocol/tee/intel-sgx)** -- **[Build your first SGX app (SCONE)](./create-your-first-sgx-app)** -- **[End-to-end Encryption](./end-to-end-encryption)** -- **[SGX Encrypted Dataset](./sgx-encrypted-dataset)** -- **[Access Confidential Assets](./access-confidential-assets)** -- **[Build Intel TDX app](./create-your-first-tdx-app)** diff --git a/src/guides/build-iapp/advanced/quick-start-for-developers.md b/src/guides/build-iapp/advanced/quick-start-for-developers.md index 8a5e0932..13c15d5f 100644 --- a/src/guides/build-iapp/advanced/quick-start-for-developers.md +++ b/src/guides/build-iapp/advanced/quick-start-for-developers.md @@ -64,7 +64,7 @@ Ethereum wallet. See iExec SDK documentation Create a new folder for your iExec project and initialize the project: -```text +```bash mkdir ~/iexec-projects cd ~/iexec-projects iexec init --skip-wallet @@ -87,7 +87,7 @@ for a full list. You can now check your wallet content: -```text +```bash iexec wallet show ``` @@ -102,7 +102,7 @@ Let's deploy an iExec app! Initialize a new application -```text +```bash iexec app init ``` @@ -134,22 +134,22 @@ iExec. You will now deploy your app on iExec, this will be your first transaction on the blockchain: -```text -iexec app deploy +```bash twoslash +iexec app deploy --chain {{chainName}} ``` ::: tip While running `iexec app deploy` you sent your first transaction on the -bellecour blockchain. +{{chainName}} blockchain. ::: You can check your deployed apps with their index, let's check your last deployed app: -```text -iexec app show +```bash twoslash +iexec app show --chain {{chainName}} ``` ## Run your app on iExec @@ -173,21 +173,21 @@ At any time you can: - view your balance -```sh -iexec account show +```bash twoslash +iexec account show --chain {{chainName}} ``` - deposit RLC from your wallet to your iExec Account -```sh -iexec account deposit +```bash twoslash +iexec account deposit --chain {{chainName}} ``` - withdraw RLC from your iExec account to your wallet \(only stake can be withdrawn\) -```sh -iexec account withdraw +```bash twoslash +iexec account withdraw --chain {{chainName}} ``` ::: @@ -197,8 +197,8 @@ to pay for the computation. Everything is ready to run your application! -```text -iexec app run --args --workerpool prod-v8-learn.main.pools.iexec.eth --watch +```bash twoslash +iexec app run --chain {{chainName}} --args --workerpool prod-v8-learn.main.pools.iexec.eth --watch ``` ::: info @@ -253,14 +253,14 @@ is a 32Bytes hexadecimal string\). Download the result of your task -```text -iexec task show --download my-result +```bash twoslash +iexec task show --chain {{chainName}} --download my-result ``` You can get your taskid with the command: -```text -iexec deal show +```bash twoslash +iexec deal show --chain {{chainName}} ``` ::: info @@ -274,7 +274,7 @@ produce an text file in `result.txt`. Let's discover the result of the computation. -```text +```bash unzip my-result.zip -d my-result cat my-result/result.txt ``` @@ -301,13 +301,13 @@ The conditions to use an app are defined in the **apporder**. Publish a new apporder for your application. -```text -iexec app publish +```bash twoslash +iexec app publish --chain {{chainName}} ``` ::: info -`iexec app publish` options allows to define custom access rules to the app +`iexec app publish` command allows to define custom access rules to the app \(run `iexec app publish --help` to discover all the possibilities\). You will learn more about orders management later, keep the apporder default @@ -320,18 +320,14 @@ conditions defined in apporder. You can check the published apporders for your app -```text -iexec orderbook app +```bash twoslash +iexec orderbook app --chain {{chainName}} ``` Congratulation you just created a decentralized application! Anyone can now trigger an execution of your application on the iExec decentralized infrastructure. -- With the iexec SDK CLI - `iexec app run --workerpool prod-v8-learn.main.pools.iexec.eth` -- On iExec marketplace - ## What's next? You are now familiar with the following key iExec concepts for developers: @@ -346,3 +342,16 @@ You are now familiar with the following key iExec concepts for developers: Continue with these guides: - [Learn how to build your first application running on iExec](your-first-app.md) + + diff --git a/src/guides/build-iapp/advanced/sgx-encrypted-dataset.md b/src/guides/build-iapp/advanced/sgx-encrypted-dataset.md deleted file mode 100644 index 8eb068b1..00000000 --- a/src/guides/build-iapp/advanced/sgx-encrypted-dataset.md +++ /dev/null @@ -1,365 +0,0 @@ -# Access a confidential dataset - -In this tutorial, you will learn how to leverage an encrypted dataset by using -the `IEXEC_DATASET_FILENAME` environment variable in your application. - -::: tip Prerequisites: - -- Familiarity with the basic concepts of - [Intel® SGX](/get-started/protocol/tee/intel-sgx) and - [SCONE](https://scontain.com) framework. -- [Build With a Scone TEE application](create-your-first-sgx-app.md) - -::: - -Trusted Execution Environments offer a huge advantage from a security -perspective. They guarantee that the behavior of execution does not change even -when launched on an untrusted remote machine. The data inside this type of -environment is also protected, which allows its monetization while preventing -leakage. - -With iExec, it is possible to authorize only applications you trust to use your -datasets and get paid for it. Data is encrypted using standard encryption -mechanisms and the plain version never leaves your machine. The encrypted -version is made available for usage and the encryption key is pushed into the -[SMS](/get-started/protocol/tee/intel-sgx#secret-management-service-sms). After -you deploy the dataset on iExec it is you, and only you, who decides which -application is allowed to get the secret to decrypt it. - -::: warning - -Datasets are only decrypted inside authorized -[enclaves](/get-started/protocol/tee/intel-sgx) and never leave them. The same -thing applies to secrets. - -::: - -::: info - -Your secrets are transferred with the SDK from your machine to the SMS over a -TLS channel. - -::: - -Let's see how to do all of that! - -## Encrypt the dataset - -Before starting, let's make sure we are inside the `~/iexec-projects` folder -previously created during the [quick start](./quick-start-for-developers.md) -tutorial. - -```bash -cd ~/iexec-projects -mkdir tee-dataset-app && cd tee-dataset-app -iexec init --skip-wallet -``` - -Make sure your `chain.json` content is the same as the one described -[here](create-your-first-sgx-app.md#update-chain-json). - -Init the dataset configuration. - -```bash -iexec dataset init --encrypted -``` - -This command will create the `datasets/encrypted`, `datasets/original` and -`.secrets/datasets` folders. A new `dataset` section will be added to the -`iexec.json` file as well. - -```bash -. -├── datasets -│ ├── encrypted -│ └── original -└── .secrets - └── datasets -``` - -We will create a dummy file that has `"Hello, world!"` as content inside -`datasets/original`. Alternatively, you can put your own dataset file. - -```bash -echo "Hello, confidential world!" > datasets/original/my-first-dataset.txt -``` - -```bash -datasets -├── encrypted -└── original - └── my-first-dataset.txt -``` - -Now run the following command to encrypt the file: - -```bash -iexec dataset encrypt -``` - -::: info - -`iexec dataset encrypt` will output a checksum, keep this value for a later use. - -::: - -```bash -datasets -├── encrypted -│ └── my-first-dataset.txt.enc -└── original - └── my-first-dataset.txt -``` - -As you can see, the command generated the file -`datasets/encrypted/my-first-dataset.txt.enc`. That file is the encrypted -version of your dataset, you should push it somewhere accessible because the -worker will download it during the execution process. You will enter this file's -URI in the `iexec.json`file (`multiaddr` attribute) when you will deploy your -dataset. Make sure that the URI is a **DIRECT** download link (not a link to a -web page for example). - -::: info - -You can use Github for example to publish the file but you should add **/raw/** -to the URI like this: -[https://github.com/<username>/<repo>/raw/master/my-first-dataset.txt.enc](https://github.com///raw/master/my-first-dataset.txt.enc) - -::: - -The file `.secrets/datasets/my-first-dataset.txt.key` is the encryption key, -make sure to back it up securely. The file `.secrets/datasets/dataset.key` is -just an "alias" in the sense that it is the key of the last encrypted dataset. - -```bash -.secrets -└── datasets - ├── dataset.key - └── my-first-dataset.txt.key -``` - -## Deploy the dataset - -Fill in the fields of the `iexec.json` file. Choose a `name` for your dataset, -put the encrypted file's URI in `multiaddr` (the URI you got after publishing -the file) and fill the `checksum` field. The `checksum` of the dataset consists -of a `0x` prefix followed by the `sha256sum` of the dataset. This `checksum` is -printed when running the `iexec dataset encrypt` command. If you missed it, you -can retrieve the `sha256sum` of the dataset by running -`sha256sum datasets/encrypted/my-first-dataset.txt.enc`. - -```bash -$ cat iexec.json -{ - "description": "My iExec ressource description...", - - ... - - "dataset": { - "owner": "0x-your-wallet-address", - "name": "Encrypted hello world dataset", - "multiaddr": "/ipfs/QmW2WQi7j6c7UgJTarActp7tDNikE4B2qXtFCfLPdsgaTQ", - "checksum": "<0x-sha256sum-of-the-dataset>" // starts with 0x - } -} -``` - -To deploy your dataset run: - -```bash -iexec dataset deploy -``` - -You will get a hexadecimal address for your deployed dataset. Use that address -to push the encryption key to the [SMS](/get-started/protocol/tee/intel-sgx) so -it is available for authorized applications. - -For simplicity, we will use the dataset with a TEE-debug app on a debug -workerpool. The debug workerpool is connected to a debug Secret Management -Service so we will send the dataset encryption key to this SMS (this is fine for -debugging but do not use to store production secrets). - -### Push the dataset secret to the SMS - -```bash -iexec dataset push-secret -``` - -### Check secret availability on the SMS - -```bash -iexec dataset check-secret -``` - -We saw in this section how to encrypt a dataset and deploy it on iExec. In -addition, we learned how to push the encryption secret to the -[SMS](/get-started/protocol/tee/intel-sgx). Now we need to build the application -that is going to consume this dataset. - -## Prepare your application - -::: warning - -For demo purposes, we omitted some development best practices in these examples. - -Make sure to check your field's best practices before going to production. - -::: - -Let's create a directory tree for this app in `~/iexec-projects/`. - -```bash -cd ~/iexec-projects/tee-dataset-app -mkdir src -touch Dockerfile -touch sconify.sh -chmod +x sconify.sh -``` - -In the folder `src/` create the file `app.js` or `app.py` then copy this code -inside: - -The application reads the content of the dataset and writes it into the result's -folder: - -::: code-group - -```javascript [src/app.js] -const fsPromises = require('fs').promises; - -(async () => { - try { - const iexecOut = process.env.IEXEC_OUT; - const iexecIn = process.env.IEXEC_IN; - const datasetFileName = process.env.IEXEC_DATASET_FILENAME; - - // Use some confidential assets - let text = ''; - try { - const confidentialFile = await fsPromises.readFile( - `${iexecIn}/${datasetFileName}` - ); - text = confidentialFile.toString(); - } catch (e) { - console.log('confidential file does not exist'); - } - // Append some results - await fsPromises.writeFile(`${iexecOut}/result.txt`, text); - console.log(text); - // Declare everything is computed - const computedJsonObj = { - 'deterministic-output-path': `${iexecOut}/result.txt`, - }; - await fsPromises.writeFile( - `${iexecOut}/computed.json`, - JSON.stringify(computedJsonObj) - ); - } catch (e) { - console.log(e); - process.exit(1); - } -})(); -``` - -```python [src/app.py] -import json -import os - -iexec_out = os.environ['IEXEC_OUT'] -iexec_in = os.environ['IEXEC_IN'] -dataset_filename = os.environ['IEXEC_DATASET_FILENAME'] - -text = '' - -# Check the confidential file exists and open it -try: - dataset_file = open(iexec_in + '/' + dataset_filename, 'r') - dataset = dataset_file.read() - text = dataset -except OSError: - print('confidential file does not exists') - exit(1) - -print(text) - -# Append some results in /iexec_out/ -with open(iexec_out + '/result.txt', 'w+') as fout: - fout.write(text) - -# Declare everything is computed -with open(iexec_out + '/computed.json', 'w+') as f: - json.dump({"deterministic-output-path": iexec_out + '/result.txt'}, f) -``` - -::: - -## Build the TEE docker image - -Create the `Dockerfile` as described in -[Build your first application](./your-first-app.md#dockerize-your-app). - -Build the Docker image: - -```bash -docker build . --tag /hello-world-with-dataset:1.0.0 -``` - -Follow the steps described in -[Build Scone app > Build the TEE docker image](create-your-first-sgx-app.md#build-the-tee-docker-image). - -Update the `sconify.sh` script with the variables as follow: - -```bash -# declare related variables -IMG_NAME=tee-scone-hello-world-with-dataset -IMG_FROM=/hello-world-with-dataset:1.0.0 -IMG_TO=/${IMG_NAME}:1.0.0-debug -``` - -Run the `sconify.sh` script to build the Scone TEE application: - -```bash -./sconify.sh -``` - -```bash -docker push /tee-scone-hello-world-with-dataset:1.0.0-debug -``` - -## Test your app on iExec - -At this stage, your application is ready to be tested on iExec. - -### Deploy the TEE app on iExec - -Deploy the application as described in -[Build Scone app](create-your-first-sgx-app.md#deploy-the-tee-app-on-iexec). - -### Run the TEE app - -Specify the tag `--tag tee,scone` and the dataset to use -`--dataset ` in `iexec app run` command to run a tee app with a -dataset. - -One last thing, in order to run a **TEE-debug** app you will also need to select -a debug workerpool, use the debug workerpool -`debug-v8-learn.main.pools.iexec.eth`. - -You are now ready to run the app - -```bash -iexec app run \ - --tag tee,scone \ - --dataset \ - --workerpool debug-v8-learn.main.pools.iexec.eth \ - --watch -``` - -## Next step? - -Thanks to the explained confidential computing workflow, you now know how to use -an encrypted dataset in a Confidential Computing application. - -To go further, check out how to: - -- [Protect the result](end-to-end-encryption.md) diff --git a/src/guides/build-iapp/advanced/your-first-app.md b/src/guides/build-iapp/advanced/your-first-app.md index e3dd5a8e..e85d6724 100644 --- a/src/guides/build-iapp/advanced/your-first-app.md +++ b/src/guides/build-iapp/advanced/your-first-app.md @@ -1,5 +1,5 @@ --- -description: >- +description: In this section we will show you how you can create a Docker dapp over the iExec infrastructure. --- @@ -322,20 +322,20 @@ docker pull /hello-world:1.0.0 | grep "Digest: sha256:" | sed ' Deploy your app on iExec -```bash -iexec app deploy +```bash twoslash +iexec app deploy --chain {{chainName}} ``` Verify the deployed app \(name, multiaddr, checksum, owner\) -```bash -iexec app show +```bash twoslash +iexec app show --chain {{chainName}} ``` ### Run your app on iExec -```bash -iexec app run --workerpool debug-v8-learn.main.pools.iexec.eth --watch +```bash twoslash +iexec app run --chain {{chainName}} --workerpool debug-v8-learn.main.pools.iexec.eth --watch ``` ::: info @@ -364,8 +364,8 @@ and let the app access them through variables: Once the run is completed copy the taskid from `iexec app run` output to download and check the result -```bash -iexec task show --download my-app-result \ +```bash twoslash +iexec task show --chain {{chainName}} --download my-app-result \ && unzip my-app-result.zip -d my-app-result ``` @@ -396,8 +396,8 @@ Sometimes things don't work out right the first time and you may need to ## Publish your app on the iExec marketplace -```bash -iexec app publish +```bash twoslash +iexec app publish --chain {{chainName}} ``` **Congratulations your application is now available on iExec!** @@ -413,3 +413,16 @@ iExec: - using docker to package your app with all its dependencies - testing an iExec app locally - publishing on dockerhub + + diff --git a/src/guides/build-iapp/manage-access.md b/src/guides/build-iapp/manage-access.md index 8ce8d679..2e6a7fbd 100644 --- a/src/guides/build-iapp/manage-access.md +++ b/src/guides/build-iapp/manage-access.md @@ -246,9 +246,9 @@ Here's the detailed description of each parameter: **Examples:** -- `"1"` - Single use -- `"100"` - Limited campaign -- `"10000"` - Virtually unlimited usage +- `1` - Single use +- `100` - Limited campaign +- `10000` - Virtually unlimited usage ### `tag` @@ -270,20 +270,19 @@ All restrictions use `0x0000000000000000000000000000000000000000` to indicate **Description:** Restrict usage to a specific dataset -**Typical usage:** `"0x0000000000000000000000000000000000000000"` (no -restriction) +**Typical usage:** `0x0000000000000000000000000000000000000000` (no restriction) #### `workerpoolrestrict` **Description:** Restrict execution to a specific workerpool -**Example:** `"prod-v8-bellecour.main.pools.iexec.eth"` for the main workerpool +**Example:** `{{ workerpoolAddress }}` for the main workerpool #### `requesterrestrict` **Description:** Restrict usage to a specific user -**Typical usage:** `"0x0000000000000000000000000000000000000000"` (open to all) +**Typical usage:** `0x0000000000000000000000000000000000000000` (open to all) ## What's Next? @@ -301,3 +300,16 @@ Next steps: Complete CLI reference - **[Official Orders Documentation](https://protocol.docs.iex.ec/for-developers/advanced/manage-your-apporders)** - Protocol-level order management + + diff --git a/src/references/dataProtector/advanced/apps-whitelist.md b/src/references/dataProtector/advanced/apps-whitelist.md index c71c0db2..e245e222 100644 --- a/src/references/dataProtector/advanced/apps-whitelist.md +++ b/src/references/dataProtector/advanced/apps-whitelist.md @@ -76,9 +76,6 @@ See it in See it in [https://explorer.iex.ec/bellecour](https://explorer.iex.ec/bellecour/app/0x1cb7d4f3ffa203f211e57357d759321c6ce49921) -See it in -[https://blockscout-bellecour.iex.ec/](https://blockscout-bellecour.iex.ec/address/0x1cb7D4F3FFa203F211e57357D759321C6CE49921) - diff --git a/src/references/dataProtector/dataProtectorCore/processProtectedData.md b/src/references/dataProtector/dataProtectorCore/processProtectedData.md index 60e3cd76..c982891e 100644 --- a/src/references/dataProtector/dataProtectorCore/processProtectedData.md +++ b/src/references/dataProtector/dataProtectorCore/processProtectedData.md @@ -266,20 +266,15 @@ const processProtectedDataResponse = await dataProtectorCore.processProtectedDat ### workerpool **Type:** `AddressOrENS | 'any'` -**Default:** `prod-v8-bellecour.main.pools.iexec.eth` +**Default:** `{{ workerpoolAddress }}` -The ETH address or Ethereum Name Service (ENS) address for the iExec workerpool. It's the confidential computer on which the iExec application will run. ::: tip -iExec currently offers a production workerpool located at the Ethereum Name -Service (ENS) address `prod-v8-bellecour.main.pools.iexec.eth`. This is the -default workerpool for running confidential computations on the iExec platform. - -If you don't specify a workerpool preference, -0x0000000000000000000000000000000000000000 represents any randomly available -workerpool. +iExec currently offers a production workerpool located at the address +`{{ workerpoolAddress }}`. This is the default workerpool for running +confidential computations on the iExec platform. ::: @@ -515,4 +510,5 @@ const selectedChain = computed(() => userStore.getCurrentChainId()); const chainData = computed(() => getChainById(selectedChain.value)); const explorerUrl = computed(() => chainData.value.iexecExplorerUrl); +const workerpoolAddress = computed(() => chainData.value.workerpoolAddress); diff --git a/src/references/dataProtector/dataProtectorCore/protectData.md b/src/references/dataProtector/dataProtectorCore/protectData.md index 528f47fc..005131e4 100644 --- a/src/references/dataProtector/dataProtectorCore/protectData.md +++ b/src/references/dataProtector/dataProtectorCore/protectData.md @@ -393,24 +393,25 @@ The multiaddr field is the IPFS path of your encrypted data. You can access your encrypted IPFS data with the link: -`https://ipfs-gateway.v8-bellecour.iex.ec/ipfs/abc123...` +`{{ipfsGateway}}/ipfs/abc123...` `abc123...` is the second part of the returned string `/p2p/abc123...` ::: -## Created Protected Data + diff --git a/src/references/dataProtector/dataProtectorSharing/consume/consumeProtectedData.md b/src/references/dataProtector/dataProtectorSharing/consume/consumeProtectedData.md index 4c0a0018..f0b77dde 100644 --- a/src/references/dataProtector/dataProtectorSharing/consume/consumeProtectedData.md +++ b/src/references/dataProtector/dataProtectorSharing/consume/consumeProtectedData.md @@ -156,9 +156,9 @@ const consumeProtectedDataResult = ### workerpool **Type:** `AddressOrENS` -**Default:** `prod-v8-bellecour.main.pools.iexec.eth` +**Default:** `{{ workerpoolAddress }}` (iExec's workerpool) -Address or ENS of the workerpool. +Address or ENS of the workerpool on which your confidential task will run. ```ts twoslash import { @@ -173,7 +173,7 @@ const consumeProtectedDataResult = await dataProtectorSharing.consumeProtectedData({ protectedData: '0x123abc...', app: '0x456def...', - workerpool: 'prod-v8-bellecour.main.pools.iexec.eth', // [!code focus] + workerpool: '0xa5de76...', // [!code focus] }); ``` @@ -331,8 +331,18 @@ Identifies the specific task associated with the deal. The actual content of the protected file. diff --git a/src/references/web3mail/methods/sendEmail.md b/src/references/web3mail/methods/sendEmail.md index 53e2800f..33b8a8a5 100644 --- a/src/references/web3mail/methods/sendEmail.md +++ b/src/references/web3mail/methods/sendEmail.md @@ -216,8 +216,7 @@ const sendEmail = await web3mail.sendEmail({ ### workerpoolAddressOrEns **Type:** `workerpoolAddressOrEns` -**Default:** `prod-v8-bellecour.main.pools.iexec.eth` (iExec's production -workerpool) +**Default:** `{{workerpoolAddress}}` (iExec's workerpool) Allows specifying the workerpool that will run the Web3Mail application. @@ -231,7 +230,7 @@ const sendEmail = await web3mail.sendEmail({ protectedData: '0x123abc...', emailSubject: 'My email subject', emailContent: 'My email content', - workerpoolAddressOrEns: 'prod-v8-bellecour.main.pools.iexec.eth', // [!code focus] + workerpoolAddressOrEns: '0xa5de76...', // [!code focus] }); ``` @@ -399,4 +398,5 @@ const selectedChain = computed(() => userStore.getCurrentChainId()); const chainData = computed(() => getChainById(selectedChain.value)); const explorerUrl = computed(() => chainData.value.iexecExplorerUrl); +const workerpoolAddress = computed(() => chainData.value.workerpoolAddress); diff --git a/src/references/web3telegram/methods/sendTelegram.md b/src/references/web3telegram/methods/sendTelegram.md index 8637dbfb..27b3fbfe 100644 --- a/src/references/web3telegram/methods/sendTelegram.md +++ b/src/references/web3telegram/methods/sendTelegram.md @@ -177,8 +177,7 @@ const sendTelegram = await web3telegram.sendTelegram({ **Type:** `workerpoolAddressOrEns | undefined` -**Default:** `prod-v8-bellecour.main.pools.iexec.eth` (iExec's production -workerpool) +**Default:** `{{workerpoolAddress}}` (iExec's workerpool) Allows specifying the workerpool that will run the Web3Telegram application. @@ -193,7 +192,7 @@ const sendTelegram = await web3telegram.sendTelegram({ protectedData: '0x123abc...', senderName: 'Arthur', telegramContent: 'My telegram message content', - workerpoolAddressOrEns: 'prod-v8-bellecour.main.pools.iexec.eth', // [!code focus] + workerpoolAddressOrEns: '0xa5de76...', // [!code focus] }); ``` @@ -298,4 +297,5 @@ const selectedChain = computed(() => userStore.getCurrentChainId()); const chainData = computed(() => getChainById(selectedChain.value)); const explorerUrl = computed(() => chainData.value.iexecExplorerUrl); +const workerpoolAddress = computed(() => chainData.value.workerpoolAddress); diff --git a/src/utils/chain.utils.ts b/src/utils/chain.utils.ts index 58f171fd..bad6c3b5 100644 --- a/src/utils/chain.utils.ts +++ b/src/utils/chain.utils.ts @@ -23,7 +23,10 @@ export interface Chain { url: string; }; }; + chainName: string; iexecExplorerUrl: string; + workerpoolAddress: string; + ipfsGateway: string; } export function getSupportedChains(): Chain[] { @@ -35,7 +38,10 @@ export function getSupportedChains(): Chain[] { nativeCurrency: arbitrum.nativeCurrency, rpcUrls: arbitrum.rpcUrls, blockExplorers: arbitrum.blockExplorers, + chainName: 'arbitrum-mainnet', iexecExplorerUrl: 'https://explorer.iex.ec/arbitrum-mainnet', + workerpoolAddress: '0x2C06263943180Cc024dAFfeEe15612DB6e5fD248', + ipfsGateway: 'https://ipfs-gateway.arbitrum-mainnet.iex.ec', }, { id: Number(bellecour.id), @@ -51,7 +57,10 @@ export function getSupportedChains(): Chain[] { 'https://blockscout-bellecour.iex.ec', }, }, + chainName: 'bellecour', iexecExplorerUrl: 'https://explorer.iex.ec/bellecour', + workerpoolAddress: 'prod-v8-bellecour.main.pools.iexec.eth', + ipfsGateway: 'https://ipfs-gateway.v8-bellecour.iex.ec', }, ]; } From 0b8bdedae6fc845eca5bae3ed3b96cc446d9d015 Mon Sep 17 00:00:00 2001 From: Le-Caignec Date: Thu, 21 Aug 2025 13:18:28 +0200 Subject: [PATCH 26/33] chore: enhance documentation with new titles and descriptions for clarity - Added titles and descriptions to several guides, including "iExec Oracle," "Access Confidential Assets from Your App," "Build Your First Application with Scone Framework," and "Build Intel TDX App (Experimental)." - Updated links in various TEE guides to reflect the new "Deploy & Run" terminology. - Improved clarity in the "Quick Start for Developers" guide by integrating specific chain names into command examples. --- src/get-started/protocol/oracle.md | 1 + src/get-started/protocol/tee/intel-sgx.md | 2 +- src/get-started/protocol/tee/intel-tdx.md | 2 +- src/get-started/protocol/tee/introduction.md | 2 +- src/get-started/protocol/tee/sgx-vs-tdx.md | 2 +- .../advanced/access-confidential-assets.md | 9 +++++- .../advanced/create-your-first-sgx-app.md | 7 +++++ .../advanced/create-your-first-tdx-app.md | 13 +++++++-- .../advanced/end-to-end-encryption.md | 13 +++++++-- .../advanced/quick-start-for-developers.md | 29 ++++++++++++------- 10 files changed, 58 insertions(+), 22 deletions(-) diff --git a/src/get-started/protocol/oracle.md b/src/get-started/protocol/oracle.md index e3a8a7d5..50f84f38 100644 --- a/src/get-started/protocol/oracle.md +++ b/src/get-started/protocol/oracle.md @@ -1,4 +1,5 @@ --- +title: iExec Oracle description: A flexible and secure Oracle Solution --- diff --git a/src/get-started/protocol/tee/intel-sgx.md b/src/get-started/protocol/tee/intel-sgx.md index 125ef5e7..fe537287 100644 --- a/src/get-started/protocol/tee/intel-sgx.md +++ b/src/get-started/protocol/tee/intel-sgx.md @@ -142,7 +142,7 @@ graph TD **Ready to build with SGX?** Check out the practical guides: -- **[Build & Deploy](/guides/build-iapp/build-&-deploy)** - Create your first +- **[Deploy & Run](/guides/build-iapp/deploy-&-run)** - Create your first SGX application - **[Advanced SGX Development](/guides/build-iapp/advanced/create-your-first-sgx-app)** - Deep dive into SGX development diff --git a/src/get-started/protocol/tee/intel-tdx.md b/src/get-started/protocol/tee/intel-tdx.md index d7e2fb4d..31a7e509 100644 --- a/src/get-started/protocol/tee/intel-tdx.md +++ b/src/get-started/protocol/tee/intel-tdx.md @@ -144,5 +144,5 @@ graph TD **For production applications, use SGX**: -- **[Build & Deploy](/guides/build-iapp/build-&-deploy)** - Create +- **[Deploy & Run](/guides/build-iapp/deploy-&-run)** - Create production-ready SGX applications diff --git a/src/get-started/protocol/tee/introduction.md b/src/get-started/protocol/tee/introduction.md index d3c35b00..1e5b0ddd 100644 --- a/src/get-started/protocol/tee/introduction.md +++ b/src/get-started/protocol/tee/introduction.md @@ -121,5 +121,5 @@ TEE technologies have evolved to address different use cases: - **[Build Intel TDX App (Experimental)](/guides/build-iapp/advanced/create-your-first-tdx-app)** - Build TDX applications with traditional deployment and iApp Generator -- **[Build & Deploy](/guides/build-iapp/build-&-deploy)** - Create your first +- **[Deploy & Run](/guides/build-iapp/deploy-&-run)** - Create your first TEE application diff --git a/src/get-started/protocol/tee/sgx-vs-tdx.md b/src/get-started/protocol/tee/sgx-vs-tdx.md index 43d28ab2..6697d4ba 100644 --- a/src/get-started/protocol/tee/sgx-vs-tdx.md +++ b/src/get-started/protocol/tee/sgx-vs-tdx.md @@ -81,5 +81,5 @@ technology** for advanced use cases. - **[Build Intel TDX App (Experimental)](/guides/build-iapp/advanced/create-your-first-tdx-app)** - Build TDX applications with traditional deployment and iApp Generator -- **[Build & Deploy](/guides/build-iapp/build-&-deploy)** - Create your first +- **[Deploy & Run](/guides/build-iapp/deploy-&-run)** - Create your first TEE application diff --git a/src/guides/build-iapp/advanced/access-confidential-assets.md b/src/guides/build-iapp/advanced/access-confidential-assets.md index a3462ebc..06fd29e7 100644 --- a/src/guides/build-iapp/advanced/access-confidential-assets.md +++ b/src/guides/build-iapp/advanced/access-confidential-assets.md @@ -1,3 +1,10 @@ +--- +title: Access Confidential Assets from Your App +description: + Learn how to access confidential assets including secrets, protected data, and + requester secrets from your iExec application using the Secret Management Service +--- + # Access confidential assets from your app ::: warning @@ -55,4 +62,4 @@ graph TD You now understand how these three kinds of confidential assets work on iExec, you can go one step further by learning how to manipulate them: -- [Access to a Protected Data](guides/build-iapp/inputs-and-outputs) +- [Access to a Protected Data](/guides/build-iapp/inputs-and-outputs) diff --git a/src/guides/build-iapp/advanced/create-your-first-sgx-app.md b/src/guides/build-iapp/advanced/create-your-first-sgx-app.md index 65e4da71..67891498 100644 --- a/src/guides/build-iapp/advanced/create-your-first-sgx-app.md +++ b/src/guides/build-iapp/advanced/create-your-first-sgx-app.md @@ -1,3 +1,10 @@ +--- +title: Build Your First Application with Scone Framework +description: + Learn how to build and run Confidential Computing applications with the Scone + TEE framework for secure, privacy-preserving computation +--- + # Build your first application with Scone framework In this tutorial, you will learn how to build and run a Confidential Computing diff --git a/src/guides/build-iapp/advanced/create-your-first-tdx-app.md b/src/guides/build-iapp/advanced/create-your-first-tdx-app.md index 7025944c..f23777ae 100644 --- a/src/guides/build-iapp/advanced/create-your-first-tdx-app.md +++ b/src/guides/build-iapp/advanced/create-your-first-tdx-app.md @@ -1,3 +1,10 @@ +--- +title: Build Intel TDX App (Experimental) +description: + Learn how to build and run Confidential Computing applications with Intel TDX + technology using both traditional deployment and the iApp Generator +--- + # 🛡️ Build Intel TDX App (Experimental) In this tutorial, you will learn how to build and run a Confidential Computing @@ -103,7 +110,7 @@ Your `iexec.json` should now look like this example: "checksum": "", // starts with 0x, update it with your own image digest "mrenclave": { "framework": "TDX", // TEE framework (keep default value) - } + } }, ... } @@ -296,7 +303,7 @@ EXPERIMENTAL_TDX_APP=true iapp run **[Intel SGX Technology](/get-started/protocol/tee/intel-sgx)** for production - **[Create Your First SGX App](/guides/build-iapp/advanced/create-your-first-sgx-app)** - Build production-ready SGX applications -- **[Build & Deploy](/guides/build-iapp/build-&-deploy)** - Standard iApp +- **[Deploy & Run](/guides/build-iapp/deploy-&-run)** - Standard iApp deployment guide ### 🔗 **Related Resources** @@ -307,7 +314,7 @@ EXPERIMENTAL_TDX_APP=true iapp run Generator documentation - **[DataProtector SDK](/references/dataProtector)** - Work with protected data in TDX -- **[Advanced iApp Building](/guides/build-iapp/advanced/overview)** - Advanced +- **[Advanced iApp Building](/guides/build-iapp/advanced/quick-start-for-developers)** - Advanced development techniques diff --git a/src/guides/build-iapp/advanced/create-your-first-tdx-app.md b/src/guides/build-iapp/advanced/create-your-first-tdx-app.md index f23777ae..a83d5011 100644 --- a/src/guides/build-iapp/advanced/create-your-first-tdx-app.md +++ b/src/guides/build-iapp/advanced/create-your-first-tdx-app.md @@ -303,8 +303,8 @@ EXPERIMENTAL_TDX_APP=true iapp run **[Intel SGX Technology](/get-started/protocol/tee/intel-sgx)** for production - **[Create Your First SGX App](/guides/build-iapp/advanced/create-your-first-sgx-app)** - Build production-ready SGX applications -- **[Deploy & Run](/guides/build-iapp/deploy-&-run)** - Standard iApp - deployment guide +- **[Deploy & Run](/guides/build-iapp/deploy-&-run)** - Standard iApp deployment + guide ### 🔗 **Related Resources** @@ -314,8 +314,8 @@ EXPERIMENTAL_TDX_APP=true iapp run Generator documentation - **[DataProtector SDK](/references/dataProtector)** - Work with protected data in TDX -- **[Advanced iApp Building](/guides/build-iapp/advanced/quick-start-for-developers)** - Advanced - development techniques +- **[Advanced iApp Building](/guides/build-iapp/advanced/quick-start-for-developers)** - + Advanced development techniques diff --git a/src/guides/build-iapp/advanced/quick-start-for-developers.md b/src/guides/build-iapp/advanced/quick-start-for-developers.md index 2a35274f..a30ce0e4 100644 --- a/src/guides/build-iapp/advanced/quick-start-for-developers.md +++ b/src/guides/build-iapp/advanced/quick-start-for-developers.md @@ -205,7 +205,7 @@ to pay for the computation. Everything is ready to run your application! ```bash twoslash -iexec app run --chain arbitrum-mainnet --args --workerpool prod-v8-learn.main.pools.iexec.eth --watch +iexec app run --chain arbitrum-mainnet --args --workerpool {{workerpoolAddress}} --watch ``` ::: info @@ -217,7 +217,7 @@ Useful options: - `--args ` specify the app execution arguments - `--watch` watch execution status changes - `--workerpool
` specify the workerpool to use (for example: - `--workerpool prod-v8-learn.main.pools.iexec.eth`) + `--workerpool {{workerpoolAddress}}`) Discover more option with `iexec app run --help` @@ -361,4 +361,5 @@ const selectedChain = computed(() => userStore.getCurrentChainId()); const chainData = computed(() => getChainById(selectedChain.value)); const chainName = computed(() => chainData.value.chainName); +const workerpoolAddress = computed(() => chainData.value.workerpoolAddress); diff --git a/src/guides/build-iapp/advanced/your-first-app.md b/src/guides/build-iapp/advanced/your-first-app.md index 19a76893..75cd09ef 100644 --- a/src/guides/build-iapp/advanced/your-first-app.md +++ b/src/guides/build-iapp/advanced/your-first-app.md @@ -336,7 +336,7 @@ iexec app show --chain {{chainName}} ### Run your app on iExec ```bash twoslash -iexec app run --chain {{chainName}} --workerpool debug-v8-learn.main.pools.iexec.eth --watch +iexec app run --chain {{chainName}} --workerpool {{workerpoolAddress}} --watch ``` ::: info @@ -426,4 +426,5 @@ const selectedChain = computed(() => userStore.getCurrentChainId()); const chainData = computed(() => getChainById(selectedChain.value)); const chainName = computed(() => chainData.value.chainName); +const workerpoolAddress = computed(() => chainData.value.workerpoolAddress); diff --git a/src/guides/manage-data/manage-access.md b/src/guides/manage-data/manage-access.md index 8c4a5d01..ca814c4e 100644 --- a/src/guides/manage-data/manage-access.md +++ b/src/guides/manage-data/manage-access.md @@ -135,12 +135,12 @@ you can specify a whitelist contract that contains multiple app versions. Very useful for when you need to upgrade your iApp, without losing all the granted access. -```ts +```text twoslash // Single app -authorizedApp: 'web3mail.apps.iexec.eth'; +authorizedApp: {{web3MailAddress}}; // Or use a whitelist (recommended for production) -authorizedApp: '0x781482C39CcE25546583EaC4957Fb7Bf04C277D2'; // Web3Mail whitelist +authorizedApp: {{web3MailAppWhitelist}}; // Web3Mail whitelist ``` #### authorizedUser @@ -209,6 +209,17 @@ steps: [data monetization strategies](/guides/manage-data/monetize-protected-data) diff --git a/src/references/dataProtector/dataProtectorCore/grantAccess.md b/src/references/dataProtector/dataProtectorCore/grantAccess.md index adf54e0d..3d0c4293 100644 --- a/src/references/dataProtector/dataProtectorCore/grantAccess.md +++ b/src/references/dataProtector/dataProtectorCore/grantAccess.md @@ -92,14 +92,13 @@ const grantedAccess = await dataProtectorCore.grantAccess({ You may authorize a specific app or a whitelist of apps to use the protected data. -iExec uses the ENS `web3mail.apps.iexec.eth` for the latest version of the -Web3Mail decentralized application. +The latest version of the iExec Web3Mail decentralized application is +`{{web3MailAddress}}`. iExec also maintains a whitelist for current and past versions of Web3Mail iApp. Granting access to this whitelist allows use of an email `protectedData` with all versions of the Web3Mail application, ensuring you only have to grant this -access once. The ETH address for this whitelist is -**0x781482C39CcE25546583EaC4957Fb7Bf04C277D2**. +access once. The ETH address for this whitelist is **{{web3MailAppWhitelist}}**. ::: @@ -252,6 +251,17 @@ The result of this method confirms the new access grant. It consists of a JSON [`GrantedAccess`](/references/dataProtector/types#grantedaccess) diff --git a/src/references/dataProtector/dataProtectorCore/processProtectedData.md b/src/references/dataProtector/dataProtectorCore/processProtectedData.md index c982891e..8f3c303c 100644 --- a/src/references/dataProtector/dataProtectorCore/processProtectedData.md +++ b/src/references/dataProtector/dataProtectorCore/processProtectedData.md @@ -278,7 +278,7 @@ confidential computations on the iExec platform. ::: -::: info +::: info TDX 🧪 While protected data are processed in **TEE** by **intel SGX** technology by default, `@iexec/dataprotector` can be configured to create and process diff --git a/src/utils/chain.utils.ts b/src/utils/chain.utils.ts index bad6c3b5..5c8f4caa 100644 --- a/src/utils/chain.utils.ts +++ b/src/utils/chain.utils.ts @@ -27,6 +27,10 @@ export interface Chain { iexecExplorerUrl: string; workerpoolAddress: string; ipfsGateway: string; + web3MailAddress: string; + web3MailAppWhitelist: string; + web3TelegramAddress: string; + web3TelegramAppWhitelist: string; } export function getSupportedChains(): Chain[] { @@ -42,6 +46,10 @@ export function getSupportedChains(): Chain[] { iexecExplorerUrl: 'https://explorer.iex.ec/arbitrum-mainnet', workerpoolAddress: '0x2C06263943180Cc024dAFfeEe15612DB6e5fD248', ipfsGateway: 'https://ipfs-gateway.arbitrum-mainnet.iex.ec', + web3MailAddress: '0x9E37767A18B7E7ac2bbeba0900e3B5b0613FA385', + web3MailAppWhitelist: '0xD5054a18565c4a9E5c1aa3cEB53258bd59d4c78C', + web3TelegramAddress: '0xD8614ad70A73A426A15F6474EB4aE633e0015805', + web3TelegramAppWhitelist: '0x53AFc09a647e7D5Fa9BDC784Eb3623385C45eF89', }, { id: Number(bellecour.id), @@ -61,6 +69,10 @@ export function getSupportedChains(): Chain[] { iexecExplorerUrl: 'https://explorer.iex.ec/bellecour', workerpoolAddress: 'prod-v8-bellecour.main.pools.iexec.eth', ipfsGateway: 'https://ipfs-gateway.v8-bellecour.iex.ec', + web3MailAddress: 'web3mail.apps.iexec.eth', + web3MailAppWhitelist: '0x781482C39CcE25546583EaC4957Fb7Bf04C277D2', + web3TelegramAddress: 'web3telegram.apps.iexec.eth', + web3TelegramAppWhitelist: '0x192C6f5AccE52c81Fcc2670f10611a3665AAA98F', }, ]; } From d671ba50ab01af1df8684d4d90f884b9354a76ed Mon Sep 17 00:00:00 2001 From: Le-Caignec Date: Thu, 21 Aug 2025 15:32:28 +0200 Subject: [PATCH 29/33] docs: update application references and improve clarity in documentation - Replaced hardcoded application addresses with dynamic placeholders in the Oracle and iApp guides for better maintainability. - Updated authorization app references to use dynamic variables in Web3Mail and Web3Telegram documentation. - Enhanced clarity in the sendEmail and sendTelegram methods by improving the description of authorization requirements. --- src/get-started/protocol/oracle.md | 2 +- src/guides/build-iapp/advanced/create-your-first-tdx-app.md | 2 +- src/references/web3mail/methods/sendEmail.md | 3 ++- src/references/web3telegram/methods/fetchUserContacts.md | 4 ++-- src/references/web3telegram/methods/sendTelegram.md | 3 ++- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/get-started/protocol/oracle.md b/src/get-started/protocol/oracle.md index 50f84f38..556e0494 100644 --- a/src/get-started/protocol/oracle.md +++ b/src/get-started/protocol/oracle.md @@ -131,7 +131,7 @@ dApp, and the parameters if applicable. The Oracle result writes in the ```bash $ cat ${IEXEC_OUT}/computed.json -{ 'callback-data': '0x48656c6c6f2c20776f726c6421'} +{ 'callback-data': '0x456def...'} ``` When the computation ends the worker will send both this `callback-data` diff --git a/src/guides/build-iapp/advanced/create-your-first-tdx-app.md b/src/guides/build-iapp/advanced/create-your-first-tdx-app.md index a83d5011..91742fba 100644 --- a/src/guides/build-iapp/advanced/create-your-first-tdx-app.md +++ b/src/guides/build-iapp/advanced/create-your-first-tdx-app.md @@ -218,7 +218,7 @@ declaration await dataProtector.core.processProtectedData({ protectedData: protectedData.address, workerpool: 'tdx-labs.pools.iexec.eth', - app: '0x1919ceb0c6e60f3B497936308B58F9a6aDf071eC', + app: '0x456def...', }); ``` diff --git a/src/references/web3mail/methods/sendEmail.md b/src/references/web3mail/methods/sendEmail.md index 33b8a8a5..fcb9b3ff 100644 --- a/src/references/web3mail/methods/sendEmail.md +++ b/src/references/web3mail/methods/sendEmail.md @@ -15,7 +15,7 @@ email must explicitly authorize you to send them email communications and permission must be granted for the `Web3Mail` tool to use the `protectedData` entity containing their email address. This is best done by granting authorization to the Web3Mail app whitelist -`0x781482C39CcE25546583EaC4957Fb7Bf04C277D2` as `authorizedApp`. Refer to the +`{{web3MailAppWhitelist}}` as `authorizedApp`. Refer to the [Data Protector `grantAccess`](/references/dataProtector/dataProtectorCore/grantAccess) documentation for more details. @@ -399,4 +399,5 @@ const selectedChain = computed(() => userStore.getCurrentChainId()); const chainData = computed(() => getChainById(selectedChain.value)); const explorerUrl = computed(() => chainData.value.iexecExplorerUrl); const workerpoolAddress = computed(() => chainData.value.workerpoolAddress); +const web3MailAppWhitelist = computed(() => chainData.value.web3MailAppWhitelist); diff --git a/src/references/web3telegram/methods/fetchUserContacts.md b/src/references/web3telegram/methods/fetchUserContacts.md index 582ef300..863939dd 100644 --- a/src/references/web3telegram/methods/fetchUserContacts.md +++ b/src/references/web3telegram/methods/fetchUserContacts.md @@ -21,7 +21,7 @@ const web3Provider = getWeb3Provider('PRIVATE_KEY'); const web3telegram = new IExecWeb3telegram(web3Provider); // ---cut--- const contactsList = await web3telegram.fetchUserContacts({ - userAddress: '0xF048eF3d7E3B33A465E0599E641BB29421f7Df92', + userAddress: '0x789cba...', }); ``` @@ -44,7 +44,7 @@ const web3Provider = getWeb3Provider('PRIVATE_KEY'); const web3telegram = new IExecWeb3telegram(web3Provider); // ---cut--- const contactsList = await web3telegram.fetchUserContacts({ - userAddress: '0xF048eF3d7E3B33A465E0599E641BB29421f7Df92', // [!code focus] + userAddress: '0x789cba...', // [!code focus] }); ``` diff --git a/src/references/web3telegram/methods/sendTelegram.md b/src/references/web3telegram/methods/sendTelegram.md index 27b3fbfe..f9e0da86 100644 --- a/src/references/web3telegram/methods/sendTelegram.md +++ b/src/references/web3telegram/methods/sendTelegram.md @@ -15,7 +15,7 @@ message must explicitly authorize you to send them telegram communications and permission must be granted for the `Web3Telegram` tool to use the `protectedData` entity containing their chat ID. This is best done by granting authorization to the Web3Telegram app whitelist -`0x192C6f5AccE52c81Fcc2670f10611a3665AAA98F` as `authorizedApp`. Refer to the +`{{web3TelegramAppWhitelist}}` as `authorizedApp`. Refer to the [Data Protector `grantAccess`](/references/dataProtector/dataProtectorCore/grantAccess) documentation for more details. @@ -298,4 +298,5 @@ const selectedChain = computed(() => userStore.getCurrentChainId()); const chainData = computed(() => getChainById(selectedChain.value)); const explorerUrl = computed(() => chainData.value.iexecExplorerUrl); const workerpoolAddress = computed(() => chainData.value.workerpoolAddress); +const web3TelegramAppWhitelist = computed(() => chainData.value.web3TelegramAppWhitelist); From 6e0f3f1c01702af1d256babf5d0d0f5c2fadd71d Mon Sep 17 00:00:00 2001 From: Le-Caignec Date: Thu, 21 Aug 2025 15:38:18 +0200 Subject: [PATCH 30/33] docs: update iApp and data protector documentation for clarity and consistency - Corrected the versioning format in the "Deploy & Run" guide for the sconified image. - Standardized workerpool references in the "Run iApp Without Protected Data" guide by removing unnecessary comments. - Simplified the description of the workerpool in the "Process Protected Data" guide for better understanding. - Removed redundant instruction regarding contacting iExec for production mode in the iApp generator documentation. --- src/guides/build-iapp/deploy-&-run.md | 2 +- src/guides/use-iapp/run-iapp-without-ProtectedData.md | 6 +++--- .../dataProtector/dataProtectorCore/processProtectedData.md | 2 +- src/references/iapp-generator/building-your-iexec-app.md | 1 - 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/guides/build-iapp/deploy-&-run.md b/src/guides/build-iapp/deploy-&-run.md index f1c1b008..0dfb1510 100644 --- a/src/guides/build-iapp/deploy-&-run.md +++ b/src/guides/build-iapp/deploy-&-run.md @@ -53,7 +53,7 @@ Here is an example: ```json [ { - "sconifiedImage": "robiniexec/iapp:0.0.1-tee-scone-5.9.1-v16-debug-5aea8b4aa71d", + "sconifiedImage": "robiniexec/iapp:0.0.1-tee-scone-5.9.1-v16-5aea8b4aa71d", "appContractAddress": "0x9665136c599ec361C8eE627eC4F35A23fBa94897", "owner": "0xbabE8270aC9857Af3aaC06877888F1939FbeC578", "date": "2025-08-12T13:16:18.252Z" diff --git a/src/guides/use-iapp/run-iapp-without-ProtectedData.md b/src/guides/use-iapp/run-iapp-without-ProtectedData.md index 0a05fd36..53ac2e2e 100644 --- a/src/guides/use-iapp/run-iapp-without-ProtectedData.md +++ b/src/guides/use-iapp/run-iapp-without-ProtectedData.md @@ -59,7 +59,7 @@ const requestorderToSign = await iexec.order.createRequestorder({ app: '0x456def...', category: 0, appmaxprice: 10, - workerpool: '0xa5de76...', // ENS address for iExec's debug workerpool + workerpool: '0xa5de76...', params: 'arg1 arg2 arg3', // Command-line arguments // Other parameters have default values }); @@ -110,7 +110,7 @@ const requestorderToSign = await iexec.order.createRequestorder({ app: '0x456def...', category: 0, // Required: category for the request appmaxprice: 10, - workerpool: '0xa5de76...', // ENS address for iExec's debug workerpool + workerpool: '0xa5de76...', params: { iexec_input_files: [ 'https://example.com/config.json', @@ -167,7 +167,7 @@ const requestorderToSign = await iexec.order.createRequestorder({ app: '0x456def...', category: 0, // Required: category for the request appmaxprice: 10, - workerpool: '0xa5de76...', // ENS address for iExec's debug workerpool + workerpool: '0xa5de76...', params: { iexec_secrets: { 1: 'api-key-12345', diff --git a/src/references/dataProtector/dataProtectorCore/processProtectedData.md b/src/references/dataProtector/dataProtectorCore/processProtectedData.md index 8f3c303c..3ca080c8 100644 --- a/src/references/dataProtector/dataProtectorCore/processProtectedData.md +++ b/src/references/dataProtector/dataProtectorCore/processProtectedData.md @@ -272,7 +272,7 @@ It's the confidential computer on which the iExec application will run. ::: tip -iExec currently offers a production workerpool located at the address +iExec currently offers a workerpool located at the address `{{ workerpoolAddress }}`. This is the default workerpool for running confidential computations on the iExec platform. diff --git a/src/references/iapp-generator/building-your-iexec-app.md b/src/references/iapp-generator/building-your-iexec-app.md index f8bdf98a..8df78617 100644 --- a/src/references/iapp-generator/building-your-iexec-app.md +++ b/src/references/iapp-generator/building-your-iexec-app.md @@ -181,7 +181,6 @@ Your iApp is now running on iExec! Once your application is **stable** and **functional**, you can: -- Contact **iExec** to move to **production mode** (Full Privacy). - Learn how to **manage orders** and integrate with the **iExec protocol**. #### 📚 Recommended Resources From 78436391cfcd20033ca23b5e43a048d7b88c357a Mon Sep 17 00:00:00 2001 From: Le-Caignec Date: Thu, 21 Aug 2025 15:39:22 +0200 Subject: [PATCH 31/33] docs: update comments for clarity in various guides - Changed comments from "Get current chain and compute explorer info" to "Get current chain info" in multiple documentation files for improved clarity and consistency. --- src/get-started/tooling-and-explorers/iexec-explorer.md | 2 +- src/guides/build-iapp/advanced/create-your-first-sgx-app.md | 2 +- src/guides/build-iapp/advanced/end-to-end-encryption.md | 2 +- src/guides/build-iapp/advanced/quick-start-for-developers.md | 2 +- src/guides/build-iapp/advanced/your-first-app.md | 2 +- src/guides/build-iapp/manage-access.md | 2 +- src/guides/manage-data/manage-access.md | 2 +- src/references/dataProtector/dataProtectorCore/grantAccess.md | 2 +- .../dataProtector/dataProtectorCore/processProtectedData.md | 2 +- .../dataProtectorSharing/consume/consumeProtectedData.md | 2 +- src/references/web3mail/methods/sendEmail.md | 2 +- src/references/web3telegram/methods/sendTelegram.md | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/get-started/tooling-and-explorers/iexec-explorer.md b/src/get-started/tooling-and-explorers/iexec-explorer.md index 67875188..c5fc84f2 100644 --- a/src/get-started/tooling-and-explorers/iexec-explorer.md +++ b/src/get-started/tooling-and-explorers/iexec-explorer.md @@ -209,7 +209,7 @@ import CardGrid from '@/components/CardGrid.vue'; import useUserStore from '@/stores/useUser.store'; import {getChainById} from '@/utils/chain.utils'; -// Get current chain and compute explorer info +- // Get current chain info const userStore = useUserStore(); const selectedChain = computed(() => userStore.getCurrentChainId()); diff --git a/src/guides/build-iapp/advanced/create-your-first-sgx-app.md b/src/guides/build-iapp/advanced/create-your-first-sgx-app.md index 1b2b5d42..1f528d9b 100644 --- a/src/guides/build-iapp/advanced/create-your-first-sgx-app.md +++ b/src/guides/build-iapp/advanced/create-your-first-sgx-app.md @@ -278,7 +278,7 @@ import { computed } from 'vue'; import useUserStore from '@/stores/useUser.store'; import {getChainById} from '@/utils/chain.utils'; -// Get current chain and compute explorer info +- // Get current chain info const userStore = useUserStore(); const selectedChain = computed(() => userStore.getCurrentChainId()); diff --git a/src/guides/build-iapp/advanced/end-to-end-encryption.md b/src/guides/build-iapp/advanced/end-to-end-encryption.md index ef2ebcae..17600137 100644 --- a/src/guides/build-iapp/advanced/end-to-end-encryption.md +++ b/src/guides/build-iapp/advanced/end-to-end-encryption.md @@ -148,7 +148,7 @@ import { computed } from 'vue'; import useUserStore from '@/stores/useUser.store'; import {getChainById} from '@/utils/chain.utils'; -// Get current chain and compute explorer info +- // Get current chain info const userStore = useUserStore(); const selectedChain = computed(() => userStore.getCurrentChainId()); diff --git a/src/guides/build-iapp/advanced/quick-start-for-developers.md b/src/guides/build-iapp/advanced/quick-start-for-developers.md index a30ce0e4..016f1b65 100644 --- a/src/guides/build-iapp/advanced/quick-start-for-developers.md +++ b/src/guides/build-iapp/advanced/quick-start-for-developers.md @@ -355,7 +355,7 @@ import { computed } from 'vue'; import useUserStore from '@/stores/useUser.store'; import {getChainById} from '@/utils/chain.utils'; -// Get current chain and compute explorer info +- // Get current chain info const userStore = useUserStore(); const selectedChain = computed(() => userStore.getCurrentChainId()); diff --git a/src/guides/build-iapp/advanced/your-first-app.md b/src/guides/build-iapp/advanced/your-first-app.md index 75cd09ef..81386d32 100644 --- a/src/guides/build-iapp/advanced/your-first-app.md +++ b/src/guides/build-iapp/advanced/your-first-app.md @@ -420,7 +420,7 @@ import { computed } from 'vue'; import useUserStore from '@/stores/useUser.store'; import {getChainById} from '@/utils/chain.utils'; -// Get current chain and compute explorer info +- // Get current chain info const userStore = useUserStore(); const selectedChain = computed(() => userStore.getCurrentChainId()); diff --git a/src/guides/build-iapp/manage-access.md b/src/guides/build-iapp/manage-access.md index 2e6a7fbd..e220515d 100644 --- a/src/guides/build-iapp/manage-access.md +++ b/src/guides/build-iapp/manage-access.md @@ -306,7 +306,7 @@ import { computed } from 'vue'; import useUserStore from '@/stores/useUser.store'; import {getChainById} from '@/utils/chain.utils'; -// Get current chain and compute explorer info +- // Get current chain info const userStore = useUserStore(); const selectedChain = computed(() => userStore.getCurrentChainId()); diff --git a/src/guides/manage-data/manage-access.md b/src/guides/manage-data/manage-access.md index ca814c4e..d83212ca 100644 --- a/src/guides/manage-data/manage-access.md +++ b/src/guides/manage-data/manage-access.md @@ -215,7 +215,7 @@ import {getChainById} from '@/utils/chain.utils'; import RequiredBadge from '@/components/RequiredBadge.vue' import OptionalBadge from '@/components/OptionalBadge.vue' -// Get current chain and compute explorer info +- // Get current chain info const userStore = useUserStore(); const selectedChain = computed(() => userStore.getCurrentChainId()); diff --git a/src/references/dataProtector/dataProtectorCore/grantAccess.md b/src/references/dataProtector/dataProtectorCore/grantAccess.md index 3d0c4293..1fc0e735 100644 --- a/src/references/dataProtector/dataProtectorCore/grantAccess.md +++ b/src/references/dataProtector/dataProtectorCore/grantAccess.md @@ -257,7 +257,7 @@ import {getChainById} from '@/utils/chain.utils'; import RequiredBadge from '@/components/RequiredBadge.vue' import OptionalBadge from '@/components/OptionalBadge.vue' -// Get current chain and compute explorer info +- // Get current chain info const userStore = useUserStore(); const selectedChain = computed(() => userStore.getCurrentChainId()); diff --git a/src/references/dataProtector/dataProtectorCore/processProtectedData.md b/src/references/dataProtector/dataProtectorCore/processProtectedData.md index 3ca080c8..6ddbb25d 100644 --- a/src/references/dataProtector/dataProtectorCore/processProtectedData.md +++ b/src/references/dataProtector/dataProtectorCore/processProtectedData.md @@ -504,7 +504,7 @@ import ChainNotSupportedBadge from '@/components/ChainNotSupportedBadge.vue' import useUserStore from '@/stores/useUser.store'; import {getChainById} from '@/utils/chain.utils'; -// Get current chain and compute explorer info +- // Get current chain info const userStore = useUserStore(); const selectedChain = computed(() => userStore.getCurrentChainId()); diff --git a/src/references/dataProtector/dataProtectorSharing/consume/consumeProtectedData.md b/src/references/dataProtector/dataProtectorSharing/consume/consumeProtectedData.md index f0b77dde..a548fae4 100644 --- a/src/references/dataProtector/dataProtectorSharing/consume/consumeProtectedData.md +++ b/src/references/dataProtector/dataProtectorSharing/consume/consumeProtectedData.md @@ -339,7 +339,7 @@ import RequiredBadge from '@/components/RequiredBadge.vue' import OptionalBadge from '@/components/OptionalBadge.vue' import ChainNotSupportedBadge from '@/components/ChainNotSupportedBadge.vue' -// Get current chain and compute explorer info +- // Get current chain info const userStore = useUserStore(); const selectedChain = computed(() => userStore.getCurrentChainId()); diff --git a/src/references/web3mail/methods/sendEmail.md b/src/references/web3mail/methods/sendEmail.md index fcb9b3ff..40ac7fab 100644 --- a/src/references/web3mail/methods/sendEmail.md +++ b/src/references/web3mail/methods/sendEmail.md @@ -392,7 +392,7 @@ import ChainNotSupportedBadge from '@/components/ChainNotSupportedBadge.vue' import useUserStore from '@/stores/useUser.store'; import {getChainById} from '@/utils/chain.utils'; -// Get current chain and compute explorer info +- // Get current chain info const userStore = useUserStore(); const selectedChain = computed(() => userStore.getCurrentChainId()); diff --git a/src/references/web3telegram/methods/sendTelegram.md b/src/references/web3telegram/methods/sendTelegram.md index f9e0da86..be481935 100644 --- a/src/references/web3telegram/methods/sendTelegram.md +++ b/src/references/web3telegram/methods/sendTelegram.md @@ -291,7 +291,7 @@ import ChainNotSupportedBadge from '@/components/ChainNotSupportedBadge.vue' import useUserStore from '@/stores/useUser.store'; import {getChainById} from '@/utils/chain.utils'; -// Get current chain and compute explorer info +- // Get current chain info const userStore = useUserStore(); const selectedChain = computed(() => userStore.getCurrentChainId()); From dd1a4df2cf796e5e94b38d2638e3aff76a7b90d9 Mon Sep 17 00:00:00 2001 From: Le-Caignec Date: Thu, 21 Aug 2025 15:41:10 +0200 Subject: [PATCH 32/33] fix: format --- src/references/web3mail/methods/sendEmail.md | 4 ++-- src/references/web3telegram/methods/sendTelegram.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/references/web3mail/methods/sendEmail.md b/src/references/web3mail/methods/sendEmail.md index 40ac7fab..c60744f4 100644 --- a/src/references/web3mail/methods/sendEmail.md +++ b/src/references/web3mail/methods/sendEmail.md @@ -14,8 +14,8 @@ The recipient email address in a `protectedData` entity. The user receiving the email must explicitly authorize you to send them email communications and permission must be granted for the `Web3Mail` tool to use the `protectedData` entity containing their email address. This is best done by granting -authorization to the Web3Mail app whitelist -`{{web3MailAppWhitelist}}` as `authorizedApp`. Refer to the +authorization to the Web3Mail app whitelist `{{web3MailAppWhitelist}}` as +`authorizedApp`. Refer to the [Data Protector `grantAccess`](/references/dataProtector/dataProtectorCore/grantAccess) documentation for more details. diff --git a/src/references/web3telegram/methods/sendTelegram.md b/src/references/web3telegram/methods/sendTelegram.md index be481935..5324bdfc 100644 --- a/src/references/web3telegram/methods/sendTelegram.md +++ b/src/references/web3telegram/methods/sendTelegram.md @@ -14,8 +14,8 @@ The recipient Chat ID is stored in a `protectedData` entity. The user receiving message must explicitly authorize you to send them telegram communications and permission must be granted for the `Web3Telegram` tool to use the `protectedData` entity containing their chat ID. This is best done by granting -authorization to the Web3Telegram app whitelist -`{{web3TelegramAppWhitelist}}` as `authorizedApp`. Refer to the +authorization to the Web3Telegram app whitelist `{{web3TelegramAppWhitelist}}` +as `authorizedApp`. Refer to the [Data Protector `grantAccess`](/references/dataProtector/dataProtectorCore/grantAccess) documentation for more details. From 122357f74a138647e906698fb3903b6a64e760b2 Mon Sep 17 00:00:00 2001 From: Le-Caignec Date: Thu, 21 Aug 2025 15:49:42 +0200 Subject: [PATCH 33/33] docs: fix typo --- src/get-started/tooling-and-explorers/iexec-explorer.md | 2 +- src/guides/build-iapp/advanced/create-your-first-sgx-app.md | 2 +- src/guides/build-iapp/advanced/end-to-end-encryption.md | 2 +- src/guides/build-iapp/advanced/quick-start-for-developers.md | 2 +- src/guides/build-iapp/advanced/your-first-app.md | 2 +- src/guides/build-iapp/manage-access.md | 2 +- src/guides/manage-data/manage-access.md | 2 +- src/references/dataProtector/dataProtectorCore/grantAccess.md | 2 +- .../dataProtector/dataProtectorCore/processProtectedData.md | 2 +- .../dataProtectorSharing/consume/consumeProtectedData.md | 2 +- src/references/web3mail/methods/sendEmail.md | 2 +- src/references/web3telegram/methods/sendTelegram.md | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/get-started/tooling-and-explorers/iexec-explorer.md b/src/get-started/tooling-and-explorers/iexec-explorer.md index c5fc84f2..63da6145 100644 --- a/src/get-started/tooling-and-explorers/iexec-explorer.md +++ b/src/get-started/tooling-and-explorers/iexec-explorer.md @@ -209,7 +209,7 @@ import CardGrid from '@/components/CardGrid.vue'; import useUserStore from '@/stores/useUser.store'; import {getChainById} from '@/utils/chain.utils'; -- // Get current chain info +// Get current chain info const userStore = useUserStore(); const selectedChain = computed(() => userStore.getCurrentChainId()); diff --git a/src/guides/build-iapp/advanced/create-your-first-sgx-app.md b/src/guides/build-iapp/advanced/create-your-first-sgx-app.md index 1f528d9b..9894b2f5 100644 --- a/src/guides/build-iapp/advanced/create-your-first-sgx-app.md +++ b/src/guides/build-iapp/advanced/create-your-first-sgx-app.md @@ -278,7 +278,7 @@ import { computed } from 'vue'; import useUserStore from '@/stores/useUser.store'; import {getChainById} from '@/utils/chain.utils'; -- // Get current chain info +// Get current chain info const userStore = useUserStore(); const selectedChain = computed(() => userStore.getCurrentChainId()); diff --git a/src/guides/build-iapp/advanced/end-to-end-encryption.md b/src/guides/build-iapp/advanced/end-to-end-encryption.md index 17600137..3c9b0d19 100644 --- a/src/guides/build-iapp/advanced/end-to-end-encryption.md +++ b/src/guides/build-iapp/advanced/end-to-end-encryption.md @@ -148,7 +148,7 @@ import { computed } from 'vue'; import useUserStore from '@/stores/useUser.store'; import {getChainById} from '@/utils/chain.utils'; -- // Get current chain info +// Get current chain info const userStore = useUserStore(); const selectedChain = computed(() => userStore.getCurrentChainId()); diff --git a/src/guides/build-iapp/advanced/quick-start-for-developers.md b/src/guides/build-iapp/advanced/quick-start-for-developers.md index 016f1b65..0d044dc1 100644 --- a/src/guides/build-iapp/advanced/quick-start-for-developers.md +++ b/src/guides/build-iapp/advanced/quick-start-for-developers.md @@ -355,7 +355,7 @@ import { computed } from 'vue'; import useUserStore from '@/stores/useUser.store'; import {getChainById} from '@/utils/chain.utils'; -- // Get current chain info +// Get current chain info const userStore = useUserStore(); const selectedChain = computed(() => userStore.getCurrentChainId()); diff --git a/src/guides/build-iapp/advanced/your-first-app.md b/src/guides/build-iapp/advanced/your-first-app.md index 81386d32..0fc9a29e 100644 --- a/src/guides/build-iapp/advanced/your-first-app.md +++ b/src/guides/build-iapp/advanced/your-first-app.md @@ -420,7 +420,7 @@ import { computed } from 'vue'; import useUserStore from '@/stores/useUser.store'; import {getChainById} from '@/utils/chain.utils'; -- // Get current chain info +// Get current chain info const userStore = useUserStore(); const selectedChain = computed(() => userStore.getCurrentChainId()); diff --git a/src/guides/build-iapp/manage-access.md b/src/guides/build-iapp/manage-access.md index e220515d..ecb64252 100644 --- a/src/guides/build-iapp/manage-access.md +++ b/src/guides/build-iapp/manage-access.md @@ -306,7 +306,7 @@ import { computed } from 'vue'; import useUserStore from '@/stores/useUser.store'; import {getChainById} from '@/utils/chain.utils'; -- // Get current chain info +// Get current chain info const userStore = useUserStore(); const selectedChain = computed(() => userStore.getCurrentChainId()); diff --git a/src/guides/manage-data/manage-access.md b/src/guides/manage-data/manage-access.md index d83212ca..920e9bd7 100644 --- a/src/guides/manage-data/manage-access.md +++ b/src/guides/manage-data/manage-access.md @@ -215,7 +215,7 @@ import {getChainById} from '@/utils/chain.utils'; import RequiredBadge from '@/components/RequiredBadge.vue' import OptionalBadge from '@/components/OptionalBadge.vue' -- // Get current chain info +// Get current chain info const userStore = useUserStore(); const selectedChain = computed(() => userStore.getCurrentChainId()); diff --git a/src/references/dataProtector/dataProtectorCore/grantAccess.md b/src/references/dataProtector/dataProtectorCore/grantAccess.md index 1fc0e735..c24d444d 100644 --- a/src/references/dataProtector/dataProtectorCore/grantAccess.md +++ b/src/references/dataProtector/dataProtectorCore/grantAccess.md @@ -257,7 +257,7 @@ import {getChainById} from '@/utils/chain.utils'; import RequiredBadge from '@/components/RequiredBadge.vue' import OptionalBadge from '@/components/OptionalBadge.vue' -- // Get current chain info +// Get current chain info const userStore = useUserStore(); const selectedChain = computed(() => userStore.getCurrentChainId()); diff --git a/src/references/dataProtector/dataProtectorCore/processProtectedData.md b/src/references/dataProtector/dataProtectorCore/processProtectedData.md index 6ddbb25d..e13c0368 100644 --- a/src/references/dataProtector/dataProtectorCore/processProtectedData.md +++ b/src/references/dataProtector/dataProtectorCore/processProtectedData.md @@ -504,7 +504,7 @@ import ChainNotSupportedBadge from '@/components/ChainNotSupportedBadge.vue' import useUserStore from '@/stores/useUser.store'; import {getChainById} from '@/utils/chain.utils'; -- // Get current chain info +// Get current chain info const userStore = useUserStore(); const selectedChain = computed(() => userStore.getCurrentChainId()); diff --git a/src/references/dataProtector/dataProtectorSharing/consume/consumeProtectedData.md b/src/references/dataProtector/dataProtectorSharing/consume/consumeProtectedData.md index a548fae4..1c37c2b8 100644 --- a/src/references/dataProtector/dataProtectorSharing/consume/consumeProtectedData.md +++ b/src/references/dataProtector/dataProtectorSharing/consume/consumeProtectedData.md @@ -339,7 +339,7 @@ import RequiredBadge from '@/components/RequiredBadge.vue' import OptionalBadge from '@/components/OptionalBadge.vue' import ChainNotSupportedBadge from '@/components/ChainNotSupportedBadge.vue' -- // Get current chain info +// Get current chain info const userStore = useUserStore(); const selectedChain = computed(() => userStore.getCurrentChainId()); diff --git a/src/references/web3mail/methods/sendEmail.md b/src/references/web3mail/methods/sendEmail.md index c60744f4..2aed89b7 100644 --- a/src/references/web3mail/methods/sendEmail.md +++ b/src/references/web3mail/methods/sendEmail.md @@ -392,7 +392,7 @@ import ChainNotSupportedBadge from '@/components/ChainNotSupportedBadge.vue' import useUserStore from '@/stores/useUser.store'; import {getChainById} from '@/utils/chain.utils'; -- // Get current chain info +// Get current chain info const userStore = useUserStore(); const selectedChain = computed(() => userStore.getCurrentChainId()); diff --git a/src/references/web3telegram/methods/sendTelegram.md b/src/references/web3telegram/methods/sendTelegram.md index 5324bdfc..bd0a835c 100644 --- a/src/references/web3telegram/methods/sendTelegram.md +++ b/src/references/web3telegram/methods/sendTelegram.md @@ -291,7 +291,7 @@ import ChainNotSupportedBadge from '@/components/ChainNotSupportedBadge.vue' import useUserStore from '@/stores/useUser.store'; import {getChainById} from '@/utils/chain.utils'; -- // Get current chain info +// Get current chain info const userStore = useUserStore(); const selectedChain = computed(() => userStore.getCurrentChainId());