From d79183c0e4988dd02273c9f821ff2cfe8c3f23d7 Mon Sep 17 00:00:00 2001 From: Josh Hardy Date: Fri, 13 Feb 2026 17:03:33 +0000 Subject: [PATCH 1/4] feat: add SignedContextOracleV1 metadata type New metadata type for signed context oracle endpoint discovery. - Register KnownMagic::SignedContextOracleV1 (0xff7a1507ba4419ca) - Add KnownMeta::SignedContextOracleV1 variant - Add signed_context_oracle module with encode/decode/find helpers - Payload is a simple URL string (CBOR text) identifying a GET endpoint that returns SignedContextV1 data for Rain order evaluation - 7 new tests (magic roundtrip + oracle encode/decode/find) --- crates/cli/src/meta/magic.rs | 22 +++ crates/cli/src/meta/mod.rs | 5 +- crates/cli/src/meta/types/mod.rs | 1 + .../meta/types/signed_context_oracle/mod.rs | 135 ++++++++++++++++++ foundry.lock | 3 + 5 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 crates/cli/src/meta/types/signed_context_oracle/mod.rs diff --git a/crates/cli/src/meta/magic.rs b/crates/cli/src/meta/magic.rs index a547562e..019785a8 100644 --- a/crates/cli/src/meta/magic.rs +++ b/crates/cli/src/meta/magic.rs @@ -41,6 +41,10 @@ pub enum KnownMagic { DotrainSourceV1 = 0xffa15ef0fc437099, /// Dotrain instance meta v1 DotrainGuiStateV1 = 0xffda7b2fb167c286, + /// Signed context oracle endpoint v1 + /// Payload is a single CBOR text string containing the oracle URL. + /// Used in order metadata to tell takers where to GET signed context data. + SignedContextOracleV1 = 0xff7a1507ba4419ca, } impl KnownMagic { @@ -71,6 +75,9 @@ impl TryFrom for KnownMagic { v if v == KnownMagic::RainlangSourceV1 as u64 => Ok(KnownMagic::RainlangSourceV1), v if v == KnownMagic::DotrainSourceV1 as u64 => Ok(KnownMagic::DotrainSourceV1), v if v == KnownMagic::DotrainGuiStateV1 as u64 => Ok(KnownMagic::DotrainGuiStateV1), + v if v == KnownMagic::SignedContextOracleV1 as u64 => { + Ok(KnownMagic::SignedContextOracleV1) + } _ => Err(crate::error::Error::UnknownMagic), } } @@ -176,4 +183,19 @@ mod tests { assert_eq!(hex::encode(magic_number_after_prefix), "ffda7b2fb167c286"); } + + #[test] + fn test_signed_context_oracle_v1() { + let magic_number = KnownMagic::SignedContextOracleV1; + let magic_number_after_prefix = magic_number.to_prefix_bytes(); + + assert_eq!(hex::encode(magic_number_after_prefix), "ff7a1507ba4419ca"); + } + + #[test] + fn test_signed_context_oracle_v1_roundtrip() { + let magic_number = KnownMagic::SignedContextOracleV1; + let from_u64 = KnownMagic::try_from(magic_number as u64).unwrap(); + assert_eq!(magic_number, from_u64); + } } diff --git a/crates/cli/src/meta/mod.rs b/crates/cli/src/meta/mod.rs index 9c58ef1e..3363d0c0 100644 --- a/crates/cli/src/meta/mod.rs +++ b/crates/cli/src/meta/mod.rs @@ -38,6 +38,7 @@ pub enum KnownMeta { AddressList, DotrainSourceV1, DotrainGuiStateV1, + SignedContextOracleV1, } impl TryFrom for KnownMeta { @@ -58,6 +59,7 @@ impl TryFrom for KnownMeta { Ok(KnownMeta::ExpressionDeployerV2BytecodeV1) } KnownMagic::RainlangSourceV1 => Ok(KnownMeta::RainlangSourceV1), + KnownMagic::SignedContextOracleV1 => Ok(KnownMeta::SignedContextOracleV1), _ => Err(Error::UnsupportedMeta), } } @@ -288,7 +290,8 @@ impl RainMetaDocumentV1Item { | KnownMagic::ExpressionDeployerV2BytecodeV1 | KnownMagic::DotrainSourceV1 | KnownMagic::DotrainGuiStateV1 - | KnownMagic::RainlangSourceV1 => T::try_from(self), + | KnownMagic::RainlangSourceV1 + | KnownMagic::SignedContextOracleV1 => T::try_from(self), _ => Err(Error::UnsupportedMeta)?, } } diff --git a/crates/cli/src/meta/types/mod.rs b/crates/cli/src/meta/types/mod.rs index 8cd50f86..66d3470c 100644 --- a/crates/cli/src/meta/types/mod.rs +++ b/crates/cli/src/meta/types/mod.rs @@ -8,4 +8,5 @@ pub mod interpreter_caller; pub mod op; pub mod rainlang; pub mod rainlangsource; +pub mod signed_context_oracle; pub mod solidity_abi; diff --git a/crates/cli/src/meta/types/signed_context_oracle/mod.rs b/crates/cli/src/meta/types/signed_context_oracle/mod.rs new file mode 100644 index 00000000..82086dd4 --- /dev/null +++ b/crates/cli/src/meta/types/signed_context_oracle/mod.rs @@ -0,0 +1,135 @@ +use serde::{Deserialize, Serialize}; + +use crate::{ + error::Error, + meta::{ContentEncoding, ContentLanguage, ContentType, KnownMagic, RainMetaDocumentV1Item}, +}; + +#[cfg(target_family = "wasm")] +use wasm_bindgen_utils::{impl_wasm_traits, prelude::*}; + +/// Signed Context Oracle V1 meta. +/// +/// Contains a single URL string pointing to a GET endpoint that returns +/// signed context data for use in Rain order evaluation. +/// +/// The endpoint must return JSON: `{signer, context, signature}` mapping +/// directly to `SignedContextV1`. +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[cfg_attr(target_family = "wasm", derive(Tsify))] +pub struct SignedContextOracleV1(pub String); + +#[cfg(target_family = "wasm")] +impl_wasm_traits!(SignedContextOracleV1); + +impl SignedContextOracleV1 { + /// Create a new SignedContextOracleV1 from a URL string. + pub fn new(url: String) -> Self { + Self(url) + } + + /// Get the oracle URL. + pub fn url(&self) -> &str { + &self.0 + } + + /// Encode this oracle descriptor as a `RainMetaDocumentV1Item`. + pub fn to_meta_item(&self) -> RainMetaDocumentV1Item { + RainMetaDocumentV1Item { + payload: serde_bytes::ByteBuf::from(self.0.as_bytes().to_vec()), + magic: KnownMagic::SignedContextOracleV1, + content_type: ContentType::None, + content_encoding: ContentEncoding::None, + content_language: ContentLanguage::None, + } + } + + /// Encode as a complete Rain meta document (with magic prefix). + pub fn cbor_encode(&self) -> Result, Error> { + RainMetaDocumentV1Item::cbor_encode_seq( + &vec![self.to_meta_item()], + KnownMagic::RainMetaDocumentV1, + ) + } + + /// Try to extract a `SignedContextOracleV1` from decoded meta items. + /// Returns `None` if no oracle meta is found. + pub fn find_in_items(items: &[RainMetaDocumentV1Item]) -> Option { + items + .iter() + .find(|item| matches!(item.magic, KnownMagic::SignedContextOracleV1)) + .and_then(|item| Self::try_from(item.clone()).ok()) + } +} + +impl TryFrom for SignedContextOracleV1 { + type Error = Error; + fn try_from(value: RainMetaDocumentV1Item) -> Result { + if !matches!(value.magic, KnownMagic::SignedContextOracleV1) { + return Err(Error::UnsupportedMeta); + } + let bytes = value.unpack()?; + let url = String::from_utf8(bytes)?; + Ok(Self(url)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_roundtrip() { + let url = "https://oracle.example.com/prices/eth-usd"; + let oracle = SignedContextOracleV1::new(url.to_string()); + + // Encode to Rain meta document + let encoded = oracle.cbor_encode().unwrap(); + + // Should start with Rain meta document magic + assert!(encoded.starts_with(&KnownMagic::RainMetaDocumentV1.to_prefix_bytes())); + + // Decode back + let items = RainMetaDocumentV1Item::cbor_decode(&encoded).unwrap(); + assert_eq!(items.len(), 1); + assert_eq!(items[0].magic, KnownMagic::SignedContextOracleV1); + + // Extract oracle + let decoded = SignedContextOracleV1::try_from(items[0].clone()).unwrap(); + assert_eq!(decoded.url(), url); + } + + #[test] + fn test_find_in_items() { + let url = "https://oracle.example.com/prices/eth-usd"; + let oracle = SignedContextOracleV1::new(url.to_string()); + let item = oracle.to_meta_item(); + + let found = SignedContextOracleV1::find_in_items(&[item]).unwrap(); + assert_eq!(found.url(), url); + } + + #[test] + fn test_find_in_items_missing() { + let items: Vec = vec![]; + assert!(SignedContextOracleV1::find_in_items(&items).is_none()); + } + + #[test] + fn test_new_and_url() { + let oracle = SignedContextOracleV1::new("https://example.com/feed".to_string()); + assert_eq!(oracle.url(), "https://example.com/feed"); + } + + #[test] + fn test_wrong_magic_fails() { + let item = RainMetaDocumentV1Item { + payload: serde_bytes::ByteBuf::from(b"https://example.com".to_vec()), + magic: KnownMagic::DotrainSourceV1, + content_type: ContentType::None, + content_encoding: ContentEncoding::None, + content_language: ContentLanguage::None, + }; + assert!(SignedContextOracleV1::try_from(item).is_err()); + } +} diff --git a/foundry.lock b/foundry.lock index eb03d769..e5db8921 100644 --- a/foundry.lock +++ b/foundry.lock @@ -1,5 +1,8 @@ { "lib/forge-std": { "rev": "1801b0541f4fda118a10798fd3486bb7051c5dd6" + }, + "lib/rain.deploy": { + "rev": "e419a46e2a1317a63639ac13fc5a22d7e967fbef" } } \ No newline at end of file From 27860d15d39232df7497e89e4bea5fad3a36db6c Mon Sep 17 00:00:00 2001 From: Josh Hardy Date: Fri, 13 Feb 2026 17:44:03 +0000 Subject: [PATCH 2/4] fix: address review feedback on SignedContextOracleV1 - Validate URL on construction using url::Url (Gleb's suggestion) - new() takes Url, parse() takes &str and validates - Invalid/empty URLs are rejected with Error::InvalidUrl - find_in_items() now returns Result, Error> (Gleb's suggestion) - Returns Err if magic found but decode fails - Returns Ok(None) only if magic not found - Fix doc comment: payload is raw UTF-8 bytes, not CBOR text string - Added Error::InvalidUrl variant - 10 tests (up from 7): added tests for URL validation, empty URL, decode error propagation, parsed_url accessor --- crates/cli/src/error/mod.rs | 2 + crates/cli/src/meta/magic.rs | 2 +- .../meta/types/signed_context_oracle/mod.rs | 91 +++++++++++++++---- 3 files changed, 77 insertions(+), 18 deletions(-) diff --git a/crates/cli/src/error/mod.rs b/crates/cli/src/error/mod.rs index b8ecaa71..09852ccc 100644 --- a/crates/cli/src/error/mod.rs +++ b/crates/cli/src/error/mod.rs @@ -17,6 +17,7 @@ pub enum Error { UnsupportedNetwork, InflateError(String), InvalidInput(String), + InvalidUrl(String), Utf8Error(Utf8Error), FromUtf8Error(FromUtf8Error), ReqwestError(reqwest::Error), @@ -45,6 +46,7 @@ impl std::fmt::Display for Error { f.write_str("unexpected input size, must be 32 bytes or less") } Error::InvalidInput(v) => write!(f, "invalid input: {}", v), + Error::InvalidUrl(v) => write!(f, "invalid URL: {}", v), Error::ReqwestError(v) => write!(f, "{}", v), Error::InflateError(v) => write!(f, "{}", v), Error::Utf8Error(v) => write!(f, "{}", v), diff --git a/crates/cli/src/meta/magic.rs b/crates/cli/src/meta/magic.rs index 019785a8..597e3672 100644 --- a/crates/cli/src/meta/magic.rs +++ b/crates/cli/src/meta/magic.rs @@ -42,7 +42,7 @@ pub enum KnownMagic { /// Dotrain instance meta v1 DotrainGuiStateV1 = 0xffda7b2fb167c286, /// Signed context oracle endpoint v1 - /// Payload is a single CBOR text string containing the oracle URL. + /// Payload is raw UTF-8 bytes containing the oracle endpoint URL. /// Used in order metadata to tell takers where to GET signed context data. SignedContextOracleV1 = 0xff7a1507ba4419ca, } diff --git a/crates/cli/src/meta/types/signed_context_oracle/mod.rs b/crates/cli/src/meta/types/signed_context_oracle/mod.rs index 82086dd4..9e554053 100644 --- a/crates/cli/src/meta/types/signed_context_oracle/mod.rs +++ b/crates/cli/src/meta/types/signed_context_oracle/mod.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize}; +use url::Url; use crate::{ error::Error, @@ -10,7 +11,7 @@ use wasm_bindgen_utils::{impl_wasm_traits, prelude::*}; /// Signed Context Oracle V1 meta. /// -/// Contains a single URL string pointing to a GET endpoint that returns +/// Contains a validated URL pointing to a GET endpoint that returns /// signed context data for use in Rain order evaluation. /// /// The endpoint must return JSON: `{signer, context, signature}` mapping @@ -23,17 +24,31 @@ pub struct SignedContextOracleV1(pub String); impl_wasm_traits!(SignedContextOracleV1); impl SignedContextOracleV1 { - /// Create a new SignedContextOracleV1 from a URL string. - pub fn new(url: String) -> Self { - Self(url) + /// Create a new SignedContextOracleV1 from a URL. + /// Validates that the input is a well-formed URL. + pub fn new(url: Url) -> Self { + Self(url.to_string()) } - /// Get the oracle URL. + /// Parse and create a new SignedContextOracleV1 from a string. + /// Returns an error if the string is not a valid URL. + pub fn parse(url: &str) -> Result { + let parsed = Url::parse(url).map_err(|e| Error::InvalidUrl(e.to_string()))?; + Ok(Self::new(parsed)) + } + + /// Get the oracle URL as a string. pub fn url(&self) -> &str { &self.0 } + /// Get the oracle URL as a parsed Url. + pub fn parsed_url(&self) -> Result { + Url::parse(&self.0).map_err(|e| Error::InvalidUrl(e.to_string())) + } + /// Encode this oracle descriptor as a `RainMetaDocumentV1Item`. + /// The payload is raw UTF-8 bytes of the URL string. pub fn to_meta_item(&self) -> RainMetaDocumentV1Item { RainMetaDocumentV1Item { payload: serde_bytes::ByteBuf::from(self.0.as_bytes().to_vec()), @@ -53,12 +68,16 @@ impl SignedContextOracleV1 { } /// Try to extract a `SignedContextOracleV1` from decoded meta items. - /// Returns `None` if no oracle meta is found. - pub fn find_in_items(items: &[RainMetaDocumentV1Item]) -> Option { - items + /// Returns `Ok(None)` if no oracle meta is found. + /// Returns `Err` if oracle meta is found but cannot be decoded. + pub fn find_in_items(items: &[RainMetaDocumentV1Item]) -> Result, Error> { + match items .iter() .find(|item| matches!(item.magic, KnownMagic::SignedContextOracleV1)) - .and_then(|item| Self::try_from(item.clone()).ok()) + { + Some(item) => Ok(Some(Self::try_from(item.clone())?)), + None => Ok(None), + } } } @@ -69,8 +88,8 @@ impl TryFrom for SignedContextOracleV1 { return Err(Error::UnsupportedMeta); } let bytes = value.unpack()?; - let url = String::from_utf8(bytes)?; - Ok(Self(url)) + let url_str = String::from_utf8(bytes)?; + Self::parse(&url_str) } } @@ -81,7 +100,7 @@ mod tests { #[test] fn test_roundtrip() { let url = "https://oracle.example.com/prices/eth-usd"; - let oracle = SignedContextOracleV1::new(url.to_string()); + let oracle = SignedContextOracleV1::parse(url).unwrap(); // Encode to Rain meta document let encoded = oracle.cbor_encode().unwrap(); @@ -102,25 +121,55 @@ mod tests { #[test] fn test_find_in_items() { let url = "https://oracle.example.com/prices/eth-usd"; - let oracle = SignedContextOracleV1::new(url.to_string()); + let oracle = SignedContextOracleV1::parse(url).unwrap(); let item = oracle.to_meta_item(); - let found = SignedContextOracleV1::find_in_items(&[item]).unwrap(); + let found = SignedContextOracleV1::find_in_items(&[item]).unwrap().unwrap(); assert_eq!(found.url(), url); } #[test] fn test_find_in_items_missing() { let items: Vec = vec![]; - assert!(SignedContextOracleV1::find_in_items(&items).is_none()); + assert!(SignedContextOracleV1::find_in_items(&items).unwrap().is_none()); + } + + #[test] + fn test_find_in_items_decode_error() { + // Oracle magic but invalid payload (not valid UTF-8 URL) + let item = RainMetaDocumentV1Item { + payload: serde_bytes::ByteBuf::from(vec![0xFF, 0xFE]), + magic: KnownMagic::SignedContextOracleV1, + content_type: ContentType::None, + content_encoding: ContentEncoding::None, + content_language: ContentLanguage::None, + }; + assert!(SignedContextOracleV1::find_in_items(&[item]).is_err()); } #[test] - fn test_new_and_url() { - let oracle = SignedContextOracleV1::new("https://example.com/feed".to_string()); + fn test_new_with_url() { + let url = Url::parse("https://example.com/feed").unwrap(); + let oracle = SignedContextOracleV1::new(url); assert_eq!(oracle.url(), "https://example.com/feed"); } + #[test] + fn test_parse_valid_url() { + let oracle = SignedContextOracleV1::parse("https://example.com/feed").unwrap(); + assert_eq!(oracle.url(), "https://example.com/feed"); + } + + #[test] + fn test_parse_invalid_url() { + assert!(SignedContextOracleV1::parse("not a url").is_err()); + } + + #[test] + fn test_parse_empty_url() { + assert!(SignedContextOracleV1::parse("").is_err()); + } + #[test] fn test_wrong_magic_fails() { let item = RainMetaDocumentV1Item { @@ -132,4 +181,12 @@ mod tests { }; assert!(SignedContextOracleV1::try_from(item).is_err()); } + + #[test] + fn test_parsed_url() { + let oracle = SignedContextOracleV1::parse("https://example.com/feed?pair=eth-usd").unwrap(); + let parsed = oracle.parsed_url().unwrap(); + assert_eq!(parsed.host_str(), Some("example.com")); + assert_eq!(parsed.path(), "/feed"); + } } From 78f184f877c054133b0c1c654bc3598c5080f506 Mon Sep 17 00:00:00 2001 From: Josh Hardy Date: Tue, 17 Feb 2026 13:44:53 +0000 Subject: [PATCH 3/4] =?UTF-8?q?rename=20SignedContextOracleV1=20=E2=86=92?= =?UTF-8?q?=20RaindexSignedContextOracleV1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The metadata type is specific to the Raindex calculateOrderIO entrypoint, not a generic oracle standard. Rename to reflect this. --- crates/cli/src/meta/magic.rs | 10 ++-- crates/cli/src/meta/mod.rs | 6 +-- crates/cli/src/meta/types/mod.rs | 2 +- .../mod.rs | 48 +++++++++---------- 4 files changed, 33 insertions(+), 33 deletions(-) rename crates/cli/src/meta/types/{signed_context_oracle => raindex_signed_context_oracle}/mod.rs (73%) diff --git a/crates/cli/src/meta/magic.rs b/crates/cli/src/meta/magic.rs index 597e3672..a5a14179 100644 --- a/crates/cli/src/meta/magic.rs +++ b/crates/cli/src/meta/magic.rs @@ -44,7 +44,7 @@ pub enum KnownMagic { /// Signed context oracle endpoint v1 /// Payload is raw UTF-8 bytes containing the oracle endpoint URL. /// Used in order metadata to tell takers where to GET signed context data. - SignedContextOracleV1 = 0xff7a1507ba4419ca, + RaindexSignedContextOracleV1 = 0xff7a1507ba4419ca, } impl KnownMagic { @@ -75,8 +75,8 @@ impl TryFrom for KnownMagic { v if v == KnownMagic::RainlangSourceV1 as u64 => Ok(KnownMagic::RainlangSourceV1), v if v == KnownMagic::DotrainSourceV1 as u64 => Ok(KnownMagic::DotrainSourceV1), v if v == KnownMagic::DotrainGuiStateV1 as u64 => Ok(KnownMagic::DotrainGuiStateV1), - v if v == KnownMagic::SignedContextOracleV1 as u64 => { - Ok(KnownMagic::SignedContextOracleV1) + v if v == KnownMagic::RaindexSignedContextOracleV1 as u64 => { + Ok(KnownMagic::RaindexSignedContextOracleV1) } _ => Err(crate::error::Error::UnknownMagic), } @@ -186,7 +186,7 @@ mod tests { #[test] fn test_signed_context_oracle_v1() { - let magic_number = KnownMagic::SignedContextOracleV1; + let magic_number = KnownMagic::RaindexSignedContextOracleV1; let magic_number_after_prefix = magic_number.to_prefix_bytes(); assert_eq!(hex::encode(magic_number_after_prefix), "ff7a1507ba4419ca"); @@ -194,7 +194,7 @@ mod tests { #[test] fn test_signed_context_oracle_v1_roundtrip() { - let magic_number = KnownMagic::SignedContextOracleV1; + let magic_number = KnownMagic::RaindexSignedContextOracleV1; let from_u64 = KnownMagic::try_from(magic_number as u64).unwrap(); assert_eq!(magic_number, from_u64); } diff --git a/crates/cli/src/meta/mod.rs b/crates/cli/src/meta/mod.rs index 3363d0c0..7b07d88f 100644 --- a/crates/cli/src/meta/mod.rs +++ b/crates/cli/src/meta/mod.rs @@ -38,7 +38,7 @@ pub enum KnownMeta { AddressList, DotrainSourceV1, DotrainGuiStateV1, - SignedContextOracleV1, + RaindexSignedContextOracleV1, } impl TryFrom for KnownMeta { @@ -59,7 +59,7 @@ impl TryFrom for KnownMeta { Ok(KnownMeta::ExpressionDeployerV2BytecodeV1) } KnownMagic::RainlangSourceV1 => Ok(KnownMeta::RainlangSourceV1), - KnownMagic::SignedContextOracleV1 => Ok(KnownMeta::SignedContextOracleV1), + KnownMagic::RaindexSignedContextOracleV1 => Ok(KnownMeta::RaindexSignedContextOracleV1), _ => Err(Error::UnsupportedMeta), } } @@ -291,7 +291,7 @@ impl RainMetaDocumentV1Item { | KnownMagic::DotrainSourceV1 | KnownMagic::DotrainGuiStateV1 | KnownMagic::RainlangSourceV1 - | KnownMagic::SignedContextOracleV1 => T::try_from(self), + | KnownMagic::RaindexSignedContextOracleV1 => T::try_from(self), _ => Err(Error::UnsupportedMeta)?, } } diff --git a/crates/cli/src/meta/types/mod.rs b/crates/cli/src/meta/types/mod.rs index 66d3470c..640a970b 100644 --- a/crates/cli/src/meta/types/mod.rs +++ b/crates/cli/src/meta/types/mod.rs @@ -8,5 +8,5 @@ pub mod interpreter_caller; pub mod op; pub mod rainlang; pub mod rainlangsource; -pub mod signed_context_oracle; +pub mod raindex_signed_context_oracle; pub mod solidity_abi; diff --git a/crates/cli/src/meta/types/signed_context_oracle/mod.rs b/crates/cli/src/meta/types/raindex_signed_context_oracle/mod.rs similarity index 73% rename from crates/cli/src/meta/types/signed_context_oracle/mod.rs rename to crates/cli/src/meta/types/raindex_signed_context_oracle/mod.rs index 9e554053..bc317055 100644 --- a/crates/cli/src/meta/types/signed_context_oracle/mod.rs +++ b/crates/cli/src/meta/types/raindex_signed_context_oracle/mod.rs @@ -18,19 +18,19 @@ use wasm_bindgen_utils::{impl_wasm_traits, prelude::*}; /// directly to `SignedContextV1`. #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] #[cfg_attr(target_family = "wasm", derive(Tsify))] -pub struct SignedContextOracleV1(pub String); +pub struct RaindexSignedContextOracleV1(pub String); #[cfg(target_family = "wasm")] -impl_wasm_traits!(SignedContextOracleV1); +impl_wasm_traits!(RaindexSignedContextOracleV1); -impl SignedContextOracleV1 { - /// Create a new SignedContextOracleV1 from a URL. +impl RaindexSignedContextOracleV1 { + /// Create a new RaindexSignedContextOracleV1 from a URL. /// Validates that the input is a well-formed URL. pub fn new(url: Url) -> Self { Self(url.to_string()) } - /// Parse and create a new SignedContextOracleV1 from a string. + /// Parse and create a new RaindexSignedContextOracleV1 from a string. /// Returns an error if the string is not a valid URL. pub fn parse(url: &str) -> Result { let parsed = Url::parse(url).map_err(|e| Error::InvalidUrl(e.to_string()))?; @@ -52,7 +52,7 @@ impl SignedContextOracleV1 { pub fn to_meta_item(&self) -> RainMetaDocumentV1Item { RainMetaDocumentV1Item { payload: serde_bytes::ByteBuf::from(self.0.as_bytes().to_vec()), - magic: KnownMagic::SignedContextOracleV1, + magic: KnownMagic::RaindexSignedContextOracleV1, content_type: ContentType::None, content_encoding: ContentEncoding::None, content_language: ContentLanguage::None, @@ -67,13 +67,13 @@ impl SignedContextOracleV1 { ) } - /// Try to extract a `SignedContextOracleV1` from decoded meta items. + /// Try to extract a `RaindexSignedContextOracleV1` from decoded meta items. /// Returns `Ok(None)` if no oracle meta is found. /// Returns `Err` if oracle meta is found but cannot be decoded. pub fn find_in_items(items: &[RainMetaDocumentV1Item]) -> Result, Error> { match items .iter() - .find(|item| matches!(item.magic, KnownMagic::SignedContextOracleV1)) + .find(|item| matches!(item.magic, KnownMagic::RaindexSignedContextOracleV1)) { Some(item) => Ok(Some(Self::try_from(item.clone())?)), None => Ok(None), @@ -81,10 +81,10 @@ impl SignedContextOracleV1 { } } -impl TryFrom for SignedContextOracleV1 { +impl TryFrom for RaindexSignedContextOracleV1 { type Error = Error; fn try_from(value: RainMetaDocumentV1Item) -> Result { - if !matches!(value.magic, KnownMagic::SignedContextOracleV1) { + if !matches!(value.magic, KnownMagic::RaindexSignedContextOracleV1) { return Err(Error::UnsupportedMeta); } let bytes = value.unpack()?; @@ -100,7 +100,7 @@ mod tests { #[test] fn test_roundtrip() { let url = "https://oracle.example.com/prices/eth-usd"; - let oracle = SignedContextOracleV1::parse(url).unwrap(); + let oracle = RaindexSignedContextOracleV1::parse(url).unwrap(); // Encode to Rain meta document let encoded = oracle.cbor_encode().unwrap(); @@ -111,27 +111,27 @@ mod tests { // Decode back let items = RainMetaDocumentV1Item::cbor_decode(&encoded).unwrap(); assert_eq!(items.len(), 1); - assert_eq!(items[0].magic, KnownMagic::SignedContextOracleV1); + assert_eq!(items[0].magic, KnownMagic::RaindexSignedContextOracleV1); // Extract oracle - let decoded = SignedContextOracleV1::try_from(items[0].clone()).unwrap(); + let decoded = RaindexSignedContextOracleV1::try_from(items[0].clone()).unwrap(); assert_eq!(decoded.url(), url); } #[test] fn test_find_in_items() { let url = "https://oracle.example.com/prices/eth-usd"; - let oracle = SignedContextOracleV1::parse(url).unwrap(); + let oracle = RaindexSignedContextOracleV1::parse(url).unwrap(); let item = oracle.to_meta_item(); - let found = SignedContextOracleV1::find_in_items(&[item]).unwrap().unwrap(); + let found = RaindexSignedContextOracleV1::find_in_items(&[item]).unwrap().unwrap(); assert_eq!(found.url(), url); } #[test] fn test_find_in_items_missing() { let items: Vec = vec![]; - assert!(SignedContextOracleV1::find_in_items(&items).unwrap().is_none()); + assert!(RaindexSignedContextOracleV1::find_in_items(&items).unwrap().is_none()); } #[test] @@ -139,35 +139,35 @@ mod tests { // Oracle magic but invalid payload (not valid UTF-8 URL) let item = RainMetaDocumentV1Item { payload: serde_bytes::ByteBuf::from(vec![0xFF, 0xFE]), - magic: KnownMagic::SignedContextOracleV1, + magic: KnownMagic::RaindexSignedContextOracleV1, content_type: ContentType::None, content_encoding: ContentEncoding::None, content_language: ContentLanguage::None, }; - assert!(SignedContextOracleV1::find_in_items(&[item]).is_err()); + assert!(RaindexSignedContextOracleV1::find_in_items(&[item]).is_err()); } #[test] fn test_new_with_url() { let url = Url::parse("https://example.com/feed").unwrap(); - let oracle = SignedContextOracleV1::new(url); + let oracle = RaindexSignedContextOracleV1::new(url); assert_eq!(oracle.url(), "https://example.com/feed"); } #[test] fn test_parse_valid_url() { - let oracle = SignedContextOracleV1::parse("https://example.com/feed").unwrap(); + let oracle = RaindexSignedContextOracleV1::parse("https://example.com/feed").unwrap(); assert_eq!(oracle.url(), "https://example.com/feed"); } #[test] fn test_parse_invalid_url() { - assert!(SignedContextOracleV1::parse("not a url").is_err()); + assert!(RaindexSignedContextOracleV1::parse("not a url").is_err()); } #[test] fn test_parse_empty_url() { - assert!(SignedContextOracleV1::parse("").is_err()); + assert!(RaindexSignedContextOracleV1::parse("").is_err()); } #[test] @@ -179,12 +179,12 @@ mod tests { content_encoding: ContentEncoding::None, content_language: ContentLanguage::None, }; - assert!(SignedContextOracleV1::try_from(item).is_err()); + assert!(RaindexSignedContextOracleV1::try_from(item).is_err()); } #[test] fn test_parsed_url() { - let oracle = SignedContextOracleV1::parse("https://example.com/feed?pair=eth-usd").unwrap(); + let oracle = RaindexSignedContextOracleV1::parse("https://example.com/feed?pair=eth-usd").unwrap(); let parsed = oracle.parsed_url().unwrap(); assert_eq!(parsed.host_str(), Some("example.com")); assert_eq!(parsed.path(), "/feed"); From 1a60bbf238deb59a2c19f4b5f62a1557480b6426 Mon Sep 17 00:00:00 2001 From: Josh Hardy Date: Sun, 22 Feb 2026 21:13:52 +0000 Subject: [PATCH 4/4] fix: apply cargo fmt to fix CI formatting issues --- .../meta/types/raindex_signed_context_oracle/mod.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/crates/cli/src/meta/types/raindex_signed_context_oracle/mod.rs b/crates/cli/src/meta/types/raindex_signed_context_oracle/mod.rs index bc317055..ca0546c3 100644 --- a/crates/cli/src/meta/types/raindex_signed_context_oracle/mod.rs +++ b/crates/cli/src/meta/types/raindex_signed_context_oracle/mod.rs @@ -124,14 +124,18 @@ mod tests { let oracle = RaindexSignedContextOracleV1::parse(url).unwrap(); let item = oracle.to_meta_item(); - let found = RaindexSignedContextOracleV1::find_in_items(&[item]).unwrap().unwrap(); + let found = RaindexSignedContextOracleV1::find_in_items(&[item]) + .unwrap() + .unwrap(); assert_eq!(found.url(), url); } #[test] fn test_find_in_items_missing() { let items: Vec = vec![]; - assert!(RaindexSignedContextOracleV1::find_in_items(&items).unwrap().is_none()); + assert!(RaindexSignedContextOracleV1::find_in_items(&items) + .unwrap() + .is_none()); } #[test] @@ -184,7 +188,8 @@ mod tests { #[test] fn test_parsed_url() { - let oracle = RaindexSignedContextOracleV1::parse("https://example.com/feed?pair=eth-usd").unwrap(); + let oracle = + RaindexSignedContextOracleV1::parse("https://example.com/feed?pair=eth-usd").unwrap(); let parsed = oracle.parsed_url().unwrap(); assert_eq!(parsed.host_str(), Some("example.com")); assert_eq!(parsed.path(), "/feed");