Smart Contract Integration
Two ways smart contracts and APIs work together on Opsalis — use them independently or combine them.
Two Patterns
| Pattern | What it does | Use case |
|---|---|---|
| SC‑as‑Server | Register any smart contract as a REST API | Let HTTP clients call blockchain functions with a simple GET or POST |
| SC‑as‑Client | Smart contracts call APIs via an oracle | On-chain logic that needs off-chain data (insurance, derivatives, automation) |
SC-as-Server: Any Smart Contract as a REST API
Register any read-only or write function from any supported blockchain as a standard REST endpoint in the Opsalis catalog. Callers use plain HTTP — no Solidity, ABI encoding, or wallet required.
Supported Chains
Base, Ethereum, Arbitrum, Polygon, BNB Chain, Avalanche (mainnets and testnets).
How It Works
View/pure functions are free and instant (eth_call). Write functions use the node operator's wallet and return the transaction hash.
Example: Chainlink ETH/USD as REST API
The Chainlink ETH/USD Price Feed on Ethereum mainnet (0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419) exposes latestAnswer() and decimals().
Step 1 — Register via the web console:
- Backend type: Smart Contract
- Contract address:
0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419 - Chain: Ethereum
- ABI: paste the Chainlink aggregator ABI (just the functions you want to expose)
Step 2 — Call it:
curl https://your-node.example.com:3000/v1/chainlink-eth-usd/latestAnswer
Response:
{
"success": true,
"view": true,
"function": "latestAnswer",
"result": "186423000000",
"chain_id": 1
}
Chainlink uses 8 decimals: 186423000000 / 1e8 = $1,864.23.
Example: Uniswap V3 Swap Quotes
Register the Uniswap V3 QuoterV2 on Base (0x3d4e44Eb1374240CE5F1B136aa68B6A5f2f0Caa3). Expose quoteExactInputSingle() to let HTTP clients get real-time swap quotes.
Call it (how much USDC for 1 WETH?):
curl -X POST https://your-node.example.com:3000/v1/uniswap-quote/quoteExactInputSingle \
-H "Content-Type: application/json" \
-d '{
"tokenIn": "0x4200000000000000000000000000000000000006",
"tokenOut": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"amountIn": "1000000000000000000",
"fee": 500,
"sqrtPriceLimitX96": "0"
}'
Response:
{
"success": true,
"function": "quoteExactInputSingle",
"result": {
"amountOut": "1863410241",
"sqrtPriceX96After": "1412854891823641928374918",
"initializedTicksCrossed": "2",
"gasEstimate": "127400"
},
"chain_id": 8453
}
amountOut is raw USDC (6 decimals): 1863410241 / 1e6 = $1,863.41.
SC-as-Client: Smart Contracts That Call APIs
Any smart contract on Base can request data from any API in the Opsalis catalog. The result is delivered on-chain via a callback — the same request/fulfill pattern used by Chainlink VRF and other oracles.
How It Works
Real-World Use Cases
A smart contract auto-pays policyholders when the USGS reports an earthquake above magnitude 6.0 within 100 km of an insured location. No claims process, no adjusters — the contract reads the API and settles instantly.
Agricultural hedging contracts that settle based on actual temperature or rainfall data from a weather API. Farmers lock in a price; if drought hits, the contract pays out automatically.
Travelers buy coverage for a specific flight. If the flight status API reports a delay over 2 hours, the contract refunds the ticket automatically — before the traveler even lands.
Example: Parametric Earthquake Insurance
This contract monitors earthquake data from the USGS API (registered in the Opsalis catalog). When an earthquake above the configured magnitude threshold occurs near an insured location, the contract automatically pays out the policyholder.
Step 1 — The Solidity contract:
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
interface IOpsalisOracle {
function requestData(
bytes32 wrapperUid, bytes32 apiUid, bytes calldata params,
address callbackAddr, bytes4 callbackSel,
address apiOwnerWallet, uint256 fee
) external returns (bytes32);
}
interface IERC20 {
function approve(address, uint256) external returns (bool);
function transfer(address, uint256) external returns (bool);
}
contract EarthquakeInsurance {
IOpsalisOracle public immutable oracle;
IERC20 public immutable usdc;
struct Policy {
address holder;
uint256 payout; // USDC amount
int32 lat; // latitude x 1000 (e.g. 37770 = 37.77)
int32 lon; // longitude x 1000
uint16 radiusKm;
uint16 minMagnitude; // x 10 (e.g. 60 = M6.0)
bool active;
}
mapping(uint256 => Policy) public policies;
mapping(bytes32 => uint256) public requestToPolicy;
uint256 public nextPolicyId;
// ... (full contract below)
}
Step 2 — Deploy and fund:
# Deploy to Base Sepolia
forge create EarthquakeInsurance \
--rpc-url https://sepolia.base.org \
--private-key $KEY \
--constructor-args $ORACLE_ADDRESS $USDC_ADDRESS
# Fund with USDC for payouts + oracle fees
cast send $USDC "transfer(address,uint256)" $CONTRACT 10000000 \
--rpc-url https://sepolia.base.org --private-key $KEY
Step 3 — Create a policy:
# Insure San Francisco (lat 37.77, lon -122.42) for M5.0+, $50 payout
cast send $CONTRACT \
"createPolicy(address,uint256,int32,int32,uint16,uint16)" \
$POLICYHOLDER 50000000 37770 -122420 200 50 \
--rpc-url https://sepolia.base.org --private-key $KEY
Step 4 — Check for earthquakes (anyone can trigger):
# This calls the USGS API through the Opsalis oracle
cast send $CONTRACT \
"checkEarthquake(uint256,bytes32,bytes32,address)" \
0 $WRAPPER_UID $USGS_API_UID $API_OWNER \
--rpc-url https://sepolia.base.org --private-key $KEY
The oracle fetches live USGS data. If a qualifying earthquake is found, the contract pays the policyholder automatically.
Payment Flow
| Party | Role | Earns |
|---|---|---|
| API owner | Registered the USGS earthquake API | 95% of each oracle call fee |
| Opsalis | Protocol royalty (immutable, on-chain) | 5% of each oracle call fee |
| Node operator | Runs the node, fulfills the request | Reimbursed via the API owner's pricing |
Both transfers happen atomically in a single transaction. If either fails, the entire request reverts — no funds are ever held by any intermediary.
Full Circle: SC Calls SC Through Opsalis
The two patterns can combine. A Base smart contract uses the oracle to call a Chainlink price feed that is registered as an API in Opsalis.
The Chainlink protocol call is free (read-only eth_call). The Opsalis fee covers the node operator's infrastructure costs, paid in USDC on Base. This creates a cross-chain oracle bridge — read data from any chain, deliver it to Base.
API Reference
OpsalisOracleRouter Interface
Params Encoding
The params field is ABI-encoded as a single string containing a JSON object:
// View function, no arguments
bytes memory params = abi.encode(
'{"path":"/latestAnswer","method":"GET"}'
);
// Function with arguments
bytes memory params = abi.encode(
'{"path":"/balanceOf","method":"GET","account":"0xabc...123"}'
);
// REST API endpoint
bytes memory params = abi.encode(
'{"path":"/v1/earthquakes/recent","method":"GET","min_magnitude":"5","limit":"10"}'
);
Events
event DataRequested(
bytes32 indexed wrapperUid,
bytes32 indexed apiUid,
bytes32 requestId,
bytes params,
address callbackAddress,
bytes4 callbackSelector,
address requester
);
event DataFulfilled(
bytes32 indexed requestId,
bytes32 indexed wrapperUid
);