# clp-feed-interface
Interface package for querying the **Coreum Lending Protocol (CLP) Feed** oracle contract. This package provides type-safe bindings for interacting with the CLP Feed price oracle, which aggregates validator-signed price data for various assets.
## Installation
Add this to your `Cargo.toml`:
```toml
[dependencies]
clp-feed-interface = "0.1.0"
cosmwasm-std = "2.2"
```
## Quick Start
### Using the Helper Querier (Recommended)
```rust
use cosmwasm_std::{Deps, Addr, StdResult};
use clp_feed_interface::ClpFeedQuerier;
// In your contract's execute or query function
pub fn get_price(deps: Deps, oracle_addr: Addr, denom: String) -> StdResult<String> {
let oracle = ClpFeedQuerier::new(&deps.querier, oracle_addr);
let response = oracle.query_price_by_denom(denom)?;
match response.price {
Some(price_data) => Ok(price_data.price),
None => Err(cosmwasm_std::StdError::generic_err("Price not found")),
}
}
```
### Direct Query
```rust
use cosmwasm_std::{Deps, Addr, StdResult};
use clp_feed_interface::{QueryMsg, AggregatedPriceResponse};
pub fn query_price(deps: Deps, oracle_addr: Addr, asset: String) -> StdResult<AggregatedPriceResponse> {
deps.querier.query_wasm_smart(
oracle_addr.to_string(),
&QueryMsg::GetPrice { asset },
)
}
```
## Available Queries
### Price Queries
#### `GetPrice`
Get the current aggregated price for an asset by name.
```rust
use clp_feed_interface::QueryMsg;
let query = QueryMsg::GetPrice {
asset: "ATOM".to_string()
};
```
#### `GetPriceByDenom`
Get the current aggregated price for a denom (e.g., "uatom").
```rust
let query = QueryMsg::GetPriceByDenom {
denom: "uatom".to_string()
};
```
#### `GetAllPrices`
Get all current aggregated prices.
```rust
let query = QueryMsg::GetAllPrices {};
```
### Validator Queries
#### `GetValidator`
Get information about a specific validator.
```rust
let query = QueryMsg::GetValidator {
validator_id: "validator1".to_string()
};
```
#### `GetAllValidators`
Get all registered validators.
```rust
let query = QueryMsg::GetAllValidators {};
```
### Configuration Queries
#### `GetConfig`
Get contract configuration (min signatures, max price age).
```rust
let query = QueryMsg::GetConfig {};
```
#### `GetAdmin`
Get the admin address.
```rust
let query = QueryMsg::GetAdmin {};
```
#### `GetOperators`
Get all operator addresses.
```rust
let query = QueryMsg::GetOperators {};
```
#### `GetDenomExists`
Check if a denom is configured.
```rust
let query = QueryMsg::GetDenomExists {
denom: "uatom".to_string()
};
```
#### `GetRecentSubmission`
Get a recent price submission from a specific validator.
```rust
let query = QueryMsg::GetRecentSubmission {
asset: "ATOM".to_string(),
validator_id: "validator1".to_string(),
};
```
## Type Definitions
### `AggregatedPrice`
The main price data structure returned by the oracle:
```rust
pub struct AggregatedPrice {
pub asset: String, // Asset symbol (e.g., "ATOM")
pub price: String, // Price as string
pub timestamp: Timestamp, // Last update timestamp
pub deviation: Option<String>, // Standard deviation (optional)
pub submissions: Vec<PriceSubmission>, // Individual validator submissions
pub feed_block_height: u64, // Oracle feed block height
pub chain_block_height: Option<u64>, // Chain block height (optional)
}
```
### `PriceSubmission`
Individual validator price submission:
```rust
pub struct PriceSubmission {
pub validator_id: String,
pub asset: String,
pub price: String,
pub timestamp: u64, // Unix timestamp in seconds
pub sources: Vec<String>, // Price data sources
pub signature: String, // Ed25519 signature (hex-encoded)
}
```
### `ValidatorInfo`
Validator information:
```rust
pub struct ValidatorInfo {
pub public_key: String, // Ed25519 public key (hex-encoded)
pub active: bool, // Whether validator is active
}
```
## Complete Example
```rust
use cosmwasm_std::{Deps, DepsMut, Env, MessageInfo, Response, StdResult, Uint128};
use clp_feed_interface::{ClpFeedQuerier, AggregatedPriceResponse};
pub fn execute_trade(
deps: DepsMut,
env: Env,
info: MessageInfo,
collateral_denom: String,
amount: Uint128,
) -> StdResult<Response> {
// Load your contract's config (which should store the oracle address)
let config = CONFIG.load(deps.storage)?;
// Query the oracle for collateral price
let oracle = ClpFeedQuerier::new(&deps.querier, config.oracle_address);
let price_response = oracle.query_price_by_denom(collateral_denom.clone())?;
// Extract price data
let price_data = price_response.price
.ok_or_else(|| cosmwasm_std::StdError::generic_err("Price not available"))?;
// Validate price freshness (optional)
let price_age = env.block.time.seconds() - price_data.timestamp.seconds();
if price_age > 300 {
return Err(cosmwasm_std::StdError::generic_err("Price data too old"));
}
// Use the price in your logic
let price_value = price_data.price.parse::<f64>()
.map_err(|_| cosmwasm_std::StdError::generic_err("Invalid price format"))?;
// Your trading logic here...
Ok(Response::new()
.add_attribute("action", "trade")
.add_attribute("price_used", price_data.price)
.add_attribute("price_timestamp", price_data.timestamp.seconds().to_string()))
}
```
## Response Types
All query responses are strongly typed:
- `AggregatedPriceResponse` - Contains `Option<AggregatedPrice>`
- `AllPricesResponse` - Contains `Vec<AggregatedPrice>`
- `ValidatorInfoResponse` - Contains validator ID and `Option<ValidatorInfo>`
- `AllValidatorsResponse` - Contains `Vec<(String, ValidatorInfo)>`
- `PriceSubmissionResponse` - Contains `Option<PriceSubmission>`
- `ConfigResponse` - Contains `min_signatures: u32` and `max_price_age: u64`
- `AdminResponse` - Contains `admin: Addr`
- `OperatorsResponse` - Contains `operators: Vec<Addr>`
- `DenomExistsResponse` - Contains `exists: bool` and `asset: Option<AssetInfo>`
## Deployed Contracts
### Mainnet
- **Contract Address**: `TBD` (Update after deployment)
### Testnet
- **Contract Address**: `TBD` (Update after deployment)
## Version Compatibility
| 0.1.0 | 0.1.0 | ✅ Compatible |
## Features
- ✅ **Type-safe** - Full Rust type definitions for all queries and responses
- ✅ **Lightweight** - Minimal dependencies (only CosmWasm standard libraries)
- ✅ **Helper functions** - Convenient `ClpFeedQuerier` wrapper
- ✅ **Well-documented** - Comprehensive inline documentation
- ✅ **Schema support** - Compatible with CosmWasm schema generation
## Error Handling
The oracle may return `None` for prices in certain cases:
- Asset/denom not configured
- No price data available yet
- Price data expired
Always check for `None` values:
```rust
let response = oracle.query_price_by_denom("uatom".to_string())?;
match response.price {
Some(price) => {
// Use price
},
None => {
// Handle missing price
return Err(cosmwasm_std::StdError::generic_err("Price not available"));
}
}
```
## License
MIT
## Links
- [Repository](https://github.com/your-org/coreum_lending_protocol)
- [Documentation](https://docs.rs/clp-feed-interface)
- [Coreum Lending Protocol](https://github.com/your-org/coreum_lending_protocol)