> For the complete documentation index, see [llms.txt](https://docs.ethernity.cloud/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ethernity.cloud/developer-guide/the-guide/step-by-step-dapp.md).

# Step-by-Step dApp

**Project Setup**

To initiate the creation of a new React app using `npx create-react-app`, follow these steps:

1. Ensure that you have Node.js and npm (Node Package Manager) installed on your system.
2. Open your terminal or command prompt.
3. Execute the following command:

```
npx create-react-app my-app
```

Replace "my-app" with your desired name for the React app. This command will establish a new directory named "my-app" and configure a basic React application structure within it.

4. After the process completes, navigate to the newly created directory:

```
cd my-app
```

5. Launch the development server:

```
npm start
```

This action will start the development server and automatically open your React app in a web browser. You can now commence building your React application by making changes to the files within the "src" directory.

Utilizing `npx create-react-app` presents a swift and straightforward method for initializing a new React project with all the essential configurations and dependencies, freeing you to concentrate on developing your app without concerning yourself with the initial setup.

**Ethernity Cloud Runner package installation**

To begin developing with the Ethernity Cloud Runner, you can easily set up your environment by installing the package using npm:

```
$ npm install @ethernity-cloud/runner --save
```

This command will install the Ethernity Cloud Runner package and save it as a dependency in your project. With the package installed, you're ready to start utilizing the Ethernity Cloud Runner functionality and explore its capabilities for your application development.

**Ethernity Cloud Runner usage and integration**

This comprehensive guide explains the seamless integration of the Ethernity Cloud Runner module into your React application, empowering developers to execute Python tasks. The following sections elaborate on the integration process:

1. **Import Statements:**

   Begin by editing /src/App.js and by importing the essential modules and styles. Import `./App.css` for styling, and the pivotal pieces from the `@ethernity-cloud/runner` package: the default `EthernityCloudRunner` class plus `ECRunner`, `ECStatus`, and `ECAddress` from the enums entry point.

   These are what you use to interact with the runner, pick the enclave image, react to task status, and select the network.

```javascript
import './App.css';
import EthernityCloudRunner from "@ethernity-cloud/runner";
import { ECRunner, ECStatus, ECAddress } from "@ethernity-cloud/runner/enums";
```

2. **Defining Code to be Executed:**

   The Ethernity Cloud Runner allows users to execute tasks using different programming languages and frameworks. Currently, the runner supports two main templates: Python and Node.js. Users can define the code to be executed within these templates to perform specific tasks on the Ethernity Cloud ecosystem.<br>

   **Python Template:**

   In the Python template, users can write their code in Python programming language.

   Below there is an example of Python code that returns

   ```javascript
   str = "Hello World!";

   ___etny_result___("Hello, World!");
   ```

   \
   **Node.js Template:**\
   For those who prefer JavaScript, the Node.js template offers a powerful option.

   Below there is an example of Node.js code that computes the sum of two numbers:

   ```javascript
   const string = "Hello World!";

   ___etny_result___(string);
   ```

   \
   To use either template, users need to provide the code in the corresponding programming language that defines the specific task they want to execute.\
   \
   As you can see, the`___etny_result___` function is specially used inside a Ethernity Cloud Runner tasks. When executing a task, this function allows the task code to send the result back to the Ethernity Cloud ecosystem.

   Because there is no output console of the code that is being process, this special function plays a crucial role in ensuring that the results of executed tasks are safely recorded and sent to the user performing the task request.\
   \
   For our example we are using the following nodejs code:

   ```javascript
   const code = `___etny_result___("Hello, World!")`;
   ```
3. **App Function Component:**

   Define the `App` function component, which plays a pivotal role in rendering the entire application.

```javascript
function App() {
}

export default App;
```

4. **Execute Task Function:**

Within the `App` function, define the `executeTask` function as an asynchronous function that triggers upon clicking the "Execute task" button.

```javascript
const executeTask = async () => {
};
```

5. **Runner Initialization:**

The first crucial step involves creating an instance of the `EthernityCloudRunner`. Initialize the runner by constructing:

```javascript
const runner = new EthernityCloudRunner();
```

Called with no arguments, the runner targets the **Bloxberg testnet** and uses the browser wallet (MetaMask via `window.ethereum`).

**Selecting a network.** The constructor takes the network's token contract address as its first argument (import the addresses from `@ethernity-cloud/runner/enums`). Ethernity Cloud supports the following networks:

| Network          | Type    | Chain ID | Address enum                         |
| ---------------- | ------- | -------- | ------------------------------------ |
| Bloxberg         | mainnet | 8995     | `ECAddress.BLOXBERG.MAINNET_ADDRESS` |
| Bloxberg         | testnet | 8995     | `ECAddress.BLOXBERG.TESTNET_ADDRESS` |
| Polygon          | mainnet | 137      | `ECAddress.POLYGON.MAINNET_ADDRESS`  |
| Polygon Amoy     | testnet | 80002    | `ECAddress.POLYGON.TESTNET_ADDRESS`  |
| IoTeX            | testnet | 4690     | `ECAddress.IOTEX.TESTNET_ADDRESS`    |
| Ethereum Sepolia | testnet | 11155111 | `ECAddress.SEPOLIA.TESTNET_ADDRESS`  |
| LitVM LiteForge  | testnet | 4441     | `ECAddress.LITVM.TESTNET_ADDRESS`    |

```javascript
import { ECAddress } from "@ethernity-cloud/runner/enums";

// e.g. run on Polygon Amoy
const runner = new EthernityCloudRunner(ECAddress.POLYGON.TESTNET_ADDRESS);
```

The IoTeX, Sepolia, and LitVM testnets share a single ECLD token address, so the runner reads the chain ID from your wallet/provider to tell them apart. When you connect a browser wallet or pass a `provider`, this is automatic. If you drive the runner with a raw private key instead, pass the network's chain ID as the third constructor argument (and an `rpcUrl` in the wallet options) so the correct chain is selected:

```javascript
const runner = new EthernityCloudRunner(
    ECAddress.IOTEX.TESTNET_ADDRESS,
    { privateKey: "0x…", rpcUrl: "https://babel-api.testnet.iotex.io" },
    4690 // IoTeX Testnet chain ID
);
```

Make sure the enclave image you pass to `runner.run(...)` (step 8) belongs to the same network — the `ECRunner` enum is keyed by network, e.g. `ECRunner.IOTEX.PYNITHY_RUNNER_TESTNET` for IoTeX or `ECRunner.BLOXBERG.PYNITHY_RUNNER_TESTNET` for Bloxberg.

6. **Decentralized Storage Initialization:**

Next, initialize the Ethernity Cloud Runner's decentralized storage by specifying the IPFS address where it will communicate with the IPFS network.

```javascript
// this is a server provided by Ethernity CLOUD, please bear in mind that you can use your own Decentralized Storage server
const ipfsAddress = 'https://ipfs.ethernity.cloud';
runner.initializeStorage(ipfsAddress);
```

For this integration, you have multiple options to initialize the storage:

* **Ethernity Cloud IPFS Server (Recommended for Development):**

Utilize the default IPFS address '[https://ipfs.ethernity.cloud](https://ipfs.ethernity.cloud/)' provided by Ethernity Cloud, which serves as an efficient option for development purposes. It ensures seamless initialization with the specified IPFS address, allowing you to focus on task execution without managing your own IPFS infrastructure.

* **Custom IPFS Server:**

Alternatively, if you have your own IPFS server set up or prefer to use a different IPFS address, you can provide the desired IPFS address to the runner.initializeStorage(ipfsAddress) method. This option empowers you to leverage any IPFS infrastructure that suits your specific requirements.

* **Other Decentralized Storage Solutions:**

Ethernity Cloud Runner offers the flexibility to integrate with various decentralized storage solutions beyond IPFS. While IPFS is the default and recommended option, you can explore other decentralized storage systems based on your needs and preferences.

7. **Events subscription:**

The runner is an `EventTarget`. As a task moves through its lifecycle it dispatches `CustomEvent`s **named by the task status**, so you subscribe using the `ECStatus` values:

* `ECStatus.DEFAULT` (`"Running"`) — progress updates while the task is encrypting, being submitted, matched, and processed.
* `ECStatus.SUCCESS` (`"Success"`) — the task finished and a result is available.
* `ECStatus.ERROR` (`"Error"`) — something failed.

Each event's `detail` carries `{ message, status, progress }`, where `progress` is a human-readable phase label (one of the `ECEvent` values, e.g. `"In Progress"`, `"Downloading result"`, `"Finished"`).

```javascript
const onProgress = (e) => {
    console.log(`[${e.detail.progress}] ${e.detail.message}`);
};

const onSuccess = async (e) => {
    // The result is available on the runner once the Success event fires.
    const result = await runner.getResult();
    console.log(`Task Result: ${result}`);
};

const onError = (e) => {
    console.error(e.detail.message);
};

runner.addEventListener(ECStatus.DEFAULT, onProgress); // "Running" progress updates
runner.addEventListener(ECStatus.SUCCESS, onSuccess);
runner.addEventListener(ECStatus.ERROR, onError);
```

By subscribing to these three status events, developers can follow the execution phase-by-phase (via `e.detail.progress`) and fetch the final result with `await runner.getResult()` once `ECStatus.SUCCESS` fires.

8. **Task Execution:**

```javascript
// Resource requirements for the task.
const resources = { taskPrice: 10, cpu: 1, memory: 1, storage: 40, bandwidth: 1, duration: 1, validators: 1 };

await runner.run(resources, ECRunner.BLOXBERG.PYNITHY_RUNNER_TESTNET, code);
```

The heart of the integration is the `await runner.run(...)` line, which initiates task execution. The function signature is `run(resources, secureLockEnclave, code, nodeAddress = '', trustedZoneEnclave)`:

* **Resources:** An object describing the resources the task needs — `taskPrice` (in the network's token), `cpu`, `memory` (GB), `storage` (GB), `bandwidth`, `duration`, and `validators`.
* **Enclave image (`secureLockEnclave`):** The enclave image to execute the task, taken from the network-keyed `ECRunner` enum. Two templates are available per network:
  * Python: `ECRunner.<NETWORK>.PYNITHY_RUNNER_TESTNET`
  * Node.js: `ECRunner.<NETWORK>.NODENITHY_RUNNER_TESTNET`

    where `<NETWORK>` matches the network you selected in step 5 (`BLOXBERG`, `POLYGON`, `IOTEX`, `SEPOLIA`, `LITVM`). Mainnet variants drop the `_TESTNET` suffix.
* **Code:** The code to execute as the task (preserve proper indentation for Python).
* **Node Address (Optional):** Provide an EC node's wallet address to auto-approve the order on that node; omit it (empty string) to have the order matched and manually approved by any available node.
  * **Manual Approval:** Omitting the node address lets the network match and approve the task.
  * **Automatic Approval:** Passing a node address targets that node for a seamless, quick execution.

9. **Rendering the Button**

```javascript
return (
    <div className="container">
        <button className="centeredButton" onClick={executeTask}>Execute Task</button>
    </div>
);
```

10. **Final application code**

```javascript
import './App.css';
import EthernityCloudRunner from "@ethernity-cloud/runner";
import { ECRunner, ECStatus, ECAddress } from "@ethernity-cloud/runner/enums";

const code = `___etny_result___("Hello, World!")`;

// example of a Node.js script
// const jsCode = `function add(a, b) { return a + b; }\n ___etny_result___(add(1, 10).toString());`;

function App() {
    const executeTask = async () => {
        // No network address -> Bloxberg testnet with the browser wallet.
        // To target another network, pass its address, e.g.
        //   new EthernityCloudRunner(ECAddress.POLYGON.TESTNET_ADDRESS);
        const runner = new EthernityCloudRunner();

        // Ethernity CLOUD Decentralized Storage server (you may use your own).
        const ipfsAddress = 'https://ipfs.ethernity.cloud';
        runner.initializeStorage(ipfsAddress);

        const onProgress = (e) => {
            console.log(`[${e.detail.progress}] ${e.detail.message}`);
        };
        const onSuccess = async () => {
            const result = await runner.getResult();
            console.log(`Task Result: ${result}`);
        };
        const onError = (e) => {
            console.error(e.detail.message);
        };

        runner.addEventListener(ECStatus.DEFAULT, onProgress); // "Running" updates
        runner.addEventListener(ECStatus.SUCCESS, onSuccess);
        runner.addEventListener(ECStatus.ERROR, onError);

        const resources = { taskPrice: 10, cpu: 1, memory: 1, storage: 40, bandwidth: 1, duration: 1, validators: 1 };

        // Pick the enclave image for your network and language:
        //   - Python : ECRunner.<NETWORK>.PYNITHY_RUNNER_TESTNET
        //   - Node.js: ECRunner.<NETWORK>.NODENITHY_RUNNER_TESTNET
        // We use the Bloxberg Python testnet enclave here.
        await runner.run(resources, ECRunner.BLOXBERG.PYNITHY_RUNNER_TESTNET, code);
        // For Node.js instead:
        // await runner.run(resources, ECRunner.BLOXBERG.NODENITHY_RUNNER_TESTNET, code);
    };

    return (
        <div className="container">
            <button className="centeredButton" onClick={executeTask}>Execute Task</button>
        </div>
    );
}

export default App;
```

11. **Application styling**

Now, navigate to the src/App.css file and proceed to enhance its content by adding the following CSS classes:

```css
.container {
    /* Set the container to flex to align the button horizontally and vertically */
    display: flex;
    justify-content: center; /* Center horizontally */
    align-items: center; /* Center vertically */
    height: 100vh; /* Adjust the container's height based on your requirement */
}

.centeredButton {
    /* Add your button styles here */
    padding: 10px 20px;
    background-color: #007bff;
    color: #fff;
    border: none;
    cursor: pointer;
    font-size: 16px;
    border-radius: 5px;
}
```

In conclusion, the above-mentioned code elegantly integrates the Ethernity Cloud Runner into your React app, enabling seamless execution of Python/Node.js code snippets while facilitating interaction with the IPFS network for efficient data storage and retrieval. As a professional developer, you can now leverage this integration to enhance your React applications with powerful decentralized task execution capabilities.
