Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions crates/foreign-chain-health-check/src/probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,8 @@ pub async fn probe_all_providers(config: &ForeignChainsConfig) -> ProbeReport {
ForeignChain::Bnb => probe_evm::<Bnb>(chain, chain_config).await,
ForeignChain::HyperEvm => probe_evm::<HyperEvm>(chain, chain_config).await,
ForeignChain::Polygon => probe_evm::<Polygon>(chain, chain_config).await,
// TODO(#4003): probe Bitcoin, Aptos and Sui. Ethereum, Solana and Ton have no
// inspector, so there is nothing to probe them with.
// TODO(#4003): probe Bitcoin, Aptos, Sui, Solana and Fogo. Ethereum and Ton have
// no inspector, so there is nothing to probe them with.
_ => rows_of(chain, chain_config, ProviderStatus::ProbeNotImplemented),
}
});
Expand Down
1 change: 1 addition & 0 deletions crates/foreign-chain-inspector/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ tracing = { workspace = true }

[dev-dependencies]
assert_matches = { workspace = true }
base64 = { workspace = true }
httpmock = { workspace = true }
mockall = { workspace = true }
rstest = { workspace = true }
Expand Down
167 changes: 167 additions & 0 deletions crates/foreign-chain-inspector/src/contract_interface_conversions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ use crate::starknet::StarknetExtractedValue;
use crate::starknet::inspector::{StarknetExtractor, StarknetFinality};
use crate::sui::SuiExtractedValue;
use crate::sui::inspector::{SuiExtractor, SuiFinality};
use crate::svm::SvmExtractedValue;
use crate::svm::inspector::{SvmExtractor, SvmFinality};

#[derive(Debug, thiserror::Error)]
pub enum ConversionError {
Expand Down Expand Up @@ -461,6 +463,124 @@ impl From<SuiExtractedValue> for dtos::ExtractedValue {
}
}

impl From<SvmFinality> for dtos::SvmFinality {
fn from(value: SvmFinality) -> Self {
match value {
SvmFinality::Confirmed => dtos::SvmFinality::Confirmed,
SvmFinality::Finalized => dtos::SvmFinality::Finalized,
}
}
}

impl TryFrom<dtos::SvmFinality> for SvmFinality {
type Error = ConversionError;
fn try_from(value: dtos::SvmFinality) -> Result<Self, Self::Error> {
match value {
dtos::SvmFinality::Confirmed => Ok(SvmFinality::Confirmed),
dtos::SvmFinality::Finalized => Ok(SvmFinality::Finalized),
other => Err(ConversionError::UnsupportedVariant {
value: format!("{other:?}"),
context: "SvmFinality",
}),
}
}
}

impl TryFrom<SvmExtractor> for dtos::SvmExtractor {
type Error = ConversionError;
fn try_from(value: SvmExtractor) -> Result<Self, Self::Error> {
match value {
SvmExtractor::InnerInstruction {
instruction_index,
inner_instruction_index,
} => Ok(dtos::SvmExtractor::InnerInstruction {
instruction_index: u64::try_from(instruction_index).map_err(|_| {
ConversionError::IntegerOverflow {
context: "SvmExtractor::InnerInstruction instruction_index exceeds u64",
}
})?,
inner_instruction_index: u64::try_from(inner_instruction_index).map_err(|_| {
ConversionError::IntegerOverflow {
context:
"SvmExtractor::InnerInstruction inner_instruction_index exceeds u64",
}
})?,
}),
SvmExtractor::AccountState { pubkey } => Ok(dtos::SvmExtractor::AccountState {
pubkey: dtos::SvmAddress(pubkey),
}),
}
}
}

impl TryFrom<dtos::SvmExtractor> for SvmExtractor {
type Error = ConversionError;
fn try_from(value: dtos::SvmExtractor) -> Result<Self, Self::Error> {
match value {
dtos::SvmExtractor::InnerInstruction {
instruction_index,
inner_instruction_index,
} => Ok(SvmExtractor::InnerInstruction {
instruction_index: usize::try_from(instruction_index).map_err(|_| {
ConversionError::IntegerOverflow {
context:
"SvmExtractor::InnerInstruction instruction_index exceeds platform usize",
}
})?,
inner_instruction_index: usize::try_from(inner_instruction_index).map_err(
|_| ConversionError::IntegerOverflow {
context: "SvmExtractor::InnerInstruction inner_instruction_index exceeds platform usize",
},
)?,
}),
dtos::SvmExtractor::AccountState { pubkey } => Ok(SvmExtractor::AccountState {
pubkey: pubkey.0,
}),
other => Err(ConversionError::UnsupportedVariant {
value: format!("{other:?}"),
context: "SvmExtractor",
}),
}
}
}

impl From<SvmExtractedValue> for dtos::SvmExtractedValue {
fn from(value: SvmExtractedValue) -> Self {
match value {
SvmExtractedValue::InnerInstruction(instruction) => {
dtos::SvmExtractedValue::InnerInstruction(instruction)
}
SvmExtractedValue::AccountState(account) => {
dtos::SvmExtractedValue::AccountState(account)
}
}
}
}

impl TryFrom<dtos::SvmExtractedValue> for SvmExtractedValue {
type Error = ConversionError;
fn try_from(value: dtos::SvmExtractedValue) -> Result<Self, Self::Error> {
match value {
dtos::SvmExtractedValue::InnerInstruction(instruction) => {
Ok(SvmExtractedValue::InnerInstruction(instruction))
}
dtos::SvmExtractedValue::AccountState(account) => {
Ok(SvmExtractedValue::AccountState(account))
}
other => Err(ConversionError::UnsupportedVariant {
value: format!("{other:?}"),
context: "SvmExtractedValue",
}),
}
}
}

impl From<SvmExtractedValue> for dtos::ExtractedValue {
fn from(value: SvmExtractedValue) -> Self {
dtos::ExtractedValue::SvmExtractedValue(value.into())
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -748,4 +868,51 @@ mod tests {
let back = SuiExtractedValue::try_from(contract).unwrap();
assert_eq!(inspector, back);
}

#[test]
fn svm_finality_roundtrip() {
for (inspector, contract) in [
(SvmFinality::Confirmed, dtos::SvmFinality::Confirmed),
(SvmFinality::Finalized, dtos::SvmFinality::Finalized),
] {
assert_eq!(contract, dtos::SvmFinality::from(inspector.clone()));
assert_eq!(inspector, SvmFinality::try_from(contract).unwrap());
}
}

#[test]
fn svm_extractor_roundtrip() {
let extractors = [
SvmExtractor::InnerInstruction {
instruction_index: 3,
inner_instruction_index: 1,
},
SvmExtractor::AccountState { pubkey: [0x0a; 32] },
];
for inspector in extractors {
let contract = dtos::SvmExtractor::try_from(inspector.clone()).unwrap();
let back = SvmExtractor::try_from(contract).unwrap();
assert_eq!(inspector, back);
}
}

#[test]
fn svm_extracted_value_roundtrip() {
let values = [
SvmExtractedValue::InnerInstruction(dtos::SvmInnerInstruction {
program_id: dtos::SvmAddress([0x01; 32]),
accounts: vec![dtos::SvmAddress([0x02; 32])],
data: vec![0xde, 0xad, 0xbe, 0xef],
}),
SvmExtractedValue::AccountState(dtos::SvmAccount {
owner: dtos::SvmAddress([0x03; 32]),
data: vec![0xca, 0xfe],
}),
];
for inspector in values {
let contract = dtos::SvmExtractedValue::from(inspector.clone());
let back = SvmExtractedValue::try_from(contract).unwrap();
assert_eq!(inspector, back);
}
}
}
7 changes: 6 additions & 1 deletion crates/foreign-chain-inspector/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pub mod hyperevm;
pub mod polygon;
pub mod starknet;
pub mod sui;
pub mod svm;

pub trait ForeignChainInspector {
type TransactionId;
Expand Down Expand Up @@ -370,7 +371,9 @@ pub enum ForeignChainInspectionError {
TransactionFailed,
#[error("transaction not found")]
TransactionNotFound,
#[error("provided log index is out of bounds")]
#[error("account not found")]
AccountNotFound,
#[error("no value at the requested index in the transaction")]
LogIndexOutOfBounds,
#[error("failed to borsh serialize log event")]
EventLogFailedBorshSerialization(std::io::Error),
Expand Down Expand Up @@ -448,6 +451,7 @@ impl ForeignChainInspectionError {
| Self::NonCanonicalBlock { .. }
| Self::TransactionFailed
| Self::TransactionNotFound
| Self::AccountNotFound
| Self::LogIndexOutOfBounds => None,
}
}
Expand Down Expand Up @@ -697,6 +701,7 @@ mod tests {
)]
// The transaction's own state is an answer, not a fault of the provider that reported it.
#[case(ForeignChainInspectionError::TransactionNotFound, None)]
#[case(ForeignChainInspectionError::AccountNotFound, None)]
#[case(ForeignChainInspectionError::TransactionFailed, None)]
#[case(ForeignChainInspectionError::NotFinalized, None)]
#[case(ForeignChainInspectionError::NotEnoughBlockConfirmations {
Expand Down
11 changes: 11 additions & 0 deletions crates/foreign-chain-inspector/src/svm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use near_mpc_contract_interface::types::{SvmAccount, SvmInnerInstruction};

pub mod inspector;

mpc_primitives::define_hash!(SvmTransactionSignature, 64);

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum SvmExtractedValue {
InnerInstruction(SvmInnerInstruction),
AccountState(SvmAccount),
}
Loading