OpenPay (3 crates, ~13k LOC, 175 tests) op-connect sub-merchant onboarding + KYB + split-payments + payouts + 1099-K op-3ds2 3DS2.3 SCA processor (AReq/ARes/CReq/CRes/RReq/RRes + exemptions) op-tax US/EU/UK/AU/CA/IN tax with Avalara/Stripe/CCH/Vertex/TaxJar adapters Smart Byte (3 crates, ~7k LOC, 57 tests) smart-byte-libp2p libp2p transport (kad/gossipsub/mdns/autonat/relay/dcutr/identify/ping/req_resp) smart-byte-crdt LWW/GCounter/PnCounter/OrSet/LwwMap/RgaList/2P-Set + HLC + vector clock + Automerge/Yjs interop smart-byte-keri-witness KERI key-rotation cycle + witness layer + watchers + recovery + delegation EOC (3 crates, ~8k LOC, 108 tests) eoc-tools function-calling across Anthropic/OpenAI/Google/Mistral/Cohere + parallel exec + sandbox eoc-multimodal vision (CLIP/SigLIP/ColPali) + audio (Whisper/MMS) + video sampling + modality router eoc-spec-decode vanilla + SpS-with-temp + lookahead speculative decoding + EAGLE/Medusa stubs All three workspaces compile cleanly. Forbidden-unsafe, no unwrap outside tests. Co-Authored-By: Claude Opus 4.7 <[email protected]>
115 lines
3.6 KiB
Rust
115 lines
3.6 KiB
Rust
//! Error types for `op-connect`.
|
|
//!
|
|
//! One sealed enum per crate convention. Callers should `match` exhaustively;
|
|
//! adding a variant is a SemVer-major change.
|
|
|
|
use thiserror::Error;
|
|
|
|
/// Result alias for `op-connect`.
|
|
pub type Result<T> = core::result::Result<T, Error>;
|
|
|
|
/// All possible failure modes inside `op-connect`.
|
|
#[derive(Debug, Error)]
|
|
pub enum Error {
|
|
/// A connected account was referenced but does not exist in the registry.
|
|
#[error("connected account not found: {0}")]
|
|
AccountNotFound(String),
|
|
|
|
/// The account is not in the right onboarding state for the requested operation.
|
|
#[error("account state invalid for operation: {reason}")]
|
|
AccountStateInvalid {
|
|
/// Human-readable reason.
|
|
reason: String,
|
|
},
|
|
|
|
/// An onboarding step was submitted out of order or twice.
|
|
#[error("onboarding step invalid: {reason}")]
|
|
OnboardingStepInvalid {
|
|
/// Human-readable reason.
|
|
reason: String,
|
|
},
|
|
|
|
/// A required onboarding requirement is missing.
|
|
#[error("requirement missing: {0}")]
|
|
RequirementMissing(String),
|
|
|
|
/// Beneficial-owner identification incomplete.
|
|
///
|
|
/// Per FinCEN Customer Due Diligence Final Rule (31 CFR § 1010.230)
|
|
/// and EU AMLD5 (Directive (EU) 2018/843, Art. 3(6)), institutions
|
|
/// must identify each natural person who owns 25% or more of an
|
|
/// entity. If declared ownership totals less than 100% and no
|
|
/// "control prong" individual is named, this error fires.
|
|
#[error("FinCEN CDD beneficial-owner rule violated: {reason}")]
|
|
BeneficialOwnerIncomplete {
|
|
/// Which prong of the rule was missed.
|
|
reason: String,
|
|
},
|
|
|
|
/// A split-payment plan failed validation: legs do not sum to source,
|
|
/// or contained a negative leg.
|
|
#[error("invalid split: {reason}")]
|
|
InvalidSplit {
|
|
/// Why the split was rejected.
|
|
reason: String,
|
|
},
|
|
|
|
/// A currency mismatch between source payment and a split leg, or
|
|
/// between accounts in an internal transfer.
|
|
#[error("currency mismatch: {0}")]
|
|
CurrencyMismatch(String),
|
|
|
|
/// Arithmetic overflow on a Money sum.
|
|
#[error("arithmetic overflow")]
|
|
Overflow,
|
|
|
|
/// Screening fired a hit that blocks onboarding.
|
|
#[error("screening blocked: {reason}")]
|
|
ScreeningBlocked {
|
|
/// Why the screening result blocked the operation.
|
|
reason: String,
|
|
},
|
|
|
|
/// An onboarding provider (the trait impl) returned an upstream error.
|
|
#[error("provider error: {0}")]
|
|
Provider(String),
|
|
|
|
/// A payout-schedule field is out of range (e.g. `day_of_month=32`).
|
|
#[error("invalid payout schedule: {reason}")]
|
|
InvalidPayoutSchedule {
|
|
/// Which field was invalid.
|
|
reason: String,
|
|
},
|
|
|
|
/// A liability-model invocation tried to nest `Hybrid` inside `Hybrid`,
|
|
/// which the model does not support.
|
|
#[error("invalid liability model: {reason}")]
|
|
InvalidLiabilityModel {
|
|
/// Why the model was rejected.
|
|
reason: String,
|
|
},
|
|
|
|
/// Tax-reporting form generation failed validation.
|
|
#[error("tax reporting error: {reason}")]
|
|
TaxReporting {
|
|
/// What went wrong.
|
|
reason: String,
|
|
},
|
|
|
|
/// ToS acceptance was rejected (mismatched hash, missing fields, etc.).
|
|
#[error("tos acceptance invalid: {reason}")]
|
|
TosInvalid {
|
|
/// Why it was rejected.
|
|
reason: String,
|
|
},
|
|
|
|
/// Anything bubbled up from `op-core`.
|
|
#[error("op-core error: {0}")]
|
|
Core(#[from] op_core::Error),
|
|
}
|
|
|
|
impl From<op_screening::Error> for Error {
|
|
fn from(value: op_screening::Error) -> Self {
|
|
Self::Provider(format!("screening: {value}"))
|
|
}
|
|
}
|