# Create Your First dAPP using Foundry

[Foundry](https://book.getfoundry.sh/) is a smart contract development toolchain and manages your dependencies, compiles your project, runs tests, deploys, and lets you interact with the chain from the command-line and via Solidity scripts. Foundry also allow you to simulate development on the Sepolia network including Solidity native testing.&#x20;

> **Note:** that the FHE operations are only behavior simulations and may not accurately reflect actual system performance, gas consumption, etc.

### Getting Started

First, create a new project, and then initialize the Foundry project using the `forge init` command. The default template comes with one dependency installed: Forge Standard Library. This is the preferred testing library used for Foundry projects. Additionally, the template also comes with an empty starter contract and a simple test, you can easily remove them.

```sh
mkdir my-project
cd my-project
forge init 
code my-project
```

> If this is your first time using Foundry, refer to the [installation](https://book.getfoundry.sh/getting-started/installation) instructions for guidance.

The initialized project has the following structure:

```
├── lib/
├── script/
├── src/
└── test/
```

These are the default paths for a Foundry project.

* `lib/` is where to store dependency libraries or external contracts.
* `script/`  is where to store scripts for automating tasks, such as contract deployment scripts or contract interaction scripts.
* `src/` is where Solidity source code is placed, usually containing your contract files.
* `test/` is used to store test files.

Clone the **sight-oracle-contracts** repository.

```bash
git clone https://github.com/sight-ai/sight-oracle-contracts
```

Install OpenZeppelin library.

```sh
forge install OpenZeppelin/openzeppelin-contracts --no-commit
```

Forge can remap dependencies to make them easier to import. Create a **remappings.txt** file in the root directory, then copy the text below into **remappings.txt**.

```
forge-std/=lib/forge-std/src/
@sight-oracle/contracts=lib/sight-oracle-contracts/contracts
@openzeppelin/contracts=lib/openzeppelin-contracts/contracts
```

### Writing Contract

In the src directory, create a new file named `Example.sol`, and copy the example contract code below into `src/Example.sol`.

```solidity
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import "@sight-oracle/contracts/Oracle/Types.sol";
import "@sight-oracle/contracts/Oracle/Oracle.sol";
import "@sight-oracle/contracts/Oracle/RequestBuilder.sol";
import "@sight-oracle/contracts/Oracle/ResponseResolver.sol";

contract Example {
    // Use Sight Oracle's RequestBuilder and ResponseResolver to interact with Sight Oracle
    using RequestBuilder for Request;
    using ResponseResolver for CapsulatedValue;

    event OracleCallback(bytes32 indexed reqId);

    bytes32 latestReqId;
    Oracle public oracle;
    CapsulatedValue private _target;

    constructor(address oracle_) payable {
        oracle = Oracle(payable(oracle_));
    }

    function makeRequest() public payable {
        // Initialize new FHE computation request of a single step.
        Request memory r = RequestBuilder.newRequest(
            msg.sender,
            1,
            address(this),
            this.callback.selector, // specify the callback for Oracle
            ""
        );

        // Generate a random encrypted value and store in Sight Network
        r.rand();

        // Send the request via Sight FHE Oracle
        latestReqId = oracle.send(r);
    }

    // only Oracle can call this
    function callback(
        bytes32 reqId,
        CapsulatedValue[] memory values
    ) public onlyOracle {
        // Decode value from Oracle callback
        CapsulatedValue memory result = values[0];

        // Keep this encrypted target value
        _target = result;
        emit OracleCallback(reqId);
    }

    function getLatestReqId() public view returns (bytes32) {
        return latestReqId;
    }

    function getTarget() public view returns (CapsulatedValue memory) {
        return _target;
    }

    modifier onlyOracle() {
        require(msg.sender == address(oracle), "Only Oracle Can Do This");
        _;
    }
}
```

#### Explanation

1. **Contract Initialization**:
   * The `Example` contract imports the necessary modules from the Sight Oracle package.
   * The contract uses the `RequestBuilder` library to construct requests and the `ResponseResolver` library to interpret the responses.
2. **Constructor**:
   * The constructor initializes the contract with the address of the Sight Oracle. This address is used to send requests and handle callbacks.
3. **makeRequest Function**:
   * This function initiates a new request to the Sight Oracle.
   * A new request is created using `RequestBuilder.newRequest`, specifying the sender, the number of steps in the computation, the address to which the callback should be sent, and the callback function.
   * The `rand` function is called to generate a random encrypted value and store it in the Sight Network.
   * The `send` function sends the request to the Sight Oracle.
4. **callback Function**:
   * This function is called by the Sight Oracle once the computation is complete.
   * It decodes the returned value using the `ResponseResolver` and stores the encrypted target value in the `_target` variable.
5. **Modifiers**:
   * `onlyOracle`: Ensures that only the Sight Oracle can call the `callback` function.
6. **View Function**:
   * `getLatestReqId`:  Retrieves the request ID of the most recent request sent to the `Oracle`.
   * `getTarget`:  Retrieves the target value of the most recent request.

### Deploy Contracts

**Environment Setup**

We will to deploy the `Example` contract and the Sight Oracle contract to the Sepolia testnet. To do this, we need to configure Foundry by setting up the Sepolia RPC.

> **Note：**&#x49;f you don’t have Sepolia RPC yet, click [here](https://dashboard.alchemy.com/) to get Sepolia RPC.&#x20;

```properties
PRIVATE_KEY=<YOUR_PRIVATE_KEY>
SEPOLIA_RPC_URL=<SEPOLIA_RPC_URL>
SEPOLIA_ORACLE_CONTRACT_ADDRESS=0xC5ac65f17Ce781E9F325634b6218Dc75a5CF9abF
```

Add these environment variables to the `.env` file. `SEPOLIA_ORACLE_CONTRACT_ADDRESS` is the Oracle address deployed on the Sepolia test network.

**Write a deployment script.**

Next, create a folder and name it `script` and create a file in it called `DeployExample.s.sol`. This is where we will create the deployment script itself.

Copy the following code snippet into the `scripts/DeployExample.sol` file.

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {Script} from "forge-std/Script.sol";
import {Example} from "../src/Example.sol";

contract DeployExample is Script {
    function run() external {
        address oracleAddress = vm.envAddress(
            "SEPOLIA_ORACLE_CONTRACT_ADDRESS"
        );
        uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
        vm.startBroadcast(deployerPrivateKey);

        Example example = new Example(oracleAddress);
        vm.stopBroadcast();
    }
}
```

**Explanation**

* A `Script` contract in the Foundry framework is a foundational contract that provides various utilities and functionalities required when deploying smart contracts.
* `DeployExample` is a deployment script contract, which inherits from the `Script` contract in the Foundry framework.
* Use `vm.envAddress()` and `vm.envUint()` to read the Oracle contract address on the Sepolia test network and the private key used for deployment from environment variables, respectively.
* `vm.startBroadcast()` initiates the recording of all transactions that will be broadcasted to the blockchain, while `vm.stopBroadcast()` concludes the broadcasting of transactions.
* `new` is used to create a new instance of a smart contract. Using `new Example(oracleAddress)` to deploy a Example contract with the Oracle address  argument.

> **Note:** you must be careful when exposing private keys in a `.env` file and loading them into programs. This is only recommended for use with non-privileged deployers or for local / test setups. For production setups please review the various [wallet options](https://book.getfoundry.sh/reference/forge/forge-script.html#wallet-options---raw) that Foundry supports.

**Run** **deployment script**

```sh
# To load the variables in the .env file
source .env

# To deploy oracle contract and example contract
forge script script/DeployExample.s.sol:DeployExample --rpc-url $SEPOLIA_RPC_URL --broadcast -vvvv  
```

**Explanation**

* `script/DeployExample.s.sol:DeployExample` is the path to the script you want to run.&#x20;
* The `--rpc-url` option specifies the RPC endpoint, which can be a URL or an existing alias from the `[rpc_endpoints]` table.&#x20;
* The `--broadcast` parameter will broadcast the transactions to the network.&#x20;
* &#x20;The `-vvvv` flag will display debug information, including internal calls for each transaction, gas consumption, RPC request details, etc. This is especially useful for debugging and diagnostics.

This should take a little while, since Forge will also wait for the transaction receipts. You should see something like this after a minute or so:

<figure><img src="https://4239479252-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fc6n88IVs810uKFVbVyUQ%2Fuploads%2FJP4h9JVOIZcVB1L6gRAi%2F%E6%88%AA%E5%B1%8F2024-11-16%2023.44.00.png?alt=media&#x26;token=ae9fb192-7e2c-41eb-8f7e-c5db12d820a0" alt=""><figcaption></figcaption></figure>

Congratulations! you have successfully deployed the Sight Oracle and Example contracts to the Sepolia testnet.

### Send Request

Now, you have successfully deployed the Example contract. Next, you can call the `makeRequest` function from the Example contract just deployed to send a request. Foundry provides a powerful tool specifically for interacting with on-chain contracts—`cast`, and we will use this tool to execute the `makeRequest` call.

Run this code to send a request to the Example contract.

```
cast send <YOUR_CONTACT_ADDRESS> "makeRequest()" --rpc-url $SEPOLIA_RPC_URL --private-key $PRIVATE_KEY
```

* Replace `<YOUR_CONTACT_ADDRESS>` with the `Example` contract address you just deployed.&#x20;
* The `cast send` is used to sign and send a transaction; `makeRequest()` is the function being called. The `--private-key` option specifies the private key used for signing the transaction.

It may take some time for this transaction to be written to the Sepolia test chain. After about 10 seconds, you should see something like this:

<figure><img src="https://4239479252-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fc6n88IVs810uKFVbVyUQ%2Fuploads%2F7jsXz1dU3VYdvJ40qTmE%2F%E6%88%AA%E5%B1%8F2024-11-17%2000.02.31.png?alt=media&#x26;token=96380c54-320f-43ad-aa9b-17308429510c" alt=""><figcaption></figcaption></figure>

Congratulations, you have successfully sent a Sight Oracle request on the Sepolia test network. Next, you can copy the `transactionHash` from the log to view the details of the request on [Etherscan](https://sepolia.etherscan.io/), as shown in the image below:

<figure><img src="https://4239479252-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fc6n88IVs810uKFVbVyUQ%2Fuploads%2FD6fGgzHal1eYEZc51ZSG%2F%E6%88%AA%E5%B1%8F2024-11-17%2000.04.29.png?alt=media&#x26;token=f4166a24-1c55-4d3c-89d7-59d71d04c062" alt=""><figcaption></figcaption></figure>
