> ## Documentation Index
> Fetch the complete documentation index at: https://docs.initia.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Using Connect Oracle

<Warning>
  Compiling contracts that use
  [ConnectOracle.sol](https://github.com/initia-labs/minievm/blob/main/x/evm/contracts/connect_oracle/ConnectOracle.sol)
  requires the
  [viaIR](https://soliditylang.org/blog/2024/07/12/a-closer-look-at-via-ir)
  feature. For Foundry/Forge, this can be done by using the `--via-ir` flag. The
  relevant methods for other tools may vary.
</Warning>

### Foundry

For this tutorial, you will be using the
[Foundry](https://github.com/foundry-rs/foundry) toolkit to develop, compile,
and deploy your contracts. If you do not have Foundry installed, follow the
[Foundry installation instructions](https://getfoundry.sh/).

## Setup

Create a new project directory and initialize it with `forge init`:

```sh theme={null}
mkdir connect-oracle
cd connect-oracle
forge init
```

## Implementing the Contract

Before writing the contract, first rename the template contract to `Oracle.sol`.

```sh theme={null}
mv src/Counter.sol src/Oracle.sol
```

Then update the contract from the template to be your oracle contract. Declare
the `IConnectOracle` interface, which will be used to interact with the
ConnectOracle contract.

```solidity src/Oracle.sol theme={null}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

interface IConnectOracle {
    struct Price {
        uint256 price;
        uint256 timestamp;
        uint64 height;
        uint64 nonce;
        uint64 decimal;
        uint64 id;
    }

    function get_price(string memory pair_id) external view returns (Price memory);
    function get_prices(string[] memory pair_ids) external view returns (Price[] memory);
}

contract Oracle {
    IConnectOracle public connect;
```

Next, define the constructor for the contract. This will be used to initialize
the contract with the ConnectOracle contract address.

<Note>
  The ConnectOracle contract is on MiniEVM precompiles. You can get its address by querying `${REST_URL}/minievm/evm/v1/connect_oracle` where `${REST_URL}` refers to the REST endpoint URL of the rollup.

  ```sh theme={null}
  curl https://rest-evm-1.anvil.asia-southeast.initia.xyz/minievm/evm/v1/connect_oracle
  ```

  The output will look like this:

  ```json theme={null}
  {
    "address": "0x031ECb63480983FD216D17BB6e1d393f3816b72F"
  }
  ```
</Note>

```solidity src/Oracle.sol theme={null}
    constructor(address oracleAddress) {
        connect = IConnectOracle(oracleAddress);
    }
```

Once the constructor is implemented, move on to defining the different functions
that the contract will have.

* `oracle_get_price`: This function will return the price of a single asset pair
* `oracle_get_prices`: This function will return the price of multiple asset
  pairs

```solidity src/Oracle.sol theme={null}
    function oracle_get_price() external view returns (uint256 price, uint256 timestamp) {
        IConnectOracle.Price memory p = connect.get_price("BTC/USD");
        return (p.price, p.timestamp);
    }

    function oracle_get_prices() external view returns (uint256[] memory prices) {
        string[] memory pair_ids = new string[](2);
        pair_ids[0] = "BTC/USD";
        pair_ids[1] = "ETH/USD";

        IConnectOracle.Price[] memory result = connect.get_prices(pair_ids);

        prices = new uint256[](result.length);
        for (uint256 i = 0; i < result.length; i++) {
            prices[i] = result[i].price;
        }
    }
```

The complete contract will then look like this:

```solidity src/Oracle.sol theme={null}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

interface IConnectOracle {
    struct Price {
        uint256 price;
        uint256 timestamp;
        uint64 height;
        uint64 nonce;
        uint64 decimal;
        uint64 id;
    }

    function get_price(string memory pair_id) external view returns (Price memory);
    function get_prices(string[] memory pair_ids) external view returns (Price[] memory);
}

contract Oracle {
    IConnectOracle public connect;

    constructor(address oracleAddress) {
        connect = IConnectOracle(oracleAddress);
    }

    function oracle_get_price() external view returns (uint256 price, uint256 timestamp) {
        IConnectOracle.Price memory p = connect.get_price("BTC/USD");
        return (p.price, p.timestamp);
    }

    function oracle_get_prices() external view returns (uint256[] memory prices) {
        string[] memory pair_ids = new string[](2);
        pair_ids[0] = "BTC/USD";
        pair_ids[1] = "ETH/USD";

        IConnectOracle.Price[] memory result = connect.get_prices(pair_ids);

        prices = new uint256[](result.length);
        for (uint256 i = 0; i < result.length; i++) {
            prices[i] = result[i].price;
        }

        return prices;
    }
}
```

Running `forge compile` will fail unless you provide a test file that matches
the `Oracle.sol` contract. Foundry expects a test file like `Oracle.t.sol` to
exist and import the contract under test. To resolve this, rename the existing
test file `Counter.t.sol` to `Oracle.t.sol`.

```sh theme={null}
mv test/Counter.t.sol test/Oracle.t.sol
```

Also replace the file contents with placeholder content.

```solidity test/Oracle.t.sol theme={null}
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;

import {Test, console} from "forge-std/Test.sol";

contract OracleTest is Test {

}
```

Now running `forge compile` should work without any errors.

```sh theme={null}
forge compile

# [Expected Output]:
# [⠢] Compiling...
# [⠰] Compiling 27 files with 0.8.21
# [⠃] Solc 0.8.21 finished in 6.25s
# Compiler run successful!
```

## Deploying the Contract

Now that the contract is compiled and ready, you can deploy it to the MiniEVM.
To accomplish this, use Foundry's `forge script` command. First, create a script
file to handle the deployment. Create a new file named `Oracle.s.sol` in the
`script` directory.

```solidity script/Oracle.s.sol theme={null}
    // SPDX-License-Identifier: UNLICENSED
    pragma solidity ^0.8.24;

    import {Script, console} from "forge-std/Script.sol";
    import {Oracle} from "../src/Oracle.sol";

    contract OracleScript is Script {
        Oracle public oracle;

        function setUp() public {}

        function run() public {
            address oracleAddress = 0x031ECb63480983FD216D17BB6e1d393f3816b72F;

            vm.startBroadcast();

            oracle = new Oracle(oracleAddress);

            vm.stopBroadcast();
        }
    }
```

Set your environment variables and run the deployment. Be sure to replace
`PRIVATE_KEY` with the deployer's private key, and `JSON_RPC_URL` with your
rollup's JSON-RPC endpoint.

```sh theme={null}
export PRIVATE_KEY=0x...
export JSON_RPC_URL=https://jsonrpc-evm-1.anvil.asia-southeast.initia.xyz

forge script script/Oracle.s.sol:OracleScript \
  --rpc-url $JSON_RPC_URL \
  --private-key $PRIVATE_KEY \
  --broadcast \
  --via-ir \
  --with-gas-price 0 \
  --skip-simulation
```

Output should look like this:

```sh theme={null}
[⠊] Compiling...
[⠊] Compiling 18 files with Solc 0.8.28
[⠒] Solc 0.8.28 finished in 918.49ms
Compiler run successful!
Script ran successfully.

SKIPPING ON-CHAIN SIMULATION.

##### 4303131403034904
✅  [Success] Hash: 0x8d9c488d7599fd867e45eee3b3a6ede24fec8f6459433051c341ef1937026bcf
Contract Address: 0x505500221090Cd06400125B4f41A266B89Ffd62e
Block: 10493369
Gas Used: 290728

✅ Sequence #1 on 4303131403034904 | Total Paid: 0. ETH (290728 gas * avg 0 gwei)
```

To query the `oracle_get_price()` function, use Foundry’s cast call command.

```sh theme={null}
cast call 0x505500221090Cd06400125B4f41A266B89Ffd62e "oracle_get_price()" --rpc-url $JSON_RPC_URL
```

Output should look like this:

```sh theme={null}
0x00000000000000000000000000000000000000000000000000000002c3cd0d430000000000000000000000000000000000000000000000001856610b4b695788
```

The output is an ABI-encoded hexadecimal result containing the price and
timestamp. The first 32 bytes represent the price, and the next 32 bytes
represent the timestamp.

| Field     | ABI-Encoded Value  | Decoded Value       |
| --------- | ------------------ | ------------------- |
| Price     | 0x2c3cd0d43        | 11874929987         |
| Timestamp | 0x1856610b4b695788 | 1753695806045116296 |
