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.
Compiling contracts that use
ConnectOracle.sol
requires the
viaIR
feature. For Foundry/Forge, this can be done by using the --via-ir flag. The
relevant methods for other tools may vary.
Foundry
For this tutorial, you will be using the
Foundry toolkit to develop, compile,
and deploy your contracts. If you do not have Foundry installed, follow the
Foundry installation instructions.
Setup
Create a new project directory and initialize it with forge init:
mkdir connect-oracle
cd connect-oracle
forge init
Implementing the Contract
Before writing the contract, first rename the template contract to Oracle.sol.
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.
// 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.
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.curl https://rest-evm-1.anvil.asia-southeast.initia.xyz/minievm/evm/v1/connect_oracle
The output will look like this:{
"address": "0x031ECb63480983FD216D17BB6e1d393f3816b72F"
}
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
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:
// 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.
mv test/Counter.t.sol test/Oracle.t.sol
Also replace the file contents with placeholder content.
// 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.
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.
// 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.
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:
[⠊] 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.
cast call 0x505500221090Cd06400125B4f41A266B89Ffd62e "oracle_get_price()" --rpc-url $JSON_RPC_URL
Output should look like this:
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 |